Home | All Classes | Main Classes | Annotated | Grouped Classes | Functions

Transformed Graphics Demo

This example lets the user rotate, shear and scale text and graphics arbitrarily.


Implementation:

/****************************************************************************
** $Id: qt/xform.cpp   3.3.8   edited Jan 11 14:37 $
**
** Copyright (C) 1992-2007 Trolltech ASA.  All rights reserved.
**
** This file is part of an example program for TQt.  This example
** program may be used, distributed and modified without limitation.
**
*****************************************************************************/

#include <tqapplication.h>

#include <tqdialog.h>
#include <tqlabel.h>
#include <tqlineedit.h>
#include <tqpushbutton.h>
#include <tqcheckbox.h>
#include <tqradiobutton.h>
#include <tqbuttongroup.h>
#include <tqlcdnumber.h>
#include <tqslider.h>
#include <tqmenubar.h>
#include <tqfontdialog.h>
#include <tqlayout.h>
#include <tqvbox.h>
#include <tqwidgetstack.h>

#include <tqpainter.h>
#include <tqpixmap.h>
#include <tqpicture.h>

#include <stdlib.h>


class ModeNames {
public:
    enum Mode { Text, Image, Picture };
};


class XFormControl : public TQVBox, public ModeNames
{
    TQ_OBJECT
public:
    XFormControl( const TQFont &initialFont, TQWidget *parent=0, const char *name=0 );
   ~XFormControl() {}

    TQWMatrix matrix();

signals:
    void newMatrix( TQWMatrix );
    void newText( const TQString& );
    void newFont( const TQFont & );
    void newMode( int );
private slots:
    void newMtx();
    void newTxt(const TQString&);
    void selectFont();
    void fontSelected( const TQFont & );
    void changeMode(int);
    void timerEvent(TQTimerEvent*);
private:
    Mode mode;
    TQSlider      *rotS;                // Rotation angle scroll bar
    TQSlider      *shearS;              // Shear value scroll bar
    TQSlider      *magS;                // Magnification value scroll bar
    TQLCDNumber   *rotLCD;              // Rotation angle LCD display
    TQLCDNumber   *shearLCD;            // Shear value LCD display
    TQLCDNumber   *magLCD;              // Magnification value LCD display
    TQCheckBox    *mirror;              // Checkbox for mirror image on/of
    TQWidgetStack* optionals;
    TQLineEdit    *textEd;              // Inp[ut field for xForm text
    TQPushButton  *fpb;                 // Select font push button
    TQRadioButton *rb_txt;              // Radio button for text
    TQRadioButton *rb_img;              // Radio button for image
    TQRadioButton *rb_pic;              // Radio button for picture
    TQFont currentFont;
};

/*
  ShowXForm displays a text or a pixmap (TQPixmap) using a coordinate
  transformation matrix (TQWMatrix)
*/

class ShowXForm : public TQWidget, public ModeNames
{
    TQ_OBJECT
public:
    ShowXForm( const TQFont &f, TQWidget *parent=0, const char *name=0 );
   ~ShowXForm() {}
    void showIt();                      // (Re)displays text or pixmap

    Mode mode() const { return m; }
public slots:
    void setText( const TQString& );
    void setMatrix( TQWMatrix );
    void setFont( const TQFont &f );
    void setPixmap( TQPixmap );
    void setPicture( const TQPicture& );
    void setMode( int );
private:
    TQSizePolicy sizePolicy() const;
    TQSize sizeHint() const;
    void paintEvent( TQPaintEvent * );
    void resizeEvent( TQResizeEvent * );
    TQWMatrix  mtx;                      // coordinate transform matrix
    TQString   text;                     // text to be displayed
    TQPixmap   pix;                      // pixmap to be displayed
    TQPicture  picture;                  // text to be displayed
    TQRect     eraseRect;                // covers last displayed text/pixmap
    Mode      m;
};

