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