-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New properties framework #4045
New properties framework #4045
Conversation
Here's a preview of what it looked like at some point, when it wasn't actually functional but had all Map properties represented: And here's a video of the current state, with only three properties, but they are fully implemented: resize-map-button.mp4Main advantages are currently:
|
I got a chance to try this out and look at the code. I like it. It's nice to have the resize map button more accessible on the map properties. As far as the code, I'm definitely less equipped than you to judge it but I had a few thoughts. At first I wondered if there might be a way to define these editable properties and the widgets that would be produced on the edited objects themselves (worlds, maps, etc.) but I guess that's really only used in this property editor component, so there's no need. The properties have to take the editor factory in as a constructor argument, and currently you are creating a subclass for each type of property. I'm wondering about if there's a way to make it so that only the PropertiesWidget would even need to know about the factory. I feel like the factory could just be a way to generate editor widgets for well-known types of properties that don't need customization. Or maybe the factory just becomes a parameter to addProperty() instead and you only need to provide one if you need to customize the produced widget. Also, it might be nice if there was a lighter syntax for adding a property that didn't entail creating a class for each property. Part of what makes me think this is the current need to store the editor factory in each property which creates a little more boilerplate for each property, while classes that customize the widget like MapSizeProperty don't actually need the factory at all from what I can see. Being able to just pass in lambdas or something for getting/setting the value to addProperty() could be nice. I would think there would be a lot of properties where you would just be calling existing getters and setters, but maybe I'm wrong. Feel free to disregard any of this, though, just some initial thoughts that may be misinformed |
@dogboydog Thanks for writing down your thoughts on the new properties implementation! They've been the exact things I'm also wondering about / struggling with. There may not be one simple solution for everything, but indeed this "factory" argument is quite annoying, especially when passing in that "default factory" most of the time anyway. I've thought about creating the properties through the factory instead. So far there are
When not using |
f40314a
to
f13fd5c
Compare
Small update on the current state. Last week I've finished implementing the built-in properties for all data types, minus a few that will need a custom widget: In the above we see a lacking widget for setting "Allowed Transformations" as well as for changing tileset parameters (which will use a button for now, similar to "Resize Map"). In the past days I've addressed many loose ends, like setting minimum/maximum values, step sizes and file dialog filters. I've also improved the widget for setting up the font of text objects, so it takes up less vertical space: The biggest task remaining is to add support for editing, adding and removing Custom Properties, and also to make the headers collapsible. Other open tasks are restoring support for changing the properties of multiple objects at once and displaying "inherited" values like the class set on a tile when a tile object is selected. |
036f68c
to
68d84af
Compare
Screenshot showing some of the recent changes:
|
50abb67
to
99dcb30
Compare
After the above change, inherited properties are now shown in disabled state, with a '+' button that allows adding those properties: One issue that remains to be addressed is when the removal of a property exposes an inherited property with the same name, but with a different type. The relevant property will need to be re-created in this case. |
bf0c1cf
to
6b23c51
Compare
Latest changes address various features that already existed with the old properties solution:
Also there is now a custom widget for the tile object flipping states: And there is a tool tip showing the type of each custom property, including the type for class members: |
1385a01
to
b1d79f7
Compare
5e872ea
to
2177a6e
Compare
Reported feedback so far:
Many thanks to @eishiya for all their feedback! |
The new property editor will be based on a widget hierarchy instead of a QTreeView. This will allow better customization and direct widget interaction. This first step implements various property edit widgets which are instantiated based on the type of QVariant values. * DoubleSpinBox, with precision logic from existing property editor * Custom spin boxes and combo boxes which shrink horizontally * Property names elide when there isn't enough space * QPointF and QColor editor factories * Includes a test with all built-in map properties * Supports headers (not collapsible for now) * Supports separators * EnumEditorFactory, with support for non-consecutive enums * Name and editor widgets are stretched by a fixed 2:3 ratio and ignore their size hint * Includes some start on possible API for setting/getting the value
It adjusts the layout based on its width. Also made a few other visual tweaks.
Introduced Property class and changed from using editor factories to having the property itself create its widget.
* Map size is read-only but features a "Resize Map" button that triggers the resize dialog. * Both map size and tile size are implemented based on the new "ValueTypeEditorFactory" which selects an editor based on the value type. This functionality is moved out of the VariantEditor. * Introduced AbstractProperty, ValueProperty and QObjectProperty in an attempt to provide some convenience on top of the Property interface. I'm not entirely convinced it was a good idea to put the "createEditor" function on the Property. It makes it easy to do custom widgets for a property, but annoying to have it use a type-based editor.
* Introduced MapProperties class to make it easier to emit valueChanged for all the map's properties, as well to move their creation out of PropertiesWidget::currentObjectChanged. * Added GetSetProperty that makes it easier to define a property in terms of a given getter and setter function, since it avoids the need for a specific Property subclass. * Finished implementation of the BoolEditorFactory (signals connected). * Moved property edit widgets to their own file.
* Introduced a few helper functions to reduce code duplication, like MapProperties::push. * Disabled properties when they are irrelevant. * Finished connecting the signals for the remaining editor factories: StringEditorFactory, IntEditorFactory, FloatEditorFactory, PointEditorFactory, PointFEditorFactory, RectFEditorFactory and ColorEditorFactory.
This property uses an editable combo box with the valid classes set up for the given object type.
Still needs special handling for: * Color (requires handling invalid/unset values) * Widget for editing allowed transformations * Widget for showing tileset parameters (and trigger edit dialog) * Specifying 1 as minimum value for column count
Some details remain to be done: * Changes made to layer properties should apply to all selected layers * Opacity should probably be a slider now and have appropriate limits * Step size for opacity and parallax factor is too big
Added support for editing QUrl values using UrlEditorFactory that creates a FileEdit.
Also in this change: * Made SpinBox and DoubleSpinBox don't respond to changing from keyboard typing immediately. * Share a single implementation of wrapping label/widget pairs for SizeEdit, SizeFEdit, PointEdit, PointFEdit and RectFEdit. * Added widget factories for QFont, QSizeF and Qt::Alignment. * Allow setting suffix on custom FloatEditorFactory, used for adding degree symbol to rotation values. A few things remain to be done: * Custom widget for editing tile object flipping flags * Try reducing size of font editor with style toggle buttons
Now all built-in properties are present, apart from some loose ends. * Added RectEdit / RectEditorFactory (QRect values) * Added Property::toolTip (set on label and editor, but currently not functional on label due to the eliding tool tip logic) * Added change events to fix updating of WangSet and WangColor properties (was already broken with old framework)
Instead there are now typed Property subclasses similar to the generic GetSetProperty.
0728bd0
to
8679152
Compare
A lot of places were still relying on the mapChanged signal, but they should use mapResized or the MapChangeEvent since 2177fac.
When adding custom class properties, they are expanded with the first member focused.
Use a special property that creates a name edit as label and a type combo box as editor, instead of a modal Add Property dialog. VariantEditorView::focusProperty now makes sure that the focused property widget is visible. The "add value" property is automatically removed when it loses focus. To achieve this, each property now gets its own parent widget rather than just having its widgets added to a nested horizontal layout. This way, we can check whether the focus remains within the same parent widget. The Add button has Qt::StrongFocus policy now, otherwise the focus would be lost to the properties view when clicking it.
When changed by other means (scripting, undo/redo, Layers view), the name wasn't updating due to a missing valueChanged call.
We don't really need to put it in a QWidget with a vertical layout.
8679152
to
1a3e249
Compare
- Top-level properties can be selected by clicking. - Holding Ctrl or Shift allows selecting multiple. - Keyboard handling for selection implemented. - Remove and Rename actions on tool bar now functional. - Copy/paste shortcuts work. As part of implementing this, the VariantEditor and VariantEditorView have been merged into a single PropertiesView class. ToDo: - selectedPropertiesChanged may not get emitted when a selected property is removed. - Add Copy/Paste actions to context menu.
To match the rename in the last commit. The term "VariantEditor" referred to the initial approach of using QVariant for all properties. Now "PropertiesView" is more appropriate, since it is a view based on the type-agnostic "Property" hierarchy.
Now they both scale vertically to cover the minimum size of both.
Better to not touch the clipboard at all in this case.
When pasting custom properties, we now make sure that the Custom Properties group is expanded and select the pasted properties for some additional feedback. Also focus the first pasted property, which makes sure at least one of them is visible.
This change also disables Enter for opening the combo box popup, fixing the rather broken behavior (at least on Linux) that pressing Enter to select a type will immediately re-open the popup. That only applies to combo boxes in the Properties view, though.
This makes the property-specific actions like "Go to Object" and "Open Containing Folder" available again, as well as the Cut, Copy and Paste actions. For now, the Custom Types Editor has no context menu anymore... Property widgets are now removed before their property is deleted to avoid a crash when right-clicking the AddValueProperty, since that caused the focus to be lost and thus the removal of the property while at the same time triggering a context menu for it.
The QCommonStyle always uses the WindowText role when rendering a checkbox label, so change the palette so that is picks up the HighlightedText role when the property is selected.
The tab order follows the widget creation order, which is not what we want when properties are inserted between other properties. Hence we now explicitly set the tab order in this case. We can't just call QWidget::setTabOrder on the row widgets unfortunately, because the call does nothing when called with widgets that have Qt::NoFocus policy. Calling QWidget::setTabOrder only on the inserted sequence led to other issues, which led me to the solution of setting the tab order for all property widgets to match the order in the layout. To avoid too much repeated work when multiple properties are inserted, the fixTabOrder call is scheduled using QMetaObject::invokeMethod.
Instead of a using the disabled state for properties that are not set on the current object, inherited values now feature a Reset button and have their name displayed in bold when they have been overridden. This makes inherited properties directly editable, matching the behavior for class members. To avoid confusion, properties from other selected objects are no longer displayed (this reverts 8cc0374).
This adds the feature originally implemented in 8434f5e to the new Properties view.
To make inherited properties easier to distinguish from explicitly set properties, their labels are now dimmed (by disabling them). This is done recursively for any class members.
To avoid synchronizing the value for all selected objects.
Now it is possible to enter the hex value (or CSS color name) to set a color's value.
1a3e249
to
544ae78
Compare
I've started implementing a new properties framework in an attempt to improve some existing usability issues as well as to make it easier to add support for list properties (#4002).
This is a work-in-progress! It its current state the Properties view can only edit a few built-in map properties.
I'm sharing this here for the curious and to gather feedback.