1 | /****************************************************************************
|
---|
2 | ** $Id: xform.cpp 2 2005-11-16 15:49:26Z dmik $
|
---|
3 | **
|
---|
4 | ** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
|
---|
5 | **
|
---|
6 | ** This file is part of an example program for Qt. This example
|
---|
7 | ** program may be used, distributed and modified without limitation.
|
---|
8 | **
|
---|
9 | *****************************************************************************/
|
---|
10 |
|
---|
11 | #include <qapplication.h>
|
---|
12 |
|
---|
13 | #include <qdialog.h>
|
---|
14 | #include <qlabel.h>
|
---|
15 | #include <qlineedit.h>
|
---|
16 | #include <qpushbutton.h>
|
---|
17 | #include <qcheckbox.h>
|
---|
18 | #include <qradiobutton.h>
|
---|
19 | #include <qbuttongroup.h>
|
---|
20 | #include <qlcdnumber.h>
|
---|
21 | #include <qslider.h>
|
---|
22 | #include <qmenubar.h>
|
---|
23 | #include <qfontdialog.h>
|
---|
24 | #include <qlayout.h>
|
---|
25 | #include <qvbox.h>
|
---|
26 | #include <qwidgetstack.h>
|
---|
27 |
|
---|
28 | #include <qpainter.h>
|
---|
29 | #include <qpixmap.h>
|
---|
30 | #include <qpicture.h>
|
---|
31 |
|
---|
32 | #include <stdlib.h>
|
---|
33 |
|
---|
34 |
|
---|
35 | class ModeNames {
|
---|
36 | public:
|
---|
37 | enum Mode { Text, Image, Picture };
|
---|
38 | };
|
---|
39 |
|
---|
40 |
|
---|
41 | class XFormControl : public QVBox, public ModeNames
|
---|
42 | {
|
---|
43 | Q_OBJECT
|
---|
44 | public:
|
---|
45 | XFormControl( const QFont &initialFont, QWidget *parent=0, const char *name=0 );
|
---|
46 | ~XFormControl() {}
|
---|
47 |
|
---|
48 | QWMatrix matrix();
|
---|
49 |
|
---|
50 | signals:
|
---|
51 | void newMatrix( QWMatrix );
|
---|
52 | void newText( const QString& );
|
---|
53 | void newFont( const QFont & );
|
---|
54 | void newMode( int );
|
---|
55 | private slots:
|
---|
56 | void newMtx();
|
---|
57 | void newTxt(const QString&);
|
---|
58 | void selectFont();
|
---|
59 | void fontSelected( const QFont & );
|
---|
60 | void changeMode(int);
|
---|
61 | void timerEvent(QTimerEvent*);
|
---|
62 | private:
|
---|
63 | Mode mode;
|
---|
64 | QSlider *rotS; // Rotation angle scroll bar
|
---|
65 | QSlider *shearS; // Shear value scroll bar
|
---|
66 | QSlider *magS; // Magnification value scroll bar
|
---|
67 | QLCDNumber *rotLCD; // Rotation angle LCD display
|
---|
68 | QLCDNumber *shearLCD; // Shear value LCD display
|
---|
69 | QLCDNumber *magLCD; // Magnification value LCD display
|
---|
70 | QCheckBox *mirror; // Checkbox for mirror image on/of
|
---|
71 | QWidgetStack* optionals;
|
---|
72 | QLineEdit *textEd; // Inp[ut field for xForm text
|
---|
73 | QPushButton *fpb; // Select font push button
|
---|
74 | QRadioButton *rb_txt; // Radio button for text
|
---|
75 | QRadioButton *rb_img; // Radio button for image
|
---|
76 | QRadioButton *rb_pic; // Radio button for picture
|
---|
77 | QFont currentFont;
|
---|
78 | };
|
---|
79 |
|
---|
80 | /*
|
---|
81 | ShowXForm displays a text or a pixmap (QPixmap) using a coordinate
|
---|
82 | transformation matrix (QWMatrix)
|
---|
83 | */
|
---|
84 |
|
---|
85 | class ShowXForm : public QWidget, public ModeNames
|
---|
86 | {
|
---|
87 | Q_OBJECT
|
---|
88 | public:
|
---|
89 | ShowXForm( const QFont &f, QWidget *parent=0, const char *name=0 );
|
---|
90 | ~ShowXForm() {}
|
---|
91 | void showIt(); // (Re)displays text or pixmap
|
---|
92 |
|
---|
93 | Mode mode() const { return m; }
|
---|
94 | public slots:
|
---|
95 | void setText( const QString& );
|
---|
96 | void setMatrix( QWMatrix );
|
---|
97 | void setFont( const QFont &f );
|
---|
98 | void setPixmap( QPixmap );
|
---|
99 | void setPicture( const QPicture& );
|
---|
100 | void setMode( int );
|
---|
101 | private:
|
---|
102 | QSizePolicy sizePolicy() const;
|
---|
103 | QSize sizeHint() const;
|
---|
104 | void paintEvent( QPaintEvent * );
|
---|
105 | void resizeEvent( QResizeEvent * );
|
---|
106 | QWMatrix mtx; // coordinate transform matrix
|
---|
107 | QString text; // text to be displayed
|
---|
108 | QPixmap pix; // pixmap to be displayed
|
---|
109 | QPicture picture; // text to be displayed
|
---|
110 | QRect eraseRect; // covers last displayed text/pixmap
|
---|
111 | Mode m;
|
---|
112 | };
|
---|
113 |
|
---|
114 | XFormControl::XFormControl( const QFont &initialFont,
|
---|
115 | QWidget *parent, const char *name )
|
---|
116 | : QVBox( parent, name )
|
---|
117 | {
|
---|
118 | setSpacing(6);
|
---|
119 | setMargin(6);
|
---|
120 | currentFont = initialFont;
|
---|
121 | mode = Image;
|
---|
122 |
|
---|
123 | rotLCD = new QLCDNumber( 4, this, "rotateLCD" );
|
---|
124 | rotS = new QSlider( QSlider::Horizontal, this,
|
---|
125 | "rotateSlider" );
|
---|
126 | shearLCD = new QLCDNumber( 5,this, "shearLCD" );
|
---|
127 | shearS = new QSlider( QSlider::Horizontal, this,
|
---|
128 | "shearSlider" );
|
---|
129 | mirror = new QCheckBox( this, "mirrorCheckBox" );
|
---|
130 | rb_txt = new QRadioButton( this, "text" );
|
---|
131 | rb_img = new QRadioButton( this, "image" );
|
---|
132 | rb_pic = new QRadioButton( this, "picture" );
|
---|
133 | optionals = new QWidgetStack(this);
|
---|
134 | QVBox* optionals_text = new QVBox(optionals);
|
---|
135 | optionals_text->setSpacing(6);
|
---|
136 | QVBox* optionals_other = new QVBox(optionals);
|
---|
137 | optionals_other->setSpacing(6);
|
---|
138 | optionals->addWidget(optionals_text,0);
|
---|
139 | optionals->addWidget(optionals_other,1);
|
---|
140 | fpb = new QPushButton( optionals_text, "text" );
|
---|
141 | textEd = new QLineEdit( optionals_text, "text" );
|
---|
142 | textEd->setFocus();
|
---|
143 |
|
---|
144 | rotLCD->display( " 0'" );
|
---|
145 |
|
---|
146 | rotS->setRange( -180, 180 );
|
---|
147 | rotS->setValue( 0 );
|
---|
148 | connect( rotS, SIGNAL(valueChanged(int)), SLOT(newMtx()) );
|
---|
149 |
|
---|
150 | shearLCD->display( "0.00" );
|
---|
151 |
|
---|
152 | shearS->setRange( -25, 25 );
|
---|
153 | shearS->setValue( 0 );
|
---|
154 | connect( shearS, SIGNAL(valueChanged(int)), SLOT(newMtx()) );
|
---|
155 |
|
---|
156 | mirror->setText( tr("Mirror") );
|
---|
157 | connect( mirror, SIGNAL(clicked()), SLOT(newMtx()) );
|
---|
158 |
|
---|
159 | QButtonGroup *bg = new QButtonGroup(this);
|
---|
160 | bg->hide();
|
---|
161 | bg->insert(rb_txt,0);
|
---|
162 | bg->insert(rb_img,1);
|
---|
163 | bg->insert(rb_pic,2);
|
---|
164 | rb_txt->setText( tr("Text") );
|
---|
165 | rb_img->setText( tr("Image") );
|
---|
166 | rb_img->setChecked(TRUE);
|
---|
167 | rb_pic->setText( tr("Picture") );
|
---|
168 | connect( bg, SIGNAL(clicked(int)), SLOT(changeMode(int)) );
|
---|
169 |
|
---|
170 | fpb->setText( tr("Select font...") );
|
---|
171 | connect( fpb, SIGNAL(clicked()), SLOT(selectFont()) );
|
---|
172 |
|
---|
173 | textEd->setText( "Troll" );
|
---|
174 | connect( textEd, SIGNAL(textChanged(const QString&)),
|
---|
175 | SLOT(newTxt(const QString&)) );
|
---|
176 |
|
---|
177 | magLCD = new QLCDNumber( 4,optionals_other, "magLCD" );
|
---|
178 | magLCD->display( "100" );
|
---|
179 | magS = new QSlider( QSlider::Horizontal, optionals_other,
|
---|
180 | "magnifySlider" );
|
---|
181 | magS->setRange( 0, 800 );
|
---|
182 | connect( magS, SIGNAL(valueChanged(int)), SLOT(newMtx()) );
|
---|
183 | magS->setValue( 0 );
|
---|
184 | connect( magS, SIGNAL(valueChanged(int)), magLCD, SLOT(display(int)));
|
---|
185 |
|
---|
186 | optionals_text->adjustSize();
|
---|
187 | optionals_other->adjustSize();
|
---|
188 | changeMode(Image);
|
---|
189 |
|
---|
190 | startTimer(20); // start an initial animation
|
---|
191 | }
|
---|
192 |
|
---|
193 | void XFormControl::timerEvent(QTimerEvent*)
|
---|
194 | {
|
---|
195 | int v = magS->value();
|
---|
196 | v = (v+2)+v/10;
|
---|
197 | if ( v >= 200 ) {
|
---|
198 | v = 200;
|
---|
199 | killTimers();
|
---|
200 | }
|
---|
201 | magS->setValue(v);
|
---|
202 | }
|
---|
203 |
|
---|
204 |
|
---|
205 |
|
---|
206 | /*
|
---|
207 | Called whenever the user has changed one of the matrix parameters
|
---|
208 | (i.e. rotate, shear or magnification)
|
---|
209 | */
|
---|
210 | void XFormControl::newMtx()
|
---|
211 | {
|
---|
212 | emit newMatrix( matrix() );
|
---|
213 | }
|
---|
214 |
|
---|
215 | void XFormControl::newTxt(const QString& s)
|
---|
216 | {
|
---|
217 | emit newText(s);
|
---|
218 | changeMode(Text);
|
---|
219 | }
|
---|
220 |
|
---|
221 | /*
|
---|
222 | Calculates the matrix appropriate for the current controls,
|
---|
223 | and updates the displays.
|
---|
224 | */
|
---|
225 | QWMatrix XFormControl::matrix()
|
---|
226 | {
|
---|
227 | QWMatrix m;
|
---|
228 | if (mode != Text) {
|
---|
229 | double magVal = 1.0*magS->value()/100;
|
---|
230 | m.scale( magVal, magVal );
|
---|
231 | }
|
---|
232 | double shearVal = 1.0*shearS->value()/25;
|
---|
233 | m.shear( shearVal, shearVal );
|
---|
234 | m.rotate( rotS->value() );
|
---|
235 | if ( mirror->isChecked() ) {
|
---|
236 | m.scale( 1, -1 );
|
---|
237 | m.rotate( 180 );
|
---|
238 | }
|
---|
239 |
|
---|
240 | QString tmp;
|
---|
241 | tmp.sprintf( "%1.2f", shearVal );
|
---|
242 | if ( shearVal >= 0 )
|
---|
243 | tmp.insert( 0, " " );
|
---|
244 | shearLCD->display( tmp );
|
---|
245 |
|
---|
246 | int rot = rotS->value();
|
---|
247 | if ( rot < 0 )
|
---|
248 | rot = rot + 360;
|
---|
249 | tmp.sprintf( "%3i'", rot );
|
---|
250 | rotLCD->display( tmp );
|
---|
251 | return m;
|
---|
252 | }
|
---|
253 |
|
---|
254 |
|
---|
255 | void XFormControl::selectFont()
|
---|
256 | {
|
---|
257 | bool ok;
|
---|
258 | QFont f = QFontDialog::getFont( &ok, currentFont );
|
---|
259 | if ( ok ) {
|
---|
260 | currentFont = f;
|
---|
261 | fontSelected( f );
|
---|
262 | }
|
---|
263 | }
|
---|
264 |
|
---|
265 | void XFormControl::fontSelected( const QFont &font )
|
---|
266 | {
|
---|
267 | emit newFont( font );
|
---|
268 | changeMode(Text);
|
---|
269 | }
|
---|
270 |
|
---|
271 | /*
|
---|
272 | Sets the mode - Text, Image, or Picture.
|
---|
273 | */
|
---|
274 |
|
---|
275 | void XFormControl::changeMode(int m)
|
---|
276 | {
|
---|
277 | mode = (Mode)m;
|
---|
278 |
|
---|
279 | emit newMode( m );
|
---|
280 | newMtx();
|
---|
281 | if ( mode == Text ) {
|
---|
282 | optionals->raiseWidget(0);
|
---|
283 | rb_txt->setChecked(TRUE);
|
---|
284 | } else {
|
---|
285 | optionals->raiseWidget(1);
|
---|
286 | if ( mode == Image )
|
---|
287 | rb_img->setChecked(TRUE);
|
---|
288 | else
|
---|
289 | rb_pic->setChecked(TRUE);
|
---|
290 | }
|
---|
291 | qApp->flushX();
|
---|
292 | }
|
---|
293 |
|
---|
294 | ShowXForm::ShowXForm( const QFont &initialFont,
|
---|
295 | QWidget *parent, const char *name )
|
---|
296 | : QWidget( parent, name, WResizeNoErase )
|
---|
297 | {
|
---|
298 | setFont( initialFont );
|
---|
299 | setBackgroundColor( white );
|
---|
300 | m = Text;
|
---|
301 | eraseRect = QRect( 0, 0, 0, 0 );
|
---|
302 | }
|
---|
303 |
|
---|
304 | QSizePolicy ShowXForm::sizePolicy() const
|
---|
305 | {
|
---|
306 | return QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
|
---|
307 | }
|
---|
308 |
|
---|
309 | QSize ShowXForm::sizeHint() const
|
---|
310 | {
|
---|
311 | return QSize(400,400);
|
---|
312 | }
|
---|
313 |
|
---|
314 | void ShowXForm::paintEvent( QPaintEvent * )
|
---|
315 | {
|
---|
316 | showIt();
|
---|
317 | }
|
---|
318 |
|
---|
319 | void ShowXForm::resizeEvent( QResizeEvent * )
|
---|
320 | {
|
---|
321 | eraseRect = QRect( width()/2, height()/2, 0, 0 );
|
---|
322 | repaint(rect());
|
---|
323 | }
|
---|
324 |
|
---|
325 | void ShowXForm::setText( const QString& s )
|
---|
326 | {
|
---|
327 | text = s;
|
---|
328 | showIt();
|
---|
329 | }
|
---|
330 |
|
---|
331 | void ShowXForm::setMatrix( QWMatrix w )
|
---|
332 | {
|
---|
333 | mtx = w;
|
---|
334 | showIt();
|
---|
335 | }
|
---|
336 |
|
---|
337 | void ShowXForm::setFont( const QFont &f )
|
---|
338 | {
|
---|
339 | m = Text;
|
---|
340 | QWidget::setFont( f );
|
---|
341 | }
|
---|
342 |
|
---|
343 | void ShowXForm::setPixmap( QPixmap pm )
|
---|
344 | {
|
---|
345 | pix = pm;
|
---|
346 | m = Image;
|
---|
347 | showIt();
|
---|
348 | }
|
---|
349 |
|
---|
350 | void ShowXForm::setPicture( const QPicture& p )
|
---|
351 | {
|
---|
352 | picture = p;
|
---|
353 | m = Picture;
|
---|
354 | showIt();
|
---|
355 | }
|
---|
356 |
|
---|
357 | void ShowXForm::setMode( int mode )
|
---|
358 | {
|
---|
359 | m = (Mode)mode;
|
---|
360 | }
|
---|
361 |
|
---|
362 | void ShowXForm::showIt()
|
---|
363 | {
|
---|
364 | QPainter p;
|
---|
365 | QRect r; // rectangle covering new text/pixmap in virtual coordinates
|
---|
366 | QWMatrix um; // copy user specified transform
|
---|
367 | int textYPos = 0; // distance from boundingRect y pos to baseline
|
---|
368 | int textXPos = 0; // distance from boundingRect x pos to text start
|
---|
369 | QRect br;
|
---|
370 | QFontMetrics fm( fontMetrics() ); // get widget font metrics
|
---|
371 | switch ( mode() ) {
|
---|
372 | case Text:
|
---|
373 | br = fm.boundingRect( text ); // rectangle covering text
|
---|
374 | r = br;
|
---|
375 | textYPos = -r.y();
|
---|
376 | textXPos = -r.x();
|
---|
377 | br.moveTopLeft( QPoint( -br.width()/2, -br.height()/2 ) );
|
---|
378 | break;
|
---|
379 | case Image:
|
---|
380 | r = pix.rect();
|
---|
381 | break;
|
---|
382 | case Picture:
|
---|
383 | // ### need QPicture::boundingRect()
|
---|
384 | r = QRect(0,0,1000,1000);
|
---|
385 | break;
|
---|
386 | }
|
---|
387 | r.moveTopLeft( QPoint(-r.width()/2, -r.height()/2) );
|
---|
388 | // compute union of new and old rect
|
---|
389 | // the resulting rectangle will cover what is already displayed
|
---|
390 | // and have room for the new text/pixmap
|
---|
391 | eraseRect = eraseRect.unite( mtx.map(r) );
|
---|
392 | eraseRect.moveBy( -1, -1 ); // add border for matrix round off
|
---|
393 | eraseRect.setSize( QSize( eraseRect.width() + 2,eraseRect.height() + 2 ) );
|
---|
394 | int pw = QMIN(eraseRect.width(),width());
|
---|
395 | int ph = QMIN(eraseRect.height(),height());
|
---|
396 | QPixmap pm( pw, ph ); // off-screen drawing pixmap
|
---|
397 | pm.fill( backgroundColor() );
|
---|
398 |
|
---|
399 | p.begin( &pm );
|
---|
400 | um.translate( pw/2, ph/2 ); // 0,0 is center
|
---|
401 | um = mtx * um;
|
---|
402 | p.setWorldMatrix( um );
|
---|
403 | switch ( mode() ) {
|
---|
404 | case Text:
|
---|
405 | p.setFont( font() ); // use widget font
|
---|
406 | p.drawText( r.left() + textXPos, r.top() + textYPos, text );
|
---|
407 | #if 0
|
---|
408 | p.setPen( red );
|
---|
409 | p.drawRect( br );
|
---|
410 | #endif
|
---|
411 | break;
|
---|
412 | case Image:
|
---|
413 | p.drawPixmap( -pix.width()/2, -pix.height()/2, pix );
|
---|
414 | //QPixmap rotated = pix.xForm(mtx);
|
---|
415 | //bitBlt( &pm, pm.width()/2 - rotated.width()/2,
|
---|
416 | //pm.height()/2 - rotated.height()/2, &rotated );
|
---|
417 | break;
|
---|
418 | case Picture:
|
---|
419 | // ### need QPicture::boundingRect()
|
---|
420 | p.scale(0.25,0.25);
|
---|
421 | p.translate(-230,-180);
|
---|
422 | p.drawPicture( picture );
|
---|
423 | }
|
---|
424 | p.end();
|
---|
425 |
|
---|
426 | int xpos = width()/2 - pw/2;
|
---|
427 | int ypos = height()/2 - ph/2;
|
---|
428 | bitBlt( this, xpos, ypos, // copy pixmap to widget
|
---|
429 | &pm, 0, 0, -1, -1 );
|
---|
430 | eraseRect = mtx.map( r );
|
---|
431 | }
|
---|
432 |
|
---|
433 |
|
---|
434 | /*
|
---|
435 | Grand unifying widget, putting ShowXForm and XFormControl
|
---|
436 | together.
|
---|
437 | */
|
---|
438 |
|
---|
439 | class XFormCenter : public QHBox, public ModeNames
|
---|
440 | {
|
---|
441 | Q_OBJECT
|
---|
442 | public:
|
---|
443 | XFormCenter( QWidget *parent=0, const char *name=0 );
|
---|
444 | public slots:
|
---|
445 | void setFont( const QFont &f ) { sx->setFont( f ); }
|
---|
446 | void newMode( int );
|
---|
447 | private:
|
---|
448 | ShowXForm *sx;
|
---|
449 | XFormControl *xc;
|
---|
450 | };
|
---|
451 |
|
---|
452 | void XFormCenter::newMode( int m )
|
---|
453 | {
|
---|
454 | static bool first_i = TRUE;
|
---|
455 | static bool first_p = TRUE;
|
---|
456 |
|
---|
457 | if ( sx->mode() == m )
|
---|
458 | return;
|
---|
459 | if ( m == Image && first_i ) {
|
---|
460 | first_i = FALSE;
|
---|
461 | QPixmap pm;
|
---|
462 | if ( pm.load( "image.any" ) )
|
---|
463 | sx->setPixmap( pm );
|
---|
464 | return;
|
---|
465 | }
|
---|
466 | if ( m == Picture && first_p ) {
|
---|
467 | first_p = FALSE;
|
---|
468 | QPicture p;
|
---|
469 | if (p.load( "picture.any" ))
|
---|
470 | sx->setPicture( p );
|
---|
471 | return;
|
---|
472 | }
|
---|
473 | sx->setMode(m);
|
---|
474 | }
|
---|
475 |
|
---|
476 | XFormCenter::XFormCenter( QWidget *parent, const char *name )
|
---|
477 | : QHBox( parent, name )
|
---|
478 | {
|
---|
479 | QFont f( "Charter", 36, QFont::Bold );
|
---|
480 |
|
---|
481 | xc = new XFormControl( f, this );
|
---|
482 | sx = new ShowXForm( f, this );
|
---|
483 | setStretchFactor(sx,1);
|
---|
484 | xc->setFrameStyle( QFrame::Panel | QFrame::Raised );
|
---|
485 | xc->setLineWidth( 2 );
|
---|
486 | connect( xc, SIGNAL(newText(const QString&)), sx,
|
---|
487 | SLOT(setText(const QString&)) );
|
---|
488 | connect( xc, SIGNAL(newMatrix(QWMatrix)),
|
---|
489 | sx, SLOT(setMatrix(QWMatrix)) );
|
---|
490 | connect( xc, SIGNAL(newFont(const QFont&)), sx,
|
---|
491 | SLOT(setFont(const QFont&)) );
|
---|
492 | connect( xc, SIGNAL(newMode(int)), SLOT(newMode(int)) );
|
---|
493 | sx->setText( "Troll" );
|
---|
494 | newMode( Image );
|
---|
495 | sx->setMatrix(xc->matrix());
|
---|
496 | }
|
---|
497 |
|
---|
498 |
|
---|
499 | int main( int argc, char **argv )
|
---|
500 | {
|
---|
501 | QApplication a( argc, argv );
|
---|
502 |
|
---|
503 | XFormCenter *xfc = new XFormCenter;
|
---|
504 |
|
---|
505 | a.setMainWidget( xfc );
|
---|
506 | xfc->setCaption("Qt Example - XForm");
|
---|
507 | xfc->show();
|
---|
508 | return a.exec();
|
---|
509 | }
|
---|
510 |
|
---|
511 | #include "xform.moc" // include metadata generated by the moc
|
---|