Fixed cstring include in kdTree.h, some infinity and comment stuff.
[fic.git] / gui.cpp
blobbb1db98236393649466cfa8d38917ba77315b8b5
1 #include <sstream> // needed for ::load and ::rezoom
3 #include "gui.h"
4 #include "modules/colorModel.h" // using color coefficients for RGB->gray conversion
6 using namespace std;
8 //// Non-member functions
9 static vector<double> getColorPSNR(const QImage &a,const QImage &b) {
10 int width= a.width(), height= a.height();
11 int x, y;
12 QRgb *line1, *line2;
13 int sum, sumR, sumG, sumB;
14 sum= sumR= sumG= sumB= 0;
15 for (y=0; y<height; ++y) {
16 line1= (QRgb*)a.scanLine(y);
17 line2= (QRgb*)b.scanLine(y);
18 for (x=0; x<width; ++x) {
19 sum+= sqr( getGray(line1[x]) - getGray(line2[x]) );
20 sumR+= sqr( qRed(line1[x]) - qRed(line2[x]) );
21 sumG+= sqr( qGreen(line1[x]) - qGreen(line2[x]) );
22 sumB+= sqr( qBlue(line1[x]) - qBlue(line2[x]) );
25 vector<double> result(4);
26 result[0]= sumR;
27 result[1]= sumG;
28 result[2]= sumB;
29 result[3]= sum;
30 double mul= double(width*height) * double(sqr(255));
31 for (vector<double>::iterator it=result.begin(); it!=result.end(); ++it)
32 *it= 10.0 * log10(mul / *it);
33 return result;
35 static QString getPSNRmessage(const QImage &img1,const QImage &img2) {
36 vector<double> psnr= getColorPSNR(img1,img2);
37 return QObject::tr("gray PSNR: %3 dB\nR,G,B: %4,%5,%6 dB") .arg(psnr[3],0,'f',2)
38 .arg(psnr[0],0,'f',2) .arg(psnr[1],0,'f',2) .arg(psnr[2],0,'f',2);
42 //// Public members
43 ImageViewer::ImageViewer(QApplication &app)
44 : modules_settings( IRoot::newCompatibleModule() ), modules_encoding(0)
45 , zoom(0), lastPath(QDir::current().filePath("x"))
46 , readAct(this), writeAct(this), compareAct(this), exitAct(this)
47 , settingsAct(this), encodeAct(this), saveAct(this)
48 , loadAct(this), clearAct(this), iterateAct(this), zoomIncAct(this), zoomDecAct(this) {
49 // try to load guessed language translation
50 if ( translator.load( "lang-"+QLocale::system().name(), app.applicationDirPath() ) )
51 app.installTranslator(&translator);
52 // create a scrolling area with a label for viewing images
53 imageLabel= new QLabel(this);
54 imageLabel->setBackgroundRole(QPalette::Dark);
55 imageLabel->setSizePolicy(QSizePolicy::Ignored,QSizePolicy::Ignored);
57 QScrollArea *scrollArea= new QScrollArea(this);
58 scrollArea->setBackgroundRole(QPalette::Dark);
59 scrollArea->setWidget(imageLabel);
60 setCentralWidget(scrollArea);
62 setStatusBar(new QStatusBar(this));
64 createActions();
65 createMenus();
66 translateUi();
67 updateActions();
69 resize(800,600);
72 //// Private methods
73 void ImageViewer::createActions() {
74 // create all actions and connect them to the appropriate slots
75 #define A(name) \
76 aConnect( &name##Act, SIGNAL(triggered()), this, SLOT(name()) );
77 #define AS(name,signal) \
78 aConnect( &name##Act, SIGNAL(triggered()), this, SLOT(signal()) );
79 A(read)
80 A(write)
81 A(compare)
82 AS(exit,close)
84 A(settings)
85 A(encode)
86 A(save)
88 A(load)
89 A(clear)
90 A(iterate)
91 A(zoomInc)
92 A(zoomDec)
94 #undef A
95 #undef AS
97 void ImageViewer::createMenus() {
98 imageMenu.addAction(&readAct);
99 imageMenu.addAction(&writeAct);
100 imageMenu.addSeparator();
101 imageMenu.addAction(&compareAct);
102 imageMenu.addSeparator();
103 imageMenu.addAction(&exitAct);
105 compMenu.addAction(&settingsAct);
106 compMenu.addAction(&encodeAct);
107 compMenu.addAction(&saveAct);
109 decompMenu.addAction(&loadAct);
110 decompMenu.addAction(&clearAct);
111 decompMenu.addAction(&iterateAct);
112 decompMenu.addSeparator();
113 decompMenu.addAction(&zoomIncAct);
114 decompMenu.addAction(&zoomDecAct);
116 menuBar()->addMenu(&imageMenu);
117 menuBar()->addMenu(&compMenu);
118 menuBar()->addMenu(&decompMenu);
119 //menuBar()->addMenu(langMenu);
120 //menuBar()->addMenu(helpMenu);
122 void ImageViewer::translateUi() {
123 setWindowTitle(tr("Fractal Image Compressor"));
124 // set action names and shortcuts
125 #define A(name,shortcut,text) \
126 name##Act.setText(tr(text)); \
127 name##Act.setShortcut(tr(shortcut));
128 A(read, "Ctrl+R", "Read...")
129 A(write, "Ctrl+W", "Write...")
130 A(compare, "", "Compare to...")
131 A(exit, "Ctrl+Q", "Quit")
133 A(settings, "", "Settings")
134 A(encode, " ", "Start encoding")
135 A(save, "Ctrl+S", "Save FIC...")
137 A(load, "Ctrl+L", "Load FIC...")
138 A(clear, "Ctrl+C", "Clear image")
139 A(iterate, "Ctrl+I", "Iterate image")
140 A(zoomInc, "Ctrl++", "Increase zoom")
141 A(zoomDec, "Ctrl+-", "Decrease zoom")
142 #undef A
144 // set the tiles of menu items
145 #define M(name,title) \
146 name##Menu.setTitle(tr(title));
147 M(image, "&Image");
148 M(comp, "&Compression");
149 M(decomp, "&Decompression");
150 #undef M
152 void ImageViewer::updateActions() {
153 bool pixmapOk= imageLabel->pixmap();
154 IRoot::Mode mode= modules_encoding ? modules_encoding->getMode() : IRoot::Clear;
156 //readAct.setEnabled(true);
157 writeAct.setEnabled(pixmapOk);
158 compareAct.setEnabled(pixmapOk);
159 //exitAct.setEnabled(true);
161 //settingsAct.setEnabled(true);
162 encodeAct.setEnabled(pixmapOk);
163 saveAct.setEnabled( mode != IRoot::Clear );
165 //loadAct.setEnabled(true);
166 clearAct.setEnabled ( mode != IRoot::Clear );
167 iterateAct.setEnabled( mode != IRoot::Clear );
168 zoomIncAct.setEnabled( mode != IRoot::Clear && zoom<3 );
169 zoomDecAct.setEnabled( mode != IRoot::Clear && zoom>0 );
172 //// Private slots
173 void ImageViewer::read() {
174 // get the file name
175 QString fname= QFileDialog::getOpenFileName( this, tr("Read image file")
176 , lastDir(), tr("PNG images (*.png)\nAll files (*.*)") );
177 if (fname.isEmpty())
178 // no file selected
179 return;
180 lastPath.setPath(fname);
181 // try to load, check for errors
182 QImage image(fname);
183 if (image.isNull()) {
184 QMessageBox::information( this, tr("Error"), tr("Cannot open %1.").arg(fname) );
185 return;
187 // convert to 24-bits
188 if ( image.format() != QImage::Format_RGB32 )
189 image= image.convertToFormat(QImage::Format_RGB32);
190 // display it
191 changePixmap(QPixmap::fromImage(image));
192 updateActions();
194 void ImageViewer::write() {
195 // get the file name
196 QString fname= QFileDialog::getSaveFileName( this, tr("Write image file")
197 , lastDir(), tr("PNG images (*.png)\nAll files (*.*)") );
198 if (fname.isEmpty())
199 return;
200 lastPath.setPath(fname);
201 // try to save the image
202 if ( !imageLabel->pixmap()->save(fname) ) {
203 QMessageBox::information( this, tr("Error"), tr("Cannot write file %1.").arg(fname) );
204 return;
206 updateActions();
208 void ImageViewer::compare() {
209 // let the user choose a file
210 QString fname= QFileDialog::getOpenFileName
211 ( this, tr("Compare to image"), lastDir()
212 , tr("PNG images (*.png)\nJFIF images (*.jpg *.jpeg)\nAll files (*.*)") );
213 if (fname.isEmpty())
214 return;
215 lastPath.setPath(fname);
216 // open the file as an image, check it's got the same dimensions as the diplayed one
217 QImage image(fname);
218 if ( image.format() != QImage::Format_RGB32 )
219 image= image.convertToFormat(QImage::Format_RGB32);
220 if (image.isNull()) {
221 QMessageBox::information( this, tr("Error"), tr("Cannot open %1.").arg(fname) );
222 return;
224 if ( image.width()!=imageLabel->pixmap()->width()
225 || image.height()!=imageLabel->pixmap()->height() ) {
226 QMessageBox::information
227 ( this, tr("Error"), tr("Images don't have the same dimensions.").arg(fname) );
228 return;
230 // compute the PSNRs and display them
231 QString message= getPSNRmessage( image, imageLabel->pixmap()->toImage() );
232 QMessageBox::information( this, tr("Comparison"), message );
234 void ImageViewer::settings() {
235 IRoot *newSettings= modules_settings->clone();
236 SettingsDialog dialog(this,newSettings);
237 newSettings= dialog.getSettings();
238 if ( dialog.exec() )
239 // the dialog wasn't cancelled -> swap with the current and new settings
240 swap(newSettings,modules_settings);
241 delete newSettings;
243 void ImageViewer::encode() {
244 EncodingProgress::create(this);
246 void ImageViewer::encDone() {
247 int encMsecs;
248 IRoot *modules_encoded= EncodingProgress::destroy(encMsecs);
250 if (modules_encoded) { // encoding successful - iterate the image and display some info
251 zoom= 0;
252 // replace the old state
253 delete modules_encoding;
254 modules_encoding= modules_encoded;
255 // decode the image
256 QImage beforeImg= modules_encoding->toImage();
258 QTime decTime;
259 decTime.start();
260 modules_encoding->decodeAct(MTypes::Clear);
261 modules_encoding->decodeAct(MTypes::Iterate,AutoIterationCount);
262 int decMsecs= decTime.elapsed();
264 QImage afterImg= modules_encoding->toImage();
265 changePixmap( QPixmap::fromImage(afterImg) );
266 // show some info
267 QString message= tr("Time to encode: %1 seconds\nTime to decode: %2 seconds\n")
268 .arg(encMsecs/1000.0) .arg(decMsecs/1000.0) + getPSNRmessage(beforeImg,afterImg);
269 QMessageBox::information( this, tr("encoded"), message );
270 encData.clear();
273 updateActions();
275 void ImageViewer::save() {
276 // get a filename to suggest
277 QFileInfo finfo(lastPath.path());
278 QString fname= finfo.dir().filePath( finfo.completeBaseName() + tr(".fic") );
279 fname= QFileDialog::getSaveFileName
280 ( this, tr("Save encoded image"), fname, tr("FIC images (*.fic)") );
281 if (fname.isEmpty())
282 return;
283 lastPath.setPath(fname);
284 if ( !modules_encoding->toFile( fname.toStdString().c_str() ) )
285 QMessageBox::information( this, tr("Error"), tr("Cannot write file %1.").arg(fname) );
287 void ImageViewer::load() {
288 QString fname= QFileDialog::getOpenFileName
289 ( this, tr("Load encoded image"), lastDir(), tr("FIC images (*.fic)") );
290 if (fname.isEmpty())
291 return;
292 lastPath.setPath(fname);
293 // IRoot needs to be loaded from cleared state
294 IRoot *modules_old= modules_encoding;
295 modules_encoding= modules_settings->clone(Module::ShallowCopy);
297 string decData;
298 bool error= !file2string( fname.toStdString().c_str(), decData );
299 if (!error) {
300 stringstream stream(decData);
301 error= !modules_encoding->fromStream( stream, zoom );
304 if (error) {
305 QMessageBox::information( this, tr("Error"), tr("Cannot load file %1.").arg(fname) );
306 swap(modules_encoding,modules_old);
307 } else { // loading was successful
308 swap(encData,decData);
309 modules_encoding->decodeAct(Clear);
310 modules_encoding->decodeAct(MTypes::Iterate,AutoIterationCount);
311 changePixmap( QPixmap::fromImage(modules_encoding->toImage()) );
312 updateActions();
315 delete modules_old;
317 void ImageViewer::clear() {
318 modules_encoding->decodeAct(Clear);
319 changePixmap( QPixmap::fromImage(modules_encoding->toImage()) );
320 updateActions();
322 void ImageViewer::iterate() {
323 modules_encoding->decodeAct(Iterate);
324 changePixmap( QPixmap::fromImage(modules_encoding->toImage()) );
325 updateActions();
327 void ImageViewer::zoomInc() {
328 ++zoom;
329 if (!rezoom())
330 --zoom, QMessageBox::information( this, tr("Error"), tr("Zooming failed.") );
332 void ImageViewer::zoomDec() {
333 --zoom;
334 ASSERT(zoom>=0);
335 if (!rezoom())
336 ++zoom, QMessageBox::information( this, tr("Error"), tr("Zooming failed.") );
339 bool ImageViewer::rezoom() {
340 // create a stream that contains the "saved image"
341 stringstream stream;
342 if ( encData.empty() ) { // cache is empty - we have to create it (save the image)
343 if ( !modules_encoding->toStream(stream) )
344 return false;
345 encData= stream.str();
346 } else // reusing the cache
347 stream.str(encData);
348 // reload the image from the stream
349 IRoot *newRoot= modules_settings->clone(Module::ShallowCopy);
350 if ( newRoot->fromStream(stream,zoom) ) {
351 delete modules_encoding;
352 modules_encoding= newRoot;
353 } else {
354 delete newRoot;
355 return false;
357 // successfully reloaded -> auto-iterate the image and show it
358 modules_encoding->decodeAct(MTypes::Clear);
359 modules_encoding->decodeAct(MTypes::Iterate,AutoIterationCount);
360 changePixmap( QPixmap::fromImage(modules_encoding->toImage()) );
361 updateActions();
362 return true;
366 //// SettingsDialog class
368 SettingsDialog::SettingsDialog( ImageViewer *parent, IRoot *settingsHolder )
369 : QDialog(parent,Qt::Dialog), settings(settingsHolder) {
370 setWindowTitle(tr("Compression settings"));
371 setModal(true);
372 // create a grid layout for the dialog
373 QGridLayout *layout= new QGridLayout;
374 setLayout(layout);
375 // add a tree widget
376 this->treeWidget= new QTreeWidget(this);
377 treeWidget->setHeaderLabel(tr("Modules"));
378 layout->addWidget(treeWidget,0,0);
379 // add a group-box to display settings of a module
380 this->setBox= new QGroupBox(this);
381 layout->addWidget(setBox,0,1);
382 // add a load/save button-box and connect it to a slot of this dialog
383 this->loadSaveButtons= new QDialogButtonBox
384 ( QDialogButtonBox::Open|QDialogButtonBox::Save, Qt::Horizontal, this );
385 aConnect( loadSaveButtons, SIGNAL(clicked(QAbstractButton*))
386 , this, SLOT(loadSaveClick(QAbstractButton*)) );
387 layout->addWidget(loadSaveButtons,1,0,Qt::AlignLeft);
388 // add a button-box and connect the clicking actions
389 QDialogButtonBox *buttons= new QDialogButtonBox
390 ( QDialogButtonBox::Ok|QDialogButtonBox::Cancel, Qt::Horizontal, this );
391 layout->addWidget(buttons,1,1); // the right-bottom cell
392 aConnect( buttons, SIGNAL(accepted()), this, SLOT(accept()) );
393 aConnect( buttons, SIGNAL(rejected()), this, SLOT(reject()) );
394 // create the tree
395 QTreeWidgetItem *treeRoot= new QTreeWidgetItem;
396 treeWidget->addTopLevelItem(treeRoot);
397 treeRoot->setText( 0, tr("Root") );
399 aConnect( treeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*))
400 , this, SLOT(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)) );
402 initialize();
404 void SettingsDialog::initialize() {
405 QTreeWidgetItem *treeRoot= treeWidget->topLevelItem(0);
406 ASSERT( treeRoot && settings && setBox );
408 clearQtContainer( treeRoot->takeChildren() );
410 settings->adjustSettings(-1,treeRoot,setBox);
411 treeWidget->setCurrentItem(treeRoot);
412 treeWidget->expandAll();
414 void SettingsDialog::currentItemChanged(QTreeWidgetItem *curItem,QTreeWidgetItem*) {
415 // get the module that should show its settings
416 ASSERT(curItem);
417 Module *curMod= static_cast<Module*>( curItem->data(0,Qt::UserRole).value<void*>() );
418 ASSERT(curMod);
419 // clear the settings box and make the module fill it
420 clearQtContainer( setBox->children() );
421 setBox->setTitle( tr("%1 module settings") .arg(curMod->info().name) );
422 curMod->adjustSettings(-1,0,setBox);
424 void SettingsDialog::settingChanges(int which) {
425 QTreeWidgetItem *tree= treeWidget->currentItem();
426 Module *module= static_cast<Module*>( tree->data(0,Qt::UserRole).value<void*>() );
427 module->adjustSettings(which,tree,setBox);
429 void SettingsDialog::loadSaveClick(QAbstractButton *button) {
430 QDialogButtonBox::StandardButton test= loadSaveButtons->standardButton(button);
431 switch ( test ) {
432 case QDialogButtonBox::Open: { // open-button has been clicked
433 // ask for the name to load from
434 QString fname= QFileDialog::getOpenFileName( this, tr("Load settings file")
435 , parentViewer().lastDir(), tr("FIC settings (*.fms)") );
436 if (fname.isEmpty())
437 return;
438 // try to load the settings
439 IRoot *newSettings= settings->clone(Module::ShallowCopy);
440 if ( newSettings->allSettingsFromFile(fname.toStdString().c_str()) ) {
441 delete settings;
442 settings= newSettings;
443 initialize();
444 } else {
445 QMessageBox::information( this, tr("Error")
446 , tr("Cannot load settings from %1.").arg(fname) );
447 delete newSettings;
449 } break;
450 case QDialogButtonBox::Save: { // save-button has been clicked
451 // ask for the name to save in
452 QString fname= QFileDialog::getSaveFileName( this, tr("Save settings file")
453 , parentViewer().lastDir(), tr("FIC settings (*.fms)") );
454 if (fname.isEmpty())
455 return;
456 // try to save the settings
457 if ( !settings->allSettingsToFile(fname.toStdString().c_str()) )
458 QMessageBox::information( this, tr("Error")
459 , tr("Cannot save settings into %1.").arg(fname) );
460 } break;
461 default:
462 ASSERT(false);
466 //// GUI-related Module members
467 namespace NOSPACE {
468 QWidget* newSettingsWidget(Module::ChoiceType type,QWidget *parent) {
469 QWidget *result=0;
470 switch (type) {
471 case Module::Int:
472 case Module::IntLog2:
473 result= new QSpinBox(parent);
474 break;
475 case Module::Float:
476 result= new QDoubleSpinBox(parent);
477 break;
478 case Module::ModuleCombo:
479 case Module::Combo:
480 result= new QComboBox(parent);
481 break;
482 default:
483 ASSERT(false);
484 }// switch
485 return result;
488 void Module::adjustSettings(int which,QTreeWidgetItem *myTree,QGroupBox *setBox) {
489 if (which<0) {
490 // no change has really happened
491 ASSERT(which==-1);
492 if (myTree) {
493 // I should create the subtree -> store this-pointer as data
494 ASSERT( myTree->childCount() == 0 );
495 myTree->setData( 0, Qt::UserRole, QVariant::fromValue((void*)this) );
496 if (!settings) {
497 myTree->setFlags(0);
498 return;
500 // find child modules and make them create their subtrees
501 const SettingTypeItem *setType= info().setType;
502 const SettingItem *setItem= settings;
503 for (; setType->type.type!=Stop; ++setItem,++setType)
504 if ( setType->type.type == ModuleCombo ) {
505 // it is a module -> label its subtree-root and recurse (polymorphically)
506 ASSERT(setItem->m);
507 if ( !setItem->m->info().setLength )
508 continue; // skipping modules with no settings
509 QTreeWidgetItem *childTree= new QTreeWidgetItem(myTree);
510 childTree->setText( 0, QObject::tr(setType->label) );
511 setItem->m->adjustSettings( -1, childTree, 0 );
514 int setLength= info().setLength;
515 if ( setBox && setLength ) {
516 // fill the group-box
517 QGridLayout *layout= new QGridLayout(setBox);
518 setBox->setLayout(layout);
519 const SettingTypeItem *typeItem= info().setType;
520 for (int i=0; i<setLength; ++i,++typeItem) {
521 // add a line - one option
522 QString desc(typeItem->desc);
523 QLabel *label= new QLabel( typeItem->label, setBox );
524 label->setToolTip(desc);
526 QWidget *widget= newSettingsWidget( typeItem->type.type, setBox );
527 settingsType2widget( widget, *typeItem );
528 settings2widget( widget, i );
529 widget->setToolTip(desc);
530 label->setBuddy(widget);
531 layout->addWidget( label, i, 0 );
532 layout->addWidget( widget, i, 1 );
534 SignalChanger *changer= new SignalChanger(i,widget,typeItem->type.type);
535 aConnect( changer, SIGNAL(notify(int)) // assuming the setBox's
536 , setBox->parent(), SLOT(settingChanges(int)) ); // parent is SettingsDialog
537 }// for loop
538 }// filling the box
539 } else {
540 // which>=0... a setting has changed -> get the change from the widget
541 ASSERT( which < info().setLength );
542 QLayoutItem *item= setBox->layout()->itemAt(2*which+1);
543 ASSERT(item);
544 widget2settings( item->widget() , which );
545 // handle module-type settings
546 const SettingTypeItem &setType= info().setType[which];
547 if ( setType.type.type == ModuleCombo ) {
548 ASSERT(myTree);
549 // get the new module id and check whether it has really changed
550 SettingItem &setItem= settings[which];
551 int newId= (*setType.type.data.compatIDs)[setItem.val.i];
552 if ( newId == setItem.m->info().id )
553 return;
554 // replace the child module
555 clearQtContainer( myTree->takeChildren() );
556 delete setItem.m;
557 setItem.m= ModuleFactory::newModule(newId);
558 adjustSettings( -1, myTree, 0 );
560 // update module defaults
561 ModuleFactory::changeDefaultSettings(*this);
564 void Module::widget2settings(const QWidget *widget,int which) {
565 ASSERT( 0<=which && which<info().setLength );
566 switch( info().setType[which].type.type ) {
567 case Int:
568 case IntLog2:
569 settings[which].val.i= debugCast<const QSpinBox*>(widget)->value();
570 break;
571 case Float:
572 settings[which].val.f= debugCast<const QDoubleSpinBox*>(widget)->value();
573 break;
574 case ModuleCombo:
575 case Combo:
576 settings[which].val.i= debugCast<const QComboBox*>(widget)->currentIndex();
577 break;
578 default:
579 ASSERT(false);
580 }// switch
582 void Module::settings2widget(QWidget *widget,int which) {
583 ASSERT( 0<=which && which<info().setLength );
584 switch( info().setType[which].type.type ) {
585 case Int:
586 case IntLog2:
587 debugCast<QSpinBox*>(widget)->setValue( settings[which].val.i );
588 break;
589 case Float:
590 debugCast<QDoubleSpinBox*>(widget)->setValue( settings[which].val.f );
591 break;
592 case ModuleCombo:
593 case Combo:
594 debugCast<QComboBox*>(widget)->setCurrentIndex( settings[which].val.i );
595 break;
596 default:
597 ASSERT(false);
598 }// switch
600 namespace NOSPACE {
601 class ItemAdder {
602 QComboBox *box;
603 public:
604 ItemAdder(QWidget *widget): box( debugCast<QComboBox*>(widget) ) {}
605 void operator()(int i) {
606 const Module::TypeInfo &info= ModuleFactory::prototype(i).info();
607 box->addItem(info.name);
608 box->setItemData( box->count()-1, QObject::tr(info.desc), Qt::ToolTipRole );
612 void Module::settingsType2widget(QWidget *widget,const SettingTypeItem &typeItem) {
613 ASSERT(widget);
614 const SettingType &type= typeItem.type;
616 switch(type.type) {
617 case IntLog2:
618 debugCast<QSpinBox*>(widget)->setPrefix(QObject::tr("2^"));
619 // fall through
620 case Int: {
621 debugCast<QSpinBox*>(widget)->setRange( type.data.i[0], type.data.i[1] );
622 // try to guess a reasonable step for the spin-box
623 int range= type.data.i[1]-type.data.i[0];
624 int step= (int)exp10(floor(log10(range/5)));
625 if (!(step>0))
626 step= 1;
627 debugCast<QSpinBox*>(widget)->setSingleStep(step);
628 break;
630 case Float: {
631 debugCast<QDoubleSpinBox*>(widget)->setRange( type.data.f[0], type.data.f[1] );
632 // try to guess a reasonable step for the spin-box
633 float range= type.data.f[1]-type.data.f[0];
634 debugCast<QDoubleSpinBox*>(widget)->setSingleStep( exp10(floor(log10(range/5))) );
635 break;
637 case ModuleCombo: {
638 const vector<int> &modules= *typeItem.type.data.compatIDs;
639 for_each( modules, ItemAdder(widget) );
640 break;
642 case Combo:
643 debugCast<QComboBox*>(widget)->addItems( QString(type.data.text).split('\n') );
644 break;
645 default:
646 ASSERT(false);
647 }// switch
651 #ifndef NDEBUG
652 void ImageViewer::mousePressEvent(QMouseEvent *event) {
653 // check the event, get the clicking point coordinates relative to the image
654 if ( !event || !modules_encoding
655 || modules_encoding->getMode() == IRoot::Clear)
656 return;
657 const QPoint click= imageLabel->mapFrom( this, event->pos() );
658 // get the image
659 QPixmap pixmap= *imageLabel->pixmap();
660 if ( click.isNull() )
661 return;
663 static QWidget *debugWidget= 0;
664 delete debugWidget;
665 debugWidget= modules_encoding->debugModule(pixmap,click);
666 debugWidget->setParent(this);
667 debugWidget->setWindowFlags(Qt::Dialog);
668 debugWidget->show();
670 changePixmap(pixmap);
672 #endif
675 EncodingProgress *EncodingProgress::instance= 0;