mirror of
https://github.com/stella-emu/stella.git
synced 2026-10-11 22:29:55 +00:00
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:
@@ -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
@@ -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
@@ -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};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user