XFormControl::XFormControl( const TQFont &initialFont,
                            TQWidget *parent, const char *name )
        : TQVBox( parent, name )
{
    setSpacing(6);
    setMargin(6);
    currentFont = initialFont;
    mode = Image;

    rotLCD      = new TQLCDNumber( 4, this, "rotateLCD" );
    rotS        = new TQSlider( TQSlider::Horizontal, this,
                                  "rotateSlider" );
    shearLCD    = new TQLCDNumber( 5,this, "shearLCD" );
    shearS      = new TQSlider( TQSlider::Horizontal, this,
                                  "shearSlider" );
    mirror      = new TQCheckBox( this, "mirrorCheckBox" );
    rb_txt = new TQRadioButton( this, "text" );
    rb_img = new TQRadioButton( this, "image" );
    rb_pic = new TQRadioButton( this, "picture" );
    optionals = new TQWidgetStack(this);
    TQVBox* optionals_text = new TQVBox(optionals);
    optionals_text->setSpacing(6);
    TQVBox* optionals_other = new TQVBox(optionals);
    optionals_other->setSpacing(6);
    optionals->addWidget(optionals_text,0);
    optionals->addWidget(optionals_other,1);
    fpb         = new TQPushButton( optionals_text, "text" );
    textEd      = new TQLineEdit( optionals_text, "text" );
    textEd->setFocus();

    rotLCD->display( "  0'" );

    rotS->setRange( -180, 180 );
    rotS->setValue( 0 );
    connect( rotS, TQ_SIGNAL(valueChanged(int)), TQ_SLOT(newMtx()) );

    shearLCD->display( "0.00" );

    shearS->setRange( -25, 25 );
    shearS->setValue( 0 );
    connect( shearS, TQ_SIGNAL(valueChanged(int)), TQ_SLOT(newMtx()) );

    mirror->setText( tr("Mirror") );
    connect( mirror, TQ_SIGNAL(clicked()), TQ_SLOT(newMtx()) );

    TQButtonGroup *bg = new TQButtonGroup(this);
    bg->hide();
    bg->insert(rb_txt,0);
    bg->insert(rb_img,1);
    bg->insert(rb_pic,2);
    rb_txt->setText( tr("Text") );
    rb_img->setText( tr("Image") );
    rb_img->setChecked(TRUE);
    rb_pic->setText( tr("Picture") );
    connect( bg, TQ_SIGNAL(clicked(int)), TQ_SLOT(changeMode(int)) );

    fpb->setText( tr("Select font...") );
    connect( fpb, TQ_SIGNAL(clicked()), TQ_SLOT(selectFont()) );

    textEd->setText( "Troll" );
    connect( textEd, TQ_SIGNAL(textChanged(const TQString&)),
                     TQ_SLOT(newTxt(const TQString&)) );

    magLCD = new TQLCDNumber( 4,optionals_other, "magLCD" );
    magLCD->display( "100" );
    magS = new TQSlider( TQSlider::Horizontal, optionals_other,
                           "magnifySlider" );
    magS->setRange( 0, 800 );
    connect( magS, TQ_SIGNAL(valueChanged(int)), TQ_SLOT(newMtx()) );
    magS->setValue( 0 );
    connect( magS, TQ_SIGNAL(valueChanged(int)), magLCD, TQ_SLOT(display(int)));

    optionals_text->adjustSize();
    optionals_other->adjustSize();
    changeMode(Image);

    startTimer(20); // start an initial animation
}

void XFormControl::timerEvent(TQTimerEvent*)
{
    int v = magS->value();
    v = (v+2)+v/10;
    if ( v >= 200 ) {
        v = 200;
        killTimers();
    }
    magS->setValue(v);
}



/*
    Called whenever the user has changed one of the matrix parameters
    (i.e. rotate, shear or magnification)
*/
void XFormControl::newMtx()
{
    emit newMatrix( matrix() );
}

void XFormControl::newTxt(const TQString& s)
{
    emit newText(s);
    changeMode(Text);
}

