Finalized MemView dialog layout (#1186)

* Improved and fixed the MemView dialog layout; the TWO_LINE_DECAY switch selects one or two line decay rate slider display

* MemView: saved some more space by pulling the first big view label into the settings column again
This commit is contained in:
hammersdev
2026-10-11 11:38:40 -02:30
committed by GitHub
parent 6787c39275
commit a8ef4ac25e
4 changed files with 70 additions and 27 deletions
@@ -142,23 +142,36 @@ MemViewWindowDialog::MemViewWindowDialog(OSystem& osystem, DialogContainer& pare
myShowData = new CheckboxWidget(this, font, TEXT_SHOW_DATA, Cmd::ShowDataChanged);
wid.push_back(myShowData);
// Use a slightly different size for the swatch boxes than default
// - 1 because the frame will be drawn one pixel larger than commanded (?)
const int swatchHeight = CheckboxWidget::boxSize(font) + 2 * (font.getLineHeight() / 8) - 1;
const int swatchWidth = swatchHeight * 2;
myShowPc = new CheckboxWidget(this, font, TEXT_SHOW_PC, Cmd::ShowPcChanged);
wid.push_back(myShowPc);
myPcColor = new ColorWidget(this, font);
myPcColor = new ColorWidget(this, font, swatchWidth, swatchHeight);
myPcColor->setColorRgb(pcWidgetColor);
myShowReads = new CheckboxWidget(this, font, TEXT_SHOW_READS, Cmd::ShowReadsChanged);
wid.push_back(myShowReads);
myReadColor = new ColorWidget(this, font);
myReadColor = new ColorWidget(this, font, swatchWidth, swatchHeight);
myReadColor->setColorRgb(readWidgetColor);
myShowWrites = new CheckboxWidget(this, font, TEXT_SHOW_WRITES, Cmd::ShowWritesChanged);
wid.push_back(myShowWrites);
myWriteColor = new ColorWidget(this, font);
myWriteColor = new ColorWidget(this, font, swatchWidth, swatchHeight);
myWriteColor->setColorRgb(writeWidgetColor);
myDecayLbl = new LabelWidget(this, font, TEXT_DECAY_RATE);
myDecaySlider = new SliderWidget(this, font, 10, Cmd::DecayRateChanged, 4, "%");
if constexpr (TWO_LINE_DECAY)
myDecayLbl = new LabelWidget(this, font, TEXT_DECAY_RATE);
else
// If you ask me, the full text would make the settings too wide
myDecayLbl = new LabelWidget(this, font, TEXT_DECAY);
// Make the slider wide enough to be able to set every value between 0..100
const int fontWidth = _font.getMaxCharWidth();
const int sliderChars = (101 + fontWidth - 1) / fontWidth;
myDecaySlider = new SliderWidget(this, font, sliderChars, Cmd::DecayRateChanged, 4, "%", 0, false, true);
myDecaySlider->setMinValue(0);
myDecaySlider->setMaxValue(100);
myDecaySlider->setStepValue(1);
@@ -510,12 +523,13 @@ void MemViewWindowDialog::updateViews()
updateAccessData();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void MemViewWindowDialog::layout()
{
using GUI::BoxLayout;
using GUI::anchoredItem;
using GUI::stretchedItem;
using GUI::alignedItem;
using GUI::widgetItem;
using GUI::labeledRow;
using Dir = BoxLayout::Dir;
@@ -526,24 +540,25 @@ void MemViewWindowDialog::layout()
const int HBORDER = Dialog::hBorder(),
VBORDER = Dialog::vBorder(),
VGAP = Dialog::vGap();
static constexpr int DIALOG_MARGIN_H = 14;
static constexpr int DIALOG_MARGIN_V = 12;
VGAP = Dialog::vGap(),
DIALOG_MARGIN_H = HBORDER * 1.6,
DIALOG_MARGIN_V = VBORDER * 1.6,
RAM_SETTINGS_GAP = VGAP * 4;
// Create views now that it is foreseeable they will be assigned a size
if (myFirstLayout)
if(myFirstLayout)
createViews();
const auto buildRoot = [&](int mainMaxW) {
const auto swatchRow = [](CheckboxWidget* cb, ColorWidget* swatch) {
const auto swatchRow = [&](CheckboxWidget* cb, ColorWidget* swatch) {
auto row = std::make_unique<BoxLayout>(Dir::Horizontal);
row->addAuto(anchoredItem(cb));
row->addStretchSpace();
row->addStretchSpace(1, fontWidth() * 3);
row->addAuto(anchoredItem(swatch));
return row;
};
auto settingsCol = std::make_unique<BoxLayout>(Dir::Vertical, VGAP, 0, DIALOG_MARGIN_V);
auto settingsCol = std::make_unique<BoxLayout>(Dir::Vertical, VGAP);
settingsCol->addAuto(anchoredItem(mySingleRow));
settingsCol->addAuto(anchoredItem(mySeparators));
settingsCol->addAuto(anchoredItem(myInverted));
@@ -554,7 +569,15 @@ void MemViewWindowDialog::layout()
settingsCol->addAuto(swatchRow(myShowReads, myReadColor));
settingsCol->addAuto(swatchRow(myShowWrites, myWriteColor));
settingsCol->addSpace(VGAP);
settingsCol->addAuto(labeledRow(myDecayLbl, myDecaySlider));
if constexpr(TWO_LINE_DECAY) {
settingsCol->addAuto(anchoredItem(myDecayLbl));
settingsCol->addAuto(stretchedItem(myDecaySlider));
} else {
auto decayRow = std::make_unique<BoxLayout>(BoxLayout::Dir::Horizontal);
decayRow->addAuto(anchoredItem(myDecayLbl));
decayRow->addStretch(alignedItem(myDecaySlider, GUI::HAlign::Right, GUI::VAlign::Center));
settingsCol->addAuto(std::move(decayRow));
}
settingsCol->addSpace(VGAP);
settingsCol->addAuto(anchoredItem(myClearButton));
@@ -571,7 +594,8 @@ void MemViewWindowDialog::layout()
// different border constants and drift apart by a few px, which is enough
// to drop a whole zoom level and strand unused space below the grid
const int ramMaxH = std::max(I32(ramMin.h),
_h - 2 * VBORDER - I32(settingsSize.h) - VGAP);
_h - 2 * DIALOG_MARGIN_V - I32(settingsSize.h) - RAM_SETTINGS_GAP);
myRamView->setMaxCandidateSize(settingsW, ramMaxH);
auto ramRow = std::make_unique<BoxLayout>(Dir::Horizontal, HBORDER);
@@ -591,13 +615,22 @@ void MemViewWindowDialog::layout()
I32(cartRamMin.h)));
}
auto leftCol = std::make_unique<BoxLayout>(Dir::Vertical, VGAP);
// Add correct first label for main area
ramRow->addStretchSpace(1, HBORDER);
ramRow->addAuto(GUI::alignedItem((myCartRamView && myBigCartRam) ? myCartRamLbl : myRomLbl,
GUI::HAlign::Left, GUI::VAlign::Top));
auto leftCol = std::make_unique<BoxLayout>(Dir::Vertical, RAM_SETTINGS_GAP);
// Reserve the full candidate height so the settings column tracks a drag
// continuously, rather than snapping when RAM's zoom level steps down
leftCol->addFixed(std::move(ramRow), ramMaxH, 0);
leftCol->addAuto(std::move(settingsCol));
auto lowerLeft = std::make_unique<BoxLayout>(Dir::Horizontal);
lowerLeft->addAuto(std::move(settingsCol));
// Minimum extra space between the swatches and the first big view
lowerLeft->addSpace(HBORDER * 2);
leftCol->addAuto(std::move(lowerLeft));
if (mainMaxW > 0)
if(mainMaxW > 0)
{
// Calculate the best sizes of the main views
const int mainMaxH = _h - 2 * DIALOG_MARGIN_V;
@@ -621,10 +654,10 @@ void MemViewWindowDialog::layout()
root->addAuto(std::move(leftCol));
if(myBigCartRam)
{
root->addAuto(GUI::alignedItem(myCartRamLbl, GUI::HAlign::Left, GUI::VAlign::Top));
addMainView(*root, Cartridge::ImageScope::NONE, myCartRamView);
root->addAuto(GUI::alignedItem(myRomLbl, GUI::HAlign::Left, GUI::VAlign::Top));
}
root->addAuto(GUI::alignedItem(myRomLbl, GUI::HAlign::Left, GUI::VAlign::Top));
for(const auto& [scope, view]: myViews)
if(scope != Cartridge::ImageScope::NONE)
addMainView(*root, scope, view);
@@ -75,7 +75,9 @@ class MemViewWindowDialog : public Dialog
static constexpr std::string_view TEXT_SHOW_PC = "Show PC";
static constexpr std::string_view TEXT_SHOW_READS = "Show reads";
static constexpr std::string_view TEXT_SHOW_WRITES = "Show writes";
static constexpr std::string_view TEXT_DECAY_RATE = "Decay rate:";
static constexpr bool TWO_LINE_DECAY = false;
static constexpr std::string_view TEXT_DECAY_RATE = "Decay rate: ";
static constexpr std::string_view TEXT_DECAY = "Decay: ";
static constexpr std::string_view TEXT_CLEAR = "Clear";
public:
+10 -5
View File
@@ -1035,14 +1035,15 @@ void CheckboxWidget::drawWidget(bool hilite)
SliderWidget::SliderWidget(GuiObject* boss, const GUI::Font& font,
int trackChars, GuiCmd::Code cmd, int valueChars,
string_view valueUnit, int valueLabelGap,
bool forceLabelSign)
bool forceLabelSign, bool valueRightAligned)
: ButtonWidget(boss, font,
(trackChars != 0 ? trackChars : 10) * font.getMaxCharWidth(),
font.getLineHeight(), "", cmd),
_valueUnit{valueUnit},
_valueLabelGap{valueLabelGap},
_valueLabelWidth{valueChars * font.getMaxCharWidth()},
_forceLabelSign{forceLabelSign}
_forceLabelSign{forceLabelSign},
_valueRightAligned{valueRightAligned}
{
_flags = Widget::Flag::Enabled | Widget::Flag::TrackMouse | Widget::Flag::ClearBG;
_bgcolor = kDlgColor;
@@ -1241,9 +1242,13 @@ void SliderWidget::drawWidget(bool hilite)
s.fillRect(x + p, y - 2, 2, h + 4,
!isEnabled() ? kColor : hilite ? kSliderColorHi : kSliderColor);
if(_valueLabelWidth > 0)
s.drawString(_font, _valueLabel + _valueUnit, _x + _w - _valueLabelWidth,
_y + firstTextY(), _valueLabelWidth,
// Draw the value and unit
const int alignmentOffset = _valueRightAligned ?
std::max(_valueLabelWidth - (static_cast<int>(_valueLabel.size() + _valueUnit.size())
* _fontWidth), 0) : 0;
if((_valueLabelWidth - alignmentOffset) > 0)
s.drawString(_font, _valueLabel + _valueUnit, _x + _w - _valueLabelWidth +
alignmentOffset, _y + firstTextY(), _valueLabelWidth - alignmentOffset,
isEnabled() ? kTextColor : kColor);
}
+4 -1
View File
@@ -689,7 +689,8 @@ class SliderWidget : public ButtonWidget
SliderWidget(GuiObject* boss, const GUI::Font& font,
int trackChars = 0, GuiCmd::Code cmd = GuiCmd::None,
int valueChars = 0, string_view valueUnit = "",
int valueLabelGap = 0, bool forceLabelSign = false);
int valueLabelGap = 0, bool forceLabelSign = false,
bool valueRightAligned = false);
~SliderWidget() override = default;
/** Clamps to [min, max], updates the value label, and sends _cmd if it actually changed */
@@ -757,6 +758,8 @@ class SliderWidget : public ButtonWidget
int _valueLabelWidth{0};
// Whether a positive value label is prefixed with '+'
bool _forceLabelSign{false};
// Show the value and unit right-aligned when there are fewer chars than intended
bool _valueRightAligned{false};
// Number of tickmark intervals drawn along the track (see setTickmarkIntervals)
int _numIntervals{0};