UI: add support for uiLayout based panels #113584
No reviewers
Labels
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset Browser
Interest
Asset Browser Project Overview
Interest
Audio
Interest
Automated Testing
Interest
Blender Asset Bundle
Interest
BlendFile
Interest
Collada
Interest
Compatibility
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
EEVEE
Interest
EEVEE & Viewport
Interest
Freestyle
Interest
Geometry Nodes
Interest
Grease Pencil
Interest
ID Management
Interest
Images & Movies
Interest
Import Export
Interest
Line Art
Interest
Masking
Interest
Metal
Interest
Modeling
Interest
Modifiers
Interest
Motion Tracking
Interest
Nodes & Physics
Interest
OpenGL
Interest
Overlay
Interest
Overrides
Interest
Performance
Interest
Physics
Interest
Pipeline, Assets & IO
Interest
Platforms, Builds & Tests
Interest
Python API
Interest
Render & Cycles
Interest
Render Pipeline
Interest
Sculpt, Paint & Texture
Interest
Text Editor
Interest
Translations
Interest
Triaging
Interest
Undo
Interest
USD
Interest
User Interface
Interest
UV Editing
Interest
VFX & Video
Interest
Video Sequencer
Interest
Virtual Reality
Interest
Vulkan
Interest
Wayland
Interest
Workbench
Interest: X11
Legacy
Blender 2.8 Project
Legacy
Milestone 1: Basic, Local Asset Browser
Legacy
OpenGL Error
Meta
Good First Issue
Meta
Papercut
Meta
Retrospective
Meta
Security
Module
Animation & Rigging
Module
Core
Module
Development Management
Module
EEVEE & Viewport
Module
Grease Pencil
Module
Modeling
Module
Nodes & Physics
Module
Pipeline, Assets & IO
Module
Platforms, Builds & Tests
Module
Python API
Module
Render & Cycles
Module
Sculpt, Paint & Texture
Module
Triaging
Module
User Interface
Module
VFX & Video
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Priority
High
Priority
Low
Priority
Normal
Priority
Unbreak Now!
Status
Archived
Status
Confirmed
Status
Duplicate
Status
Needs Info from Developers
Status
Needs Information from User
Status
Needs Triage
Status
Resolved
Type
Bug
Type
Design
Type
Known Issue
Type
Patch
Type
Report
Type
To Do
No Milestone
No project
No Assignees
5 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: blender/blender#113584
Loading…
Reference in New Issue
No description provided.
Delete Branch "JacquesLucke/blender:layout-panels"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
This adds support for so called "layout panels" which are panels that are created as part of
uiLayout
. The goal is to make it easier to have expandable sections as part of a UI.The reason I'm working on this is to find a better solution to what was attempted in #108565.
Problems with Existing Approaches
Currently, there are two ways to create these expandable sections:
Panel
type for each expandable section and use theparent_id
to make this a subpanel of another panel. This has a few problems:uiLayout
drawing code is more scattered, because one can't just use a single function that creates the layout for an entire panel including its subpanels.uiLayout
. This is done in the material properties. It also has a few problems:Solution
A possible solution to all of these problems is to add support for panels to
uiLayout
directly:Integrating subpanels with
uiLayout
has some benefits:Open/Close State
The most tricky thing is to decide where to store the open/close state. Ideally, it should be stored in the
region
because then the same layout panel can be opened and closed in every region independently. Unfortunately, storing the state in the region is fairly complex in some cases.For example, for modifier subpanels the region would have to store an open/close state for each panel in each modifier in each object. So a map with
object pointer + modifier id + panel id
as key would be required. Obviously, this map could become quite big. Also storing that many ID pointers in UI data is not great and we don't even have stable modifier ids yet. There also isn't an obvious way for how to clear unused elements from the map which could become necessary when it becomes big.In practice, it's rare that the same modifier list is shown in two editors. So the benefit of storing the open/close state in the region is negilible. Therefor, a much simpler solution is possible: the open/close state can be stored in the modifier directly. This is actually how it's implemented right now already (see
ui_expand_flag
).The implementation of layout panels in this patch is agnostic to how the open/close state is stored exactly, as long as it can be referenced as a boolean rna property. This allows us to store the state the state in the modifier directly but also allows us to store the state in the region for other layout panels in the future. We could consider adding an API that makes it easy to store the state in the region for cases where the key is simpler. For example:
uiLayoutPanel(layout, TIP_("Mesh Settings"), PanelRegionKey("mesh_settings"))
.Python API
Adding a Python API is fairly straight forward with the current design. However, it is not included in this patch so that we can mature the internal API a bit more if necessary, before addon developers start to depend on it. It would probably work like so:
WIP: UI: UILayout based subpanelsto WIP: UI: uiLayout based subpanelsThe overall approach looks pretty nice, especially at the API level. Two points:
Other than that I didn't do an in depth look at the code.
Fixed that part.
Don't really want to make the specifics of the current implementation part of the discussion yet, before it's not clear that we want to be able to create subpanels like this in the first place. Nested subpanels and interleaved top-level buttons actually "just work". Not that it looks super great currently.
Checked over the patch & tested functionality.
Overall I think this is nice functionality to be able to declare expandable sections inline, but this exposes some awkwardness in the API which don't have clear solutions AFAICS.
Notes:
The
uiLayoutPanel
are likely to be used by add-ons, script authors are likely to favor them overPanelType
sub-panels if they're less hassle to add (may be OK, but something to be aware of).In some cases it will seem strange that UI show-state is shared between all regions - not in the case of modifiers, but if script authors might share this state in situations users wouldn't expect it (toolbar/properties for e.g.).
It would be good if the shown state could be stored automatically without define RNA elsewhere because it adds more boiler plate and may cause unexpected shared state if Python developers are forced to store these values on the Scene or WindowManager (in situations where they can't attach ID properties).
The use of unique RNA properties per sub-panel seems like it could be an issue in the future.
If this was limited to modifiers it's not so bad, but add-ons are going to have to define their own properties in situations that are likely to get messy (script authors might add
bpy.types.WindowManager.show_my_exporter_1
,show_my_exporter_2
... etc) if they wish to use these in a file selector for example... with multiple add-ons I think this is likely to get out of hand, having to define many properties for UI elements.This could be handled by supporting an unique-name, passed to for each sub-panel (
{addon}.{name}
by convention for e.g.), then thePanel
could store this data. A down side of this is the potential for garbage to accumulate, although in practice I don't think it's likely to be a problem and we could support clearing unused ID's if needed.We could consider supporting both (RNA properties and ID's in the
Panel
), although this also feels a bit weak & worth avoiding if possible.Regarding naming, these should be clearly differentiated from
Panel/PanelType
panels. Terms such asanonymous
,pseudo
,collapsible
... could be used.Thanks for the feedback.
I think the term "collapsible" is ok, or just "section". Using "anonymous" or "pseudo" feels wrong to me.
I tried to use string identifiers for the sections now. I agree that it would be nice to store the open-state per region and not in rna properties in the modifier. Unfortunately, I ran into a issue with instanced panels which is that they are constantly being freed and added again whenever something changes. I couldn't find a way to keep the open-state around after adding a new modifier for example. Seems like this will require proper identifiers for instanced panels, which also implies that we'll need identifiers for modifiers, constraints, etc.
This might be good anyway. We rely on the modifier name as identifier in a few places where it would be nice to have a more stable identifier instead.
Quick summary for myself and others:
Currently, whether a modifier (sub)panel is open is stored in the modifier itself. This works okayish, but has the problem that the open-close-status is shared between multiple property editors, which is generally unexpected for panels. Would be good to know if that behavior is ok for you (ideally not just for modifiers, but also constraints, fcurve modifiers, and maybe even all subpanels).
An alternative could be to store the open-close-status in each area/editor independently. This is more similar to most panels. Unfortunately, it requires us to uniquely identify a panel within an editor and it's not entirely clear how that identifier should be build. There are different options for the identifier:
[modifier_name][panel_id]
: Has the problem that the open-close-status is shared between different objects with the same modifiers. Also, it would be lost when the modifier name changes.[modifier_id][panel_id]
: Fixes the problem that renaming the modifier opens/closes panels, but the open-close-status might still be linked between different objects, because modifier ids wouldn't be globally unique (we don't even have them at all yet).[object_name][modifier_id][panel_id]
: Now the open-close-state is not shared between objects anymore, but renaming the object would break things.[object_pointer][modifier_id][panel_id]
: Would not have any of the mentioned issues, but now the identifier can't just be a simple string anymore, which makes things more difficult when we want to expose the functionality to create subpanels to the Python API. More generally, a single ID pointer might not be enough in all cases, but it could be good enough for now.Just to add my input to the conversation:
What I would consider 'correct' behavior is indeed if the collapse state of each panel is separate per editor.
However, I personally don't really see any realistic use-case for two editors with the same context and different panel states. Of course, this might change in the future. Other editors like 3D viewport or outliner have several display or filter options that provide different value despite the context being the same, but for the properties panels, as they really just give an overview over all properties of the context I personally don't see the same benefit.
I'll change this patch as follows:
id pointers + modifier id + panel id
keys in every region is a bit too far away, comes with new problems (huge number of keys in files with many objects in many regions), does not provide a significant benefit for users in practice and is also the existing behavior for modifier panels (so no regression).The goal here is to reduce the scope of this patch so that we can get panels in the geometry nodes modifier in 4.1 which has high priority without getting in the way of opening up this functionality to the API later on.
WIP: UI: uiLayout based subpanelsto UI: add support for uiLayout based panels@blender-bot build
Looks good. There is a change in the look of the bevel modifier which shouldn't happen here though. Looks like some padding issues and a row/column mismatch maybe.
I don't love the way of exposing panel expansion in the modifier RNA, but it's the best option I can think of.
@ -343,0 +345,4 @@
float start_y;
float end_y;
PointerRNA open_owner_ptr;
std::string open_prop_name;
Don't forget
#include <string>
@ -343,0 +354,4 @@
};
/**
* "Layout Panels" are panels which are defined as part of the `uiLayout`. As such they have a
#uiLayout
@ -343,0 +357,4 @@
* "Layout Panels" are panels which are defined as part of the `uiLayout`. As such they have a
* specific place in the layout and can not be freely dragged around like top level panels.
*
* This struct gathers information about the layout panels created by layouting code. This is then
layouting
->layout
(same below)@ -2287,0 +2306,4 @@
uiLayout *uiLayoutPanel(const bContext *C,
uiLayout *layout,
const char *name,
PointerRNA *open_prop_owner,
Pass by const reference? And maybe
StringRef
too? Mostly care about constness thoughNote that making it const is not really correct, because the opening and closing of the panel is also done via the poinyer provided here.
I saw
PointerRNA
more like theSpan
vs.MutableSpan
situation. It's just a view, and to do it properly we'd needMutablePointerRNA
.Well, that's true, but doesn't really change the situation here right now imo.
@ -644,6 +644,10 @@ void ui_but_to_pixelrect(rcti *rect,
const ARegion *region,
const uiBlock *block,
const uiBut *but);
void ui_to_pixelrect(const ARegion *region,
Return
rcti
by value@blender-bot build
There's a slightly larger gap below the last subpanel now. It isn't a big deal, and it's a bit subjective, but ideally this wouldn't change spacing at all.
Maybe it would be best not to change existing modifiers in this commit? It seems a bit arbitrary just to change two of them.
@ -250,0 +255,4 @@
int miter_outer = RNA_enum_get(ptr, "miter_outer");
bool edge_bevel = RNA_enum_get(ptr, "affect") != MOD_BEVEL_AFFECT_VERTICES;
uiItemR(uiLayoutRow(layout, false), ptr, "profile_type", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
This property isn't supposed to have the label displayed to the left, you'll need to disable property split for this row.
@blender-bot build