/*
    Calculates the matrix appropriate for the current controls,
    and updates the displays.
*/
TQWMatrix XFormControl::matrix()
{
    TQWMatrix m;
    if (mode != Text) {
        double magVal = 1.0*magS->value()/100;
        m.scale( magVal, magVal );
    }
    double shearVal = 1.0*shearS->value()/25;
    m.shear( shearVal, shearVal );
    m.rotate( rotS->value() );
    if ( mirror->isChecked() ) {
        m.scale( 1, -1 );
        m.rotate( 180 );
    }

    TQString tmp;
    tmp.sprintf( "%1.2f", shearVal  );
    if ( shearVal >= 0 )
        tmp.insert( 0, " " );
    shearLCD->display( tmp );

    int rot = rotS->value();
    if ( rot < 0 )
        rot = rot + 360;
    tmp.sprintf( "%3i'", rot );
    rotLCD->display( tmp );
    return m;
}


void XFormControl::selectFont()
{
    bool ok;
    TQFont f = TQFontDialog::getFont( &ok, currentFont );
    if ( ok ) {
        currentFont = f;
        fontSelected( f );
    }
}

void XFormControl::fontSelected( const TQFont &font )
{
    emit newFont( font );
    changeMode(Text);
}

/*
    Sets the mode - Text, Image, or Picture.
*/

void XFormControl::changeMode(int m)
{
    mode = (Mode)m;

    emit newMode( m );
    newMtx();
    if ( mode == Text ) {
        optionals->raiseWidget(0);
        rb_txt->setChecked(TRUE);
    } else {
        optionals->raiseWidget(1);
        if ( mode == Image )
            rb_img->setChecked(TRUE);
        else
            rb_pic->setChecked(TRUE);
    }
    tqApp->flushX();
}

ShowXForm::ShowXForm( const TQFont &initialFont,
                      TQWidget *parent, const char *name )
        : TQWidget( parent, name, WResizeNoErase )
{
    setFont( initialFont );
    setBackgroundColor( white );
    m = Text;
    eraseRect = TQRect( 0, 0, 0, 0 );
}

TQSizePolicy ShowXForm::sizePolicy() const
{
    return TQSizePolicy( TQSizePolicy::Expanding, TQSizePolicy::Expanding );
}

TQSize ShowXForm::sizeHint() const
{
    return TQSize(400,400);
}

void ShowXForm::paintEvent( TQPaintEvent * )
{
    showIt();
}

void ShowXForm::resizeEvent( TQResizeEvent * )
{
    eraseRect = TQRect( width()/2, height()/2, 0, 0 );
    repaint(rect());
}

void ShowXForm::setText( const TQString& s )
{
    text = s;
    showIt();
}

void ShowXForm::setMatrix( TQWMatrix w )
{
    mtx = w;
    showIt();
}

void ShowXForm::setFont( const TQFont &f )
{
    m = Text;
    TQWidget::setFont( f );
}

void ShowXForm::setPixmap( TQPixmap pm )
{
    pix  = pm;
    m    = Image;
    showIt();
}

void ShowXForm::setPicture( const TQPicture& p )
{
    picture = p;
    m = Picture;
    showIt();
}

void ShowXForm::setMode( int mode )
{
    m = (Mode)mode;
}

