diff --git a/dialogs.py b/dialogs.py index ffc5fa0..ce58a16 100644 --- a/dialogs.py +++ b/dialogs.py @@ -7,7 +7,9 @@ import spritelib as SLib from levelitems import ListWidgetItem_SortsByOther, SpriteItem, ZoneItem from dirty import SetDirty -from zones import CameraModeZoomSettingsLayout + +from gui.dialogs.zone_dialog import CameraModeZoomSettingsLayout + from ui import createHorzLine from raw_data import RawData diff --git a/gui/components/combo_box.py b/gui/components/combo_box.py new file mode 100644 index 0000000..1a1e98f --- /dev/null +++ b/gui/components/combo_box.py @@ -0,0 +1,52 @@ +from PyQt5 import QtWidgets + +DEFAULT_MAX_HEIGHT_HINT = 300 +DEFAULT_HEIGHT_HINT = 300 + + +class ReggieComboBox(QtWidgets.QComboBox): + def __init__(self, preferred_height: int = DEFAULT_HEIGHT_HINT, max_height: int = DEFAULT_MAX_HEIGHT_HINT) -> None: + super().__init__() + self._preferred_height = preferred_height + self._max_height = max_height + + def showPopup(self): + super().showPopup() + # After the popup is shown, we can access the popup widget: + popup = self.view().parentWidget() + + if not popup: + return + + # Hide the popup until resized and relocated properly + # If we do not do that, you can see for a brief moment + # a flicker, so the resizing/relocating of the box. To + # prevent showing that, we hide the popup until everything + # is finished. + + popup.hide() + super().hidePopup() + + # Force a max height + popup.setMaximumHeight(self._max_height) + + # Force the popup geometry to appear under the combo box + # (By default, Qt tries to position it, but since we override showPopup(), + # we need to do it ourselves.) + combo_rect = self.rect() + global_bottom_left = self.mapToGlobal(combo_rect.bottomLeft()) + + # Evaluate how big the popup *wants* to be + size_hint = popup.sizeHint() + desired_width = max(self.width(), size_hint.width()) + desired_height = self._preferred_height + + # Place the popup so that its top-left corner is at the combo box's bottom-left + popup.setGeometry( + global_bottom_left.x(), + global_bottom_left.y(), + desired_width, + desired_height + ) + + popup.show() diff --git a/zones.py b/gui/dialogs/zone_dialog.py similarity index 98% rename from zones.py rename to gui/dialogs/zone_dialog.py index 930b6ba..7d7b2c0 100644 --- a/zones.py +++ b/gui/dialogs/zone_dialog.py @@ -1,7 +1,22 @@ +""" +zone_dialog.py + +This module defines: + - ZonesDialog: a dialog with tabs for each zone. + - ZoneTab: a widget for editing a single zone’s properties. + - CameraModeZoomSettingsLayout: a custom layout for camera mode and zoom settings. + +Dependencies: + - PyQt5 + - common, globals_, ui, and levelitems +""" + from PyQt5 import QtWidgets, QtCore import common import globals_ + +from gui.components.combo_box import ReggieComboBox from ui import GetIcon from levelitems import ZoneItem @@ -501,7 +516,7 @@ def createAudio(self, z): self.Audio = QtWidgets.QGroupBox(globals_.trans.string('ZonesDlg', 52)) self.AutoEditMusic = False - self.Zone_music = QtWidgets.QComboBox() + self.Zone_music = ReggieComboBox() self.Zone_music.setToolTip(globals_.trans.string('ZonesDlg', 54)) for songid, text in globals_.MusicInfo: self.Zone_music.addItem(text, songid) diff --git a/reggie.py b/reggie.py index 47817e5..b06caf2 100644 --- a/reggie.py +++ b/reggie.py @@ -99,7 +99,9 @@ from levelitems import LocationItem, ZoneItem, ObjectItem, SpriteItem, EntranceItem, ListWidgetItem_SortsByOther, PathItem, CommentItem, PathEditorLineItem from dialogs import AutoSavedInfoDialog, DiagnosticToolDialog, ScreenCapChoiceDialog, AreaChoiceDialog, ObjectTypeSwapDialog, ObjectTilesetSwapDialog, ObjectShiftDialog, MetaInfoDialog, AboutDialog, CameraProfilesDialog from background import BGDialog -from zones import ZonesDialog + +from gui.dialogs.zone_dialog import ZonesDialog, CameraModeZoomSettingsLayout + from tiles import UnloadTileset, LoadTileset, LoadOverrides from area import AreaOptionsDialog from level import Level_NSMBW