diff --git a/src/common/Rect.hxx b/src/common/Rect.hxx index bb3186548..832d95e88 100644 --- a/src/common/Rect.hxx +++ b/src/common/Rect.hxx @@ -95,7 +95,7 @@ struct Size Another very wide spread approach to rectangle classes treats (bottom,right) also as a part of the rectangle. - Coneptually, both are sound, but the approach we use saves many intermediate + Conceptually, both are sound, but the approach we use saves many intermediate computations (like computing the height in our case is done by doing this: height = bottom - top; while in the alternate system, it would be @@ -158,6 +158,18 @@ struct Rect return x >= left && y >= top && x < right && y < bottom; } + // Tests whether 'r' is completely contained within this rectangle. + // If it isn't, then set 'x' and 'y' such that moving 'r' to this + // position will make it be contained. + bool contains(uInt32& x, uInt32& y, const Rect& r) const { + if(r.left < left) x = left; + else if(r.right > right) x = r.left - (r.right - right); + if(r.top < top) y = top; + else if(r.bottom > bottom) y = r.top - (r.bottom - bottom); + + return r.left != x || r.top != y; + } + friend ostream& operator<<(ostream& os, const Rect& r) { os << r.point() << "," << r.size(); return os; diff --git a/src/debugger/gui/RomListSettings.cxx b/src/debugger/gui/RomListSettings.cxx index 054143485..950f198fe 100644 --- a/src/debugger/gui/RomListSettings.cxx +++ b/src/debugger/gui/RomListSettings.cxx @@ -88,30 +88,31 @@ RomListSettings::RomListSettings(GuiObject* boss, const GUI::Font& font) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void RomListSettings::show(uInt32 x, uInt32 y, int data) +void RomListSettings::show(uInt32 x, uInt32 y, const Common::Rect& bossRect, int data) { - _xorig = x * instance().frameBuffer().hidpiScaleFactor(); - _yorig = y * instance().frameBuffer().hidpiScaleFactor(); - _item = data; + uInt32 scale = instance().frameBuffer().hidpiScaleFactor(); + _xorig = bossRect.x() + x * scale; + _yorig = bossRect.y() + y * scale; + // Only show if we're inside the visible area + if(!bossRect.contains(_xorig, _yorig)) + return; + + _item = data; open(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomListSettings::center() { - // Make sure the menu is exactly where it should be, in case the image - // offset has changed - const Common::Rect& image = instance().frameBuffer().imageRect(); - const uInt32 scale = instance().frameBuffer().hidpiScaleFactor(); - uInt32 x = image.x() + _xorig; - uInt32 y = image.y() + _yorig; - uInt32 tx = image.x() + image.width(); - uInt32 ty = image.y() + image.height(); - if(x + _w*scale > tx) x -= (x + _w*scale - tx); - if(y + _h*scale > ty) y -= (y + _h*scale - ty); + // First set position according to original coordinates + surface().setDstPos(_xorig, _yorig); - surface().setDstPos(x, y); + // Now make sure that the entire menu can fit inside the image bounds + // If not, we reset its position + if(!instance().frameBuffer().imageRect().contains( + _xorig, _yorig, surface().dstRect())) + surface().setDstPos(_xorig, _yorig); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/debugger/gui/RomListSettings.hxx b/src/debugger/gui/RomListSettings.hxx index 632f4accb..c603b7400 100644 --- a/src/debugger/gui/RomListSettings.hxx +++ b/src/debugger/gui/RomListSettings.hxx @@ -36,7 +36,7 @@ class RomListSettings : public Dialog, public CommandSender /** Show dialog onscreen at the specified coordinates ('data' will be the currently selected line number in RomListWidget) */ - void show(uInt32 x, uInt32 y, int data = -1); + void show(uInt32 x, uInt32 y, const Common::Rect& bossRect, int data = -1); /** This dialog uses its own positioning, so we override Dialog::center() */ void center() override; diff --git a/src/debugger/gui/RomListWidget.cxx b/src/debugger/gui/RomListWidget.cxx index 73c1fb233..5865123b8 100644 --- a/src/debugger/gui/RomListWidget.cxx +++ b/src/debugger/gui/RomListWidget.cxx @@ -248,7 +248,8 @@ void RomListWidget::handleMouseDown(int x, int y, MouseButton b, int clickCount) // Set selected and add menu at current x,y mouse location _selectedItem = findItem(x, y); scrollToSelected(); - myMenu->show(x + getAbsX(), y + getAbsY(), _selectedItem); + myMenu->show(x + getAbsX(), y + getAbsY(), + dialog().surface().dstRect(), _selectedItem); } else { diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index 9aa6ea12a..4335caa3d 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -926,13 +926,13 @@ void FrameBuffer::setAvailableVidModes(uInt32 baseWidth, uInt32 baseHeight) { // Windowed and fullscreen mode differ only in screen size myWindowedModeList.add( - VideoMode(baseWidth, baseHeight, baseWidth, baseHeight, VideoMode::Stretch::Fill) + VideoMode(baseWidth, baseHeight, baseWidth, baseHeight, VideoMode::Stretch::None) ); for(uInt32 i = 0; i < myFullscreenDisplays.size(); ++i) { myFullscreenModeLists[i].add( VideoMode(baseWidth, baseHeight, myFullscreenDisplays[i].w, myFullscreenDisplays[i].h, - VideoMode::Stretch::Fill, "", 1, i) + VideoMode::Stretch::None, "", 1, i) ); } } @@ -941,8 +941,6 @@ void FrameBuffer::setAvailableVidModes(uInt32 baseWidth, uInt32 baseHeight) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const FrameBuffer::VideoMode& FrameBuffer::getSavedVidMode(bool fullscreen) { - EventHandlerState state = myOSystem.eventHandler().state(); - if(fullscreen) { Int32 i = getCurrentDisplayIndex(); @@ -959,6 +957,7 @@ const FrameBuffer::VideoMode& FrameBuffer::getSavedVidMode(bool fullscreen) // Now select the best resolution depending on the state // UI modes (launcher and debugger) have only one supported resolution // so the 'current' one is the only valid one + EventHandlerState state = myOSystem.eventHandler().state(); if(state == EventHandlerState::DEBUGGER || state == EventHandlerState::LAUNCHER) myCurrentModeList->setByZoom(1); else // TIA mode @@ -979,7 +978,7 @@ const FrameBuffer::VideoMode& FrameBuffer::getSavedVidMode(bool fullscreen) // // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FrameBuffer::VideoMode::VideoMode() - : stretch(VideoMode::Stretch::Fill), + : stretch(VideoMode::Stretch::None), description(""), zoom(1), fsIndex(-1) @@ -1035,6 +1034,10 @@ FrameBuffer::VideoMode::VideoMode(uInt32 iw, uInt32 ih, uInt32 sw, uInt32 sh, iw = screen.w; ih = screen.h; break; + + case Stretch::None: + // Don't do any scaling at all + break; } } else @@ -1045,6 +1048,7 @@ FrameBuffer::VideoMode::VideoMode(uInt32 iw, uInt32 ih, uInt32 sw, uInt32 sh, { case Stretch::Preserve: case Stretch::Fill: + case Stretch::None: screen.w = iw; screen.h = ih; break; diff --git a/src/emucore/FrameBuffer.hxx b/src/emucore/FrameBuffer.hxx index a0e7484bb..ba53f8fc4 100644 --- a/src/emucore/FrameBuffer.hxx +++ b/src/emucore/FrameBuffer.hxx @@ -57,7 +57,7 @@ class FrameBuffer // 'screen' are the dimensions of the screen itself struct VideoMode { - enum class Stretch { Preserve, Fill }; + enum class Stretch { Preserve, Fill, None }; Common::Rect image; Common::Size screen; diff --git a/src/gui/ContextMenu.cxx b/src/gui/ContextMenu.cxx index d60a96ce8..a23b7bc65 100644 --- a/src/gui/ContextMenu.cxx +++ b/src/gui/ContextMenu.cxx @@ -68,14 +68,13 @@ void ContextMenu::addItems(const VariantList& items) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void ContextMenu::show(uInt32 x, uInt32 y, const Common::Rect& bossRect, int item) +void ContextMenu::show(uInt32 x, uInt32 y, const Common::Rect& bossRect, int item) { - const Common::Rect& image = instance().frameBuffer().imageRect(); uInt32 scale = instance().frameBuffer().hidpiScaleFactor(); - _xorig = bossRect.x() + scale * x - image.x(); - _yorig = bossRect.y() + scale * y - image.y(); + _xorig = bossRect.x() + x * scale; + _yorig = bossRect.y() + y * scale; - // Only show if we're inside the visible area + // Only show menu if we're inside the visible area if(!bossRect.contains(_xorig, _yorig)) return; @@ -88,18 +87,14 @@ void ContextMenu::show(uInt32 x, uInt32 y, const Common::Rect& bossRect, int it // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ContextMenu::center() { - // Make sure the menu is exactly where it should be, in case the image - // offset has changed - const Common::Rect& image = instance().frameBuffer().imageRect(); - recalc(image); - uInt32 x = image.x() + _xorig; - uInt32 y = image.y() + _yorig; - uInt32 tx = image.x() + image.width(); - uInt32 ty = image.y() + image.height(); - if(x + _w > tx) x -= (x + _w - tx); - if(y + _h > ty) y -= (y + _h - ty); + // First set position according to original coordinates + surface().setDstPos(_xorig, _yorig); - surface().setDstPos(x, y); + // Now make sure that the entire menu can fit inside the image bounds + // If not, we reset its position + if(!instance().frameBuffer().imageRect().contains( + _xorig, _yorig, surface().dstRect())) + surface().setDstPos(_xorig, _yorig); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -