"Fossies" - the Fresh Open Source Software Archive

Member "stella-6.0.2/src/gui/DeveloperDialog.cxx" (11 Oct 2019, 42527 Bytes) of package /linux/privat/stella-6.0.2-src.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "DeveloperDialog.cxx" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 6.0.1_vs_6.0.2.

    1 //============================================================================
    2 //
    3 //   SSSS    tt          lll  lll
    4 //  SS  SS   tt           ll   ll
    5 //  SS     tttttt  eeee   ll   ll   aaaa
    6 //   SSSS    tt   ee  ee  ll   ll      aa
    7 //      SS   tt   eeeeee  ll   ll   aaaaa  --  "An Atari 2600 VCS Emulator"
    8 //  SS  SS   tt   ee      ll   ll  aa  aa
    9 //   SSSS     ttt  eeeee llll llll  aaaaa
   10 //
   11 // Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony
   12 // and the Stella Team
   13 //
   14 // See the file "License.txt" for information on usage and redistribution of
   15 // this file, and for a DISCLAIMER OF ALL WARRANTIES.
   16 //============================================================================
   17 
   18 #include "bspf.hxx"
   19 #include "OSystem.hxx"
   20 #include "Joystick.hxx"
   21 #include "Paddles.hxx"
   22 #include "PointingDevice.hxx"
   23 #include "SaveKey.hxx"
   24 #include "AtariVox.hxx"
   25 #include "Settings.hxx"
   26 #include "EditTextWidget.hxx"
   27 #include "PopUpWidget.hxx"
   28 #include "RadioButtonWidget.hxx"
   29 #include "ColorWidget.hxx"
   30 #include "TabWidget.hxx"
   31 #include "Widget.hxx"
   32 #include "Font.hxx"
   33 #include "Console.hxx"
   34 #include "TIA.hxx"
   35 #include "OSystem.hxx"
   36 #include "StateManager.hxx"
   37 #include "RewindManager.hxx"
   38 #include "M6502.hxx"
   39 #ifdef DEBUGGER_SUPPORT
   40   #include "Debugger.hxx"
   41   #include "CartDebug.hxx"
   42   #include "DebuggerDialog.hxx"
   43 #endif
   44 #include "DeveloperDialog.hxx"
   45 
   46 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
   47 DeveloperDialog::DeveloperDialog(OSystem& osystem, DialogContainer& parent,
   48                                  const GUI::Font& font, int max_w, int max_h)
   49   : Dialog(osystem, parent, font, "Developer settings")
   50 {
   51   const int VGAP = 4;
   52   const int lineHeight = font.getLineHeight(),
   53     fontWidth = font.getMaxCharWidth(),
   54     buttonHeight = font.getLineHeight() + 4;
   55   int xpos, ypos;
   56 
   57   // Set real dimensions
   58   _w = std::min(53 * fontWidth + 10, max_w);
   59   _h = std::min(15 * (lineHeight + VGAP) + 14 + _th, max_h);
   60 
   61   // The tab widget
   62   xpos = 2; ypos = 4;
   63   myTab = new TabWidget(this, font, xpos, ypos + _th, _w - 2 * xpos, _h - _th - buttonHeight - 16 - ypos);
   64   addTabWidget(myTab);
   65 
   66   addEmulationTab(font);
   67   addVideoTab(font);
   68   addTimeMachineTab(font);
   69   addDebuggerTab(font);
   70 
   71   WidgetArray wid;
   72   addDefaultsOKCancelBGroup(wid, font);
   73   addBGroupToFocusList(wid);
   74 
   75   // Activate the first tab
   76   myTab->setActiveTab(0);
   77 }
   78 
   79 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
   80 void DeveloperDialog::addEmulationTab(const GUI::Font& font)
   81 {
   82   const int HBORDER = 10;
   83   const int INDENT = 16+4;
   84   const int VBORDER = 8;
   85   const int VGAP = 4;
   86   int ypos = VBORDER;
   87   int lineHeight = font.getLineHeight();
   88   WidgetArray wid;
   89   VariantList items;
   90   int tabID = myTab->addTab("Emulation");
   91 
   92   // settings set
   93   mySettingsGroup0 = new RadioButtonGroup();
   94   RadioButtonWidget* r = new RadioButtonWidget(myTab, font, HBORDER, ypos + 1,
   95                                                "Player settings", mySettingsGroup0, kPlrSettings);
   96   wid.push_back(r);
   97   ypos += lineHeight + VGAP;
   98   r = new RadioButtonWidget(myTab, font, HBORDER, ypos + 1,
   99                             "Developer settings", mySettingsGroup0, kDevSettings);
  100   wid.push_back(r);
  101   ypos += lineHeight + VGAP * 1;
  102 
  103   myFrameStatsWidget = new CheckboxWidget(myTab, font, HBORDER + INDENT * 1, ypos + 1, "Console info overlay");
  104   wid.push_back(myFrameStatsWidget);
  105   ypos += lineHeight + VGAP;
  106 
  107   // 2600/7800 mode
  108   items.clear();
  109   VarList::push_back(items, "Atari 2600", "2600");
  110   VarList::push_back(items, "Atari 7800", "7800");
  111   int lwidth = font.getStringWidth("Console ");
  112   int pwidth = font.getStringWidth("Atari 2600");
  113 
  114   myConsoleWidget = new PopUpWidget(myTab, font, HBORDER + INDENT * 1, ypos, pwidth, lineHeight, items,
  115                                     "Console ", lwidth, kConsole);
  116   wid.push_back(myConsoleWidget);
  117   ypos += lineHeight + VGAP;
  118 
  119   // Randomize items
  120   myLoadingROMLabel = new StaticTextWidget(myTab, font, HBORDER + INDENT*1, ypos + 1, "When loading a ROM:");
  121   wid.push_back(myLoadingROMLabel);
  122   ypos += lineHeight + VGAP;
  123 
  124   myRandomBankWidget = new CheckboxWidget(myTab, font, HBORDER + INDENT * 2, ypos + 1,
  125                                           "Random startup bank");
  126   wid.push_back(myRandomBankWidget);
  127   ypos += lineHeight + VGAP;
  128 
  129   // Randomize RAM
  130   myRandomizeRAMWidget = new CheckboxWidget(myTab, font, HBORDER + INDENT * 2, ypos + 1,
  131                                             "Randomize zero-page and extended RAM", kRandRAMID);
  132   wid.push_back(myRandomizeRAMWidget);
  133   ypos += lineHeight + VGAP;
  134 
  135   // Randomize CPU
  136   myRandomizeCPULabel = new StaticTextWidget(myTab, font, HBORDER + INDENT * 2, ypos + 1, "Randomize CPU ");
  137   wid.push_back(myRandomizeCPULabel);
  138 
  139   int xpos = myRandomizeCPULabel->getRight() + 10;
  140   const char* const cpuregs[] = { "SP", "A", "X", "Y", "PS" };
  141   for(int i = 0; i < 5; ++i)
  142   {
  143     myRandomizeCPUWidget[i] = new CheckboxWidget(myTab, font, xpos, ypos + 1,
  144                                            cpuregs[i], kRandCPUID);
  145     wid.push_back(myRandomizeCPUWidget[i]);
  146     xpos += CheckboxWidget::boxSize() + font.getStringWidth("XX") + 20;
  147   }
  148   ypos += lineHeight + VGAP;
  149 
  150   // How to handle undriven TIA pins
  151   myUndrivenPinsWidget = new CheckboxWidget(myTab, font, HBORDER + INDENT * 1, ypos + 1,
  152                                             "Drive unused TIA pins randomly on a read/peek");
  153   wid.push_back(myUndrivenPinsWidget);
  154   ypos += lineHeight + VGAP;
  155 
  156 #ifdef DEBUGGER_SUPPORT
  157   myRWPortBreakWidget = new CheckboxWidget(myTab, font, HBORDER + INDENT * 1, ypos + 1,
  158                                            "Break on reads from write ports");
  159   wid.push_back(myRWPortBreakWidget);
  160   ypos += lineHeight + VGAP;
  161 #endif
  162 
  163   // Thumb ARM emulation exception
  164   myThumbExceptionWidget = new CheckboxWidget(myTab, font, HBORDER + INDENT * 1, ypos + 1,
  165                                               "Fatal ARM emulation error throws exception");
  166   wid.push_back(myThumbExceptionWidget);
  167   ypos += lineHeight + VGAP;
  168 
  169   // AtariVox/SaveKey EEPROM access
  170   myEEPROMAccessWidget = new CheckboxWidget(myTab, font, HBORDER + INDENT * 1, ypos + 1,
  171                                             "Display AtariVox/SaveKey EEPROM R/W access");
  172   wid.push_back(myEEPROMAccessWidget);
  173 
  174   // Add items for tab 0
  175   addToFocusList(wid, myTab, tabID);
  176 }
  177 
  178 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  179 void DeveloperDialog::addVideoTab(const GUI::Font& font)
  180 {
  181   const int HBORDER = 10;
  182   const int INDENT = 16 + 4;
  183   const int VBORDER = 8;
  184   const int VGAP = 4;
  185   int ypos = VBORDER;
  186   int lineHeight = font.getLineHeight();
  187   int fontWidth = font.getMaxCharWidth(), fontHeight = font.getFontHeight();
  188   int lwidth = font.getStringWidth("Intensity ");
  189   int pwidth = font.getMaxCharWidth() * 6;
  190   WidgetArray wid;
  191   VariantList items;
  192   int tabID = myTab->addTab("Video");
  193 
  194   wid.clear();
  195 
  196   // settings set
  197   mySettingsGroup1 = new RadioButtonGroup();
  198   RadioButtonWidget* r = new RadioButtonWidget(myTab, font, HBORDER, ypos + 1,
  199                                                "Player settings", mySettingsGroup1, kPlrSettings);
  200   wid.push_back(r);
  201   ypos += lineHeight + VGAP;
  202   r = new RadioButtonWidget(myTab, font, HBORDER, ypos + 1,
  203                             "Developer settings", mySettingsGroup1, kDevSettings);
  204   wid.push_back(r);
  205   ypos += lineHeight + VGAP * 1;
  206 
  207   // TV jitter effect
  208   myTVJitterWidget = new CheckboxWidget(myTab, font, HBORDER + INDENT * 1, ypos + 1,
  209                                         "Jitter/roll effect", kTVJitter);
  210   wid.push_back(myTVJitterWidget);
  211   myTVJitterRecWidget = new SliderWidget(myTab, font,
  212                                          myTVJitterWidget->getRight() + fontWidth * 3, ypos - 1,
  213                                          "Recovery ", 0, kTVJitterChanged);
  214   myTVJitterRecWidget->setMinValue(1); myTVJitterRecWidget->setMaxValue(20);
  215   myTVJitterRecWidget->setTickmarkInterval(5);
  216   wid.push_back(myTVJitterRecWidget);
  217   myTVJitterRecLabelWidget = new StaticTextWidget(myTab, font,
  218                                                   myTVJitterRecWidget->getRight() + 4,
  219                                                   myTVJitterRecWidget->getTop() + 2,
  220                                                   5 * fontWidth, fontHeight, "");
  221   ypos += lineHeight + VGAP;
  222 
  223   myColorLossWidget = new CheckboxWidget(myTab, font, HBORDER + INDENT * 1, ypos + 1,
  224                                          "PAL color-loss");
  225   wid.push_back(myColorLossWidget);
  226   ypos += lineHeight + VGAP;
  227 
  228   // debug colors
  229   myDebugColorsWidget = new CheckboxWidget(myTab, font, HBORDER + INDENT * 1, ypos + 1,
  230                                            "Debug colors (*)");
  231   wid.push_back(myDebugColorsWidget);
  232   ypos += lineHeight + VGAP + 2;
  233 
  234   items.clear();
  235   VarList::push_back(items, "Red", "r");
  236   VarList::push_back(items, "Orange", "o");
  237   VarList::push_back(items, "Yellow", "y");
  238   VarList::push_back(items, "Green", "g");
  239   VarList::push_back(items, "Purple", "p");
  240   VarList::push_back(items, "Blue", "b");
  241 
  242   static constexpr int dbg_cmds[DEBUG_COLORS] = {
  243     kP0ColourChangedCmd,  kM0ColourChangedCmd,  kP1ColourChangedCmd,
  244     kM1ColourChangedCmd,  kPFColourChangedCmd,  kBLColourChangedCmd
  245   };
  246 
  247   auto createDebugColourWidgets = [&](int idx, const string& desc)
  248   {
  249     int x = HBORDER + INDENT * 1;
  250     myDbgColour[idx] = new PopUpWidget(myTab, font, x, ypos - 1,
  251                                        pwidth, lineHeight, items, desc, lwidth, dbg_cmds[idx]);
  252     wid.push_back(myDbgColour[idx]);
  253     x += myDbgColour[idx]->getWidth() + 10;
  254     myDbgColourSwatch[idx] = new ColorWidget(myTab, font, x, ypos - 1,
  255                                              uInt32(2 * lineHeight), lineHeight);
  256     ypos += lineHeight + VGAP * 1;
  257   };
  258 
  259   createDebugColourWidgets(0, "Player 0  ");
  260   createDebugColourWidgets(1, "Missile 0 ");
  261   createDebugColourWidgets(2, "Player 1  ");
  262   createDebugColourWidgets(3, "Missile 1 ");
  263   createDebugColourWidgets(4, "Playfield ");
  264   createDebugColourWidgets(5, "Ball      ");
  265 
  266   // Add message concerning usage
  267   const GUI::Font& infofont = instance().frameBuffer().infoFont();
  268   ypos = myTab->getHeight() - 5 - fontHeight - infofont.getFontHeight() - 10;
  269   new StaticTextWidget(myTab, infofont, HBORDER, ypos, "(*) Colors identical for player and developer settings");
  270 
  271   // Add items for tab 2
  272   addToFocusList(wid, myTab, tabID);
  273 }
  274 
  275 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  276 void DeveloperDialog::addTimeMachineTab(const GUI::Font& font)
  277 {
  278   const string INTERVALS[NUM_INTERVALS] = {
  279     " 1 frame",
  280     " 3 frames",
  281     "10 frames",
  282     "30 frames",
  283     " 1 second",
  284     " 3 seconds",
  285     "10 seconds"
  286   };
  287   const string INT_SETTINGS[NUM_INTERVALS] = {
  288     "1f",
  289     "3f",
  290     "10f",
  291     "30f",
  292     "1s",
  293     "3s",
  294     "10s"
  295   };
  296   const string HORIZONS[NUM_HORIZONS] = {
  297     " 3 seconds",
  298     "10 seconds",
  299     "30 seconds",
  300     " 1 minute",
  301     " 3 minutes",
  302     "10 minutes",
  303     "30 minutes",
  304     "60 minutes"
  305   };
  306   const string HOR_SETTINGS[NUM_HORIZONS] = {
  307     "3s",
  308     "10s",
  309     "30s",
  310     "1m",
  311     "3m",
  312     "10m",
  313     "30m",
  314     "60m"
  315   };
  316   const int HBORDER = 10;
  317   const int INDENT = 16+4;
  318   const int VBORDER = 8;
  319   const int VGAP = 4;
  320   int ypos = VBORDER;
  321   int lineHeight = font.getLineHeight(),
  322     fontHeight = font.getFontHeight(),
  323     fontWidth = font.getMaxCharWidth(),
  324     lwidth = fontWidth * 11;
  325   WidgetArray wid;
  326   VariantList items;
  327   int tabID = myTab->addTab("Time Machine");
  328 
  329   // settings set
  330   mySettingsGroup2 = new RadioButtonGroup();
  331   RadioButtonWidget* r = new RadioButtonWidget(myTab, font, HBORDER, ypos + 1,
  332                                                "Player settings", mySettingsGroup2, kPlrSettings);
  333   wid.push_back(r);
  334   ypos += lineHeight + VGAP;
  335   r = new RadioButtonWidget(myTab, font, HBORDER, ypos + 1,
  336                             "Developer settings", mySettingsGroup2, kDevSettings);
  337   wid.push_back(r);
  338   ypos += lineHeight + VGAP * 1;
  339 
  340   myTimeMachineWidget = new CheckboxWidget(myTab, font, HBORDER + INDENT, ypos + 1,
  341                                            "Time Machine", kTimeMachine);
  342   wid.push_back(myTimeMachineWidget);
  343   ypos += lineHeight + VGAP;
  344 
  345   int swidth = fontWidth * 12 + 5; // width of PopUpWidgets below
  346   myStateSizeWidget = new SliderWidget(myTab, font, HBORDER + INDENT * 2, ypos - 1, swidth, lineHeight,
  347                                        "Buffer size (*)   ", 0, kSizeChanged, lwidth, " states");
  348   myStateSizeWidget->setMinValue(20);
  349   myStateSizeWidget->setMaxValue(1000);
  350   myStateSizeWidget->setStepValue(20);
  351   myStateSizeWidget->setTickmarkInterval(5);
  352   wid.push_back(myStateSizeWidget);
  353   ypos += lineHeight + VGAP;
  354 
  355   myUncompressedWidget = new SliderWidget(myTab, font, HBORDER + INDENT * 2, ypos - 1, swidth, lineHeight,
  356                                           "Uncompressed size ", 0, kUncompressedChanged, lwidth, " states");
  357   myUncompressedWidget->setMinValue(0);
  358   myUncompressedWidget->setMaxValue(1000);
  359   myUncompressedWidget->setStepValue(20);
  360   myUncompressedWidget->setTickmarkInterval(5);
  361   wid.push_back(myUncompressedWidget);
  362   ypos += lineHeight + VGAP;
  363 
  364   items.clear();
  365   for(int i = 0; i < NUM_INTERVALS; ++i)
  366     VarList::push_back(items, INTERVALS[i], INT_SETTINGS[i]);
  367   int pwidth = font.getStringWidth("10 seconds");
  368   myStateIntervalWidget = new PopUpWidget(myTab, font, HBORDER + INDENT * 2, ypos, pwidth,
  369                                           lineHeight, items, "Interval          ", 0, kIntervalChanged);
  370   wid.push_back(myStateIntervalWidget);
  371   ypos += lineHeight + VGAP;
  372 
  373   items.clear();
  374   for(int i = 0; i < NUM_HORIZONS; ++i)
  375     VarList::push_back(items, HORIZONS[i], HOR_SETTINGS[i]);
  376   myStateHorizonWidget = new PopUpWidget(myTab, font, HBORDER + INDENT * 2, ypos, pwidth,
  377                                          lineHeight, items, "Horizon         ~ ", 0, kHorizonChanged);
  378   wid.push_back(myStateHorizonWidget);
  379 
  380   // Add message concerning usage
  381   const GUI::Font& infofont = instance().frameBuffer().infoFont();
  382   ypos = myTab->getHeight() - 5 - fontHeight - infofont.getFontHeight() - 10;
  383   new StaticTextWidget(myTab, infofont, HBORDER, ypos, "(*) Any size change clears the buffer");
  384 
  385   addToFocusList(wid, myTab, tabID);
  386 }
  387 
  388 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  389 void DeveloperDialog::addDebuggerTab(const GUI::Font& font)
  390 {
  391   int tabID = myTab->addTab("Debugger");
  392   WidgetArray wid;
  393 
  394 #ifdef DEBUGGER_SUPPORT
  395   const int HBORDER = 10;
  396   const int VBORDER = 8;
  397   const int VGAP = 4;
  398 
  399   VariantList items;
  400   int fontWidth = font.getMaxCharWidth(),
  401     fontHeight = font.getFontHeight(),
  402     lineHeight = font.getLineHeight();
  403   int xpos, ypos, pwidth;
  404   const GUI::Size& ds = instance().frameBuffer().desktopSize();
  405 
  406   xpos = HBORDER;
  407   ypos = VBORDER;
  408 
  409   // font size
  410   items.clear();
  411   VarList::push_back(items, "Small", "small");
  412   VarList::push_back(items, "Medium", "medium");
  413   VarList::push_back(items, "Large", "large");
  414   pwidth = font.getStringWidth("Medium");
  415   myDebuggerFontSize =
  416     new PopUpWidget(myTab, font, HBORDER, ypos + 1, pwidth, lineHeight, items,
  417                     "Font size (*)  ", 0, kDFontSizeChanged);
  418   wid.push_back(myDebuggerFontSize);
  419   ypos += lineHeight + 4;
  420 
  421   // Font style (bold label vs. text, etc)
  422   items.clear();
  423   VarList::push_back(items, "All normal font", "0");
  424   VarList::push_back(items, "Bold labels only", "1");
  425   VarList::push_back(items, "Bold non-labels only", "2");
  426   VarList::push_back(items, "All bold font", "3");
  427   pwidth = font.getStringWidth("Bold non-labels only");
  428   myDebuggerFontStyle =
  429     new PopUpWidget(myTab, font, HBORDER, ypos + 1, pwidth, lineHeight, items,
  430                     "Font style (*) ", 0);
  431   wid.push_back(myDebuggerFontStyle);
  432 
  433   ypos += lineHeight + VGAP * 4;
  434 
  435   // Debugger width and height
  436   myDebuggerWidthSlider = new SliderWidget(myTab, font, xpos, ypos-1, "Debugger width (*)  ",
  437                                            0, 0, 6 * fontWidth, "px");
  438   myDebuggerWidthSlider->setMinValue(DebuggerDialog::kSmallFontMinW);
  439   myDebuggerWidthSlider->setMaxValue(ds.w);
  440   myDebuggerWidthSlider->setStepValue(10);
  441   // one tickmark every ~100 pixel
  442   myDebuggerWidthSlider->setTickmarkInterval((ds.w - DebuggerDialog::kSmallFontMinW + 50) / 100);
  443   wid.push_back(myDebuggerWidthSlider);
  444   ypos += lineHeight + VGAP;
  445 
  446   myDebuggerHeightSlider = new SliderWidget(myTab, font, xpos, ypos-1, "Debugger height (*) ",
  447                                             0, 0, 6 * fontWidth, "px");
  448   myDebuggerHeightSlider->setMinValue(DebuggerDialog::kSmallFontMinH);
  449   myDebuggerHeightSlider->setMaxValue(ds.h);
  450   myDebuggerHeightSlider->setStepValue(10);
  451   // one tickmark every ~100 pixel
  452   myDebuggerHeightSlider->setTickmarkInterval((ds.h - DebuggerDialog::kSmallFontMinH + 50) / 100);
  453   wid.push_back(myDebuggerHeightSlider);
  454   ypos += lineHeight + VGAP * 4;
  455 
  456   myGhostReadsTrapWidget = new CheckboxWidget(myTab, font, HBORDER, ypos + 1,
  457                                              "Trap on 'ghost' reads");
  458   wid.push_back(myGhostReadsTrapWidget);
  459 
  460   // Add message concerning usage
  461   const GUI::Font& infofont = instance().frameBuffer().infoFont();
  462   ypos = myTab->getHeight() - 5 - fontHeight - infofont.getFontHeight() - 10;
  463   new StaticTextWidget(myTab, infofont, HBORDER, ypos, "(*) Changes require a ROM reload");
  464 
  465   // Debugger is only realistically available in windowed modes 800x600 or greater
  466   // (and when it's actually been compiled into the app)
  467   bool debuggerAvailable =
  468 #if defined(DEBUGGER_SUPPORT) && defined(WINDOWED_SUPPORT)
  469     (ds.w >= 800 && ds.h >= 600);  // TODO - maybe this logic can disappear?
  470 #else
  471     false;
  472 #endif
  473   if(!debuggerAvailable)
  474   {
  475     myDebuggerWidthSlider->clearFlags(WIDGET_ENABLED);
  476     myDebuggerHeightSlider->clearFlags(WIDGET_ENABLED);
  477   }
  478 #else
  479   new StaticTextWidget(myTab, font, 0, 20, _w - 20, font.getFontHeight(),
  480                        "Debugger support not included", TextAlign::Center);
  481 #endif
  482 
  483   addToFocusList(wid, myTab, tabID);
  484 }
  485 
  486 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  487 void DeveloperDialog::loadSettings(SettingsSet set)
  488 {
  489   const string& prefix = set == SettingsSet::player ? "plr." : "dev.";
  490 
  491   myFrameStats[set] = instance().settings().getBool(prefix + "stats");
  492   myConsole[set] = instance().settings().getString(prefix + "console") == "7800" ? 1 : 0;
  493   // Randomization
  494   myRandomBank[set] = instance().settings().getBool(prefix + "bankrandom");
  495   myRandomizeRAM[set] = instance().settings().getBool(prefix + "ramrandom");
  496   myRandomizeCPU[set] = instance().settings().getString(prefix + "cpurandom");
  497   // Undriven TIA pins
  498   myUndrivenPins[set] = instance().settings().getBool(prefix + "tiadriven");
  499 #ifdef DEBUGGER_SUPPORT
  500   // Read from write ports break
  501   myRWPortBreak[set] = instance().settings().getBool(prefix + "rwportbreak");
  502 #endif
  503   // Thumb ARM emulation exception
  504   myThumbException[set] = instance().settings().getBool(prefix + "thumb.trapfatal");
  505   // AtariVox/SaveKey EEPROM access
  506   myEEPROMAccess[set] = instance().settings().getBool(prefix + "eepromaccess");
  507 
  508   // Debug colors
  509   myDebugColors[set] = instance().settings().getBool(prefix + "debugcolors");
  510   // PAL color-loss effect
  511   myColorLoss[set] = instance().settings().getBool(prefix + "colorloss");
  512   // Jitter
  513   myTVJitter[set] = instance().settings().getBool(prefix + "tv.jitter");
  514   myTVJitterRec[set] = instance().settings().getInt(prefix + "tv.jitter_recovery");
  515 
  516   // States
  517   myTimeMachine[set] = instance().settings().getBool(prefix + "timemachine");
  518   myStateSize[set] = instance().settings().getInt(prefix + "tm.size");
  519   myUncompressed[set] = instance().settings().getInt(prefix + "tm.uncompressed");
  520   myStateInterval[set] = instance().settings().getString(prefix + "tm.interval");
  521   myStateHorizon[set] = instance().settings().getString(prefix + "tm.horizon");
  522 }
  523 
  524 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  525 void DeveloperDialog::saveSettings(SettingsSet set)
  526 {
  527   const string& prefix = set == SettingsSet::player ? "plr." : "dev.";
  528 
  529   instance().settings().setValue(prefix + "stats", myFrameStats[set]);
  530   instance().settings().setValue(prefix + "console", myConsole[set] == 1 ? "7800" : "2600");
  531   // Randomization
  532   instance().settings().setValue(prefix + "bankrandom", myRandomBank[set]);
  533   instance().settings().setValue(prefix + "ramrandom", myRandomizeRAM[set]);
  534   instance().settings().setValue(prefix + "cpurandom", myRandomizeCPU[set]);
  535   // Undriven TIA pins
  536   instance().settings().setValue(prefix + "tiadriven", myUndrivenPins[set]);
  537 #ifdef DEBUGGER_SUPPORT
  538   // Read from write ports break
  539   instance().settings().setValue(prefix + "rwportbreak", myRWPortBreak[set]);
  540 #endif
  541   // Thumb ARM emulation exception
  542   instance().settings().setValue(prefix + "thumb.trapfatal", myThumbException[set]);
  543   // AtariVox/SaveKey EEPROM access
  544   instance().settings().setValue(prefix + "eepromaccess", myEEPROMAccess[set]);
  545 
  546   // Debug colors
  547   instance().settings().setValue(prefix + "debugcolors", myDebugColors[set]);
  548   // PAL color loss
  549   instance().settings().setValue(prefix + "colorloss", myColorLoss[set]);
  550   // Jitter
  551   instance().settings().setValue(prefix + "tv.jitter", myTVJitter[set]);
  552   instance().settings().setValue(prefix + "tv.jitter_recovery", myTVJitterRec[set]);
  553 
  554   // States
  555   instance().settings().setValue(prefix + "timemachine", myTimeMachine[set]);
  556   instance().settings().setValue(prefix + "tm.size", myStateSize[set]);
  557   instance().settings().setValue(prefix + "tm.uncompressed", myUncompressed[set]);
  558   instance().settings().setValue(prefix + "tm.interval", myStateInterval[set]);
  559   instance().settings().setValue(prefix + "tm.horizon", myStateHorizon[set]);
  560 }
  561 
  562 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  563 void DeveloperDialog::getWidgetStates(SettingsSet set)
  564 {
  565   myFrameStats[set] = myFrameStatsWidget->getState();
  566   myConsole[set] = myConsoleWidget->getSelected() == 1;
  567   // Randomization
  568   myRandomBank[set] = myRandomBankWidget->getState();
  569   myRandomizeRAM[set] = myRandomizeRAMWidget->getState();
  570   string cpurandom;
  571   const char* const cpuregs[] = { "S", "A", "X", "Y", "P" };
  572   for(int i = 0; i < 5; ++i)
  573     if(myRandomizeCPUWidget[i]->getState())
  574       cpurandom += cpuregs[i];
  575   myRandomizeCPU[set] = cpurandom;
  576   // Undriven TIA pins
  577   myUndrivenPins[set] = myUndrivenPinsWidget->getState();
  578 #ifdef DEBUGGER_SUPPORT
  579   // Read from write ports break
  580   myRWPortBreak[set] = myRWPortBreakWidget->getState();
  581 #endif
  582   // Thumb ARM emulation exception
  583   myThumbException[set] = myThumbExceptionWidget->getState();
  584   // AtariVox/SaveKey EEPROM access
  585   myEEPROMAccess[set] = myEEPROMAccessWidget->getState();
  586 
  587   // Debug colors
  588   myDebugColors[set] = myDebugColorsWidget->getState();
  589   // PAL color-loss effect
  590   myColorLoss[set] = myColorLossWidget->getState();
  591   // Jitter
  592   myTVJitter[set] = myTVJitterWidget->getState();
  593   myTVJitterRec[set] = myTVJitterRecWidget->getValue();
  594 
  595   // States
  596   myTimeMachine[set] = myTimeMachineWidget->getState();
  597   myStateSize[set] = myStateSizeWidget->getValue();
  598   myUncompressed[set] = myUncompressedWidget->getValue();
  599   myStateInterval[set] = myStateIntervalWidget->getSelected();
  600   myStateInterval[set] = myStateIntervalWidget->getSelectedTag().toString();
  601   myStateHorizon[set] = myStateHorizonWidget->getSelectedTag().toString();
  602 }
  603 
  604 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  605 void DeveloperDialog::setWidgetStates(SettingsSet set)
  606 {
  607   myFrameStatsWidget->setState(myFrameStats[set]);
  608   myConsoleWidget->setSelectedIndex(myConsole[set]);
  609   // Randomization
  610   myRandomBankWidget->setState(myRandomBank[set]);
  611   myRandomizeRAMWidget->setState(myRandomizeRAM[set]);
  612 
  613   const string& cpurandom = myRandomizeCPU[set];
  614   const char* const cpuregs[] = { "S", "A", "X", "Y", "P" };
  615   for(int i = 0; i < 5; ++i)
  616     myRandomizeCPUWidget[i]->setState(BSPF::containsIgnoreCase(cpurandom, cpuregs[i]));
  617   // Undriven TIA pins
  618   myUndrivenPinsWidget->setState(myUndrivenPins[set]);
  619 #ifdef DEBUGGER_SUPPORT
  620   // Read from write ports break
  621   myRWPortBreakWidget->setState(myRWPortBreak[set]);
  622 #endif
  623   // Thumb ARM emulation exception
  624   myThumbExceptionWidget->setState(myThumbException[set]);
  625   // AtariVox/SaveKey EEPROM access
  626   myEEPROMAccessWidget->setState(myEEPROMAccess[set]);
  627 
  628   handleConsole();
  629 
  630   // Debug colors
  631   myDebugColorsWidget->setState(myDebugColors[set]);
  632   // PAL color-loss effect
  633   myColorLossWidget->setState(myColorLoss[set]);
  634   // Jitter
  635   myTVJitterWidget->setState(myTVJitter[set]);
  636   myTVJitterRecWidget->setValue(myTVJitterRec[set]);
  637 
  638   handleTVJitterChange(myTVJitterWidget->getState());
  639   handleEnableDebugColors();
  640 
  641   // States
  642   myTimeMachineWidget->setState(myTimeMachine[set]);
  643   myStateSizeWidget->setValue(myStateSize[set]);
  644   myUncompressedWidget->setValue(myUncompressed[set]);
  645   myStateIntervalWidget->setSelected(myStateInterval[set]);
  646   myStateHorizonWidget->setSelected(myStateHorizon[set]);
  647 
  648   handleTimeMachine();
  649   handleSize();
  650   handleUncompressed();
  651   handleInterval();
  652   handleHorizon();
  653 }
  654 
  655 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  656 void DeveloperDialog::loadConfig()
  657 {
  658   bool devSettings = instance().settings().getBool("dev.settings");
  659   mySettings = devSettings;
  660   mySettingsGroup0->setSelected(devSettings ? 1 : 0);
  661   mySettingsGroup1->setSelected(devSettings ? 1 : 0);
  662   mySettingsGroup2->setSelected(devSettings ? 1 : 0);
  663 
  664   // load both setting sets...
  665   loadSettings(SettingsSet::player);
  666   loadSettings(SettingsSet::developer);
  667   // ...and select the current one
  668   setWidgetStates(SettingsSet(mySettingsGroup0->getSelected()));
  669 
  670   // Debug colours
  671   handleDebugColours(instance().settings().getString("tia.dbgcolors"));
  672 
  673 #ifdef DEBUGGER_SUPPORT
  674   uInt32 w, h;
  675 
  676   // Debugger size
  677   const GUI::Size& ds = instance().settings().getSize("dbg.res");
  678   w = ds.w; h = ds.h;
  679 
  680   myDebuggerWidthSlider->setValue(w);
  681   myDebuggerHeightSlider->setValue(h);
  682 
  683   // Debugger font size
  684   string size = instance().settings().getString("dbg.fontsize");
  685   myDebuggerFontSize->setSelected(size, "medium");
  686 
  687   // Debugger font style
  688   int style = instance().settings().getInt("dbg.fontstyle");
  689   myDebuggerFontStyle->setSelected(style, "0");
  690 
  691   // Ghost reads trap
  692   myGhostReadsTrapWidget->setState(instance().settings().getBool("dbg.ghostreadstrap"));
  693 
  694   handleFontSize();
  695 #endif
  696 
  697   myTab->loadConfig();
  698 }
  699 
  700 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  701 void DeveloperDialog::saveConfig()
  702 {
  703   instance().settings().setValue("dev.settings", mySettingsGroup0->getSelected() == SettingsSet::developer);
  704   // copy current widget status into set...
  705   getWidgetStates(SettingsSet(mySettingsGroup0->getSelected()));
  706   // ...and save both sets
  707   saveSettings(SettingsSet::player);
  708   saveSettings(SettingsSet::developer);
  709 
  710   // activate the current settings
  711   instance().frameBuffer().showFrameStats(myFrameStatsWidget->getState());
  712   // jitter
  713   if(instance().hasConsole())
  714   {
  715     instance().console().tia().toggleJitter(myTVJitterWidget->getState() ? 1 : 0);
  716     instance().console().tia().setJitterRecoveryFactor(myTVJitterRecWidget->getValue());
  717   }
  718   handleEnableDebugColors();
  719   // PAL color loss
  720   if(instance().hasConsole())
  721     instance().console().enableColorLoss(myColorLossWidget->getState());
  722 
  723   // Debug colours
  724   string dbgcolors;
  725   for(int i = 0; i < DEBUG_COLORS; ++i)
  726     dbgcolors += myDbgColour[i]->getSelectedTag().toString();
  727   if(instance().hasConsole() &&
  728      instance().console().tia().setFixedColorPalette(dbgcolors))
  729     instance().settings().setValue("tia.dbgcolors", dbgcolors);
  730 
  731   // update RewindManager
  732   instance().state().rewindManager().setup();
  733   instance().state().setRewindMode(myTimeMachineWidget->getState() ?
  734                                    StateManager::Mode::TimeMachine : StateManager::Mode::Off);
  735 
  736 #ifdef DEBUGGER_SUPPORT
  737   // Debugger font style
  738   instance().settings().setValue("dbg.fontstyle",
  739                                  myDebuggerFontStyle->getSelectedTag().toString());
  740   // Debugger size
  741   instance().settings().setValue("dbg.res",
  742                                  GUI::Size(myDebuggerWidthSlider->getValue(),
  743                                  myDebuggerHeightSlider->getValue()));
  744   // Debugger font size
  745   instance().settings().setValue("dbg.fontsize", myDebuggerFontSize->getSelectedTag().toString());
  746 
  747   // Ghost reads trap
  748   instance().settings().setValue("dbg.ghostreadstrap", myGhostReadsTrapWidget->getState());
  749   if(instance().hasConsole())
  750     instance().console().system().m6502().setGhostReadsTrap(myGhostReadsTrapWidget->getState());
  751 
  752   // Read from write ports break
  753   if(instance().hasConsole())
  754     instance().console().system().m6502().setReadFromWritePortBreak(myRWPortBreakWidget->getState());
  755 #endif
  756 }
  757 
  758 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  759 void DeveloperDialog::setDefaults()
  760 {
  761   bool devSettings = mySettingsGroup0->getSelected() == 1;
  762   SettingsSet set = SettingsSet(mySettingsGroup0->getSelected());
  763 
  764   switch(myTab->getActiveTab())
  765   {
  766     case 0: // Emulation
  767       myFrameStats[set] = devSettings ? true : false;
  768       myConsole[set] = 0;
  769       // Randomization
  770       myRandomBank[set] = devSettings ? true : false;
  771       myRandomizeRAM[set] = true;
  772       myRandomizeCPU[set] = devSettings ? "SAXYP" : "AXYP";
  773       // Undriven TIA pins
  774       myUndrivenPins[set] = devSettings ? true : false;
  775     #ifdef DEBUGGER_SUPPORT
  776       // Reads from write ports
  777       myRWPortBreak[set] = devSettings ? true : false;
  778     #endif
  779       // Thumb ARM emulation exception
  780       myThumbException[set] = devSettings ? true : false;
  781       // AtariVox/SaveKey EEPROM access
  782       myEEPROMAccess[set] = devSettings ? true : false;
  783 
  784       setWidgetStates(set);
  785       break;
  786 
  787     case 1: // Video
  788       // Jitter
  789       myTVJitter[set] = true;
  790       myTVJitterRec[set] = devSettings ? 2 : 10;
  791       // PAL color-loss effect
  792       myColorLoss[set] = devSettings ? true : false;
  793       // Debug colors
  794       myDebugColors[set] = false;
  795       handleDebugColours("roygpb");
  796 
  797       setWidgetStates(set);
  798       break;
  799 
  800     case 2: // States
  801       myTimeMachine[set] = devSettings ? true : false;
  802       myStateSize[set] = 100;
  803       myUncompressed[set] = devSettings ? 60 : 30;
  804       myStateInterval[set] = devSettings ? "1f" : "30f";
  805       myStateHorizon[set] = devSettings ? "10s" : "10m";
  806 
  807       setWidgetStates(set);
  808       break;
  809 
  810     case 3: // Debugger options
  811     {
  812 #ifdef DEBUGGER_SUPPORT
  813       uInt32 w = std::min(instance().frameBuffer().desktopSize().w, uInt32(DebuggerDialog::kMediumFontMinW));
  814       uInt32 h = std::min(instance().frameBuffer().desktopSize().h, uInt32(DebuggerDialog::kMediumFontMinH));
  815       myDebuggerWidthSlider->setValue(w);
  816       myDebuggerHeightSlider->setValue(h);
  817       myDebuggerFontSize->setSelected("medium");
  818       myDebuggerFontStyle->setSelected("0");
  819 
  820       myGhostReadsTrapWidget->setState(true);
  821 
  822       handleFontSize();
  823 #endif
  824       break;
  825     }
  826 
  827     default:
  828       break;
  829   }
  830 }
  831 
  832 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  833 void DeveloperDialog::handleCommand(CommandSender* sender, int cmd, int data, int id)
  834 {
  835   switch(cmd)
  836   {
  837     case kPlrSettings:
  838       handleSettings(false);
  839       break;
  840 
  841     case kDevSettings:
  842       handleSettings(true);
  843       break;
  844 
  845     case kConsole:
  846       handleConsole();
  847         break;
  848 
  849     case kTVJitter:
  850       handleTVJitterChange(myTVJitterWidget->getState());
  851       break;
  852 
  853     case kTVJitterChanged:
  854       myTVJitterRecLabelWidget->setValue(myTVJitterRecWidget->getValue());
  855       break;
  856 
  857     case kPPinCmd:
  858       instance().console().tia().driveUnusedPinsRandom(myUndrivenPinsWidget->getState());
  859       break;
  860 
  861     case kTimeMachine:
  862       handleTimeMachine();
  863       break;
  864 
  865     case kSizeChanged:
  866       handleSize();
  867       break;
  868 
  869     case kUncompressedChanged:
  870       handleUncompressed();
  871       break;
  872 
  873     case kIntervalChanged:
  874       handleInterval();
  875       break;
  876 
  877     case kHorizonChanged:
  878       handleHorizon();
  879       break;
  880 
  881     case kP0ColourChangedCmd:
  882       handleDebugColours(0, myDbgColour[0]->getSelected());
  883       break;
  884 
  885     case kM0ColourChangedCmd:
  886       handleDebugColours(1, myDbgColour[1]->getSelected());
  887       break;
  888 
  889     case kP1ColourChangedCmd:
  890       handleDebugColours(2, myDbgColour[2]->getSelected());
  891       break;
  892 
  893     case kM1ColourChangedCmd:
  894       handleDebugColours(3, myDbgColour[3]->getSelected());
  895       break;
  896 
  897     case kPFColourChangedCmd:
  898       handleDebugColours(4, myDbgColour[4]->getSelected());
  899       break;
  900 
  901     case kBLColourChangedCmd:
  902       handleDebugColours(5, myDbgColour[5]->getSelected());
  903       break;
  904 
  905 #ifdef DEBUGGER_SUPPORT
  906     case kDFontSizeChanged:
  907       handleFontSize();
  908       break;
  909 #endif
  910 
  911     case GuiObject::kOKCmd:
  912       saveConfig();
  913       close();
  914       break;
  915 
  916     case GuiObject::kCloseCmd:
  917       // Revert changes made to event mapping
  918       close();
  919       break;
  920 
  921     case GuiObject::kDefaultsCmd:
  922       setDefaults();
  923       break;
  924 
  925     default:
  926       Dialog::handleCommand(sender, cmd, data, 0);
  927   }
  928 }
  929 
  930 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  931 void DeveloperDialog::handleSettings(bool devSettings)
  932 {
  933   if (mySettings != devSettings)
  934   {
  935     mySettings = devSettings; // block redundant events first!
  936     mySettingsGroup0->setSelected(devSettings ? 1 : 0);
  937     mySettingsGroup1->setSelected(devSettings ? 1 : 0);
  938     mySettingsGroup2->setSelected(devSettings ? 1 : 0);
  939     getWidgetStates(devSettings ? SettingsSet::player : SettingsSet::developer);
  940     setWidgetStates(devSettings ? SettingsSet::developer : SettingsSet::player);
  941   }
  942 }
  943 
  944 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  945 void DeveloperDialog::handleTVJitterChange(bool enable)
  946 {
  947   myTVJitterRecWidget->setEnabled(enable);
  948   myTVJitterRecLabelWidget->setEnabled(enable);
  949 }
  950 
  951 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  952 void DeveloperDialog::handleEnableDebugColors()
  953 {
  954   if(instance().hasConsole())
  955   {
  956     bool fixed = instance().console().tia().usingFixedColors();
  957     if(fixed != myDebugColorsWidget->getState())
  958       instance().console().tia().toggleFixedColors();
  959   }
  960 }
  961 
  962 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  963 void DeveloperDialog::handleConsole()
  964 {
  965   bool is7800 = myConsoleWidget->getSelected() == 1;
  966 
  967   myRandomizeRAMWidget->setEnabled(!is7800);
  968   if(is7800)
  969     myRandomizeRAMWidget->setState(false);
  970 }
  971 
  972 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  973 void DeveloperDialog::handleTimeMachine()
  974 {
  975   bool enable = myTimeMachineWidget->getState();
  976 
  977   myStateSizeWidget->setEnabled(enable);
  978   myUncompressedWidget->setEnabled(enable);
  979   myStateIntervalWidget->setEnabled(enable);
  980 
  981   uInt32 size = myStateSizeWidget->getValue();
  982   uInt32 uncompressed = myUncompressedWidget->getValue();
  983 
  984   myStateHorizonWidget->setEnabled(enable && size > uncompressed);
  985 }
  986 
  987 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  988 void DeveloperDialog::handleSize()
  989 {
  990   uInt32 size = myStateSizeWidget->getValue();
  991   uInt32 uncompressed = myUncompressedWidget->getValue();
  992   Int32 interval = myStateIntervalWidget->getSelected();
  993   Int32 horizon = myStateHorizonWidget->getSelected();
  994   bool found = false;
  995   Int32 i;
  996 
  997   // handle illegal values
  998   if(interval == -1)
  999     interval = 0;
 1000   if(horizon == -1)
 1001     horizon = 0;
 1002 
 1003   // adapt horizon and interval
 1004   do
 1005   {
 1006     for(i = horizon; i < NUM_HORIZONS; ++i)
 1007     {
 1008       if(uInt64(size) * instance().state().rewindManager().INTERVAL_CYCLES[interval]
 1009          <= instance().state().rewindManager().HORIZON_CYCLES[i])
 1010       {
 1011         found = true;
 1012         break;
 1013       }
 1014     }
 1015     if(!found)
 1016       --interval;
 1017   } while(!found);
 1018 
 1019   if(size < uncompressed)
 1020     myUncompressedWidget->setValue(size);
 1021   myStateIntervalWidget->setSelectedIndex(interval);
 1022   myStateHorizonWidget->setSelectedIndex(i);
 1023   myStateHorizonWidget->setEnabled(myTimeMachineWidget->getState() && size > uncompressed);
 1024 }
 1025 
 1026 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 1027 void DeveloperDialog::handleUncompressed()
 1028 {
 1029   uInt32 size = myStateSizeWidget->getValue();
 1030   uInt32 uncompressed = myUncompressedWidget->getValue();
 1031 
 1032   if(size < uncompressed)
 1033     myStateSizeWidget->setValue(uncompressed);
 1034   myStateHorizonWidget->setEnabled(myTimeMachineWidget->getState() && size > uncompressed);
 1035 }
 1036 
 1037 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 1038 void DeveloperDialog::handleInterval()
 1039 {
 1040   uInt32 size = myStateSizeWidget->getValue();
 1041   uInt32 uncompressed = myUncompressedWidget->getValue();
 1042   Int32 interval = myStateIntervalWidget->getSelected();
 1043   Int32 horizon = myStateHorizonWidget->getSelected();
 1044   bool found = false;
 1045   Int32 i;
 1046 
 1047   // handle illegal values
 1048   if(interval == -1)
 1049     interval = 0;
 1050   if(horizon == -1)
 1051     horizon = 0;
 1052 
 1053   // adapt horizon and size
 1054   do
 1055   {
 1056     for(i = horizon; i < NUM_HORIZONS; ++i)
 1057     {
 1058       if(uInt64(size) * instance().state().rewindManager().INTERVAL_CYCLES[interval]
 1059          <= instance().state().rewindManager().HORIZON_CYCLES[i])
 1060       {
 1061         found = true;
 1062         break;
 1063       }
 1064     }
 1065     if(!found)
 1066       size -= myStateSizeWidget->getStepValue();
 1067   } while(!found);
 1068 
 1069   myStateHorizonWidget->setSelectedIndex(i);
 1070   myStateSizeWidget->setValue(size);
 1071   if(size < uncompressed)
 1072     myUncompressedWidget->setValue(size);
 1073 }
 1074 
 1075 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 1076 void DeveloperDialog::handleHorizon()
 1077 {
 1078   uInt32 size = myStateSizeWidget->getValue();
 1079   uInt32 uncompressed = myUncompressedWidget->getValue();
 1080   Int32 interval = myStateIntervalWidget->getSelected();
 1081   Int32 horizon = myStateHorizonWidget->getSelected();
 1082   bool found = false;
 1083   Int32 i;
 1084 
 1085   // handle illegal values
 1086   if(interval == -1)
 1087     interval = 0;
 1088   if(horizon == -1)
 1089     horizon = 0;
 1090 
 1091   // adapt interval and size
 1092   do
 1093   {
 1094     for(i = interval; i >= 0; --i)
 1095     {
 1096       if(uInt64(size) * instance().state().rewindManager().INTERVAL_CYCLES[i]
 1097          <= instance().state().rewindManager().HORIZON_CYCLES[horizon])
 1098       {
 1099         found = true;
 1100         break;
 1101       }
 1102     }
 1103     if(!found)
 1104       size -= myStateSizeWidget->getStepValue();
 1105   } while(!found);
 1106 
 1107   myStateIntervalWidget->setSelectedIndex(i);
 1108   myStateSizeWidget->setValue(size);
 1109   if(size < uncompressed)
 1110     myUncompressedWidget->setValue(size);
 1111 }
 1112 
 1113 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 1114 void DeveloperDialog::handleDebugColours(int idx, int color)
 1115 {
 1116   if(idx < 0 || idx >= DEBUG_COLORS)
 1117     return;
 1118 
 1119   if(!instance().hasConsole())
 1120   {
 1121     myDbgColour[idx]->clearFlags(WIDGET_ENABLED);
 1122     myDbgColourSwatch[idx]->clearFlags(WIDGET_ENABLED);
 1123     return;
 1124   }
 1125 
 1126   static constexpr ColorId dbg_color[3][DEBUG_COLORS] = {
 1127     {
 1128       TIA::FixedColor::NTSC_RED,
 1129       TIA::FixedColor::NTSC_ORANGE,
 1130       TIA::FixedColor::NTSC_YELLOW,
 1131       TIA::FixedColor::NTSC_GREEN,
 1132       TIA::FixedColor::NTSC_PURPLE,
 1133       TIA::FixedColor::NTSC_BLUE
 1134     },
 1135     {
 1136       TIA::FixedColor::PAL_RED,
 1137       TIA::FixedColor::PAL_ORANGE,
 1138       TIA::FixedColor::PAL_YELLOW,
 1139       TIA::FixedColor::PAL_GREEN,
 1140       TIA::FixedColor::PAL_PURPLE,
 1141       TIA::FixedColor::PAL_BLUE
 1142     },
 1143     {
 1144       TIA::FixedColor::SECAM_RED,
 1145       TIA::FixedColor::SECAM_ORANGE,
 1146       TIA::FixedColor::SECAM_YELLOW,
 1147       TIA::FixedColor::SECAM_GREEN,
 1148       TIA::FixedColor::SECAM_PURPLE,
 1149       TIA::FixedColor::SECAM_BLUE
 1150     }
 1151   };
 1152 
 1153   int timing = instance().console().tia().consoleTiming() == ConsoleTiming::ntsc ? 0
 1154     : instance().console().tia().consoleTiming() == ConsoleTiming::pal ? 1 : 2;
 1155 
 1156   myDbgColourSwatch[idx]->setColor(dbg_color[timing][color]);
 1157   myDbgColour[idx]->setSelectedIndex(color);
 1158 
 1159   // make sure the selected debug colors are all different
 1160   bool usedCol[DEBUG_COLORS];
 1161 
 1162   // identify used colors
 1163   for(int i = 0; i < DEBUG_COLORS; ++i)
 1164   {
 1165     usedCol[i] = false;
 1166     for(int j = 0; j < DEBUG_COLORS; ++j)
 1167     {
 1168       if(myDbgColourSwatch[j]->getColor() == dbg_color[timing][i])
 1169       {
 1170         usedCol[i] = true;
 1171         break;
 1172       }
 1173     }
 1174   }
 1175   // check if currently changed color was used somewhere else
 1176   for(int i = 0; i < DEBUG_COLORS; ++i)
 1177   {
 1178     if (i != idx && myDbgColourSwatch[i]->getColor() == dbg_color[timing][color])
 1179     {
 1180       // if already used, change the other color to an unused one
 1181       for(int j = 0; j < DEBUG_COLORS; ++j)
 1182       {
 1183         if(!usedCol[j])
 1184         {
 1185           myDbgColourSwatch[i]->setColor(dbg_color[timing][j]);
 1186           myDbgColour[i]->setSelectedIndex(j);
 1187           break;
 1188         }
 1189       }
 1190     }
 1191   }
 1192 }
 1193 
 1194 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 1195 void DeveloperDialog::handleDebugColours(const string& colors)
 1196 {
 1197   for(int i = 0; i < DEBUG_COLORS; ++i)
 1198   {
 1199     switch(colors[i])
 1200     {
 1201       case 'r': handleDebugColours(i, 0);  break;
 1202       case 'o': handleDebugColours(i, 1);  break;
 1203       case 'y': handleDebugColours(i, 2);  break;
 1204       case 'g': handleDebugColours(i, 3);  break;
 1205       case 'p': handleDebugColours(i, 4);  break;
 1206       case 'b': handleDebugColours(i, 5);  break;
 1207       default:                              break;
 1208     }
 1209   }
 1210 }
 1211 
 1212 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 1213 void DeveloperDialog::handleFontSize()
 1214 {
 1215 #ifdef DEBUGGER_SUPPORT
 1216   uInt32 minW, minH;
 1217   int fontSize = myDebuggerFontSize->getSelected();
 1218 
 1219   if(fontSize == 0)
 1220   {
 1221     minW = DebuggerDialog::kSmallFontMinW;
 1222     minH = DebuggerDialog::kSmallFontMinH;
 1223   }
 1224   else if(fontSize == 1)
 1225   {
 1226     minW = DebuggerDialog::kMediumFontMinW;
 1227     minH = DebuggerDialog::kMediumFontMinH;
 1228   }
 1229   else // large
 1230   {
 1231     minW = DebuggerDialog::kLargeFontMinW;
 1232     minH = DebuggerDialog::kLargeFontMinH;
 1233   }
 1234   minW = std::min(instance().frameBuffer().desktopSize().w, minW);
 1235   minH = std::min(instance().frameBuffer().desktopSize().h, minH);
 1236 
 1237   myDebuggerWidthSlider->setMinValue(minW);
 1238   if(minW > uInt32(myDebuggerWidthSlider->getValue()))
 1239     myDebuggerWidthSlider->setValue(minW);
 1240 
 1241   myDebuggerHeightSlider->setMinValue(minH);
 1242   if(minH > uInt32(myDebuggerHeightSlider->getValue()))
 1243     myDebuggerHeightSlider->setValue(minH);
 1244 #endif
 1245 }