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-2021 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 "ColorWidget.hxx"
19 #include "DataGridWidget.hxx"
20 #include "EditTextWidget.hxx"
21 #include "FrameBuffer.hxx"
22 #include "Font.hxx"
23 #include "GuiObject.hxx"
24 #include "OSystem.hxx"
25 #include "Debugger.hxx"
26 #include "CartDebug.hxx"
27 #include "TIA.hxx"
28 #include "TIADebug.hxx"
29 #include "ToggleBitWidget.hxx"
30 #include "TogglePixelWidget.hxx"
31 #include "Widget.hxx"
32 #include "DelayQueueWidget.hxx"
33 #include "TiaWidget.hxx"
34 
35 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TiaWidget(GuiObject * boss,const GUI::Font & lfont,const GUI::Font & nfont,int x,int y,int w,int h)36 TiaWidget::TiaWidget(GuiObject* boss, const GUI::Font& lfont,
37                      const GUI::Font& nfont,
38                      int x, int y, int w, int h)
39   : Widget(boss, lfont, x, y, w, h),
40     CommandSender(boss)
41 {
42   const int fontWidth  = lfont.getMaxCharWidth(),
43             fontHeight = lfont.getFontHeight(),
44             lineHeight = lfont.getLineHeight(),
45             buttonW = 7 * fontWidth;
46   int xpos = 10, ypos = 10, buttonX = 0, buttonY = 0;
47   StaticTextWidget* t = nullptr;
48   ButtonWidget* b = nullptr;
49 
50 
51   ////////////////////////////
52   // VSync/VBlank
53   ////////////////////////////
54   buttonX = xpos;  buttonY = ypos;
55   myVSync = new CheckboxWidget(boss, lfont, buttonX, buttonY, "VSync", kVSyncCmd);
56   myVSync->setTarget(this);
57   addFocusWidget(myVSync);
58 
59   buttonX += myVSync->getRight() + 15;
60   myVBlank = new CheckboxWidget(boss, lfont, buttonX, buttonY, "VBlank", kVBlankCmd);
61   myVBlank->setTarget(this);
62   addFocusWidget(myVBlank);
63 
64   ypos += lineHeight * 2 + 6;
65 
66   // Color registers
67   static constexpr std::array<const char*, 4> regNames = {
68     "COLUP0", "COLUP1", "COLUPF", "COLUBK"
69   };
70   for(int row = 0; row < 4; ++row)
71   {
72     new StaticTextWidget(boss, lfont, xpos, ypos + row*lineHeight + 2,
73                          6*fontWidth, fontHeight, regNames[row], TextAlign::Left);
74   }
75   xpos += 6*fontWidth + 8;
76   myColorRegs = new DataGridWidget(boss, nfont, xpos, ypos,
77                                    1, 4, 2, 8, Common::Base::Fmt::_16);
78   myColorRegs->setTarget(this);
79   myColorRegs->setID(kColorRegsID);
80   addFocusWidget(myColorRegs);
81 
82   xpos += myColorRegs->colWidth() + 5;
83   myCOLUP0Color = new ColorWidget(boss, nfont, xpos, ypos+2,
84                                   uInt32(1.5*lineHeight), lineHeight - 4);
85   myCOLUP0Color->setTarget(this);
86 
87   ypos += lineHeight;
88   myCOLUP1Color = new ColorWidget(boss, nfont, xpos, ypos+2,
89                                   uInt32(1.5*lineHeight), lineHeight - 4);
90   myCOLUP1Color->setTarget(this);
91 
92   ypos += lineHeight;
93   myCOLUPFColor = new ColorWidget(boss, nfont, xpos, ypos+2,
94                                   uInt32(1.5*lineHeight), lineHeight - 4);
95   myCOLUPFColor->setTarget(this);
96 
97   ypos += lineHeight;
98   myCOLUBKColor = new ColorWidget(boss, nfont, xpos, ypos+2,
99                                   uInt32(1.5*lineHeight), lineHeight - 4);
100   myCOLUBKColor->setTarget(this);
101 
102   // Fixed debug colors
103   xpos += myCOLUP0Color->getWidth() + 30;  ypos = 10 + lineHeight + 6;
104   myFixedEnabled = new CheckboxWidget(boss, lfont, xpos, ypos, "Debug Colors", kDbgClCmd);
105   myFixedEnabled->setTarget(this);
106   addFocusWidget(myFixedEnabled);
107 
108   static constexpr std::array<const char*, 8> dbgLabels = {
109     "P0", "P1", "PF", "BK", "M0", "M1", "BL", "HM"
110   };
111   for(uInt32 row = 0; row <= 3; ++row)
112   {
113     ypos += lineHeight;
114     t = new StaticTextWidget(boss, lfont, xpos, ypos + 2, 2*fontWidth, fontHeight,
115                              dbgLabels[row], TextAlign::Left);
116     myFixedColors[row] = new ColorWidget(boss, nfont, xpos + 2 + t->getWidth() + 4,
117                                ypos + 2, uInt32(1.5*lineHeight), lineHeight - 4);
118     myFixedColors[row]->setTarget(this);
119   }
120   xpos += t->getWidth() + myFixedColors[0]->getWidth() + 24;
121   ypos = 10 + lineHeight + 6;
122   for(uInt32 row = 4; row <= 7; ++row)
123   {
124     ypos += lineHeight;
125     t = new StaticTextWidget(boss, lfont, xpos, ypos + 2, 2*fontWidth, fontHeight,
126                              dbgLabels[row], TextAlign::Left);
127     myFixedColors[row] = new ColorWidget(boss, nfont, xpos + 2 + t->getWidth() + 4,
128                                ypos + 2, uInt32(1.5*lineHeight), lineHeight - 4);
129     myFixedColors[row]->setTarget(this);
130   }
131 
132   ////////////////////////////
133   // Collision register bits
134   ////////////////////////////
135   xpos += myFixedColors[0]->getWidth() + 2*fontWidth + 60;  ypos = 10;
136 
137   // Add all 15 collision bits (with labels)
138   uInt32 cxclrY = 0;
139   xpos -= 2*fontWidth + 5;  ypos += lineHeight;
140   static constexpr std::array<const char*, 5> rowLabel = { "P0", "P1", "M0", "M1", "BL" };
141   static constexpr std::array<const char*, 5> colLabel = { "PF", "BL", "M1", "M0", "P1" };
142   uInt32 lwidth = 2*fontWidth, collX = xpos + lwidth + 5, collY = ypos, idx = 0;
143   for(uInt32 row = 0; row < 5; ++row)
144   {
145     // Add vertical label
146     new StaticTextWidget(boss, lfont, xpos, ypos + row*(lineHeight+3),
147                          2*fontWidth, fontHeight,
148                          rowLabel[row], TextAlign::Left);
149 
150     for(uInt32 col = 0; col < 5 - row; ++col, ++idx)
151     {
152       myCollision[idx] = new CheckboxWidget(boss, lfont, collX, collY, "", CheckboxWidget::kCheckActionCmd);
153       myCollision[idx]->setTarget(this);
154       myCollision[idx]->setID(idx);
155 
156       // We need to know where the PF_BL register is, to properly position
157       // the CXCLR button
158       if(idx == kBL_PFID)
159         cxclrY = collY;
160 
161       // Add horizontal label
162       uInt32 labelx = collX;
163       if(lwidth > uInt32(myCollision[idx]->getWidth()))
164         labelx -= (lwidth - myCollision[idx]->getWidth()) / 2;
165       else
166         labelx += (myCollision[idx]->getWidth() - lwidth) / 2;
167 
168       new StaticTextWidget(boss, lfont, labelx, ypos-lineHeight, lwidth, fontHeight,
169                            colLabel[col], TextAlign::Left);
170 
171       collX += myCollision[idx]->getWidth() + 10;
172     }
173     collX = xpos + lwidth + 5;
174     collY += lineHeight+3;
175   }
176 
177   // Clear all collision bits
178   buttonX = collX + 5*(myCollision[0]->getWidth() + 10) - buttonW - 10;
179   buttonY = lineHeight == 15 ? cxclrY : cxclrY - 4;
180   b = new ButtonWidget(boss, lfont, buttonX, buttonY, buttonW, lineHeight,
181                        "CXCLR", kCxclrCmd);
182   b->setTarget(this);
183   addFocusWidget(b);
184 
185   ////////////////////////////
186   // P0 register info
187   ////////////////////////////
188   // grP0 (new)
189   xpos = 10;  ypos = collY + 4;
190   new StaticTextWidget(boss, lfont, xpos, ypos+2, 2*fontWidth, fontHeight,
191                        "P0", TextAlign::Left);
192   xpos += 2*fontWidth + 5;
193   myGRP0 = new TogglePixelWidget(boss, nfont, xpos, ypos+1, 8, 1);
194   myGRP0->setTarget(this);
195   myGRP0->setID(kGRP0ID);
196   myGRP0->clearBackgroundColor();
197   addFocusWidget(myGRP0);
198 
199   // posP0
200   xpos += myGRP0->getWidth() + 12;
201   t = new StaticTextWidget(boss, lfont, xpos, ypos+2, 4*fontWidth, fontHeight,
202                            "Pos#", TextAlign::Left);
203   xpos += t->getWidth() + 2;
204   myPosP0 = new DataGridWidget(boss, nfont, xpos, ypos,
205                                1, 1, 3, 8, Common::Base::Fmt::_10);
206   myPosP0->setTarget(this);
207   myPosP0->setID(kPosP0ID);
208   myPosP0->setRange(0, 160);
209   addFocusWidget(myPosP0);
210 
211   // hmP0
212   xpos += myPosP0->getWidth() + fontWidth + 12;
213   new StaticTextWidget(boss, lfont, xpos, ypos+2, 2*fontWidth, fontHeight,
214                        "HM", TextAlign::Left);
215   xpos += 2*fontWidth + 5;
216   myHMP0 = new DataGridWidget(boss, nfont, xpos, ypos,
217                               1, 1, 1, 4, Common::Base::Fmt::_16_1);
218   myHMP0->setTarget(this);
219   myHMP0->setID(kHMP0ID);
220   addFocusWidget(myHMP0);
221 
222   // P0 reflect
223   xpos += myHMP0->getWidth() + 15;
224   myRefP0 = new CheckboxWidget(boss, lfont, xpos, ypos+1,
225                                "Reflect", CheckboxWidget::kCheckActionCmd);
226   myRefP0->setTarget(this);
227   myRefP0->setID(kRefP0ID);
228   addFocusWidget(myRefP0);
229 
230   // P0 reset
231   xpos += myRefP0->getWidth() + 12;
232   buttonX = xpos;
233   b = new ButtonWidget(boss, lfont, xpos, ypos, buttonW, lineHeight,
234                        "RESP0", kResP0Cmd);
235   b->setTarget(this);
236   addFocusWidget(b);
237 
238   // grP0 (old)
239   xpos = 10 + 2*fontWidth + 5;  ypos += myGRP0->getHeight() + 5;
240   myGRP0Old = new TogglePixelWidget(boss, nfont, xpos, ypos+1, 8, 1);
241   myGRP0Old->setTarget(this);
242   myGRP0Old->setID(kGRP0OldID);
243   myGRP0Old->clearBackgroundColor();
244   addFocusWidget(myGRP0Old);
245 
246   // P0 delay
247   xpos += myGRP0Old->getWidth() + 12;
248   myDelP0 = new CheckboxWidget(boss, lfont, xpos, ypos+1,
249                                "VDel", CheckboxWidget::kCheckActionCmd);
250   myDelP0->setTarget(this);
251   myDelP0->setID(kDelP0ID);
252   addFocusWidget(myDelP0);
253 
254   // NUSIZ0 (player portion)
255   xpos += myDelP0->getWidth() + 12;
256   new StaticTextWidget(boss, lfont, xpos, ypos+2, 5*fontWidth, fontHeight,
257                        "NuSiz", TextAlign::Left);
258   xpos += 5*fontWidth + 5;
259   myNusizP0 = new DataGridWidget(boss, nfont, xpos, ypos,
260                                  1, 1, 1, 3, Common::Base::Fmt::_16_1);
261   myNusizP0->setTarget(this);
262   myNusizP0->setID(kNusizP0ID);
263   addFocusWidget(myNusizP0);
264 
265   xpos += myNusizP0->getWidth() + 5;
266   myNusizP0Text = new EditTextWidget(boss, nfont, xpos, ypos, 21*fontWidth,
267                                      lineHeight, "");
268   myNusizP0Text->setEditable(false, true);
269 
270   ////////////////////////////
271   // P1 register info
272   ////////////////////////////
273   // grP1 (new)
274   xpos = 10;  ypos += lineHeight + 12;
275   new StaticTextWidget(boss, lfont, xpos, ypos+2, 2*fontWidth, fontHeight,
276                        "P1", TextAlign::Left);
277   xpos += 2*fontWidth + 5;
278   myGRP1 = new TogglePixelWidget(boss, nfont, xpos, ypos+1, 8, 1);
279   myGRP1->setTarget(this);
280   myGRP1->setID(kGRP1ID);
281   myGRP1->clearBackgroundColor();
282   addFocusWidget(myGRP1);
283 
284   // posP1
285   xpos += myGRP1->getWidth() + 12;
286   t = new StaticTextWidget(boss, lfont, xpos, ypos+2, 4*fontWidth, fontHeight,
287                            "Pos#", TextAlign::Left);
288   xpos += t->getWidth() + 2;
289   myPosP1 = new DataGridWidget(boss, nfont, xpos, ypos,
290                                1, 1, 3, 8, Common::Base::Fmt::_10);
291   myPosP1->setTarget(this);
292   myPosP1->setID(kPosP1ID);
293   myPosP1->setRange(0, 160);
294   addFocusWidget(myPosP1);
295 
296   // hmP1
297   xpos += myPosP1->getWidth() + fontWidth + 12;
298   new StaticTextWidget(boss, lfont, xpos, ypos+2, 2*fontWidth, fontHeight,
299                        "HM", TextAlign::Left);
300   xpos += 2*fontWidth + 5;
301   myHMP1 = new DataGridWidget(boss, nfont, xpos, ypos,
302                               1, 1, 1, 4, Common::Base::Fmt::_16_1);
303   myHMP1->setTarget(this);
304   myHMP1->setID(kHMP1ID);
305   addFocusWidget(myHMP1);
306 
307   // P1 reflect
308   xpos += myHMP1->getWidth() + 15;
309   myRefP1 = new CheckboxWidget(boss, lfont, xpos, ypos+1,
310                                "Reflect", CheckboxWidget::kCheckActionCmd);
311   myRefP1->setTarget(this);
312   myRefP1->setID(kRefP1ID);
313   addFocusWidget(myRefP1);
314 
315   // P1 reset
316   xpos += myRefP1->getWidth() + 12;
317   b = new ButtonWidget(boss, lfont, xpos, ypos, buttonW, lineHeight,
318                        "RESP1", kResP1Cmd);
319   b->setTarget(this);
320   addFocusWidget(b);
321 
322   // grP1 (old)
323   xpos = 10 + 2*fontWidth + 5;  ypos += myGRP1->getHeight() + 5;
324   myGRP1Old = new TogglePixelWidget(boss, nfont, xpos, ypos+1, 8, 1);
325   myGRP1Old->setTarget(this);
326   myGRP1Old->setID(kGRP1OldID);
327   myGRP1Old->clearBackgroundColor();
328   addFocusWidget(myGRP1Old);
329 
330   // P1 delay
331   xpos += myGRP1Old->getWidth() + 12;
332   myDelP1 = new CheckboxWidget(boss, lfont, xpos, ypos+1,
333                                "VDel", CheckboxWidget::kCheckActionCmd);
334   myDelP1->setTarget(this);
335   myDelP1->setID(kDelP1ID);
336   addFocusWidget(myDelP1);
337 
338   // NUSIZ1 (player portion)
339   xpos += myDelP1->getWidth() + 12;
340   new StaticTextWidget(boss, lfont, xpos, ypos+2, 5*fontWidth, fontHeight,
341                        "NuSiz", TextAlign::Left);
342   xpos += 5*fontWidth + 5;
343   myNusizP1 = new DataGridWidget(boss, nfont, xpos, ypos,
344                                  1, 1, 1, 3, Common::Base::Fmt::_16_1);
345   myNusizP1->setTarget(this);
346   myNusizP1->setID(kNusizP1ID);
347   addFocusWidget(myNusizP1);
348 
349   xpos += myNusizP1->getWidth() + 5;
350   myNusizP1Text = new EditTextWidget(boss, nfont, xpos, ypos, 21*fontWidth,
351                                      lineHeight, "");
352   myNusizP1Text->setEditable(false, true);
353 
354   ////////////////////////////
355   // M0 register info
356   ////////////////////////////
357   // enaM0
358   xpos = 10;  ypos += lineHeight + 12;
359   new StaticTextWidget(boss, lfont, xpos, ypos+2, 2*fontWidth, fontHeight,
360                        "M0", TextAlign::Left);
361   xpos += 2*fontWidth + 5;
362   myEnaM0 = new TogglePixelWidget(boss, nfont, xpos, ypos+1, 1, 1);
363   myEnaM0->setTarget(this);
364   myEnaM0->setID(kEnaM0ID);
365   myEnaM0->clearBackgroundColor();
366   addFocusWidget(myEnaM0);
367 
368   // posM0
369   xpos += myEnaM0->getWidth() + 12;
370   t = new StaticTextWidget(boss, lfont, xpos, ypos+2, 4*fontWidth, fontHeight,
371                            "Pos#", TextAlign::Left);
372   xpos += t->getWidth() + 2;
373   myPosM0 = new DataGridWidget(boss, nfont, xpos, ypos,
374                                1, 1, 3, 8, Common::Base::Fmt::_10);
375   myPosM0->setTarget(this);
376   myPosM0->setID(kPosM0ID);
377   myPosM0->setRange(0, 160);
378   addFocusWidget(myPosM0);
379 
380   // hmM0
381   xpos += myPosM0->getWidth() + 12;
382   new StaticTextWidget(boss, lfont, xpos, ypos+2, 2*fontWidth, fontHeight,
383                        "HM", TextAlign::Left);
384   xpos += 2*fontWidth + 5;
385   myHMM0 = new DataGridWidget(boss, nfont, xpos, ypos,
386                               1, 1, 1, 4, Common::Base::Fmt::_16_1);
387   myHMM0->setTarget(this);
388   myHMM0->setID(kHMM0ID);
389   addFocusWidget(myHMM0);
390 
391   // NUSIZ0 (missile portion)
392   xpos += myHMM0->getWidth() + 12;
393   new StaticTextWidget(boss, lfont, xpos, ypos+2, 4*fontWidth, fontHeight,
394                        "Size", TextAlign::Left);
395   xpos += 4*fontWidth + 5;
396   myNusizM0 = new DataGridWidget(boss, nfont, xpos, ypos,
397                                  1, 1, 1, 2, Common::Base::Fmt::_16_1);
398   myNusizM0->setTarget(this);
399   myNusizM0->setID(kNusizM0ID);
400   addFocusWidget(myNusizM0);
401 
402   // M0 reset to player 0
403   xpos += myNusizM0->getWidth() + 15;
404   myResMP0 = new CheckboxWidget(boss, lfont, xpos, ypos+1,
405                                 "Reset to P0", CheckboxWidget::kCheckActionCmd);
406   myResMP0->setTarget(this);
407   myResMP0->setID(kResMP0ID);
408   addFocusWidget(myResMP0);
409 
410   // M0 reset
411   xpos = buttonX;
412   b = new ButtonWidget(boss, lfont, xpos, ypos, buttonW, lineHeight,
413                        "RESM0", kResM0Cmd);
414   b->setTarget(this);
415   addFocusWidget(b);
416 
417   ////////////////////////////
418   // M1 register info
419   ////////////////////////////
420   // enaM1
421   xpos = 10;  ypos += lineHeight + 4;
422   new StaticTextWidget(boss, lfont, xpos, ypos+2, 2*fontWidth, fontHeight,
423                        "M1", TextAlign::Left);
424   xpos += 2*fontWidth + 5;
425   myEnaM1 = new TogglePixelWidget(boss, nfont, xpos, ypos+1, 1, 1);
426   myEnaM1->setTarget(this);
427   myEnaM1->setID(kEnaM1ID);
428   myEnaM1->clearBackgroundColor();
429   addFocusWidget(myEnaM1);
430 
431   // posM0
432   xpos += myEnaM1->getWidth() + 12;
433   t = new StaticTextWidget(boss, lfont, xpos, ypos+2, 4*fontWidth, fontHeight,
434                            "Pos#", TextAlign::Left);
435   xpos += t->getWidth() + 2;
436   myPosM1 = new DataGridWidget(boss, nfont, xpos, ypos,
437                                1, 1, 3, 8, Common::Base::Fmt::_10);
438   myPosM1->setTarget(this);
439   myPosM1->setID(kPosM1ID);
440   myPosM1->setRange(0, 160);
441   addFocusWidget(myPosM1);
442 
443   // hmM0
444   xpos += myPosM1->getWidth() + 12;
445   new StaticTextWidget(boss, lfont, xpos, ypos+2, 2*fontWidth, fontHeight,
446                        "HM", TextAlign::Left);
447   xpos += 2*fontWidth + 5;
448   myHMM1 = new DataGridWidget(boss, nfont, xpos, ypos,
449                               1, 1, 1, 4, Common::Base::Fmt::_16_1);
450   myHMM1->setTarget(this);
451   myHMM1->setID(kHMM1ID);
452   addFocusWidget(myHMM1);
453 
454   // NUSIZ1 (missile portion)
455   xpos += myHMM1->getWidth() + 12;
456   new StaticTextWidget(boss, lfont, xpos, ypos+2, 4*fontWidth, fontHeight,
457                        "Size", TextAlign::Left);
458   xpos += 4*fontWidth + 5;
459   myNusizM1 = new DataGridWidget(boss, nfont, xpos, ypos,
460                                  1, 1, 1, 2, Common::Base::Fmt::_16_1);
461   myNusizM1->setTarget(this);
462   myNusizM1->setID(kNusizM1ID);
463   addFocusWidget(myNusizM1);
464 
465   // M1 reset to player 0
466   xpos += myNusizM1->getWidth() + 15;
467   myResMP1 = new CheckboxWidget(boss, lfont, xpos, ypos+1,
468                                 "Reset to P1", CheckboxWidget::kCheckActionCmd);
469   myResMP1->setTarget(this);
470   myResMP1->setID(kResMP1ID);
471   addFocusWidget(myResMP1);
472 
473   // M1 reset
474   xpos = buttonX;
475   b = new ButtonWidget(boss, lfont, xpos, ypos, buttonW, lineHeight,
476                        "RESM1", kResM1Cmd);
477   b->setTarget(this);
478   addFocusWidget(b);
479 
480   ////////////////////////////
481   // BL register info
482   ////////////////////////////
483   // enaBL
484   xpos = 10;  ypos += lineHeight + 4;
485   new StaticTextWidget(boss, lfont, xpos, ypos+2, 2*fontWidth, fontHeight,
486                        "BL", TextAlign::Left);
487   xpos += 2*fontWidth + 5;
488   myEnaBL = new TogglePixelWidget(boss, nfont, xpos, ypos+1, 1, 1);
489   myEnaBL->setTarget(this);
490   myEnaBL->setID(kEnaBLID);
491   myEnaBL->clearBackgroundColor();
492   addFocusWidget(myEnaBL);
493 
494   // posBL
495   xpos += myEnaBL->getWidth() + 12;
496   t = new StaticTextWidget(boss, lfont, xpos, ypos+2, 4*fontWidth, fontHeight,
497                            "Pos#", TextAlign::Left);
498   xpos += t->getWidth() + 2;
499   myPosBL = new DataGridWidget(boss, nfont, xpos, ypos,
500                                1, 1, 3, 8, Common::Base::Fmt::_10);
501   myPosBL->setTarget(this);
502   myPosBL->setID(kPosBLID);
503   myPosBL->setRange(0, 160);
504   addFocusWidget(myPosBL);
505 
506   // hmBL
507   xpos += myPosBL->getWidth() + 12;
508   new StaticTextWidget(boss, lfont, xpos, ypos+2, 2*fontWidth, fontHeight,
509                        "HM", TextAlign::Left);
510   xpos += 2*fontWidth + 5;
511   myHMBL = new DataGridWidget(boss, nfont, xpos, ypos,
512                               1, 1, 1, 4, Common::Base::Fmt::_16_1);
513   myHMBL->setTarget(this);
514   myHMBL->setID(kHMBLID);
515   addFocusWidget(myHMBL);
516 
517   // CTRLPF (size portion)
518   xpos += myHMBL->getWidth() + 12;
519   new StaticTextWidget(boss, lfont, xpos, ypos+2, 4*fontWidth, fontHeight,
520                        "Size", TextAlign::Left);
521   xpos += 4*fontWidth + 5;
522   mySizeBL = new DataGridWidget(boss, nfont, xpos, ypos,
523                                 1, 1, 1, 2, Common::Base::Fmt::_16_1);
524   mySizeBL->setTarget(this);
525   mySizeBL->setID(kSizeBLID);
526   addFocusWidget(mySizeBL);
527 
528   // Reset ball
529   xpos = buttonX;
530   b = new ButtonWidget(boss, lfont, xpos, ypos, buttonW, lineHeight,
531                        "RESBL", kResBLCmd);
532   b->setTarget(this);
533   addFocusWidget(b);
534 
535   // Ball (old)
536   xpos = 10 + 2*fontWidth + 5;  ypos += myEnaBL->getHeight() + 5;
537   myEnaBLOld = new TogglePixelWidget(boss, nfont, xpos, ypos+1, 1, 1);
538   myEnaBLOld->setTarget(this);
539   myEnaBLOld->setID(kEnaBLOldID);
540   myEnaBLOld->clearBackgroundColor();
541   addFocusWidget(myEnaBLOld);
542 
543   // Ball delay
544   xpos += myEnaBLOld->getWidth() + 12;
545   myDelBL = new CheckboxWidget(boss, lfont, xpos, ypos+1,
546                                "VDel", CheckboxWidget::kCheckActionCmd);
547   myDelBL->setTarget(this);
548   myDelBL->setID(kDelBLID);
549   addFocusWidget(myDelBL);
550 
551   ////////////////////////////
552   // PF 0/1/2 registers
553   ////////////////////////////
554   const GUI::Font& sf = instance().frameBuffer().smallFont();
555   const int sfWidth = sf.getMaxCharWidth(),
556             sfHeight = sf.getFontHeight();
557   static constexpr std::array<const char*, 8> bitNames = {
558     "0", "1", "2", "3", "4", "5", "6", "7"
559   };
560 
561   // PF0
562   xpos = 10;  ypos += lineHeight + sfHeight + 6;
563   new StaticTextWidget(boss, lfont, xpos, ypos+2, 2*fontWidth, fontHeight,
564                        "PF", TextAlign::Left);
565   xpos += 2*fontWidth + 5;
566   myPF[0] = new TogglePixelWidget(boss, nfont, xpos, ypos+1, 4, 1, 4);
567   myPF[0]->setTarget(this);
568   myPF[0]->setID(kPF0ID);
569   addFocusWidget(myPF[0]);
570 
571   // PF1
572   xpos += myPF[0]->getWidth() + 2;
573   myPF[1] = new TogglePixelWidget(boss, nfont, xpos, ypos+1, 8, 1);
574   myPF[1]->setTarget(this);
575   myPF[1]->setID(kPF1ID);
576   addFocusWidget(myPF[1]);
577 
578   // PF2
579   xpos += myPF[1]->getWidth() + 2;
580   myPF[2] = new TogglePixelWidget(boss, nfont, xpos, ypos+1, 8, 1);
581   myPF[2]->setTarget(this);
582   myPF[2]->setID(kPF2ID);
583   addFocusWidget(myPF[2]);
584 
585   // PFx bit labels
586   auto start = [&](int sw) { return (sw - sfWidth) / 2; };
587   int colw = myPF[0]->getWidth() / 4;
588   xpos = 10 + 2*fontWidth + 5 + start(colw);
589   int _ypos = ypos - sfHeight;
590   for(int i = 4; i <= 7; ++i)
591   {
592     new StaticTextWidget(boss, sf, xpos, _ypos, sfWidth, sfHeight,
593                          bitNames[i], TextAlign::Left);
594     xpos += colw;
595   }
596   xpos = 10 + 2*fontWidth + 5 + myPF[0]->getWidth() + 2 + start(colw);
597   for(int i = 7; i >= 0; --i)
598   {
599     new StaticTextWidget(boss, sf, xpos, _ypos, sfWidth, sfHeight,
600                          bitNames[i], TextAlign::Left);
601     xpos += colw;
602   }
603   xpos = 10 + 2*fontWidth + 5 + myPF[0]->getWidth() + 2 +
604          myPF[1]->getWidth() + 2 + start(colw);
605   for(int i = 0; i <= 7; ++i)
606   {
607     new StaticTextWidget(boss, sf, xpos, _ypos, sfWidth, sfHeight,
608                          bitNames[i], TextAlign::Left);
609     xpos += colw;
610   }
611 
612   // PF reflect, score, priority
613   xpos = 10 + 4*fontWidth;  ypos += lineHeight + 6;
614   myRefPF = new CheckboxWidget(boss, lfont, xpos, ypos+1,
615                                "Reflect", CheckboxWidget::kCheckActionCmd);
616   myRefPF->setTarget(this);
617   myRefPF->setID(kRefPFID);
618   addFocusWidget(myRefPF);
619 
620   xpos += myRefPF->getWidth() + 15;
621   myScorePF = new CheckboxWidget(boss, lfont, xpos, ypos+1,
622                                  "Score", CheckboxWidget::kCheckActionCmd);
623   myScorePF->setTarget(this);
624   myScorePF->setID(kScorePFID);
625   addFocusWidget(myScorePF);
626 
627   xpos += myScorePF->getWidth() + 15;
628   myPriorityPF = new CheckboxWidget(boss, lfont, xpos, ypos+1,
629                                     "Priority", CheckboxWidget::kCheckActionCmd);
630   myPriorityPF->setTarget(this);
631   myPriorityPF->setID(kPriorityPFID);
632   addFocusWidget(myPriorityPF);
633 
634   xpos = 10;
635   ypos += lineHeight + 10;
636   t = new StaticTextWidget(boss, lfont, xpos, ypos, 13*fontWidth, fontHeight,
637     "Queued Writes", TextAlign::Left);
638 
639   xpos += t->getWidth() + 10;
640   myDelayQueueWidget = new DelayQueueWidget(boss, lfont, xpos, ypos);
641 
642   ////////////////////////////
643   // Strobe buttons
644   ////////////////////////////
645   buttonX = xpos + myDelayQueueWidget->getWidth() + 20;
646   buttonY = ypos;
647   b = new ButtonWidget(boss, lfont, buttonX, buttonY, buttonW, lineHeight,
648                        "WSYNC", kWsyncCmd);
649   b->setTarget(this);
650   addFocusWidget(b);
651 
652   buttonY += lineHeight + 3;
653   b = new ButtonWidget(boss, lfont, buttonX, buttonY, buttonW, lineHeight,
654                        "RSYNC", kRsyncCmd);
655   b->setTarget(this);
656   addFocusWidget(b);
657 
658   buttonX = b->getRight() + 20;
659   buttonY = ypos;
660   b = new ButtonWidget(boss, lfont, buttonX, buttonY, buttonW, lineHeight,
661                        "HMOVE", kHmoveCmd);
662   b->setTarget(this);
663   addFocusWidget(b);
664 
665   buttonY += lineHeight + 3;
666   b = new ButtonWidget(boss, lfont, buttonX, buttonY, buttonW, lineHeight,
667                        "HMCLR", kHmclrCmd);
668   b->setTarget(this);
669   addFocusWidget(b);
670 
671   setHelpAnchor("TIATab", true);
672 }
673 
674 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
handleCommand(CommandSender * sender,int cmd,int data,int id)675 void TiaWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
676 {
677   Debugger& dbg = instance().debugger();
678   TIADebug& tia = dbg.tiaDebug();
679 
680   switch(cmd)
681   {
682     case kWsyncCmd:
683       tia.strobeWsync();
684       break;
685 
686     case kRsyncCmd:
687       tia.strobeRsync();
688       break;
689 
690     case kResP0Cmd:
691       tia.strobeResP0();
692       break;
693 
694     case kResP1Cmd:
695       tia.strobeResP1();
696       break;
697 
698     case kResM0Cmd:
699       tia.strobeResM0();
700       break;
701 
702     case kResM1Cmd:
703       tia.strobeResM1();
704       break;
705 
706     case kResBLCmd:
707       tia.strobeResBL();
708       break;
709 
710     case kHmoveCmd:
711       tia.strobeHmove();
712       break;
713 
714     case kHmclrCmd:
715       tia.strobeHmclr();
716       break;
717 
718     case kCxclrCmd:
719       tia.strobeCxclr();
720       break;
721 
722     case kDbgClCmd:
723       myFixedEnabled->setState(tia.tia().toggleFixedColors());
724       break;
725 
726     case kVSyncCmd:
727       tia.vsync((tia.vsyncAsInt() & ~0x02) | (myVSync->getState() ? 0x02 : 0x00));
728       break;
729 
730     case kVBlankCmd:
731       tia.vblank((tia.vblankAsInt() & ~0x02) | (myVBlank->getState() ? 0x02 : 0x00));
732       break;
733 
734     case DataGridWidget::kItemDataChangedCmd:
735       switch(id)
736       {
737         case kColorRegsID:
738           changeColorRegs();
739           break;
740 
741         case kPosP0ID:
742           tia.posP0(myPosP0->getSelectedValue());
743           break;
744 
745         case kPosP1ID:
746           tia.posP1(myPosP1->getSelectedValue());
747           break;
748 
749         case kPosM0ID:
750           tia.posM0(myPosM0->getSelectedValue());
751           break;
752 
753         case kPosM1ID:
754           tia.posM1(myPosM1->getSelectedValue());
755           break;
756 
757         case kPosBLID:
758           tia.posBL(myPosBL->getSelectedValue());
759           break;
760 
761         case kHMP0ID:
762           tia.hmP0(myHMP0->getSelectedValue());
763           break;
764 
765         case kHMP1ID:
766           tia.hmP1(myHMP1->getSelectedValue());
767           break;
768 
769         case kHMM0ID:
770           tia.hmM0(myHMM0->getSelectedValue());
771           break;
772 
773         case kHMM1ID:
774           tia.hmM1(myHMM1->getSelectedValue());
775           break;
776 
777         case kHMBLID:
778           tia.hmBL(myHMBL->getSelectedValue());
779           break;
780 
781         case kNusizP0ID:
782           tia.nusizP0(myNusizP0->getSelectedValue());
783           myNusizP0Text->setText(tia.nusizP0String());
784           break;
785 
786         case kNusizP1ID:
787           tia.nusizP1(myNusizP1->getSelectedValue());
788           myNusizP1Text->setText(tia.nusizP1String());
789           break;
790 
791         case kNusizM0ID:
792           tia.nusizM0(myNusizM0->getSelectedValue());
793           break;
794 
795         case kNusizM1ID:
796           tia.nusizM1(myNusizM1->getSelectedValue());
797           break;
798 
799         case kSizeBLID:
800           tia.sizeBL(mySizeBL->getSelectedValue());
801           break;
802 
803         default:
804           cerr << "TiaWidget DG changed\n";
805           break;
806       }
807       break;
808 
809     case ToggleWidget::kItemDataChangedCmd:
810       switch(id)
811       {
812         case kGRP0ID:
813           tia.grP0(myGRP0->getIntState());
814           break;
815 
816         case kGRP0OldID:
817           tia.setGRP0Old(myGRP0Old->getIntState());
818           break;
819 
820         case kGRP1ID:
821           tia.grP1(myGRP1->getIntState());
822           break;
823 
824         case kGRP1OldID:
825           tia.setGRP1Old(myGRP1Old->getIntState());
826           break;
827 
828         case kEnaM0ID:
829           tia.enaM0(myEnaM0->getIntState());
830           break;
831 
832         case kEnaM1ID:
833           tia.enaM1(myEnaM1->getIntState());
834           break;
835 
836         case kEnaBLID:
837           tia.enaBL(myEnaBL->getIntState());
838           break;
839 
840         case kEnaBLOldID:
841           tia.setENABLOld(myEnaBLOld->getIntState() != 0);
842           break;
843 
844         case kPF0ID:
845           tia.pf0(myPF[0]->getIntState());
846           break;
847 
848         case kPF1ID:
849           tia.pf1(myPF[1]->getIntState());
850           break;
851 
852         case kPF2ID:
853           tia.pf2(myPF[2]->getIntState());
854           break;
855 
856         default:
857           break;
858       }
859       break;
860 
861     case CheckboxWidget::kCheckActionCmd:
862       switch(id)
863       {
864         case kP0_PFID:
865           tia.collision(CollisionBit::P0PF, true);
866           break;
867 
868         case kP0_BLID:
869           tia.collision(CollisionBit::P0BL, true);
870           break;
871 
872         case kP0_M1ID:
873           tia.collision(CollisionBit::M1P0, true);
874           break;
875 
876         case kP0_M0ID:
877           tia.collision(CollisionBit::M0P0, true);
878           break;
879 
880         case kP0_P1ID:
881           tia.collision(CollisionBit::P0P1, true);
882           break;
883 
884         case kP1_PFID:
885           tia.collision(CollisionBit::P1PF, true);
886           break;
887         case kP1_BLID:
888           tia.collision(CollisionBit::P1BL, true);
889           break;
890 
891         case kP1_M1ID:
892           tia.collision(CollisionBit::M1P1, true);
893           break;
894         case kP1_M0ID:
895           tia.collision(CollisionBit::M0P1, true);
896           break;
897 
898         case kM0_PFID:
899           tia.collision(CollisionBit::M0PF, true);
900           break;
901 
902         case kM0_BLID:
903           tia.collision(CollisionBit::M0BL, true);
904           break;
905 
906         case kM0_M1ID:
907           tia.collision(CollisionBit::M0M1, true);
908           break;
909 
910         case kM1_PFID:
911           tia.collision(CollisionBit::M1PF, true);
912           break;
913 
914         case kM1_BLID:
915           tia.collision(CollisionBit::M1BL, true);
916           break;
917 
918         case kBL_PFID:
919           tia.collision(CollisionBit::BLPF, true);
920           break;
921 
922         case kRefP0ID:
923           tia.refP0(myRefP0->getState() ? 1 : 0);
924           break;
925 
926         case kRefP1ID:
927           tia.refP1(myRefP1->getState() ? 1 : 0);
928           break;
929 
930         case kDelP0ID:
931           tia.vdelP0(myDelP0->getState() ? 1 : 0);
932           break;
933 
934         case kDelP1ID:
935           tia.vdelP1(myDelP1->getState() ? 1 : 0);
936           break;
937 
938         case kDelBLID:
939           tia.vdelBL(myDelBL->getState() ? 1 : 0);
940           break;
941 
942         case kResMP0ID:
943           tia.resMP0(myResMP0->getState() ? 1 : 0);
944           break;
945 
946         case kResMP1ID:
947           tia.resMP1(myResMP1->getState() ? 1 : 0);
948           break;
949 
950         case kRefPFID:
951           tia.refPF(myRefPF->getState() ? 1 : 0);
952           break;
953 
954         case kScorePFID:
955           tia.scorePF(myScorePF->getState() ? 1 : 0);
956           break;
957 
958         case kPriorityPFID:
959           tia.priorityPF(myPriorityPF->getState() ? 1 : 0);
960           break;
961 
962         default:
963           break;
964       }
965       break;
966 
967     default:
968       break;
969   }
970 }
971 
972 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
loadConfig()973 void TiaWidget::loadConfig()
974 {
975   IntArray alist;
976   IntArray vlist;
977   BoolArray blist, changed, grNew, grOld;
978 
979   Debugger& dbg = instance().debugger();
980   TIADebug& tia = dbg.tiaDebug();
981   const TiaState& state    = static_cast<const TiaState&>(tia.getState());
982   const TiaState& oldstate = static_cast<const TiaState&>(tia.getOldState());
983 
984   // Color registers
985   alist.clear();  vlist.clear();  changed.clear();
986   for(uInt32 i = 0; i < 4; ++i)
987   {
988     alist.push_back(i);
989     vlist.push_back(state.coluRegs[i]);
990     changed.push_back(state.coluRegs[i] != oldstate.coluRegs[i]);
991   }
992   myColorRegs->setList(alist, vlist, changed);
993 
994   bool fixed = tia.tia().usingFixedColors();
995 
996   myCOLUP0Color->setColor(state.coluRegs[0]);
997   myCOLUP1Color->setColor(state.coluRegs[1]);
998   myCOLUPFColor->setColor(state.coluRegs[2]);
999   myCOLUBKColor->setColor(state.coluRegs[3]);
1000   myCOLUP0Color->setCrossed(fixed);
1001   myCOLUP1Color->setCrossed(fixed);
1002   myCOLUPFColor->setCrossed(fixed);
1003   myCOLUBKColor->setCrossed(fixed);
1004 
1005   // Fixed debug colors
1006   myFixedEnabled->setState(fixed);
1007   for(uInt32 c = 0; c < 8; ++c)
1008   {
1009     myFixedColors[c]->setColor(state.fixedCols[c]);
1010     myFixedColors[c]->setCrossed(!fixed);
1011   }
1012 
1013   ////////////////////////////
1014   // Collision register bits
1015   ////////////////////////////
1016   myCollision[kP0_PFID]->setState(tia.collP0_PF(), state.cx[0] != oldstate.cx[0]);
1017   myCollision[kP0_BLID]->setState(tia.collP0_BL(), state.cx[1] != oldstate.cx[1]);
1018   myCollision[kP0_M1ID]->setState(tia.collM1_P0(), state.cx[2] != oldstate.cx[2]);
1019   myCollision[kP0_M0ID]->setState(tia.collM0_P0(), state.cx[3] != oldstate.cx[3]);
1020   myCollision[kP0_P1ID]->setState(tia.collP0_P1(), state.cx[4] != oldstate.cx[4]);
1021   myCollision[kP1_PFID]->setState(tia.collP1_PF(), state.cx[5] != oldstate.cx[5]);
1022   myCollision[kP1_BLID]->setState(tia.collP1_BL(), state.cx[6] != oldstate.cx[6]);
1023   myCollision[kP1_M1ID]->setState(tia.collM1_P1(), state.cx[7] != oldstate.cx[7]);
1024   myCollision[kP1_M0ID]->setState(tia.collM0_P1(), state.cx[8] != oldstate.cx[8]);
1025   myCollision[kM0_PFID]->setState(tia.collM0_PF(), state.cx[9] != oldstate.cx[9]);
1026   myCollision[kM0_BLID]->setState(tia.collM0_BL(), state.cx[10] != oldstate.cx[10]);
1027   myCollision[kM0_M1ID]->setState(tia.collM0_M1(), state.cx[11] != oldstate.cx[11]);
1028   myCollision[kM1_PFID]->setState(tia.collM1_PF(), state.cx[12] != oldstate.cx[12]);
1029   myCollision[kM1_BLID]->setState(tia.collM1_BL(), state.cx[13] != oldstate.cx[13]);
1030   myCollision[kBL_PFID]->setState(tia.collBL_PF(), state.cx[14] != oldstate.cx[14]);
1031 
1032   ////////////////////////////
1033   // P0 register info
1034   ////////////////////////////
1035   // grP0 (new and old)
1036   if(tia.vdelP0())
1037   {
1038     myGRP0->setColor(kBGColorLo);
1039     myGRP0Old->setColor(state.coluRegs[0]);
1040     myGRP0Old->setCrossed(false);
1041   }
1042   else
1043   {
1044     myGRP0->setColor(state.coluRegs[0]);
1045     myGRP0Old->setColor(kBGColorLo);
1046     myGRP0Old->setCrossed(true);
1047   }
1048   myGRP0->setIntState(state.gr[TiaState::P0], state.ref[TiaState::P0]);
1049   myGRP0Old->setIntState(state.gr[TiaState::P0+2], state.ref[TiaState::P0]);
1050 
1051   // posP0
1052   myPosP0->setList(0, state.pos[TiaState::P0],
1053       state.pos[TiaState::P0] != oldstate.pos[TiaState::P0]);
1054 
1055   // hmP0
1056   myHMP0->setList(0, state.hm[TiaState::P0],
1057       state.hm[TiaState::P0] != oldstate.hm[TiaState::P0]);
1058 
1059   // refP0 & vdelP0
1060   myRefP0->setState(tia.refP0(), state.ref[TiaState::P0] != oldstate.ref[TiaState::P0]);
1061   myDelP0->setState(tia.vdelP0(), state.vdel[TiaState::P0] != oldstate.vdel[TiaState::P0]);
1062 
1063   // NUSIZ0 (player portion)
1064   bool nusiz0changed = state.size[TiaState::P0] != oldstate.size[TiaState::P0];
1065   myNusizP0->setList(0, state.size[TiaState::P0], nusiz0changed);
1066   myNusizP0Text->setText(tia.nusizP0String(), nusiz0changed);
1067 
1068   ////////////////////////////
1069   // P1 register info
1070   ////////////////////////////
1071   // grP1 (new and old)
1072   if(tia.vdelP1())
1073   {
1074     myGRP1->setColor(kBGColorLo);
1075     myGRP1Old->setColor(state.coluRegs[1]);
1076     myGRP1Old->setCrossed(false);
1077   }
1078   else
1079   {
1080     myGRP1->setColor(state.coluRegs[1]);
1081     myGRP1Old->setColor(kBGColorLo);
1082     myGRP1Old->setCrossed(true);
1083   }
1084   myGRP1->setIntState(state.gr[TiaState::P1], state.ref[TiaState::P1]);
1085   myGRP1Old->setIntState(state.gr[TiaState::P1+2], state.ref[TiaState::P1]);
1086 
1087   // posP1
1088   myPosP1->setList(0, state.pos[TiaState::P1],
1089       state.pos[TiaState::P1] != oldstate.pos[TiaState::P1]);
1090 
1091   // hmP1
1092   myHMP1->setList(0, state.hm[TiaState::P1],
1093       state.hm[TiaState::P1] != oldstate.hm[TiaState::P1]);
1094 
1095   // refP1 & vdelP1
1096   myRefP1->setState(tia.refP1(), state.ref[TiaState::P1] != oldstate.ref[TiaState::P1]);
1097   myDelP1->setState(tia.vdelP1(), state.vdel[TiaState::P1] != oldstate.vdel[TiaState::P1]);
1098 
1099   // NUSIZ1 (player portion)
1100   bool nusiz1changed = state.size[TiaState::P1] != oldstate.size[TiaState::P1];
1101   myNusizP1->setList(0, state.size[TiaState::P1], nusiz1changed);
1102   myNusizP1Text->setText(tia.nusizP1String(), nusiz1changed);
1103 
1104   ////////////////////////////
1105   // M0 register info
1106   ////////////////////////////
1107   // enaM0
1108   myEnaM0->setColor(state.coluRegs[0]);
1109   myEnaM0->setIntState(tia.enaM0() ? 1 : 0, false);
1110 
1111   // posM0
1112   myPosM0->setList(0, state.pos[TiaState::M0],
1113       state.pos[TiaState::M0] != oldstate.pos[TiaState::M0]);
1114 
1115   // hmM0
1116   myHMM0->setList(0, state.hm[TiaState::M0],
1117       state.hm[TiaState::M0] != oldstate.hm[TiaState::M0]);
1118 
1119   // NUSIZ0 (missile portion)
1120   myNusizM0->setList(0, state.size[TiaState::M0],
1121       state.size[TiaState::M0] != oldstate.size[TiaState::M0]);
1122 
1123   // resMP0
1124   myResMP0->setState(tia.resMP0(), state.resm[TiaState::P0] != oldstate.resm[TiaState::P0]);
1125 
1126   ////////////////////////////
1127   // M1 register info
1128   ////////////////////////////
1129   // enaM1
1130   myEnaM1->setColor(state.coluRegs[1]);
1131   myEnaM1->setIntState(tia.enaM1() ? 1 : 0, false);
1132 
1133   // posM1
1134   myPosM1->setList(0, state.pos[TiaState::M1],
1135       state.pos[TiaState::M1] != oldstate.pos[TiaState::M1]);
1136 
1137   // hmM1
1138   myHMM1->setList(0, state.hm[TiaState::M1],
1139       state.hm[TiaState::M1] != oldstate.hm[TiaState::M1]);
1140 
1141   // NUSIZ1 (missile portion)
1142   myNusizM1->setList(0, state.size[TiaState::M1],
1143       state.size[TiaState::M1] != oldstate.size[TiaState::M1]);
1144 
1145   // resMP1
1146   myResMP1->setState(tia.resMP1(),state.resm[TiaState::P1] != oldstate.resm[TiaState::P1]);
1147 
1148   ////////////////////////////
1149   // BL register info
1150   ////////////////////////////
1151   // enaBL (new and old)
1152   if(tia.vdelBL())
1153   {
1154     myEnaBL->setColor(kBGColorLo);
1155     myEnaBLOld->setColor(state.coluRegs[2]);
1156     myEnaBLOld->setCrossed(false);
1157   }
1158   else
1159   {
1160     myEnaBL->setColor(state.coluRegs[2]);
1161     myEnaBLOld->setColor(kBGColorLo);
1162     myEnaBLOld->setCrossed(true);
1163   }
1164   myEnaBL->setIntState(state.gr[4], false);
1165   myEnaBLOld->setIntState(state.gr[5], false);
1166 
1167   // posBL
1168   myPosBL->setList(0, state.pos[TiaState::BL],
1169       state.pos[TiaState::BL] != oldstate.pos[TiaState::BL]);
1170 
1171   // hmBL
1172   myHMBL->setList(0, state.hm[TiaState::BL],
1173       state.hm[TiaState::BL] != oldstate.hm[TiaState::BL]);
1174 
1175   // CTRLPF (size portion)
1176   mySizeBL->setList(0, state.size[TiaState::BL],
1177       state.size[TiaState::BL] != oldstate.size[TiaState::BL]);
1178 
1179   // vdelBL
1180   myDelBL->setState(tia.vdelBL(), state.vdel[2] != oldstate.vdel[2]);
1181 
1182   ////////////////////////////
1183   // PF register info
1184   ////////////////////////////
1185   // PF0
1186   myPF[0]->setColor(state.coluRegs[2]);
1187   myPF[0]->setIntState(state.pf[0], true);  // reverse bit order
1188 
1189   // PF1
1190   myPF[1]->setColor(state.coluRegs[2]);
1191   myPF[1]->setIntState(state.pf[1], false);
1192 
1193   // PF2
1194   myPF[2]->setColor(state.coluRegs[2]);
1195   myPF[2]->setIntState(state.pf[2], true);  // reverse bit order
1196 
1197   // Reflect
1198   myRefPF->setState(tia.refPF(), state.pf[3] != oldstate.pf[3]);
1199 
1200   // Score
1201   myScorePF->setState(tia.scorePF(), state.pf[4] != oldstate.pf[4]);
1202 
1203   // Priority
1204   myPriorityPF->setState(tia.priorityPF(), state.pf[5] != oldstate.pf[5]);
1205 
1206   myDelayQueueWidget->loadConfig();
1207 
1208   myVSync->setState(tia.vsync(), tia.vsync() != oldstate.vsb[0]);
1209   myVBlank->setState(tia.vblank(), tia.vblank() != oldstate.vsb[1]);
1210 }
1211 
1212 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
changeColorRegs()1213 void TiaWidget::changeColorRegs()
1214 {
1215   int addr  = myColorRegs->getSelectedAddr();
1216   int value = myColorRegs->getSelectedValue();
1217 
1218   switch(addr)
1219   {
1220     case kCOLUP0Addr:
1221       instance().debugger().tiaDebug().coluP0(value);
1222       myCOLUP0Color->setColor(value);
1223       break;
1224 
1225     case kCOLUP1Addr:
1226       instance().debugger().tiaDebug().coluP1(value);
1227       myCOLUP1Color->setColor(value);
1228       break;
1229 
1230     case kCOLUPFAddr:
1231       instance().debugger().tiaDebug().coluPF(value);
1232       myCOLUPFColor->setColor(value);
1233       break;
1234 
1235     case kCOLUBKAddr:
1236       instance().debugger().tiaDebug().coluBK(value);
1237       myCOLUBKColor->setColor(value);
1238       break;
1239 
1240     default:
1241       break;
1242   }
1243 }
1244