void ShowXForm::showIt()
{
    TQPainter p;
    TQRect r;      // rectangle covering new text/pixmap in virtual coordinates
    TQWMatrix um;  // copy user specified transform
    int textYPos = 0; // distance from boundingRect y pos to baseline
    int textXPos = 0; // distance from boundingRect x pos to text start
    TQRect br;
    TQFontMetrics fm( fontMetrics() );   // get widget font metrics
    switch ( mode() ) {
      case Text:
        br = fm.boundingRect( text );   // rectangle covering text
        r  = br;
        textYPos = -r.y();
        textXPos = -r.x();
        br.moveTopLeft( TQPoint( -br.width()/2, -br.height()/2 ) );
        break;
      case Image:
        r = TQRect(0, 0, pix.width()+1, pix.height()+1);
        break;
      case Picture:
        // ### need TQPicture::boundingRect()
        r = TQRect(0,0,1000,1000);
        break;
    }
    r.moveTopLeft( TQPoint(-r.width()/2, -r.height()/2) );
    r.moveBy( -1, -1 ); // add border for matrix round off
    r.setSize( TQSize( r.width() + 2,r.height() + 2 ) );
          // compute union of new and old rect
          // the resulting rectangle will cover what is already displayed
          // and have room for the new text/pixmap
    eraseRect = eraseRect.unite( mtx.mapRect(r) );
    int pw = TQMIN(eraseRect.width(),width());
    int ph = TQMIN(eraseRect.height(),height());
    TQPixmap pm( pw, ph );               // off-screen drawing pixmap
    pm.fill( backgroundColor() );

    p.begin( &pm );
    um.translate( pw/2, ph/2 ); // 0,0 is center
    um = mtx * um;
    p.setWorldMatrix( um );
    switch ( mode() ) {
      case Text:
        p.setFont( font() );            // use widget font
        p.drawText( r.left() + textXPos, r.top() + textYPos, text );
#if 0
        p.setPen( red );
        p.drawRect( br );
#endif
        break;
    case Image:
        p.drawPixmap( -pix.width()/2, -pix.height()/2, pix );
        break;
      case Picture:
        // ### need TQPicture::boundingRect()
        p.scale(0.25,0.25);
        p.translate(-230,-180);
        p.drawPicture( picture );
    }
    p.end();

    int xpos = width()/2  - pw/2;
    int ypos = height()/2 - ph/2;
    bitBlt( this, xpos, ypos,                   // copy pixmap to widget
            &pm, 0, 0, -1, -1 );
    eraseRect =  mtx.map( r );
}


/*
    Grand unifying widget, putting ShowXForm and XFormControl
    together.
*/

class XFormCenter : public TQHBox, public ModeNames
{
    TQ_OBJECT
public:
    XFormCenter( TQWidget *parent=0, const char *name=0 );
public slots:
    void setFont( const TQFont &f ) { sx->setFont( f ); }
    void newMode( int );
private:
    ShowXForm   *sx;
    XFormControl *xc;
};

void XFormCenter::newMode( int m )
{
    static bool first_i = TRUE;
    static bool first_p = TRUE;

    if ( sx->mode() == m )
        return;
    if ( m == Image && first_i ) {
        first_i = FALSE;
        TQPixmap pm;
        if ( pm.load( "image.any" ) )
            sx->setPixmap( pm );
        return;
    }
    if ( m == Picture && first_p ) {
        first_p = FALSE;
        TQPicture p;
        if (p.load( "picture.any" ))
            sx->setPicture( p );
        return;
    }
    sx->setMode(m);
}

XFormCenter::XFormCenter( TQWidget *parent, const char *name )
    : TQHBox( parent, name )
{
    TQFont f( "Charter", 36, TQFont::Bold );

    xc = new XFormControl( f, this );
    sx = new ShowXForm( f, this );
    setStretchFactor(sx,1);
    xc->setFrameStyle( TQFrame::Panel | TQFrame::Raised );
    xc->setLineWidth( 2 );
    connect( xc, TQ_SIGNAL(newText(const TQString&)), sx,
                 TQ_SLOT(setText(const TQString&)) );
    connect( xc, TQ_SIGNAL(newMatrix(TQWMatrix)),
             sx, TQ_SLOT(setMatrix(TQWMatrix)) );
    connect( xc, TQ_SIGNAL(newFont(const TQFont&)), sx,
                 TQ_SLOT(setFont(const TQFont&)) );
    connect( xc, TQ_SIGNAL(newMode(int)), TQ_SLOT(newMode(int)) );
    sx->setText( "Troll" );
    newMode( Image );
    sx->setMatrix(xc->matrix());
}


int main( int argc, char **argv )
{
    TQApplication a( argc, argv );

    XFormCenter *xfc = new XFormCenter;

    a.setMainWidget( xfc );
    xfc->setCaption("TQt Example - XForm");
    xfc->show();
    return a.exec();
}

#include "xform.moc"                  // include metadata generated by the tqmoc

See also Examples.


Copyright © 2007 TrolltechTrademarks
TQt 3.3.8