diff --git a/forms/connectionslistitem.ui b/forms/connectionslistitem.ui index 116da983..e02fefa8 100644 --- a/forms/connectionslistitem.ui +++ b/forms/connectionslistitem.ui @@ -81,6 +81,9 @@ <html><head/><body><p>Where the connected map should be positioned relative to the current map.</p></body></html> + + true + @@ -88,6 +91,9 @@ <html><head/><body><p>The name of the map to connect to the current map.</p></body></html> + + true + @@ -117,12 +123,12 @@ NoScrollComboBox QComboBox -
noscrollcombobox.h
+
noscrollwidgets.h
NoScrollSpinBox QSpinBox -
noscrollspinbox.h
+
noscrollwidgets.h
diff --git a/forms/customattributesdialog.ui b/forms/customattributesdialog.ui index 90dfba6e..9e59c9cf 100644 --- a/forms/customattributesdialog.ui +++ b/forms/customattributesdialog.ui @@ -164,7 +164,7 @@ NoScrollComboBox QComboBox -
noscrollcombobox.h
+
noscrollwidgets.h
diff --git a/forms/gridsettingsdialog.ui b/forms/gridsettingsdialog.ui index 75d31de1..76a301f3 100644 --- a/forms/gridsettingsdialog.ui +++ b/forms/gridsettingsdialog.ui @@ -57,15 +57,9 @@
- - false - QComboBox::SizeAdjustPolicy::AdjustToContentsOnFirstShow - - 0 - @@ -254,12 +248,12 @@ NoScrollSpinBox QSpinBox -
noscrollspinbox.h
+
noscrollwidgets.h
NoScrollComboBox QComboBox -
noscrollcombobox.h
+
noscrollwidgets.h
ColorInputWidget diff --git a/forms/mainwindow.ui b/forms/mainwindow.ui index d650bdef..0e2a5dd5 100644 --- a/forms/mainwindow.ui +++ b/forms/mainwindow.ui @@ -1105,18 +1105,12 @@
- - Qt::FocusPolicy::StrongFocus - <html><head/><body><p>Primary Tileset</p><p>Defines the first 0x200 metatiles available for the map.</p></body></html> true - - 0 - @@ -1128,24 +1122,18 @@ - - Qt::FocusPolicy::StrongFocus - <html><head/><body><p>Secondary Tileset</p><p>Defines the second 0x200 metatiles available for the map.</p></body></html> true - - 0 - - - 0 + + true @@ -2720,9 +2708,6 @@ - - false - QComboBox::SizeAdjustPolicy::AdjustToContents @@ -3274,7 +3259,7 @@ NoScrollComboBox QComboBox -
noscrollcombobox.h
+
noscrollwidgets.h
AdjustingStackedWidget diff --git a/forms/mapheaderform.ui b/forms/mapheaderform.ui index d4fc36f3..3db1688d 100644 --- a/forms/mapheaderform.ui +++ b/forms/mapheaderform.ui @@ -239,12 +239,12 @@ NoScrollComboBox QComboBox -
noscrollcombobox.h
+
noscrollwidgets.h
NoScrollSpinBox QSpinBox -
noscrollspinbox.h
+
noscrollwidgets.h
diff --git a/forms/mapimageexporter.ui b/forms/mapimageexporter.ui index 489df227..c8d479b8 100644 --- a/forms/mapimageexporter.ui +++ b/forms/mapimageexporter.ui @@ -40,6 +40,9 @@
+ + true + QComboBox::InsertPolicy::NoInsert @@ -436,12 +439,12 @@ NoScrollComboBox QComboBox -
noscrollcombobox.h
+
noscrollwidgets.h
NoScrollSpinBox QSpinBox -
noscrollspinbox.h
+
noscrollwidgets.h
diff --git a/forms/metatileimageexporter.ui b/forms/metatileimageexporter.ui index 7c6bfe49..73587ed6 100644 --- a/forms/metatileimageexporter.ui +++ b/forms/metatileimageexporter.ui @@ -98,9 +98,6 @@ false - - false -
@@ -108,9 +105,6 @@ false - - false - @@ -503,7 +497,7 @@ NoScrollComboBox QComboBox -
noscrollcombobox.h
+
noscrollwidgets.h
UIntSpinBox diff --git a/forms/newlayoutform.ui b/forms/newlayoutform.ui index bc3e7502..b3c0649b 100644 --- a/forms/newlayoutform.ui +++ b/forms/newlayoutform.ui @@ -231,12 +231,12 @@ NoScrollComboBox QComboBox -
noscrollcombobox.h
+
noscrollwidgets.h
NoScrollSpinBox QSpinBox -
noscrollspinbox.h
+
noscrollwidgets.h
diff --git a/forms/newmapconnectiondialog.ui b/forms/newmapconnectiondialog.ui index 85aeec72..2b94229e 100644 --- a/forms/newmapconnectiondialog.ui +++ b/forms/newmapconnectiondialog.ui @@ -47,6 +47,9 @@ <html><head/><body><p>The name of the map to connect to the current map.</p></body></html> + + true +
@@ -61,6 +64,9 @@ <html><head/><body><p>Where the connected map should be positioned relative to the current map.</p></body></html> + + true + @@ -95,7 +101,7 @@ NoScrollComboBox QComboBox -
noscrollcombobox.h
+
noscrollwidgets.h
diff --git a/forms/newmapdialog.ui b/forms/newmapdialog.ui index 604800f8..ec8c2612 100644 --- a/forms/newmapdialog.ui +++ b/forms/newmapdialog.ui @@ -245,7 +245,7 @@ NoScrollComboBox QComboBox -
noscrollcombobox.h
+
noscrollwidgets.h
diff --git a/forms/newtilesetdialog.ui b/forms/newtilesetdialog.ui index 494aaca7..67f67b78 100644 --- a/forms/newtilesetdialog.ui +++ b/forms/newtilesetdialog.ui @@ -71,9 +71,6 @@
- - false - Primary @@ -151,7 +148,7 @@ NoScrollComboBox QComboBox -
noscrollcombobox.h
+
noscrollwidgets.h
diff --git a/forms/palettecolorsearch.ui b/forms/palettecolorsearch.ui index b6ae87c8..749cf6ee 100644 --- a/forms/palettecolorsearch.ui +++ b/forms/palettecolorsearch.ui @@ -144,7 +144,7 @@ NoScrollSpinBox QSpinBox -
noscrollspinbox.h
+
noscrollwidgets.h
diff --git a/forms/preferenceeditor.ui b/forms/preferenceeditor.ui index 8b36a441..ddb20b9b 100644 --- a/forms/preferenceeditor.ui +++ b/forms/preferenceeditor.ui @@ -93,9 +93,6 @@
- - false - @@ -110,9 +107,6 @@ <html><head/><body><p>The color space to use for exported images. If &quot;---&quot; is set, no color space will be used for the exported image. For details on each color space, see Qt's manual page for QColorSpace.</p></body></html> - - false -
@@ -519,7 +513,7 @@ NoScrollComboBox QComboBox -
noscrollcombobox.h
+
noscrollwidgets.h
diff --git a/forms/projectsettingseditor.ui b/forms/projectsettingseditor.ui index f2284c07..3bb6a332 100644 --- a/forms/projectsettingseditor.ui +++ b/forms/projectsettingseditor.ui @@ -408,9 +408,6 @@
- - false - @@ -874,6 +871,9 @@ <html><head/><body><p>The default primary tileset to use for new maps/layouts.</p></body></html> + + true + @@ -888,6 +888,9 @@ <html><head/><body><p>The default secondary tileset to use for new maps/layouts.</p></body></html> + + true + @@ -1128,9 +1131,6 @@ <html><head/><body><p>The number of bytes each metatile has for metatile attributes. This is the metadata about each metatile like behvior, layer type, etc.</p></body></html> - - false - @@ -1268,9 +1268,6 @@ <html><head/><body><p>The icon that will be displayed for the Events tab in the editor. If 'Automatic' is chosen, the icon will be a random player character from the project's base game version. If 'Custom' is chosen an image file path may be specified.</p></body></html> - - false - @@ -1466,7 +1463,11 @@ - + + + true + + @@ -1892,7 +1893,7 @@ NoScrollComboBox QComboBox -
noscrollcombobox.h
+
noscrollwidgets.h
UIntSpinBox @@ -1907,12 +1908,12 @@ NoScrollSpinBox QSpinBox -
noscrollspinbox.h
+
noscrollwidgets.h
NoScrollTextEdit QTextEdit -
noscrolltextedit.h
+
noscrollwidgets.h
diff --git a/forms/regionmapeditor.ui b/forms/regionmapeditor.ui index 66787b7b..2cb4d3a6 100644 --- a/forms/regionmapeditor.ui +++ b/forms/regionmapeditor.ui @@ -44,7 +44,7 @@
- + QComboBox::SizeAdjustPolicy::AdjustToContents @@ -739,7 +739,7 @@ - + @@ -773,9 +773,6 @@ <html><head/><body><p>The section of the region map which the map is grouped under. This also determines the name of the map that is displayed when the player enters it.</p></body></html> - - false - @@ -922,9 +919,6 @@ <html><head/><body><p>The section of the region map which the map is grouped under. This also determines the name of the map that is display when the player enters it.</p></body></html> - - false - @@ -1171,12 +1165,12 @@ NoScrollComboBox QComboBox -
noscrollcombobox.h
+
noscrollwidgets.h
NoScrollSpinBox QSpinBox -
noscrollspinbox.h
+
noscrollwidgets.h
diff --git a/forms/resizelayoutpopup.ui b/forms/resizelayoutpopup.ui index c98fe10f..43d1a97d 100644 --- a/forms/resizelayoutpopup.ui +++ b/forms/resizelayoutpopup.ui @@ -235,7 +235,7 @@ NoScrollSpinBox QSpinBox -
noscrollspinbox.h
+
noscrollwidgets.h
diff --git a/forms/tileseteditor.ui b/forms/tileseteditor.ui index eb2580b7..3872a4e8 100644 --- a/forms/tileseteditor.ui +++ b/forms/tileseteditor.ui @@ -403,6 +403,9 @@ QComboBox::InsertPolicy::NoInsert + + true +
@@ -460,6 +463,9 @@ QComboBox::InsertPolicy::NoInsert + + true + @@ -530,6 +536,9 @@ QComboBox::InsertPolicy::NoInsert + + true + @@ -1144,7 +1153,7 @@ NoScrollComboBox QComboBox -
noscrollcombobox.h
+
noscrollwidgets.h
NoScrollGraphicsView diff --git a/forms/wildmonchart.ui b/forms/wildmonchart.ui index 05c0ba44..fec086dd 100644 --- a/forms/wildmonchart.ui +++ b/forms/wildmonchart.ui @@ -43,7 +43,7 @@
- + @@ -140,10 +140,7 @@ - - - false - + QComboBox::AdjustToMinimumContentsLengthWithIcon @@ -240,7 +237,7 @@ NoScrollComboBox QComboBox -
noscrollcombobox.h
+
noscrollwidgets.h
diff --git a/forms/wildmonsearch.ui b/forms/wildmonsearch.ui index 117f7242..bdd507c5 100644 --- a/forms/wildmonsearch.ui +++ b/forms/wildmonsearch.ui @@ -84,7 +84,7 @@ NoScrollComboBox QComboBox -
noscrollcombobox.h
+
noscrollwidgets.h
diff --git a/include/editor.h b/include/editor.h index 5b36dbfc..d356aef3 100644 --- a/include/editor.h +++ b/include/editor.h @@ -245,7 +245,7 @@ private: void displayConnection(MapConnection *connection); void displayDivingConnection(MapConnection *connection); void removeDivingMapPixmap(MapConnection *connection); - void onDivingMapEditingFinished(NoScrollComboBox* combo, const QString &direction); + void onDivingMapEditingFinished(ComboBox *combo, const QString &direction); void updateDivingMapButton(QToolButton* button, const QString &mapName); void updateEncounterFields(EncounterFields newFields); QString getMovementPermissionText(uint16_t collision, uint16_t elevation); diff --git a/include/ui/combobox.h b/include/ui/combobox.h new file mode 100644 index 00000000..ff57be26 --- /dev/null +++ b/include/ui/combobox.h @@ -0,0 +1,32 @@ +#ifndef COMBOBOX_H +#define COMBOBOX_H + +#include + +// Contains our general-purpose additions to QComboBox + +class ComboBox : public QComboBox +{ + Q_OBJECT +public: + explicit ComboBox(QWidget *parent = nullptr); + + void setTextItem(const QString &text); + void setNumberItem(int value); + void setHexItem(uint32_t value); + + virtual void setEditable(bool editable); + virtual void setLineEdit(QLineEdit *edit); + + void setClearButtonEnabled(bool enabled); + +signals: + void editingFinished(); + +private: + void setItem(int index, const QString &text); + + void initLineEdit(QLineEdit *edit); +}; + +#endif // COMBOBOX_H diff --git a/include/ui/divingmappixmapitem.h b/include/ui/divingmappixmapitem.h index 0a4a32c1..43679e0b 100644 --- a/include/ui/divingmappixmapitem.h +++ b/include/ui/divingmappixmapitem.h @@ -2,7 +2,7 @@ #define DIVINGMAPPIXMAPITEM_H #include "mapconnection.h" -#include "noscrollcombobox.h" +#include "combobox.h" #include #include @@ -11,7 +11,7 @@ class DivingMapPixmapItem : public QObject, public QGraphicsPixmapItem { Q_OBJECT public: - DivingMapPixmapItem(MapConnection *connection, NoScrollComboBox *combo); + DivingMapPixmapItem(MapConnection *connection, ComboBox *combo); ~DivingMapPixmapItem(); MapConnection* connection() const { return m_connection; } @@ -19,7 +19,7 @@ public: private: QPointer m_connection; - QPointer m_combo; + QPointer m_combo; void setComboText(const QString &text); static QPixmap getBasePixmap(MapConnection* connection); diff --git a/include/ui/edithistoryspinbox.h b/include/ui/edithistoryspinbox.h new file mode 100644 index 00000000..6cf88c91 --- /dev/null +++ b/include/ui/edithistoryspinbox.h @@ -0,0 +1,24 @@ +#ifndef EDITHISTORYSPINBOX_H +#define EDITHISTORYSPINBOX_H + +#include "noscrollwidgets.h" + +class EditHistorySpinBox : public NoScrollSpinBox +{ + Q_OBJECT + +public: + explicit EditHistorySpinBox(QWidget *parent = nullptr) : NoScrollSpinBox(parent) {} + + void focusOutEvent(QFocusEvent *event) override { + m_actionId++; + NoScrollSpinBox::focusOutEvent(event); + } + + unsigned getActionId() const { return m_actionId; } + +private: + unsigned m_actionId{0}; +}; + +#endif // EDITHISTORYSPINBOX_H diff --git a/include/ui/eventcombobox.h b/include/ui/eventcombobox.h new file mode 100644 index 00000000..12eba05a --- /dev/null +++ b/include/ui/eventcombobox.h @@ -0,0 +1,22 @@ +#ifndef EVENTCOMBOBOX_H +#define EVENTCOMBOBOX_H + +#include "noscrollwidgets.h" + +#include + +class EventComboBox : public NoScrollComboBox +{ + Q_OBJECT +public: + explicit EventComboBox(QWidget *parent = nullptr) : NoScrollComboBox(parent) { + // Make speed a priority when loading comboboxes. + setMinimumContentsLength(24);// an arbitrary limit + setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon); + + // In general, event combo boxes are always editable. + setEditable(true); + } +}; + +#endif // EVENTCOMBOBOX_H diff --git a/include/ui/eventfilters.h b/include/ui/eventfilters.h index 4fc5ee83..96260e10 100644 --- a/include/ui/eventfilters.h +++ b/include/ui/eventfilters.h @@ -2,18 +2,6 @@ #include - -/// Prevent wheel scroll -class WheelFilter : public QObject { - Q_OBJECT -public: - WheelFilter(QObject *parent) : QObject(parent) {} - virtual ~WheelFilter() {} - bool eventFilter(QObject *obj, QEvent *event) override; -}; - - - /// Ctrl+Wheel = zoom class MapSceneEventFilter : public QObject { Q_OBJECT diff --git a/include/ui/eventframes.h b/include/ui/eventframes.h index 3858e54e..71cc04a8 100644 --- a/include/ui/eventframes.h +++ b/include/ui/eventframes.h @@ -4,8 +4,8 @@ #include -#include "noscrollspinbox.h" -#include "noscrollcombobox.h" +#include "edithistoryspinbox.h" +#include "eventcombobox.h" #include "mainwindow.h" #include "events.h" @@ -40,8 +40,8 @@ public: QSpinBox *spinner_id; - NoScrollSpinBox *spinner_x; - NoScrollSpinBox *spinner_y; + EditHistorySpinBox *spinner_x; + EditHistorySpinBox *spinner_y; NoScrollSpinBox *spinner_z; QLabel *hideable_label_z; @@ -58,10 +58,10 @@ protected: bool connected = false; QPointer project; - void populateDropdown(NoScrollComboBox * combo, const QStringList &items); - void populateScriptDropdown(NoScrollComboBox * combo, Project * project); - void populateMapNameDropdown(NoScrollComboBox * combo, Project * project); - void populateIdNameDropdown(NoScrollComboBox * combo, Project * project, const QString &mapName, Event::Group group); + void populateDropdown(EventComboBox * combo, const QStringList &items); + void populateScriptDropdown(EventComboBox * combo, Project * project); + void populateMapNameDropdown(EventComboBox * combo, Project * project); + void populateIdNameDropdown(EventComboBox * combo, Project * project, const QString &mapName, Event::Group group); private: Event *event; @@ -83,15 +83,15 @@ public: public: QLineEdit *line_edit_local_id; - NoScrollComboBox *combo_sprite; - NoScrollComboBox *combo_movement; + EventComboBox *combo_sprite; + EventComboBox *combo_movement; NoScrollSpinBox *spinner_radius_x; NoScrollSpinBox *spinner_radius_y; - NoScrollComboBox *combo_script; + EventComboBox *combo_script; QToolButton *button_script; - NoScrollComboBox *combo_flag; - NoScrollComboBox *combo_trainer_type; - NoScrollComboBox *combo_radius_treeid; + EventComboBox *combo_flag; + EventComboBox *combo_trainer_type; + EventComboBox *combo_radius_treeid; QCheckBox *check_in_connection; private: @@ -114,9 +114,9 @@ public: public: QLineEdit *line_edit_local_id; - NoScrollComboBox *combo_sprite; - NoScrollComboBox *combo_target_id; - NoScrollComboBox *combo_target_map; + EventComboBox *combo_sprite; + EventComboBox *combo_target_id; + EventComboBox *combo_target_map; private: CloneObjectEvent *clone; @@ -140,8 +140,8 @@ public: public: QLineEdit *line_edit_id; - NoScrollComboBox *combo_dest_map; - NoScrollComboBox *combo_dest_warp; + EventComboBox *combo_dest_map; + EventComboBox *combo_dest_warp; QPushButton *warning; private: @@ -165,9 +165,9 @@ public: virtual void populate(Project *project) override; public: - NoScrollComboBox *combo_script; - NoScrollComboBox *combo_var; - NoScrollComboBox *combo_var_value; + EventComboBox *combo_script; + EventComboBox *combo_var; + EventComboBox *combo_var_value; private: TriggerEvent *trigger; @@ -188,7 +188,7 @@ public: virtual void populate(Project *project) override; public: - NoScrollComboBox *combo_weather; + EventComboBox *combo_weather; private: WeatherTriggerEvent *weatherTrigger; @@ -209,8 +209,8 @@ public: virtual void populate(Project *project) override; public: - NoScrollComboBox *combo_facing_dir; - NoScrollComboBox *combo_script; + EventComboBox *combo_facing_dir; + EventComboBox *combo_script; private: SignEvent *sign; @@ -233,8 +233,8 @@ public: public: QFrame *hideable_quantity; QFrame *hideable_itemfinder; - NoScrollComboBox *combo_item; - NoScrollComboBox *combo_flag; + EventComboBox *combo_item; + EventComboBox *combo_flag; NoScrollSpinBox *spinner_quantity; QCheckBox *check_itemfinder; @@ -257,7 +257,7 @@ public: virtual void populate(Project *project) override; public: - NoScrollComboBox *combo_base_id; + EventComboBox *combo_base_id; private: SecretBaseEvent *secretBase; @@ -281,8 +281,8 @@ public: QLineEdit *line_edit_id; QFrame *hideable_respawn_map; QFrame *hideable_respawn_npc; - NoScrollComboBox *combo_respawn_map; - NoScrollComboBox *combo_respawn_npc; + EventComboBox *combo_respawn_map; + EventComboBox *combo_respawn_npc; private: HealLocationEvent *healLocation; diff --git a/include/ui/graphicsview.h b/include/ui/graphicsview.h index 8557f5b2..31859ce9 100644 --- a/include/ui/graphicsview.h +++ b/include/ui/graphicsview.h @@ -1,6 +1,8 @@ #ifndef GRAPHICSVIEW_H #define GRAPHICSVIEW_H +#include "noscrollwidgets.h" + #include #include @@ -90,11 +92,8 @@ class NoScrollGraphicsView : public GraphicsView { Q_OBJECT public: - NoScrollGraphicsView(QWidget *parent = nullptr) : GraphicsView(parent) {} - -protected: - void wheelEvent(QWheelEvent *event) { - event->ignore(); + NoScrollGraphicsView(QWidget *parent = nullptr) : GraphicsView(parent) { + NoScrollFilter::apply(this, false); } }; diff --git a/include/ui/mapheaderform.h b/include/ui/mapheaderform.h index fb4f7aa9..24ab4af5 100644 --- a/include/ui/mapheaderform.h +++ b/include/ui/mapheaderform.h @@ -12,7 +12,7 @@ #include "mapheader.h" #include "project.h" -#include "noscrollcombobox.h" +#include "combobox.h" namespace Ui { class MapHeaderForm; @@ -65,7 +65,7 @@ private: QPointer m_project = nullptr; bool m_allowProjectChanges = true; - void setText(NoScrollComboBox *combo, const QString &text) const; + void setText(ComboBox *combo, const QString &text) const; void setText(QLineEdit *lineEdit, const QString &text) const; void setLocations(const QStringList &locations); void updateLocationName(); diff --git a/include/ui/noscrollcombobox.h b/include/ui/noscrollcombobox.h deleted file mode 100644 index 0ae2487c..00000000 --- a/include/ui/noscrollcombobox.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef NOSCROLLCOMBOBOX_H -#define NOSCROLLCOMBOBOX_H - -#include - -class NoScrollComboBox : public QComboBox -{ - Q_OBJECT - -public: - explicit NoScrollComboBox(QWidget *parent = nullptr); - void wheelEvent(QWheelEvent *event); - void setTextItem(const QString &text); - void setNumberItem(int value); - void setHexItem(uint32_t value); - void setClearButtonEnabled(bool enabled); - void setEditable(bool editable); - void setLineEdit(QLineEdit *edit); - void setFocusedScrollingEnabled(bool enabled); - -signals: - void editingFinished(); - -private: - void setItem(int index, const QString &text); - - bool focusedScrollingEnabled = true; -}; - -#endif // NOSCROLLCOMBOBOX_H diff --git a/include/ui/noscrollspinbox.h b/include/ui/noscrollspinbox.h deleted file mode 100644 index 0615da5a..00000000 --- a/include/ui/noscrollspinbox.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef NOSCROLLSPINBOX_H -#define NOSCROLLSPINBOX_H - -#include - -class NoScrollSpinBox : public QSpinBox -{ - Q_OBJECT - -public: - explicit NoScrollSpinBox(QWidget *parent = nullptr); - void wheelEvent(QWheelEvent *event) override; - void focusOutEvent(QFocusEvent *event) override; - - void setLineEditEnabled(bool enabled); - - unsigned getActionId(); - -private: -}; - -#endif // NOSCROLLSPINBOX_H diff --git a/include/ui/noscrolltextedit.h b/include/ui/noscrolltextedit.h deleted file mode 100644 index dfc66789..00000000 --- a/include/ui/noscrolltextedit.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef NOSCROLLTEXTEDIT_H -#define NOSCROLLTEXTEDIT_H - -#include -#include - -class NoScrollTextEdit : public QTextEdit -{ - Q_OBJECT -public: - explicit NoScrollTextEdit(const QString &text, QWidget *parent = nullptr) : QTextEdit(text, parent) { - setFocusPolicy(Qt::StrongFocus); - }; - explicit NoScrollTextEdit(QWidget *parent = nullptr) : NoScrollTextEdit(QString(), parent) {}; - - virtual void wheelEvent(QWheelEvent *event) override { - if (hasFocus()) { - QTextEdit::wheelEvent(event); - } else { - event->ignore(); - } - }; -}; - -#endif // NOSCROLLTEXTEDIT_H diff --git a/include/ui/noscrollwidgets.h b/include/ui/noscrollwidgets.h new file mode 100644 index 00000000..c3cc4672 --- /dev/null +++ b/include/ui/noscrollwidgets.h @@ -0,0 +1,79 @@ +#ifndef NOSCROLLWIDGETS_H +#define NOSCROLLWIDGETS_H + +#include "combobox.h" + +#include +#include + +/// Prevent widgets from stealing focus when a user scrolls past it. +/// Any QObject with this filter will never accept wheel events. +/// Any QWidget with this filter will only accept wheel events +/// if 'allowIfFocused' is 'true' and the widget has focus. +class NoScrollFilter : public QObject { + Q_OBJECT +public: + NoScrollFilter(QObject *parent, bool allowIfFocused) + : QObject(parent), m_allowIfFocused(allowIfFocused) {} + + static NoScrollFilter* apply(QObject *target, bool allowIfFocused = true); + bool eventFilter(QObject *obj, QEvent *event) override; + + void setAllowIfFocused(bool enabled) { m_allowIfFocused = enabled; } + +private: + bool m_allowIfFocused; +}; + + + +class NoScrollComboBox : public ComboBox { + Q_OBJECT +public: + explicit NoScrollComboBox(QWidget *parent = nullptr) : ComboBox(parent) { + m_filter = NoScrollFilter::apply(this); + } + + void setEditable(bool editable) override; + void setLineEdit(QLineEdit *edit) override; + + void setAllowScrollingIfFocused(bool enabled) { if (m_filter) m_filter->setAllowIfFocused(enabled); } + +private: + NoScrollFilter* m_filter = nullptr; +}; + +class NoScrollAbstractSpinBox : public QAbstractSpinBox { + Q_OBJECT +public: + explicit NoScrollAbstractSpinBox(QWidget *parent = nullptr) : QAbstractSpinBox(parent) { + NoScrollFilter::apply(this); + } +}; + +class NoScrollDoubleSpinBox : public QDoubleSpinBox { + Q_OBJECT +public: + explicit NoScrollDoubleSpinBox(QWidget *parent = nullptr) : QDoubleSpinBox(parent) { + NoScrollFilter::apply(this); + } +}; + +class NoScrollSpinBox : public QSpinBox { + Q_OBJECT +public: + explicit NoScrollSpinBox(QWidget *parent = nullptr) : QSpinBox(parent) { + NoScrollFilter::apply(this); + } +}; + +class NoScrollTextEdit : public QTextEdit { + Q_OBJECT +public: + explicit NoScrollTextEdit(const QString &text, QWidget *parent = nullptr) : QTextEdit(text, parent) { + NoScrollFilter::apply(this); + } + explicit NoScrollTextEdit(QWidget *parent = nullptr) : NoScrollTextEdit(QString(), parent) {} +}; + +#endif // NOSCROLLWIDGETS_H diff --git a/include/ui/preferenceeditor.h b/include/ui/preferenceeditor.h index 72b514c6..81c62068 100644 --- a/include/ui/preferenceeditor.h +++ b/include/ui/preferenceeditor.h @@ -4,7 +4,6 @@ #include #include "config.h" -class NoScrollComboBox; class QAbstractButton; diff --git a/include/ui/projectsettingseditor.h b/include/ui/projectsettingseditor.h index 579aec21..dd9b2b8c 100644 --- a/include/ui/projectsettingseditor.h +++ b/include/ui/projectsettingseditor.h @@ -5,7 +5,6 @@ #include "project.h" #include "ui_projectsettingseditor.h" -class NoScrollComboBox; class QAbstractButton; diff --git a/include/ui/tileseteditor.h b/include/ui/tileseteditor.h index 8fced9bb..49b0ec91 100644 --- a/include/ui/tileseteditor.h +++ b/include/ui/tileseteditor.h @@ -12,7 +12,7 @@ #include "metatilelayersitem.h" #include "metatileimageexporter.h" -class NoScrollComboBox; +class ComboBox; class Layout; namespace Ui { @@ -136,7 +136,7 @@ private: void commitMetatileChange(Metatile * prevMetatile); void commitMetatileAndLabelChange(Metatile * prevMetatile, QString prevLabel); uint32_t attributeNameToValue(Metatile::Attr attribute, const QString &text, bool *ok); - void commitAttributeFromComboBox(Metatile::Attr attribute, NoScrollComboBox *combo); + void commitAttributeFromComboBox(Metatile::Attr attribute, ComboBox *combo); void onRawAttributesEdited(); void refreshMetatileAttributes(); void commitMetatileBehavior(); diff --git a/include/ui/uintspinbox.h b/include/ui/uintspinbox.h index aa8bcb77..ef4a57c2 100644 --- a/include/ui/uintspinbox.h +++ b/include/ui/uintspinbox.h @@ -1,16 +1,15 @@ #ifndef UINTSPINBOX_H #define UINTSPINBOX_H -#include +#include "noscrollwidgets.h" #include /* QSpinBox stores minimum/maximum/value as ints. This class is a version of QAbstractSpinBox for values above 0x7FFFFFFF. It minimally implements some QSpinBox-specific features like prefixes to simplify support for hex value input. - It also implements the scroll focus requirements of NoScrollSpinBox. */ -class UIntSpinBox : public QAbstractSpinBox +class UIntSpinBox : public NoScrollAbstractSpinBox { Q_OBJECT @@ -48,7 +47,6 @@ private: QString stripped(QString input) const; virtual void stepBy(int steps) override; - virtual void wheelEvent(QWheelEvent *event) override; virtual void focusOutEvent(QFocusEvent *event) override; protected: diff --git a/porymap.pro b/porymap.pro index 4353c7a8..41756e93 100644 --- a/porymap.pro +++ b/porymap.pro @@ -78,6 +78,7 @@ SOURCES += src/core/advancemapparser.cpp \ src/ui/aboutporymap.cpp \ src/ui/checkeredbgscene.cpp \ src/ui/colorinputwidget.cpp \ + src/ui/combobox.cpp \ src/ui/connectionslistitem.cpp \ src/ui/customattributesdialog.cpp \ src/ui/customattributestable.cpp \ @@ -121,8 +122,7 @@ SOURCES += src/core/advancemapparser.cpp \ src/ui/newlayoutform.cpp \ src/ui/newlocationdialog.cpp \ src/ui/newmapgroupdialog.cpp \ - src/ui/noscrollcombobox.cpp \ - src/ui/noscrollspinbox.cpp \ + src/ui/noscrollwidgets.cpp \ src/ui/montabwidget.cpp \ src/ui/encountertablemodel.cpp \ src/ui/encountertabledelegates.cpp \ @@ -195,12 +195,15 @@ HEADERS += include/core/advancemapparser.h \ include/lib/orderedjson.h \ include/ui/aboutporymap.h \ include/ui/checkeredbgscene.h \ + include/ui/combobox.h \ include/ui/connectionslistitem.h \ include/ui/customattributesdialog.h \ include/ui/customattributestable.h \ include/ui/customscriptseditor.h \ include/ui/customscriptslistitem.h \ include/ui/divingmappixmapitem.h \ + include/ui/edithistoryspinbox.h \ + include/ui/eventcombobox.h \ include/ui/eventpixmapitem.h \ include/ui/bordermetatilespixmapitem.h \ include/ui/collisionpixmapitem.h \ @@ -239,9 +242,7 @@ HEADERS += include/core/advancemapparser.h \ include/ui/newlayoutform.h \ include/ui/newlocationdialog.h \ include/ui/newmapgroupdialog.h \ - include/ui/noscrollcombobox.h \ - include/ui/noscrollspinbox.h \ - include/ui/noscrolltextedit.h \ + include/ui/noscrollwidgets.h \ include/ui/montabwidget.h \ include/ui/encountertablemodel.h \ include/ui/encountertabledelegates.h \ diff --git a/src/editor.cpp b/src/editor.cpp index 6ad57961..9cf07fd0 100644 --- a/src/editor.cpp +++ b/src/editor.cpp @@ -541,8 +541,6 @@ void Editor::configureEncounterJSON(QWidget *window) { QVBoxLayout *slotChoiceLayout = new QVBoxLayout; if (useGroups) { auto groupCombo = new NoScrollComboBox; - groupCombo->setEditable(false); - groupCombo->setMinimumContentsLength(10); connect(groupCombo, QOverload::of(&QComboBox::textActivated), [&tempFields, ¤tField, &updateTotal, index](QString newGroupName) { for (EncounterField &field : tempFields) { if (field.name == currentField.name) { @@ -1035,7 +1033,7 @@ QString Editor::getDivingMapName(const QString &direction) const { return (pixmapItem && pixmapItem->connection()) ? pixmapItem->connection()->targetMapName() : QString(); } -void Editor::onDivingMapEditingFinished(NoScrollComboBox *combo, const QString &direction) { +void Editor::onDivingMapEditingFinished(ComboBox *combo, const QString &direction) { if (!setDivingMapName(combo->currentText(), direction)) { // If user input was invalid, restore the combo to the previously-valid text. combo->setTextItem(getDivingMapName(direction)); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 08ce1a7a..b0f3848c 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -385,7 +385,7 @@ void MainWindow::initExtraSignals() { connect(ui->action_NewMap, &QAction::triggered, this, &MainWindow::openNewMapDialog); connect(ui->action_NewLayout, &QAction::triggered, this, &MainWindow::openNewLayoutDialog); - connect(ui->comboBox_LayoutSelector, &NoScrollComboBox::editingFinished, this, &MainWindow::onLayoutSelectorEditingFinished); + connect(ui->comboBox_LayoutSelector, &ComboBox::editingFinished, this, &MainWindow::onLayoutSelectorEditingFinished); connect(ui->checkBox_smartPaths, &QCheckBox::toggled, this, &MainWindow::setSmartPathsEnabled); connect(ui->checkBox_ToggleBorder, &QCheckBox::toggled, this, &MainWindow::setBorderVisibility); connect(ui->checkBox_MirrorConnections, &QCheckBox::toggled, this, &MainWindow::setMirrorConnectionsEnabled); @@ -502,9 +502,9 @@ void MainWindow::initMiscHeapObjects() { void MainWindow::initMapList() { ui->mapListContainer->setCurrentIndex(porymapConfig.mapListTab); - WheelFilter *wheelFilter = new WheelFilter(this); - ui->mainTabBar->installEventFilter(wheelFilter); - ui->mapListContainer->tabBar()->installEventFilter(wheelFilter); + auto noScrollFilter = new NoScrollFilter(this, false); + ui->mainTabBar->installEventFilter(noScrollFilter); + ui->mapListContainer->tabBar()->installEventFilter(noScrollFilter); // Create buttons for adding and removing items from the mapList QFrame *buttonFrame = new QFrame(this->ui->mapListContainer); @@ -1455,13 +1455,13 @@ bool MainWindow::setProjectUI() { ui->comboBox_DiveMap->clear(); ui->comboBox_DiveMap->addItems(project->mapNames()); ui->comboBox_DiveMap->setClearButtonEnabled(true); - ui->comboBox_DiveMap->setFocusedScrollingEnabled(false); + ui->comboBox_DiveMap->setAllowScrollingIfFocused(false); const QSignalBlocker b_EmergeMap(ui->comboBox_EmergeMap); ui->comboBox_EmergeMap->clear(); ui->comboBox_EmergeMap->addItems(project->mapNames()); ui->comboBox_EmergeMap->setClearButtonEnabled(true); - ui->comboBox_EmergeMap->setFocusedScrollingEnabled(false); + ui->comboBox_EmergeMap->setAllowScrollingIfFocused(false); // Show/hide parts of the UI that are dependent on the user's project settings diff --git a/src/ui/combobox.cpp b/src/ui/combobox.cpp new file mode 100644 index 00000000..45a404a7 --- /dev/null +++ b/src/ui/combobox.cpp @@ -0,0 +1,69 @@ +#include "combobox.h" +#include "utility.h" + +#include + +ComboBox::ComboBox(QWidget *parent) : QComboBox(parent) { + // QComboBox (as of writing) has no 'editing finished' signal to capture + // changes made either through the text edit or the drop-down. + connect(this, QOverload::of(&QComboBox::activated), this, &ComboBox::editingFinished); +} + +void ComboBox::initLineEdit(QLineEdit *edit) { + if (!edit) return; + + connect(edit, &QLineEdit::editingFinished, this, &ComboBox::editingFinished, Qt::UniqueConnection); + + if (edit->completer()) { + // Allow items to be searched by any part of the word, displaying all matches. + // The default completer behavior is not particularly good, so we do this for all our combo boxes. + edit->completer()->setCompletionMode(QCompleter::PopupCompletion); + edit->completer()->setFilterMode(Qt::MatchContains); + } +} + +void ComboBox::setEditable(bool editable) { + QComboBox::setEditable(editable); + + // Changing editability will either create or destroy the line edit. + // If it was newly-created it needs to be connected. + if (editable) initLineEdit(lineEdit()); +} + +void ComboBox::setLineEdit(QLineEdit *edit) { + QComboBox::setLineEdit(edit); + initLineEdit(edit); +} + +void ComboBox::setItem(int index, const QString &text) { + if (index >= 0) { + // Valid item + setCurrentIndex(index); + } else if (isEditable()) { + // Invalid item in editable box, just display the text + setCurrentText(text); + } else { + // Invalid item in uneditable box, display text as placeholder + // On Qt < 5.15 this will display an empty box +#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) + setPlaceholderText(text); +#endif + setCurrentIndex(index); + } +} + +void ComboBox::setTextItem(const QString &text){ + setItem(findText(text), text); +} + +void ComboBox::setNumberItem(int value) { + setItem(findData(value), QString::number(value)); +} + +void ComboBox::setHexItem(uint32_t value) { + setItem(findData(value), Util::toHexString(value)); +} + +void ComboBox::setClearButtonEnabled(bool enabled) { + if (lineEdit()) lineEdit()->setClearButtonEnabled(enabled); +} diff --git a/src/ui/connectionslistitem.cpp b/src/ui/connectionslistitem.cpp index b773f752..797c018b 100644 --- a/src/ui/connectionslistitem.cpp +++ b/src/ui/connectionslistitem.cpp @@ -16,7 +16,6 @@ ConnectionsListItem::ConnectionsListItem(QWidget *parent, MapConnection * connec // Direction const QSignalBlocker b_Direction(ui->comboBox_Direction); - ui->comboBox_Direction->setMinimumContentsLength(0); ui->comboBox_Direction->addItems(MapConnection::cardinalDirections); ui->comboBox_Direction->installEventFilter(this); @@ -26,7 +25,7 @@ ConnectionsListItem::ConnectionsListItem(QWidget *parent, MapConnection * connec const QSignalBlocker b_Map(ui->comboBox_Map); ui->comboBox_Map->setMinimumContentsLength(6); ui->comboBox_Map->addItems(mapNames); - ui->comboBox_Map->setFocusedScrollingEnabled(false); // Scrolling could cause rapid changes to many different maps + ui->comboBox_Map->setAllowScrollingIfFocused(false); // Scrolling could cause rapid changes to many different maps ui->comboBox_Map->setInsertPolicy(QComboBox::NoInsert); ui->comboBox_Map->installEventFilter(this); diff --git a/src/ui/customattributesdialog.cpp b/src/ui/customattributesdialog.cpp index 36b2694e..c6b88369 100644 --- a/src/ui/customattributesdialog.cpp +++ b/src/ui/customattributesdialog.cpp @@ -16,7 +16,6 @@ CustomAttributesDialog::CustomAttributesDialog(CustomAttributesTable *table) : // Type combo box ui->comboBox_Type->addItems({"String", "Number", "Boolean"}); - ui->comboBox_Type->setEditable(false); // When the value type is changed, update the value input widget connect(ui->comboBox_Type, QOverload::of(&QComboBox::currentIndexChanged), this, &CustomAttributesDialog::setInputType); diff --git a/src/ui/customattributestable.cpp b/src/ui/customattributestable.cpp index ba9409c8..29853981 100644 --- a/src/ui/customattributestable.cpp +++ b/src/ui/customattributestable.cpp @@ -1,6 +1,6 @@ #include "customattributestable.h" #include "parseutil.h" -#include "noscrollspinbox.h" +#include "noscrollwidgets.h" #include "utility.h" #include #include diff --git a/src/ui/divingmappixmapitem.cpp b/src/ui/divingmappixmapitem.cpp index 550e0037..d1a97fb2 100644 --- a/src/ui/divingmappixmapitem.cpp +++ b/src/ui/divingmappixmapitem.cpp @@ -1,7 +1,7 @@ #include "divingmappixmapitem.h" #include "config.h" -DivingMapPixmapItem::DivingMapPixmapItem(MapConnection *connection, NoScrollComboBox *combo) +DivingMapPixmapItem::DivingMapPixmapItem(MapConnection *connection, ComboBox *combo) : QGraphicsPixmapItem(getBasePixmap(connection)) { m_connection = connection; diff --git a/src/ui/encountertabledelegates.cpp b/src/ui/encountertabledelegates.cpp index 12e105bb..c49d45e9 100644 --- a/src/ui/encountertabledelegates.cpp +++ b/src/ui/encountertabledelegates.cpp @@ -3,7 +3,7 @@ #include #include "project.h" -#include "noscrollcombobox.h" +#include "noscrollwidgets.h" @@ -20,6 +20,7 @@ void SpeciesComboDelegate::paint(QPainter *painter, const QStyleOptionViewItem & QWidget *SpeciesComboDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &) const { NoScrollComboBox *editor = new NoScrollComboBox(parent); + editor->setEditable(true); editor->setFrame(false); editor->addItems(this->project->speciesNames); return editor; diff --git a/src/ui/eventfilters.cpp b/src/ui/eventfilters.cpp index 553b21fc..1f3d94f1 100644 --- a/src/ui/eventfilters.cpp +++ b/src/ui/eventfilters.cpp @@ -3,16 +3,6 @@ #include - -bool WheelFilter::eventFilter(QObject *, QEvent *event) { - if (event->type() == QEvent::Wheel) { - return true; - } - return false; -} - - - bool MapSceneEventFilter::eventFilter(QObject*, QEvent *event) { if (event->type() == QEvent::GraphicsSceneWheel) { QGraphicsSceneWheelEvent *wheelEvent = static_cast(event); diff --git a/src/ui/eventframes.cpp b/src/ui/eventframes.cpp index a1af9e97..f812e9ca 100644 --- a/src/ui/eventframes.cpp +++ b/src/ui/eventframes.cpp @@ -30,7 +30,7 @@ void EventFrame::setup() { QHBoxLayout *l_layout_xyz = new QHBoxLayout(); // x spinner & label - this->spinner_x = new NoScrollSpinBox(this); + this->spinner_x = new EditHistorySpinBox(this); this->spinner_x->setMinimum(numeric_limits::min()); this->spinner_x->setMaximum(numeric_limits::max()); @@ -43,7 +43,7 @@ void EventFrame::setup() { l_layout_xyz->addLayout(l_layout_x); // y spinner & label - this->spinner_y = new NoScrollSpinBox(this); + this->spinner_y = new EditHistorySpinBox(this); this->spinner_y->setMinimum(numeric_limits::min()); this->spinner_y->setMaximum(numeric_limits::max()); @@ -114,7 +114,7 @@ void EventFrame::connectSignals(MainWindow *) { } }); - connect(this->event->getPixmapItem(), &EventPixmapItem::xChanged, this->spinner_x, &NoScrollSpinBox::setValue); + connect(this->event->getPixmapItem(), &EventPixmapItem::xChanged, this->spinner_x, &EditHistorySpinBox::setValue); this->spinner_y->disconnect(); connect(this->spinner_y, QOverload::of(&QSpinBox::valueChanged), [this](int value) { @@ -123,7 +123,7 @@ void EventFrame::connectSignals(MainWindow *) { this->event->getMap()->commit(new EventMove(QList() << this->event, 0, delta, this->spinner_y->getActionId())); } }); - connect(this->event->getPixmapItem(), &EventPixmapItem::yChanged, this->spinner_y, &NoScrollSpinBox::setValue); + connect(this->event->getPixmapItem(), &EventPixmapItem::yChanged, this->spinner_y, &EditHistorySpinBox::setValue); this->spinner_z->disconnect(); connect(this->spinner_z, QOverload::of(&QSpinBox::valueChanged), [this](int value) { @@ -181,7 +181,7 @@ void EventFrame::setActive(bool active) { this->blockSignals(!active); } -void EventFrame::populateDropdown(NoScrollComboBox * combo, const QStringList &items) { +void EventFrame::populateDropdown(EventComboBox * combo, const QStringList &items) { // Set the items in the combo box. This may be called after the frame is initialized // if the frame needs to be repopulated, so ensure the text in the combo is preserved // and that we don't accidentally fire 'currentTextChanged'. @@ -192,7 +192,7 @@ void EventFrame::populateDropdown(NoScrollComboBox * combo, const QStringList &i combo->setTextItem(savedText); } -void EventFrame::populateScriptDropdown(NoScrollComboBox * combo, Project * project) { +void EventFrame::populateScriptDropdown(EventComboBox * combo, Project * project) { // The script dropdown and autocomplete are populated with scripts used by the map's events and from its scripts file. Map *map = this->event ? this->event->getMap() : nullptr; if (!map) @@ -223,7 +223,7 @@ void EventFrame::populateScriptDropdown(NoScrollComboBox * combo, Project * proj connect(map, &Map::scriptsModified, this, &EventFrame::invalidateValues, Qt::UniqueConnection); } -void EventFrame::populateMapNameDropdown(NoScrollComboBox * combo, Project * project) { +void EventFrame::populateMapNameDropdown(EventComboBox * combo, Project * project) { if (!project) return; @@ -233,7 +233,7 @@ void EventFrame::populateMapNameDropdown(NoScrollComboBox * combo, Project * pro connect(project, &Project::mapCreated, this, &EventFrame::invalidateValues, Qt::UniqueConnection); } -void EventFrame::populateIdNameDropdown(NoScrollComboBox * combo, Project * project, const QString &mapName, Event::Group group) { +void EventFrame::populateIdNameDropdown(EventComboBox * combo, Project * project, const QString &mapName, Event::Group group) { if (!project || !project->isKnownMap(mapName)) return; @@ -257,7 +257,7 @@ void ObjectFrame::setup() { // sprite combo QFormLayout *l_form_sprite = new QFormLayout(); - this->combo_sprite = new NoScrollComboBox(this); + this->combo_sprite = new EventComboBox(this); static const QString combo_sprite_toolTip = Util::toHtmlParagraph("The sprite graphics to use for this object."); this->combo_sprite->setToolTip(combo_sprite_toolTip); l_form_sprite->addRow("Sprite", this->combo_sprite); @@ -265,7 +265,7 @@ void ObjectFrame::setup() { // movement QFormLayout *l_form_movement = new QFormLayout(); - this->combo_movement = new NoScrollComboBox(this); + this->combo_movement = new EventComboBox(this); static const QString combo_movement_toolTip = Util::toHtmlParagraph("The object's natural movement behavior when the player is not interacting with it."); this->combo_movement->setToolTip(combo_movement_toolTip); l_form_movement->addRow("Movement", this->combo_movement); @@ -291,7 +291,7 @@ void ObjectFrame::setup() { // script QFormLayout *l_form_script = new QFormLayout(); - this->combo_script = new NoScrollComboBox(this); + this->combo_script = new EventComboBox(this); static const QString combo_script_toolTip = Util::toHtmlParagraph("The script that is executed with this event."); this->combo_script->setToolTip(combo_script_toolTip); @@ -312,7 +312,7 @@ void ObjectFrame::setup() { // event flag QFormLayout *l_form_flag = new QFormLayout(); - this->combo_flag = new NoScrollComboBox(this); + this->combo_flag = new EventComboBox(this); static const QString combo_flag_toolTip = Util::toHtmlParagraph("The flag that hides the object when set."); this->combo_flag->setToolTip(combo_flag_toolTip); l_form_flag->addRow("Event Flag", this->combo_flag); @@ -320,7 +320,7 @@ void ObjectFrame::setup() { // trainer type QFormLayout *l_form_trainer = new QFormLayout(); - this->combo_trainer_type = new NoScrollComboBox(this); + this->combo_trainer_type = new EventComboBox(this); static const QString combo_trainer_type_toolTip = Util::toHtmlParagraph("The trainer type of this object event. If it is not a trainer, use NONE. " "SEE ALL DIRECTIONS should only be used with a sight radius of 1."); this->combo_trainer_type->setToolTip(combo_trainer_type_toolTip); @@ -329,7 +329,7 @@ void ObjectFrame::setup() { // sight radius / berry tree id QFormLayout *l_form_radius_treeid = new QFormLayout(); - this->combo_radius_treeid = new NoScrollComboBox(this); + this->combo_radius_treeid = new EventComboBox(this); static const QString combo_radius_treeid_toolTip = Util::toHtmlParagraph("The maximum sight range of a trainer, OR the unique id of the berry tree."); this->combo_radius_treeid->setToolTip(combo_radius_treeid_toolTip); l_form_radius_treeid->addRow("Sight Radius / Berry Tree ID", this->combo_radius_treeid); @@ -482,7 +482,7 @@ void CloneObjectFrame::setup() { // sprite combo (edits disabled) QFormLayout *l_form_sprite = new QFormLayout(); - this->combo_sprite = new NoScrollComboBox(this); + this->combo_sprite = new EventComboBox(this); static const QString combo_sprite_toolTip = Util::toHtmlParagraph("The sprite graphics to use for this object. This is updated automatically " "to match the target object, and so can't be edited. By default the games " "will get the graphics directly from the target object, so this field is ignored."); @@ -493,7 +493,7 @@ void CloneObjectFrame::setup() { // clone map id combo QFormLayout *l_form_dest_map = new QFormLayout(); - this->combo_target_map = new NoScrollComboBox(this); + this->combo_target_map = new EventComboBox(this); static const QString combo_target_map_toolTip = Util::toHtmlParagraph("The name of the map that the object being cloned is on."); this->combo_target_map->setToolTip(combo_target_map_toolTip); l_form_dest_map->addRow("Target Map", this->combo_target_map); @@ -501,7 +501,7 @@ void CloneObjectFrame::setup() { // clone local id combo QFormLayout *l_form_dest_id = new QFormLayout(); - this->combo_target_id = new NoScrollComboBox(this); + this->combo_target_id = new EventComboBox(this); static const QString combo_target_id_toolTip = Util::toHtmlParagraph("The Local ID name or number of the object being cloned."); this->combo_target_id->setToolTip(combo_target_id_toolTip); l_form_dest_id->addRow("Target Local ID", this->combo_target_id); @@ -599,7 +599,7 @@ void WarpFrame::setup() { // desination map combo QFormLayout *l_form_dest_map = new QFormLayout(); - this->combo_dest_map = new NoScrollComboBox(this); + this->combo_dest_map = new EventComboBox(this); static const QString combo_dest_map_toolTip = Util::toHtmlParagraph("The destination map name of the warp."); this->combo_dest_map->setToolTip(combo_dest_map_toolTip); l_form_dest_map->addRow("Destination Map", this->combo_dest_map); @@ -607,7 +607,7 @@ void WarpFrame::setup() { // desination warp id QFormLayout *l_form_dest_warp = new QFormLayout(); - this->combo_dest_warp = new NoScrollComboBox(this); + this->combo_dest_warp = new EventComboBox(this); static const QString combo_dest_warp_toolTip = Util::toHtmlParagraph("The warp id on the destination map."); this->combo_dest_warp->setToolTip(combo_dest_warp_toolTip); l_form_dest_warp->addRow("Destination Warp", this->combo_dest_warp); @@ -701,7 +701,7 @@ void TriggerFrame::setup() { // script combo QFormLayout *l_form_script = new QFormLayout(); - this->combo_script = new NoScrollComboBox(this); + this->combo_script = new EventComboBox(this); static const QString combo_script_toolTip = Util::toHtmlParagraph("The script that is executed with this event."); this->combo_script->setToolTip(combo_script_toolTip); l_form_script->addRow("Script", this->combo_script); @@ -709,7 +709,7 @@ void TriggerFrame::setup() { // var combo QFormLayout *l_form_var = new QFormLayout(); - this->combo_var = new NoScrollComboBox(this); + this->combo_var = new EventComboBox(this); static const QString combo_var_toolTip = Util::toHtmlParagraph("The variable by which the script is triggered. " "The script is triggered when this variable's value matches 'Var Value'."); this->combo_var->setToolTip(combo_var_toolTip); @@ -718,7 +718,7 @@ void TriggerFrame::setup() { // var value combo QFormLayout *l_form_var_val = new QFormLayout(); - this->combo_var_value = new NoScrollComboBox(this); + this->combo_var_value = new EventComboBox(this); static const QString combo_var_value_toolTip = Util::toHtmlParagraph("The variable's value that triggers the script."); this->combo_var_value->setToolTip(combo_var_value_toolTip); l_form_var_val->addRow("Var Value", this->combo_var_value); @@ -788,7 +788,7 @@ void WeatherTriggerFrame::setup() { // weather combo QFormLayout *l_form_weather = new QFormLayout(); - this->combo_weather = new NoScrollComboBox(this); + this->combo_weather = new EventComboBox(this); static const QString combo_weather_toolTip = Util::toHtmlParagraph("The weather that starts when the player steps on this spot."); this->combo_weather->setToolTip(combo_weather_toolTip); l_form_weather->addRow("Weather", this->combo_weather); @@ -837,7 +837,7 @@ void SignFrame::setup() { // facing dir combo QFormLayout *l_form_facing_dir = new QFormLayout(); - this->combo_facing_dir = new NoScrollComboBox(this); + this->combo_facing_dir = new EventComboBox(this); static const QString combo_facing_dir_toolTip = Util::toHtmlParagraph("The direction that the player must be facing to be able to interact with this event."); this->combo_facing_dir->setToolTip(combo_facing_dir_toolTip); l_form_facing_dir->addRow("Player Facing Direction", this->combo_facing_dir); @@ -845,7 +845,7 @@ void SignFrame::setup() { // script combo QFormLayout *l_form_script = new QFormLayout(); - this->combo_script = new NoScrollComboBox(this); + this->combo_script = new EventComboBox(this); static const QString combo_script_toolTip = Util::toHtmlParagraph("The script that is executed with this event."); this->combo_script->setToolTip(combo_script_toolTip); l_form_script->addRow("Script", this->combo_script); @@ -905,7 +905,7 @@ void HiddenItemFrame::setup() { // item combo QFormLayout *l_form_item = new QFormLayout(); - this->combo_item = new NoScrollComboBox(this); + this->combo_item = new EventComboBox(this); static const QString combo_item_toolTip = Util::toHtmlParagraph("The item to be given."); this->combo_item->setToolTip(combo_item_toolTip); l_form_item->addRow("Item", this->combo_item); @@ -913,7 +913,7 @@ void HiddenItemFrame::setup() { // flag combo QFormLayout *l_form_flag = new QFormLayout(); - this->combo_flag = new NoScrollComboBox(this); + this->combo_flag = new EventComboBox(this); static const QString combo_flag_toolTip = Util::toHtmlParagraph("The flag that is set when the hidden item is picked up."); this->combo_flag->setToolTip(combo_flag_toolTip); l_form_flag->addRow("Flag", this->combo_flag); @@ -1023,7 +1023,7 @@ void SecretBaseFrame::setup() { // item combo QFormLayout *l_form_base_id = new QFormLayout(); - this->combo_base_id = new NoScrollComboBox(this); + this->combo_base_id = new EventComboBox(this); static const QString combo_base_id_toolTip = Util::toHtmlParagraph("The secret base id that is inside this secret base entrance. " "Secret base ids are meant to be unique to each and every secret base entrance."); this->combo_base_id->setToolTip(combo_base_id_toolTip); @@ -1086,7 +1086,7 @@ void HealLocationFrame::setup() { this->hideable_respawn_map = new QFrame; QFormLayout *l_form_respawn_map = new QFormLayout(hideable_respawn_map); l_form_respawn_map->setContentsMargins(0, 0, 0, 0); - this->combo_respawn_map = new NoScrollComboBox(hideable_respawn_map); + this->combo_respawn_map = new EventComboBox(hideable_respawn_map); static const QString combo_respawn_map_toolTip = Util::toHtmlParagraph("The map where the player will respawn after whiteout."); this->combo_respawn_map->setToolTip(combo_respawn_map_toolTip); l_form_respawn_map->addRow("Respawn Map", this->combo_respawn_map); @@ -1096,7 +1096,7 @@ void HealLocationFrame::setup() { this->hideable_respawn_npc = new QFrame; QFormLayout *l_form_respawn_npc = new QFormLayout(hideable_respawn_npc); l_form_respawn_npc->setContentsMargins(0, 0, 0, 0); - this->combo_respawn_npc = new NoScrollComboBox(hideable_respawn_npc); + this->combo_respawn_npc = new EventComboBox(hideable_respawn_npc); static const QString combo_respawn_npc_toolTip = Util::toHtmlParagraph("The Local ID name or number of the NPC the player " "interacts with upon respawning after whiteout."); this->combo_respawn_npc->setToolTip(combo_respawn_npc_toolTip); diff --git a/src/ui/mapheaderform.cpp b/src/ui/mapheaderform.cpp index 921aec82..890face2 100644 --- a/src/ui/mapheaderform.cpp +++ b/src/ui/mapheaderform.cpp @@ -187,7 +187,7 @@ void MapHeaderForm::setAllowsEscaping(bool allowsEscaping) { ui->checkBox_ void MapHeaderForm::setFloorNumber(int floorNumber) { ui->spinBox_FloorNumber->setValue(floorNumber); } // If we always call setText / setTextItem the user's cursor may move to the end of the text while they're typing. -void MapHeaderForm::setText(NoScrollComboBox *combo, const QString &text) const { +void MapHeaderForm::setText(ComboBox *combo, const QString &text) const { if (combo->currentText() != text) combo->setTextItem(text); } diff --git a/src/ui/montabwidget.cpp b/src/ui/montabwidget.cpp index e2291f11..2a08de45 100644 --- a/src/ui/montabwidget.cpp +++ b/src/ui/montabwidget.cpp @@ -1,6 +1,6 @@ #include "montabwidget.h" -#include "noscrollcombobox.h" #include "editor.h" +#include "noscrollwidgets.h" #include "encountertablemodel.h" #include "encountertabledelegates.h" #include "eventfilters.h" @@ -15,7 +15,7 @@ MonTabWidget::MonTabWidget(Editor *editor, QWidget *parent) : QTabWidget(parent) connect(this, &MonTabWidget::edited, this->editor, &Editor::wildMonTableEdited); populate(); - this->tabBar()->installEventFilter(new WheelFilter(this)); + this->tabBar()->installEventFilter(new NoScrollFilter(this, false)); } MonTabWidget::~MonTabWidget() { diff --git a/src/ui/noscrollcombobox.cpp b/src/ui/noscrollcombobox.cpp deleted file mode 100644 index 191c5c45..00000000 --- a/src/ui/noscrollcombobox.cpp +++ /dev/null @@ -1,97 +0,0 @@ -#include "noscrollcombobox.h" -#include "utility.h" - -#include -#include -#include - -NoScrollComboBox::NoScrollComboBox(QWidget *parent) - : QComboBox(parent) -{ - // Don't let scrolling hijack focus. - setFocusPolicy(Qt::StrongFocus); - - // Make speed a priority when loading comboboxes. - setMinimumContentsLength(24);// an arbitrary limit - setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon); - - // Allow items to be searched by any part of the word, displaying all matches. - setEditable(true);// can set to false manually when using - this->completer()->setCompletionMode(QCompleter::PopupCompletion); - this->completer()->setFilterMode(Qt::MatchContains); - - static const QRegularExpression re("[^\\s]*"); - QValidator *validator = new QRegularExpressionValidator(re, this); - this->setValidator(validator); - - // QComboBox (as of writing) has no 'editing finished' signal to capture - // changes made either through the text edit or the drop-down. - connect(this, QOverload::of(&QComboBox::activated), this, &NoScrollComboBox::editingFinished); - connect(this->lineEdit(), &QLineEdit::editingFinished, this, &NoScrollComboBox::editingFinished); -} - -// On macOS QComboBox::setEditable and QComboBox::setLineEdit will override our changes to the focus policy, so we enforce it here. -void NoScrollComboBox::setEditable(bool editable) { - auto policy = focusPolicy(); - QComboBox::setEditable(editable); - setFocusPolicy(policy); -} -void NoScrollComboBox::setLineEdit(QLineEdit *edit) { - auto policy = focusPolicy(); - QComboBox::setLineEdit(edit); - setFocusPolicy(policy); -} - -void NoScrollComboBox::wheelEvent(QWheelEvent *event) -{ - // By default NoScrollComboBoxes will allow scrolling to modify its contents only when it explicitly has focus. - // If focusedScrollingEnabled is false it won't allow scrolling even with focus. - if (this->focusedScrollingEnabled && hasFocus()) { - QComboBox::wheelEvent(event); - } else { - event->ignore(); - } -} - -void NoScrollComboBox::setFocusedScrollingEnabled(bool enabled) -{ - this->focusedScrollingEnabled = enabled; -} - -void NoScrollComboBox::setItem(int index, const QString &text) -{ - if (index >= 0) { - // Valid item - this->setCurrentIndex(index); - } else if (this->isEditable()) { - // Invalid item in editable box, just display the text - this->setCurrentText(text); - } else { - // Invalid item in uneditable box, display text as placeholder - // On Qt < 5.15 this will display an empty box -#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) - this->setPlaceholderText(text); -#endif - this->setCurrentIndex(index); - } -} - -void NoScrollComboBox::setTextItem(const QString &text) -{ - this->setItem(this->findText(text), text); -} - -void NoScrollComboBox::setNumberItem(int value) -{ - this->setItem(this->findData(value), QString::number(value)); -} - -void NoScrollComboBox::setHexItem(uint32_t value) -{ - this->setItem(this->findData(value), Util::toHexString(value)); -} - -void NoScrollComboBox::setClearButtonEnabled(bool enabled) { - if (this->lineEdit()) - this->lineEdit()->setClearButtonEnabled(enabled); -} diff --git a/src/ui/noscrollspinbox.cpp b/src/ui/noscrollspinbox.cpp deleted file mode 100644 index 3493d4ee..00000000 --- a/src/ui/noscrollspinbox.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "noscrollspinbox.h" -#include -#include - -unsigned actionId = 0xffff; - -NoScrollSpinBox::NoScrollSpinBox(QWidget *parent) - : QSpinBox(parent) -{ - // Don't let scrolling hijack focus. - setFocusPolicy(Qt::StrongFocus); -} - -void NoScrollSpinBox::wheelEvent(QWheelEvent *event) -{ - // Only allow scrolling to modify contents when it explicitly has focus. - if (hasFocus()) { - QSpinBox::wheelEvent(event); - } else { - event->ignore(); - } -} - -void NoScrollSpinBox::focusOutEvent(QFocusEvent *event) { - actionId++; - QSpinBox::focusOutEvent(event); -} - -void NoScrollSpinBox::setLineEditEnabled(bool enabled) { - this->lineEdit()->setReadOnly(!enabled); -} - -unsigned NoScrollSpinBox::getActionId() { - return actionId; -} diff --git a/src/ui/noscrollwidgets.cpp b/src/ui/noscrollwidgets.cpp new file mode 100644 index 00000000..f34f7a60 --- /dev/null +++ b/src/ui/noscrollwidgets.cpp @@ -0,0 +1,37 @@ +#include "noscrollwidgets.h" + +#include + +bool NoScrollFilter::eventFilter(QObject *object, QEvent *event) { + if (event->type() != QEvent::Wheel) return false; + + if (m_allowIfFocused) { + auto widget = qobject_cast(object); + if (widget && widget->hasFocus()) return false; + } + event->ignore(); + return true; +} + +NoScrollFilter* NoScrollFilter::apply(QObject *target, bool allowIfFocused) { + if (!target) return nullptr; + + auto widget = qobject_cast(target); + if (widget) widget->setFocusPolicy(Qt::StrongFocus); + + auto filter = new NoScrollFilter(target, allowIfFocused); + target->installEventFilter(filter); + return filter; +} + +// On macOS QComboBox::setEditable and QComboBox::setLineEdit will override our changes to the focus policy, so we enforce it here. +void NoScrollComboBox::setEditable(bool editable) { + auto policy = focusPolicy(); + ComboBox::setEditable(editable); + setFocusPolicy(policy); +} +void NoScrollComboBox::setLineEdit(QLineEdit *edit) { + auto policy = focusPolicy(); + ComboBox::setLineEdit(edit); + setFocusPolicy(policy); +} diff --git a/src/ui/preferenceeditor.cpp b/src/ui/preferenceeditor.cpp index 7fd85ff9..e2e52be3 100644 --- a/src/ui/preferenceeditor.cpp +++ b/src/ui/preferenceeditor.cpp @@ -1,6 +1,5 @@ #include "preferenceeditor.h" #include "ui_preferenceeditor.h" -#include "noscrollcombobox.h" #include "message.h" #include @@ -17,9 +16,6 @@ PreferenceEditor::PreferenceEditor(QWidget *parent) : ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose); - ui->comboBox_ColorSpace->setMinimumContentsLength(0); - ui->comboBox_ApplicationTheme->setMinimumContentsLength(0); - connect(ui->buttonBox, &QDialogButtonBox::clicked, this, &PreferenceEditor::dialogButtonClicked); connect(ui->pushButton_CustomizeApplicationFont, &QPushButton::clicked, [this] { diff --git a/src/ui/projectsettingseditor.cpp b/src/ui/projectsettingseditor.cpp index 0df96149..3e7123fd 100644 --- a/src/ui/projectsettingseditor.cpp +++ b/src/ui/projectsettingseditor.cpp @@ -1,6 +1,5 @@ #include "projectsettingseditor.h" #include "config.h" -#include "noscrollcombobox.h" #include "prefab.h" #include "filedialog.h" #include "newdefinedialog.h" @@ -80,7 +79,7 @@ void ProjectSettingsEditor::connectSignals() { connect(ui->spinBox_TerrainTypeMask, &UIntSpinBox::textChanged, this, &ProjectSettingsEditor::updateAttributeMaskOverlapWarning); // Record that there are unsaved changes if any of the settings are modified - for (auto combo : ui->centralwidget->findChildren()){ + for (auto combo : ui->centralwidget->findChildren()){ // Changes to these two combo boxes are just for info display, don't mark as unsaved if (combo != ui->comboBox_IconSpecies && combo != ui->comboBox_WarpBehaviors) connect(combo, &QComboBox::currentTextChanged, this, &ProjectSettingsEditor::markEdited); diff --git a/src/ui/regionmapeditor.cpp b/src/ui/regionmapeditor.cpp index 513d3971..0331c1dd 100644 --- a/src/ui/regionmapeditor.cpp +++ b/src/ui/regionmapeditor.cpp @@ -1102,10 +1102,10 @@ void RegionMapEditor::on_action_Swap_triggered() { QFormLayout form(&popup); - QComboBox *oldSecBox = new QComboBox(); + auto oldSecBox = new NoScrollComboBox(); oldSecBox->addItems(this->project->locationNames()); form.addRow(new QLabel("Map Section 1:"), oldSecBox); - QComboBox *newSecBox = new QComboBox(); + auto newSecBox = new NoScrollComboBox(); newSecBox->addItems(this->project->locationNames()); form.addRow(new QLabel("Map Section 2:"), newSecBox); @@ -1141,10 +1141,10 @@ void RegionMapEditor::on_action_Replace_triggered() { QFormLayout form(&popup); - QComboBox *oldSecBox = new QComboBox(); + auto oldSecBox = new NoScrollComboBox(); oldSecBox->addItems(this->project->locationNames()); form.addRow(new QLabel("Old Map Section:"), oldSecBox); - QComboBox *newSecBox = new QComboBox(); + auto newSecBox = new NoScrollComboBox(); newSecBox->addItems(this->project->locationNames()); form.addRow(new QLabel("New Map Section:"), newSecBox); diff --git a/src/ui/tileseteditor.cpp b/src/ui/tileseteditor.cpp index 723a2afd..aff49d35 100644 --- a/src/ui/tileseteditor.cpp +++ b/src/ui/tileseteditor.cpp @@ -145,7 +145,6 @@ void TilesetEditor::initAttributesUi() { for (auto i = project->metatileBehaviorMapInverse.constBegin(); i != project->metatileBehaviorMapInverse.constEnd(); i++) { this->ui->comboBox_MetatileBehaviors->addItem(i.value(), i.key()); } - this->ui->comboBox_MetatileBehaviors->setMinimumContentsLength(0); } else { this->ui->frame_MetatileBehavior->setVisible(false); } @@ -155,7 +154,6 @@ void TilesetEditor::initAttributesUi() { for (auto i = project->terrainTypeToName.constBegin(); i != project->terrainTypeToName.constEnd(); i++) { this->ui->comboBox_TerrainType->addItem(i.value(), i.key()); } - this->ui->comboBox_TerrainType->setMinimumContentsLength(0); } else { this->ui->frame_TerrainType->setVisible(false); } @@ -165,7 +163,6 @@ void TilesetEditor::initAttributesUi() { for (auto i = project->encounterTypeToName.constBegin(); i != project->encounterTypeToName.constEnd(); i++) { this->ui->comboBox_EncounterType->addItem(i.value(), i.key()); } - this->ui->comboBox_EncounterType->setMinimumContentsLength(0); } else { this->ui->frame_EncounterType->setVisible(false); } @@ -175,8 +172,6 @@ void TilesetEditor::initAttributesUi() { this->ui->comboBox_LayerType->addItem("Normal - Middle/Top", Metatile::LayerType::Normal); this->ui->comboBox_LayerType->addItem("Covered - Bottom/Middle", Metatile::LayerType::Covered); this->ui->comboBox_LayerType->addItem("Split - Bottom/Top", Metatile::LayerType::Split); - this->ui->comboBox_LayerType->setEditable(false); - this->ui->comboBox_LayerType->setMinimumContentsLength(0); if (!projectConfig.metatileLayerTypeMask) { // User doesn't have triple layer metatiles, but has no layer type attribute. // Porymap is still using the layer type value to render metatiles, and with @@ -668,7 +663,7 @@ uint32_t TilesetEditor::attributeNameToValue(Metatile::Attr attribute, const QSt return text.toUInt(ok, 0); } -void TilesetEditor::commitAttributeFromComboBox(Metatile::Attr attribute, NoScrollComboBox *combo) { +void TilesetEditor::commitAttributeFromComboBox(Metatile::Attr attribute, ComboBox *combo) { if (!this->metatile) return; bool ok; diff --git a/src/ui/uintspinbox.cpp b/src/ui/uintspinbox.cpp index 7155aa67..de3c9fb8 100644 --- a/src/ui/uintspinbox.cpp +++ b/src/ui/uintspinbox.cpp @@ -1,8 +1,7 @@ #include "uintspinbox.h" -#include UIntSpinBox::UIntSpinBox(QWidget *parent) - : QAbstractSpinBox(parent), + : NoScrollAbstractSpinBox(parent), m_minimum(0), m_maximum(99), m_value(m_minimum), @@ -11,9 +10,6 @@ UIntSpinBox::UIntSpinBox(QWidget *parent) m_hasPadding(false), m_numChars(2) { - // Don't let scrolling hijack focus. - setFocusPolicy(Qt::StrongFocus); - this->updateEdit(); connect(lineEdit(), SIGNAL(textEdited(QString)), this, SLOT(onEditFinished())); }; @@ -193,15 +189,6 @@ QAbstractSpinBox::StepEnabled UIntSpinBox::stepEnabled() const { return flags; } -void UIntSpinBox::wheelEvent(QWheelEvent *event) { - // Only allow scrolling to modify contents when it explicitly has focus. - if (hasFocus()) { - QAbstractSpinBox::wheelEvent(event); - } else { - event->ignore(); - } -} - void UIntSpinBox::focusOutEvent(QFocusEvent *event) { this->updateEdit(); QAbstractSpinBox::focusOutEvent(event);