2023-08-16 00:20:26 +10:00
|
|
|
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
2023-05-31 16:19:06 +02:00
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
2009-03-13 13:38:41 +00:00
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
|
* \ingroup edinterface
|
2011-02-27 20:29:51 +00:00
|
|
|
*/
|
|
|
|
|
|
2024-01-22 15:58:18 +01:00
|
|
|
#include <algorithm>
|
2022-11-25 23:48:02 -06:00
|
|
|
#include <cmath>
|
|
|
|
|
#include <cstdlib>
|
|
|
|
|
#include <cstring>
|
2009-03-13 13:38:41 +00:00
|
|
|
|
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "DNA_screen_types.h"
|
2009-04-27 18:05:58 +00:00
|
|
|
#include "DNA_userdef_types.h"
|
2009-03-13 13:38:41 +00:00
|
|
|
|
2022-11-25 23:48:02 -06:00
|
|
|
#include "BLI_array.hh"
|
2020-09-01 15:23:55 +10:00
|
|
|
#include "BLI_dynstr.h"
|
2009-03-13 13:38:41 +00:00
|
|
|
#include "BLI_listbase.h"
|
2024-01-06 01:47:39 +01:00
|
|
|
#include "BLI_math_base.h"
|
2025-04-10 23:27:21 +00:00
|
|
|
#include "BLI_path_utils.hh"
|
2012-08-21 19:35:06 +00:00
|
|
|
#include "BLI_rect.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BLI_string.h"
|
2024-05-27 18:46:19 +02:00
|
|
|
#include "BLI_string_ref.hh"
|
2011-01-07 18:36:47 +00:00
|
|
|
#include "BLI_utildefines.h"
|
2009-03-13 13:38:41 +00:00
|
|
|
|
2024-02-09 18:59:42 +01:00
|
|
|
#include "BLT_translation.hh"
|
2011-06-15 11:41:15 +00:00
|
|
|
|
2023-11-16 11:41:55 +01:00
|
|
|
#include "BKE_context.hh"
|
2024-02-10 18:25:14 +01:00
|
|
|
#include "BKE_global.hh"
|
2024-03-26 12:57:30 -04:00
|
|
|
#include "BKE_idprop.hh"
|
Add more control over ID renaming behavior.
This commit adds low-level logic in BKE to support three behaviors in
case of name conflict when renaming an ID:
1. Always tweak new name of the renamed ID (never modify the other ID
name).
2. Always set requested name in renamed ID, modifying as needed the
other ID name.
3. Only modify the other ID name if it shares the same root name with the
current renamed ID's name.
It also adds quite some changes to IDTemplate, Outliner code, and
RNA-defined UILayout code, and the lower-level UI button API, to allow
for the new behavior defined in the design (i.e. option three from above list).
When renaming from the UI either 'fails' (falls back to adjusted name) or forces
renaming another ID, an INFO report is displayed.
This commit also fixes several issues in existing code, especially
regarding undo handling in rename operations (which could lead to saving
the wrong name in undo step, and/or over-generating undo steps).
API wise, the bahavior when directly assigning a name to the `ID.name`
property remains unchanged (option one from the list above). But a new
API call `ID.rename` has been added, which offers all three behaviors.
Unittests were added to cover the new implemented behaviors (both at
BKE level, and the RNA/Py API).
This commit implements #119139 design.
Pull Request: https://projects.blender.org/blender/blender/pulls/126996
2024-09-20 13:36:50 +02:00
|
|
|
#include "BKE_lib_id.hh"
|
Templates for render output paths
This adds basic templating support to render output paths. By putting
"{variable_name}" in the path string, it will be replaced by the named
variable's value when generating the actual output path. This is similar
to how "//" is already substituted with the path to the blend file's
current directory.
This templating system is implemented for both the primary render output
path as well as the File Output node in the compositing nodes. Support
for using templates in other places can be implemented in future PRs.
In addition to the "{variable_name}" syntax, some additional syntax is
also supported:
- Since "{" and "}" now have special meaning, "{{" and "}}" are now
escape sequences for literal "{" and "}".
- "{variable_name:format_specifier}", where "format_specifier" is a
special syntax using "#", which allows the user to specify how numeric
variables should be formatted:
- "{variable_name:###}" will format the number as an integer with at
least 3 characters (padding with zeros as needed).
- "{variable_name:.##}" will format the number as a float with
precisely 2 fractional digits.
- "{variable_name:###.##}" will format the number as a float with at
least 3 characters for the integer part and precisely 2 for the
fractional part.
For the primary render output path: if there is a template syntax error,
a variable doesn't exist, or a format specifier isn't valid (e.g. trying
to format a string with "##"), the render that needs to write to the
output path fails with a descriptive error message.
For both the primary and File Output node paths: if there are template
syntax errors the field is highlighted in red in the UI, and a tooltip
describes the offending syntax errors. Note that these do *not* yet
reflect errors due to missing variables. That will be for a follow-up
PR.
In addition to the general system, this PR also implements a limited set
of variables for use in templates, but more can be implemented in future
PRs. The variables added in this PR are:
- `blend_name`: the name of the current blend file without the file
extension.
- `fps`: the frames per second of the current scene.
- `resolution_x` and `resolution_y`: the render output resolution.
Pull Request: https://projects.blender.org/blender/blender/pulls/134860
2025-05-08 15:37:28 +02:00
|
|
|
#include "BKE_path_templates.hh"
|
2023-09-25 17:48:21 -04:00
|
|
|
#include "BKE_screen.hh"
|
2009-03-13 13:38:41 +00:00
|
|
|
|
2023-08-10 22:40:27 +02:00
|
|
|
#include "RNA_access.hh"
|
2024-07-10 18:30:02 +02:00
|
|
|
#include "RNA_prototypes.hh"
|
2009-03-13 13:38:41 +00:00
|
|
|
|
2023-08-05 02:57:52 +02:00
|
|
|
#include "UI_interface.hh"
|
2009-03-13 13:38:41 +00:00
|
|
|
|
Add more control over ID renaming behavior.
This commit adds low-level logic in BKE to support three behaviors in
case of name conflict when renaming an ID:
1. Always tweak new name of the renamed ID (never modify the other ID
name).
2. Always set requested name in renamed ID, modifying as needed the
other ID name.
3. Only modify the other ID name if it shares the same root name with the
current renamed ID's name.
It also adds quite some changes to IDTemplate, Outliner code, and
RNA-defined UILayout code, and the lower-level UI button API, to allow
for the new behavior defined in the design (i.e. option three from above list).
When renaming from the UI either 'fails' (falls back to adjusted name) or forces
renaming another ID, an INFO report is displayed.
This commit also fixes several issues in existing code, especially
regarding undo handling in rename operations (which could lead to saving
the wrong name in undo step, and/or over-generating undo steps).
API wise, the bahavior when directly assigning a name to the `ID.name`
property remains unchanged (option one from the list above). But a new
API call `ID.rename` has been added, which offers all three behaviors.
Unittests were added to cover the new implemented behaviors (both at
BKE level, and the RNA/Py API).
This commit implements #119139 design.
Pull Request: https://projects.blender.org/blender/blender/pulls/126996
2024-09-20 13:36:50 +02:00
|
|
|
#include "ED_id_management.hh"
|
|
|
|
|
|
2023-08-04 23:11:22 +02:00
|
|
|
#include "WM_api.hh"
|
|
|
|
|
#include "WM_types.hh"
|
2009-03-13 13:38:41 +00:00
|
|
|
|
2025-05-19 17:25:52 +02:00
|
|
|
#include "fmt/format.h"
|
2022-11-26 00:21:17 -06:00
|
|
|
#include "interface_intern.hh"
|
2009-04-02 01:39:33 +00:00
|
|
|
|
2024-12-06 14:08:10 +01:00
|
|
|
using blender::StringRef;
|
|
|
|
|
using blender::StringRefNull;
|
|
|
|
|
|
2018-06-16 14:48:21 +02:00
|
|
|
/* Show an icon button after each RNA button to use to quickly set keyframes,
|
2023-02-12 14:37:16 +11:00
|
|
|
* this is a way to display animation/driven/override status, see #54951. */
|
2018-06-16 14:48:21 +02:00
|
|
|
#define UI_PROP_DECORATE
|
2018-06-25 12:06:31 +02:00
|
|
|
/* Alternate draw mode where some buttons can use single icon width,
|
|
|
|
|
* giving more room for the text at the expense of nicely aligned text. */
|
|
|
|
|
#define UI_PROP_SEP_ICON_WIDTH_EXCEPTION
|
2018-06-16 14:48:21 +02:00
|
|
|
|
2019-09-06 16:12:47 +10:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Structs and Defines
|
|
|
|
|
* \{ */
|
2009-03-13 13:38:41 +00:00
|
|
|
|
2012-01-22 19:52:41 +00:00
|
|
|
#define UI_OPERATOR_ERROR_RET(_ot, _opname, return_statement) \
|
2022-11-25 23:48:02 -06:00
|
|
|
if (ot == nullptr) { \
|
2012-01-22 19:52:41 +00:00
|
|
|
ui_item_disabled(layout, _opname); \
|
|
|
|
|
RNA_warning("'%s' unknown operator", _opname); \
|
|
|
|
|
return_statement; \
|
|
|
|
|
} \
|
|
|
|
|
(void)0
|
|
|
|
|
|
UI: Layout changes for new checkbox layout possibilities
Follow-up to previous commit.
Some examples:
{F8473507} {F8473508} {F8473509} {F8473510}
For more screenshots, please see D7430.
We use column or row headings here to bring more structure, and to give
the eye visual anchors which aid eye-scanning. The left-aligned
checkboxes likewise help with this. And we keep the adherence to the
center line, so the alignment matches up between the various buttons and
controls.
* Changes the property split percentage from 50/50% to 40/60%. This is
needed to give enough space for the checkboxes. But in most cases this
looks better anyway - see Transform panel. In some cases it simply
fills out the available space more efficently.
* Fix various hacks where we previously used manually defined splits.
When we did this, the alignment was never quite right, and the layout
code was a mess.
* Adds column headings to many places where a list of checkboxes all
share a common purpose or leading text.
* Add checkbox + value configurations various places where a checkbox
only serves to enable the value slider
* Removes most uses of grid flow layout. The grid flow layouts combine
poorly with column headings, and also they would mess alignment up
badly. The grid flow layouts also often made buttons and controls jump
around on the screen if you would just resize editors slightly,
causing visual confusion, making users lose their place. The logic for
at what time the list of items would re-flow was often flawed, jumping
to multiple columns too fast or too late - and frankly, the grid flow
layouts would often just look bad.
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7430
Reviewed by: Brecht Van Lommel, Pablo Vazquez.
Most work here by William Reynish, few changes by Julian Eisel.
2020-04-17 16:54:03 +02:00
|
|
|
#define UI_ITEM_PROP_SEP_DIVIDE 0.4f
|
2012-01-22 19:52:41 +00:00
|
|
|
|
2009-05-19 17:13:33 +00:00
|
|
|
/* uiLayoutRoot */
|
|
|
|
|
|
2022-11-25 23:48:02 -06:00
|
|
|
struct uiLayoutRoot {
|
|
|
|
|
uiLayoutRoot *next, *prev;
|
2009-03-13 13:38:41 +00:00
|
|
|
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
int type;
|
2021-11-05 14:56:22 +01:00
|
|
|
wmOperatorCallContext opcontext;
|
2009-03-13 13:38:41 +00:00
|
|
|
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
int emw, emh;
|
2014-01-17 00:23:00 +01:00
|
|
|
int padding;
|
2009-03-13 13:38:41 +00:00
|
|
|
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
uiMenuHandleFunc handlefunc;
|
|
|
|
|
void *argv;
|
2009-03-13 13:38:41 +00:00
|
|
|
|
2020-03-15 17:32:25 +11:00
|
|
|
const uiStyle *style;
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
uiBlock *block;
|
2009-05-19 17:13:33 +00:00
|
|
|
uiLayout *layout;
|
2022-11-25 23:48:02 -06:00
|
|
|
};
|
2009-04-22 18:39:44 +00:00
|
|
|
|
2025-03-31 15:30:58 +02:00
|
|
|
namespace blender::ui {
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
/* Item */
|
2009-04-22 18:39:44 +00:00
|
|
|
|
2025-03-31 15:30:58 +02:00
|
|
|
enum class ItemType : int8_t {
|
|
|
|
|
Button,
|
|
|
|
|
|
|
|
|
|
LayoutRow,
|
|
|
|
|
LayoutPanelHeader,
|
|
|
|
|
LayoutPanelBody,
|
|
|
|
|
LayoutColumn,
|
|
|
|
|
LayoutColumnFlow,
|
|
|
|
|
LayoutRowFlow,
|
|
|
|
|
LayoutGridFlow,
|
|
|
|
|
LayoutBox,
|
|
|
|
|
LayoutAbsolute,
|
|
|
|
|
LayoutSplit,
|
|
|
|
|
LayoutOverlap,
|
2025-05-07 23:29:49 +02:00
|
|
|
LayoutRadial, /* AKA: menu pie. */
|
2025-03-31 15:30:58 +02:00
|
|
|
|
|
|
|
|
LayoutRoot,
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
#if 0
|
2025-03-31 15:30:58 +02:00
|
|
|
TemplateColumnFlow,
|
|
|
|
|
TemplateSplit,
|
|
|
|
|
TemplateBox,
|
2009-03-13 13:38:41 +00:00
|
|
|
|
2025-03-31 15:30:58 +02:00
|
|
|
TemplateHeader,
|
|
|
|
|
TemplateHeaderID,
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
#endif
|
2022-11-25 23:48:02 -06:00
|
|
|
};
|
2009-03-13 13:38:41 +00:00
|
|
|
|
2025-03-31 18:23:16 +02:00
|
|
|
enum class ItemInternalFlag : uint8_t {
|
|
|
|
|
AutoFixedSize = 1 << 0,
|
|
|
|
|
FixedSize = 1 << 1,
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-03-31 18:23:16 +02:00
|
|
|
BoxItem = 1 << 2, /* The item is "inside" a box item */
|
|
|
|
|
PropSep = 1 << 3,
|
|
|
|
|
InsidePropSep = 1 << 4,
|
2018-06-16 14:48:21 +02:00
|
|
|
/* Show an icon button next to each property (to set keyframes, show status).
|
2025-03-31 18:23:16 +02:00
|
|
|
* Enabled by default, depends on 'ItemInternalFlag::PropSep'. */
|
|
|
|
|
PropDecorate = 1 << 5,
|
|
|
|
|
PropDecorateNoPad = 1 << 6,
|
2023-07-30 16:14:09 +10:00
|
|
|
};
|
2025-03-31 18:23:16 +02:00
|
|
|
ENUM_OPERATORS(ItemInternalFlag, ItemInternalFlag::PropDecorateNoPad)
|
|
|
|
|
|
|
|
|
|
} // namespace blender::ui
|
2023-07-29 14:47:15 +10:00
|
|
|
|
2025-03-31 15:30:58 +02:00
|
|
|
using uiItemType = blender::ui::ItemType;
|
2025-03-31 18:23:16 +02:00
|
|
|
using uiItemInternalFlag = blender::ui::ItemInternalFlag;
|
2025-03-31 15:30:58 +02:00
|
|
|
|
2024-07-10 14:46:06 +02:00
|
|
|
struct uiButtonItem : uiItem {
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
uiBut *but;
|
2022-11-25 23:48:02 -06:00
|
|
|
};
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
|
2025-04-25 19:45:25 +02:00
|
|
|
struct uiLayoutItemFlow : public uiLayout {
|
2009-04-16 12:17:58 +00:00
|
|
|
int number;
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
int totcol;
|
2022-11-25 23:48:02 -06:00
|
|
|
};
|
2009-04-11 01:52:27 +00:00
|
|
|
|
2025-04-25 19:45:25 +02:00
|
|
|
struct uiLayoutItemGridFlow : public uiLayout {
|
2018-06-09 16:50:05 +02:00
|
|
|
/* Extra parameters */
|
|
|
|
|
bool row_major; /* Fill first row first, instead of filling first column first. */
|
|
|
|
|
bool even_columns; /* Same width for all columns. */
|
|
|
|
|
bool even_rows; /* Same height for all rows. */
|
2019-01-15 23:24:20 +11:00
|
|
|
/**
|
|
|
|
|
* - If positive, absolute fixed number of columns.
|
|
|
|
|
* - If 0, fully automatic (based on available width).
|
|
|
|
|
* - If negative, automatic but only generates number of columns/rows
|
|
|
|
|
* multiple of given (absolute) value.
|
|
|
|
|
*/
|
2018-07-01 09:23:51 +02:00
|
|
|
int columns_len;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-09 16:50:05 +02:00
|
|
|
/* Pure internal runtime storage. */
|
|
|
|
|
int tot_items, tot_columns, tot_rows;
|
2022-11-25 23:48:02 -06:00
|
|
|
};
|
2018-06-09 16:50:05 +02:00
|
|
|
|
2025-04-25 19:45:25 +02:00
|
|
|
struct uiLayoutItemBx : public uiLayout {
|
2009-05-21 15:34:09 +00:00
|
|
|
uiBut *roundbox;
|
2022-11-25 23:48:02 -06:00
|
|
|
};
|
2009-03-13 13:38:41 +00:00
|
|
|
|
2025-04-25 19:45:25 +02:00
|
|
|
struct uiLayoutItemPanelHeader : public uiLayout {
|
UI: add support for uiLayout based panels
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 initial use case for this are panels in the geometry nodes modifier. This patch provides
a better solution compared to what was attempted in #108565.
### Problems with Existing Approaches
Currently, there are two ways to create these expandable sections:
* One can define a new `Panel` type for each expandable section and use the `parent_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.
* It does not work so well for dynamic amounts of panels (e.g. like what we need for
the geometry nodes modifier to organize the inputs).
* Typically, Blender uses a immediate-ui approach, but subpanels break that currently
and need extra handling.
* The order of panels is not very explicit.
* One can't interleave subpanels and other ui elements, subpanels always come at the
end of the parent panel.
* Custom solution using existing `uiLayout`. This is done in the material properties. It
also has a few problems:
* Custom solutions tend to work slightly different in different places. So the UI is less unified.
* Can't drag open/close multiple panels.
* The background color for subpanels does not change.
### Solution
A possible solution to all of these problems is to add support for panels to `uiLayout` directly:
```cpp
/* Add elements before subpanel. */
if (uiLayout *panel_layout = uiLayoutPanel(layout, ...)) {
/* Add elements in subpanel, but only of the panel is open. */
}
/* Add elements after subpanel. */
```
Integrating subpanels with `uiLayout` has some benefits:
* Subpanels are treated like any other sub-layout and don't have unnecessary boilerplate.
* It becomes trivial to have a dynamic number of potentially nested subpanels.
* Resolves all mentioned problems of custom subpanel solutions.
### 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 negligible. Therefor, a much simpler solution
is possible: the open/close state can be stored in the modifier directly. This is actually
how it was implemented before 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 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 (not included)
Adding a Python API is fairly straight forward. 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:
```python
if panel := layout.panel("Mesh Settings", ...):
# Add layout elements in the panel if it's open.
```
Pull Request: https://projects.blender.org/blender/blender/pulls/113584
2023-12-22 17:57:57 +01:00
|
|
|
PointerRNA open_prop_owner;
|
|
|
|
|
char open_prop_name[64];
|
|
|
|
|
};
|
|
|
|
|
|
2025-04-25 19:45:25 +02:00
|
|
|
struct uiLayoutItemPanelBody : public uiLayout {};
|
UI: add support for uiLayout based panels
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 initial use case for this are panels in the geometry nodes modifier. This patch provides
a better solution compared to what was attempted in #108565.
### Problems with Existing Approaches
Currently, there are two ways to create these expandable sections:
* One can define a new `Panel` type for each expandable section and use the `parent_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.
* It does not work so well for dynamic amounts of panels (e.g. like what we need for
the geometry nodes modifier to organize the inputs).
* Typically, Blender uses a immediate-ui approach, but subpanels break that currently
and need extra handling.
* The order of panels is not very explicit.
* One can't interleave subpanels and other ui elements, subpanels always come at the
end of the parent panel.
* Custom solution using existing `uiLayout`. This is done in the material properties. It
also has a few problems:
* Custom solutions tend to work slightly different in different places. So the UI is less unified.
* Can't drag open/close multiple panels.
* The background color for subpanels does not change.
### Solution
A possible solution to all of these problems is to add support for panels to `uiLayout` directly:
```cpp
/* Add elements before subpanel. */
if (uiLayout *panel_layout = uiLayoutPanel(layout, ...)) {
/* Add elements in subpanel, but only of the panel is open. */
}
/* Add elements after subpanel. */
```
Integrating subpanels with `uiLayout` has some benefits:
* Subpanels are treated like any other sub-layout and don't have unnecessary boilerplate.
* It becomes trivial to have a dynamic number of potentially nested subpanels.
* Resolves all mentioned problems of custom subpanel solutions.
### 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 negligible. Therefor, a much simpler solution
is possible: the open/close state can be stored in the modifier directly. This is actually
how it was implemented before 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 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 (not included)
Adding a Python API is fairly straight forward. 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:
```python
if panel := layout.panel("Mesh Settings", ...):
# Add layout elements in the panel if it's open.
```
Pull Request: https://projects.blender.org/blender/blender/pulls/113584
2023-12-22 17:57:57 +01:00
|
|
|
|
2025-04-25 19:45:25 +02:00
|
|
|
struct uiLayoutItemSplit : public uiLayout {
|
2009-06-07 13:20:41 +00:00
|
|
|
float percentage;
|
2022-11-25 23:48:02 -06:00
|
|
|
};
|
2009-06-07 13:20:41 +00:00
|
|
|
|
2025-04-25 19:45:25 +02:00
|
|
|
struct uiLayoutItemRoot : public uiLayout {};
|
2009-03-13 13:38:41 +00:00
|
|
|
|
2019-09-06 16:12:47 +10:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Item
|
|
|
|
|
* \{ */
|
2009-03-13 13:38:41 +00:00
|
|
|
|
2024-12-06 14:08:10 +01:00
|
|
|
static StringRef ui_item_name_add_colon(StringRef name, char namestr[UI_MAX_NAME_STR])
|
|
|
|
|
{
|
|
|
|
|
const int len = name.size();
|
|
|
|
|
|
|
|
|
|
if (len != 0 && len + 1 < UI_MAX_NAME_STR) {
|
|
|
|
|
memcpy(namestr, name.data(), len);
|
|
|
|
|
namestr[len] = ':';
|
|
|
|
|
namestr[len + 1] = '\0';
|
|
|
|
|
return namestr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static StringRefNull ui_item_name_add_colon(StringRefNull name, char namestr[UI_MAX_NAME_STR])
|
2023-10-19 09:24:06 -07:00
|
|
|
{
|
2024-12-06 14:08:10 +01:00
|
|
|
const int len = name.size();
|
2023-10-19 09:24:06 -07:00
|
|
|
|
|
|
|
|
if (len != 0 && len + 1 < UI_MAX_NAME_STR) {
|
2024-12-06 14:08:10 +01:00
|
|
|
memcpy(namestr, name.data(), len);
|
2023-10-19 09:24:06 -07:00
|
|
|
namestr[len] = ':';
|
|
|
|
|
namestr[len + 1] = '\0';
|
|
|
|
|
return namestr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return name;
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-05 12:12:28 -05:00
|
|
|
static int ui_item_fit(const int item,
|
|
|
|
|
const int pos,
|
|
|
|
|
const int all,
|
|
|
|
|
const int available,
|
|
|
|
|
const bool is_last,
|
|
|
|
|
const int alignment,
|
|
|
|
|
float *extra_pixel)
|
2009-03-13 13:38:41 +00:00
|
|
|
{
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
/* available == 0 is unlimited */
|
2017-07-28 10:56:41 +02:00
|
|
|
if (ELEM(0, available, all)) {
|
2009-06-03 00:04:48 +00:00
|
|
|
return item;
|
2017-07-28 10:56:41 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (all > available) {
|
2009-04-16 12:17:58 +00:00
|
|
|
/* contents is bigger than available space */
|
2019-03-25 10:15:20 +11:00
|
|
|
if (is_last) {
|
2012-03-30 01:51:25 +00:00
|
|
|
return available - pos;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2020-07-03 14:20:10 +02:00
|
|
|
|
2022-12-08 13:04:50 +11:00
|
|
|
const float width = *extra_pixel + (item * available) / float(all);
|
|
|
|
|
*extra_pixel = width - int(width);
|
|
|
|
|
return int(width);
|
2009-04-16 12:17:58 +00:00
|
|
|
}
|
2020-07-03 14:20:10 +02:00
|
|
|
|
|
|
|
|
/* contents is smaller or equal to available space */
|
|
|
|
|
if (alignment == UI_LAYOUT_ALIGN_EXPAND) {
|
|
|
|
|
if (is_last) {
|
|
|
|
|
return available - pos;
|
2017-07-28 10:56:41 +02:00
|
|
|
}
|
2020-07-03 14:20:10 +02:00
|
|
|
|
2022-12-08 13:04:50 +11:00
|
|
|
const float width = *extra_pixel + (item * available) / float(all);
|
|
|
|
|
*extra_pixel = width - int(width);
|
|
|
|
|
return int(width);
|
2009-04-16 12:17:58 +00:00
|
|
|
}
|
2020-07-03 14:20:10 +02:00
|
|
|
return item;
|
2009-03-13 13:38:41 +00:00
|
|
|
}
|
|
|
|
|
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
/* variable button size in which direction? */
|
2012-03-30 01:51:25 +00:00
|
|
|
#define UI_ITEM_VARY_X 1
|
|
|
|
|
#define UI_ITEM_VARY_Y 2
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
|
2015-02-13 09:10:53 +01:00
|
|
|
static int ui_layout_vary_direction(uiLayout *layout)
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
return ((ELEM(layout->root_->type, UI_LAYOUT_HEADER, UI_LAYOUT_PIEMENU) ||
|
2025-04-23 14:54:06 +02:00
|
|
|
(layout->alignment_ != UI_LAYOUT_ALIGN_EXPAND)) ?
|
Pie Menus C code backend.
This commit merges the code in the pie-menu branch.
As per decisions taken the last few days, there are no pie menus
included and there will be an official add-on including overrides of
some keys with pie menus. However, people will now be able to use the
new code in python.
Full Documentation is in http://wiki.blender.org/index.php/Dev:Ref/
Thanks:
Campbell Barton, Dalai Felinto and Ton Roosendaal for the code review
and design comments
Jonathan Williamson, Pawel Lyczkowski, Pablo Vazquez among others for
suggestions during the development.
Special Thanks to Sean Olson, for his support, suggestions, testing and
merciless bugging so that I would finish the pie menu code. Without him
we wouldn't be here. Also to the rest of the developers of the original
python add-on, Patrick Moore and Dan Eicher and finally to Matt Ebb, who
did the research and first implementation and whose code I used to get
started.
2014-08-11 10:39:59 +02:00
|
|
|
UI_ITEM_VARY_X :
|
|
|
|
|
UI_ITEM_VARY_Y);
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
}
|
|
|
|
|
|
2018-06-09 16:50:05 +02:00
|
|
|
static bool ui_layout_variable_size(uiLayout *layout)
|
|
|
|
|
{
|
2025-05-22 13:45:02 +10:00
|
|
|
/* Note that this code is probably a bit unreliable, we'd probably want to know whether it's
|
2019-01-15 23:24:20 +11:00
|
|
|
* variable in X and/or Y, etc. But for now it mimics previous one,
|
2019-06-16 13:37:21 +10:00
|
|
|
* with addition of variable flag set for children of grid-flow layouts. */
|
2025-04-23 14:54:06 +02:00
|
|
|
return ui_layout_vary_direction(layout) == UI_ITEM_VARY_X || layout->variable_size_;
|
2018-06-09 16:50:05 +02:00
|
|
|
}
|
|
|
|
|
|
2021-09-28 14:07:59 +10:00
|
|
|
/**
|
|
|
|
|
* Factors to apply to #UI_UNIT_X when calculating button width.
|
|
|
|
|
* This is used when the layout is a varying size, see #ui_layout_variable_size.
|
|
|
|
|
*/
|
|
|
|
|
struct uiTextIconPadFactor {
|
|
|
|
|
float text;
|
|
|
|
|
float icon;
|
2021-09-30 12:41:01 +10:00
|
|
|
float icon_only;
|
2021-09-28 14:07:59 +10:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* This adds over an icons width of padding even when no icon is used,
|
|
|
|
|
* this is done because most buttons need additional space (drop-down chevron for example).
|
|
|
|
|
* menus and labels use much smaller `text` values compared to this default.
|
|
|
|
|
*
|
2024-02-05 12:12:28 -05:00
|
|
|
* \note It may seem odd that the icon only adds 0.25, but taking margins into account it's fine,
|
2021-09-28 14:07:59 +10:00
|
|
|
* except for #ui_text_pad_compact where a bit more margin is required.
|
|
|
|
|
*/
|
2024-02-05 12:12:28 -05:00
|
|
|
constexpr uiTextIconPadFactor ui_text_pad_default = {1.50f, 0.25f, 0.0f};
|
2021-09-28 14:07:59 +10:00
|
|
|
|
|
|
|
|
/** #ui_text_pad_default scaled down. */
|
2024-02-05 12:12:28 -05:00
|
|
|
constexpr uiTextIconPadFactor ui_text_pad_compact = {1.25f, 0.35f, 0.0f};
|
2021-09-28 14:07:59 +10:00
|
|
|
|
|
|
|
|
/** Least amount of padding not to clip the text or icon. */
|
2024-02-05 12:12:28 -05:00
|
|
|
constexpr uiTextIconPadFactor ui_text_pad_none = {0.25f, 1.50f, 0.0f};
|
2021-09-28 14:07:59 +10:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Estimated size of text + icon.
|
|
|
|
|
*/
|
|
|
|
|
static int ui_text_icon_width_ex(uiLayout *layout,
|
2024-12-06 14:08:10 +01:00
|
|
|
const StringRef name,
|
2021-09-28 14:07:59 +10:00
|
|
|
int icon,
|
2024-02-05 12:12:28 -05:00
|
|
|
const uiTextIconPadFactor &pad_factor,
|
2023-09-05 00:58:57 +02:00
|
|
|
const uiFontStyle *fstyle)
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
{
|
2025-04-23 14:54:06 +02:00
|
|
|
const int unit_x = UI_UNIT_X * (layout->scale_[0] ? layout->scale_[0] : 1.0f);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-09-30 12:41:01 +10:00
|
|
|
/* When there is no text, always behave as if this is an icon-only button
|
|
|
|
|
* since it's not useful to return empty space. */
|
2024-12-06 14:08:10 +01:00
|
|
|
if (icon && name.is_empty()) {
|
2024-02-05 12:12:28 -05:00
|
|
|
return unit_x * (1.0f + pad_factor.icon_only);
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-02 13:02:30 -05:00
|
|
|
if (ui_layout_variable_size(layout)) {
|
2024-12-06 14:08:10 +01:00
|
|
|
if (!icon && name.is_empty()) {
|
2024-02-05 12:12:28 -05:00
|
|
|
return unit_x * (1.0f + pad_factor.icon_only);
|
2021-09-30 17:45:09 +10:00
|
|
|
}
|
|
|
|
|
|
2025-04-23 14:54:06 +02:00
|
|
|
if (layout->alignment_ != UI_LAYOUT_ALIGN_EXPAND) {
|
2025-04-24 17:22:28 +02:00
|
|
|
layout->flag_ |= uiItemInternalFlag::FixedSize;
|
2017-08-11 13:18:30 +03:00
|
|
|
}
|
2021-10-26 00:10:18 +11:00
|
|
|
|
2024-02-05 12:12:28 -05:00
|
|
|
float margin = pad_factor.text;
|
2019-05-03 16:15:11 +03:00
|
|
|
if (icon) {
|
2024-02-05 12:12:28 -05:00
|
|
|
margin += pad_factor.icon;
|
2019-05-03 16:15:11 +03:00
|
|
|
}
|
2021-10-26 00:10:18 +11:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
const float aspect = layout->root_->block->aspect;
|
2021-10-26 00:10:18 +11:00
|
|
|
return UI_fontstyle_string_width_with_block_aspect(fstyle, name, aspect) +
|
2023-01-03 11:04:16 +11:00
|
|
|
int(ceilf(unit_x * margin));
|
2014-02-27 15:50:30 +11:00
|
|
|
}
|
2020-07-03 14:20:10 +02:00
|
|
|
return unit_x * 10;
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
}
|
|
|
|
|
|
2024-02-05 12:12:28 -05:00
|
|
|
static int ui_text_icon_width(uiLayout *layout,
|
2024-12-06 14:08:10 +01:00
|
|
|
const StringRef name,
|
2024-02-05 12:12:28 -05:00
|
|
|
const int icon,
|
|
|
|
|
const bool compact)
|
2021-09-28 14:07:59 +10:00
|
|
|
{
|
|
|
|
|
return ui_text_icon_width_ex(
|
2024-02-05 12:12:28 -05:00
|
|
|
layout, name, icon, compact ? ui_text_pad_compact : ui_text_pad_default, UI_FSTYLE_WIDGET);
|
2021-09-28 14:07:59 +10:00
|
|
|
}
|
|
|
|
|
|
2024-07-10 14:46:06 +02:00
|
|
|
static void ui_item_size(const uiItem *item, int *r_w, int *r_h)
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
{
|
2025-04-24 17:22:28 +02:00
|
|
|
if (item->type_ == uiItemType::Button) {
|
2024-07-10 14:46:06 +02:00
|
|
|
const uiButtonItem *bitem = static_cast<const uiButtonItem *>(item);
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
|
2019-03-25 10:15:20 +11:00
|
|
|
if (r_w) {
|
|
|
|
|
*r_w = BLI_rctf_size_x(&bitem->but->rect);
|
|
|
|
|
}
|
|
|
|
|
if (r_h) {
|
|
|
|
|
*r_h = BLI_rctf_size_y(&bitem->but->rect);
|
|
|
|
|
}
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2024-07-10 14:46:06 +02:00
|
|
|
const uiLayout *litem = static_cast<const uiLayout *>(item);
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
|
2019-03-25 10:15:20 +11:00
|
|
|
if (r_w) {
|
2025-04-23 16:37:14 +02:00
|
|
|
*r_w = litem->w_;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
|
|
|
|
if (r_h) {
|
2025-04-23 16:37:14 +02:00
|
|
|
*r_h = litem->h_;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-10 14:46:06 +02:00
|
|
|
static void ui_item_offset(const uiItem *item, int *r_x, int *r_y)
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
{
|
2025-04-24 17:22:28 +02:00
|
|
|
if (item->type_ == uiItemType::Button) {
|
2024-07-10 14:46:06 +02:00
|
|
|
const uiButtonItem *bitem = static_cast<const uiButtonItem *>(item);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-03-25 10:15:20 +11:00
|
|
|
if (r_x) {
|
|
|
|
|
*r_x = bitem->but->rect.xmin;
|
|
|
|
|
}
|
|
|
|
|
if (r_y) {
|
|
|
|
|
*r_y = bitem->but->rect.ymin;
|
|
|
|
|
}
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2019-03-25 10:15:20 +11:00
|
|
|
if (r_x) {
|
|
|
|
|
*r_x = 0;
|
|
|
|
|
}
|
|
|
|
|
if (r_y) {
|
|
|
|
|
*r_y = 0;
|
|
|
|
|
}
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-05 12:12:28 -05:00
|
|
|
static void ui_item_position(uiItem *item, const int x, const int y, const int w, const int h)
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
{
|
2025-04-24 17:22:28 +02:00
|
|
|
if (item->type_ == uiItemType::Button) {
|
2024-07-10 14:46:06 +02:00
|
|
|
uiButtonItem *bitem = static_cast<uiButtonItem *>(item);
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
|
2012-08-18 16:53:46 +00:00
|
|
|
bitem->but->rect.xmin = x;
|
|
|
|
|
bitem->but->rect.ymin = y;
|
|
|
|
|
bitem->but->rect.xmax = x + w;
|
|
|
|
|
bitem->but->rect.ymax = y + h;
|
2018-05-23 10:47:12 +02:00
|
|
|
|
2024-12-09 09:14:44 +11:00
|
|
|
ui_but_update(bitem->but); /* For `strlen`. */
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2024-07-10 14:46:06 +02:00
|
|
|
uiLayout *litem = static_cast<uiLayout *>(item);
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->x_ = x;
|
|
|
|
|
litem->y_ = y + h;
|
|
|
|
|
litem->w_ = w;
|
|
|
|
|
litem->h_ = h;
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-05 12:12:28 -05:00
|
|
|
static void ui_item_move(uiItem *item, const int delta_xmin, const int delta_xmax)
|
2017-02-25 13:18:41 +03:00
|
|
|
{
|
2025-04-24 17:22:28 +02:00
|
|
|
if (item->type_ == uiItemType::Button) {
|
2024-07-10 14:46:06 +02:00
|
|
|
uiButtonItem *bitem = static_cast<uiButtonItem *>(item);
|
2017-02-25 13:18:41 +03:00
|
|
|
|
|
|
|
|
bitem->but->rect.xmin += delta_xmin;
|
|
|
|
|
bitem->but->rect.xmax += delta_xmax;
|
2018-05-23 10:47:12 +02:00
|
|
|
|
2024-12-09 09:14:44 +11:00
|
|
|
ui_but_update(bitem->but); /* For `strlen`. */
|
2017-02-25 13:18:41 +03:00
|
|
|
}
|
|
|
|
|
else {
|
2024-07-10 14:46:06 +02:00
|
|
|
uiLayout *litem = static_cast<uiLayout *>(item);
|
2017-02-25 13:18:41 +03:00
|
|
|
|
2019-03-25 10:15:20 +11:00
|
|
|
if (delta_xmin > 0) {
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->x_ += delta_xmin;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
|
|
|
|
else {
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->w_ += delta_xmax;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2017-02-25 13:18:41 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-06 16:12:47 +10:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Special RNA Items
|
|
|
|
|
* \{ */
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
|
2018-12-20 11:59:31 +11:00
|
|
|
int uiLayoutGetLocalDir(const uiLayout *layout)
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
{
|
2025-04-24 17:22:28 +02:00
|
|
|
switch (layout->type_) {
|
2025-03-31 15:30:58 +02:00
|
|
|
case uiItemType::LayoutRow:
|
|
|
|
|
case uiItemType::LayoutRoot:
|
|
|
|
|
case uiItemType::LayoutOverlap:
|
|
|
|
|
case uiItemType::LayoutPanelHeader:
|
2025-05-14 16:24:51 +02:00
|
|
|
case uiItemType::LayoutGridFlow:
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
return UI_LAYOUT_HORIZONTAL;
|
2025-03-31 15:30:58 +02:00
|
|
|
case uiItemType::LayoutColumn:
|
|
|
|
|
case uiItemType::LayoutColumnFlow:
|
|
|
|
|
case uiItemType::LayoutSplit:
|
|
|
|
|
case uiItemType::LayoutAbsolute:
|
|
|
|
|
case uiItemType::LayoutBox:
|
|
|
|
|
case uiItemType::LayoutPanelBody:
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
default:
|
|
|
|
|
return UI_LAYOUT_VERTICAL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-01 15:47:09 +02:00
|
|
|
static uiLayout *ui_item_local_sublayout(uiLayout *test, uiLayout *layout, bool align)
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
{
|
|
|
|
|
uiLayout *sub;
|
2019-03-25 10:15:20 +11:00
|
|
|
if (uiLayoutGetLocalDir(test) == UI_LAYOUT_HORIZONTAL) {
|
2025-04-25 19:45:25 +02:00
|
|
|
sub = &layout->row(align);
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
|
|
|
|
else {
|
2025-04-26 21:07:34 +02:00
|
|
|
sub = &layout->column(align);
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2018-05-23 10:47:12 +02:00
|
|
|
|
2025-04-23 14:54:06 +02:00
|
|
|
sub->space_ = 0;
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
return sub;
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-09 17:39:19 +00:00
|
|
|
static void ui_layer_but_cb(bContext *C, void *arg_but, void *arg_index)
|
|
|
|
|
{
|
2012-03-30 01:51:25 +00:00
|
|
|
wmWindow *win = CTX_wm_window(C);
|
2022-11-25 23:48:02 -06:00
|
|
|
uiBut *but = static_cast<uiBut *>(arg_but);
|
2012-03-30 01:51:25 +00:00
|
|
|
PointerRNA *ptr = &but->rnapoin;
|
|
|
|
|
PropertyRNA *prop = but->rnaprop;
|
2021-01-04 17:02:13 +11:00
|
|
|
const int index = POINTER_AS_INT(arg_index);
|
2022-02-24 22:48:34 +11:00
|
|
|
const bool shift = win->eventstate->modifier & KM_SHIFT;
|
2020-08-26 10:11:13 +10:00
|
|
|
const int len = RNA_property_array_length(ptr, prop);
|
2009-09-09 17:39:19 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!shift) {
|
2025-02-16 18:39:35 +11:00
|
|
|
BLI_assert(index < len);
|
|
|
|
|
blender::Array<bool, RNA_STACK_ARRAY> value_array(len);
|
|
|
|
|
value_array.fill(false);
|
|
|
|
|
value_array[index] = true;
|
2009-09-09 17:39:19 +00:00
|
|
|
|
2025-02-16 18:39:35 +11:00
|
|
|
RNA_property_boolean_set_array(ptr, prop, value_array.data());
|
2009-09-09 17:39:19 +00:00
|
|
|
|
|
|
|
|
RNA_property_update(C, ptr, prop);
|
|
|
|
|
|
2025-02-14 15:29:26 +01:00
|
|
|
for (const std::unique_ptr<uiBut> &cbut : but->block->buttons) {
|
|
|
|
|
ui_but_update(cbut.get());
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2009-09-09 17:39:19 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-13 13:38:41 +00:00
|
|
|
/* create buttons for an item with an RNA array */
|
2015-05-05 03:13:47 +10:00
|
|
|
static void ui_item_array(uiLayout *layout,
|
|
|
|
|
uiBlock *block,
|
2025-05-19 17:25:52 +02:00
|
|
|
const StringRef name,
|
2015-05-05 03:13:47 +10:00
|
|
|
int icon,
|
|
|
|
|
PointerRNA *ptr,
|
|
|
|
|
PropertyRNA *prop,
|
2024-02-05 12:12:28 -05:00
|
|
|
const int len,
|
2015-05-05 03:13:47 +10:00
|
|
|
int x,
|
2024-02-05 12:12:28 -05:00
|
|
|
const int y,
|
2015-05-05 03:13:47 +10:00
|
|
|
int w,
|
2024-02-05 12:12:28 -05:00
|
|
|
const int /*h*/,
|
|
|
|
|
const bool expand,
|
|
|
|
|
const bool slider,
|
|
|
|
|
const int toggle,
|
|
|
|
|
const bool icon_only,
|
|
|
|
|
const bool compact,
|
|
|
|
|
const bool show_text)
|
2009-03-13 13:38:41 +00:00
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
const uiStyle *style = layout->root_->style;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-03-13 13:38:41 +00:00
|
|
|
/* retrieve type and subtype */
|
2020-10-02 13:02:30 -05:00
|
|
|
const PropertyType type = RNA_property_type(prop);
|
|
|
|
|
const PropertySubType subtype = RNA_property_subtype(prop);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-12-29 12:01:32 -05:00
|
|
|
uiLayout *sub = ui_item_local_sublayout(layout, layout, true);
|
2014-11-09 21:20:40 +01:00
|
|
|
UI_block_layout_set_current(block, sub);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-03-13 13:38:41 +00:00
|
|
|
/* create label */
|
2024-12-06 14:08:10 +01:00
|
|
|
if (!name.is_empty() && show_text) {
|
2024-03-01 14:26:45 -05:00
|
|
|
uiDefBut(block, UI_BTYPE_LABEL, 0, name, 0, 0, w, UI_UNIT_Y, nullptr, 0.0, 0.0, "");
|
2018-05-28 16:40:27 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-03-13 13:38:41 +00:00
|
|
|
/* create buttons */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (type == PROP_BOOLEAN && ELEM(subtype, PROP_LAYER, PROP_LAYER_MEMBER)) {
|
2009-03-13 13:38:41 +00:00
|
|
|
/* special check for layer layout */
|
2020-08-26 10:11:13 +10:00
|
|
|
const int cols = (len >= 20) ? 2 : 1;
|
2020-10-02 13:02:30 -05:00
|
|
|
const int colbuts = len / (2 * cols);
|
2019-01-04 11:05:53 +11:00
|
|
|
uint layer_used = 0;
|
|
|
|
|
uint layer_active = 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-05-07 17:03:15 +02:00
|
|
|
UI_block_layout_set_current(block, &layout->absolute(false));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-02 13:02:30 -05:00
|
|
|
const int butw = UI_UNIT_X * 0.75;
|
|
|
|
|
const int buth = UI_UNIT_X * 0.75;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-02 13:02:30 -05:00
|
|
|
for (int b = 0; b < cols; b++) {
|
2014-11-09 21:20:40 +01:00
|
|
|
UI_block_align_begin(block);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-02 13:02:30 -05:00
|
|
|
for (int a = 0; a < colbuts; a++) {
|
2014-05-01 05:57:01 +10:00
|
|
|
const int layer_num = a + b * colbuts;
|
2019-01-04 11:05:53 +11:00
|
|
|
const uint layer_flag = (1u << layer_num);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-11-18 16:06:31 +13:00
|
|
|
if (layer_used & layer_flag) {
|
2019-03-25 10:15:20 +11:00
|
|
|
if (layer_active & layer_flag) {
|
2013-11-18 16:06:31 +13:00
|
|
|
icon = ICON_LAYER_ACTIVE;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
|
|
|
|
else {
|
2013-11-18 16:06:31 +13:00
|
|
|
icon = ICON_LAYER_USED;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2013-11-18 16:06:31 +13:00
|
|
|
else {
|
|
|
|
|
icon = ICON_BLANK1;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-02 13:02:30 -05:00
|
|
|
uiBut *but = uiDefAutoButR(
|
2013-11-18 15:53:46 +13:00
|
|
|
block, ptr, prop, layer_num, "", icon, x + butw * a, y + buth, butw, buth);
|
2019-03-25 10:15:20 +11:00
|
|
|
if (subtype == PROP_LAYER_MEMBER) {
|
2018-09-19 12:05:58 +10:00
|
|
|
UI_but_func_set(but, ui_layer_but_cb, but, POINTER_FROM_INT(layer_num));
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2009-09-09 17:39:19 +00:00
|
|
|
}
|
2020-10-02 13:02:30 -05:00
|
|
|
for (int a = 0; a < colbuts; a++) {
|
2014-05-01 05:57:01 +10:00
|
|
|
const int layer_num = a + len / 2 + b * colbuts;
|
2019-01-04 11:05:53 +11:00
|
|
|
const uint layer_flag = (1u << layer_num);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-11-18 16:06:31 +13:00
|
|
|
if (layer_used & layer_flag) {
|
2019-03-25 10:15:20 +11:00
|
|
|
if (layer_active & layer_flag) {
|
2013-11-18 16:06:31 +13:00
|
|
|
icon = ICON_LAYER_ACTIVE;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
|
|
|
|
else {
|
2013-11-18 16:06:31 +13:00
|
|
|
icon = ICON_LAYER_USED;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2013-11-18 16:06:31 +13:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
icon = ICON_BLANK1;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-02 13:02:30 -05:00
|
|
|
uiBut *but = uiDefAutoButR(
|
|
|
|
|
block, ptr, prop, layer_num, "", icon, x + butw * a, y, butw, buth);
|
2019-03-25 10:15:20 +11:00
|
|
|
if (subtype == PROP_LAYER_MEMBER) {
|
2018-09-19 12:05:58 +10:00
|
|
|
UI_but_func_set(but, ui_layer_but_cb, but, POINTER_FROM_INT(layer_num));
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2014-11-09 21:20:40 +01:00
|
|
|
UI_block_align_end(block);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-30 01:51:25 +00:00
|
|
|
x += colbuts * butw + style->buttonspacex;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2009-09-09 17:39:19 +00:00
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
else if (subtype == PROP_MATRIX) {
|
2025-05-22 23:52:41 +10:00
|
|
|
int totdim, dim_size[/*RNA_MAX_ARRAY_DIMENSION*/ 3];
|
2009-03-13 13:38:41 +00:00
|
|
|
int row, col;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-05-07 17:03:15 +02:00
|
|
|
UI_block_layout_set_current(block, &layout->absolute(true));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-30 01:51:25 +00:00
|
|
|
totdim = RNA_property_array_dimension(ptr, prop, dim_size);
|
2019-03-25 10:15:20 +11:00
|
|
|
if (totdim != 2) {
|
|
|
|
|
/* Only 2D matrices supported in UI so far. */
|
|
|
|
|
return;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2010-01-06 01:41:00 +00:00
|
|
|
w /= dim_size[0];
|
2023-09-25 16:56:17 +10:00
|
|
|
// h /= dim_size[1]; /* UNUSED */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-02 13:02:30 -05:00
|
|
|
for (int a = 0; a < len; a++) {
|
2012-03-30 01:51:25 +00:00
|
|
|
col = a % dim_size[0];
|
|
|
|
|
row = a / dim_size[0];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-02 13:02:30 -05:00
|
|
|
uiBut *but = uiDefAutoButR(block,
|
|
|
|
|
ptr,
|
|
|
|
|
prop,
|
|
|
|
|
a,
|
|
|
|
|
"",
|
|
|
|
|
ICON_NONE,
|
|
|
|
|
x + w * col,
|
|
|
|
|
y + (dim_size[1] * UI_UNIT_Y) - (row * UI_UNIT_Y),
|
|
|
|
|
w,
|
|
|
|
|
UI_UNIT_Y);
|
2019-03-25 10:15:20 +11:00
|
|
|
if (slider && but->type == UI_BTYPE_NUM) {
|
2020-09-04 21:18:45 +02:00
|
|
|
uiButNumber *number_but = (uiButNumber *)but;
|
2024-02-01 12:42:25 -05:00
|
|
|
const float step_size = number_but->step_size;
|
2024-02-05 12:16:14 -05:00
|
|
|
const float precision = number_but->precision;
|
2020-09-10 15:28:55 +02:00
|
|
|
but = ui_but_change_type(but, UI_BTYPE_NUM_SLIDER);
|
2024-02-01 12:42:25 -05:00
|
|
|
uiButNumberSlider *slider_but = reinterpret_cast<uiButNumberSlider *>(but);
|
|
|
|
|
slider_but->step_size = step_size;
|
2024-02-05 12:16:14 -05:00
|
|
|
slider_but->precision = precision;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2012-11-17 16:11:02 +00:00
|
|
|
else if (subtype == PROP_DIRECTION && !expand) {
|
2014-11-15 18:18:47 +01:00
|
|
|
uiDefButR_prop(block,
|
|
|
|
|
UI_BTYPE_UNITVEC,
|
|
|
|
|
0,
|
|
|
|
|
name,
|
|
|
|
|
x,
|
|
|
|
|
y,
|
|
|
|
|
UI_UNIT_X * 3,
|
|
|
|
|
UI_UNIT_Y * 3,
|
|
|
|
|
ptr,
|
|
|
|
|
prop,
|
|
|
|
|
-1,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
2025-02-14 15:12:48 -05:00
|
|
|
std::nullopt);
|
2011-05-19 11:18:09 +00:00
|
|
|
}
|
RNA: subtypes and units
* Reviewed subtypes, making them more specific and adding new ones.
* Subtypes now have an associated type of units (length, area, volume,
mass, rotation, time, velocity, acceleration). These are not used
yet anywhere.
* Centralized code that decides the name of array items based on
subtype (XYZ, RGB), was copied in 3 places.
* RNA_def_float etc functions still need to be update, will do this
later together with another change.
2009-08-10 21:31:05 +00:00
|
|
|
else {
|
2021-07-03 23:08:40 +10:00
|
|
|
/* NOTE: this block of code is a bit arbitrary and has just been made
|
2011-08-14 11:38:17 +00:00
|
|
|
* to work with common cases, but may need to be re-worked */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-08-14 11:38:17 +00:00
|
|
|
/* special case, boolean array in a menu, this could be used in a more generic way too */
|
2019-08-13 19:45:20 +03:00
|
|
|
if (ELEM(subtype, PROP_COLOR, PROP_COLOR_GAMMA) && !expand && ELEM(len, 3, 4)) {
|
2011-02-27 18:03:19 +00:00
|
|
|
uiDefAutoButR(block, ptr, prop, -1, "", ICON_NONE, 0, 0, w, UI_UNIT_Y);
|
2011-08-14 11:38:17 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2020-12-11 09:37:29 +01:00
|
|
|
/* Even if 'expand' is false, we expand anyway. */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-09-16 18:13:19 +10:00
|
|
|
/* Layout for known array sub-types. */
|
2012-03-30 01:51:25 +00:00
|
|
|
char str[3] = {'\0'};
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-28 16:40:27 +02:00
|
|
|
if (!icon_only && show_text) {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (type != PROP_BOOLEAN) {
|
2012-03-30 01:51:25 +00:00
|
|
|
str[1] = ':';
|
2011-08-14 11:38:17 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2021-07-05 12:47:46 +10:00
|
|
|
/* Show check-boxes for rna on a non-emboss block (menu for eg). */
|
2022-11-25 23:48:02 -06:00
|
|
|
bool *boolarr = nullptr;
|
2025-04-23 16:37:14 +02:00
|
|
|
if (type == PROP_BOOLEAN && ELEM(layout->root_->block->emboss,
|
2025-03-31 00:36:46 +02:00
|
|
|
blender::ui::EmbossType::None,
|
|
|
|
|
blender::ui::EmbossType::Pulldown))
|
2024-01-02 18:12:54 +01:00
|
|
|
{
|
2025-04-12 17:17:24 +02:00
|
|
|
boolarr = MEM_calloc_arrayN<bool>(len, __func__);
|
2011-08-14 11:38:17 +00:00
|
|
|
RNA_property_boolean_get_array(ptr, prop, boolarr);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-28 16:40:27 +02:00
|
|
|
const char *str_buf = show_text ? str : "";
|
2020-10-02 13:02:30 -05:00
|
|
|
for (int a = 0; a < len; a++) {
|
2018-05-28 16:40:27 +02:00
|
|
|
if (!icon_only && show_text) {
|
UI: New Global Top-Bar (WIP)
== Main Features/Changes for Users
* Add horizontal bar at top of all non-temp windows, consisting out of two horizontal sub-bars.
* Upper sub-bar contains global menus (File, Render, etc.), tabs for workspaces and scene selector.
* Lower sub-bar contains object mode selector, screen-layout and render-layer selector. Later operator and/or tool settings will be placed here.
* Individual sections of the topbar are individually scrollable.
* Workspace tabs can be double- or ctrl-clicked for renaming and contain 'x' icon for deleting.
* Top-bar should scale nicely with DPI.
* The lower half of the top-bar can be hided by dragging the lower top-bar edge up. Better hiding options are planned (e.g. hide in fullscreen modes).
* Info editors at the top of the window and using the full window width with be replaced by the top-bar.
* In fullscreen modes, no more info editor is added on top, the top-bar replaces it.
== Technical Features/Changes
* Adds initial support for global areas
A global area is part of the window, not part of the regular screen-layout.
I've added a macro iterator to iterate over both, global and screen-layout level areas. When iterating over areas, from now on developers should always consider if they have to include global areas.
* Adds a TOPBAR editor type
The editor type is hidden in the UI editor type menu.
* Adds a variation of the ID template to display IDs as tab buttons (template_ID_tabs in BPY)
* Does various changes to RNA button creation code to improve their appearance in the horizontal top-bar.
* Adds support for dynamically sized regions. That is, regions that scale automatically to the layout bounds.
The code for this is currently a big hack (it's based on drawing the UI multiple times). This should definitely be improved.
* Adds a template for displaying operator properties optimized for the top-bar. This will probably change a lot still and is in fact disabled in code.
Since the final top-bar design depends a lot on other 2.8 designs (mainly tool-system and workspaces), we decided to not show the operator or tool settings in the top-bar for now. That means most of the lower sub-bar is empty for the time being.
NOTE: Top-bar or global area data is not written to files or SDNA. They are simply added to the window when opening Blender or reading a file. This allows us doing changes to the top-bar without having to care for compatibility.
== ToDo's
It's a bit hard to predict all the ToDo's here are the known main ones:
* Add options for the new active-tool system and for operator redo to the topbar.
* Automatically hide the top-bar in fullscreen modes.
* General visual polish.
* Top-bar drag & drop support (WIP in temp-tab_drag_drop).
* Improve dynamic regions (should also fix some layout glitches).
* Make internal terminology consistent.
* Enable topbar file writing once design is more advanced.
* Address TODO's and XXX's in code :)
Thanks @brecht for the review! And @sergey for the complaining ;)
Differential Revision: D2758
2018-04-20 17:14:03 +02:00
|
|
|
str[0] = RNA_property_array_item_char(prop, a);
|
|
|
|
|
}
|
|
|
|
|
if (boolarr) {
|
|
|
|
|
icon = boolarr[a] ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-02 13:02:30 -05:00
|
|
|
const int width_item = ((compact && type == PROP_BOOLEAN) ?
|
|
|
|
|
min_ii(w, ui_text_icon_width(layout, str_buf, icon, false)) :
|
|
|
|
|
w);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-02 13:02:30 -05:00
|
|
|
uiBut *but = uiDefAutoButR(
|
|
|
|
|
block, ptr, prop, a, str_buf, icon, 0, 0, width_item, UI_UNIT_Y);
|
2019-03-25 10:15:20 +11:00
|
|
|
if (slider && but->type == UI_BTYPE_NUM) {
|
2020-09-04 21:18:45 +02:00
|
|
|
uiButNumber *number_but = (uiButNumber *)but;
|
2024-02-01 12:42:25 -05:00
|
|
|
const float step_size = number_but->step_size;
|
2024-02-05 12:16:14 -05:00
|
|
|
const float precision = number_but->precision;
|
2020-09-10 15:28:55 +02:00
|
|
|
but = ui_but_change_type(but, UI_BTYPE_NUM_SLIDER);
|
2024-02-01 12:42:25 -05:00
|
|
|
uiButNumberSlider *slider_but = reinterpret_cast<uiButNumberSlider *>(but);
|
|
|
|
|
slider_but->step_size = step_size;
|
2024-02-05 12:16:14 -05:00
|
|
|
slider_but->precision = precision;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2019-05-21 14:39:09 +10:00
|
|
|
if ((toggle == 1) && but->type == UI_BTYPE_CHECKBOX) {
|
2014-11-09 21:20:40 +01:00
|
|
|
but->type = UI_BTYPE_TOGGLE;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
|
|
|
|
if ((a == 0) && (subtype == PROP_AXISANGLE)) {
|
2014-11-09 21:20:40 +01:00
|
|
|
UI_but_unit_type_set(but, PROP_UNIT_ROTATION);
|
2009-03-25 20:49:15 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (boolarr) {
|
2011-08-14 11:38:17 +00:00
|
|
|
MEM_freeN(boolarr);
|
2009-03-13 13:38:41 +00:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2014-11-09 21:20:40 +01:00
|
|
|
UI_block_layout_set_current(block, layout);
|
2009-03-13 13:38:41 +00:00
|
|
|
}
|
|
|
|
|
|
Fix for [#35224] Transform Orientation - order inconsistency
Fix turned out to remove as much "manual UI" from 3D view header as possible. Mode selector and all transform manipulators/orientations stuff are now RNA-based UI (leaving basically only edit mesh select modes with custom handlers, as they have some quite specific features).
To achieve this, four main modifications were done:
* enum-operator-generated menus are now MENU (i.e. dropdown lists) in headers too.
* All bit-flag enums expanded in ROW buttons now have a handling consistent with e.g. layers, or what we already have for transform manipulators, i.e. clicking select only one element, shift-click to select multiple ones.
* Consequently, the three RNA booleans manipulators flags are merged into a single bit-flag enum (yes, this is also an API change, though I doubt many scripts use it).
* Now the width of enum-based dropdown lists is computed from longest item name in enum, no more from a dummy place holder string (when no label/name is given).
All this allows to remove some code from 3DView/transform areas, that was actually mostly duplicating RNA/operator one.
Also done a few optimizations here and there (among others, do not pass &numitems to RNA_property_enum_items() when you do not need it, saves at least an iteration over enum items to count them).
Many thanks to Brecht for the reviews!
2013-05-12 13:16:11 +00:00
|
|
|
static void ui_item_enum_expand_handle(bContext *C, void *arg1, void *arg2)
|
|
|
|
|
{
|
|
|
|
|
wmWindow *win = CTX_wm_window(C);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-02-24 22:48:34 +11:00
|
|
|
if ((win->eventstate->modifier & KM_SHIFT) == 0) {
|
Fix for [#35224] Transform Orientation - order inconsistency
Fix turned out to remove as much "manual UI" from 3D view header as possible. Mode selector and all transform manipulators/orientations stuff are now RNA-based UI (leaving basically only edit mesh select modes with custom handlers, as they have some quite specific features).
To achieve this, four main modifications were done:
* enum-operator-generated menus are now MENU (i.e. dropdown lists) in headers too.
* All bit-flag enums expanded in ROW buttons now have a handling consistent with e.g. layers, or what we already have for transform manipulators, i.e. clicking select only one element, shift-click to select multiple ones.
* Consequently, the three RNA booleans manipulators flags are merged into a single bit-flag enum (yes, this is also an API change, though I doubt many scripts use it).
* Now the width of enum-based dropdown lists is computed from longest item name in enum, no more from a dummy place holder string (when no label/name is given).
All this allows to remove some code from 3DView/transform areas, that was actually mostly duplicating RNA/operator one.
Also done a few optimizations here and there (among others, do not pass &numitems to RNA_property_enum_items() when you do not need it, saves at least an iteration over enum items to count them).
Many thanks to Brecht for the reviews!
2013-05-12 13:16:11 +00:00
|
|
|
uiBut *but = (uiBut *)arg1;
|
2020-08-26 10:11:13 +10:00
|
|
|
const int enum_value = POINTER_AS_INT(arg2);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Fix for [#35224] Transform Orientation - order inconsistency
Fix turned out to remove as much "manual UI" from 3D view header as possible. Mode selector and all transform manipulators/orientations stuff are now RNA-based UI (leaving basically only edit mesh select modes with custom handlers, as they have some quite specific features).
To achieve this, four main modifications were done:
* enum-operator-generated menus are now MENU (i.e. dropdown lists) in headers too.
* All bit-flag enums expanded in ROW buttons now have a handling consistent with e.g. layers, or what we already have for transform manipulators, i.e. clicking select only one element, shift-click to select multiple ones.
* Consequently, the three RNA booleans manipulators flags are merged into a single bit-flag enum (yes, this is also an API change, though I doubt many scripts use it).
* Now the width of enum-based dropdown lists is computed from longest item name in enum, no more from a dummy place holder string (when no label/name is given).
All this allows to remove some code from 3DView/transform areas, that was actually mostly duplicating RNA/operator one.
Also done a few optimizations here and there (among others, do not pass &numitems to RNA_property_enum_items() when you do not need it, saves at least an iteration over enum items to count them).
Many thanks to Brecht for the reviews!
2013-05-12 13:16:11 +00:00
|
|
|
int current_value = RNA_property_enum_get(&but->rnapoin, but->rnaprop);
|
|
|
|
|
if (!(current_value & enum_value)) {
|
|
|
|
|
current_value = enum_value;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
current_value &= enum_value;
|
|
|
|
|
}
|
|
|
|
|
RNA_property_enum_set(&but->rnapoin, but->rnaprop, current_value);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
Fix for [#35224] Transform Orientation - order inconsistency
Fix turned out to remove as much "manual UI" from 3D view header as possible. Mode selector and all transform manipulators/orientations stuff are now RNA-based UI (leaving basically only edit mesh select modes with custom handlers, as they have some quite specific features).
To achieve this, four main modifications were done:
* enum-operator-generated menus are now MENU (i.e. dropdown lists) in headers too.
* All bit-flag enums expanded in ROW buttons now have a handling consistent with e.g. layers, or what we already have for transform manipulators, i.e. clicking select only one element, shift-click to select multiple ones.
* Consequently, the three RNA booleans manipulators flags are merged into a single bit-flag enum (yes, this is also an API change, though I doubt many scripts use it).
* Now the width of enum-based dropdown lists is computed from longest item name in enum, no more from a dummy place holder string (when no label/name is given).
All this allows to remove some code from 3DView/transform areas, that was actually mostly duplicating RNA/operator one.
Also done a few optimizations here and there (among others, do not pass &numitems to RNA_property_enum_items() when you do not need it, saves at least an iteration over enum items to count them).
Many thanks to Brecht for the reviews!
2013-05-12 13:16:11 +00:00
|
|
|
}
|
2019-04-17 15:02:30 +02:00
|
|
|
|
2019-04-18 13:59:59 +02:00
|
|
|
/**
|
|
|
|
|
* Draw a single enum button, a utility for #ui_item_enum_expand_exec
|
|
|
|
|
*/
|
2019-04-17 15:02:30 +02:00
|
|
|
static void ui_item_enum_expand_elem_exec(uiLayout *layout,
|
|
|
|
|
uiBlock *block,
|
|
|
|
|
PointerRNA *ptr,
|
|
|
|
|
PropertyRNA *prop,
|
2024-12-06 14:08:10 +01:00
|
|
|
const std::optional<StringRef> uiname,
|
2019-04-18 13:59:59 +02:00
|
|
|
const int h,
|
|
|
|
|
const eButType but_type,
|
|
|
|
|
const bool icon_only,
|
2019-04-17 15:02:30 +02:00
|
|
|
const EnumPropertyItem *item,
|
2019-04-18 13:59:59 +02:00
|
|
|
const bool is_first)
|
2019-04-17 15:02:30 +02:00
|
|
|
{
|
2024-12-06 14:08:10 +01:00
|
|
|
const char *name = (!uiname || !uiname->is_empty()) ? item->name : "";
|
2019-04-18 13:59:59 +02:00
|
|
|
const int icon = item->icon;
|
|
|
|
|
const int value = item->value;
|
2022-12-29 12:01:32 -05:00
|
|
|
const int itemw = ui_text_icon_width(block->curlayout, icon_only ? "" : name, icon, false);
|
2019-04-17 15:02:30 +02:00
|
|
|
|
2019-04-18 13:59:59 +02:00
|
|
|
uiBut *but;
|
2019-04-17 15:02:30 +02:00
|
|
|
if (icon && name[0] && !icon_only) {
|
|
|
|
|
but = uiDefIconTextButR_prop(
|
2025-02-14 15:12:48 -05:00
|
|
|
block, but_type, 0, icon, name, 0, 0, itemw, h, ptr, prop, -1, 0, value, std::nullopt);
|
2019-04-17 15:02:30 +02:00
|
|
|
}
|
|
|
|
|
else if (icon) {
|
2019-04-18 13:59:59 +02:00
|
|
|
const int w = (is_first) ? itemw : ceilf(itemw - U.pixelsize);
|
|
|
|
|
but = uiDefIconButR_prop(
|
2025-02-14 15:12:48 -05:00
|
|
|
block, but_type, 0, icon, 0, 0, w, h, ptr, prop, -1, 0, value, std::nullopt);
|
2019-04-17 15:02:30 +02:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
but = uiDefButR_prop(
|
2025-02-14 15:12:48 -05:00
|
|
|
block, but_type, 0, name, 0, 0, itemw, h, ptr, prop, -1, 0, value, std::nullopt);
|
2019-04-17 15:02:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (RNA_property_flag(prop) & PROP_ENUM_FLAG) {
|
2023-05-24 11:21:18 +10:00
|
|
|
/* If this is set, assert since we're clobbering someone else's callback. */
|
2019-05-11 15:35:48 +02:00
|
|
|
/* Buttons get their block's func by default, so we cannot assert in that case either. */
|
2022-11-25 23:48:02 -06:00
|
|
|
BLI_assert(ELEM(but->func, nullptr, block->func));
|
2019-04-17 15:02:30 +02:00
|
|
|
UI_but_func_set(but, ui_item_enum_expand_handle, but, POINTER_FROM_INT(value));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (uiLayoutGetLocalDir(layout) != UI_LAYOUT_HORIZONTAL) {
|
|
|
|
|
but->drawflag |= UI_BUT_TEXT_LEFT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Allow quick, inaccurate swipe motions to switch tabs
|
2019-04-18 13:59:59 +02:00
|
|
|
* (no need to keep cursor over them). */
|
2019-04-17 15:02:30 +02:00
|
|
|
if (but_type == UI_BTYPE_TAB) {
|
|
|
|
|
but->flag |= UI_BUT_DRAG_LOCK;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-29 21:20:58 +01:00
|
|
|
static void ui_item_enum_expand_exec(uiLayout *layout,
|
2015-05-05 03:13:47 +10:00
|
|
|
uiBlock *block,
|
|
|
|
|
PointerRNA *ptr,
|
|
|
|
|
PropertyRNA *prop,
|
2024-12-06 14:08:10 +01:00
|
|
|
const std::optional<StringRef> uiname,
|
2019-04-18 13:59:59 +02:00
|
|
|
const int h,
|
|
|
|
|
const eButType but_type,
|
|
|
|
|
const bool icon_only)
|
2009-04-16 12:17:58 +00:00
|
|
|
{
|
2019-04-17 08:44:38 +02:00
|
|
|
/* XXX: The way this function currently handles uiname parameter
|
|
|
|
|
* is insane and inconsistent with general UI API:
|
|
|
|
|
*
|
|
|
|
|
* - uiname is the *enum property* label.
|
2022-11-25 23:48:02 -06:00
|
|
|
* - when it is nullptr or empty, we do not draw *enum items* labels,
|
2019-04-17 08:44:38 +02:00
|
|
|
* this doubles the icon_only parameter.
|
|
|
|
|
* - we *never* draw (i.e. really use) the enum label uiname, it is just used as a mere flag!
|
|
|
|
|
*
|
|
|
|
|
* Unfortunately, fixing this implies an API "soft break", so better to defer it for later... :/
|
|
|
|
|
* - mont29
|
2013-10-12 11:28:37 +00:00
|
|
|
*/
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-10-29 21:20:58 +01:00
|
|
|
BLI_assert(RNA_property_type(prop) == PROP_ENUM);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
const bool radial = (layout->root_->type == UI_LAYOUT_PIEMENU);
|
2020-10-02 13:02:30 -05:00
|
|
|
|
|
|
|
|
bool free;
|
|
|
|
|
const EnumPropertyItem *item_array;
|
2019-03-25 10:15:20 +11:00
|
|
|
if (radial) {
|
2022-11-25 23:48:02 -06:00
|
|
|
RNA_property_enum_items_gettexted_all(
|
|
|
|
|
static_cast<bContext *>(block->evil_C), ptr, prop, &item_array, nullptr, &free);
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
|
|
|
|
else {
|
2022-11-25 23:48:02 -06:00
|
|
|
RNA_property_enum_items_gettexted(
|
|
|
|
|
static_cast<bContext *>(block->evil_C), ptr, prop, &item_array, nullptr, &free);
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-03-18 09:35:12 +11:00
|
|
|
/* We don't want nested rows, cols in menus. */
|
2022-11-25 23:48:02 -06:00
|
|
|
uiLayout *layout_radial = nullptr;
|
Pie Menus C code backend.
This commit merges the code in the pie-menu branch.
As per decisions taken the last few days, there are no pie menus
included and there will be an official add-on including overrides of
some keys with pie menus. However, people will now be able to use the
new code in python.
Full Documentation is in http://wiki.blender.org/index.php/Dev:Ref/
Thanks:
Campbell Barton, Dalai Felinto and Ton Roosendaal for the code review
and design comments
Jonathan Williamson, Pawel Lyczkowski, Pablo Vazquez among others for
suggestions during the development.
Special Thanks to Sean Olson, for his support, suggestions, testing and
merciless bugging so that I would finish the pie menu code. Without him
we wouldn't be here. Also to the rest of the developers of the original
python add-on, Patrick Moore and Dan Eicher and finally to Matt Ebb, who
did the research and first implementation and whose code I used to get
started.
2014-08-11 10:39:59 +02:00
|
|
|
if (radial) {
|
2025-04-23 16:37:14 +02:00
|
|
|
if (layout->root_->layout == layout) {
|
2025-05-07 23:29:49 +02:00
|
|
|
layout_radial = &layout->menu_pie();
|
2016-12-08 11:53:48 +01:00
|
|
|
UI_block_layout_set_current(block, layout_radial);
|
|
|
|
|
}
|
|
|
|
|
else {
|
2025-04-24 17:22:28 +02:00
|
|
|
if (layout->type_ == uiItemType::LayoutRadial) {
|
2017-01-24 21:35:38 +01:00
|
|
|
layout_radial = layout;
|
|
|
|
|
}
|
2016-12-08 11:53:48 +01:00
|
|
|
UI_block_layout_set_current(block, layout);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2016-12-08 11:53:48 +01:00
|
|
|
}
|
2025-04-24 17:22:28 +02:00
|
|
|
else if (ELEM(layout->type_, uiItemType::LayoutGridFlow, uiItemType::LayoutColumnFlow) ||
|
2025-04-23 16:37:14 +02:00
|
|
|
layout->root_->type == UI_LAYOUT_MENU)
|
2019-04-17 15:02:30 +02:00
|
|
|
{
|
|
|
|
|
UI_block_layout_set_current(block, layout);
|
2013-01-17 01:03:56 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2022-12-29 12:01:32 -05:00
|
|
|
UI_block_layout_set_current(block, ui_item_local_sublayout(layout, layout, true));
|
2013-01-17 01:03:56 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-02 13:02:30 -05:00
|
|
|
for (const EnumPropertyItem *item = item_array; item->identifier; item++) {
|
2018-11-25 16:21:35 +01:00
|
|
|
const bool is_first = item == item_array;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-07-06 11:28:00 +02:00
|
|
|
if (!item->identifier[0]) {
|
|
|
|
|
const EnumPropertyItem *next_item = item + 1;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-11-25 16:21:35 +01:00
|
|
|
/* Separate items, potentially with a label. */
|
2018-07-06 11:28:00 +02:00
|
|
|
if (next_item->identifier) {
|
2019-01-15 23:24:20 +11:00
|
|
|
/* Item without identifier but with name:
|
2019-05-01 11:09:22 +10:00
|
|
|
* Add group label for the following items. */
|
2018-11-25 16:21:35 +01:00
|
|
|
if (item->name) {
|
|
|
|
|
if (!is_first) {
|
2025-05-13 17:54:26 +02:00
|
|
|
block->curlayout->separator();
|
2018-11-25 16:21:35 +01:00
|
|
|
}
|
2025-05-08 17:21:08 +02:00
|
|
|
block->curlayout->label(item->name, item->icon);
|
2018-11-25 16:21:35 +01:00
|
|
|
}
|
|
|
|
|
else if (radial && layout_radial) {
|
2025-05-13 17:54:26 +02:00
|
|
|
layout_radial->separator();
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2025-05-13 17:54:26 +02:00
|
|
|
block->curlayout->separator();
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
2009-07-10 11:36:02 +00:00
|
|
|
continue;
|
2018-07-06 11:28:00 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-17 15:02:30 +02:00
|
|
|
ui_item_enum_expand_elem_exec(
|
|
|
|
|
layout, block, ptr, prop, uiname, h, but_type, icon_only, item, is_first);
|
2018-11-23 12:11:18 +11:00
|
|
|
}
|
2019-04-17 15:02:30 +02:00
|
|
|
|
2014-11-09 21:20:40 +01:00
|
|
|
UI_block_layout_set_current(block, layout);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-01-21 22:00:40 +00:00
|
|
|
if (free) {
|
2025-04-12 17:25:55 +02:00
|
|
|
MEM_freeN(item_array);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2012-01-21 22:00:40 +00:00
|
|
|
}
|
2018-10-29 21:20:58 +01:00
|
|
|
static void ui_item_enum_expand(uiLayout *layout,
|
|
|
|
|
uiBlock *block,
|
|
|
|
|
PointerRNA *ptr,
|
|
|
|
|
PropertyRNA *prop,
|
2024-12-06 14:08:10 +01:00
|
|
|
const std::optional<StringRef> uiname,
|
2019-04-18 13:59:59 +02:00
|
|
|
const int h,
|
|
|
|
|
const bool icon_only)
|
2018-10-29 21:20:58 +01:00
|
|
|
{
|
|
|
|
|
ui_item_enum_expand_exec(layout, block, ptr, prop, uiname, h, UI_BTYPE_ROW, icon_only);
|
|
|
|
|
}
|
|
|
|
|
static void ui_item_enum_expand_tabs(uiLayout *layout,
|
|
|
|
|
bContext *C,
|
|
|
|
|
uiBlock *block,
|
|
|
|
|
PointerRNA *ptr,
|
|
|
|
|
PropertyRNA *prop,
|
2020-10-13 12:43:28 -05:00
|
|
|
PointerRNA *ptr_highlight,
|
|
|
|
|
PropertyRNA *prop_highlight,
|
2025-03-07 17:53:54 +01:00
|
|
|
const std::optional<StringRef> uiname,
|
2019-04-18 13:59:59 +02:00
|
|
|
const int h,
|
|
|
|
|
const bool icon_only)
|
2018-10-29 21:20:58 +01:00
|
|
|
{
|
2025-02-14 15:29:26 +01:00
|
|
|
const int start_size = block->buttons.size();
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-10-29 21:20:58 +01:00
|
|
|
ui_item_enum_expand_exec(layout, block, ptr, prop, uiname, h, UI_BTYPE_TAB, icon_only);
|
2025-04-08 18:43:18 +02:00
|
|
|
|
|
|
|
|
if (block->buttons.is_empty()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-14 15:29:26 +01:00
|
|
|
BLI_assert(start_size != block->buttons.size());
|
2020-10-13 12:43:28 -05:00
|
|
|
|
2025-02-14 15:29:26 +01:00
|
|
|
for (int i = start_size; i < block->buttons.size(); i++) {
|
|
|
|
|
uiBut *tab = block->buttons[i].get();
|
2018-10-29 21:20:58 +01:00
|
|
|
UI_but_drawflag_enable(tab, ui_but_align_opposite_to_area_align_get(CTX_wm_region(C)));
|
2023-07-25 16:22:31 +02:00
|
|
|
if (icon_only) {
|
2025-05-09 13:34:35 +02:00
|
|
|
UI_but_drawflag_enable(tab, UI_BUT_HAS_QUICK_TOOLTIP);
|
2023-07-25 16:22:31 +02:00
|
|
|
}
|
2018-10-29 21:20:58 +01:00
|
|
|
}
|
2020-10-13 12:43:28 -05:00
|
|
|
|
2022-11-25 23:48:02 -06:00
|
|
|
const bool use_custom_highlight = (prop_highlight != nullptr);
|
2020-10-13 12:43:28 -05:00
|
|
|
|
|
|
|
|
if (use_custom_highlight) {
|
|
|
|
|
const int highlight_array_len = RNA_property_array_length(ptr_highlight, prop_highlight);
|
2022-11-25 23:48:02 -06:00
|
|
|
blender::Array<bool, 64> highlight_array(highlight_array_len);
|
|
|
|
|
RNA_property_boolean_get_array(ptr_highlight, prop_highlight, highlight_array.data());
|
2025-02-14 15:29:26 +01:00
|
|
|
const int end = std::min<int>(start_size + highlight_array_len, block->buttons.size());
|
|
|
|
|
for (int i = start_size; i < end; i++) {
|
|
|
|
|
uiBut *tab_but = block->buttons[i].get();
|
2020-10-13 12:43:28 -05:00
|
|
|
SET_FLAG_FROM_TEST(tab_but->flag, !highlight_array[i], UI_BUT_INACTIVE);
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-10-29 21:20:58 +01:00
|
|
|
}
|
2009-04-16 12:17:58 +00:00
|
|
|
|
Key Configuration
Keymaps are now saveable and configurable from the user preferences, note
that editing one item in a keymap means the whole keymap is now defined by
the user and will not be updated by Blender, an option for syncing might be
added later. The outliner interface is still there, but I will probably
remove it.
There's actually 3 levels now:
* Default builtin key configuration.
* Key configuration loaded from .py file, for configs like Blender 2.4x
or other 3D applications.
* Keymaps edited by the user and saved in .B.blend. These can be saved
to .py files as well to make creating distributable configurations
easier.
Also, user preferences sections were reorganized a bit, now there is:
Interface, Editing, Input, Files and System.
Implementation notes:
* wmKeyConfig was added which represents a key configuration containing
keymaps.
* wmKeymapItem was renamed to wmKeyMapItem for consistency with wmKeyMap.
* Modal maps are not wrapped yet.
* User preferences DNA file reading did not support newdataadr() yet,
added this now for reading keymaps.
* Key configuration related settings are now RNA wrapped.
* is_property_set and is_property_hidden python methods were added.
2009-10-08 18:40:03 +00:00
|
|
|
/* callback for keymap item change button */
|
2022-11-25 23:48:02 -06:00
|
|
|
static void ui_keymap_but_cb(bContext * /*C*/, void *but_v, void * /*key_v*/)
|
Key Configuration
Keymaps are now saveable and configurable from the user preferences, note
that editing one item in a keymap means the whole keymap is now defined by
the user and will not be updated by Blender, an option for syncing might be
added later. The outliner interface is still there, but I will probably
remove it.
There's actually 3 levels now:
* Default builtin key configuration.
* Key configuration loaded from .py file, for configs like Blender 2.4x
or other 3D applications.
* Keymaps edited by the user and saved in .B.blend. These can be saved
to .py files as well to make creating distributable configurations
easier.
Also, user preferences sections were reorganized a bit, now there is:
Interface, Editing, Input, Files and System.
Implementation notes:
* wmKeyConfig was added which represents a key configuration containing
keymaps.
* wmKeymapItem was renamed to wmKeyMapItem for consistency with wmKeyMap.
* Modal maps are not wrapped yet.
* User preferences DNA file reading did not support newdataadr() yet,
added this now for reading keymaps.
* Key configuration related settings are now RNA wrapped.
* is_property_set and is_property_hidden python methods were added.
2009-10-08 18:40:03 +00:00
|
|
|
{
|
2022-11-25 23:48:02 -06:00
|
|
|
uiBut *but = static_cast<uiBut *>(but_v);
|
2022-05-12 17:30:18 +02:00
|
|
|
BLI_assert(but->type == UI_BTYPE_HOTKEY_EVENT);
|
|
|
|
|
const uiButHotkeyEvent *hotkey_but = (uiButHotkeyEvent *)but;
|
|
|
|
|
|
|
|
|
|
RNA_int_set(
|
|
|
|
|
&but->rnapoin, "shift", (hotkey_but->modifier_key & KM_SHIFT) ? KM_MOD_HELD : KM_NOTHING);
|
|
|
|
|
RNA_int_set(
|
|
|
|
|
&but->rnapoin, "ctrl", (hotkey_but->modifier_key & KM_CTRL) ? KM_MOD_HELD : KM_NOTHING);
|
|
|
|
|
RNA_int_set(
|
|
|
|
|
&but->rnapoin, "alt", (hotkey_but->modifier_key & KM_ALT) ? KM_MOD_HELD : KM_NOTHING);
|
|
|
|
|
RNA_int_set(
|
|
|
|
|
&but->rnapoin, "oskey", (hotkey_but->modifier_key & KM_OSKEY) ? KM_MOD_HELD : KM_NOTHING);
|
2025-03-25 23:32:41 +00:00
|
|
|
RNA_int_set(
|
|
|
|
|
&but->rnapoin, "hyper", (hotkey_but->modifier_key & KM_HYPER) ? KM_MOD_HELD : KM_NOTHING);
|
Key Configuration
Keymaps are now saveable and configurable from the user preferences, note
that editing one item in a keymap means the whole keymap is now defined by
the user and will not be updated by Blender, an option for syncing might be
added later. The outliner interface is still there, but I will probably
remove it.
There's actually 3 levels now:
* Default builtin key configuration.
* Key configuration loaded from .py file, for configs like Blender 2.4x
or other 3D applications.
* Keymaps edited by the user and saved in .B.blend. These can be saved
to .py files as well to make creating distributable configurations
easier.
Also, user preferences sections were reorganized a bit, now there is:
Interface, Editing, Input, Files and System.
Implementation notes:
* wmKeyConfig was added which represents a key configuration containing
keymaps.
* wmKeymapItem was renamed to wmKeyMapItem for consistency with wmKeyMap.
* Modal maps are not wrapped yet.
* User preferences DNA file reading did not support newdataadr() yet,
added this now for reading keymaps.
* Key configuration related settings are now RNA wrapped.
* is_property_set and is_property_hidden python methods were added.
2009-10-08 18:40:03 +00:00
|
|
|
}
|
|
|
|
|
|
UI: New Global Top-Bar (WIP)
== Main Features/Changes for Users
* Add horizontal bar at top of all non-temp windows, consisting out of two horizontal sub-bars.
* Upper sub-bar contains global menus (File, Render, etc.), tabs for workspaces and scene selector.
* Lower sub-bar contains object mode selector, screen-layout and render-layer selector. Later operator and/or tool settings will be placed here.
* Individual sections of the topbar are individually scrollable.
* Workspace tabs can be double- or ctrl-clicked for renaming and contain 'x' icon for deleting.
* Top-bar should scale nicely with DPI.
* The lower half of the top-bar can be hided by dragging the lower top-bar edge up. Better hiding options are planned (e.g. hide in fullscreen modes).
* Info editors at the top of the window and using the full window width with be replaced by the top-bar.
* In fullscreen modes, no more info editor is added on top, the top-bar replaces it.
== Technical Features/Changes
* Adds initial support for global areas
A global area is part of the window, not part of the regular screen-layout.
I've added a macro iterator to iterate over both, global and screen-layout level areas. When iterating over areas, from now on developers should always consider if they have to include global areas.
* Adds a TOPBAR editor type
The editor type is hidden in the UI editor type menu.
* Adds a variation of the ID template to display IDs as tab buttons (template_ID_tabs in BPY)
* Does various changes to RNA button creation code to improve their appearance in the horizontal top-bar.
* Adds support for dynamically sized regions. That is, regions that scale automatically to the layout bounds.
The code for this is currently a big hack (it's based on drawing the UI multiple times). This should definitely be improved.
* Adds a template for displaying operator properties optimized for the top-bar. This will probably change a lot still and is in fact disabled in code.
Since the final top-bar design depends a lot on other 2.8 designs (mainly tool-system and workspaces), we decided to not show the operator or tool settings in the top-bar for now. That means most of the lower sub-bar is empty for the time being.
NOTE: Top-bar or global area data is not written to files or SDNA. They are simply added to the window when opening Blender or reading a file. This allows us doing changes to the top-bar without having to care for compatibility.
== ToDo's
It's a bit hard to predict all the ToDo's here are the known main ones:
* Add options for the new active-tool system and for operator redo to the topbar.
* Automatically hide the top-bar in fullscreen modes.
* General visual polish.
* Top-bar drag & drop support (WIP in temp-tab_drag_drop).
* Improve dynamic regions (should also fix some layout glitches).
* Make internal terminology consistent.
* Enable topbar file writing once design is more advanced.
* Address TODO's and XXX's in code :)
Thanks @brecht for the review! And @sergey for the complaining ;)
Differential Revision: D2758
2018-04-20 17:14:03 +02:00
|
|
|
/**
|
|
|
|
|
* Create label + button for RNA property
|
|
|
|
|
*
|
|
|
|
|
* \param w_hint: For varying width layout, this becomes the label width.
|
|
|
|
|
* Otherwise it's used to fit both items into it.
|
2019-03-19 15:17:46 +11:00
|
|
|
*/
|
UI: New Global Top-Bar (WIP)
== Main Features/Changes for Users
* Add horizontal bar at top of all non-temp windows, consisting out of two horizontal sub-bars.
* Upper sub-bar contains global menus (File, Render, etc.), tabs for workspaces and scene selector.
* Lower sub-bar contains object mode selector, screen-layout and render-layer selector. Later operator and/or tool settings will be placed here.
* Individual sections of the topbar are individually scrollable.
* Workspace tabs can be double- or ctrl-clicked for renaming and contain 'x' icon for deleting.
* Top-bar should scale nicely with DPI.
* The lower half of the top-bar can be hided by dragging the lower top-bar edge up. Better hiding options are planned (e.g. hide in fullscreen modes).
* Info editors at the top of the window and using the full window width with be replaced by the top-bar.
* In fullscreen modes, no more info editor is added on top, the top-bar replaces it.
== Technical Features/Changes
* Adds initial support for global areas
A global area is part of the window, not part of the regular screen-layout.
I've added a macro iterator to iterate over both, global and screen-layout level areas. When iterating over areas, from now on developers should always consider if they have to include global areas.
* Adds a TOPBAR editor type
The editor type is hidden in the UI editor type menu.
* Adds a variation of the ID template to display IDs as tab buttons (template_ID_tabs in BPY)
* Does various changes to RNA button creation code to improve their appearance in the horizontal top-bar.
* Adds support for dynamically sized regions. That is, regions that scale automatically to the layout bounds.
The code for this is currently a big hack (it's based on drawing the UI multiple times). This should definitely be improved.
* Adds a template for displaying operator properties optimized for the top-bar. This will probably change a lot still and is in fact disabled in code.
Since the final top-bar design depends a lot on other 2.8 designs (mainly tool-system and workspaces), we decided to not show the operator or tool settings in the top-bar for now. That means most of the lower sub-bar is empty for the time being.
NOTE: Top-bar or global area data is not written to files or SDNA. They are simply added to the window when opening Blender or reading a file. This allows us doing changes to the top-bar without having to care for compatibility.
== ToDo's
It's a bit hard to predict all the ToDo's here are the known main ones:
* Add options for the new active-tool system and for operator redo to the topbar.
* Automatically hide the top-bar in fullscreen modes.
* General visual polish.
* Top-bar drag & drop support (WIP in temp-tab_drag_drop).
* Improve dynamic regions (should also fix some layout glitches).
* Make internal terminology consistent.
* Enable topbar file writing once design is more advanced.
* Address TODO's and XXX's in code :)
Thanks @brecht for the review! And @sergey for the complaining ;)
Differential Revision: D2758
2018-04-20 17:14:03 +02:00
|
|
|
static uiBut *ui_item_with_label(uiLayout *layout,
|
|
|
|
|
uiBlock *block,
|
2025-05-19 17:25:52 +02:00
|
|
|
const StringRef name,
|
2024-02-05 12:12:28 -05:00
|
|
|
const int icon,
|
UI: New Global Top-Bar (WIP)
== Main Features/Changes for Users
* Add horizontal bar at top of all non-temp windows, consisting out of two horizontal sub-bars.
* Upper sub-bar contains global menus (File, Render, etc.), tabs for workspaces and scene selector.
* Lower sub-bar contains object mode selector, screen-layout and render-layer selector. Later operator and/or tool settings will be placed here.
* Individual sections of the topbar are individually scrollable.
* Workspace tabs can be double- or ctrl-clicked for renaming and contain 'x' icon for deleting.
* Top-bar should scale nicely with DPI.
* The lower half of the top-bar can be hided by dragging the lower top-bar edge up. Better hiding options are planned (e.g. hide in fullscreen modes).
* Info editors at the top of the window and using the full window width with be replaced by the top-bar.
* In fullscreen modes, no more info editor is added on top, the top-bar replaces it.
== Technical Features/Changes
* Adds initial support for global areas
A global area is part of the window, not part of the regular screen-layout.
I've added a macro iterator to iterate over both, global and screen-layout level areas. When iterating over areas, from now on developers should always consider if they have to include global areas.
* Adds a TOPBAR editor type
The editor type is hidden in the UI editor type menu.
* Adds a variation of the ID template to display IDs as tab buttons (template_ID_tabs in BPY)
* Does various changes to RNA button creation code to improve their appearance in the horizontal top-bar.
* Adds support for dynamically sized regions. That is, regions that scale automatically to the layout bounds.
The code for this is currently a big hack (it's based on drawing the UI multiple times). This should definitely be improved.
* Adds a template for displaying operator properties optimized for the top-bar. This will probably change a lot still and is in fact disabled in code.
Since the final top-bar design depends a lot on other 2.8 designs (mainly tool-system and workspaces), we decided to not show the operator or tool settings in the top-bar for now. That means most of the lower sub-bar is empty for the time being.
NOTE: Top-bar or global area data is not written to files or SDNA. They are simply added to the window when opening Blender or reading a file. This allows us doing changes to the top-bar without having to care for compatibility.
== ToDo's
It's a bit hard to predict all the ToDo's here are the known main ones:
* Add options for the new active-tool system and for operator redo to the topbar.
* Automatically hide the top-bar in fullscreen modes.
* General visual polish.
* Top-bar drag & drop support (WIP in temp-tab_drag_drop).
* Improve dynamic regions (should also fix some layout glitches).
* Make internal terminology consistent.
* Enable topbar file writing once design is more advanced.
* Address TODO's and XXX's in code :)
Thanks @brecht for the review! And @sergey for the complaining ;)
Differential Revision: D2758
2018-04-20 17:14:03 +02:00
|
|
|
PointerRNA *ptr,
|
|
|
|
|
PropertyRNA *prop,
|
2024-02-05 12:12:28 -05:00
|
|
|
const int index,
|
|
|
|
|
const int x,
|
|
|
|
|
const int y,
|
|
|
|
|
const int w_hint,
|
|
|
|
|
const int h,
|
|
|
|
|
const int flag)
|
2009-03-13 13:38:41 +00:00
|
|
|
{
|
2020-08-05 16:50:33 +02:00
|
|
|
uiLayout *sub = layout;
|
UI: New Global Top-Bar (WIP)
== Main Features/Changes for Users
* Add horizontal bar at top of all non-temp windows, consisting out of two horizontal sub-bars.
* Upper sub-bar contains global menus (File, Render, etc.), tabs for workspaces and scene selector.
* Lower sub-bar contains object mode selector, screen-layout and render-layer selector. Later operator and/or tool settings will be placed here.
* Individual sections of the topbar are individually scrollable.
* Workspace tabs can be double- or ctrl-clicked for renaming and contain 'x' icon for deleting.
* Top-bar should scale nicely with DPI.
* The lower half of the top-bar can be hided by dragging the lower top-bar edge up. Better hiding options are planned (e.g. hide in fullscreen modes).
* Info editors at the top of the window and using the full window width with be replaced by the top-bar.
* In fullscreen modes, no more info editor is added on top, the top-bar replaces it.
== Technical Features/Changes
* Adds initial support for global areas
A global area is part of the window, not part of the regular screen-layout.
I've added a macro iterator to iterate over both, global and screen-layout level areas. When iterating over areas, from now on developers should always consider if they have to include global areas.
* Adds a TOPBAR editor type
The editor type is hidden in the UI editor type menu.
* Adds a variation of the ID template to display IDs as tab buttons (template_ID_tabs in BPY)
* Does various changes to RNA button creation code to improve their appearance in the horizontal top-bar.
* Adds support for dynamically sized regions. That is, regions that scale automatically to the layout bounds.
The code for this is currently a big hack (it's based on drawing the UI multiple times). This should definitely be improved.
* Adds a template for displaying operator properties optimized for the top-bar. This will probably change a lot still and is in fact disabled in code.
Since the final top-bar design depends a lot on other 2.8 designs (mainly tool-system and workspaces), we decided to not show the operator or tool settings in the top-bar for now. That means most of the lower sub-bar is empty for the time being.
NOTE: Top-bar or global area data is not written to files or SDNA. They are simply added to the window when opening Blender or reading a file. This allows us doing changes to the top-bar without having to care for compatibility.
== ToDo's
It's a bit hard to predict all the ToDo's here are the known main ones:
* Add options for the new active-tool system and for operator redo to the topbar.
* Automatically hide the top-bar in fullscreen modes.
* General visual polish.
* Top-bar drag & drop support (WIP in temp-tab_drag_drop).
* Improve dynamic regions (should also fix some layout glitches).
* Make internal terminology consistent.
* Enable topbar file writing once design is more advanced.
* Address TODO's and XXX's in code :)
Thanks @brecht for the review! And @sergey for the complaining ;)
Differential Revision: D2758
2018-04-20 17:14:03 +02:00
|
|
|
int prop_but_width = w_hint;
|
2020-04-05 14:19:24 +02:00
|
|
|
#ifdef UI_PROP_DECORATE
|
2022-11-25 23:48:02 -06:00
|
|
|
uiLayout *layout_prop_decorate = nullptr;
|
2025-04-24 17:22:28 +02:00
|
|
|
const bool use_prop_sep = bool(layout->flag_ & uiItemInternalFlag::PropSep);
|
2025-03-31 18:23:16 +02:00
|
|
|
const bool use_prop_decorate = use_prop_sep &&
|
2025-04-24 17:22:28 +02:00
|
|
|
bool(layout->flag_ & uiItemInternalFlag::PropDecorate) &&
|
|
|
|
|
!bool(layout->flag_ & uiItemInternalFlag::PropDecorateNoPad);
|
2020-04-05 14:19:24 +02:00
|
|
|
#endif
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-03 18:52:14 +02:00
|
|
|
const bool is_keymapitem_ptr = RNA_struct_is_a(ptr->type, &RNA_KeyMapItem);
|
2020-11-18 13:30:30 +11:00
|
|
|
if ((flag & UI_ITEM_R_FULL_EVENT) && !is_keymapitem_ptr) {
|
2020-10-03 18:52:14 +02:00
|
|
|
RNA_warning("Data is not a keymap item struct: %s. Ignoring 'full_event' option.",
|
|
|
|
|
RNA_struct_identifier(ptr->type));
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-05 16:50:33 +02:00
|
|
|
UI_block_layout_set_current(block, layout);
|
|
|
|
|
|
|
|
|
|
/* Only add new row if more than 1 item will be added. */
|
2024-12-06 14:08:10 +01:00
|
|
|
if (!name.is_empty()
|
2020-10-29 07:56:43 -07:00
|
|
|
#ifdef UI_PROP_DECORATE
|
|
|
|
|
|| use_prop_decorate
|
|
|
|
|
#endif
|
|
|
|
|
)
|
|
|
|
|
{
|
2020-08-05 16:50:33 +02:00
|
|
|
/* Also avoid setting 'align' if possible. Set the space to zero instead as aligning a large
|
|
|
|
|
* number of labels can end up aligning thousands of buttons when displaying key-map search (a
|
2023-02-12 14:37:16 +11:00
|
|
|
* heavy operation), see: #78636. */
|
2025-04-25 19:45:25 +02:00
|
|
|
sub = &layout->row(layout->align_);
|
2025-04-23 14:54:06 +02:00
|
|
|
sub->space_ = 0;
|
2020-08-05 16:50:33 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-06 14:08:10 +01:00
|
|
|
if (!name.is_empty()) {
|
2020-10-29 07:56:43 -07:00
|
|
|
#ifdef UI_PROP_DECORATE
|
2018-06-05 08:56:14 +02:00
|
|
|
if (use_prop_sep) {
|
2023-08-12 16:29:49 +10:00
|
|
|
layout_prop_decorate = uiItemL_respect_property_split(layout, name, ICON_NONE);
|
UI: New Global Top-Bar (WIP)
== Main Features/Changes for Users
* Add horizontal bar at top of all non-temp windows, consisting out of two horizontal sub-bars.
* Upper sub-bar contains global menus (File, Render, etc.), tabs for workspaces and scene selector.
* Lower sub-bar contains object mode selector, screen-layout and render-layer selector. Later operator and/or tool settings will be placed here.
* Individual sections of the topbar are individually scrollable.
* Workspace tabs can be double- or ctrl-clicked for renaming and contain 'x' icon for deleting.
* Top-bar should scale nicely with DPI.
* The lower half of the top-bar can be hided by dragging the lower top-bar edge up. Better hiding options are planned (e.g. hide in fullscreen modes).
* Info editors at the top of the window and using the full window width with be replaced by the top-bar.
* In fullscreen modes, no more info editor is added on top, the top-bar replaces it.
== Technical Features/Changes
* Adds initial support for global areas
A global area is part of the window, not part of the regular screen-layout.
I've added a macro iterator to iterate over both, global and screen-layout level areas. When iterating over areas, from now on developers should always consider if they have to include global areas.
* Adds a TOPBAR editor type
The editor type is hidden in the UI editor type menu.
* Adds a variation of the ID template to display IDs as tab buttons (template_ID_tabs in BPY)
* Does various changes to RNA button creation code to improve their appearance in the horizontal top-bar.
* Adds support for dynamically sized regions. That is, regions that scale automatically to the layout bounds.
The code for this is currently a big hack (it's based on drawing the UI multiple times). This should definitely be improved.
* Adds a template for displaying operator properties optimized for the top-bar. This will probably change a lot still and is in fact disabled in code.
Since the final top-bar design depends a lot on other 2.8 designs (mainly tool-system and workspaces), we decided to not show the operator or tool settings in the top-bar for now. That means most of the lower sub-bar is empty for the time being.
NOTE: Top-bar or global area data is not written to files or SDNA. They are simply added to the window when opening Blender or reading a file. This allows us doing changes to the top-bar without having to care for compatibility.
== ToDo's
It's a bit hard to predict all the ToDo's here are the known main ones:
* Add options for the new active-tool system and for operator redo to the topbar.
* Automatically hide the top-bar in fullscreen modes.
* General visual polish.
* Top-bar drag & drop support (WIP in temp-tab_drag_drop).
* Improve dynamic regions (should also fix some layout glitches).
* Make internal terminology consistent.
* Enable topbar file writing once design is more advanced.
* Address TODO's and XXX's in code :)
Thanks @brecht for the review! And @sergey for the complaining ;)
Differential Revision: D2758
2018-04-20 17:14:03 +02:00
|
|
|
}
|
2020-04-05 14:19:24 +02:00
|
|
|
else
|
|
|
|
|
#endif
|
|
|
|
|
{
|
|
|
|
|
int w_label;
|
2018-06-09 16:50:05 +02:00
|
|
|
if (ui_layout_variable_size(layout)) {
|
2022-03-13 17:38:06 -04:00
|
|
|
/* In this case, a pure label without additional padding.
|
|
|
|
|
* Use a default width for property button(s). */
|
2018-06-05 08:56:14 +02:00
|
|
|
prop_but_width = UI_UNIT_X * 5;
|
2023-09-05 00:58:57 +02:00
|
|
|
w_label = ui_text_icon_width_ex(
|
2024-07-19 21:57:49 +02:00
|
|
|
layout, name, ICON_NONE, ui_text_pad_none, UI_FSTYLE_WIDGET);
|
2018-06-05 08:56:14 +02:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
w_label = w_hint / 3;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2024-03-01 14:26:45 -05:00
|
|
|
uiDefBut(block, UI_BTYPE_LABEL, 0, name, x, y, w_label, h, nullptr, 0.0, 0.0, "");
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
UI: New Global Top-Bar (WIP)
== Main Features/Changes for Users
* Add horizontal bar at top of all non-temp windows, consisting out of two horizontal sub-bars.
* Upper sub-bar contains global menus (File, Render, etc.), tabs for workspaces and scene selector.
* Lower sub-bar contains object mode selector, screen-layout and render-layer selector. Later operator and/or tool settings will be placed here.
* Individual sections of the topbar are individually scrollable.
* Workspace tabs can be double- or ctrl-clicked for renaming and contain 'x' icon for deleting.
* Top-bar should scale nicely with DPI.
* The lower half of the top-bar can be hided by dragging the lower top-bar edge up. Better hiding options are planned (e.g. hide in fullscreen modes).
* Info editors at the top of the window and using the full window width with be replaced by the top-bar.
* In fullscreen modes, no more info editor is added on top, the top-bar replaces it.
== Technical Features/Changes
* Adds initial support for global areas
A global area is part of the window, not part of the regular screen-layout.
I've added a macro iterator to iterate over both, global and screen-layout level areas. When iterating over areas, from now on developers should always consider if they have to include global areas.
* Adds a TOPBAR editor type
The editor type is hidden in the UI editor type menu.
* Adds a variation of the ID template to display IDs as tab buttons (template_ID_tabs in BPY)
* Does various changes to RNA button creation code to improve their appearance in the horizontal top-bar.
* Adds support for dynamically sized regions. That is, regions that scale automatically to the layout bounds.
The code for this is currently a big hack (it's based on drawing the UI multiple times). This should definitely be improved.
* Adds a template for displaying operator properties optimized for the top-bar. This will probably change a lot still and is in fact disabled in code.
Since the final top-bar design depends a lot on other 2.8 designs (mainly tool-system and workspaces), we decided to not show the operator or tool settings in the top-bar for now. That means most of the lower sub-bar is empty for the time being.
NOTE: Top-bar or global area data is not written to files or SDNA. They are simply added to the window when opening Blender or reading a file. This allows us doing changes to the top-bar without having to care for compatibility.
== ToDo's
It's a bit hard to predict all the ToDo's here are the known main ones:
* Add options for the new active-tool system and for operator redo to the topbar.
* Automatically hide the top-bar in fullscreen modes.
* General visual polish.
* Top-bar drag & drop support (WIP in temp-tab_drag_drop).
* Improve dynamic regions (should also fix some layout glitches).
* Make internal terminology consistent.
* Enable topbar file writing once design is more advanced.
* Address TODO's and XXX's in code :)
Thanks @brecht for the review! And @sergey for the complaining ;)
Differential Revision: D2758
2018-04-20 17:14:03 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-02 13:02:30 -05:00
|
|
|
const PropertyType type = RNA_property_type(prop);
|
|
|
|
|
const PropertySubType subtype = RNA_property_subtype(prop);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-02 13:02:30 -05:00
|
|
|
uiBut *but;
|
2020-11-06 12:30:59 +11:00
|
|
|
if (ELEM(subtype, PROP_FILEPATH, PROP_DIRPATH)) {
|
2025-04-25 19:45:25 +02:00
|
|
|
UI_block_layout_set_current(block, &sub->row(true));
|
2012-03-24 06:38:07 +00:00
|
|
|
but = uiDefAutoButR(block, ptr, prop, index, "", icon, x, y, prop_but_width - UI_UNIT_X, h);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-10 23:27:21 +00:00
|
|
|
if (but != nullptr) {
|
|
|
|
|
if (ELEM(subtype, PROP_FILEPATH, PROP_DIRPATH)) {
|
|
|
|
|
if ((RNA_property_flag(prop) & PROP_PATH_SUPPORTS_BLEND_RELATIVE) == 0) {
|
|
|
|
|
if (BLI_path_is_rel(but->drawstr.c_str())) {
|
2025-04-30 11:15:38 +00:00
|
|
|
UI_but_flag_enable(but, UI_BUT_REDALERT);
|
2025-04-10 23:27:21 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-15 15:20:19 +10:00
|
|
|
/* #BUTTONS_OT_file_browse calls #UI_context_active_but_prop_get_filebrowser. */
|
2014-11-09 21:20:40 +01:00
|
|
|
uiDefIconButO(block,
|
2012-03-24 06:38:07 +00:00
|
|
|
UI_BTYPE_BUT,
|
|
|
|
|
subtype == PROP_DIRPATH ? "BUTTONS_OT_directory_browse" :
|
2014-11-09 21:20:40 +01:00
|
|
|
"BUTTONS_OT_file_browse",
|
|
|
|
|
WM_OP_INVOKE_DEFAULT,
|
|
|
|
|
ICON_FILEBROWSER,
|
2018-07-01 19:57:31 +02:00
|
|
|
x,
|
|
|
|
|
y,
|
2018-10-01 10:45:50 +02:00
|
|
|
UI_UNIT_X,
|
|
|
|
|
h,
|
2025-02-14 15:12:48 -05:00
|
|
|
std::nullopt);
|
2009-03-13 13:38:41 +00:00
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
else if (flag & UI_ITEM_R_EVENT) {
|
UI: New Global Top-Bar (WIP)
== Main Features/Changes for Users
* Add horizontal bar at top of all non-temp windows, consisting out of two horizontal sub-bars.
* Upper sub-bar contains global menus (File, Render, etc.), tabs for workspaces and scene selector.
* Lower sub-bar contains object mode selector, screen-layout and render-layer selector. Later operator and/or tool settings will be placed here.
* Individual sections of the topbar are individually scrollable.
* Workspace tabs can be double- or ctrl-clicked for renaming and contain 'x' icon for deleting.
* Top-bar should scale nicely with DPI.
* The lower half of the top-bar can be hided by dragging the lower top-bar edge up. Better hiding options are planned (e.g. hide in fullscreen modes).
* Info editors at the top of the window and using the full window width with be replaced by the top-bar.
* In fullscreen modes, no more info editor is added on top, the top-bar replaces it.
== Technical Features/Changes
* Adds initial support for global areas
A global area is part of the window, not part of the regular screen-layout.
I've added a macro iterator to iterate over both, global and screen-layout level areas. When iterating over areas, from now on developers should always consider if they have to include global areas.
* Adds a TOPBAR editor type
The editor type is hidden in the UI editor type menu.
* Adds a variation of the ID template to display IDs as tab buttons (template_ID_tabs in BPY)
* Does various changes to RNA button creation code to improve their appearance in the horizontal top-bar.
* Adds support for dynamically sized regions. That is, regions that scale automatically to the layout bounds.
The code for this is currently a big hack (it's based on drawing the UI multiple times). This should definitely be improved.
* Adds a template for displaying operator properties optimized for the top-bar. This will probably change a lot still and is in fact disabled in code.
Since the final top-bar design depends a lot on other 2.8 designs (mainly tool-system and workspaces), we decided to not show the operator or tool settings in the top-bar for now. That means most of the lower sub-bar is empty for the time being.
NOTE: Top-bar or global area data is not written to files or SDNA. They are simply added to the window when opening Blender or reading a file. This allows us doing changes to the top-bar without having to care for compatibility.
== ToDo's
It's a bit hard to predict all the ToDo's here are the known main ones:
* Add options for the new active-tool system and for operator redo to the topbar.
* Automatically hide the top-bar in fullscreen modes.
* General visual polish.
* Top-bar drag & drop support (WIP in temp-tab_drag_drop).
* Improve dynamic regions (should also fix some layout glitches).
* Make internal terminology consistent.
* Enable topbar file writing once design is more advanced.
* Address TODO's and XXX's in code :)
Thanks @brecht for the review! And @sergey for the complaining ;)
Differential Revision: D2758
2018-04-20 17:14:03 +02:00
|
|
|
but = uiDefButR_prop(block,
|
|
|
|
|
UI_BTYPE_KEY_EVENT,
|
|
|
|
|
0,
|
|
|
|
|
name,
|
|
|
|
|
x,
|
|
|
|
|
y,
|
|
|
|
|
prop_but_width,
|
|
|
|
|
h,
|
|
|
|
|
ptr,
|
|
|
|
|
prop,
|
|
|
|
|
index,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
2025-02-14 15:12:48 -05:00
|
|
|
std::nullopt);
|
Key Configuration
Keymaps are now saveable and configurable from the user preferences, note
that editing one item in a keymap means the whole keymap is now defined by
the user and will not be updated by Blender, an option for syncing might be
added later. The outliner interface is still there, but I will probably
remove it.
There's actually 3 levels now:
* Default builtin key configuration.
* Key configuration loaded from .py file, for configs like Blender 2.4x
or other 3D applications.
* Keymaps edited by the user and saved in .B.blend. These can be saved
to .py files as well to make creating distributable configurations
easier.
Also, user preferences sections were reorganized a bit, now there is:
Interface, Editing, Input, Files and System.
Implementation notes:
* wmKeyConfig was added which represents a key configuration containing
keymaps.
* wmKeymapItem was renamed to wmKeyMapItem for consistency with wmKeyMap.
* Modal maps are not wrapped yet.
* User preferences DNA file reading did not support newdataadr() yet,
added this now for reading keymaps.
* Key configuration related settings are now RNA wrapped.
* is_property_set and is_property_hidden python methods were added.
2009-10-08 18:40:03 +00:00
|
|
|
}
|
2020-10-03 18:52:14 +02:00
|
|
|
else if ((flag & UI_ITEM_R_FULL_EVENT) && is_keymapitem_ptr) {
|
2024-02-07 14:22:54 +01:00
|
|
|
std::string kmi_str =
|
|
|
|
|
WM_keymap_item_to_string(static_cast<const wmKeyMapItem *>(ptr->data), false).value_or("");
|
2020-10-03 18:52:14 +02:00
|
|
|
|
|
|
|
|
but = uiDefButR_prop(block,
|
|
|
|
|
UI_BTYPE_HOTKEY_EVENT,
|
|
|
|
|
0,
|
2024-12-06 14:08:10 +01:00
|
|
|
kmi_str,
|
2020-10-03 18:52:14 +02:00
|
|
|
x,
|
|
|
|
|
y,
|
|
|
|
|
prop_but_width,
|
|
|
|
|
h,
|
|
|
|
|
ptr,
|
|
|
|
|
prop,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
2025-02-14 15:12:48 -05:00
|
|
|
std::nullopt);
|
2022-11-25 23:48:02 -06:00
|
|
|
UI_but_func_set(but, ui_keymap_but_cb, but, nullptr);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
UI: New Global Top-Bar (WIP)
== Main Features/Changes for Users
* Add horizontal bar at top of all non-temp windows, consisting out of two horizontal sub-bars.
* Upper sub-bar contains global menus (File, Render, etc.), tabs for workspaces and scene selector.
* Lower sub-bar contains object mode selector, screen-layout and render-layer selector. Later operator and/or tool settings will be placed here.
* Individual sections of the topbar are individually scrollable.
* Workspace tabs can be double- or ctrl-clicked for renaming and contain 'x' icon for deleting.
* Top-bar should scale nicely with DPI.
* The lower half of the top-bar can be hided by dragging the lower top-bar edge up. Better hiding options are planned (e.g. hide in fullscreen modes).
* Info editors at the top of the window and using the full window width with be replaced by the top-bar.
* In fullscreen modes, no more info editor is added on top, the top-bar replaces it.
== Technical Features/Changes
* Adds initial support for global areas
A global area is part of the window, not part of the regular screen-layout.
I've added a macro iterator to iterate over both, global and screen-layout level areas. When iterating over areas, from now on developers should always consider if they have to include global areas.
* Adds a TOPBAR editor type
The editor type is hidden in the UI editor type menu.
* Adds a variation of the ID template to display IDs as tab buttons (template_ID_tabs in BPY)
* Does various changes to RNA button creation code to improve their appearance in the horizontal top-bar.
* Adds support for dynamically sized regions. That is, regions that scale automatically to the layout bounds.
The code for this is currently a big hack (it's based on drawing the UI multiple times). This should definitely be improved.
* Adds a template for displaying operator properties optimized for the top-bar. This will probably change a lot still and is in fact disabled in code.
Since the final top-bar design depends a lot on other 2.8 designs (mainly tool-system and workspaces), we decided to not show the operator or tool settings in the top-bar for now. That means most of the lower sub-bar is empty for the time being.
NOTE: Top-bar or global area data is not written to files or SDNA. They are simply added to the window when opening Blender or reading a file. This allows us doing changes to the top-bar without having to care for compatibility.
== ToDo's
It's a bit hard to predict all the ToDo's here are the known main ones:
* Add options for the new active-tool system and for operator redo to the topbar.
* Automatically hide the top-bar in fullscreen modes.
* General visual polish.
* Top-bar drag & drop support (WIP in temp-tab_drag_drop).
* Improve dynamic regions (should also fix some layout glitches).
* Make internal terminology consistent.
* Enable topbar file writing once design is more advanced.
* Address TODO's and XXX's in code :)
Thanks @brecht for the review! And @sergey for the complaining ;)
Differential Revision: D2758
2018-04-20 17:14:03 +02:00
|
|
|
else {
|
2024-12-06 14:08:10 +01:00
|
|
|
const std::optional<StringRefNull> str = (type == PROP_ENUM && !(flag & UI_ITEM_R_ICON_ONLY)) ?
|
|
|
|
|
std::nullopt :
|
|
|
|
|
std::make_optional<StringRefNull>("");
|
2018-07-01 20:15:21 +02:00
|
|
|
but = uiDefAutoButR(block, ptr, prop, index, str, icon, x, y, prop_but_width, h);
|
UI: New Global Top-Bar (WIP)
== Main Features/Changes for Users
* Add horizontal bar at top of all non-temp windows, consisting out of two horizontal sub-bars.
* Upper sub-bar contains global menus (File, Render, etc.), tabs for workspaces and scene selector.
* Lower sub-bar contains object mode selector, screen-layout and render-layer selector. Later operator and/or tool settings will be placed here.
* Individual sections of the topbar are individually scrollable.
* Workspace tabs can be double- or ctrl-clicked for renaming and contain 'x' icon for deleting.
* Top-bar should scale nicely with DPI.
* The lower half of the top-bar can be hided by dragging the lower top-bar edge up. Better hiding options are planned (e.g. hide in fullscreen modes).
* Info editors at the top of the window and using the full window width with be replaced by the top-bar.
* In fullscreen modes, no more info editor is added on top, the top-bar replaces it.
== Technical Features/Changes
* Adds initial support for global areas
A global area is part of the window, not part of the regular screen-layout.
I've added a macro iterator to iterate over both, global and screen-layout level areas. When iterating over areas, from now on developers should always consider if they have to include global areas.
* Adds a TOPBAR editor type
The editor type is hidden in the UI editor type menu.
* Adds a variation of the ID template to display IDs as tab buttons (template_ID_tabs in BPY)
* Does various changes to RNA button creation code to improve their appearance in the horizontal top-bar.
* Adds support for dynamically sized regions. That is, regions that scale automatically to the layout bounds.
The code for this is currently a big hack (it's based on drawing the UI multiple times). This should definitely be improved.
* Adds a template for displaying operator properties optimized for the top-bar. This will probably change a lot still and is in fact disabled in code.
Since the final top-bar design depends a lot on other 2.8 designs (mainly tool-system and workspaces), we decided to not show the operator or tool settings in the top-bar for now. That means most of the lower sub-bar is empty for the time being.
NOTE: Top-bar or global area data is not written to files or SDNA. They are simply added to the window when opening Blender or reading a file. This allows us doing changes to the top-bar without having to care for compatibility.
== ToDo's
It's a bit hard to predict all the ToDo's here are the known main ones:
* Add options for the new active-tool system and for operator redo to the topbar.
* Automatically hide the top-bar in fullscreen modes.
* General visual polish.
* Top-bar drag & drop support (WIP in temp-tab_drag_drop).
* Improve dynamic regions (should also fix some layout glitches).
* Make internal terminology consistent.
* Enable topbar file writing once design is more advanced.
* Address TODO's and XXX's in code :)
Thanks @brecht for the review! And @sergey for the complaining ;)
Differential Revision: D2758
2018-04-20 17:14:03 +02:00
|
|
|
}
|
2009-03-13 13:38:41 +00:00
|
|
|
|
Templates for render output paths
This adds basic templating support to render output paths. By putting
"{variable_name}" in the path string, it will be replaced by the named
variable's value when generating the actual output path. This is similar
to how "//" is already substituted with the path to the blend file's
current directory.
This templating system is implemented for both the primary render output
path as well as the File Output node in the compositing nodes. Support
for using templates in other places can be implemented in future PRs.
In addition to the "{variable_name}" syntax, some additional syntax is
also supported:
- Since "{" and "}" now have special meaning, "{{" and "}}" are now
escape sequences for literal "{" and "}".
- "{variable_name:format_specifier}", where "format_specifier" is a
special syntax using "#", which allows the user to specify how numeric
variables should be formatted:
- "{variable_name:###}" will format the number as an integer with at
least 3 characters (padding with zeros as needed).
- "{variable_name:.##}" will format the number as a float with
precisely 2 fractional digits.
- "{variable_name:###.##}" will format the number as a float with at
least 3 characters for the integer part and precisely 2 for the
fractional part.
For the primary render output path: if there is a template syntax error,
a variable doesn't exist, or a format specifier isn't valid (e.g. trying
to format a string with "##"), the render that needs to write to the
output path fails with a descriptive error message.
For both the primary and File Output node paths: if there are template
syntax errors the field is highlighted in red in the UI, and a tooltip
describes the offending syntax errors. Note that these do *not* yet
reflect errors due to missing variables. That will be for a follow-up
PR.
In addition to the general system, this PR also implements a limited set
of variables for use in templates, but more can be implemented in future
PRs. The variables added in this PR are:
- `blend_name`: the name of the current blend file without the file
extension.
- `fps`: the frames per second of the current scene.
- `resolution_x` and `resolution_y`: the render output resolution.
Pull Request: https://projects.blender.org/blender/blender/pulls/134860
2025-05-08 15:37:28 +02:00
|
|
|
/* Highlight in red on path template validity errors. */
|
|
|
|
|
if (but != nullptr && ELEM(but->type, UI_BTYPE_TEXT)) {
|
|
|
|
|
/* We include PROP_NONE here because some plain string properties are used
|
|
|
|
|
* as parts of paths. For example, the sub-paths in the compositor's File
|
|
|
|
|
* Output node. */
|
|
|
|
|
if (ELEM(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_NONE)) {
|
|
|
|
|
if ((RNA_property_flag(prop) & PROP_PATH_SUPPORTS_TEMPLATES) != 0) {
|
Fix: Truncated filepath fields give incorrect path template errors
The Path Template errors reported in tooltips could be incorrect,
depending on whether the field was visually truncated in the UI or not.
For example, if you had a path `/tmp/{blend_name}{foo`, the error is
that the template expression `{foo` is unclosed. However, if the
available space for the field in the UI is too small, the displayed path
could end up as `/tmp/{blend_na...`. This is for display purposes only,
and shouldn't effect things like template errors. However, it did, and
the error checking would be run on that display string, and report that
`{blend_na...` is unclosed, which is incorrect.
The issue was that the code doing the live error checking for the UI was
using the display string because it was conveniently available.
This fixes the issue by properly querying the property value via RNA,
and using that.
Pull Request: https://projects.blender.org/blender/blender/pulls/139144
2025-05-20 11:26:51 +02:00
|
|
|
const std::string path = RNA_property_string_get(ptr, prop);
|
|
|
|
|
if (!BKE_validate_template_syntax(path.c_str()).is_empty()) {
|
Templates for render output paths
This adds basic templating support to render output paths. By putting
"{variable_name}" in the path string, it will be replaced by the named
variable's value when generating the actual output path. This is similar
to how "//" is already substituted with the path to the blend file's
current directory.
This templating system is implemented for both the primary render output
path as well as the File Output node in the compositing nodes. Support
for using templates in other places can be implemented in future PRs.
In addition to the "{variable_name}" syntax, some additional syntax is
also supported:
- Since "{" and "}" now have special meaning, "{{" and "}}" are now
escape sequences for literal "{" and "}".
- "{variable_name:format_specifier}", where "format_specifier" is a
special syntax using "#", which allows the user to specify how numeric
variables should be formatted:
- "{variable_name:###}" will format the number as an integer with at
least 3 characters (padding with zeros as needed).
- "{variable_name:.##}" will format the number as a float with
precisely 2 fractional digits.
- "{variable_name:###.##}" will format the number as a float with at
least 3 characters for the integer part and precisely 2 for the
fractional part.
For the primary render output path: if there is a template syntax error,
a variable doesn't exist, or a format specifier isn't valid (e.g. trying
to format a string with "##"), the render that needs to write to the
output path fails with a descriptive error message.
For both the primary and File Output node paths: if there are template
syntax errors the field is highlighted in red in the UI, and a tooltip
describes the offending syntax errors. Note that these do *not* yet
reflect errors due to missing variables. That will be for a follow-up
PR.
In addition to the general system, this PR also implements a limited set
of variables for use in templates, but more can be implemented in future
PRs. The variables added in this PR are:
- `blend_name`: the name of the current blend file without the file
extension.
- `fps`: the frames per second of the current scene.
- `resolution_x` and `resolution_y`: the render output resolution.
Pull Request: https://projects.blender.org/blender/blender/pulls/134860
2025-05-08 15:37:28 +02:00
|
|
|
UI_but_flag_enable(but, UI_BUT_REDALERT);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-23 14:58:08 +11:00
|
|
|
if (flag & UI_ITEM_R_IMMEDIATE) {
|
|
|
|
|
UI_but_flag_enable(but, UI_BUT_ACTIVATE_ON_INIT);
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-28 00:59:15 +10:00
|
|
|
#ifdef UI_PROP_DECORATE
|
2018-08-24 12:09:56 +10:00
|
|
|
/* Only for alignment. */
|
2020-08-05 16:50:33 +02:00
|
|
|
if (use_prop_decorate) { /* Note that sep flag may have been unset meanwhile. */
|
2025-05-08 17:21:08 +02:00
|
|
|
(layout_prop_decorate ? layout_prop_decorate : sub)->label(nullptr, ICON_BLANK1);
|
2018-08-30 20:41:40 +10:00
|
|
|
}
|
2018-08-28 00:59:15 +10:00
|
|
|
#endif /* UI_PROP_DECORATE */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-11-09 21:20:40 +01:00
|
|
|
UI_block_layout_set_current(block, layout);
|
2009-06-27 01:15:31 +00:00
|
|
|
return but;
|
2009-03-13 13:38:41 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-06-09 17:17:22 +10:00
|
|
|
void UI_context_active_but_prop_get_filebrowser(const bContext *C,
|
|
|
|
|
PointerRNA *r_ptr,
|
|
|
|
|
PropertyRNA **r_prop,
|
2020-06-11 17:24:00 +10:00
|
|
|
bool *r_is_undo,
|
2025-04-30 11:15:38 +00:00
|
|
|
bool *r_is_userdef)
|
2009-07-28 18:51:06 +00:00
|
|
|
{
|
2024-05-10 11:25:44 +10:00
|
|
|
ARegion *region = CTX_wm_region_popup(C) ? CTX_wm_region_popup(C) : CTX_wm_region(C);
|
2022-11-25 23:48:02 -06:00
|
|
|
uiBut *prevbut = nullptr;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-09-02 17:17:01 +02:00
|
|
|
*r_ptr = {};
|
2022-11-25 23:48:02 -06:00
|
|
|
*r_prop = nullptr;
|
2015-06-09 17:17:22 +10:00
|
|
|
*r_is_undo = false;
|
2020-06-11 17:24:00 +10:00
|
|
|
*r_is_userdef = false;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
if (!region) {
|
2009-07-28 18:51:06 +00:00
|
|
|
return;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-11-21 19:34:53 +01:00
|
|
|
LISTBASE_FOREACH (uiBlock *, block, ®ion->runtime->uiblocks) {
|
2025-02-14 15:29:26 +01:00
|
|
|
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
2019-01-02 19:22:56 +01:00
|
|
|
if (but && but->rnapoin.data) {
|
|
|
|
|
if (RNA_property_type(but->rnaprop) == PROP_STRING) {
|
2025-02-14 15:29:26 +01:00
|
|
|
prevbut = but.get();
|
2019-01-02 19:22:56 +01:00
|
|
|
}
|
|
|
|
|
}
|
2009-07-28 18:51:06 +00:00
|
|
|
/* find the button before the active one */
|
2019-01-02 19:22:56 +01:00
|
|
|
if ((but->flag & UI_BUT_LAST_ACTIVE) && prevbut) {
|
|
|
|
|
*r_ptr = prevbut->rnapoin;
|
|
|
|
|
*r_prop = prevbut->rnaprop;
|
|
|
|
|
*r_is_undo = (prevbut->flag & UI_BUT_UNDO) != 0;
|
2020-06-11 17:24:00 +10:00
|
|
|
*r_is_userdef = UI_but_is_userdef(prevbut);
|
2019-01-02 19:22:56 +01:00
|
|
|
return;
|
2009-07-28 18:51:06 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-06 16:12:47 +10:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Button Items
|
|
|
|
|
* \{ */
|
2009-03-13 13:38:41 +00:00
|
|
|
|
2013-02-05 05:39:18 +00:00
|
|
|
/**
|
|
|
|
|
* Update a buttons tip with an enum's description if possible.
|
|
|
|
|
*/
|
2016-02-16 14:50:26 +01:00
|
|
|
static void ui_but_tip_from_enum_item(uiBut *but, const EnumPropertyItem *item)
|
2013-02-05 05:39:18 +00:00
|
|
|
{
|
2022-11-25 23:48:02 -06:00
|
|
|
if (but->tip == nullptr || but->tip[0] == '\0') {
|
2019-09-09 21:12:47 +03:00
|
|
|
if (item->description && item->description[0] &&
|
2024-01-02 18:12:54 +01:00
|
|
|
!(but->optype && but->optype->get_description))
|
|
|
|
|
{
|
2013-02-05 05:39:18 +00:00
|
|
|
but->tip = item->description;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-22 18:39:44 +00:00
|
|
|
/* disabled item */
|
2010-11-17 09:45:45 +00:00
|
|
|
static void ui_item_disabled(uiLayout *layout, const char *name)
|
2009-04-22 18:39:44 +00:00
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
uiBlock *block = layout->root_->block;
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
|
2014-11-09 21:20:40 +01:00
|
|
|
UI_block_layout_set_current(block, layout);
|
2009-04-22 18:39:44 +00:00
|
|
|
|
2019-03-25 10:15:20 +11:00
|
|
|
if (!name) {
|
2012-03-30 01:51:25 +00:00
|
|
|
name = "";
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2009-04-22 18:39:44 +00:00
|
|
|
|
2022-12-29 12:01:32 -05:00
|
|
|
const int w = ui_text_icon_width(layout, name, 0, false);
|
2009-04-22 18:39:44 +00:00
|
|
|
|
2024-03-01 14:26:45 -05:00
|
|
|
uiBut *but = uiDefBut(block, UI_BTYPE_LABEL, 0, name, 0, 0, w, UI_UNIT_Y, nullptr, 0.0, 0.0, "");
|
2020-09-03 17:39:57 +02:00
|
|
|
UI_but_disable(but, "");
|
2009-04-22 18:39:44 +00:00
|
|
|
}
|
|
|
|
|
|
2017-10-31 16:58:26 +11:00
|
|
|
/**
|
|
|
|
|
* Operator Item
|
2022-11-25 23:48:02 -06:00
|
|
|
* \param r_opptr: Optional, initialize with operator properties when not nullptr.
|
2017-10-31 16:58:26 +11:00
|
|
|
* Will always be written to even in the case of errors.
|
|
|
|
|
*/
|
2017-11-02 04:30:07 +11:00
|
|
|
static uiBut *uiItemFullO_ptr_ex(uiLayout *layout,
|
2017-10-31 16:58:26 +11:00
|
|
|
wmOperatorType *ot,
|
2024-12-06 14:08:10 +01:00
|
|
|
std::optional<StringRef> name,
|
2017-10-31 16:58:26 +11:00
|
|
|
int icon,
|
2024-02-05 12:12:28 -05:00
|
|
|
const wmOperatorCallContext context,
|
2023-07-29 15:06:33 +10:00
|
|
|
const eUI_Item_Flag flag,
|
2017-10-31 16:58:26 +11:00
|
|
|
PointerRNA *r_opptr)
|
2009-03-13 13:38:41 +00:00
|
|
|
{
|
2017-10-31 16:58:26 +11:00
|
|
|
/* Take care to fill 'r_opptr' whatever happens. */
|
2025-04-23 16:37:14 +02:00
|
|
|
uiBlock *block = layout->root_->block;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-08-11 19:11:27 +02:00
|
|
|
std::string operator_name;
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!name) {
|
2019-03-25 10:15:20 +11:00
|
|
|
if (ot && ot->srna && (flag & UI_ITEM_R_ICON_ONLY) == 0) {
|
2023-08-11 19:11:27 +02:00
|
|
|
operator_name = WM_operatortype_name(ot, nullptr);
|
|
|
|
|
name = operator_name.c_str();
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
|
|
|
|
else {
|
2012-03-16 15:39:25 +00:00
|
|
|
name = "";
|
2011-09-15 13:20:18 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
if (layout->root_->type == UI_LAYOUT_MENU && !icon) {
|
2012-03-30 01:51:25 +00:00
|
|
|
icon = ICON_BLANK1;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-11-09 21:20:40 +01:00
|
|
|
UI_block_layout_set_current(block, layout);
|
2022-11-25 23:48:02 -06:00
|
|
|
ui_block_new_button_group(block, uiButtonGroupFlag(0));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-06 14:08:10 +01:00
|
|
|
const int w = ui_text_icon_width(layout, *name, icon, false);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-23 14:54:06 +02:00
|
|
|
const blender::ui::EmbossType prev_emboss = layout->emboss_;
|
2018-05-13 14:10:05 +02:00
|
|
|
if (flag & UI_ITEM_R_NO_BG) {
|
2025-04-23 14:54:06 +02:00
|
|
|
layout->emboss_ = blender::ui::EmbossType::NoneOrStatus;
|
2018-05-13 14:10:05 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-01-22 03:30:07 +00:00
|
|
|
/* create the button */
|
2020-10-02 13:02:30 -05:00
|
|
|
uiBut *but;
|
2012-03-24 06:38:07 +00:00
|
|
|
if (icon) {
|
2024-12-06 14:08:10 +01:00
|
|
|
if (!name->is_empty()) {
|
2014-11-09 21:20:40 +01:00
|
|
|
but = uiDefIconTextButO_ptr(
|
2025-02-14 15:12:48 -05:00
|
|
|
block, UI_BTYPE_BUT, ot, context, icon, *name, 0, 0, w, UI_UNIT_Y, std::nullopt);
|
2012-01-22 03:30:07 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2025-02-14 15:12:48 -05:00
|
|
|
but = uiDefIconButO_ptr(
|
|
|
|
|
block, UI_BTYPE_BUT, ot, context, icon, 0, 0, w, UI_UNIT_Y, std::nullopt);
|
2012-01-22 03:30:07 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2012-01-22 03:30:07 +00:00
|
|
|
else {
|
2025-02-14 15:12:48 -05:00
|
|
|
but = uiDefButO_ptr(block, UI_BTYPE_BUT, ot, context, *name, 0, 0, w, UI_UNIT_Y, std::nullopt);
|
2012-01-22 03:30:07 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-11-25 23:48:02 -06:00
|
|
|
BLI_assert(but->optype != nullptr);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-13 14:10:05 +02:00
|
|
|
if (flag & UI_ITEM_R_NO_BG) {
|
2025-04-23 14:54:06 +02:00
|
|
|
layout->emboss_ = prev_emboss;
|
2018-05-13 14:10:05 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-11-02 05:00:09 +11:00
|
|
|
if (flag & UI_ITEM_O_DEPRESS) {
|
2017-11-03 00:45:30 +11:00
|
|
|
but->flag |= UI_SELECT_DRAW;
|
2017-11-02 05:00:09 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-09-15 07:40:38 -06:00
|
|
|
if (flag & UI_ITEM_R_ICON_ONLY) {
|
|
|
|
|
UI_but_drawflag_disable(but, UI_BUT_ICON_LEFT);
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-23 14:54:06 +02:00
|
|
|
if (layout->redalert_) {
|
2014-11-09 21:20:40 +01:00
|
|
|
UI_but_flag_enable(but, UI_BUT_REDALERT);
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-23 14:54:06 +02:00
|
|
|
if (layout->active_default_) {
|
2019-03-27 21:39:44 +11:00
|
|
|
UI_but_flag_enable(but, UI_BUT_ACTIVE_DEFAULT);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
/* assign properties */
|
2025-05-22 16:26:46 -04:00
|
|
|
if (r_opptr) {
|
2024-01-29 10:19:05 -05:00
|
|
|
PointerRNA *opptr = UI_but_operator_ptr_ensure(but);
|
2025-05-22 16:26:46 -04:00
|
|
|
opptr->data = blender::bke::idprop::create_group("wmOperatorProperties").release();
|
|
|
|
|
*r_opptr = *opptr;
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-11-02 04:30:07 +11:00
|
|
|
return but;
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-25 23:48:02 -06:00
|
|
|
static void ui_item_menu_hold(bContext *C, ARegion *butregion, uiBut *but)
|
2017-11-02 04:30:07 +11:00
|
|
|
{
|
|
|
|
|
uiPopupMenu *pup = UI_popup_menu_begin(C, "", ICON_NONE);
|
|
|
|
|
uiLayout *layout = UI_popup_menu_layout(pup);
|
2025-04-23 16:37:14 +02:00
|
|
|
uiBlock *block = layout->root_->block;
|
2017-11-02 04:30:07 +11:00
|
|
|
UI_popup_menu_but_set(pup, butregion, but);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-11-02 04:30:07 +11:00
|
|
|
block->flag |= UI_BLOCK_POPUP_HOLD;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-04-25 20:41:26 +02:00
|
|
|
char direction = UI_DIR_DOWN;
|
2024-01-22 14:54:44 -05:00
|
|
|
if (but->drawstr.empty()) {
|
2020-01-16 15:55:49 +01:00
|
|
|
switch (RGN_ALIGN_ENUM_FROM_MASK(butregion->alignment)) {
|
|
|
|
|
case RGN_ALIGN_LEFT:
|
|
|
|
|
direction = UI_DIR_RIGHT;
|
|
|
|
|
break;
|
|
|
|
|
case RGN_ALIGN_RIGHT:
|
|
|
|
|
direction = UI_DIR_LEFT;
|
|
|
|
|
break;
|
|
|
|
|
case RGN_ALIGN_BOTTOM:
|
|
|
|
|
direction = UI_DIR_UP;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
direction = UI_DIR_DOWN;
|
|
|
|
|
break;
|
2018-04-25 20:41:26 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2014-11-09 21:20:40 +01:00
|
|
|
UI_block_direction_set(block, direction);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-11-25 23:48:02 -06:00
|
|
|
const char *menu_id = static_cast<const char *>(but->hold_argN);
|
2017-11-02 04:30:07 +11:00
|
|
|
MenuType *mt = WM_menutype_find(menu_id, true);
|
|
|
|
|
if (mt) {
|
2018-04-25 20:41:26 +02:00
|
|
|
uiLayoutSetContextFromBut(layout, but);
|
|
|
|
|
UI_menutype_draw(C, mt, layout);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2025-05-08 17:21:08 +02:00
|
|
|
layout->label(RPT_("Menu Missing:"), ICON_NONE);
|
|
|
|
|
layout->label(menu_id, ICON_NONE);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2017-11-02 04:30:07 +11:00
|
|
|
UI_popup_menu_end(C, pup);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2025-05-21 02:55:04 +02:00
|
|
|
PointerRNA uiLayout::op(wmOperatorType *ot,
|
|
|
|
|
std::optional<StringRef> name,
|
|
|
|
|
const int icon,
|
|
|
|
|
const wmOperatorCallContext context,
|
2025-05-22 20:19:18 +02:00
|
|
|
const eUI_Item_Flag flag)
|
2019-04-17 06:17:24 +02:00
|
|
|
{
|
2025-05-21 02:55:04 +02:00
|
|
|
PointerRNA ptr;
|
2025-05-22 16:26:46 -04:00
|
|
|
uiItemFullO_ptr_ex(this, ot, name, icon, context, flag, &ptr);
|
2025-05-21 02:55:04 +02:00
|
|
|
return ptr;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2017-11-02 04:30:07 +11:00
|
|
|
void uiItemFullOMenuHold_ptr(uiLayout *layout,
|
2016-02-16 14:50:26 +01:00
|
|
|
wmOperatorType *ot,
|
2024-12-06 14:08:10 +01:00
|
|
|
std::optional<StringRef> name,
|
2012-01-22 03:30:07 +00:00
|
|
|
int icon,
|
2024-02-05 12:12:28 -05:00
|
|
|
const wmOperatorCallContext context,
|
2023-07-29 15:06:33 +10:00
|
|
|
const eUI_Item_Flag flag,
|
2017-11-02 04:30:07 +11:00
|
|
|
const char *menu_id,
|
|
|
|
|
PointerRNA *r_opptr)
|
2019-04-17 06:17:24 +02:00
|
|
|
{
|
2025-05-22 16:26:46 -04:00
|
|
|
uiBut *but = uiItemFullO_ptr_ex(layout, ot, name, icon, context, flag, r_opptr);
|
2017-11-02 23:43:51 +11:00
|
|
|
UI_but_func_hold_set(but, ui_item_menu_hold, BLI_strdup(menu_id));
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2025-05-20 15:19:34 +02:00
|
|
|
PointerRNA uiLayout::op(const blender::StringRefNull opname,
|
|
|
|
|
const std::optional<StringRef> name,
|
|
|
|
|
int icon,
|
|
|
|
|
wmOperatorCallContext context,
|
|
|
|
|
const eUI_Item_Flag flag)
|
2017-11-02 04:30:07 +11:00
|
|
|
{
|
2024-12-06 14:08:10 +01:00
|
|
|
wmOperatorType *ot = WM_operatortype_find(opname.c_str(), false); /* print error next */
|
2025-05-20 15:19:34 +02:00
|
|
|
uiLayout *layout = this;
|
|
|
|
|
UI_OPERATOR_ERROR_RET(ot, opname.c_str(), { return PointerRNA_NULL; });
|
2025-05-21 02:55:04 +02:00
|
|
|
return this->op(ot, name, icon, context, flag);
|
2017-11-02 04:30:07 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-06 14:08:10 +01:00
|
|
|
static StringRef ui_menu_enumpropname(uiLayout *layout,
|
|
|
|
|
PointerRNA *ptr,
|
|
|
|
|
PropertyRNA *prop,
|
|
|
|
|
int retval)
|
2017-11-02 04:30:07 +11:00
|
|
|
{
|
|
|
|
|
bool free;
|
2020-10-02 13:02:30 -05:00
|
|
|
const EnumPropertyItem *item;
|
2022-11-25 23:48:02 -06:00
|
|
|
RNA_property_enum_items(
|
2025-04-23 16:37:14 +02:00
|
|
|
static_cast<bContext *>(layout->root_->block->evil_C), ptr, prop, &item, nullptr, &free);
|
2020-10-02 13:02:30 -05:00
|
|
|
|
|
|
|
|
const char *name;
|
2017-11-02 23:43:51 +11:00
|
|
|
if (RNA_enum_name(item, retval, &name)) {
|
2017-10-31 16:58:26 +11:00
|
|
|
name = CTX_IFACE_(RNA_property_translation_context(prop), name);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2009-04-22 18:39:44 +00:00
|
|
|
else {
|
2012-01-22 03:30:07 +00:00
|
|
|
name = "";
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2012-01-21 22:00:40 +00:00
|
|
|
if (free) {
|
2025-04-12 17:25:55 +02:00
|
|
|
MEM_freeN(item);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2012-01-22 11:59:30 +00:00
|
|
|
return name;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2012-01-22 03:30:07 +00:00
|
|
|
void uiItemEnumO_ptr(uiLayout *layout,
|
|
|
|
|
wmOperatorType *ot,
|
2024-12-06 14:08:10 +01:00
|
|
|
std::optional<StringRef> name,
|
2012-01-22 03:30:07 +00:00
|
|
|
int icon,
|
2024-12-06 14:08:10 +01:00
|
|
|
const StringRefNull propname,
|
2011-03-24 12:36:12 +00:00
|
|
|
int value)
|
2019-04-17 06:17:24 +02:00
|
|
|
{
|
2012-01-22 03:30:07 +00:00
|
|
|
PointerRNA ptr;
|
|
|
|
|
WM_operator_properties_create_ptr(&ptr, ot);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-06 14:08:10 +01:00
|
|
|
PropertyRNA *prop = RNA_struct_find_property(&ptr, propname.c_str());
|
2022-11-25 23:48:02 -06:00
|
|
|
if (prop == nullptr) {
|
2024-12-06 14:08:10 +01:00
|
|
|
RNA_warning("%s.%s not found", RNA_struct_identifier(ptr.type), propname.c_str());
|
2017-10-31 16:58:26 +11:00
|
|
|
return;
|
|
|
|
|
}
|
2024-12-06 14:08:10 +01:00
|
|
|
name = name.value_or(ui_menu_enumpropname(layout, &ptr, prop, value));
|
2012-01-22 19:52:41 +00:00
|
|
|
|
2025-05-22 20:19:18 +02:00
|
|
|
ptr = layout->op(ot, name, icon, layout->root_->opcontext, UI_ITEM_NONE);
|
|
|
|
|
RNA_property_enum_set(&ptr, prop, value);
|
2012-01-22 03:30:07 +00:00
|
|
|
}
|
|
|
|
|
void uiItemEnumO(uiLayout *layout,
|
2024-12-06 14:08:10 +01:00
|
|
|
const StringRefNull opname,
|
|
|
|
|
const std::optional<StringRef> name,
|
2012-01-22 03:30:07 +00:00
|
|
|
int icon,
|
2024-12-06 14:08:10 +01:00
|
|
|
const StringRefNull propname,
|
2012-01-22 03:30:07 +00:00
|
|
|
int value)
|
|
|
|
|
{
|
2024-12-06 14:08:10 +01:00
|
|
|
wmOperatorType *ot = WM_operatortype_find(opname.c_str(), false); /* print error next */
|
2009-04-22 18:39:44 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (ot) {
|
2012-01-22 03:30:07 +00:00
|
|
|
uiItemEnumO_ptr(layout, ot, name, icon, propname, value);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2024-12-06 14:08:10 +01:00
|
|
|
ui_item_disabled(layout, opname.c_str());
|
|
|
|
|
RNA_warning("unknown operator '%s'", opname.c_str());
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2009-03-13 13:38:41 +00:00
|
|
|
}
|
|
|
|
|
|
2016-02-16 14:50:26 +01:00
|
|
|
BLI_INLINE bool ui_layout_is_radial(const uiLayout *layout)
|
|
|
|
|
{
|
2025-04-24 17:22:28 +02:00
|
|
|
return (layout->type_ == uiItemType::LayoutRadial) ||
|
|
|
|
|
((layout->type_ == uiItemType::LayoutRoot) && (layout->root_->type == UI_LAYOUT_PIEMENU));
|
2016-02-16 14:50:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void uiItemsFullEnumO_items(uiLayout *layout,
|
|
|
|
|
wmOperatorType *ot,
|
2024-04-17 11:36:44 +10:00
|
|
|
const PointerRNA &ptr,
|
2016-02-16 14:50:26 +01:00
|
|
|
PropertyRNA *prop,
|
|
|
|
|
IDProperty *properties,
|
2021-11-05 14:56:22 +01:00
|
|
|
wmOperatorCallContext context,
|
2023-07-29 15:06:33 +10:00
|
|
|
eUI_Item_Flag flag,
|
2016-02-16 14:50:26 +01:00
|
|
|
const EnumPropertyItem *item_array,
|
2023-10-11 19:27:02 +02:00
|
|
|
int totitem,
|
|
|
|
|
int active)
|
2016-02-16 14:50:26 +01:00
|
|
|
{
|
2024-12-06 14:08:10 +01:00
|
|
|
const StringRefNull propname = RNA_property_identifier(prop);
|
2016-02-16 14:50:26 +01:00
|
|
|
if (RNA_property_type(prop) != PROP_ENUM) {
|
2024-12-06 14:08:10 +01:00
|
|
|
RNA_warning("%s.%s, not an enum type", RNA_struct_identifier(ptr.type), propname.c_str());
|
2016-02-16 14:50:26 +01:00
|
|
|
return;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-11-25 23:48:02 -06:00
|
|
|
uiLayout *target, *split = nullptr;
|
2025-04-23 16:37:14 +02:00
|
|
|
uiBlock *block = layout->root_->block;
|
2016-02-16 14:50:26 +01:00
|
|
|
const bool radial = ui_layout_is_radial(layout);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-02-16 14:50:26 +01:00
|
|
|
if (radial) {
|
2025-05-07 23:29:49 +02:00
|
|
|
target = &layout->menu_pie();
|
2016-02-16 14:50:26 +01:00
|
|
|
}
|
2020-09-15 07:19:57 -06:00
|
|
|
else if ((uiLayoutGetLocalDir(layout) == UI_LAYOUT_HORIZONTAL) && (flag & UI_ITEM_R_ICON_ONLY)) {
|
|
|
|
|
target = layout;
|
|
|
|
|
UI_block_layout_set_current(block, target);
|
|
|
|
|
|
|
|
|
|
/* Add a blank button to the beginning of the row. */
|
|
|
|
|
uiDefIconBut(block,
|
|
|
|
|
UI_BTYPE_LABEL,
|
|
|
|
|
0,
|
|
|
|
|
ICON_BLANK1,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
1.25f * UI_UNIT_X,
|
|
|
|
|
UI_UNIT_Y,
|
2022-11-25 23:48:02 -06:00
|
|
|
nullptr,
|
2020-09-15 07:19:57 -06:00
|
|
|
0,
|
|
|
|
|
0,
|
2025-02-14 15:12:48 -05:00
|
|
|
std::nullopt);
|
2020-09-15 07:19:57 -06:00
|
|
|
}
|
2016-02-16 14:50:26 +01:00
|
|
|
else {
|
2025-05-03 20:51:42 +02:00
|
|
|
split = &layout->split(0.0f, false);
|
2025-04-26 21:07:34 +02:00
|
|
|
target = &split->column(layout->align_);
|
2016-02-16 14:50:26 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-02-16 14:50:26 +01:00
|
|
|
bool last_iter = false;
|
2020-10-02 13:02:30 -05:00
|
|
|
const EnumPropertyItem *item = item_array;
|
|
|
|
|
for (int i = 1; item->identifier && !last_iter; i++, item++) {
|
2022-12-08 12:36:04 +11:00
|
|
|
/* Handle over-sized pies. */
|
2016-02-16 14:50:26 +01:00
|
|
|
if (radial && (totitem > PIE_MAX_ITEMS) && (i >= PIE_MAX_ITEMS)) {
|
|
|
|
|
if (item->name) { /* only visible items */
|
|
|
|
|
const EnumPropertyItem *tmp;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-02-16 14:50:26 +01:00
|
|
|
/* Check if there are more visible items for the next level. If not, we don't
|
|
|
|
|
* add a new level and add the remaining item instead of the 'more' button. */
|
2019-03-25 10:15:20 +11:00
|
|
|
for (tmp = item + 1; tmp->identifier; tmp++) {
|
|
|
|
|
if (tmp->name) {
|
2016-02-16 14:50:26 +01:00
|
|
|
break;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-02-16 14:50:26 +01:00
|
|
|
if (tmp->identifier) { /* only true if loop above found item and did early-exit */
|
2023-07-29 14:52:47 +10:00
|
|
|
ui_pie_menu_level_create(
|
|
|
|
|
block, ot, propname, properties, item_array, totitem, context, flag);
|
2016-02-16 14:50:26 +01:00
|
|
|
/* break since rest of items is handled in new pie level */
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-07-03 14:20:10 +02:00
|
|
|
last_iter = true;
|
2016-02-16 14:50:26 +01:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
continue;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2016-02-16 14:50:26 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-02-16 14:50:26 +01:00
|
|
|
if (item->identifier[0]) {
|
2025-05-22 20:19:18 +02:00
|
|
|
PointerRNA tptr = target->op(
|
|
|
|
|
ot, (flag & UI_ITEM_R_ICON_ONLY) ? nullptr : item->name, item->icon, context, flag);
|
2016-02-16 14:50:26 +01:00
|
|
|
if (properties) {
|
2025-05-22 20:19:18 +02:00
|
|
|
IDP_CopyPropertyContent(tptr.data_as<IDProperty>(), properties);
|
2016-02-16 14:50:26 +01:00
|
|
|
}
|
|
|
|
|
RNA_property_enum_set(&tptr, prop, item->value);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-02-14 15:29:26 +01:00
|
|
|
uiBut *but = block->buttons.last().get();
|
2023-10-11 19:27:02 +02:00
|
|
|
|
|
|
|
|
if (active == (i - 1)) {
|
|
|
|
|
but->flag |= UI_SELECT_DRAW;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ui_but_tip_from_enum_item(but, item);
|
2016-02-16 14:50:26 +01:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (item->name) {
|
2022-11-25 23:48:02 -06:00
|
|
|
if (item != item_array && !radial && split != nullptr) {
|
2025-04-26 21:07:34 +02:00
|
|
|
target = &split->column(layout->align_);
|
2016-02-16 14:50:26 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-02 13:02:30 -05:00
|
|
|
uiBut *but;
|
2016-02-16 14:50:26 +01:00
|
|
|
if (item->icon || radial) {
|
2025-05-08 17:21:08 +02:00
|
|
|
target->label(item->name, item->icon);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-02-14 15:29:26 +01:00
|
|
|
but = block->buttons.last().get();
|
2016-02-16 14:50:26 +01:00
|
|
|
}
|
|
|
|
|
else {
|
2025-05-08 17:21:08 +02:00
|
|
|
/* Do not use uiLayout::label here, as our root layout is a menu one,
|
2019-01-15 23:24:20 +11:00
|
|
|
* it will add a fake blank icon! */
|
2018-07-01 19:57:31 +02:00
|
|
|
but = uiDefBut(block,
|
|
|
|
|
UI_BTYPE_LABEL,
|
|
|
|
|
0,
|
|
|
|
|
item->name,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
UI_UNIT_X * 5,
|
|
|
|
|
UI_UNIT_Y,
|
2022-11-25 23:48:02 -06:00
|
|
|
nullptr,
|
2018-07-01 19:57:31 +02:00
|
|
|
0.0,
|
|
|
|
|
0.0,
|
|
|
|
|
"");
|
2025-05-13 17:54:26 +02:00
|
|
|
target->separator();
|
2016-02-16 14:50:26 +01:00
|
|
|
}
|
|
|
|
|
ui_but_tip_from_enum_item(but, item);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (radial) {
|
2019-01-15 23:24:20 +11:00
|
|
|
/* invisible dummy button to ensure all items are
|
|
|
|
|
* always at the same position */
|
2025-05-13 17:54:26 +02:00
|
|
|
target->separator();
|
2016-02-16 14:50:26 +01:00
|
|
|
}
|
|
|
|
|
else {
|
2018-09-27 15:35:22 +02:00
|
|
|
/* XXX bug here, columns draw bottom item badly */
|
2025-05-13 17:54:26 +02:00
|
|
|
target->separator();
|
2016-02-16 14:50:26 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-05 03:13:47 +10:00
|
|
|
void uiItemsFullEnumO(uiLayout *layout,
|
2024-12-06 14:08:10 +01:00
|
|
|
const StringRefNull opname,
|
|
|
|
|
const StringRefNull propname,
|
2015-05-05 03:13:47 +10:00
|
|
|
IDProperty *properties,
|
2021-11-05 14:56:22 +01:00
|
|
|
wmOperatorCallContext context,
|
2023-10-11 19:27:02 +02:00
|
|
|
eUI_Item_Flag flag,
|
|
|
|
|
const int active)
|
2009-03-13 13:38:41 +00:00
|
|
|
{
|
2024-12-06 14:08:10 +01:00
|
|
|
wmOperatorType *ot = WM_operatortype_find(opname.c_str(), false); /* print error next */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!ot || !ot->srna) {
|
2024-12-06 14:08:10 +01:00
|
|
|
ui_item_disabled(layout, opname.c_str());
|
|
|
|
|
RNA_warning("%s '%s'", ot ? "operator missing srna" : "unknown operator", opname.c_str());
|
2009-03-13 13:38:41 +00:00
|
|
|
return;
|
2009-04-22 18:39:44 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-02 13:02:30 -05:00
|
|
|
PointerRNA ptr;
|
Fix for [#35224] Transform Orientation - order inconsistency
Fix turned out to remove as much "manual UI" from 3D view header as possible. Mode selector and all transform manipulators/orientations stuff are now RNA-based UI (leaving basically only edit mesh select modes with custom handlers, as they have some quite specific features).
To achieve this, four main modifications were done:
* enum-operator-generated menus are now MENU (i.e. dropdown lists) in headers too.
* All bit-flag enums expanded in ROW buttons now have a handling consistent with e.g. layers, or what we already have for transform manipulators, i.e. clicking select only one element, shift-click to select multiple ones.
* Consequently, the three RNA booleans manipulators flags are merged into a single bit-flag enum (yes, this is also an API change, though I doubt many scripts use it).
* Now the width of enum-based dropdown lists is computed from longest item name in enum, no more from a dummy place holder string (when no label/name is given).
All this allows to remove some code from 3DView/transform areas, that was actually mostly duplicating RNA/operator one.
Also done a few optimizations here and there (among others, do not pass &numitems to RNA_property_enum_items() when you do not need it, saves at least an iteration over enum items to count them).
Many thanks to Brecht for the reviews!
2013-05-12 13:16:11 +00:00
|
|
|
WM_operator_properties_create_ptr(&ptr, ot);
|
|
|
|
|
/* so the context is passed to itemf functions (some need it) */
|
|
|
|
|
WM_operator_properties_sanitize(&ptr, false);
|
2024-12-06 14:08:10 +01:00
|
|
|
PropertyRNA *prop = RNA_struct_find_property(&ptr, propname.c_str());
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-05-25 10:07:59 +00:00
|
|
|
/* don't let bad properties slip through */
|
2022-11-25 23:48:02 -06:00
|
|
|
BLI_assert((prop == nullptr) || (RNA_property_type(prop) == PROP_ENUM));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
uiBlock *block = layout->root_->block;
|
2012-03-24 06:38:07 +00:00
|
|
|
if (prop && RNA_property_type(prop) == PROP_ENUM) {
|
2022-11-25 23:48:02 -06:00
|
|
|
const EnumPropertyItem *item_array = nullptr;
|
2016-02-16 14:50:26 +01:00
|
|
|
int totitem;
|
2014-01-04 18:08:43 +11:00
|
|
|
bool free;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-02-16 14:50:26 +01:00
|
|
|
if (ui_layout_is_radial(layout)) {
|
2019-04-17 08:44:38 +02:00
|
|
|
/* XXX: While "_all()" guarantees spatial stability,
|
|
|
|
|
* it's bad when an enum has > 8 items total,
|
|
|
|
|
* but only a small subset will ever be shown at once
|
|
|
|
|
* (e.g. Mode Switch menu, after the introduction of GP editing modes).
|
2018-07-31 10:22:19 +02:00
|
|
|
*/
|
|
|
|
|
#if 0
|
2019-04-17 08:24:14 +02:00
|
|
|
RNA_property_enum_items_gettexted_all(
|
2023-07-12 14:18:59 +02:00
|
|
|
static_cast<bContext *>(block->evil_C), &ptr, prop, &item_array, &totitem, &free);
|
2018-07-31 10:22:19 +02:00
|
|
|
#else
|
2022-11-25 23:48:02 -06:00
|
|
|
RNA_property_enum_items_gettexted(
|
|
|
|
|
static_cast<bContext *>(block->evil_C), &ptr, prop, &item_array, &totitem, &free);
|
2018-07-31 10:22:19 +02:00
|
|
|
#endif
|
Pie Menus C code backend.
This commit merges the code in the pie-menu branch.
As per decisions taken the last few days, there are no pie menus
included and there will be an official add-on including overrides of
some keys with pie menus. However, people will now be able to use the
new code in python.
Full Documentation is in http://wiki.blender.org/index.php/Dev:Ref/
Thanks:
Campbell Barton, Dalai Felinto and Ton Roosendaal for the code review
and design comments
Jonathan Williamson, Pawel Lyczkowski, Pablo Vazquez among others for
suggestions during the development.
Special Thanks to Sean Olson, for his support, suggestions, testing and
merciless bugging so that I would finish the pie menu code. Without him
we wouldn't be here. Also to the rest of the developers of the original
python add-on, Patrick Moore and Dan Eicher and finally to Matt Ebb, who
did the research and first implementation and whose code I used to get
started.
2014-08-11 10:39:59 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2023-04-03 18:23:30 +02:00
|
|
|
bContext *C = static_cast<bContext *>(block->evil_C);
|
2023-08-31 11:59:58 -04:00
|
|
|
const bContextStore *previous_ctx = CTX_store_get(C);
|
2025-04-23 16:37:14 +02:00
|
|
|
CTX_store_set(C, layout->context_);
|
2023-04-03 18:23:30 +02:00
|
|
|
RNA_property_enum_items_gettexted(C, &ptr, prop, &item_array, &totitem, &free);
|
|
|
|
|
CTX_store_set(C, previous_ctx);
|
Pie Menus C code backend.
This commit merges the code in the pie-menu branch.
As per decisions taken the last few days, there are no pie menus
included and there will be an official add-on including overrides of
some keys with pie menus. However, people will now be able to use the
new code in python.
Full Documentation is in http://wiki.blender.org/index.php/Dev:Ref/
Thanks:
Campbell Barton, Dalai Felinto and Ton Roosendaal for the code review
and design comments
Jonathan Williamson, Pawel Lyczkowski, Pablo Vazquez among others for
suggestions during the development.
Special Thanks to Sean Olson, for his support, suggestions, testing and
merciless bugging so that I would finish the pie menu code. Without him
we wouldn't be here. Also to the rest of the developers of the original
python add-on, Patrick Moore and Dan Eicher and finally to Matt Ebb, who
did the research and first implementation and whose code I used to get
started.
2014-08-11 10:39:59 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-02-16 14:50:26 +01:00
|
|
|
/* add items */
|
2023-10-11 19:27:02 +02:00
|
|
|
uiItemsFullEnumO_items(
|
|
|
|
|
layout, ot, ptr, prop, properties, context, flag, item_array, totitem, active);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-01-21 22:00:40 +00:00
|
|
|
if (free) {
|
2025-04-12 17:25:55 +02:00
|
|
|
MEM_freeN(item_array);
|
2012-01-21 22:00:40 +00:00
|
|
|
}
|
2009-03-13 13:38:41 +00:00
|
|
|
}
|
2012-06-21 20:14:27 +00:00
|
|
|
else if (prop && RNA_property_type(prop) != PROP_ENUM) {
|
2024-12-06 14:08:10 +01:00
|
|
|
RNA_warning("%s.%s, not an enum type", RNA_struct_identifier(ptr.type), propname.c_str());
|
2012-06-21 20:14:27 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else {
|
2024-12-06 14:08:10 +01:00
|
|
|
RNA_warning("%s.%s not found", RNA_struct_identifier(ptr.type), propname.c_str());
|
2012-06-21 20:14:27 +00:00
|
|
|
return;
|
|
|
|
|
}
|
2009-03-13 13:38:41 +00:00
|
|
|
}
|
|
|
|
|
|
2024-12-06 14:08:10 +01:00
|
|
|
void uiItemsEnumO(uiLayout *layout, const StringRefNull opname, const StringRefNull propname)
|
2009-12-22 11:59:30 +00:00
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
uiItemsFullEnumO(layout, opname, propname, nullptr, layout->root_->opcontext, UI_ITEM_NONE);
|
2009-12-22 11:59:30 +00:00
|
|
|
}
|
|
|
|
|
|
2011-03-24 12:36:12 +00:00
|
|
|
void uiItemEnumO_value(uiLayout *layout,
|
2024-12-06 14:08:10 +01:00
|
|
|
const StringRefNull name,
|
2011-03-24 12:36:12 +00:00
|
|
|
int icon,
|
2024-12-06 14:08:10 +01:00
|
|
|
const StringRefNull opname,
|
|
|
|
|
const StringRefNull propname,
|
2011-03-24 12:36:12 +00:00
|
|
|
int value)
|
|
|
|
|
{
|
2024-12-06 14:08:10 +01:00
|
|
|
wmOperatorType *ot = WM_operatortype_find(opname.c_str(), false); /* print error next */
|
|
|
|
|
UI_OPERATOR_ERROR_RET(ot, opname.c_str(), return);
|
2012-01-22 03:30:07 +00:00
|
|
|
|
2020-10-02 13:02:30 -05:00
|
|
|
PointerRNA ptr;
|
2012-01-22 03:30:07 +00:00
|
|
|
WM_operator_properties_create_ptr(&ptr, ot);
|
2011-03-24 12:36:12 +00:00
|
|
|
|
|
|
|
|
/* enum lookup */
|
2024-12-06 14:08:10 +01:00
|
|
|
PropertyRNA *prop = RNA_struct_find_property(&ptr, propname.c_str());
|
2022-11-25 23:48:02 -06:00
|
|
|
if (prop == nullptr) {
|
2024-12-06 14:08:10 +01:00
|
|
|
RNA_warning("%s.%s not found", RNA_struct_identifier(ptr.type), propname.c_str());
|
2011-03-24 12:36:12 +00:00
|
|
|
return;
|
|
|
|
|
}
|
2025-05-22 20:19:18 +02:00
|
|
|
ptr = layout->op(ot, name, icon, layout->root_->opcontext, UI_ITEM_NONE);
|
2011-03-24 12:36:12 +00:00
|
|
|
RNA_property_enum_set(&ptr, prop, value);
|
|
|
|
|
}
|
|
|
|
|
|
2010-12-03 17:05:21 +00:00
|
|
|
void uiItemEnumO_string(uiLayout *layout,
|
2024-12-06 14:08:10 +01:00
|
|
|
const StringRef name,
|
2010-12-03 17:05:21 +00:00
|
|
|
int icon,
|
2024-12-06 14:08:10 +01:00
|
|
|
const StringRefNull opname,
|
|
|
|
|
const StringRefNull propname,
|
2010-12-03 17:05:21 +00:00
|
|
|
const char *value_str)
|
2009-06-07 14:53:08 +00:00
|
|
|
{
|
2024-12-06 14:08:10 +01:00
|
|
|
wmOperatorType *ot = WM_operatortype_find(opname.c_str(), false); /* print error next */
|
|
|
|
|
UI_OPERATOR_ERROR_RET(ot, opname.c_str(), return);
|
2012-01-22 03:30:07 +00:00
|
|
|
|
2020-10-02 13:02:30 -05:00
|
|
|
PointerRNA ptr;
|
2012-01-22 03:30:07 +00:00
|
|
|
WM_operator_properties_create_ptr(&ptr, ot);
|
2012-12-18 18:25:48 +00:00
|
|
|
|
2024-12-06 14:08:10 +01:00
|
|
|
PropertyRNA *prop = RNA_struct_find_property(&ptr, propname.c_str());
|
2022-11-25 23:48:02 -06:00
|
|
|
if (prop == nullptr) {
|
2024-12-06 14:08:10 +01:00
|
|
|
RNA_warning("%s.%s not found", RNA_struct_identifier(ptr.type), propname.c_str());
|
2020-10-02 13:02:30 -05:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2009-06-09 05:39:01 +00:00
|
|
|
/* enum lookup */
|
2020-10-02 13:02:30 -05:00
|
|
|
/* no need for translations here */
|
|
|
|
|
const EnumPropertyItem *item;
|
|
|
|
|
bool free;
|
2022-11-25 23:48:02 -06:00
|
|
|
RNA_property_enum_items(
|
2025-04-23 16:37:14 +02:00
|
|
|
static_cast<bContext *>(layout->root_->block->evil_C), &ptr, prop, &item, nullptr, &free);
|
RNA
* Enums can now be dynamically created in the _itemf callback,
using RNA_enum_item(s)_add, RNA_enum_item_end. All places asking
for enum items now need to potentially free the items.
* This callback now also gets context, this was added specifically
for operators. This doesn't fit design well at all, needed to do
some ugly hacks, but can't find a good solution at the moment.
* All enums must have a default list of items too, even with an
_itemf callback, for docs and fallback in case there is no context.
* Used by MESH_OT_merge, MESH_OT_select_similar, TFM_OT_select_orientation.
* Also changes some operator properties that were enums to booleas
(unselected, deselect), to make them consistent with other ops.
2009-07-10 19:56:13 +00:00
|
|
|
|
2020-10-02 13:02:30 -05:00
|
|
|
int value;
|
2022-11-25 23:48:02 -06:00
|
|
|
if (item == nullptr || RNA_enum_value_from_id(item, value_str, &value) == 0) {
|
2012-01-21 22:00:40 +00:00
|
|
|
if (free) {
|
2025-04-12 17:25:55 +02:00
|
|
|
MEM_freeN(item);
|
2012-01-21 22:00:40 +00:00
|
|
|
}
|
2024-12-06 14:08:10 +01:00
|
|
|
RNA_warning(
|
|
|
|
|
"%s.%s, enum %s not found", RNA_struct_identifier(ptr.type), propname.c_str(), value_str);
|
2009-06-07 14:53:08 +00:00
|
|
|
return;
|
|
|
|
|
}
|
2012-12-18 18:25:48 +00:00
|
|
|
|
2020-10-02 13:02:30 -05:00
|
|
|
if (free) {
|
2025-04-12 17:25:55 +02:00
|
|
|
MEM_freeN(item);
|
2020-10-02 13:02:30 -05:00
|
|
|
}
|
2025-05-22 20:19:18 +02:00
|
|
|
ptr = layout->op(ot, name, icon, layout->root_->opcontext, UI_ITEM_NONE);
|
2009-06-09 05:39:01 +00:00
|
|
|
RNA_property_enum_set(&ptr, prop, value);
|
2009-06-07 14:53:08 +00:00
|
|
|
}
|
|
|
|
|
|
2010-12-03 17:05:21 +00:00
|
|
|
void uiItemStringO(uiLayout *layout,
|
2024-12-06 14:08:10 +01:00
|
|
|
const std::optional<StringRef> name,
|
2010-12-03 17:05:21 +00:00
|
|
|
int icon,
|
2024-12-06 14:08:10 +01:00
|
|
|
const StringRefNull opname,
|
|
|
|
|
const StringRefNull propname,
|
2010-12-03 17:05:21 +00:00
|
|
|
const char *value)
|
2009-03-13 13:38:41 +00:00
|
|
|
{
|
2025-05-22 20:19:18 +02:00
|
|
|
PointerRNA ptr = layout->op(opname, name, icon, layout->root_->opcontext, UI_ITEM_NONE);
|
|
|
|
|
if (RNA_pointer_is_null(&ptr)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2024-12-06 14:08:10 +01:00
|
|
|
RNA_string_set(&ptr, propname.c_str(), value);
|
2009-03-13 13:38:41 +00:00
|
|
|
}
|
|
|
|
|
|
2025-05-24 16:15:51 +02:00
|
|
|
PointerRNA uiLayout::op(wmOperatorType *ot, const std::optional<StringRef> name, int icon)
|
|
|
|
|
{
|
|
|
|
|
return this->op(ot, name, icon, root_->opcontext, UI_ITEM_NONE);
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-23 01:07:12 +02:00
|
|
|
PointerRNA uiLayout::op(const StringRefNull opname, const std::optional<StringRef> name, int icon)
|
2009-03-13 13:38:41 +00:00
|
|
|
{
|
2025-05-23 01:07:12 +02:00
|
|
|
return this->op(opname, name, icon, root_->opcontext, UI_ITEM_NONE);
|
2009-03-13 13:38:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* RNA property items */
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
|
2015-05-05 03:13:47 +10:00
|
|
|
static void ui_item_rna_size(uiLayout *layout,
|
2024-12-06 14:08:10 +01:00
|
|
|
StringRef name,
|
UI: New Global Top-Bar (WIP)
== Main Features/Changes for Users
* Add horizontal bar at top of all non-temp windows, consisting out of two horizontal sub-bars.
* Upper sub-bar contains global menus (File, Render, etc.), tabs for workspaces and scene selector.
* Lower sub-bar contains object mode selector, screen-layout and render-layer selector. Later operator and/or tool settings will be placed here.
* Individual sections of the topbar are individually scrollable.
* Workspace tabs can be double- or ctrl-clicked for renaming and contain 'x' icon for deleting.
* Top-bar should scale nicely with DPI.
* The lower half of the top-bar can be hided by dragging the lower top-bar edge up. Better hiding options are planned (e.g. hide in fullscreen modes).
* Info editors at the top of the window and using the full window width with be replaced by the top-bar.
* In fullscreen modes, no more info editor is added on top, the top-bar replaces it.
== Technical Features/Changes
* Adds initial support for global areas
A global area is part of the window, not part of the regular screen-layout.
I've added a macro iterator to iterate over both, global and screen-layout level areas. When iterating over areas, from now on developers should always consider if they have to include global areas.
* Adds a TOPBAR editor type
The editor type is hidden in the UI editor type menu.
* Adds a variation of the ID template to display IDs as tab buttons (template_ID_tabs in BPY)
* Does various changes to RNA button creation code to improve their appearance in the horizontal top-bar.
* Adds support for dynamically sized regions. That is, regions that scale automatically to the layout bounds.
The code for this is currently a big hack (it's based on drawing the UI multiple times). This should definitely be improved.
* Adds a template for displaying operator properties optimized for the top-bar. This will probably change a lot still and is in fact disabled in code.
Since the final top-bar design depends a lot on other 2.8 designs (mainly tool-system and workspaces), we decided to not show the operator or tool settings in the top-bar for now. That means most of the lower sub-bar is empty for the time being.
NOTE: Top-bar or global area data is not written to files or SDNA. They are simply added to the window when opening Blender or reading a file. This allows us doing changes to the top-bar without having to care for compatibility.
== ToDo's
It's a bit hard to predict all the ToDo's here are the known main ones:
* Add options for the new active-tool system and for operator redo to the topbar.
* Automatically hide the top-bar in fullscreen modes.
* General visual polish.
* Top-bar drag & drop support (WIP in temp-tab_drag_drop).
* Improve dynamic regions (should also fix some layout glitches).
* Make internal terminology consistent.
* Enable topbar file writing once design is more advanced.
* Address TODO's and XXX's in code :)
Thanks @brecht for the review! And @sergey for the complaining ;)
Differential Revision: D2758
2018-04-20 17:14:03 +02:00
|
|
|
int icon,
|
|
|
|
|
PointerRNA *ptr,
|
|
|
|
|
PropertyRNA *prop,
|
|
|
|
|
int index,
|
|
|
|
|
bool icon_only,
|
|
|
|
|
bool compact,
|
|
|
|
|
int *r_w,
|
|
|
|
|
int *r_h)
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
{
|
2020-10-02 13:02:30 -05:00
|
|
|
int w = 0, h;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
/* arbitrary extended width by type */
|
2021-01-04 17:02:13 +11:00
|
|
|
const PropertyType type = RNA_property_type(prop);
|
|
|
|
|
const PropertySubType subtype = RNA_property_subtype(prop);
|
2020-10-02 13:02:30 -05:00
|
|
|
const int len = RNA_property_array_length(ptr, prop);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-02 13:02:30 -05:00
|
|
|
bool is_checkbox_only = false;
|
2024-12-06 14:08:10 +01:00
|
|
|
if (name.is_empty() && !icon_only) {
|
Fix for [#35224] Transform Orientation - order inconsistency
Fix turned out to remove as much "manual UI" from 3D view header as possible. Mode selector and all transform manipulators/orientations stuff are now RNA-based UI (leaving basically only edit mesh select modes with custom handlers, as they have some quite specific features).
To achieve this, four main modifications were done:
* enum-operator-generated menus are now MENU (i.e. dropdown lists) in headers too.
* All bit-flag enums expanded in ROW buttons now have a handling consistent with e.g. layers, or what we already have for transform manipulators, i.e. clicking select only one element, shift-click to select multiple ones.
* Consequently, the three RNA booleans manipulators flags are merged into a single bit-flag enum (yes, this is also an API change, though I doubt many scripts use it).
* Now the width of enum-based dropdown lists is computed from longest item name in enum, no more from a dummy place holder string (when no label/name is given).
All this allows to remove some code from 3DView/transform areas, that was actually mostly duplicating RNA/operator one.
Also done a few optimizations here and there (among others, do not pass &numitems to RNA_property_enum_items() when you do not need it, saves at least an iteration over enum items to count them).
Many thanks to Brecht for the reviews!
2013-05-12 13:16:11 +00:00
|
|
|
if (ELEM(type, PROP_STRING, PROP_POINTER)) {
|
|
|
|
|
name = "non-empty text";
|
|
|
|
|
}
|
|
|
|
|
else if (type == PROP_BOOLEAN) {
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
if (icon == ICON_NONE) {
|
2021-07-05 12:47:46 +10:00
|
|
|
/* Exception for check-boxes, they need a little less space to align nicely. */
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
is_checkbox_only = true;
|
|
|
|
|
}
|
Fix for [#35224] Transform Orientation - order inconsistency
Fix turned out to remove as much "manual UI" from 3D view header as possible. Mode selector and all transform manipulators/orientations stuff are now RNA-based UI (leaving basically only edit mesh select modes with custom handlers, as they have some quite specific features).
To achieve this, four main modifications were done:
* enum-operator-generated menus are now MENU (i.e. dropdown lists) in headers too.
* All bit-flag enums expanded in ROW buttons now have a handling consistent with e.g. layers, or what we already have for transform manipulators, i.e. clicking select only one element, shift-click to select multiple ones.
* Consequently, the three RNA booleans manipulators flags are merged into a single bit-flag enum (yes, this is also an API change, though I doubt many scripts use it).
* Now the width of enum-based dropdown lists is computed from longest item name in enum, no more from a dummy place holder string (when no label/name is given).
All this allows to remove some code from 3DView/transform areas, that was actually mostly duplicating RNA/operator one.
Also done a few optimizations here and there (among others, do not pass &numitems to RNA_property_enum_items() when you do not need it, saves at least an iteration over enum items to count them).
Many thanks to Brecht for the reviews!
2013-05-12 13:16:11 +00:00
|
|
|
icon = ICON_DOT;
|
|
|
|
|
}
|
|
|
|
|
else if (type == PROP_ENUM) {
|
|
|
|
|
/* Find the longest enum item name, instead of using a dummy text! */
|
2020-10-02 13:02:30 -05:00
|
|
|
const EnumPropertyItem *item_array;
|
2014-01-04 18:08:43 +11:00
|
|
|
bool free;
|
2025-04-23 16:37:14 +02:00
|
|
|
RNA_property_enum_items_gettexted(static_cast<bContext *>(layout->root_->block->evil_C),
|
2022-11-25 23:48:02 -06:00
|
|
|
ptr,
|
|
|
|
|
prop,
|
|
|
|
|
&item_array,
|
|
|
|
|
nullptr,
|
|
|
|
|
&free);
|
2020-10-02 13:02:30 -05:00
|
|
|
|
|
|
|
|
for (const EnumPropertyItem *item = item_array; item->identifier; item++) {
|
Fix for [#35224] Transform Orientation - order inconsistency
Fix turned out to remove as much "manual UI" from 3D view header as possible. Mode selector and all transform manipulators/orientations stuff are now RNA-based UI (leaving basically only edit mesh select modes with custom handlers, as they have some quite specific features).
To achieve this, four main modifications were done:
* enum-operator-generated menus are now MENU (i.e. dropdown lists) in headers too.
* All bit-flag enums expanded in ROW buttons now have a handling consistent with e.g. layers, or what we already have for transform manipulators, i.e. clicking select only one element, shift-click to select multiple ones.
* Consequently, the three RNA booleans manipulators flags are merged into a single bit-flag enum (yes, this is also an API change, though I doubt many scripts use it).
* Now the width of enum-based dropdown lists is computed from longest item name in enum, no more from a dummy place holder string (when no label/name is given).
All this allows to remove some code from 3DView/transform areas, that was actually mostly duplicating RNA/operator one.
Also done a few optimizations here and there (among others, do not pass &numitems to RNA_property_enum_items() when you do not need it, saves at least an iteration over enum items to count them).
Many thanks to Brecht for the reviews!
2013-05-12 13:16:11 +00:00
|
|
|
if (item->identifier[0]) {
|
UI: New Global Top-Bar (WIP)
== Main Features/Changes for Users
* Add horizontal bar at top of all non-temp windows, consisting out of two horizontal sub-bars.
* Upper sub-bar contains global menus (File, Render, etc.), tabs for workspaces and scene selector.
* Lower sub-bar contains object mode selector, screen-layout and render-layer selector. Later operator and/or tool settings will be placed here.
* Individual sections of the topbar are individually scrollable.
* Workspace tabs can be double- or ctrl-clicked for renaming and contain 'x' icon for deleting.
* Top-bar should scale nicely with DPI.
* The lower half of the top-bar can be hided by dragging the lower top-bar edge up. Better hiding options are planned (e.g. hide in fullscreen modes).
* Info editors at the top of the window and using the full window width with be replaced by the top-bar.
* In fullscreen modes, no more info editor is added on top, the top-bar replaces it.
== Technical Features/Changes
* Adds initial support for global areas
A global area is part of the window, not part of the regular screen-layout.
I've added a macro iterator to iterate over both, global and screen-layout level areas. When iterating over areas, from now on developers should always consider if they have to include global areas.
* Adds a TOPBAR editor type
The editor type is hidden in the UI editor type menu.
* Adds a variation of the ID template to display IDs as tab buttons (template_ID_tabs in BPY)
* Does various changes to RNA button creation code to improve their appearance in the horizontal top-bar.
* Adds support for dynamically sized regions. That is, regions that scale automatically to the layout bounds.
The code for this is currently a big hack (it's based on drawing the UI multiple times). This should definitely be improved.
* Adds a template for displaying operator properties optimized for the top-bar. This will probably change a lot still and is in fact disabled in code.
Since the final top-bar design depends a lot on other 2.8 designs (mainly tool-system and workspaces), we decided to not show the operator or tool settings in the top-bar for now. That means most of the lower sub-bar is empty for the time being.
NOTE: Top-bar or global area data is not written to files or SDNA. They are simply added to the window when opening Blender or reading a file. This allows us doing changes to the top-bar without having to care for compatibility.
== ToDo's
It's a bit hard to predict all the ToDo's here are the known main ones:
* Add options for the new active-tool system and for operator redo to the topbar.
* Automatically hide the top-bar in fullscreen modes.
* General visual polish.
* Top-bar drag & drop support (WIP in temp-tab_drag_drop).
* Improve dynamic regions (should also fix some layout glitches).
* Make internal terminology consistent.
* Enable topbar file writing once design is more advanced.
* Address TODO's and XXX's in code :)
Thanks @brecht for the review! And @sergey for the complaining ;)
Differential Revision: D2758
2018-04-20 17:14:03 +02:00
|
|
|
w = max_ii(w, ui_text_icon_width(layout, item->name, item->icon, compact));
|
Fix for [#35224] Transform Orientation - order inconsistency
Fix turned out to remove as much "manual UI" from 3D view header as possible. Mode selector and all transform manipulators/orientations stuff are now RNA-based UI (leaving basically only edit mesh select modes with custom handlers, as they have some quite specific features).
To achieve this, four main modifications were done:
* enum-operator-generated menus are now MENU (i.e. dropdown lists) in headers too.
* All bit-flag enums expanded in ROW buttons now have a handling consistent with e.g. layers, or what we already have for transform manipulators, i.e. clicking select only one element, shift-click to select multiple ones.
* Consequently, the three RNA booleans manipulators flags are merged into a single bit-flag enum (yes, this is also an API change, though I doubt many scripts use it).
* Now the width of enum-based dropdown lists is computed from longest item name in enum, no more from a dummy place holder string (when no label/name is given).
All this allows to remove some code from 3DView/transform areas, that was actually mostly duplicating RNA/operator one.
Also done a few optimizations here and there (among others, do not pass &numitems to RNA_property_enum_items() when you do not need it, saves at least an iteration over enum items to count them).
Many thanks to Brecht for the reviews!
2013-05-12 13:16:11 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
Fix for [#35224] Transform Orientation - order inconsistency
Fix turned out to remove as much "manual UI" from 3D view header as possible. Mode selector and all transform manipulators/orientations stuff are now RNA-based UI (leaving basically only edit mesh select modes with custom handlers, as they have some quite specific features).
To achieve this, four main modifications were done:
* enum-operator-generated menus are now MENU (i.e. dropdown lists) in headers too.
* All bit-flag enums expanded in ROW buttons now have a handling consistent with e.g. layers, or what we already have for transform manipulators, i.e. clicking select only one element, shift-click to select multiple ones.
* Consequently, the three RNA booleans manipulators flags are merged into a single bit-flag enum (yes, this is also an API change, though I doubt many scripts use it).
* Now the width of enum-based dropdown lists is computed from longest item name in enum, no more from a dummy place holder string (when no label/name is given).
All this allows to remove some code from 3DView/transform areas, that was actually mostly duplicating RNA/operator one.
Also done a few optimizations here and there (among others, do not pass &numitems to RNA_property_enum_items() when you do not need it, saves at least an iteration over enum items to count them).
Many thanks to Brecht for the reviews!
2013-05-12 13:16:11 +00:00
|
|
|
if (free) {
|
2025-04-12 17:25:55 +02:00
|
|
|
MEM_freeN(item_array);
|
Fix for [#35224] Transform Orientation - order inconsistency
Fix turned out to remove as much "manual UI" from 3D view header as possible. Mode selector and all transform manipulators/orientations stuff are now RNA-based UI (leaving basically only edit mesh select modes with custom handlers, as they have some quite specific features).
To achieve this, four main modifications were done:
* enum-operator-generated menus are now MENU (i.e. dropdown lists) in headers too.
* All bit-flag enums expanded in ROW buttons now have a handling consistent with e.g. layers, or what we already have for transform manipulators, i.e. clicking select only one element, shift-click to select multiple ones.
* Consequently, the three RNA booleans manipulators flags are merged into a single bit-flag enum (yes, this is also an API change, though I doubt many scripts use it).
* Now the width of enum-based dropdown lists is computed from longest item name in enum, no more from a dummy place holder string (when no label/name is given).
All this allows to remove some code from 3DView/transform areas, that was actually mostly duplicating RNA/operator one.
Also done a few optimizations here and there (among others, do not pass &numitems to RNA_property_enum_items() when you do not need it, saves at least an iteration over enum items to count them).
Many thanks to Brecht for the reviews!
2013-05-12 13:16:11 +00:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2016-12-15 22:22:54 +01:00
|
|
|
if (!w) {
|
|
|
|
|
if (type == PROP_ENUM && icon_only) {
|
UI: New Global Top-Bar (WIP)
== Main Features/Changes for Users
* Add horizontal bar at top of all non-temp windows, consisting out of two horizontal sub-bars.
* Upper sub-bar contains global menus (File, Render, etc.), tabs for workspaces and scene selector.
* Lower sub-bar contains object mode selector, screen-layout and render-layer selector. Later operator and/or tool settings will be placed here.
* Individual sections of the topbar are individually scrollable.
* Workspace tabs can be double- or ctrl-clicked for renaming and contain 'x' icon for deleting.
* Top-bar should scale nicely with DPI.
* The lower half of the top-bar can be hided by dragging the lower top-bar edge up. Better hiding options are planned (e.g. hide in fullscreen modes).
* Info editors at the top of the window and using the full window width with be replaced by the top-bar.
* In fullscreen modes, no more info editor is added on top, the top-bar replaces it.
== Technical Features/Changes
* Adds initial support for global areas
A global area is part of the window, not part of the regular screen-layout.
I've added a macro iterator to iterate over both, global and screen-layout level areas. When iterating over areas, from now on developers should always consider if they have to include global areas.
* Adds a TOPBAR editor type
The editor type is hidden in the UI editor type menu.
* Adds a variation of the ID template to display IDs as tab buttons (template_ID_tabs in BPY)
* Does various changes to RNA button creation code to improve their appearance in the horizontal top-bar.
* Adds support for dynamically sized regions. That is, regions that scale automatically to the layout bounds.
The code for this is currently a big hack (it's based on drawing the UI multiple times). This should definitely be improved.
* Adds a template for displaying operator properties optimized for the top-bar. This will probably change a lot still and is in fact disabled in code.
Since the final top-bar design depends a lot on other 2.8 designs (mainly tool-system and workspaces), we decided to not show the operator or tool settings in the top-bar for now. That means most of the lower sub-bar is empty for the time being.
NOTE: Top-bar or global area data is not written to files or SDNA. They are simply added to the window when opening Blender or reading a file. This allows us doing changes to the top-bar without having to care for compatibility.
== ToDo's
It's a bit hard to predict all the ToDo's here are the known main ones:
* Add options for the new active-tool system and for operator redo to the topbar.
* Automatically hide the top-bar in fullscreen modes.
* General visual polish.
* Top-bar drag & drop support (WIP in temp-tab_drag_drop).
* Improve dynamic regions (should also fix some layout glitches).
* Make internal terminology consistent.
* Enable topbar file writing once design is more advanced.
* Address TODO's and XXX's in code :)
Thanks @brecht for the review! And @sergey for the complaining ;)
Differential Revision: D2758
2018-04-20 17:14:03 +02:00
|
|
|
w = ui_text_icon_width(layout, "", ICON_BLANK1, compact);
|
2019-03-25 10:15:20 +11:00
|
|
|
if (index != RNA_ENUM_VALUE) {
|
2017-04-11 13:25:46 +03:00
|
|
|
w += 0.6f * UI_UNIT_X;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2016-12-15 22:22:54 +01:00
|
|
|
}
|
|
|
|
|
else {
|
UI: New Global Top-Bar (WIP)
== Main Features/Changes for Users
* Add horizontal bar at top of all non-temp windows, consisting out of two horizontal sub-bars.
* Upper sub-bar contains global menus (File, Render, etc.), tabs for workspaces and scene selector.
* Lower sub-bar contains object mode selector, screen-layout and render-layer selector. Later operator and/or tool settings will be placed here.
* Individual sections of the topbar are individually scrollable.
* Workspace tabs can be double- or ctrl-clicked for renaming and contain 'x' icon for deleting.
* Top-bar should scale nicely with DPI.
* The lower half of the top-bar can be hided by dragging the lower top-bar edge up. Better hiding options are planned (e.g. hide in fullscreen modes).
* Info editors at the top of the window and using the full window width with be replaced by the top-bar.
* In fullscreen modes, no more info editor is added on top, the top-bar replaces it.
== Technical Features/Changes
* Adds initial support for global areas
A global area is part of the window, not part of the regular screen-layout.
I've added a macro iterator to iterate over both, global and screen-layout level areas. When iterating over areas, from now on developers should always consider if they have to include global areas.
* Adds a TOPBAR editor type
The editor type is hidden in the UI editor type menu.
* Adds a variation of the ID template to display IDs as tab buttons (template_ID_tabs in BPY)
* Does various changes to RNA button creation code to improve their appearance in the horizontal top-bar.
* Adds support for dynamically sized regions. That is, regions that scale automatically to the layout bounds.
The code for this is currently a big hack (it's based on drawing the UI multiple times). This should definitely be improved.
* Adds a template for displaying operator properties optimized for the top-bar. This will probably change a lot still and is in fact disabled in code.
Since the final top-bar design depends a lot on other 2.8 designs (mainly tool-system and workspaces), we decided to not show the operator or tool settings in the top-bar for now. That means most of the lower sub-bar is empty for the time being.
NOTE: Top-bar or global area data is not written to files or SDNA. They are simply added to the window when opening Blender or reading a file. This allows us doing changes to the top-bar without having to care for compatibility.
== ToDo's
It's a bit hard to predict all the ToDo's here are the known main ones:
* Add options for the new active-tool system and for operator redo to the topbar.
* Automatically hide the top-bar in fullscreen modes.
* General visual polish.
* Top-bar drag & drop support (WIP in temp-tab_drag_drop).
* Improve dynamic regions (should also fix some layout glitches).
* Make internal terminology consistent.
* Enable topbar file writing once design is more advanced.
* Address TODO's and XXX's in code :)
Thanks @brecht for the review! And @sergey for the complaining ;)
Differential Revision: D2758
2018-04-20 17:14:03 +02:00
|
|
|
/* not compact for float/int buttons, looks too squashed */
|
|
|
|
|
w = ui_text_icon_width(
|
|
|
|
|
layout, name, icon, ELEM(type, PROP_FLOAT, PROP_INT) ? false : compact);
|
2016-12-15 22:22:54 +01:00
|
|
|
}
|
|
|
|
|
}
|
2012-03-30 01:51:25 +00:00
|
|
|
h = UI_UNIT_Y;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
/* increase height for arrays */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (index == RNA_NO_INDEX && len > 0) {
|
2024-12-06 14:08:10 +01:00
|
|
|
if (name.is_empty() && icon == ICON_NONE) {
|
2012-03-30 01:51:25 +00:00
|
|
|
h = 0;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2025-04-24 17:22:28 +02:00
|
|
|
if (bool(layout->flag_ & uiItemInternalFlag::PropSep)) {
|
2018-05-28 16:40:27 +02:00
|
|
|
h = 0;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
|
|
|
|
if (ELEM(subtype, PROP_LAYER, PROP_LAYER_MEMBER)) {
|
2012-03-30 01:51:25 +00:00
|
|
|
h += 2 * UI_UNIT_Y;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
|
|
|
|
else if (subtype == PROP_MATRIX) {
|
2014-03-28 14:53:37 +11:00
|
|
|
h += ceilf(sqrtf(len)) * UI_UNIT_Y;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
|
|
|
|
else {
|
2012-03-30 01:51:25 +00:00
|
|
|
h += len * UI_UNIT_Y;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2019-08-10 14:42:14 +03:00
|
|
|
|
|
|
|
|
/* Increase width requirement if in a variable size layout. */
|
|
|
|
|
if (ui_layout_variable_size(layout)) {
|
2024-12-06 14:08:10 +01:00
|
|
|
if (type == PROP_BOOLEAN && !name.is_empty()) {
|
2012-03-30 01:51:25 +00:00
|
|
|
w += UI_UNIT_X / 5;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
else if (is_checkbox_only) {
|
|
|
|
|
w -= UI_UNIT_X / 4;
|
|
|
|
|
}
|
2019-03-25 10:15:20 +11:00
|
|
|
else if (type == PROP_ENUM && !icon_only) {
|
2012-03-30 01:51:25 +00:00
|
|
|
w += UI_UNIT_X / 4;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2020-11-06 12:30:59 +11:00
|
|
|
else if (ELEM(type, PROP_FLOAT, PROP_INT)) {
|
2012-03-30 01:51:25 +00:00
|
|
|
w += UI_UNIT_X * 3;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-30 01:51:25 +00:00
|
|
|
*r_w = w;
|
|
|
|
|
*r_h = h;
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-29 15:06:33 +10:00
|
|
|
static bool ui_item_rna_is_expand(PropertyRNA *prop, int index, const eUI_Item_Flag item_flag)
|
2020-04-27 13:50:16 +02:00
|
|
|
{
|
|
|
|
|
const bool is_array = RNA_property_array_check(prop);
|
|
|
|
|
const int subtype = RNA_property_subtype(prop);
|
|
|
|
|
return is_array && (index == RNA_NO_INDEX) &&
|
|
|
|
|
((item_flag & UI_ITEM_R_EXPAND) ||
|
|
|
|
|
!ELEM(subtype, PROP_COLOR, PROP_COLOR_GAMMA, PROP_DIRECTION));
|
|
|
|
|
}
|
|
|
|
|
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
/**
|
|
|
|
|
* Find first layout ancestor (or self) with a heading set.
|
|
|
|
|
*
|
|
|
|
|
* \returns the layout to add the heading to as fallback (i.e. if it can't be placed in a split
|
|
|
|
|
* layout). Its #uiLayout.heading member can be cleared to mark the heading as added (so
|
|
|
|
|
* it's not added multiple times). Returns a pointer to the heading
|
|
|
|
|
*/
|
|
|
|
|
static uiLayout *ui_layout_heading_find(uiLayout *cur_layout)
|
|
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
for (uiLayout *parent = cur_layout; parent; parent = parent->parent_) {
|
|
|
|
|
if (parent->heading_[0]) {
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
return parent;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-25 23:48:02 -06:00
|
|
|
return nullptr;
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ui_layout_heading_label_add(uiLayout *layout,
|
|
|
|
|
uiLayout *heading_layout,
|
|
|
|
|
bool right_align,
|
|
|
|
|
bool respect_prop_split)
|
|
|
|
|
{
|
2025-04-23 14:54:06 +02:00
|
|
|
const int prev_alignment = layout->alignment_;
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
|
|
|
|
|
if (right_align) {
|
|
|
|
|
uiLayoutSetAlignment(layout, UI_LAYOUT_ALIGN_RIGHT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (respect_prop_split) {
|
2025-04-23 16:37:14 +02:00
|
|
|
uiItemL_respect_property_split(layout, heading_layout->heading_, ICON_NONE);
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2025-05-08 17:21:08 +02:00
|
|
|
layout->label(heading_layout->heading_, ICON_NONE);
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
}
|
|
|
|
|
/* After adding the heading label, we have to mark it somehow as added, so it's not added again
|
|
|
|
|
* for other items in this layout. For now just clear it. */
|
2025-04-23 16:37:14 +02:00
|
|
|
heading_layout->heading_[0] = '\0';
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
|
2025-04-23 14:54:06 +02:00
|
|
|
layout->alignment_ = prev_alignment;
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
}
|
|
|
|
|
|
2020-04-05 14:19:24 +02:00
|
|
|
/**
|
|
|
|
|
* Hack to add further items in a row into the second part of the split layout, so the label part
|
|
|
|
|
* keeps a fixed size.
|
|
|
|
|
* \return The layout to place further items in for the split layout.
|
|
|
|
|
*/
|
|
|
|
|
static uiLayout *ui_item_prop_split_layout_hack(uiLayout *layout_parent, uiLayout *layout_split)
|
|
|
|
|
{
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
/* Tag item as using property split layout, this is inherited to children so they can get special
|
|
|
|
|
* treatment if needed. */
|
2025-04-24 17:22:28 +02:00
|
|
|
layout_parent->flag_ |= uiItemInternalFlag::InsidePropSep;
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
|
2025-04-24 17:22:28 +02:00
|
|
|
if (layout_parent->type_ == uiItemType::LayoutRow) {
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
/* Prevent further splits within the row. */
|
|
|
|
|
uiLayoutSetPropSep(layout_parent, false);
|
|
|
|
|
|
2025-04-25 19:45:25 +02:00
|
|
|
layout_parent->child_items_layout_ = &layout_split->row(true);
|
2025-04-23 16:37:14 +02:00
|
|
|
return layout_parent->child_items_layout_;
|
2020-04-05 14:19:24 +02:00
|
|
|
}
|
|
|
|
|
return layout_split;
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-10 03:39:31 +02:00
|
|
|
void uiLayout::prop(PointerRNA *ptr,
|
|
|
|
|
PropertyRNA *prop,
|
|
|
|
|
int index,
|
|
|
|
|
int value,
|
|
|
|
|
eUI_Item_Flag flag,
|
2025-05-19 17:25:52 +02:00
|
|
|
const std::optional<StringRef> name_opt,
|
2025-05-10 03:39:31 +02:00
|
|
|
int icon,
|
2025-05-19 17:25:52 +02:00
|
|
|
const std::optional<StringRef> placeholder)
|
2009-03-13 13:38:41 +00:00
|
|
|
{
|
2025-05-10 03:39:31 +02:00
|
|
|
|
|
|
|
|
uiBlock *block = root_->block;
|
2023-10-19 09:24:06 -07:00
|
|
|
char namestr[UI_MAX_NAME_STR];
|
2025-05-10 03:39:31 +02:00
|
|
|
const bool use_prop_sep = bool(flag_ & uiItemInternalFlag::PropSep);
|
|
|
|
|
const bool inside_prop_sep = bool(flag_ & uiItemInternalFlag::InsidePropSep);
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
/* Columns can define a heading to insert. If the first item added to a split layout doesn't have
|
|
|
|
|
* a label to display in the first column, the heading is inserted there. Otherwise it's inserted
|
|
|
|
|
* as a new row before the first item. */
|
2025-05-10 03:39:31 +02:00
|
|
|
uiLayout *heading_layout = ui_layout_heading_find(this);
|
2021-07-05 12:47:46 +10:00
|
|
|
/* Although check-boxes use the split layout, they are an exception and should only place their
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
* label in the second column, to not make that almost empty.
|
2019-03-22 15:29:25 +11:00
|
|
|
*
|
|
|
|
|
* Keep using 'use_prop_sep' instead of disabling it entirely because
|
|
|
|
|
* we need the ability to have decorators still. */
|
2019-03-23 00:01:00 +11:00
|
|
|
bool use_prop_sep_split_label = use_prop_sep;
|
2020-04-27 15:24:25 +02:00
|
|
|
bool use_split_empty_name = (flag & UI_ITEM_R_SPLIT_EMPTY_NAME);
|
2019-03-22 15:29:25 +11:00
|
|
|
|
2018-06-16 14:48:21 +02:00
|
|
|
#ifdef UI_PROP_DECORATE
|
2022-11-25 23:48:02 -06:00
|
|
|
struct DecorateInfo {
|
2018-06-16 14:48:21 +02:00
|
|
|
bool use_prop_decorate;
|
2018-06-18 07:52:17 +02:00
|
|
|
int len;
|
2018-06-16 14:48:21 +02:00
|
|
|
uiLayout *layout;
|
|
|
|
|
uiBut *but;
|
|
|
|
|
};
|
2022-11-25 23:48:02 -06:00
|
|
|
DecorateInfo ui_decorate{};
|
2025-05-10 03:39:31 +02:00
|
|
|
ui_decorate.use_prop_decorate = (bool(flag_ & uiItemInternalFlag::PropDecorate) && use_prop_sep);
|
2022-11-25 23:48:02 -06:00
|
|
|
|
2018-06-16 14:48:21 +02:00
|
|
|
#endif /* UI_PROP_DECORATE */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-05-10 03:39:31 +02:00
|
|
|
UI_block_layout_set_current(block, this);
|
2022-11-25 23:48:02 -06:00
|
|
|
ui_block_new_button_group(block, uiButtonGroupFlag(0));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
/* retrieve info */
|
2019-05-21 12:30:07 +10:00
|
|
|
const PropertyType type = RNA_property_type(prop);
|
|
|
|
|
const bool is_array = RNA_property_array_check(prop);
|
|
|
|
|
const int len = (is_array) ? RNA_property_array_length(ptr, prop) : 0;
|
Add more control over ID renaming behavior.
This commit adds low-level logic in BKE to support three behaviors in
case of name conflict when renaming an ID:
1. Always tweak new name of the renamed ID (never modify the other ID
name).
2. Always set requested name in renamed ID, modifying as needed the
other ID name.
3. Only modify the other ID name if it shares the same root name with the
current renamed ID's name.
It also adds quite some changes to IDTemplate, Outliner code, and
RNA-defined UILayout code, and the lower-level UI button API, to allow
for the new behavior defined in the design (i.e. option three from above list).
When renaming from the UI either 'fails' (falls back to adjusted name) or forces
renaming another ID, an INFO report is displayed.
This commit also fixes several issues in existing code, especially
regarding undo handling in rename operations (which could lead to saving
the wrong name in undo step, and/or over-generating undo steps).
API wise, the bahavior when directly assigning a name to the `ID.name`
property remains unchanged (option one from the list above). But a new
API call `ID.rename` has been added, which offers all three behaviors.
Unittests were added to cover the new implemented behaviors (both at
BKE level, and the RNA/Py API).
This commit implements #119139 design.
Pull Request: https://projects.blender.org/blender/blender/pulls/126996
2024-09-20 13:36:50 +02:00
|
|
|
const bool is_id_name_prop = (ptr->owner_id == ptr->data && type == PROP_STRING &&
|
|
|
|
|
prop == RNA_struct_name_property(ptr->type));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-21 12:30:07 +10:00
|
|
|
const bool icon_only = (flag & UI_ITEM_R_ICON_ONLY) != 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-21 14:39:09 +10:00
|
|
|
/* Boolean with -1 to signify that the value depends on the presence of an icon. */
|
|
|
|
|
const int toggle = ((flag & UI_ITEM_R_TOGGLE) ? 1 : ((flag & UI_ITEM_R_ICON_NEVER) ? 0 : -1));
|
|
|
|
|
const bool no_icon = (toggle == 0);
|
|
|
|
|
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
/* set name and icon */
|
2025-05-19 17:25:52 +02:00
|
|
|
StringRef name = name_opt.value_or(icon_only ? "" : RNA_property_ui_name(prop));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-20 12:14:48 +02:00
|
|
|
if (type != PROP_BOOLEAN) {
|
|
|
|
|
flag &= ~UI_ITEM_R_CHECKBOX_INVERT;
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-12 19:24:47 +11:00
|
|
|
if (flag & UI_ITEM_R_ICON_ONLY) {
|
|
|
|
|
/* pass */
|
|
|
|
|
}
|
2014-07-20 01:30:29 +10:00
|
|
|
else if (ELEM(type, PROP_INT, PROP_FLOAT, PROP_STRING, PROP_POINTER)) {
|
2023-10-19 09:24:06 -07:00
|
|
|
if (use_prop_sep == false) {
|
|
|
|
|
name = ui_item_name_add_colon(name, namestr);
|
|
|
|
|
}
|
2014-03-12 19:24:47 +11:00
|
|
|
}
|
|
|
|
|
else if (type == PROP_BOOLEAN && is_array && index == RNA_NO_INDEX) {
|
2023-10-19 09:24:06 -07:00
|
|
|
if (use_prop_sep == false) {
|
|
|
|
|
name = ui_item_name_add_colon(name, namestr);
|
|
|
|
|
}
|
2014-03-12 19:24:47 +11:00
|
|
|
}
|
|
|
|
|
else if (type == PROP_ENUM && index != RNA_ENUM_VALUE) {
|
UI: New Global Top-Bar (WIP)
== Main Features/Changes for Users
* Add horizontal bar at top of all non-temp windows, consisting out of two horizontal sub-bars.
* Upper sub-bar contains global menus (File, Render, etc.), tabs for workspaces and scene selector.
* Lower sub-bar contains object mode selector, screen-layout and render-layer selector. Later operator and/or tool settings will be placed here.
* Individual sections of the topbar are individually scrollable.
* Workspace tabs can be double- or ctrl-clicked for renaming and contain 'x' icon for deleting.
* Top-bar should scale nicely with DPI.
* The lower half of the top-bar can be hided by dragging the lower top-bar edge up. Better hiding options are planned (e.g. hide in fullscreen modes).
* Info editors at the top of the window and using the full window width with be replaced by the top-bar.
* In fullscreen modes, no more info editor is added on top, the top-bar replaces it.
== Technical Features/Changes
* Adds initial support for global areas
A global area is part of the window, not part of the regular screen-layout.
I've added a macro iterator to iterate over both, global and screen-layout level areas. When iterating over areas, from now on developers should always consider if they have to include global areas.
* Adds a TOPBAR editor type
The editor type is hidden in the UI editor type menu.
* Adds a variation of the ID template to display IDs as tab buttons (template_ID_tabs in BPY)
* Does various changes to RNA button creation code to improve their appearance in the horizontal top-bar.
* Adds support for dynamically sized regions. That is, regions that scale automatically to the layout bounds.
The code for this is currently a big hack (it's based on drawing the UI multiple times). This should definitely be improved.
* Adds a template for displaying operator properties optimized for the top-bar. This will probably change a lot still and is in fact disabled in code.
Since the final top-bar design depends a lot on other 2.8 designs (mainly tool-system and workspaces), we decided to not show the operator or tool settings in the top-bar for now. That means most of the lower sub-bar is empty for the time being.
NOTE: Top-bar or global area data is not written to files or SDNA. They are simply added to the window when opening Blender or reading a file. This allows us doing changes to the top-bar without having to care for compatibility.
== ToDo's
It's a bit hard to predict all the ToDo's here are the known main ones:
* Add options for the new active-tool system and for operator redo to the topbar.
* Automatically hide the top-bar in fullscreen modes.
* General visual polish.
* Top-bar drag & drop support (WIP in temp-tab_drag_drop).
* Improve dynamic regions (should also fix some layout glitches).
* Make internal terminology consistent.
* Enable topbar file writing once design is more advanced.
* Address TODO's and XXX's in code :)
Thanks @brecht for the review! And @sergey for the complaining ;)
Differential Revision: D2758
2018-04-20 17:14:03 +02:00
|
|
|
if (flag & UI_ITEM_R_COMPACT) {
|
|
|
|
|
name = "";
|
|
|
|
|
}
|
2023-10-19 09:24:06 -07:00
|
|
|
else {
|
|
|
|
|
if (use_prop_sep == false) {
|
|
|
|
|
name = ui_item_name_add_colon(name, namestr);
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-03-12 19:24:47 +11:00
|
|
|
}
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
|
2019-05-21 14:39:09 +10:00
|
|
|
if (no_icon == false) {
|
|
|
|
|
if (icon == ICON_NONE) {
|
|
|
|
|
icon = RNA_property_ui_icon(prop);
|
2019-03-25 07:34:06 +11:00
|
|
|
}
|
|
|
|
|
|
2019-05-21 14:39:09 +10:00
|
|
|
/* Menus and pie-menus don't show checkbox without this. */
|
2025-05-10 03:39:31 +02:00
|
|
|
if ((root_->type == UI_LAYOUT_MENU) ||
|
2021-07-05 12:47:46 +10:00
|
|
|
/* Use check-boxes only as a fallback in pie-menu's, when no icon is defined. */
|
2025-05-10 03:39:31 +02:00
|
|
|
((root_->type == UI_LAYOUT_PIEMENU) && (icon == ICON_NONE)))
|
2019-05-21 14:39:09 +10:00
|
|
|
{
|
2020-08-26 10:11:13 +10:00
|
|
|
const int prop_flag = RNA_property_flag(prop);
|
2019-05-21 14:39:09 +10:00
|
|
|
if (type == PROP_BOOLEAN) {
|
|
|
|
|
if ((is_array == false) || (index != RNA_NO_INDEX)) {
|
|
|
|
|
if (prop_flag & PROP_ICONS_CONSECUTIVE) {
|
|
|
|
|
icon = ICON_CHECKBOX_DEHLT; /* but->iconadd will set to correct icon */
|
|
|
|
|
}
|
|
|
|
|
else if (is_array) {
|
2022-10-07 22:52:53 +11:00
|
|
|
icon = RNA_property_boolean_get_index(ptr, prop, index) ? ICON_CHECKBOX_HLT :
|
|
|
|
|
ICON_CHECKBOX_DEHLT;
|
2019-05-21 14:39:09 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2022-10-07 22:52:53 +11:00
|
|
|
icon = RNA_property_boolean_get(ptr, prop) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
|
2019-05-21 14:39:09 +10:00
|
|
|
}
|
|
|
|
|
}
|
2018-07-02 19:11:36 +02:00
|
|
|
}
|
2019-05-21 14:39:09 +10:00
|
|
|
else if (type == PROP_ENUM) {
|
|
|
|
|
if (index == RNA_ENUM_VALUE) {
|
2020-08-26 10:11:13 +10:00
|
|
|
const int enum_value = RNA_property_enum_get(ptr, prop);
|
2019-05-21 14:39:09 +10:00
|
|
|
if (prop_flag & PROP_ICONS_CONSECUTIVE) {
|
|
|
|
|
icon = ICON_CHECKBOX_DEHLT; /* but->iconadd will set to correct icon */
|
|
|
|
|
}
|
|
|
|
|
else if (prop_flag & PROP_ENUM_FLAG) {
|
|
|
|
|
icon = (enum_value & value) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
|
|
|
|
|
}
|
|
|
|
|
else {
|
2023-09-13 19:24:16 +02:00
|
|
|
/* Only a single value can be chosen, so display as radio buttons. */
|
|
|
|
|
icon = (enum_value == value) ? ICON_RADIOBUT_ON : ICON_RADIOBUT_OFF;
|
2019-05-21 14:39:09 +10:00
|
|
|
}
|
|
|
|
|
}
|
2018-07-02 19:11:36 +02:00
|
|
|
}
|
2011-08-14 10:17:41 +00:00
|
|
|
}
|
2019-05-21 14:39:09 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef UI_PROP_SEP_ICON_WIDTH_EXCEPTION
|
|
|
|
|
if (use_prop_sep) {
|
|
|
|
|
if (type == PROP_BOOLEAN && (icon == ICON_NONE) && !icon_only) {
|
|
|
|
|
use_prop_sep_split_label = false;
|
2020-05-09 17:15:25 +10:00
|
|
|
/* For check-boxes we make an exception: We allow showing them in a split row even without
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
* label. It typically relates to its neighbor items, so no need for an extra label. */
|
2020-04-27 15:24:25 +02:00
|
|
|
use_split_empty_name = true;
|
2010-09-23 07:31:44 +00:00
|
|
|
}
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
}
|
2019-05-21 14:39:09 +10:00
|
|
|
#endif
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-08-15 15:48:20 +10:00
|
|
|
if ((type == PROP_ENUM) && (RNA_property_flag(prop) & PROP_ENUM_FLAG)) {
|
|
|
|
|
flag |= UI_ITEM_R_EXPAND;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-21 12:30:07 +10:00
|
|
|
const bool slider = (flag & UI_ITEM_R_SLIDER) != 0;
|
|
|
|
|
const bool expand = (flag & UI_ITEM_R_EXPAND) != 0;
|
|
|
|
|
const bool no_bg = (flag & UI_ITEM_R_NO_BG) != 0;
|
|
|
|
|
const bool compact = (flag & UI_ITEM_R_COMPACT) != 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
/* get size */
|
2019-05-21 12:30:07 +10:00
|
|
|
int w, h;
|
2025-05-10 03:39:31 +02:00
|
|
|
ui_item_rna_size(this, name, icon, ptr, prop, index, icon_only, compact, &w, &h);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-05-10 03:39:31 +02:00
|
|
|
const blender::ui::EmbossType prev_emboss = emboss_;
|
2018-05-13 14:10:05 +02:00
|
|
|
if (no_bg) {
|
2025-05-10 03:39:31 +02:00
|
|
|
emboss_ = blender::ui::EmbossType::NoneOrStatus;
|
2018-05-13 14:10:05 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-11-25 23:48:02 -06:00
|
|
|
uiBut *but = nullptr;
|
2019-05-21 12:30:07 +10:00
|
|
|
|
2018-05-28 16:40:27 +02:00
|
|
|
/* Split the label / property. */
|
2025-05-10 03:39:31 +02:00
|
|
|
uiLayout *layout_parent = this;
|
|
|
|
|
uiLayout *layout = this;
|
2018-05-28 16:40:27 +02:00
|
|
|
if (use_prop_sep) {
|
2022-11-25 23:48:02 -06:00
|
|
|
uiLayout *layout_row = nullptr;
|
2018-06-16 14:48:21 +02:00
|
|
|
#ifdef UI_PROP_DECORATE
|
|
|
|
|
if (ui_decorate.use_prop_decorate) {
|
2025-04-25 19:45:25 +02:00
|
|
|
layout_row = &layout->row(true);
|
2025-04-23 14:54:06 +02:00
|
|
|
layout_row->space_ = 0;
|
2018-06-18 15:50:21 +02:00
|
|
|
ui_decorate.len = max_ii(1, len);
|
2018-06-16 14:48:21 +02:00
|
|
|
}
|
|
|
|
|
#endif /* UI_PROP_DECORATE */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-06 14:08:10 +01:00
|
|
|
if (name.is_empty() && !use_split_empty_name) {
|
2018-05-30 17:28:12 +02:00
|
|
|
/* Ensure we get a column when text is not set. */
|
2025-04-26 21:07:34 +02:00
|
|
|
layout = &(layout_row ? layout_row : layout)->column(true);
|
2025-04-23 14:54:06 +02:00
|
|
|
layout->space_ = 0;
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
if (heading_layout) {
|
|
|
|
|
ui_layout_heading_label_add(layout, heading_layout, false, false);
|
|
|
|
|
}
|
2018-05-28 16:40:27 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2025-05-03 20:51:42 +02:00
|
|
|
uiLayout *layout_split =
|
|
|
|
|
&(layout_row ? layout_row : layout)->split(UI_ITEM_PROP_SEP_DIVIDE, true);
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
bool label_added = false;
|
2025-04-26 21:07:34 +02:00
|
|
|
uiLayout *layout_sub = &layout_split->column(true);
|
2025-04-23 14:54:06 +02:00
|
|
|
layout_sub->space_ = 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
if (!use_prop_sep_split_label) {
|
|
|
|
|
/* Pass */
|
|
|
|
|
}
|
2020-04-27 13:50:16 +02:00
|
|
|
else if (ui_item_rna_is_expand(prop, index, flag)) {
|
2025-05-19 17:25:52 +02:00
|
|
|
fmt::memory_buffer name_with_suffix;
|
2018-05-30 17:28:12 +02:00
|
|
|
char str[2] = {'\0'};
|
|
|
|
|
for (int a = 0; a < len; a++) {
|
|
|
|
|
str[0] = RNA_property_array_item_char(prop, a);
|
2024-12-06 14:08:10 +01:00
|
|
|
const bool use_prefix = (a == 0 && !name.is_empty());
|
2018-05-30 17:28:12 +02:00
|
|
|
if (use_prefix) {
|
2025-05-19 17:25:52 +02:00
|
|
|
fmt::format_to(fmt::appender(name_with_suffix), "{} {}", name, str[0]);
|
2018-05-30 17:28:12 +02:00
|
|
|
}
|
|
|
|
|
but = uiDefBut(block,
|
2018-05-30 19:45:03 +02:00
|
|
|
UI_BTYPE_LABEL,
|
|
|
|
|
0,
|
2025-05-19 17:25:52 +02:00
|
|
|
use_prefix ? StringRef(name_with_suffix.data(), name_with_suffix.size()) :
|
|
|
|
|
str,
|
2018-05-30 19:45:03 +02:00
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
w,
|
|
|
|
|
UI_UNIT_Y,
|
2022-11-25 23:48:02 -06:00
|
|
|
nullptr,
|
2018-05-30 19:45:03 +02:00
|
|
|
0.0,
|
|
|
|
|
0.0,
|
|
|
|
|
"");
|
2018-05-30 17:28:12 +02:00
|
|
|
but->drawflag |= UI_BUT_TEXT_RIGHT;
|
|
|
|
|
but->drawflag &= ~UI_BUT_TEXT_LEFT;
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
|
|
|
|
|
label_added = true;
|
2018-05-30 17:28:12 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2018-05-30 17:28:12 +02:00
|
|
|
else {
|
2024-04-01 22:10:28 +11:00
|
|
|
but = uiDefBut(block, UI_BTYPE_LABEL, 0, name, 0, 0, w, UI_UNIT_Y, nullptr, 0.0, 0.0, "");
|
|
|
|
|
but->drawflag |= UI_BUT_TEXT_RIGHT;
|
|
|
|
|
but->drawflag &= ~UI_BUT_TEXT_LEFT;
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
|
2024-04-01 22:10:28 +11:00
|
|
|
label_added = true;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
if (!label_added && heading_layout) {
|
|
|
|
|
ui_layout_heading_label_add(layout_sub, heading_layout, true, false);
|
2018-10-25 15:27:31 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
layout_split = ui_item_prop_split_layout_hack(layout_parent, layout_split);
|
|
|
|
|
|
2018-09-04 14:07:26 +10:00
|
|
|
/* Watch out! We can only write into the new layout now. */
|
2018-06-18 07:52:17 +02:00
|
|
|
if ((type == PROP_ENUM) && (flag & UI_ITEM_R_EXPAND)) {
|
2018-09-04 14:07:26 +10:00
|
|
|
/* Expanded enums each have their own name. */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-01-15 23:24:20 +11:00
|
|
|
/* Often expanded enum's are better arranged into a row,
|
|
|
|
|
* so check the existing layout. */
|
2018-12-20 11:59:31 +11:00
|
|
|
if (uiLayoutGetLocalDir(layout) == UI_LAYOUT_HORIZONTAL) {
|
2025-04-25 19:45:25 +02:00
|
|
|
layout = &layout_split->row(true);
|
2018-09-04 14:07:26 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2025-04-26 21:07:34 +02:00
|
|
|
layout = &layout_split->column(true);
|
2018-06-18 07:52:17 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2018-06-18 07:52:17 +02:00
|
|
|
else {
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
if (use_prop_sep_split_label) {
|
|
|
|
|
name = "";
|
|
|
|
|
}
|
2025-04-26 21:07:34 +02:00
|
|
|
layout = &layout_split->column(true);
|
2018-06-18 07:52:17 +02:00
|
|
|
}
|
2025-04-23 14:54:06 +02:00
|
|
|
layout->space_ = 0;
|
2018-05-30 17:28:12 +02:00
|
|
|
}
|
2018-06-16 14:48:21 +02:00
|
|
|
|
|
|
|
|
#ifdef UI_PROP_DECORATE
|
|
|
|
|
if (ui_decorate.use_prop_decorate) {
|
2025-04-26 21:07:34 +02:00
|
|
|
ui_decorate.layout = &layout_row->column(true);
|
2025-04-23 14:54:06 +02:00
|
|
|
ui_decorate.layout->space_ = 0;
|
2018-06-16 14:48:21 +02:00
|
|
|
UI_block_layout_set_current(block, layout);
|
2025-02-14 15:29:26 +01:00
|
|
|
ui_decorate.but = block->last_but();
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-08-28 00:59:15 +10:00
|
|
|
/* Clear after. */
|
2025-04-24 17:22:28 +02:00
|
|
|
layout->flag_ |= uiItemInternalFlag::PropDecorateNoPad;
|
2018-06-16 14:48:21 +02:00
|
|
|
}
|
|
|
|
|
#endif /* UI_PROP_DECORATE */
|
2018-05-28 16:40:27 +02:00
|
|
|
}
|
|
|
|
|
/* End split. */
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
else if (heading_layout) {
|
|
|
|
|
/* Could not add heading to split layout, fallback to inserting it to the layout with the
|
|
|
|
|
* heading itself. */
|
|
|
|
|
ui_layout_heading_label_add(heading_layout, heading_layout, false, false);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
/* array property */
|
2018-05-28 16:40:27 +02:00
|
|
|
if (index == RNA_NO_INDEX && is_array) {
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
if (inside_prop_sep) {
|
|
|
|
|
/* Within a split row, add array items to a column so they match the column layout of
|
|
|
|
|
* previous items (e.g. transform vector with lock icon for each item). */
|
2025-04-26 21:07:34 +02:00
|
|
|
layout = &layout->column(true);
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
}
|
|
|
|
|
|
UI: New Global Top-Bar (WIP)
== Main Features/Changes for Users
* Add horizontal bar at top of all non-temp windows, consisting out of two horizontal sub-bars.
* Upper sub-bar contains global menus (File, Render, etc.), tabs for workspaces and scene selector.
* Lower sub-bar contains object mode selector, screen-layout and render-layer selector. Later operator and/or tool settings will be placed here.
* Individual sections of the topbar are individually scrollable.
* Workspace tabs can be double- or ctrl-clicked for renaming and contain 'x' icon for deleting.
* Top-bar should scale nicely with DPI.
* The lower half of the top-bar can be hided by dragging the lower top-bar edge up. Better hiding options are planned (e.g. hide in fullscreen modes).
* Info editors at the top of the window and using the full window width with be replaced by the top-bar.
* In fullscreen modes, no more info editor is added on top, the top-bar replaces it.
== Technical Features/Changes
* Adds initial support for global areas
A global area is part of the window, not part of the regular screen-layout.
I've added a macro iterator to iterate over both, global and screen-layout level areas. When iterating over areas, from now on developers should always consider if they have to include global areas.
* Adds a TOPBAR editor type
The editor type is hidden in the UI editor type menu.
* Adds a variation of the ID template to display IDs as tab buttons (template_ID_tabs in BPY)
* Does various changes to RNA button creation code to improve their appearance in the horizontal top-bar.
* Adds support for dynamically sized regions. That is, regions that scale automatically to the layout bounds.
The code for this is currently a big hack (it's based on drawing the UI multiple times). This should definitely be improved.
* Adds a template for displaying operator properties optimized for the top-bar. This will probably change a lot still and is in fact disabled in code.
Since the final top-bar design depends a lot on other 2.8 designs (mainly tool-system and workspaces), we decided to not show the operator or tool settings in the top-bar for now. That means most of the lower sub-bar is empty for the time being.
NOTE: Top-bar or global area data is not written to files or SDNA. They are simply added to the window when opening Blender or reading a file. This allows us doing changes to the top-bar without having to care for compatibility.
== ToDo's
It's a bit hard to predict all the ToDo's here are the known main ones:
* Add options for the new active-tool system and for operator redo to the topbar.
* Automatically hide the top-bar in fullscreen modes.
* General visual polish.
* Top-bar drag & drop support (WIP in temp-tab_drag_drop).
* Improve dynamic regions (should also fix some layout glitches).
* Make internal terminology consistent.
* Enable topbar file writing once design is more advanced.
* Address TODO's and XXX's in code :)
Thanks @brecht for the review! And @sergey for the complaining ;)
Differential Revision: D2758
2018-04-20 17:14:03 +02:00
|
|
|
ui_item_array(layout,
|
2018-05-28 16:40:27 +02:00
|
|
|
block,
|
|
|
|
|
name,
|
|
|
|
|
icon,
|
|
|
|
|
ptr,
|
|
|
|
|
prop,
|
|
|
|
|
len,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
w,
|
|
|
|
|
h,
|
2019-03-23 00:01:00 +11:00
|
|
|
expand,
|
|
|
|
|
slider,
|
|
|
|
|
toggle,
|
|
|
|
|
icon_only,
|
|
|
|
|
compact,
|
|
|
|
|
!use_prop_sep_split_label);
|
2018-05-28 16:40:27 +02:00
|
|
|
}
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
/* enum item */
|
2012-03-24 06:38:07 +00:00
|
|
|
else if (type == PROP_ENUM && index == RNA_ENUM_VALUE) {
|
2024-12-06 14:08:10 +01:00
|
|
|
if (icon && !name.is_empty() && !icon_only) {
|
2024-02-05 14:38:05 -05:00
|
|
|
uiDefIconTextButR_prop(
|
2025-02-14 15:12:48 -05:00
|
|
|
block, UI_BTYPE_ROW, 0, icon, name, 0, 0, w, h, ptr, prop, -1, 0, value, std::nullopt);
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
|
|
|
|
else if (icon) {
|
2014-11-09 21:20:40 +01:00
|
|
|
uiDefIconButR_prop(
|
2025-02-14 15:12:48 -05:00
|
|
|
block, UI_BTYPE_ROW, 0, icon, 0, 0, w, h, ptr, prop, -1, 0, value, std::nullopt);
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
|
|
|
|
else {
|
2025-02-14 15:12:48 -05:00
|
|
|
uiDefButR_prop(
|
|
|
|
|
block, UI_BTYPE_ROW, 0, name, 0, 0, w, h, ptr, prop, -1, 0, value, std::nullopt);
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
/* expanded enum */
|
2018-08-15 15:48:20 +10:00
|
|
|
else if (type == PROP_ENUM && expand) {
|
2010-10-16 02:40:31 +00:00
|
|
|
ui_item_enum_expand(layout, block, ptr, prop, name, h, icon_only);
|
2018-08-15 15:48:20 +10:00
|
|
|
}
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
/* property with separate label */
|
2020-11-06 12:51:49 +11:00
|
|
|
else if (ELEM(type, PROP_ENUM, PROP_STRING, PROP_POINTER)) {
|
2012-03-30 01:51:25 +00:00
|
|
|
but = ui_item_with_label(layout, block, name, icon, ptr, prop, index, 0, 0, w, h, flag);
|
Add more control over ID renaming behavior.
This commit adds low-level logic in BKE to support three behaviors in
case of name conflict when renaming an ID:
1. Always tweak new name of the renamed ID (never modify the other ID
name).
2. Always set requested name in renamed ID, modifying as needed the
other ID name.
3. Only modify the other ID name if it shares the same root name with the
current renamed ID's name.
It also adds quite some changes to IDTemplate, Outliner code, and
RNA-defined UILayout code, and the lower-level UI button API, to allow
for the new behavior defined in the design (i.e. option three from above list).
When renaming from the UI either 'fails' (falls back to adjusted name) or forces
renaming another ID, an INFO report is displayed.
This commit also fixes several issues in existing code, especially
regarding undo handling in rename operations (which could lead to saving
the wrong name in undo step, and/or over-generating undo steps).
API wise, the bahavior when directly assigning a name to the `ID.name`
property remains unchanged (option one from the list above). But a new
API call `ID.rename` has been added, which offers all three behaviors.
Unittests were added to cover the new implemented behaviors (both at
BKE level, and the RNA/Py API).
This commit implements #119139 design.
Pull Request: https://projects.blender.org/blender/blender/pulls/126996
2024-09-20 13:36:50 +02:00
|
|
|
|
|
|
|
|
if (is_id_name_prop) {
|
|
|
|
|
Main *bmain = CTX_data_main(static_cast<bContext *>(block->evil_C));
|
|
|
|
|
ID *id = ptr->owner_id;
|
2024-11-20 12:08:08 +01:00
|
|
|
UI_but_func_rename_full_set(
|
|
|
|
|
but, [bmain, id](const std::string &new_name) { ED_id_rename(*bmain, *id, new_name); });
|
Add more control over ID renaming behavior.
This commit adds low-level logic in BKE to support three behaviors in
case of name conflict when renaming an ID:
1. Always tweak new name of the renamed ID (never modify the other ID
name).
2. Always set requested name in renamed ID, modifying as needed the
other ID name.
3. Only modify the other ID name if it shares the same root name with the
current renamed ID's name.
It also adds quite some changes to IDTemplate, Outliner code, and
RNA-defined UILayout code, and the lower-level UI button API, to allow
for the new behavior defined in the design (i.e. option three from above list).
When renaming from the UI either 'fails' (falls back to adjusted name) or forces
renaming another ID, an INFO report is displayed.
This commit also fixes several issues in existing code, especially
regarding undo handling in rename operations (which could lead to saving
the wrong name in undo step, and/or over-generating undo steps).
API wise, the bahavior when directly assigning a name to the `ID.name`
property remains unchanged (option one from the list above). But a new
API call `ID.rename` has been added, which offers all three behaviors.
Unittests were added to cover the new implemented behaviors (both at
BKE level, and the RNA/Py API).
This commit implements #119139 design.
Pull Request: https://projects.blender.org/blender/blender/pulls/126996
2024-09-20 13:36:50 +02:00
|
|
|
}
|
|
|
|
|
|
2022-05-20 14:30:17 +10:00
|
|
|
bool results_are_suggestions = false;
|
|
|
|
|
if (type == PROP_STRING) {
|
|
|
|
|
const eStringPropertySearchFlag search_flag = RNA_property_string_search_flag(prop);
|
|
|
|
|
if (search_flag & PROP_STRING_SEARCH_SUGGESTION) {
|
|
|
|
|
results_are_suggestions = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-11-25 23:48:02 -06:00
|
|
|
but = ui_but_add_search(but, ptr, prop, nullptr, nullptr, results_are_suggestions);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-23 14:54:06 +02:00
|
|
|
if (layout->redalert_) {
|
2014-11-09 21:20:40 +01:00
|
|
|
UI_but_flag_enable(but, UI_BUT_REDALERT);
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-23 14:54:06 +02:00
|
|
|
if (layout->activate_init_) {
|
2019-03-20 22:40:38 +11:00
|
|
|
UI_but_flag_enable(but, UI_BUT_ACTIVATE_ON_INIT);
|
2009-06-27 01:15:31 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
/* single button */
|
2009-05-19 17:13:33 +00:00
|
|
|
else {
|
2012-03-24 02:51:46 +00:00
|
|
|
but = uiDefAutoButR(block, ptr, prop, index, name, icon, 0, 0, w, h);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-03-25 10:15:20 +11:00
|
|
|
if (slider && but->type == UI_BTYPE_NUM) {
|
2024-02-01 12:42:25 -05:00
|
|
|
uiButNumber *number_but = (uiButNumber *)but;
|
|
|
|
|
const float step_size = number_but->step_size;
|
2024-02-05 12:16:14 -05:00
|
|
|
const float precision = number_but->precision;
|
2020-09-10 15:28:55 +02:00
|
|
|
but = ui_but_change_type(but, UI_BTYPE_NUM_SLIDER);
|
2024-02-01 12:42:25 -05:00
|
|
|
uiButNumberSlider *slider_but = reinterpret_cast<uiButNumberSlider *>(but);
|
|
|
|
|
slider_but->step_size = step_size;
|
2024-02-05 12:16:14 -05:00
|
|
|
slider_but->precision = precision;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-20 12:14:48 +02:00
|
|
|
if (flag & UI_ITEM_R_CHECKBOX_INVERT) {
|
2020-03-09 16:43:47 +01:00
|
|
|
if (ELEM(but->type,
|
|
|
|
|
UI_BTYPE_CHECKBOX,
|
|
|
|
|
UI_BTYPE_CHECKBOX_N,
|
|
|
|
|
UI_BTYPE_ICON_TOGGLE,
|
|
|
|
|
UI_BTYPE_ICON_TOGGLE_N))
|
|
|
|
|
{
|
2019-05-20 12:14:48 +02:00
|
|
|
but->drawflag |= UI_BUT_CHECKBOX_INVERT;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-21 14:39:09 +10:00
|
|
|
if ((toggle == 1) && but->type == UI_BTYPE_CHECKBOX) {
|
2014-11-09 21:20:40 +01:00
|
|
|
but->type = UI_BTYPE_TOGGLE;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-23 14:54:06 +02:00
|
|
|
if (layout->redalert_) {
|
2014-11-09 21:20:40 +01:00
|
|
|
UI_but_flag_enable(but, UI_BUT_REDALERT);
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-23 14:54:06 +02:00
|
|
|
if (layout->activate_init_) {
|
2019-03-20 22:40:38 +11:00
|
|
|
UI_but_flag_enable(but, UI_BUT_ACTIVATE_ON_INIT);
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2009-05-19 17:13:33 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-21 14:39:09 +10:00
|
|
|
/* The resulting button may have the icon set since boolean button drawing
|
|
|
|
|
* is being 'helpful' and adding an icon for us.
|
|
|
|
|
* In this case we want the ability not to have an icon.
|
|
|
|
|
*
|
|
|
|
|
* We could pass an argument not to set the icon to begin with however this is the one case
|
2021-06-24 15:56:58 +10:00
|
|
|
* the functionality is needed. */
|
2019-05-21 14:39:09 +10:00
|
|
|
if (but && no_icon) {
|
|
|
|
|
if ((icon == ICON_NONE) && (but->icon != ICON_NONE)) {
|
|
|
|
|
ui_def_but_icon_clear(but);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-05 12:47:46 +10:00
|
|
|
/* Mark non-embossed text-fields inside a list-box. */
|
2018-06-29 21:13:35 +02:00
|
|
|
if (but && (block->flag & UI_BLOCK_LIST_ITEM) && (but->type == UI_BTYPE_TEXT) &&
|
2025-03-31 00:36:46 +02:00
|
|
|
ELEM(but->emboss, blender::ui::EmbossType::None, blender::ui::EmbossType::NoneOrStatus))
|
2021-06-28 19:41:28 +02:00
|
|
|
{
|
2014-11-09 21:20:40 +01:00
|
|
|
UI_but_flag_enable(but, UI_BUT_LIST_ITEM);
|
2013-11-23 18:43:23 +01:00
|
|
|
}
|
|
|
|
|
|
UI: Support semi-modal text input while other UI stays interactive
Adds support for text buttons that capture text input, while the rest of the
UI stays interactive. This is useful for example for filter buttons in popups
that are used for searching. Current search popups are an ad-hoc implementation
that doesn't use the normal widget system (and thus are quite limited).
For the brush assets project this is important to allow quickly popping up the
brush asset shelf popup, immediately typing to search a brush, and activating
a brush with a single click (rather than having to confirm text input first).
All UI elements stay interactive with hover feedback, changing asset library
and catalogs is possible, tooltips and context menus can be opened, and any
text input is still sent to the search button.
Normal search popups already keep their search results interactive like this
during text input, but are too limited because they don't use our widget
system. For example custom layouts are not possible with them. With this
feature implemented, we could consider rewriting them to use the widget
system, removing the ad-hoc implementation.
Part of the brush assets project, see:
- https://projects.blender.org/blender/blender/issues/116337
- https://projects.blender.org/blender/blender/pulls/106303
Initially reviewed in:
https://projects.blender.org/blender/blender/pulls/122871
2024-07-06 12:22:16 +02:00
|
|
|
if (but) {
|
|
|
|
|
if (placeholder) {
|
2025-05-19 17:25:52 +02:00
|
|
|
UI_but_placeholder_set(but, *placeholder);
|
UI: Support semi-modal text input while other UI stays interactive
Adds support for text buttons that capture text input, while the rest of the
UI stays interactive. This is useful for example for filter buttons in popups
that are used for searching. Current search popups are an ad-hoc implementation
that doesn't use the normal widget system (and thus are quite limited).
For the brush assets project this is important to allow quickly popping up the
brush asset shelf popup, immediately typing to search a brush, and activating
a brush with a single click (rather than having to confirm text input first).
All UI elements stay interactive with hover feedback, changing asset library
and catalogs is possible, tooltips and context menus can be opened, and any
text input is still sent to the search button.
Normal search popups already keep their search results interactive like this
during text input, but are too limited because they don't use our widget
system. For example custom layouts are not possible with them. With this
feature implemented, we could consider rewriting them to use the widget
system, removing the ad-hoc implementation.
Part of the brush assets project, see:
- https://projects.blender.org/blender/blender/issues/116337
- https://projects.blender.org/blender/blender/pulls/106303
Initially reviewed in:
https://projects.blender.org/blender/blender/pulls/122871
2024-07-06 12:22:16 +02:00
|
|
|
}
|
|
|
|
|
if (ELEM(but->type, UI_BTYPE_TEXT) && (flag & UI_ITEM_R_TEXT_BUT_FORCE_SEMI_MODAL_ACTIVE)) {
|
|
|
|
|
UI_but_flag2_enable(but, UI_BUT2_FORCE_SEMI_MODAL_ACTIVE);
|
|
|
|
|
}
|
2023-10-12 11:44:08 -07:00
|
|
|
}
|
|
|
|
|
|
2018-06-16 14:48:21 +02:00
|
|
|
#ifdef UI_PROP_DECORATE
|
2018-08-28 00:59:15 +10:00
|
|
|
if (ui_decorate.use_prop_decorate) {
|
2025-02-14 15:29:26 +01:00
|
|
|
uiBut *but_decorate = ui_decorate.but ? block->next_but(ui_decorate.but) : block->first_but();
|
|
|
|
|
|
|
|
|
|
/* Move temporarily last buts to avoid multiple reallocations while inserting decorators. */
|
|
|
|
|
blender::Vector<std::unique_ptr<uiBut>> tmp;
|
2025-03-24 16:03:55 +01:00
|
|
|
tmp.reserve(ui_decorate.len);
|
2025-02-14 15:29:26 +01:00
|
|
|
while (but_decorate && but_decorate != block->buttons.last().get()) {
|
|
|
|
|
tmp.append(block->buttons.pop_last());
|
|
|
|
|
}
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
const bool use_blank_decorator = (flag & UI_ITEM_R_FORCE_BLANK_DECORATE);
|
2025-04-26 21:07:34 +02:00
|
|
|
uiLayout *layout_col = &ui_decorate.layout->column(false);
|
2025-04-23 14:54:06 +02:00
|
|
|
layout_col->space_ = 0;
|
|
|
|
|
layout_col->emboss_ = blender::ui::EmbossType::None;
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
|
2018-06-16 14:48:21 +02:00
|
|
|
int i;
|
2018-06-18 07:52:17 +02:00
|
|
|
for (i = 0; i < ui_decorate.len && but_decorate; i++) {
|
2022-11-25 23:48:02 -06:00
|
|
|
PointerRNA *ptr_dec = use_blank_decorator ? nullptr : &but_decorate->rnapoin;
|
|
|
|
|
PropertyRNA *prop_dec = use_blank_decorator ? nullptr : but_decorate->rnaprop;
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
|
2018-06-16 14:48:21 +02:00
|
|
|
/* The icons are set in 'ui_but_anim_flag' */
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
uiItemDecoratorR_prop(layout_col, ptr_dec, prop_dec, but_decorate->rnaindex);
|
2025-02-14 15:29:26 +01:00
|
|
|
but = block->buttons.last().get();
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
|
2025-02-14 15:29:26 +01:00
|
|
|
if (!tmp.is_empty()) {
|
|
|
|
|
block->buttons.append(tmp.pop_last());
|
|
|
|
|
but_decorate = block->buttons.last().get();
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
but_decorate = nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
while (!tmp.is_empty()) {
|
|
|
|
|
block->buttons.append(tmp.pop_last());
|
2018-06-16 14:48:21 +02:00
|
|
|
}
|
2018-06-18 07:52:17 +02:00
|
|
|
BLI_assert(ELEM(i, 1, ui_decorate.len));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-24 17:22:28 +02:00
|
|
|
layout->flag_ &= ~uiItemInternalFlag::PropDecorateNoPad;
|
2018-06-16 14:48:21 +02:00
|
|
|
}
|
|
|
|
|
#endif /* UI_PROP_DECORATE */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-13 14:10:05 +02:00
|
|
|
if (no_bg) {
|
2025-04-23 14:54:06 +02:00
|
|
|
layout->emboss_ = prev_emboss;
|
2018-05-13 14:10:05 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-03-12 19:24:47 +11:00
|
|
|
/* ensure text isn't added to icon_only buttons */
|
|
|
|
|
if (but && icon_only) {
|
2024-01-16 21:04:17 +01:00
|
|
|
BLI_assert(but->str.empty());
|
2009-03-13 13:38:41 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2025-05-08 20:45:37 +02:00
|
|
|
void uiLayout::prop(PointerRNA *ptr,
|
|
|
|
|
const StringRefNull propname,
|
|
|
|
|
const eUI_Item_Flag flag,
|
2025-05-19 17:25:52 +02:00
|
|
|
const std::optional<StringRef> name,
|
2025-05-08 20:45:37 +02:00
|
|
|
int icon)
|
2009-03-13 13:38:41 +00:00
|
|
|
{
|
2024-12-06 14:08:10 +01:00
|
|
|
PropertyRNA *prop = RNA_struct_find_property(ptr, propname.c_str());
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!prop) {
|
2025-05-08 20:45:37 +02:00
|
|
|
ui_item_disabled(this, propname.c_str());
|
2024-12-06 14:08:10 +01:00
|
|
|
RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname.c_str());
|
2009-04-15 15:09:36 +00:00
|
|
|
return;
|
2009-04-22 18:39:44 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-05-10 03:39:31 +02:00
|
|
|
this->prop(ptr, prop, RNA_NO_INDEX, 0, flag, name, icon);
|
2009-04-22 18:39:44 +00:00
|
|
|
}
|
|
|
|
|
|
2019-03-25 18:55:38 +11:00
|
|
|
void uiItemFullR_with_popover(uiLayout *layout,
|
|
|
|
|
PointerRNA *ptr,
|
|
|
|
|
PropertyRNA *prop,
|
|
|
|
|
int index,
|
|
|
|
|
int value,
|
2023-07-29 15:06:33 +10:00
|
|
|
const eUI_Item_Flag flag,
|
2024-12-06 14:08:10 +01:00
|
|
|
const std::optional<StringRefNull> name,
|
2019-03-25 18:55:38 +11:00
|
|
|
int icon,
|
|
|
|
|
const char *panel_type)
|
|
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
uiBlock *block = layout->root_->block;
|
2025-02-14 15:29:26 +01:00
|
|
|
int i = block->buttons.size();
|
2025-05-10 03:39:31 +02:00
|
|
|
layout->prop(ptr, prop, index, value, flag, name, icon);
|
2025-02-14 15:29:26 +01:00
|
|
|
for (; i < block->buttons.size(); i++) {
|
|
|
|
|
uiBut *but = block->buttons[i].get();
|
2020-03-09 16:27:24 +01:00
|
|
|
if (but->rnaprop == prop && ELEM(but->type, UI_BTYPE_MENU, UI_BTYPE_COLOR)) {
|
2019-03-25 20:10:32 +11:00
|
|
|
ui_but_rna_menu_convert_to_panel_type(but, panel_type);
|
2019-03-25 18:55:38 +11:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-02-14 15:29:26 +01:00
|
|
|
if (i == block->buttons.size()) {
|
2024-12-06 14:08:10 +01:00
|
|
|
const StringRefNull propname = RNA_property_identifier(prop);
|
2019-03-25 18:55:38 +11:00
|
|
|
ui_item_disabled(layout, panel_type);
|
|
|
|
|
RNA_warning("property could not use a popover: %s.%s (%s)",
|
|
|
|
|
RNA_struct_identifier(ptr->type),
|
2024-12-06 14:08:10 +01:00
|
|
|
propname.c_str(),
|
2019-03-25 18:55:38 +11:00
|
|
|
panel_type);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2019-03-25 20:31:06 +11:00
|
|
|
void uiItemFullR_with_menu(uiLayout *layout,
|
|
|
|
|
PointerRNA *ptr,
|
|
|
|
|
PropertyRNA *prop,
|
|
|
|
|
int index,
|
|
|
|
|
int value,
|
2023-07-29 15:06:33 +10:00
|
|
|
const eUI_Item_Flag flag,
|
2024-12-06 14:08:10 +01:00
|
|
|
const std::optional<StringRefNull> name,
|
2019-03-25 20:31:06 +11:00
|
|
|
int icon,
|
|
|
|
|
const char *menu_type)
|
|
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
uiBlock *block = layout->root_->block;
|
2025-02-14 15:29:26 +01:00
|
|
|
int i = block->buttons.size();
|
2025-05-10 03:39:31 +02:00
|
|
|
layout->prop(ptr, prop, index, value, flag, name, icon);
|
2025-02-14 15:29:26 +01:00
|
|
|
while (i < block->buttons.size()) {
|
|
|
|
|
uiBut *but = block->buttons[i].get();
|
2019-03-25 20:31:06 +11:00
|
|
|
if (but->rnaprop == prop && but->type == UI_BTYPE_MENU) {
|
|
|
|
|
ui_but_rna_menu_convert_to_menu_type(but, menu_type);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2025-02-14 15:29:26 +01:00
|
|
|
i++;
|
2019-03-25 20:31:06 +11:00
|
|
|
}
|
2025-02-14 15:29:26 +01:00
|
|
|
if (i == block->buttons.size()) {
|
2024-12-06 14:08:10 +01:00
|
|
|
const StringRefNull propname = RNA_property_identifier(prop);
|
2019-03-25 20:31:06 +11:00
|
|
|
ui_item_disabled(layout, menu_type);
|
|
|
|
|
RNA_warning("property could not use a menu: %s.%s (%s)",
|
|
|
|
|
RNA_struct_identifier(ptr->type),
|
2024-12-06 14:08:10 +01:00
|
|
|
propname.c_str(),
|
2019-03-25 20:31:06 +11:00
|
|
|
menu_type);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2024-12-06 14:08:10 +01:00
|
|
|
void uiItemEnumR_prop(uiLayout *layout,
|
|
|
|
|
const std::optional<StringRefNull> name,
|
|
|
|
|
int icon,
|
|
|
|
|
PointerRNA *ptr,
|
|
|
|
|
PropertyRNA *prop,
|
|
|
|
|
int value)
|
2015-08-18 19:04:06 +10:00
|
|
|
{
|
|
|
|
|
if (RNA_property_type(prop) != PROP_ENUM) {
|
2024-12-06 14:08:10 +01:00
|
|
|
const StringRefNull propname = RNA_property_identifier(prop);
|
|
|
|
|
ui_item_disabled(layout, propname.c_str());
|
|
|
|
|
RNA_warning("property not an enum: %s.%s", RNA_struct_identifier(ptr->type), propname.c_str());
|
2015-08-18 19:04:06 +10:00
|
|
|
return;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-05-10 03:39:31 +02:00
|
|
|
layout->prop(ptr, prop, RNA_ENUM_VALUE, value, UI_ITEM_NONE, name, icon);
|
2015-08-18 19:04:06 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-08-24 11:44:28 +10:00
|
|
|
void uiItemEnumR_string_prop(uiLayout *layout,
|
2022-11-25 23:48:02 -06:00
|
|
|
PointerRNA *ptr,
|
2018-08-24 11:44:28 +10:00
|
|
|
PropertyRNA *prop,
|
|
|
|
|
const char *value,
|
2024-12-06 14:08:10 +01:00
|
|
|
const std::optional<StringRefNull> name,
|
2018-08-24 11:44:28 +10:00
|
|
|
int icon)
|
2009-07-02 19:41:31 +00:00
|
|
|
{
|
2018-08-24 11:44:28 +10:00
|
|
|
if (UNLIKELY(RNA_property_type(prop) != PROP_ENUM)) {
|
2024-12-06 14:08:10 +01:00
|
|
|
const StringRefNull propname = RNA_property_identifier(prop);
|
|
|
|
|
ui_item_disabled(layout, propname.c_str());
|
|
|
|
|
RNA_warning("not an enum property: %s.%s", RNA_struct_identifier(ptr->type), propname.c_str());
|
2009-07-02 19:41:31 +00:00
|
|
|
return;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-02 13:02:30 -05:00
|
|
|
const EnumPropertyItem *item;
|
|
|
|
|
bool free;
|
2022-11-25 23:48:02 -06:00
|
|
|
RNA_property_enum_items(
|
2025-04-23 16:37:14 +02:00
|
|
|
static_cast<bContext *>(layout->root_->block->evil_C), ptr, prop, &item, nullptr, &free);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-02 13:02:30 -05:00
|
|
|
int ivalue;
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!RNA_enum_value_from_id(item, value, &ivalue)) {
|
2024-12-06 14:08:10 +01:00
|
|
|
const StringRefNull propname = RNA_property_identifier(prop);
|
2012-01-21 22:00:40 +00:00
|
|
|
if (free) {
|
2025-04-12 17:25:55 +02:00
|
|
|
MEM_freeN(item);
|
2012-01-21 22:00:40 +00:00
|
|
|
}
|
2024-12-06 14:08:10 +01:00
|
|
|
ui_item_disabled(layout, propname.c_str());
|
2011-09-09 01:29:53 +00:00
|
|
|
RNA_warning("enum property value not found: %s", value);
|
2009-07-02 19:41:31 +00:00
|
|
|
return;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-02 13:02:30 -05:00
|
|
|
for (int a = 0; item[a].identifier; a++) {
|
2020-01-15 16:09:27 +01:00
|
|
|
if (item[a].identifier[0] == '\0') {
|
|
|
|
|
/* Skip enum item separators. */
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
if (item[a].value == ivalue) {
|
2024-12-06 14:44:35 -05:00
|
|
|
const StringRefNull item_name = name.value_or(
|
|
|
|
|
CTX_IFACE_(RNA_property_translation_context(prop), item[a].name));
|
|
|
|
|
const eUI_Item_Flag flag = !item_name.is_empty() ? UI_ITEM_NONE : UI_ITEM_R_ICON_ONLY;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-05-10 03:39:31 +02:00
|
|
|
layout->prop(ptr, prop, RNA_ENUM_VALUE, ivalue, flag, item_name, icon ? icon : item[a].icon);
|
2009-07-02 19:41:31 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2012-01-21 22:00:40 +00:00
|
|
|
if (free) {
|
2025-04-12 17:25:55 +02:00
|
|
|
MEM_freeN(item);
|
2012-01-21 22:00:40 +00:00
|
|
|
}
|
2009-07-02 19:41:31 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-08-24 11:44:28 +10:00
|
|
|
void uiItemEnumR_string(uiLayout *layout,
|
2022-11-25 23:48:02 -06:00
|
|
|
PointerRNA *ptr,
|
2024-12-06 14:08:10 +01:00
|
|
|
const StringRefNull propname,
|
2018-08-24 11:44:28 +10:00
|
|
|
const char *value,
|
2024-12-06 14:08:10 +01:00
|
|
|
const std::optional<StringRefNull> name,
|
2018-08-24 11:44:28 +10:00
|
|
|
int icon)
|
|
|
|
|
{
|
2024-12-06 14:08:10 +01:00
|
|
|
PropertyRNA *prop = RNA_struct_find_property(ptr, propname.c_str());
|
2022-11-25 23:48:02 -06:00
|
|
|
if (UNLIKELY(prop == nullptr)) {
|
2024-12-06 14:08:10 +01:00
|
|
|
ui_item_disabled(layout, propname.c_str());
|
|
|
|
|
RNA_warning(
|
|
|
|
|
"enum property not found: %s.%s", RNA_struct_identifier(ptr->type), propname.c_str());
|
2018-08-24 11:44:28 +10:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
uiItemEnumR_string_prop(layout, ptr, prop, value, name, icon);
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-06 14:08:10 +01:00
|
|
|
void uiItemsEnumR(uiLayout *layout, PointerRNA *ptr, const StringRefNull propname)
|
2009-04-22 18:39:44 +00:00
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
uiBlock *block = layout->root_->block;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-06 14:08:10 +01:00
|
|
|
PropertyRNA *prop = RNA_struct_find_property(ptr, propname.c_str());
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!prop) {
|
2024-12-06 14:08:10 +01:00
|
|
|
ui_item_disabled(layout, propname.c_str());
|
|
|
|
|
RNA_warning(
|
|
|
|
|
"enum property not found: %s.%s", RNA_struct_identifier(ptr->type), propname.c_str());
|
2009-04-22 18:39:44 +00:00
|
|
|
return;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (RNA_property_type(prop) != PROP_ENUM) {
|
2024-12-06 14:08:10 +01:00
|
|
|
RNA_warning("not an enum property: %s.%s", RNA_struct_identifier(ptr->type), propname.c_str());
|
2011-03-25 04:36:10 +00:00
|
|
|
return;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-05-03 20:51:42 +02:00
|
|
|
uiLayout *split = &layout->split(0.0f, false);
|
2025-04-26 21:07:34 +02:00
|
|
|
uiLayout *column = &split->column(false);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-02 13:02:30 -05:00
|
|
|
int totitem;
|
|
|
|
|
const EnumPropertyItem *item;
|
|
|
|
|
bool free;
|
2022-11-25 23:48:02 -06:00
|
|
|
RNA_property_enum_items_gettexted(
|
|
|
|
|
static_cast<bContext *>(block->evil_C), ptr, prop, &item, &totitem, &free);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-09-09 18:41:07 +02:00
|
|
|
for (int i = 0; i < totitem; i++) {
|
2020-07-03 14:20:10 +02:00
|
|
|
if (item[i].identifier[0]) {
|
|
|
|
|
uiItemEnumR_prop(column, item[i].name, item[i].icon, ptr, prop, item[i].value);
|
2025-02-14 15:29:26 +01:00
|
|
|
ui_but_tip_from_enum_item(block->buttons.last().get(), &item[i]);
|
2020-07-03 14:20:10 +02:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (item[i].name) {
|
|
|
|
|
if (i != 0) {
|
2025-04-26 21:07:34 +02:00
|
|
|
column = &split->column(false);
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2020-07-03 14:20:10 +02:00
|
|
|
|
2025-05-08 17:21:08 +02:00
|
|
|
column->label(item[i].name, ICON_NONE);
|
2025-02-14 15:29:26 +01:00
|
|
|
uiBut *bt = block->buttons.last().get();
|
2020-07-03 14:20:10 +02:00
|
|
|
bt->drawflag = UI_BUT_TEXT_LEFT;
|
|
|
|
|
|
|
|
|
|
ui_but_tip_from_enum_item(bt, &item[i]);
|
|
|
|
|
}
|
|
|
|
|
else {
|
2025-05-13 17:54:26 +02:00
|
|
|
column->separator();
|
2009-08-21 02:51:56 +00:00
|
|
|
}
|
|
|
|
|
}
|
2020-07-03 14:20:10 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-07-03 14:20:10 +02:00
|
|
|
if (free) {
|
2025-04-12 17:25:55 +02:00
|
|
|
MEM_freeN(item);
|
2009-04-22 18:39:44 +00:00
|
|
|
}
|
2009-03-13 13:38:41 +00:00
|
|
|
}
|
|
|
|
|
|
2009-06-27 01:15:31 +00:00
|
|
|
/* Pointer RNA button with search */
|
|
|
|
|
|
2019-03-25 12:19:55 +11:00
|
|
|
static void search_id_collection(StructRNA *ptype, PointerRNA *r_ptr, PropertyRNA **r_prop)
|
2009-06-27 01:15:31 +00:00
|
|
|
{
|
|
|
|
|
/* look for collection property in Main */
|
2021-02-05 16:23:34 +11:00
|
|
|
/* NOTE: using global Main is OK-ish here, UI shall not access other Mains anyway. */
|
2023-09-06 00:48:50 +02:00
|
|
|
*r_ptr = RNA_main_pointer_create(G_MAIN);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-11-25 23:48:02 -06:00
|
|
|
*r_prop = nullptr;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-03-25 12:19:55 +11:00
|
|
|
RNA_STRUCT_BEGIN (r_ptr, iprop) {
|
2009-06-27 01:15:31 +00:00
|
|
|
/* if it's a collection and has same pointer type, we've got it */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (RNA_property_type(iprop) == PROP_COLLECTION) {
|
2020-10-02 13:02:30 -05:00
|
|
|
StructRNA *srna = RNA_property_pointer_type(r_ptr, iprop);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (ptype == srna) {
|
2019-03-25 12:19:55 +11:00
|
|
|
*r_prop = iprop;
|
2009-06-27 01:15:31 +00:00
|
|
|
break;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
2009-06-27 01:15:31 +00:00
|
|
|
}
|
|
|
|
|
RNA_STRUCT_END;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-05-08 12:01:35 +10:00
|
|
|
static void ui_rna_collection_search_arg_free_fn(void *ptr)
|
2020-04-08 23:08:32 +02:00
|
|
|
{
|
2022-11-25 23:48:02 -06:00
|
|
|
uiRNACollectionSearch *coll_search = static_cast<uiRNACollectionSearch *>(ptr);
|
2020-04-08 23:08:32 +02:00
|
|
|
UI_butstore_free(coll_search->butstore_block, coll_search->butstore);
|
2024-10-08 12:14:03 +02:00
|
|
|
MEM_delete(coll_search);
|
2020-04-08 23:08:32 +02:00
|
|
|
}
|
|
|
|
|
|
2022-04-04 03:50:55 +02:00
|
|
|
uiBut *ui_but_add_search(uiBut *but,
|
|
|
|
|
PointerRNA *ptr,
|
|
|
|
|
PropertyRNA *prop,
|
|
|
|
|
PointerRNA *searchptr,
|
|
|
|
|
PropertyRNA *searchprop,
|
2022-05-20 14:30:17 +10:00
|
|
|
const bool results_are_suggestions)
|
2009-06-27 01:15:31 +00:00
|
|
|
{
|
|
|
|
|
/* for ID's we do automatic lookup */
|
2022-05-20 14:30:17 +10:00
|
|
|
bool has_search_fn = false;
|
|
|
|
|
|
2020-10-02 21:24:09 -05:00
|
|
|
PointerRNA sptr;
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!searchprop) {
|
2022-05-20 14:30:17 +10:00
|
|
|
if (RNA_property_type(prop) == PROP_STRING) {
|
|
|
|
|
has_search_fn = (RNA_property_string_search_flag(prop) != 0);
|
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
if (RNA_property_type(prop) == PROP_POINTER) {
|
2020-10-02 13:02:30 -05:00
|
|
|
StructRNA *ptype = RNA_property_pointer_type(ptr, prop);
|
2009-06-27 01:15:31 +00:00
|
|
|
search_id_collection(ptype, &sptr, &searchprop);
|
2012-03-30 01:51:25 +00:00
|
|
|
searchptr = &sptr;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2009-06-27 01:15:31 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-06-27 01:15:31 +00:00
|
|
|
/* turn button into search button */
|
2022-05-20 14:30:17 +10:00
|
|
|
if (has_search_fn || searchprop) {
|
2024-10-08 12:14:03 +02:00
|
|
|
uiRNACollectionSearch *coll_search = MEM_new<uiRNACollectionSearch>(__func__);
|
2020-08-07 14:34:11 +02:00
|
|
|
uiButSearch *search_but;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-08-07 14:34:11 +02:00
|
|
|
but = ui_but_change_type(but, UI_BTYPE_SEARCH_MENU);
|
|
|
|
|
search_but = (uiButSearch *)but;
|
2022-05-20 14:30:17 +10:00
|
|
|
|
|
|
|
|
if (searchptr) {
|
|
|
|
|
search_but->rnasearchpoin = *searchptr;
|
|
|
|
|
search_but->rnasearchprop = searchprop;
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-07 16:33:19 +11:00
|
|
|
but->hardmax = std::max(but->hardmax, 256.0f);
|
2013-11-21 14:43:08 +01:00
|
|
|
but->drawflag |= UI_BUT_ICON_LEFT | UI_BUT_TEXT_LEFT;
|
2015-03-24 15:05:27 +11:00
|
|
|
if (RNA_property_is_unlink(prop)) {
|
2016-11-28 18:59:31 +01:00
|
|
|
but->flag |= UI_BUT_VALUE_CLEAR;
|
2015-03-24 15:05:27 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-05-12 01:42:42 +02:00
|
|
|
coll_search->target_ptr = *ptr;
|
|
|
|
|
coll_search->target_prop = prop;
|
2022-05-20 14:30:17 +10:00
|
|
|
|
|
|
|
|
if (searchptr) {
|
|
|
|
|
coll_search->search_ptr = *searchptr;
|
|
|
|
|
coll_search->search_prop = searchprop;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Rely on `has_search_fn`. */
|
|
|
|
|
coll_search->search_ptr = PointerRNA_NULL;
|
2022-11-25 23:48:02 -06:00
|
|
|
coll_search->search_prop = nullptr;
|
2022-05-20 14:30:17 +10:00
|
|
|
}
|
|
|
|
|
|
2020-04-08 23:08:32 +02:00
|
|
|
coll_search->search_but = but;
|
|
|
|
|
coll_search->butstore_block = but->block;
|
|
|
|
|
coll_search->butstore = UI_butstore_create(coll_search->butstore_block);
|
|
|
|
|
UI_butstore_register(coll_search->butstore, &coll_search->search_but);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-11-24 05:15:48 +00:00
|
|
|
if (RNA_property_type(prop) == PROP_ENUM) {
|
|
|
|
|
/* XXX, this will have a menu string,
|
|
|
|
|
* but in this case we just want the text */
|
2024-01-16 21:04:17 +01:00
|
|
|
but->str.clear();
|
2012-11-24 05:15:48 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-04-04 03:50:55 +02:00
|
|
|
UI_but_func_search_set_results_are_suggestions(but, results_are_suggestions);
|
|
|
|
|
|
2017-05-12 01:42:42 +02:00
|
|
|
UI_but_func_search_set(but,
|
2018-07-01 20:15:21 +02:00
|
|
|
ui_searchbox_create_generic,
|
2020-05-07 23:16:05 +10:00
|
|
|
ui_rna_collection_search_update_fn,
|
2019-03-20 19:26:54 +01:00
|
|
|
coll_search,
|
2021-04-14 11:11:51 -05:00
|
|
|
false,
|
2020-05-08 12:01:35 +10:00
|
|
|
ui_rna_collection_search_arg_free_fn,
|
2022-11-25 23:48:02 -06:00
|
|
|
nullptr,
|
|
|
|
|
nullptr);
|
2022-03-17 17:45:29 +01:00
|
|
|
/* If this is called multiple times for the same button, an earlier call may have taken the
|
|
|
|
|
* else branch below so the button was disabled. Now we have a searchprop, so it can be enabled
|
|
|
|
|
* again. */
|
|
|
|
|
but->flag &= ~UI_BUT_DISABLED;
|
2009-06-27 01:15:31 +00:00
|
|
|
}
|
2017-09-14 10:58:47 +02:00
|
|
|
else if (but->type == UI_BTYPE_SEARCH_MENU) {
|
2019-01-15 23:24:20 +11:00
|
|
|
/* In case we fail to find proper searchprop,
|
|
|
|
|
* so other code might have already set but->type to search menu... */
|
2017-12-28 17:57:18 +01:00
|
|
|
but->flag |= UI_BUT_DISABLED;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2020-08-07 14:34:11 +02:00
|
|
|
|
|
|
|
|
return but;
|
2017-09-14 10:58:47 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-08-24 11:44:28 +10:00
|
|
|
void uiItemPointerR_prop(uiLayout *layout,
|
|
|
|
|
PointerRNA *ptr,
|
|
|
|
|
PropertyRNA *prop,
|
|
|
|
|
PointerRNA *searchptr,
|
|
|
|
|
PropertyRNA *searchprop,
|
2024-12-06 14:08:10 +01:00
|
|
|
const std::optional<StringRefNull> name_opt,
|
2022-04-04 03:50:55 +02:00
|
|
|
int icon,
|
|
|
|
|
bool results_are_suggestions)
|
2009-06-27 01:15:31 +00:00
|
|
|
{
|
2025-04-24 17:22:28 +02:00
|
|
|
const bool use_prop_sep = bool(layout->flag_ & uiItemInternalFlag::PropSep);
|
2023-10-19 09:24:06 -07:00
|
|
|
|
2022-11-25 23:48:02 -06:00
|
|
|
ui_block_new_button_group(uiLayoutGetBlock(layout), uiButtonGroupFlag(0));
|
2020-09-15 09:38:19 -05:00
|
|
|
|
2020-10-02 13:02:30 -05:00
|
|
|
const PropertyType type = RNA_property_type(prop);
|
2014-07-20 01:30:29 +10:00
|
|
|
if (!ELEM(type, PROP_POINTER, PROP_STRING, PROP_ENUM)) {
|
2018-08-24 11:44:28 +10:00
|
|
|
RNA_warning("Property %s.%s must be a pointer, string or enum",
|
|
|
|
|
RNA_struct_identifier(ptr->type),
|
|
|
|
|
RNA_property_identifier(prop));
|
2009-06-27 01:15:31 +00:00
|
|
|
return;
|
|
|
|
|
}
|
2018-08-24 11:44:28 +10:00
|
|
|
if (RNA_property_type(searchprop) != PROP_COLLECTION) {
|
2012-11-24 04:51:56 +00:00
|
|
|
RNA_warning("search collection property is not a collection type: %s.%s",
|
2018-08-24 11:44:28 +10:00
|
|
|
RNA_struct_identifier(searchptr->type),
|
|
|
|
|
RNA_property_identifier(searchprop));
|
use ICON_NULL define rather then 0, makes UI calls less confusing. (no functional change)
eg: uiItemR(row, &dvar_ptr, "type", 0, "", 0); -> uiItemR(row, &dvar_ptr, "type", 0, "", ICON_NULL);
2010-12-23 02:43:40 +00:00
|
|
|
return;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-06-27 01:15:31 +00:00
|
|
|
/* get icon & name */
|
2012-03-30 01:51:25 +00:00
|
|
|
if (icon == ICON_NONE) {
|
2024-07-25 10:17:40 +10:00
|
|
|
const StructRNA *icontype;
|
2019-03-25 10:15:20 +11:00
|
|
|
if (type == PROP_POINTER) {
|
2012-03-30 01:51:25 +00:00
|
|
|
icontype = RNA_property_pointer_type(ptr, prop);
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
|
|
|
|
else {
|
2012-03-30 01:51:25 +00:00
|
|
|
icontype = RNA_property_pointer_type(searchptr, searchprop);
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-30 01:51:25 +00:00
|
|
|
icon = RNA_struct_ui_icon(icontype);
|
2009-06-27 01:15:31 +00:00
|
|
|
}
|
2024-12-06 14:08:10 +01:00
|
|
|
StringRefNull name = name_opt.value_or(RNA_property_ui_name(prop));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-10-19 09:24:06 -07:00
|
|
|
char namestr[UI_MAX_NAME_STR];
|
|
|
|
|
if (use_prop_sep == false) {
|
|
|
|
|
name = ui_item_name_add_colon(name, namestr);
|
|
|
|
|
}
|
|
|
|
|
|
2009-06-27 01:15:31 +00:00
|
|
|
/* create button */
|
2020-10-02 13:02:30 -05:00
|
|
|
uiBlock *block = uiLayoutGetBlock(layout);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-02 13:02:30 -05:00
|
|
|
int w, h;
|
2022-12-29 12:01:32 -05:00
|
|
|
ui_item_rna_size(layout, name, icon, ptr, prop, 0, false, false, &w, &h);
|
2013-01-24 13:02:00 +00:00
|
|
|
w += UI_UNIT_X; /* X icon needs more space */
|
2020-10-02 13:02:30 -05:00
|
|
|
uiBut *but = ui_item_with_label(layout, block, name, icon, ptr, prop, 0, 0, 0, w, h, 0);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-04-04 03:50:55 +02:00
|
|
|
but = ui_but_add_search(but, ptr, prop, searchptr, searchprop, results_are_suggestions);
|
2009-06-27 01:15:31 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-08-24 11:44:28 +10:00
|
|
|
void uiItemPointerR(uiLayout *layout,
|
|
|
|
|
PointerRNA *ptr,
|
2024-12-06 14:08:10 +01:00
|
|
|
const StringRefNull propname,
|
2018-08-24 11:44:28 +10:00
|
|
|
PointerRNA *searchptr,
|
2024-12-06 14:08:10 +01:00
|
|
|
const StringRefNull searchpropname,
|
|
|
|
|
const std::optional<StringRefNull> name,
|
2018-08-24 11:44:28 +10:00
|
|
|
int icon)
|
|
|
|
|
{
|
|
|
|
|
/* validate arguments */
|
2024-12-06 14:08:10 +01:00
|
|
|
PropertyRNA *prop = RNA_struct_find_property(ptr, propname.c_str());
|
2018-08-24 11:44:28 +10:00
|
|
|
if (!prop) {
|
2024-12-06 14:08:10 +01:00
|
|
|
RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname.c_str());
|
2018-08-24 11:44:28 +10:00
|
|
|
return;
|
|
|
|
|
}
|
2024-12-06 14:08:10 +01:00
|
|
|
PropertyRNA *searchprop = RNA_struct_find_property(searchptr, searchpropname.c_str());
|
2018-08-24 11:44:28 +10:00
|
|
|
if (!searchprop) {
|
|
|
|
|
RNA_warning("search collection property not found: %s.%s",
|
|
|
|
|
RNA_struct_identifier(searchptr->type),
|
2024-12-06 14:08:10 +01:00
|
|
|
searchpropname.c_str());
|
2018-08-24 11:44:28 +10:00
|
|
|
return;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-04-04 03:50:55 +02:00
|
|
|
uiItemPointerR_prop(layout, ptr, prop, searchptr, searchprop, name, icon, false);
|
2018-08-24 11:44:28 +10:00
|
|
|
}
|
|
|
|
|
|
2019-03-25 20:31:06 +11:00
|
|
|
void ui_item_menutype_func(bContext *C, uiLayout *layout, void *arg_mt)
|
2009-04-22 18:39:44 +00:00
|
|
|
{
|
2012-03-30 01:51:25 +00:00
|
|
|
MenuType *mt = (MenuType *)arg_mt;
|
2017-11-02 18:19:11 +11:00
|
|
|
UI_menutype_draw(C, mt, layout);
|
2009-04-22 18:39:44 +00:00
|
|
|
}
|
|
|
|
|
|
2018-05-25 15:46:22 +02:00
|
|
|
void ui_item_paneltype_func(bContext *C, uiLayout *layout, void *arg_pt)
|
2018-04-22 17:16:39 +02:00
|
|
|
{
|
2018-05-23 19:46:40 +02:00
|
|
|
PanelType *pt = (PanelType *)arg_pt;
|
2018-05-25 12:19:04 +02:00
|
|
|
UI_paneltype_draw(C, pt, layout);
|
2018-04-22 17:16:39 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-05-05 03:13:47 +10:00
|
|
|
static uiBut *ui_item_menu(uiLayout *layout,
|
2025-01-29 12:49:31 -05:00
|
|
|
const StringRef name,
|
2015-05-05 03:13:47 +10:00
|
|
|
int icon,
|
|
|
|
|
uiMenuCreateFunc func,
|
|
|
|
|
void *arg,
|
|
|
|
|
void *argN,
|
2025-02-14 15:12:48 -05:00
|
|
|
const std::optional<StringRef> tip,
|
2024-08-27 15:35:18 +02:00
|
|
|
bool force_menu,
|
|
|
|
|
uiButArgNFree func_argN_free_fn = MEM_freeN,
|
|
|
|
|
uiButArgNCopy func_argN_copy_fn = MEM_dupallocN)
|
2009-03-13 13:38:41 +00:00
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
uiBlock *block = layout->root_->block;
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
uiLayout *heading_layout = ui_layout_heading_find(layout);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-11-09 21:20:40 +01:00
|
|
|
UI_block_layout_set_current(block, layout);
|
2022-11-25 23:48:02 -06:00
|
|
|
ui_block_new_button_group(block, uiButtonGroupFlag(0));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
if (layout->root_->type == UI_LAYOUT_MENU && !icon) {
|
2012-03-30 01:51:25 +00:00
|
|
|
icon = ICON_BLANK1;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-11-25 23:48:02 -06:00
|
|
|
uiTextIconPadFactor pad_factor = ui_text_pad_compact;
|
2025-04-23 16:37:14 +02:00
|
|
|
if (layout->root_->type == UI_LAYOUT_HEADER) { /* Ugly! */
|
2018-06-13 11:57:09 +02:00
|
|
|
if (icon == ICON_NONE && force_menu) {
|
2018-06-13 11:20:50 +02:00
|
|
|
/* pass */
|
|
|
|
|
}
|
|
|
|
|
else if (force_menu) {
|
2021-09-28 14:07:59 +10:00
|
|
|
pad_factor.text = 1.85;
|
2021-09-30 12:41:01 +10:00
|
|
|
pad_factor.icon_only = 0.6f;
|
2014-01-27 19:10:53 +11:00
|
|
|
}
|
|
|
|
|
else {
|
2021-09-30 12:41:01 +10:00
|
|
|
pad_factor.text = 0.75f;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-05 12:12:28 -05:00
|
|
|
const int w = ui_text_icon_width_ex(layout, name, icon, pad_factor, UI_FSTYLE_WIDGET);
|
2021-09-28 14:07:59 +10:00
|
|
|
const int h = UI_UNIT_Y;
|
|
|
|
|
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
if (heading_layout) {
|
|
|
|
|
ui_layout_heading_label_add(layout, heading_layout, true, true);
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-02 13:02:30 -05:00
|
|
|
uiBut *but;
|
2024-12-06 14:08:10 +01:00
|
|
|
if (!name.is_empty() && icon) {
|
2012-03-24 02:51:46 +00:00
|
|
|
but = uiDefIconTextMenuBut(block, func, arg, icon, name, 0, 0, w, h, tip);
|
2018-12-27 12:48:00 +01:00
|
|
|
}
|
|
|
|
|
else if (icon) {
|
2012-03-24 02:51:46 +00:00
|
|
|
but = uiDefIconMenuBut(block, func, arg, icon, 0, 0, w, h, tip);
|
2024-12-06 14:08:10 +01:00
|
|
|
if (force_menu && !name.is_empty()) {
|
2019-01-04 15:12:12 +01:00
|
|
|
UI_but_drawflag_enable(but, UI_BUT_ICON_LEFT);
|
2018-12-27 12:48:00 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2018-12-27 12:48:00 +01:00
|
|
|
else {
|
2012-03-24 02:51:46 +00:00
|
|
|
but = uiDefMenuBut(block, func, arg, name, 0, 0, w, h, tip);
|
2018-12-27 12:48:00 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-10-30 10:46:29 +11:00
|
|
|
if (argN) {
|
2021-06-24 15:56:58 +10:00
|
|
|
/* ugly! */
|
2018-10-30 10:46:29 +11:00
|
|
|
if (arg != argN) {
|
|
|
|
|
but->poin = (char *)but;
|
|
|
|
|
}
|
2012-03-30 01:51:25 +00:00
|
|
|
but->func_argN = argN;
|
2024-08-27 15:35:18 +02:00
|
|
|
but->func_argN_free_fn = func_argN_free_fn;
|
|
|
|
|
but->func_argN_copy_fn = func_argN_copy_fn;
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
if (ELEM(layout->root_->type, UI_LAYOUT_PANEL, UI_LAYOUT_TOOLBAR) ||
|
2020-09-16 15:28:02 +10:00
|
|
|
/* We never want a drop-down in menu! */
|
2025-04-23 16:37:14 +02:00
|
|
|
(force_menu && layout->root_->type != UI_LAYOUT_MENU))
|
2019-01-15 23:24:20 +11:00
|
|
|
{
|
2014-11-09 21:20:40 +01:00
|
|
|
UI_but_type_set_menu_from_pulldown(but);
|
2010-06-27 19:10:36 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-05-06 18:11:28 +10:00
|
|
|
return but;
|
2009-03-13 13:38:41 +00:00
|
|
|
}
|
|
|
|
|
|
2025-05-14 23:22:56 +02:00
|
|
|
void uiLayout::menu(MenuType *mt, const std::optional<StringRef> name_opt, int icon)
|
2009-04-22 18:39:44 +00:00
|
|
|
{
|
2025-05-14 23:22:56 +02:00
|
|
|
uiBlock *block = root_->block;
|
2022-11-25 23:48:02 -06:00
|
|
|
bContext *C = static_cast<bContext *>(block->evil_C);
|
2021-07-28 12:26:11 +02:00
|
|
|
if (WM_menutype_poll(C, mt) == false) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-29 12:49:31 -05:00
|
|
|
const StringRef name = name_opt.value_or(CTX_IFACE_(mt->translation_context, mt->label));
|
2011-09-15 13:20:18 +00:00
|
|
|
|
2025-05-14 23:22:56 +02:00
|
|
|
if (root_->type == UI_LAYOUT_MENU && !icon) {
|
2012-03-30 01:51:25 +00:00
|
|
|
icon = ICON_BLANK1;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2009-10-06 13:04:31 +00:00
|
|
|
|
2025-05-14 23:22:56 +02:00
|
|
|
ui_item_menu(this,
|
2018-11-14 09:47:23 +11:00
|
|
|
name,
|
|
|
|
|
icon,
|
|
|
|
|
ui_item_menutype_func,
|
|
|
|
|
mt,
|
2022-11-25 23:48:02 -06:00
|
|
|
nullptr,
|
2018-11-14 09:47:23 +11:00
|
|
|
mt->description ? TIP_(mt->description) : "",
|
|
|
|
|
false);
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
}
|
2009-04-22 18:39:44 +00:00
|
|
|
|
2025-05-14 23:22:56 +02:00
|
|
|
void uiLayout::menu(const StringRef menuname, const std::optional<StringRef> name, int icon)
|
2019-05-27 15:30:48 +10:00
|
|
|
{
|
2025-02-04 13:53:30 +01:00
|
|
|
MenuType *mt = WM_menutype_find(menuname, false);
|
2022-11-25 23:48:02 -06:00
|
|
|
if (mt == nullptr) {
|
2025-02-04 13:53:30 +01:00
|
|
|
RNA_warning("not found %s", std::string(menuname).c_str());
|
2019-05-27 15:30:48 +10:00
|
|
|
return;
|
|
|
|
|
}
|
2025-05-14 23:22:56 +02:00
|
|
|
this->menu(mt, name, icon);
|
2019-05-27 15:30:48 +10:00
|
|
|
}
|
|
|
|
|
|
2025-02-04 13:53:30 +01:00
|
|
|
void uiItemMContents(uiLayout *layout, const StringRef menuname)
|
2018-12-20 11:33:08 +11:00
|
|
|
{
|
2025-02-04 13:53:30 +01:00
|
|
|
MenuType *mt = WM_menutype_find(menuname, false);
|
2022-11-25 23:48:02 -06:00
|
|
|
if (mt == nullptr) {
|
2025-02-04 13:53:30 +01:00
|
|
|
RNA_warning("not found %s", std::string(menuname).c_str());
|
2018-12-20 11:33:08 +11:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
uiBlock *block = layout->root_->block;
|
2022-11-25 23:48:02 -06:00
|
|
|
bContext *C = static_cast<bContext *>(block->evil_C);
|
2021-07-28 12:26:11 +02:00
|
|
|
if (WM_menutype_poll(C, mt) == false) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-08-18 14:42:48 +02:00
|
|
|
|
2018-12-20 11:33:08 +11:00
|
|
|
UI_menutype_draw(C, mt, layout);
|
|
|
|
|
}
|
|
|
|
|
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
void uiItemDecoratorR_prop(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index)
|
|
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
uiBlock *block = layout->root_->block;
|
2020-08-07 14:34:11 +02:00
|
|
|
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
UI_block_layout_set_current(block, layout);
|
2025-04-26 21:07:34 +02:00
|
|
|
uiLayout *col = &layout->column(false);
|
2025-04-23 14:54:06 +02:00
|
|
|
col->space_ = 0;
|
|
|
|
|
col->emboss_ = blender::ui::EmbossType::None;
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
|
2022-11-25 23:48:02 -06:00
|
|
|
if (ELEM(nullptr, ptr, prop) || !RNA_property_animateable(ptr, prop)) {
|
2020-08-07 14:34:11 +02:00
|
|
|
uiBut *but = uiDefIconBut(block,
|
|
|
|
|
UI_BTYPE_DECORATOR,
|
|
|
|
|
0,
|
|
|
|
|
ICON_BLANK1,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
UI_UNIT_X,
|
|
|
|
|
UI_UNIT_Y,
|
2022-11-25 23:48:02 -06:00
|
|
|
nullptr,
|
2020-08-07 14:34:11 +02:00
|
|
|
0.0,
|
|
|
|
|
0.0,
|
|
|
|
|
"");
|
2020-04-27 13:50:16 +02:00
|
|
|
but->flag |= UI_BUT_DISABLED;
|
|
|
|
|
return;
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
}
|
2020-04-27 13:50:16 +02:00
|
|
|
|
2023-07-29 15:06:33 +10:00
|
|
|
const bool is_expand = ui_item_rna_is_expand(prop, index, UI_ITEM_NONE);
|
2020-04-27 13:50:16 +02:00
|
|
|
const bool is_array = RNA_property_array_check(prop);
|
|
|
|
|
|
|
|
|
|
/* Loop for the array-case, but only do in case of an expanded array. */
|
|
|
|
|
for (int i = 0; i < (is_expand ? RNA_property_array_length(ptr, prop) : 1); i++) {
|
2023-02-03 16:12:14 +01:00
|
|
|
uiButDecorator *but = (uiButDecorator *)uiDefIconBut(block,
|
|
|
|
|
UI_BTYPE_DECORATOR,
|
|
|
|
|
0,
|
|
|
|
|
ICON_DOT,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
UI_UNIT_X,
|
|
|
|
|
UI_UNIT_Y,
|
|
|
|
|
nullptr,
|
|
|
|
|
0.0,
|
|
|
|
|
0.0,
|
|
|
|
|
TIP_("Animate property"));
|
|
|
|
|
|
|
|
|
|
UI_but_func_set(but, ui_but_anim_decorate_cb, but, nullptr);
|
|
|
|
|
but->flag |= UI_BUT_UNDO | UI_BUT_DRAG_LOCK;
|
2024-03-08 11:31:01 +11:00
|
|
|
/* Decorators have their own RNA data, using the normal #uiBut RNA members has many
|
|
|
|
|
* side-effects. */
|
2023-02-03 16:12:14 +01:00
|
|
|
but->decorated_rnapoin = *ptr;
|
|
|
|
|
but->decorated_rnaprop = prop;
|
2023-06-06 11:30:49 +02:00
|
|
|
/* ui_def_but_rna() sets non-array buttons to have a RNA index of 0. */
|
|
|
|
|
but->decorated_rnaindex = (!is_array || is_expand) ? i : index;
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-06 14:08:10 +01:00
|
|
|
void uiItemDecoratorR(uiLayout *layout,
|
|
|
|
|
PointerRNA *ptr,
|
|
|
|
|
const std::optional<StringRefNull> propname,
|
|
|
|
|
int index)
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
{
|
2022-11-25 23:48:02 -06:00
|
|
|
PropertyRNA *prop = nullptr;
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
|
2020-04-27 13:50:16 +02:00
|
|
|
if (ptr && propname) {
|
|
|
|
|
/* validate arguments */
|
2024-12-06 14:08:10 +01:00
|
|
|
prop = RNA_struct_find_property(ptr, propname->c_str());
|
2020-04-27 13:50:16 +02:00
|
|
|
if (!prop) {
|
2024-12-06 14:08:10 +01:00
|
|
|
ui_item_disabled(layout, propname->c_str());
|
|
|
|
|
RNA_warning(
|
|
|
|
|
"property not found: %s.%s", RNA_struct_identifier(ptr->type), propname->c_str());
|
2020-04-27 13:50:16 +02:00
|
|
|
return;
|
|
|
|
|
}
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
}
|
|
|
|
|
|
2022-11-25 23:48:02 -06:00
|
|
|
/* ptr and prop are allowed to be nullptr here. */
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
uiItemDecoratorR_prop(layout, ptr, prop, index);
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-06 14:08:10 +01:00
|
|
|
void uiItemPopoverPanel_ptr(uiLayout *layout,
|
|
|
|
|
const bContext *C,
|
|
|
|
|
PanelType *pt,
|
2025-02-04 13:53:30 +01:00
|
|
|
const std::optional<StringRef> name_opt,
|
2024-12-06 14:08:10 +01:00
|
|
|
int icon)
|
2018-04-22 17:16:39 +02:00
|
|
|
{
|
2025-02-04 13:53:30 +01:00
|
|
|
const StringRef name = name_opt.value_or(CTX_IFACE_(pt->translation_context, pt->label));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
if (layout->root_->type == UI_LAYOUT_MENU && !icon) {
|
2018-04-22 17:16:39 +02:00
|
|
|
icon = ICON_BLANK1;
|
2018-06-09 17:36:28 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-07-07 20:00:35 +02:00
|
|
|
const bContextStore *previous_ctx = CTX_store_get(C);
|
|
|
|
|
/* Set context for polling (and panel header drawing). */
|
2025-04-23 16:37:14 +02:00
|
|
|
CTX_store_set(const_cast<bContext *>(C), layout->context_);
|
2024-07-07 20:00:35 +02:00
|
|
|
|
2022-11-25 23:48:02 -06:00
|
|
|
const bool ok = (pt->poll == nullptr) || pt->poll(C, pt);
|
|
|
|
|
if (ok && (pt->draw_header != nullptr)) {
|
2025-04-25 19:45:25 +02:00
|
|
|
layout = &layout->row(true);
|
2022-11-25 23:48:02 -06:00
|
|
|
Panel panel{};
|
2023-10-10 18:17:31 +02:00
|
|
|
Panel_Runtime panel_runtime{};
|
|
|
|
|
panel.runtime = &panel_runtime;
|
2022-11-25 23:48:02 -06:00
|
|
|
panel.type = pt;
|
|
|
|
|
panel.layout = layout;
|
2022-11-28 15:52:58 -06:00
|
|
|
panel.flag = PNL_POPOVER;
|
2018-06-09 17:36:28 +02:00
|
|
|
pt->draw_header(C, &panel);
|
|
|
|
|
}
|
2024-07-07 20:00:35 +02:00
|
|
|
|
|
|
|
|
CTX_store_set(const_cast<bContext *>(C), previous_ctx);
|
|
|
|
|
|
2021-02-16 09:38:42 -05:00
|
|
|
uiBut *but = ui_item_menu(
|
2023-03-28 00:00:18 +02:00
|
|
|
layout, name, icon, ui_item_paneltype_func, pt, nullptr, TIP_(pt->description), true);
|
2018-04-22 17:16:39 +02:00
|
|
|
but->type = UI_BTYPE_POPOVER;
|
2018-06-09 17:36:28 +02:00
|
|
|
if (!ok) {
|
2018-05-02 10:58:56 +02:00
|
|
|
but->flag |= UI_BUT_DISABLED;
|
|
|
|
|
}
|
2018-04-22 17:16:39 +02:00
|
|
|
}
|
|
|
|
|
|
2024-12-06 14:08:10 +01:00
|
|
|
void uiItemPopoverPanel(uiLayout *layout,
|
|
|
|
|
const bContext *C,
|
2025-02-04 13:53:30 +01:00
|
|
|
const StringRef panel_type,
|
|
|
|
|
std::optional<blender::StringRef> name_opt,
|
2024-12-06 14:08:10 +01:00
|
|
|
int icon)
|
2018-04-22 17:16:39 +02:00
|
|
|
{
|
2025-02-04 13:53:30 +01:00
|
|
|
PanelType *pt = WM_paneltype_find(panel_type, true);
|
2022-11-25 23:48:02 -06:00
|
|
|
if (pt == nullptr) {
|
2025-02-04 13:53:30 +01:00
|
|
|
RNA_warning("Panel type not found '%s'", std::string(panel_type).c_str());
|
2018-04-22 17:16:39 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2024-12-06 14:08:10 +01:00
|
|
|
uiItemPopoverPanel_ptr(layout, C, pt, name_opt, icon);
|
2018-04-22 17:16:39 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-04-22 17:16:39 +02:00
|
|
|
void uiItemPopoverPanelFromGroup(uiLayout *layout,
|
|
|
|
|
bContext *C,
|
|
|
|
|
int space_id,
|
|
|
|
|
int region_id,
|
|
|
|
|
const char *context,
|
|
|
|
|
const char *category)
|
|
|
|
|
{
|
|
|
|
|
SpaceType *st = BKE_spacetype_from_id(space_id);
|
2022-11-25 23:48:02 -06:00
|
|
|
if (st == nullptr) {
|
2018-04-22 17:16:39 +02:00
|
|
|
RNA_warning("space type not found %d", space_id);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
ARegionType *art = BKE_regiontype_from_id(st, region_id);
|
2022-11-25 23:48:02 -06:00
|
|
|
if (art == nullptr) {
|
2018-04-22 17:16:39 +02:00
|
|
|
RNA_warning("region type not found %d", region_id);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-04-03 19:15:01 +02:00
|
|
|
LISTBASE_FOREACH (PanelType *, pt, &art->paneltypes) {
|
2018-04-22 17:16:39 +02:00
|
|
|
/* Causes too many panels, check context. */
|
2018-06-09 14:21:39 +02:00
|
|
|
if (pt->parent_id[0] == '\0') {
|
|
|
|
|
if (/* (*context == '\0') || */ STREQ(pt->context, context)) {
|
|
|
|
|
if ((*category == '\0') || STREQ(pt->category, category)) {
|
2022-11-25 23:48:02 -06:00
|
|
|
if (pt->poll == nullptr || pt->poll(C, pt)) {
|
2024-12-06 14:08:10 +01:00
|
|
|
uiItemPopoverPanel_ptr(layout, C, pt, std::nullopt, ICON_NONE);
|
2018-06-09 14:21:39 +02:00
|
|
|
}
|
2018-04-22 17:16:39 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
/* label item */
|
2024-12-06 14:08:10 +01:00
|
|
|
static uiBut *uiItemL_(uiLayout *layout, const StringRef name, int icon)
|
2009-04-22 18:39:44 +00:00
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
uiBlock *block = layout->root_->block;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-11-09 21:20:40 +01:00
|
|
|
UI_block_layout_set_current(block, layout);
|
2022-11-25 23:48:02 -06:00
|
|
|
ui_block_new_button_group(block, uiButtonGroupFlag(0));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
if (layout->root_->type == UI_LAYOUT_MENU && !icon) {
|
2012-03-30 01:51:25 +00:00
|
|
|
icon = ICON_BLANK1;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-07-19 21:57:49 +02:00
|
|
|
const int w = ui_text_icon_width_ex(layout, name, icon, ui_text_pad_none, UI_FSTYLE_WIDGET);
|
2020-10-02 13:02:30 -05:00
|
|
|
uiBut *but;
|
2024-12-06 14:08:10 +01:00
|
|
|
if (icon && !name.is_empty()) {
|
2024-03-01 14:26:45 -05:00
|
|
|
but = uiDefIconTextBut(
|
2025-02-14 15:12:48 -05:00
|
|
|
block, UI_BTYPE_LABEL, 0, icon, name, 0, 0, w, UI_UNIT_Y, nullptr, 0.0, 0.0, std::nullopt);
|
2018-09-19 08:34:41 +10:00
|
|
|
}
|
|
|
|
|
else if (icon) {
|
|
|
|
|
but = uiDefIconBut(
|
2025-02-14 15:12:48 -05:00
|
|
|
block, UI_BTYPE_LABEL, 0, icon, 0, 0, w, UI_UNIT_Y, nullptr, 0.0, 0.0, std::nullopt);
|
2018-09-19 08:34:41 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2025-02-14 15:12:48 -05:00
|
|
|
but = uiDefBut(
|
|
|
|
|
block, UI_BTYPE_LABEL, 0, name, 0, 0, w, UI_UNIT_Y, nullptr, 0.0, 0.0, std::nullopt);
|
2018-09-19 08:34:41 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-03-21 12:58:31 +00:00
|
|
|
/* to compensate for string size padding in ui_text_icon_width,
|
|
|
|
|
* make text aligned right if the layout is aligned right.
|
|
|
|
|
*/
|
|
|
|
|
if (uiLayoutGetAlignment(layout) == UI_LAYOUT_ALIGN_RIGHT) {
|
2013-11-21 14:43:08 +01:00
|
|
|
but->drawflag &= ~UI_BUT_TEXT_LEFT; /* default, needs to be unset */
|
|
|
|
|
but->drawflag |= UI_BUT_TEXT_RIGHT;
|
2013-03-21 12:58:31 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-07-05 12:47:46 +10:00
|
|
|
/* Mark as a label inside a list-box. */
|
Fix [#35750] list items in properties editor (text colors not following list item theme).
Issue goes back since we stopped using LISTROW button to draw item's name (i.e. since we have custom buttons in list items!).
This commit:
* Adds a new flag to uiBlock, UI_BLOCK_LIST_ITEM, to mark blocks used for each list item.
* Adds a new button type, LISTLABEL, which basically behaves exactly as LABEL, but uses wcol_list_item color set.
* When uiItemL is called, it checks whether current block has UI_BLOCK_LIST_ITEM set, and if so, switch produced button to LISTLABEL type.
* Adds a new helper func, ui_layout_list_set_labels_active, called after the active list item has been "drawn", to set all LISTLABEL buttons as UI_SELECT.
Note custom widget_state_label() was removed, in interface_widgets.c, as it did nothing more than default widget_state().
Thanks to Brecht for the review and advices.
2013-06-26 07:28:55 +00:00
|
|
|
if (block->flag & UI_BLOCK_LIST_ITEM) {
|
2013-11-21 16:51:29 +01:00
|
|
|
but->flag |= UI_BUT_LIST_ITEM;
|
Fix [#35750] list items in properties editor (text colors not following list item theme).
Issue goes back since we stopped using LISTROW button to draw item's name (i.e. since we have custom buttons in list items!).
This commit:
* Adds a new flag to uiBlock, UI_BLOCK_LIST_ITEM, to mark blocks used for each list item.
* Adds a new button type, LISTLABEL, which basically behaves exactly as LABEL, but uses wcol_list_item color set.
* When uiItemL is called, it checks whether current block has UI_BLOCK_LIST_ITEM set, and if so, switch produced button to LISTLABEL type.
* Adds a new helper func, ui_layout_list_set_labels_active, called after the active list item has been "drawn", to set all LISTLABEL buttons as UI_SELECT.
Note custom widget_state_label() was removed, in interface_widgets.c, as it did nothing more than default widget_state().
Thanks to Brecht for the review and advices.
2013-06-26 07:28:55 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-23 14:54:06 +02:00
|
|
|
if (layout->redalert_) {
|
2018-11-01 19:43:46 +01:00
|
|
|
UI_but_flag_enable(but, UI_BUT_REDALERT);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Drag and drop 2.5 integration! Finally, slashdot regulars can use
Blender too now! :)
** Drag works as follows:
- drag-able items are defined by the standard interface ui toolkit
- each button can get this feature, via uiButSetDragXXX(but, ...).
There are calls to define drag-able images, ID blocks, RNA paths,
file paths, and so on. By default you drag an icon, exceptionally
an ImBuf
- Drag items are registered centrally in the WM, it allows more drag
items simultaneous too, but not implemented
** Drop works as follows:
- On mouse release, and if drag items exist in the WM, it converts
the mouse event to an EVT_DROP type. This event then gets the full
drag info as customdata
- drop regions are defined with WM_dropbox_add(), similar to keymaps
you can make a "drop map" this way, which become 'drop map handlers'
in the queues.
- next to that the UI kit handles some common button types (like
accepting ID or names) to be catching a drop event too.
- Every "drop box" has two callbacks:
- poll() = check if the event drag data is relevant for this box
- copy() = fill in custom properties in the dropbox to initialize
an operator
- The dropbox handler then calls its standard Operator with its
dropbox properties.
** Currently implemented
Drag items:
- ID icons in browse buttons
- ID icons in context menu of properties region
- ID icons in outliner and rna viewer
- FileBrowser icons
- FileBrowser preview images
Drag-able icons are subtly visualized by making them brighter a bit
on mouse-over. In case the icon is a button or UI element too (most
cases), the drag-able feature will make the item react to
mouse-release instead of mouse-press.
Drop options:
- UI buttons: ID and text buttons (paste name)
- View3d: Object ID drop copies object
- View3d: Material ID drop assigns to object under cursor
- View3d: Image ID drop assigns to object UV texture under cursor
- Sequencer: Path drop will add either Image or Movie strip
- Image window: Path drop will open image
** Drag and drop Notes:
- Dropping into another Blender window (from same application) works
too. I've added code that passes on mousemoves and clicks to other
windows, without activating them though. This does make using multi-window
Blender a bit friendler.
- Dropping a file path to an image, is not the same as dropping an
Image ID... keep this in mind. Sequencer for example wants paths to
be dropped, textures in 3d window wants an Image ID.
- Although drop boxes could be defined via Python, I suggest they're
part of the UI and editor design (= how we want an editor to work), and
not default offered configurable like keymaps.
- At the moment only one item can be dragged at a time. This is for
several reasons.... For one, Blender doesn't have a well defined
uniform way to define "what is selected" (files, outliner items, etc).
Secondly there's potential conflicts on what todo when you drop mixed
drag sets on spots. All undefined stuff... nice for later.
- Example to bypass the above: a collection of images that form a strip,
should be represented in filewindow as a single sequence anyway.
This then will fit well and gets handled neatly by design.
- Another option to check is to allow multiple options per drop... it
could show the operator as a sort of menu, allowing arrow or scrollwheel
to choose. For time being I'd prefer to try to design a singular drop
though, just offer only one drop action per data type on given spots.
- What does work already, but a tad slow, is to use a function that
detects an object (type) under cursor, so a drag item's option can be
further refined (like drop object on object = parent). (disabled)
** More notes
- Added saving for Region layouts (like split points for toolbar)
- Label buttons now handle mouse over
- File list: added full path entry for drop feature.
- Filesel bugfix: wm_operator_exec() got called there and fully handled,
while WM event code tried same. Added new OPERATOR_HANDLED flag for this.
Maybe python needs it too?
- Cocoa: added window move event, so multi-win setups work OK (didnt save).
- Interface_handlers.c: removed win->active
- Severe area copy bug: area handlers were not set to NULL
- Filesel bugfix: next/prev folder list was not copied on area copies
** Leftover todos
- Cocoa windows seem to hang on cases still... needs check
- Cocoa 'draw overlap' swap doesn't work
- Cocoa window loses focus permanently on using Spotlight
(for these reasons, makefile building has Carbon as default atm)
- ListView templates in UI cannot become dragged yet, needs review...
it consists of two overlapping UI elements, preventing handling icon clicks.
- There's already Ghost library code to handle dropping from OS
into Blender window. I've noticed this code is unfinished for Macs, but
seems to be complete for Windows. Needs test... currently, an external
drop event will print in console when succesfully delivered to Blender's WM.
2010-01-26 18:18:21 +00:00
|
|
|
return but;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-20 16:37:07 +02:00
|
|
|
uiBut *uiItemL_ex(
|
2024-12-06 14:08:10 +01:00
|
|
|
uiLayout *layout, const StringRef name, int icon, const bool highlight, const bool redalert)
|
2020-02-28 13:51:40 +01:00
|
|
|
{
|
|
|
|
|
uiBut *but = uiItemL_(layout, name, icon);
|
|
|
|
|
|
|
|
|
|
if (highlight) {
|
|
|
|
|
/* TODO: add another flag for this. */
|
|
|
|
|
UI_but_flag_enable(but, UI_SELECT_DRAW);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (redalert) {
|
|
|
|
|
UI_but_flag_enable(but, UI_BUT_REDALERT);
|
|
|
|
|
}
|
2022-10-20 16:37:07 +02:00
|
|
|
|
|
|
|
|
return but;
|
2020-02-28 13:51:40 +01:00
|
|
|
}
|
|
|
|
|
|
2025-05-08 17:21:08 +02:00
|
|
|
void uiLayout::label(const StringRef name, int icon)
|
Drag and drop 2.5 integration! Finally, slashdot regulars can use
Blender too now! :)
** Drag works as follows:
- drag-able items are defined by the standard interface ui toolkit
- each button can get this feature, via uiButSetDragXXX(but, ...).
There are calls to define drag-able images, ID blocks, RNA paths,
file paths, and so on. By default you drag an icon, exceptionally
an ImBuf
- Drag items are registered centrally in the WM, it allows more drag
items simultaneous too, but not implemented
** Drop works as follows:
- On mouse release, and if drag items exist in the WM, it converts
the mouse event to an EVT_DROP type. This event then gets the full
drag info as customdata
- drop regions are defined with WM_dropbox_add(), similar to keymaps
you can make a "drop map" this way, which become 'drop map handlers'
in the queues.
- next to that the UI kit handles some common button types (like
accepting ID or names) to be catching a drop event too.
- Every "drop box" has two callbacks:
- poll() = check if the event drag data is relevant for this box
- copy() = fill in custom properties in the dropbox to initialize
an operator
- The dropbox handler then calls its standard Operator with its
dropbox properties.
** Currently implemented
Drag items:
- ID icons in browse buttons
- ID icons in context menu of properties region
- ID icons in outliner and rna viewer
- FileBrowser icons
- FileBrowser preview images
Drag-able icons are subtly visualized by making them brighter a bit
on mouse-over. In case the icon is a button or UI element too (most
cases), the drag-able feature will make the item react to
mouse-release instead of mouse-press.
Drop options:
- UI buttons: ID and text buttons (paste name)
- View3d: Object ID drop copies object
- View3d: Material ID drop assigns to object under cursor
- View3d: Image ID drop assigns to object UV texture under cursor
- Sequencer: Path drop will add either Image or Movie strip
- Image window: Path drop will open image
** Drag and drop Notes:
- Dropping into another Blender window (from same application) works
too. I've added code that passes on mousemoves and clicks to other
windows, without activating them though. This does make using multi-window
Blender a bit friendler.
- Dropping a file path to an image, is not the same as dropping an
Image ID... keep this in mind. Sequencer for example wants paths to
be dropped, textures in 3d window wants an Image ID.
- Although drop boxes could be defined via Python, I suggest they're
part of the UI and editor design (= how we want an editor to work), and
not default offered configurable like keymaps.
- At the moment only one item can be dragged at a time. This is for
several reasons.... For one, Blender doesn't have a well defined
uniform way to define "what is selected" (files, outliner items, etc).
Secondly there's potential conflicts on what todo when you drop mixed
drag sets on spots. All undefined stuff... nice for later.
- Example to bypass the above: a collection of images that form a strip,
should be represented in filewindow as a single sequence anyway.
This then will fit well and gets handled neatly by design.
- Another option to check is to allow multiple options per drop... it
could show the operator as a sort of menu, allowing arrow or scrollwheel
to choose. For time being I'd prefer to try to design a singular drop
though, just offer only one drop action per data type on given spots.
- What does work already, but a tad slow, is to use a function that
detects an object (type) under cursor, so a drag item's option can be
further refined (like drop object on object = parent). (disabled)
** More notes
- Added saving for Region layouts (like split points for toolbar)
- Label buttons now handle mouse over
- File list: added full path entry for drop feature.
- Filesel bugfix: wm_operator_exec() got called there and fully handled,
while WM event code tried same. Added new OPERATOR_HANDLED flag for this.
Maybe python needs it too?
- Cocoa: added window move event, so multi-win setups work OK (didnt save).
- Interface_handlers.c: removed win->active
- Severe area copy bug: area handlers were not set to NULL
- Filesel bugfix: next/prev folder list was not copied on area copies
** Leftover todos
- Cocoa windows seem to hang on cases still... needs check
- Cocoa 'draw overlap' swap doesn't work
- Cocoa window loses focus permanently on using Spotlight
(for these reasons, makefile building has Carbon as default atm)
- ListView templates in UI cannot become dragged yet, needs review...
it consists of two overlapping UI elements, preventing handling icon clicks.
- There's already Ghost library code to handle dropping from OS
into Blender window. I've noticed this code is unfinished for Macs, but
seems to be complete for Windows. Needs test... currently, an external
drop event will print in console when succesfully delivered to Blender's WM.
2010-01-26 18:18:21 +00:00
|
|
|
{
|
2025-05-08 17:21:08 +02:00
|
|
|
uiItemL_(this, name, icon);
|
Drag and drop 2.5 integration! Finally, slashdot regulars can use
Blender too now! :)
** Drag works as follows:
- drag-able items are defined by the standard interface ui toolkit
- each button can get this feature, via uiButSetDragXXX(but, ...).
There are calls to define drag-able images, ID blocks, RNA paths,
file paths, and so on. By default you drag an icon, exceptionally
an ImBuf
- Drag items are registered centrally in the WM, it allows more drag
items simultaneous too, but not implemented
** Drop works as follows:
- On mouse release, and if drag items exist in the WM, it converts
the mouse event to an EVT_DROP type. This event then gets the full
drag info as customdata
- drop regions are defined with WM_dropbox_add(), similar to keymaps
you can make a "drop map" this way, which become 'drop map handlers'
in the queues.
- next to that the UI kit handles some common button types (like
accepting ID or names) to be catching a drop event too.
- Every "drop box" has two callbacks:
- poll() = check if the event drag data is relevant for this box
- copy() = fill in custom properties in the dropbox to initialize
an operator
- The dropbox handler then calls its standard Operator with its
dropbox properties.
** Currently implemented
Drag items:
- ID icons in browse buttons
- ID icons in context menu of properties region
- ID icons in outliner and rna viewer
- FileBrowser icons
- FileBrowser preview images
Drag-able icons are subtly visualized by making them brighter a bit
on mouse-over. In case the icon is a button or UI element too (most
cases), the drag-able feature will make the item react to
mouse-release instead of mouse-press.
Drop options:
- UI buttons: ID and text buttons (paste name)
- View3d: Object ID drop copies object
- View3d: Material ID drop assigns to object under cursor
- View3d: Image ID drop assigns to object UV texture under cursor
- Sequencer: Path drop will add either Image or Movie strip
- Image window: Path drop will open image
** Drag and drop Notes:
- Dropping into another Blender window (from same application) works
too. I've added code that passes on mousemoves and clicks to other
windows, without activating them though. This does make using multi-window
Blender a bit friendler.
- Dropping a file path to an image, is not the same as dropping an
Image ID... keep this in mind. Sequencer for example wants paths to
be dropped, textures in 3d window wants an Image ID.
- Although drop boxes could be defined via Python, I suggest they're
part of the UI and editor design (= how we want an editor to work), and
not default offered configurable like keymaps.
- At the moment only one item can be dragged at a time. This is for
several reasons.... For one, Blender doesn't have a well defined
uniform way to define "what is selected" (files, outliner items, etc).
Secondly there's potential conflicts on what todo when you drop mixed
drag sets on spots. All undefined stuff... nice for later.
- Example to bypass the above: a collection of images that form a strip,
should be represented in filewindow as a single sequence anyway.
This then will fit well and gets handled neatly by design.
- Another option to check is to allow multiple options per drop... it
could show the operator as a sort of menu, allowing arrow or scrollwheel
to choose. For time being I'd prefer to try to design a singular drop
though, just offer only one drop action per data type on given spots.
- What does work already, but a tad slow, is to use a function that
detects an object (type) under cursor, so a drag item's option can be
further refined (like drop object on object = parent). (disabled)
** More notes
- Added saving for Region layouts (like split points for toolbar)
- Label buttons now handle mouse over
- File list: added full path entry for drop feature.
- Filesel bugfix: wm_operator_exec() got called there and fully handled,
while WM event code tried same. Added new OPERATOR_HANDLED flag for this.
Maybe python needs it too?
- Cocoa: added window move event, so multi-win setups work OK (didnt save).
- Interface_handlers.c: removed win->active
- Severe area copy bug: area handlers were not set to NULL
- Filesel bugfix: next/prev folder list was not copied on area copies
** Leftover todos
- Cocoa windows seem to hang on cases still... needs check
- Cocoa 'draw overlap' swap doesn't work
- Cocoa window loses focus permanently on using Spotlight
(for these reasons, makefile building has Carbon as default atm)
- ListView templates in UI cannot become dragged yet, needs review...
it consists of two overlapping UI elements, preventing handling icon clicks.
- There's already Ghost library code to handle dropping from OS
into Blender window. I've noticed this code is unfinished for Macs, but
seems to be complete for Windows. Needs test... currently, an external
drop event will print in console when succesfully delivered to Blender's WM.
2010-01-26 18:18:21 +00:00
|
|
|
}
|
|
|
|
|
|
2020-04-27 16:43:36 +02:00
|
|
|
uiPropertySplitWrapper uiItemPropertySplitWrapperCreate(uiLayout *parent_layout)
|
2019-11-25 19:41:30 +01:00
|
|
|
{
|
2022-11-25 23:48:02 -06:00
|
|
|
uiPropertySplitWrapper split_wrapper = {nullptr};
|
2020-04-27 16:43:36 +02:00
|
|
|
|
2025-04-25 19:45:25 +02:00
|
|
|
uiLayout *layout_row = &parent_layout->row(true);
|
2025-05-03 20:51:42 +02:00
|
|
|
uiLayout *layout_split = &layout_row->split(UI_ITEM_PROP_SEP_DIVIDE, true);
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
|
2025-04-26 21:07:34 +02:00
|
|
|
split_wrapper.label_column = &layout_split->column(true);
|
2025-04-23 14:54:06 +02:00
|
|
|
split_wrapper.label_column->alignment_ = UI_LAYOUT_ALIGN_RIGHT;
|
2020-04-27 16:43:36 +02:00
|
|
|
split_wrapper.property_row = ui_item_prop_split_layout_hack(parent_layout, layout_split);
|
2024-09-20 13:03:35 +02:00
|
|
|
split_wrapper.decorate_column = uiLayoutGetPropDecorate(parent_layout) ?
|
2025-04-26 21:07:34 +02:00
|
|
|
&layout_row->column(true) :
|
2024-09-20 13:03:35 +02:00
|
|
|
nullptr;
|
2019-11-25 19:41:30 +01:00
|
|
|
|
2020-04-27 16:43:36 +02:00
|
|
|
return split_wrapper;
|
|
|
|
|
}
|
2019-11-25 19:41:30 +01:00
|
|
|
|
2024-12-06 14:08:10 +01:00
|
|
|
uiLayout *uiItemL_respect_property_split(uiLayout *layout, StringRef text, int icon)
|
2020-04-27 16:43:36 +02:00
|
|
|
{
|
2025-04-24 17:22:28 +02:00
|
|
|
if (bool(layout->flag_ & uiItemInternalFlag::PropSep)) {
|
2020-04-27 16:43:36 +02:00
|
|
|
uiBlock *block = uiLayoutGetBlock(layout);
|
2020-08-26 10:11:13 +10:00
|
|
|
const uiPropertySplitWrapper split_wrapper = uiItemPropertySplitWrapperCreate(layout);
|
2020-04-27 16:43:36 +02:00
|
|
|
/* Further items added to 'layout' will automatically be added to split_wrapper.property_row */
|
2019-11-25 19:41:30 +01:00
|
|
|
|
2020-04-27 16:43:36 +02:00
|
|
|
uiItemL_(split_wrapper.label_column, text, icon);
|
|
|
|
|
UI_block_layout_set_current(block, split_wrapper.property_row);
|
2020-04-05 14:19:24 +02:00
|
|
|
|
2020-04-27 16:43:36 +02:00
|
|
|
return split_wrapper.decorate_column;
|
2019-11-25 19:41:30 +01:00
|
|
|
}
|
|
|
|
|
|
2023-10-19 09:24:06 -07:00
|
|
|
char namestr[UI_MAX_NAME_STR];
|
2024-12-06 14:08:10 +01:00
|
|
|
text = ui_item_name_add_colon(text, namestr);
|
2020-07-03 14:20:10 +02:00
|
|
|
uiItemL_(layout, text, icon);
|
|
|
|
|
|
2024-09-20 12:29:14 +02:00
|
|
|
return nullptr;
|
2019-11-25 19:41:30 +01:00
|
|
|
}
|
|
|
|
|
|
2024-12-06 14:08:10 +01:00
|
|
|
void uiItemLDrag(uiLayout *layout, PointerRNA *ptr, StringRef name, int icon)
|
Drag and drop 2.5 integration! Finally, slashdot regulars can use
Blender too now! :)
** Drag works as follows:
- drag-able items are defined by the standard interface ui toolkit
- each button can get this feature, via uiButSetDragXXX(but, ...).
There are calls to define drag-able images, ID blocks, RNA paths,
file paths, and so on. By default you drag an icon, exceptionally
an ImBuf
- Drag items are registered centrally in the WM, it allows more drag
items simultaneous too, but not implemented
** Drop works as follows:
- On mouse release, and if drag items exist in the WM, it converts
the mouse event to an EVT_DROP type. This event then gets the full
drag info as customdata
- drop regions are defined with WM_dropbox_add(), similar to keymaps
you can make a "drop map" this way, which become 'drop map handlers'
in the queues.
- next to that the UI kit handles some common button types (like
accepting ID or names) to be catching a drop event too.
- Every "drop box" has two callbacks:
- poll() = check if the event drag data is relevant for this box
- copy() = fill in custom properties in the dropbox to initialize
an operator
- The dropbox handler then calls its standard Operator with its
dropbox properties.
** Currently implemented
Drag items:
- ID icons in browse buttons
- ID icons in context menu of properties region
- ID icons in outliner and rna viewer
- FileBrowser icons
- FileBrowser preview images
Drag-able icons are subtly visualized by making them brighter a bit
on mouse-over. In case the icon is a button or UI element too (most
cases), the drag-able feature will make the item react to
mouse-release instead of mouse-press.
Drop options:
- UI buttons: ID and text buttons (paste name)
- View3d: Object ID drop copies object
- View3d: Material ID drop assigns to object under cursor
- View3d: Image ID drop assigns to object UV texture under cursor
- Sequencer: Path drop will add either Image or Movie strip
- Image window: Path drop will open image
** Drag and drop Notes:
- Dropping into another Blender window (from same application) works
too. I've added code that passes on mousemoves and clicks to other
windows, without activating them though. This does make using multi-window
Blender a bit friendler.
- Dropping a file path to an image, is not the same as dropping an
Image ID... keep this in mind. Sequencer for example wants paths to
be dropped, textures in 3d window wants an Image ID.
- Although drop boxes could be defined via Python, I suggest they're
part of the UI and editor design (= how we want an editor to work), and
not default offered configurable like keymaps.
- At the moment only one item can be dragged at a time. This is for
several reasons.... For one, Blender doesn't have a well defined
uniform way to define "what is selected" (files, outliner items, etc).
Secondly there's potential conflicts on what todo when you drop mixed
drag sets on spots. All undefined stuff... nice for later.
- Example to bypass the above: a collection of images that form a strip,
should be represented in filewindow as a single sequence anyway.
This then will fit well and gets handled neatly by design.
- Another option to check is to allow multiple options per drop... it
could show the operator as a sort of menu, allowing arrow or scrollwheel
to choose. For time being I'd prefer to try to design a singular drop
though, just offer only one drop action per data type on given spots.
- What does work already, but a tad slow, is to use a function that
detects an object (type) under cursor, so a drag item's option can be
further refined (like drop object on object = parent). (disabled)
** More notes
- Added saving for Region layouts (like split points for toolbar)
- Label buttons now handle mouse over
- File list: added full path entry for drop feature.
- Filesel bugfix: wm_operator_exec() got called there and fully handled,
while WM event code tried same. Added new OPERATOR_HANDLED flag for this.
Maybe python needs it too?
- Cocoa: added window move event, so multi-win setups work OK (didnt save).
- Interface_handlers.c: removed win->active
- Severe area copy bug: area handlers were not set to NULL
- Filesel bugfix: next/prev folder list was not copied on area copies
** Leftover todos
- Cocoa windows seem to hang on cases still... needs check
- Cocoa 'draw overlap' swap doesn't work
- Cocoa window loses focus permanently on using Spotlight
(for these reasons, makefile building has Carbon as default atm)
- ListView templates in UI cannot become dragged yet, needs review...
it consists of two overlapping UI elements, preventing handling icon clicks.
- There's already Ghost library code to handle dropping from OS
into Blender window. I've noticed this code is unfinished for Macs, but
seems to be complete for Windows. Needs test... currently, an external
drop event will print in console when succesfully delivered to Blender's WM.
2010-01-26 18:18:21 +00:00
|
|
|
{
|
2012-03-30 01:51:25 +00:00
|
|
|
uiBut *but = uiItemL_(layout, name, icon);
|
Drag and drop 2.5 integration! Finally, slashdot regulars can use
Blender too now! :)
** Drag works as follows:
- drag-able items are defined by the standard interface ui toolkit
- each button can get this feature, via uiButSetDragXXX(but, ...).
There are calls to define drag-able images, ID blocks, RNA paths,
file paths, and so on. By default you drag an icon, exceptionally
an ImBuf
- Drag items are registered centrally in the WM, it allows more drag
items simultaneous too, but not implemented
** Drop works as follows:
- On mouse release, and if drag items exist in the WM, it converts
the mouse event to an EVT_DROP type. This event then gets the full
drag info as customdata
- drop regions are defined with WM_dropbox_add(), similar to keymaps
you can make a "drop map" this way, which become 'drop map handlers'
in the queues.
- next to that the UI kit handles some common button types (like
accepting ID or names) to be catching a drop event too.
- Every "drop box" has two callbacks:
- poll() = check if the event drag data is relevant for this box
- copy() = fill in custom properties in the dropbox to initialize
an operator
- The dropbox handler then calls its standard Operator with its
dropbox properties.
** Currently implemented
Drag items:
- ID icons in browse buttons
- ID icons in context menu of properties region
- ID icons in outliner and rna viewer
- FileBrowser icons
- FileBrowser preview images
Drag-able icons are subtly visualized by making them brighter a bit
on mouse-over. In case the icon is a button or UI element too (most
cases), the drag-able feature will make the item react to
mouse-release instead of mouse-press.
Drop options:
- UI buttons: ID and text buttons (paste name)
- View3d: Object ID drop copies object
- View3d: Material ID drop assigns to object under cursor
- View3d: Image ID drop assigns to object UV texture under cursor
- Sequencer: Path drop will add either Image or Movie strip
- Image window: Path drop will open image
** Drag and drop Notes:
- Dropping into another Blender window (from same application) works
too. I've added code that passes on mousemoves and clicks to other
windows, without activating them though. This does make using multi-window
Blender a bit friendler.
- Dropping a file path to an image, is not the same as dropping an
Image ID... keep this in mind. Sequencer for example wants paths to
be dropped, textures in 3d window wants an Image ID.
- Although drop boxes could be defined via Python, I suggest they're
part of the UI and editor design (= how we want an editor to work), and
not default offered configurable like keymaps.
- At the moment only one item can be dragged at a time. This is for
several reasons.... For one, Blender doesn't have a well defined
uniform way to define "what is selected" (files, outliner items, etc).
Secondly there's potential conflicts on what todo when you drop mixed
drag sets on spots. All undefined stuff... nice for later.
- Example to bypass the above: a collection of images that form a strip,
should be represented in filewindow as a single sequence anyway.
This then will fit well and gets handled neatly by design.
- Another option to check is to allow multiple options per drop... it
could show the operator as a sort of menu, allowing arrow or scrollwheel
to choose. For time being I'd prefer to try to design a singular drop
though, just offer only one drop action per data type on given spots.
- What does work already, but a tad slow, is to use a function that
detects an object (type) under cursor, so a drag item's option can be
further refined (like drop object on object = parent). (disabled)
** More notes
- Added saving for Region layouts (like split points for toolbar)
- Label buttons now handle mouse over
- File list: added full path entry for drop feature.
- Filesel bugfix: wm_operator_exec() got called there and fully handled,
while WM event code tried same. Added new OPERATOR_HANDLED flag for this.
Maybe python needs it too?
- Cocoa: added window move event, so multi-win setups work OK (didnt save).
- Interface_handlers.c: removed win->active
- Severe area copy bug: area handlers were not set to NULL
- Filesel bugfix: next/prev folder list was not copied on area copies
** Leftover todos
- Cocoa windows seem to hang on cases still... needs check
- Cocoa 'draw overlap' swap doesn't work
- Cocoa window loses focus permanently on using Spotlight
(for these reasons, makefile building has Carbon as default atm)
- ListView templates in UI cannot become dragged yet, needs review...
it consists of two overlapping UI elements, preventing handling icon clicks.
- There's already Ghost library code to handle dropping from OS
into Blender window. I've noticed this code is unfinished for Macs, but
seems to be complete for Windows. Needs test... currently, an external
drop event will print in console when succesfully delivered to Blender's WM.
2010-01-26 18:18:21 +00:00
|
|
|
|
2019-03-25 10:15:20 +11:00
|
|
|
if (ptr && ptr->type) {
|
|
|
|
|
if (RNA_struct_is_ID(ptr->type)) {
|
2019-08-23 09:52:12 +02:00
|
|
|
UI_but_drag_set_id(but, ptr->owner_id);
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
|
|
|
|
}
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
}
|
|
|
|
|
|
2025-05-13 17:54:26 +02:00
|
|
|
void uiLayout::separator(float factor, const LayoutSeparatorType type)
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
{
|
2025-05-13 17:54:26 +02:00
|
|
|
uiBlock *block = root_->block;
|
2020-08-26 10:11:13 +10:00
|
|
|
const bool is_menu = ui_block_is_menu(block);
|
2024-05-15 20:55:08 +02:00
|
|
|
const bool is_pie = ui_block_is_pie_menu(block);
|
2019-04-25 14:40:53 +02:00
|
|
|
if (is_menu && !UI_block_can_add_separator(block)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2024-02-09 17:38:36 +01:00
|
|
|
|
2025-02-15 00:57:49 +01:00
|
|
|
/* Sizing of spaces should not depend on line width. */
|
|
|
|
|
const int space = (is_menu) ? int(7.0f * UI_SCALE_FAC * factor) :
|
|
|
|
|
int(6.0f * UI_SCALE_FAC * factor);
|
2024-02-09 17:38:36 +01:00
|
|
|
|
|
|
|
|
eButType but_type;
|
|
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
|
case LayoutSeparatorType::Line:
|
|
|
|
|
but_type = UI_BTYPE_SEPR_LINE;
|
|
|
|
|
break;
|
|
|
|
|
case LayoutSeparatorType::Auto:
|
2024-05-15 20:55:08 +02:00
|
|
|
but_type = (is_menu && !is_pie) ? UI_BTYPE_SEPR_LINE : UI_BTYPE_SEPR;
|
2024-02-09 17:38:36 +01:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
but_type = UI_BTYPE_SEPR;
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-13 17:54:26 +02:00
|
|
|
bool is_vertical_bar = (w_ == 0) && but_type == UI_BTYPE_SEPR_LINE;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-05-13 17:54:26 +02:00
|
|
|
UI_block_layout_set_current(block, this);
|
2024-03-01 18:09:02 +01:00
|
|
|
uiBut *but = uiDefBut(block,
|
|
|
|
|
but_type,
|
|
|
|
|
0,
|
|
|
|
|
"",
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
space,
|
|
|
|
|
is_vertical_bar ? UI_UNIT_Y : space,
|
|
|
|
|
nullptr,
|
|
|
|
|
0.0,
|
|
|
|
|
0.0,
|
|
|
|
|
"");
|
|
|
|
|
|
|
|
|
|
if (but_type == UI_BTYPE_SEPR_LINE) {
|
|
|
|
|
uiButSeparatorLine *but_line = static_cast<uiButSeparatorLine *>(but);
|
|
|
|
|
but_line->is_vertical = is_vertical_bar;
|
|
|
|
|
}
|
2009-04-22 18:39:44 +00:00
|
|
|
}
|
|
|
|
|
|
2023-07-12 13:18:06 +10:00
|
|
|
void uiItemProgressIndicator(uiLayout *layout,
|
|
|
|
|
const char *text,
|
|
|
|
|
const float factor,
|
|
|
|
|
const eButProgressType progress_type)
|
|
|
|
|
{
|
|
|
|
|
const bool has_text = text && text[0];
|
2025-04-23 16:37:14 +02:00
|
|
|
uiBlock *block = layout->root_->block;
|
2023-07-12 13:18:06 +10:00
|
|
|
short width;
|
|
|
|
|
|
|
|
|
|
if (progress_type == UI_BUT_PROGRESS_TYPE_BAR) {
|
|
|
|
|
width = UI_UNIT_X * 5;
|
|
|
|
|
}
|
|
|
|
|
else if (has_text) {
|
|
|
|
|
width = UI_UNIT_X * 8;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
width = UI_UNIT_X;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UI_block_layout_set_current(block, layout);
|
|
|
|
|
uiBut *but = uiDefBut(block,
|
|
|
|
|
UI_BTYPE_PROGRESS,
|
|
|
|
|
0,
|
|
|
|
|
(text) ? text : "",
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
width,
|
|
|
|
|
short(UI_UNIT_Y),
|
|
|
|
|
nullptr,
|
|
|
|
|
0.0,
|
|
|
|
|
0.0,
|
|
|
|
|
"");
|
|
|
|
|
|
2023-07-15 16:14:10 +10:00
|
|
|
if (has_text && (progress_type == UI_BUT_PROGRESS_TYPE_RING)) {
|
2023-07-12 13:18:06 +10:00
|
|
|
/* For progress bar, centered is okay, left aligned for ring/pie. */
|
|
|
|
|
but->drawflag |= UI_BUT_TEXT_LEFT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uiButProgress *progress_bar = static_cast<uiButProgress *>(but);
|
|
|
|
|
progress_bar->progress_type = eButProgressType(progress_type);
|
|
|
|
|
progress_bar->progress_factor = factor;
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-11 14:33:53 +02:00
|
|
|
void uiItemSpacer(uiLayout *layout)
|
|
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
uiBlock *block = layout->root_->block;
|
2018-11-15 16:44:42 -02:00
|
|
|
const bool is_popup = ui_block_is_popup_any(block);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-11-15 16:44:42 -02:00
|
|
|
if (is_popup) {
|
|
|
|
|
printf("Error: separator_spacer() not supported in popups.\n");
|
2018-06-11 14:33:53 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-11 14:54:04 +02:00
|
|
|
if (block->direction & UI_DIR_RIGHT) {
|
|
|
|
|
printf("Error: separator_spacer() only supported in horizontal blocks.\n");
|
2018-06-11 14:33:53 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-11 14:33:53 +02:00
|
|
|
UI_block_layout_set_current(block, layout);
|
|
|
|
|
uiDefBut(block,
|
|
|
|
|
UI_BTYPE_SEPR_SPACER,
|
|
|
|
|
0,
|
|
|
|
|
"",
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
0.3f * UI_UNIT_X,
|
|
|
|
|
UI_UNIT_Y,
|
2022-11-25 23:48:02 -06:00
|
|
|
nullptr,
|
2018-06-11 14:33:53 +02:00
|
|
|
0.0,
|
|
|
|
|
0.0,
|
|
|
|
|
"");
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-15 21:26:49 +02:00
|
|
|
void uiLayout::menu_fn(const StringRefNull name, int icon, uiMenuCreateFunc func, void *arg)
|
2009-04-22 18:39:44 +00:00
|
|
|
{
|
2019-03-25 10:15:20 +11:00
|
|
|
if (!func) {
|
2009-04-22 18:39:44 +00:00
|
|
|
return;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2009-04-22 18:39:44 +00:00
|
|
|
|
2025-05-15 21:26:49 +02:00
|
|
|
ui_item_menu(this, name, icon, func, arg, nullptr, "", false);
|
2009-04-22 18:39:44 +00:00
|
|
|
}
|
|
|
|
|
|
2025-05-15 21:26:49 +02:00
|
|
|
void uiLayout::menu_fn_argN_free(const StringRefNull name,
|
|
|
|
|
int icon,
|
|
|
|
|
uiMenuCreateFunc func,
|
|
|
|
|
void *argN)
|
2018-10-30 10:46:29 +11:00
|
|
|
{
|
2019-03-25 10:15:20 +11:00
|
|
|
if (!func) {
|
2018-10-30 10:46:29 +11:00
|
|
|
return;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2018-10-30 10:46:29 +11:00
|
|
|
|
|
|
|
|
/* Second 'argN' only ensures it gets freed. */
|
2025-05-15 21:26:49 +02:00
|
|
|
ui_item_menu(this, name, icon, func, argN, argN, "", false);
|
2018-10-30 10:46:29 +11:00
|
|
|
}
|
|
|
|
|
|
2022-11-25 23:48:02 -06:00
|
|
|
struct MenuItemLevel {
|
2021-11-05 14:56:22 +01:00
|
|
|
wmOperatorCallContext opcontext;
|
2012-03-18 07:38:51 +00:00
|
|
|
/* don't use pointers to the strings because python can dynamically
|
2023-02-12 14:37:16 +11:00
|
|
|
* allocate strings and free before the menu draws, see #27304. */
|
2011-05-06 02:55:09 +00:00
|
|
|
char opname[OP_MAX_TYPENAME];
|
|
|
|
|
char propname[MAX_IDPROP_NAME];
|
2009-04-22 18:39:44 +00:00
|
|
|
PointerRNA rnapoin;
|
2022-11-25 23:48:02 -06:00
|
|
|
};
|
2009-04-22 18:39:44 +00:00
|
|
|
|
2023-10-11 19:27:02 +02:00
|
|
|
/* Obtain the active menu item based on the calling button's text. */
|
|
|
|
|
static int menu_item_enum_opname_menu_active(bContext *C, uiBut *but, MenuItemLevel *lvl)
|
|
|
|
|
{
|
|
|
|
|
wmOperatorType *ot = WM_operatortype_find(lvl->opname, true);
|
|
|
|
|
|
|
|
|
|
if (!ot) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PointerRNA ptr;
|
|
|
|
|
const EnumPropertyItem *item_array = nullptr;
|
|
|
|
|
bool free;
|
|
|
|
|
int totitem;
|
|
|
|
|
WM_operator_properties_create_ptr(&ptr, ot);
|
|
|
|
|
/* so the context is passed to itemf functions (some need it) */
|
|
|
|
|
WM_operator_properties_sanitize(&ptr, false);
|
|
|
|
|
PropertyRNA *prop = RNA_struct_find_property(&ptr, lvl->propname);
|
2024-02-01 01:50:55 +01:00
|
|
|
if (!prop) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2023-10-11 19:27:02 +02:00
|
|
|
RNA_property_enum_items_gettexted(C, &ptr, prop, &item_array, &totitem, &free);
|
2024-01-16 21:04:17 +01:00
|
|
|
int active = RNA_enum_from_name(item_array, but->str.c_str());
|
2023-10-11 19:27:02 +02:00
|
|
|
if (free) {
|
2025-04-12 17:25:55 +02:00
|
|
|
MEM_freeN(item_array);
|
2023-10-11 19:27:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return active;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void menu_item_enum_opname_menu(bContext *C, uiLayout *layout, void *arg)
|
2009-04-22 18:39:44 +00:00
|
|
|
{
|
2022-11-25 23:48:02 -06:00
|
|
|
uiBut *but = static_cast<uiBut *>(arg);
|
|
|
|
|
MenuItemLevel *lvl = static_cast<MenuItemLevel *>(but->func_argN);
|
2021-06-29 17:20:33 +02:00
|
|
|
/* Use the operator properties from the button owning the menu. */
|
2022-11-25 23:48:02 -06:00
|
|
|
IDProperty *op_props = but->opptr ? static_cast<IDProperty *>(but->opptr->data) : nullptr;
|
2009-04-22 18:39:44 +00:00
|
|
|
|
2023-10-11 19:27:02 +02:00
|
|
|
/* The calling but's str _probably_ contains the active
|
|
|
|
|
* menu item name, set in uiItemMenuEnumFullO_ptr. */
|
|
|
|
|
const int active = menu_item_enum_opname_menu_active(C, but, lvl);
|
|
|
|
|
|
2011-09-05 17:57:04 +00:00
|
|
|
uiLayoutSetOperatorContext(layout, lvl->opcontext);
|
2023-10-11 19:27:02 +02:00
|
|
|
uiItemsFullEnumO(
|
|
|
|
|
layout, lvl->opname, lvl->propname, op_props, lvl->opcontext, UI_ITEM_NONE, active);
|
2014-02-12 10:29:15 +11:00
|
|
|
|
|
|
|
|
/* override default, needed since this was assumed pre 2.70 */
|
2025-04-23 16:37:14 +02:00
|
|
|
UI_block_direction_set(layout->root_->block, UI_DIR_DOWN);
|
2009-04-22 18:39:44 +00:00
|
|
|
}
|
|
|
|
|
|
2021-06-29 17:20:33 +02:00
|
|
|
void uiItemMenuEnumFullO_ptr(uiLayout *layout,
|
2023-05-05 00:19:31 +10:00
|
|
|
const bContext *C,
|
2021-06-29 17:20:33 +02:00
|
|
|
wmOperatorType *ot,
|
2024-12-06 14:08:10 +01:00
|
|
|
const StringRefNull propname,
|
|
|
|
|
std::optional<StringRefNull> name,
|
2021-06-29 17:20:33 +02:00
|
|
|
int icon,
|
|
|
|
|
PointerRNA *r_opptr)
|
2009-04-22 18:39:44 +00:00
|
|
|
{
|
2017-10-31 12:44:41 +11:00
|
|
|
/* Caller must check */
|
2022-11-25 23:48:02 -06:00
|
|
|
BLI_assert(ot->srna != nullptr);
|
2009-04-22 18:39:44 +00:00
|
|
|
|
2023-08-11 19:11:27 +02:00
|
|
|
std::string operator_name;
|
2024-12-06 14:08:10 +01:00
|
|
|
if (!name) {
|
2023-08-11 19:11:27 +02:00
|
|
|
operator_name = WM_operatortype_name(ot, nullptr);
|
|
|
|
|
name = operator_name.c_str();
|
2014-05-06 18:11:28 +10:00
|
|
|
}
|
2013-05-10 23:41:41 +00:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
if (layout->root_->type == UI_LAYOUT_MENU && !icon) {
|
2012-03-30 01:51:25 +00:00
|
|
|
icon = ICON_BLANK1;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2009-04-22 18:39:44 +00:00
|
|
|
|
2024-08-27 15:35:18 +02:00
|
|
|
MenuItemLevel *lvl = MEM_new<MenuItemLevel>("MenuItemLevel");
|
2023-05-09 12:50:37 +10:00
|
|
|
STRNCPY(lvl->opname, ot->idname);
|
2024-12-06 14:08:10 +01:00
|
|
|
STRNCPY(lvl->propname, propname.c_str());
|
2025-04-23 16:37:14 +02:00
|
|
|
lvl->opcontext = layout->root_->opcontext;
|
2009-04-22 18:39:44 +00:00
|
|
|
|
2024-08-27 15:35:18 +02:00
|
|
|
uiBut *but = ui_item_menu(layout,
|
2024-12-06 14:08:10 +01:00
|
|
|
*name,
|
2024-08-27 15:35:18 +02:00
|
|
|
icon,
|
|
|
|
|
menu_item_enum_opname_menu,
|
|
|
|
|
nullptr,
|
|
|
|
|
lvl,
|
2025-02-14 15:12:48 -05:00
|
|
|
std::nullopt,
|
2024-08-27 15:35:18 +02:00
|
|
|
true,
|
|
|
|
|
but_func_argN_free<MenuItemLevel>,
|
|
|
|
|
but_func_argN_copy<MenuItemLevel>);
|
2021-06-29 17:20:33 +02:00
|
|
|
/* Use the menu button as owner for the operator properties, which will then be passed to the
|
|
|
|
|
* individual menu items. */
|
|
|
|
|
if (r_opptr) {
|
2024-08-29 15:09:42 +02:00
|
|
|
but->opptr = MEM_new<PointerRNA>("uiButOpPtr");
|
2021-06-29 17:20:33 +02:00
|
|
|
WM_operator_properties_create_ptr(but->opptr, ot);
|
2022-11-25 23:48:02 -06:00
|
|
|
BLI_assert(but->opptr->data == nullptr);
|
2021-06-29 17:20:33 +02:00
|
|
|
WM_operator_properties_alloc(&but->opptr, (IDProperty **)&but->opptr->data, ot->idname);
|
|
|
|
|
*r_opptr = *but->opptr;
|
|
|
|
|
}
|
2014-05-06 18:11:28 +10:00
|
|
|
|
2013-05-10 23:41:41 +00:00
|
|
|
/* add hotkey here, lower UI code can't detect it */
|
2025-04-23 16:37:14 +02:00
|
|
|
if ((layout->root_->block->flag & UI_BLOCK_LOOP) && (ot->prop && ot->invoke)) {
|
2024-02-07 14:22:54 +01:00
|
|
|
if (std::optional<std::string> shortcut_str = WM_key_event_operator_string(
|
2025-04-23 16:37:14 +02:00
|
|
|
C, ot->idname, layout->root_->opcontext, nullptr, false))
|
2022-11-25 23:48:02 -06:00
|
|
|
{
|
2024-02-07 14:22:54 +01:00
|
|
|
ui_but_add_shortcut(but, shortcut_str->c_str(), false);
|
2013-05-10 23:41:41 +00:00
|
|
|
}
|
|
|
|
|
}
|
2009-04-22 18:39:44 +00:00
|
|
|
}
|
|
|
|
|
|
2021-06-29 17:20:33 +02:00
|
|
|
void uiItemMenuEnumFullO(uiLayout *layout,
|
2023-05-05 00:19:31 +10:00
|
|
|
const bContext *C,
|
2024-12-06 14:08:10 +01:00
|
|
|
const StringRefNull opname,
|
|
|
|
|
const StringRefNull propname,
|
|
|
|
|
StringRefNull name,
|
2021-06-29 17:20:33 +02:00
|
|
|
int icon,
|
|
|
|
|
PointerRNA *r_opptr)
|
2017-10-31 12:44:41 +11:00
|
|
|
{
|
2024-12-06 14:08:10 +01:00
|
|
|
wmOperatorType *ot = WM_operatortype_find(opname.c_str(), false); /* print error next */
|
2017-10-31 12:44:41 +11:00
|
|
|
|
2024-12-06 14:08:10 +01:00
|
|
|
UI_OPERATOR_ERROR_RET(ot, opname.c_str(), return);
|
2017-10-31 12:44:41 +11:00
|
|
|
|
|
|
|
|
if (!ot->srna) {
|
2024-12-06 14:08:10 +01:00
|
|
|
ui_item_disabled(layout, opname.c_str());
|
|
|
|
|
RNA_warning("operator missing srna '%s'", opname.c_str());
|
2017-10-31 12:44:41 +11:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-29 17:20:33 +02:00
|
|
|
uiItemMenuEnumFullO_ptr(layout, C, ot, propname, name, icon, r_opptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void uiItemMenuEnumO(uiLayout *layout,
|
2023-05-05 00:19:31 +10:00
|
|
|
const bContext *C,
|
2024-12-06 14:08:10 +01:00
|
|
|
const StringRefNull opname,
|
|
|
|
|
const StringRefNull propname,
|
|
|
|
|
StringRefNull name,
|
2021-06-29 17:20:33 +02:00
|
|
|
int icon)
|
|
|
|
|
{
|
2022-11-25 23:48:02 -06:00
|
|
|
uiItemMenuEnumFullO(layout, C, opname, propname, name, icon, nullptr);
|
2017-10-31 12:44:41 +11:00
|
|
|
}
|
|
|
|
|
|
2022-11-25 23:48:02 -06:00
|
|
|
static void menu_item_enum_rna_menu(bContext * /*C*/, uiLayout *layout, void *arg)
|
2009-04-22 18:39:44 +00:00
|
|
|
{
|
2012-03-30 01:51:25 +00:00
|
|
|
MenuItemLevel *lvl = (MenuItemLevel *)(((uiBut *)arg)->func_argN);
|
2009-04-22 18:39:44 +00:00
|
|
|
|
2009-05-28 23:37:55 +00:00
|
|
|
uiLayoutSetOperatorContext(layout, lvl->opcontext);
|
2009-04-22 18:39:44 +00:00
|
|
|
uiItemsEnumR(layout, &lvl->rnapoin, lvl->propname);
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-06 14:08:10 +01:00
|
|
|
void uiItemMenuEnumR_prop(uiLayout *layout,
|
|
|
|
|
PointerRNA *ptr,
|
|
|
|
|
PropertyRNA *prop,
|
|
|
|
|
const std::optional<StringRefNull> name,
|
|
|
|
|
int icon)
|
2009-04-22 18:39:44 +00:00
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
if (layout->root_->type == UI_LAYOUT_MENU && !icon) {
|
2012-03-30 01:51:25 +00:00
|
|
|
icon = ICON_BLANK1;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2009-04-22 18:39:44 +00:00
|
|
|
|
2024-08-27 15:35:18 +02:00
|
|
|
MenuItemLevel *lvl = MEM_new<MenuItemLevel>("MenuItemLevel");
|
2012-03-30 01:51:25 +00:00
|
|
|
lvl->rnapoin = *ptr;
|
2023-05-09 12:50:37 +10:00
|
|
|
STRNCPY(lvl->propname, RNA_property_identifier(prop));
|
2025-04-23 16:37:14 +02:00
|
|
|
lvl->opcontext = layout->root_->opcontext;
|
2009-04-22 18:39:44 +00:00
|
|
|
|
Fix for [#35224] Transform Orientation - order inconsistency
Fix turned out to remove as much "manual UI" from 3D view header as possible. Mode selector and all transform manipulators/orientations stuff are now RNA-based UI (leaving basically only edit mesh select modes with custom handlers, as they have some quite specific features).
To achieve this, four main modifications were done:
* enum-operator-generated menus are now MENU (i.e. dropdown lists) in headers too.
* All bit-flag enums expanded in ROW buttons now have a handling consistent with e.g. layers, or what we already have for transform manipulators, i.e. clicking select only one element, shift-click to select multiple ones.
* Consequently, the three RNA booleans manipulators flags are merged into a single bit-flag enum (yes, this is also an API change, though I doubt many scripts use it).
* Now the width of enum-based dropdown lists is computed from longest item name in enum, no more from a dummy place holder string (when no label/name is given).
All this allows to remove some code from 3DView/transform areas, that was actually mostly duplicating RNA/operator one.
Also done a few optimizations here and there (among others, do not pass &numitems to RNA_property_enum_items() when you do not need it, saves at least an iteration over enum items to count them).
Many thanks to Brecht for the reviews!
2013-05-12 13:16:11 +00:00
|
|
|
ui_item_menu(layout,
|
2024-12-06 14:08:10 +01:00
|
|
|
name.value_or(RNA_property_ui_name(prop)),
|
Fix for [#35224] Transform Orientation - order inconsistency
Fix turned out to remove as much "manual UI" from 3D view header as possible. Mode selector and all transform manipulators/orientations stuff are now RNA-based UI (leaving basically only edit mesh select modes with custom handlers, as they have some quite specific features).
To achieve this, four main modifications were done:
* enum-operator-generated menus are now MENU (i.e. dropdown lists) in headers too.
* All bit-flag enums expanded in ROW buttons now have a handling consistent with e.g. layers, or what we already have for transform manipulators, i.e. clicking select only one element, shift-click to select multiple ones.
* Consequently, the three RNA booleans manipulators flags are merged into a single bit-flag enum (yes, this is also an API change, though I doubt many scripts use it).
* Now the width of enum-based dropdown lists is computed from longest item name in enum, no more from a dummy place holder string (when no label/name is given).
All this allows to remove some code from 3DView/transform areas, that was actually mostly duplicating RNA/operator one.
Also done a few optimizations here and there (among others, do not pass &numitems to RNA_property_enum_items() when you do not need it, saves at least an iteration over enum items to count them).
Many thanks to Brecht for the reviews!
2013-05-12 13:16:11 +00:00
|
|
|
icon,
|
|
|
|
|
menu_item_enum_rna_menu,
|
2022-11-25 23:48:02 -06:00
|
|
|
nullptr,
|
Fix for [#35224] Transform Orientation - order inconsistency
Fix turned out to remove as much "manual UI" from 3D view header as possible. Mode selector and all transform manipulators/orientations stuff are now RNA-based UI (leaving basically only edit mesh select modes with custom handlers, as they have some quite specific features).
To achieve this, four main modifications were done:
* enum-operator-generated menus are now MENU (i.e. dropdown lists) in headers too.
* All bit-flag enums expanded in ROW buttons now have a handling consistent with e.g. layers, or what we already have for transform manipulators, i.e. clicking select only one element, shift-click to select multiple ones.
* Consequently, the three RNA booleans manipulators flags are merged into a single bit-flag enum (yes, this is also an API change, though I doubt many scripts use it).
* Now the width of enum-based dropdown lists is computed from longest item name in enum, no more from a dummy place holder string (when no label/name is given).
All this allows to remove some code from 3DView/transform areas, that was actually mostly duplicating RNA/operator one.
Also done a few optimizations here and there (among others, do not pass &numitems to RNA_property_enum_items() when you do not need it, saves at least an iteration over enum items to count them).
Many thanks to Brecht for the reviews!
2013-05-12 13:16:11 +00:00
|
|
|
lvl,
|
|
|
|
|
RNA_property_description(prop),
|
2024-08-27 15:35:18 +02:00
|
|
|
false,
|
|
|
|
|
but_func_argN_free<MenuItemLevel>,
|
|
|
|
|
but_func_argN_copy<MenuItemLevel>);
|
2009-04-22 18:39:44 +00:00
|
|
|
}
|
|
|
|
|
|
2020-10-13 12:43:28 -05:00
|
|
|
void uiItemTabsEnumR_prop(uiLayout *layout,
|
|
|
|
|
bContext *C,
|
|
|
|
|
PointerRNA *ptr,
|
|
|
|
|
PropertyRNA *prop,
|
|
|
|
|
PointerRNA *ptr_highlight,
|
|
|
|
|
PropertyRNA *prop_highlight,
|
|
|
|
|
bool icon_only)
|
2018-10-29 21:20:58 +01:00
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
uiBlock *block = layout->root_->block;
|
2018-10-29 21:20:58 +01:00
|
|
|
|
|
|
|
|
UI_block_layout_set_current(block, layout);
|
2025-03-07 17:53:54 +01:00
|
|
|
ui_item_enum_expand_tabs(layout,
|
|
|
|
|
C,
|
|
|
|
|
block,
|
|
|
|
|
ptr,
|
|
|
|
|
prop,
|
|
|
|
|
ptr_highlight,
|
|
|
|
|
prop_highlight,
|
|
|
|
|
std::nullopt,
|
|
|
|
|
UI_UNIT_Y,
|
|
|
|
|
icon_only);
|
2018-10-29 21:20:58 +01:00
|
|
|
}
|
|
|
|
|
|
2019-09-06 16:12:47 +10:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Layout Items
|
|
|
|
|
* \{ */
|
2009-03-13 13:38:41 +00:00
|
|
|
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
/* single-row layout */
|
|
|
|
|
static void ui_litem_estimate_row(uiLayout *litem)
|
2009-04-16 12:17:58 +00:00
|
|
|
{
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
int itemw, itemh;
|
2017-01-10 16:19:10 +01:00
|
|
|
bool min_size_flag = true;
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->w_ = 0;
|
|
|
|
|
litem->h_ = 0;
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
if (litem->items_.is_empty()) {
|
2024-07-10 14:46:06 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
const uiItem *item_last = litem->items_.last();
|
|
|
|
|
for (uiItem *item : litem->items_) {
|
2024-07-10 14:46:06 +02:00
|
|
|
const bool is_item_last = (item == item_last);
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
ui_item_size(item, &itemw, &itemh);
|
2009-04-16 12:17:58 +00:00
|
|
|
|
2025-04-24 17:22:28 +02:00
|
|
|
min_size_flag = min_size_flag && bool(item->flag_ & uiItemInternalFlag::FixedSize);
|
2017-01-10 16:19:10 +01:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->w_ += itemw;
|
|
|
|
|
litem->h_ = std::max(itemh, litem->h_);
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
|
2024-07-10 14:46:06 +02:00
|
|
|
if (!is_item_last) {
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->w_ += litem->space_;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
}
|
2017-01-10 16:19:10 +01:00
|
|
|
|
|
|
|
|
if (min_size_flag) {
|
2025-04-24 17:22:28 +02:00
|
|
|
litem->flag_ |= uiItemInternalFlag::FixedSize;
|
2017-01-10 16:19:10 +01:00
|
|
|
}
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
}
|
|
|
|
|
|
2009-06-03 00:04:48 +00:00
|
|
|
static int ui_litem_min_width(int itemw)
|
|
|
|
|
{
|
2023-11-07 16:33:19 +11:00
|
|
|
return std::min(2 * UI_UNIT_X, itemw);
|
2009-06-03 00:04:48 +00:00
|
|
|
}
|
|
|
|
|
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
static void ui_litem_layout_row(uiLayout *litem)
|
|
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
if (litem->items_.is_empty()) {
|
2024-07-10 14:46:06 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int last_free_item_idx = -1;
|
2020-12-18 12:39:50 -06:00
|
|
|
int x, neww, newtotw, itemw, minw, itemh, offset;
|
|
|
|
|
int freew, fixedx, freex, flag = 0, lastw = 0;
|
2017-02-25 13:18:41 +03:00
|
|
|
float extra_pixel;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
// x = litem->x_; /* UNUSED */
|
|
|
|
|
const int y = litem->y_;
|
|
|
|
|
int w = litem->w_;
|
2020-12-18 12:39:50 -06:00
|
|
|
int totw = 0;
|
|
|
|
|
int tot = 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
for (uiItem *item : litem->items_) {
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
ui_item_size(item, &itemw, &itemh);
|
2009-04-16 12:17:58 +00:00
|
|
|
totw += itemw;
|
|
|
|
|
tot++;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-03-25 10:15:20 +11:00
|
|
|
if (totw == 0) {
|
2009-04-16 12:17:58 +00:00
|
|
|
return;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-03-25 10:15:20 +11:00
|
|
|
if (w != 0) {
|
2025-04-23 14:54:06 +02:00
|
|
|
w -= (tot - 1) * litem->space_;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2020-12-18 12:39:50 -06:00
|
|
|
int fixedw = 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
const uiItem *item_last = litem->items_.last();
|
2024-07-10 14:46:06 +02:00
|
|
|
|
2009-06-03 00:04:48 +00:00
|
|
|
/* keep clamping items to fixed minimum size until all are done */
|
|
|
|
|
do {
|
2012-03-30 01:51:25 +00:00
|
|
|
freew = 0;
|
|
|
|
|
x = 0;
|
|
|
|
|
flag = 0;
|
2013-11-27 05:23:02 +01:00
|
|
|
newtotw = totw;
|
2017-02-25 13:18:41 +03:00
|
|
|
extra_pixel = 0.0f;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
for (uiItem *item : litem->items_) {
|
2025-04-24 17:22:28 +02:00
|
|
|
if (bool(item->flag_ & uiItemInternalFlag::AutoFixedSize)) {
|
2009-06-03 00:04:48 +00:00
|
|
|
continue;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2024-07-10 14:46:06 +02:00
|
|
|
const bool is_item_last = (item == item_last);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-06-03 00:04:48 +00:00
|
|
|
ui_item_size(item, &itemw, &itemh);
|
2012-03-30 01:51:25 +00:00
|
|
|
minw = ui_litem_min_width(itemw);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-03-25 10:15:20 +11:00
|
|
|
if (w - lastw > 0) {
|
2024-07-10 14:46:06 +02:00
|
|
|
neww = ui_item_fit(
|
2025-04-23 14:54:06 +02:00
|
|
|
itemw, x, totw, w - lastw, is_item_last, litem->alignment_, &extra_pixel);
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
|
|
|
|
else {
|
2012-03-30 01:51:25 +00:00
|
|
|
neww = 0; /* no space left, all will need clamping to minimum size */
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-06-03 00:04:48 +00:00
|
|
|
x += neww;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-24 17:22:28 +02:00
|
|
|
bool min_flag = bool(item->flag_ & uiItemInternalFlag::FixedSize);
|
2017-03-26 12:19:01 +03:00
|
|
|
/* ignore min flag for rows with right or center alignment */
|
2025-04-24 17:22:28 +02:00
|
|
|
if (item->type_ != uiItemType::Button &&
|
2025-04-23 14:54:06 +02:00
|
|
|
ELEM((static_cast<uiLayout *>(item))->alignment_,
|
2024-07-10 14:46:06 +02:00
|
|
|
UI_LAYOUT_ALIGN_RIGHT,
|
|
|
|
|
UI_LAYOUT_ALIGN_CENTER) &&
|
2025-04-23 14:54:06 +02:00
|
|
|
litem->alignment_ == UI_LAYOUT_ALIGN_EXPAND &&
|
2025-04-24 17:22:28 +02:00
|
|
|
bool(litem->flag_ & uiItemInternalFlag::FixedSize))
|
2019-09-19 16:14:47 +02:00
|
|
|
{
|
2017-03-26 12:19:01 +03:00
|
|
|
min_flag = false;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-03-26 12:19:01 +03:00
|
|
|
if ((neww < minw || min_flag) && w != 0) {
|
2009-06-03 00:04:48 +00:00
|
|
|
/* fixed size */
|
2025-04-24 17:22:28 +02:00
|
|
|
item->flag_ |= uiItemInternalFlag::AutoFixedSize;
|
|
|
|
|
if (item->type_ != uiItemType::Button && bool(item->flag_ & uiItemInternalFlag::FixedSize))
|
|
|
|
|
{
|
2017-01-10 16:19:10 +01:00
|
|
|
minw = itemw;
|
|
|
|
|
}
|
2009-06-03 00:04:48 +00:00
|
|
|
fixedw += minw;
|
2012-03-30 01:51:25 +00:00
|
|
|
flag = 1;
|
2013-11-27 05:23:02 +01:00
|
|
|
newtotw -= itemw;
|
2009-06-03 00:04:48 +00:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* keep free size */
|
2025-04-24 17:22:28 +02:00
|
|
|
item->flag_ &= ~uiItemInternalFlag::AutoFixedSize;
|
2009-06-03 00:04:48 +00:00
|
|
|
freew += itemw;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2009-06-03 00:04:48 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-11-27 05:23:02 +01:00
|
|
|
totw = newtotw;
|
2012-03-30 01:51:25 +00:00
|
|
|
lastw = fixedw;
|
2012-03-24 06:38:07 +00:00
|
|
|
} while (flag);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-30 01:51:25 +00:00
|
|
|
freex = 0;
|
|
|
|
|
fixedx = 0;
|
2017-02-25 13:18:41 +03:00
|
|
|
extra_pixel = 0.0f;
|
2025-04-23 16:37:14 +02:00
|
|
|
x = litem->x_;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-07-10 14:46:06 +02:00
|
|
|
int item_idx = -1;
|
2025-04-23 16:37:14 +02:00
|
|
|
for (uiItem *item : litem->items_) {
|
2024-07-10 14:46:06 +02:00
|
|
|
item_idx++;
|
|
|
|
|
const bool is_item_last = (item == item_last);
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
ui_item_size(item, &itemw, &itemh);
|
2012-03-30 01:51:25 +00:00
|
|
|
minw = ui_litem_min_width(itemw);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-24 17:22:28 +02:00
|
|
|
if (bool(item->flag_ & uiItemInternalFlag::AutoFixedSize)) {
|
2009-06-03 00:04:48 +00:00
|
|
|
/* fixed minimum size items */
|
2025-04-24 17:22:28 +02:00
|
|
|
if (item->type_ != uiItemType::Button && bool(item->flag_ & uiItemInternalFlag::FixedSize)) {
|
2017-01-10 16:19:10 +01:00
|
|
|
minw = itemw;
|
|
|
|
|
}
|
2017-02-25 13:18:41 +03:00
|
|
|
itemw = ui_item_fit(
|
2025-04-23 14:54:06 +02:00
|
|
|
minw, fixedx, fixedw, min_ii(w, fixedw), is_item_last, litem->alignment_, &extra_pixel);
|
2009-06-03 00:04:48 +00:00
|
|
|
fixedx += itemw;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* free size item */
|
2017-02-25 13:18:41 +03:00
|
|
|
itemw = ui_item_fit(
|
2025-04-23 14:54:06 +02:00
|
|
|
itemw, freex, freew, w - fixedw, is_item_last, litem->alignment_, &extra_pixel);
|
2009-06-03 00:04:48 +00:00
|
|
|
freex += itemw;
|
2024-07-10 14:46:06 +02:00
|
|
|
last_free_item_idx = item_idx;
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-06-03 00:04:48 +00:00
|
|
|
/* align right/center */
|
2012-03-30 01:51:25 +00:00
|
|
|
offset = 0;
|
2025-04-23 14:54:06 +02:00
|
|
|
if (litem->alignment_ == UI_LAYOUT_ALIGN_RIGHT) {
|
2019-03-25 10:15:20 +11:00
|
|
|
if (freew + fixedw > 0 && freew + fixedw < w) {
|
2012-05-11 17:05:10 +00:00
|
|
|
offset = w - (fixedw + freew);
|
2009-06-03 00:04:48 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2025-04-23 14:54:06 +02:00
|
|
|
else if (litem->alignment_ == UI_LAYOUT_ALIGN_CENTER) {
|
2019-03-25 10:15:20 +11:00
|
|
|
if (freew + fixedw > 0 && freew + fixedw < w) {
|
2012-05-11 17:05:10 +00:00
|
|
|
offset = (w - (fixedw + freew)) / 2;
|
2009-06-03 00:04:48 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2009-06-03 00:04:48 +00:00
|
|
|
/* position item */
|
2012-03-30 01:51:25 +00:00
|
|
|
ui_item_position(item, x + offset, y - itemh, itemw, itemh);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-06-03 00:04:48 +00:00
|
|
|
x += itemw;
|
2024-07-10 14:46:06 +02:00
|
|
|
if (!is_item_last) {
|
2025-04-23 14:54:06 +02:00
|
|
|
x += litem->space_;
|
2009-04-16 12:17:58 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2017-02-25 13:18:41 +03:00
|
|
|
/* add extra pixel */
|
2025-04-23 16:37:14 +02:00
|
|
|
int extra_pixel_move = litem->w_ - (x - litem->x_);
|
2025-04-23 14:54:06 +02:00
|
|
|
if (extra_pixel_move > 0 && litem->alignment_ == UI_LAYOUT_ALIGN_EXPAND &&
|
2025-03-31 18:23:16 +02:00
|
|
|
last_free_item_idx >= 0 && item_last &&
|
2025-04-24 17:22:28 +02:00
|
|
|
bool(item_last->flag_ & uiItemInternalFlag::AutoFixedSize))
|
2019-09-19 16:14:47 +02:00
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
ui_item_move(litem->items_[last_free_item_idx], 0, extra_pixel_move);
|
2024-07-10 14:46:06 +02:00
|
|
|
blender::MutableSpan<uiItem *> items_after_last_free =
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->items_.as_mutable_span().drop_front(last_free_item_idx + 1);
|
2024-07-10 14:46:06 +02:00
|
|
|
for (uiItem *item : items_after_last_free) {
|
|
|
|
|
ui_item_move(item, extra_pixel_move, extra_pixel_move);
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2017-02-25 13:18:41 +03:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->w_ = x - litem->x_;
|
|
|
|
|
litem->h_ = litem->y_ - y;
|
|
|
|
|
litem->x_ = x;
|
|
|
|
|
litem->y_ = y;
|
2009-04-16 12:17:58 +00:00
|
|
|
}
|
|
|
|
|
|
2024-07-10 14:46:06 +02:00
|
|
|
static int spaces_after_column_item(const uiLayout *litem,
|
|
|
|
|
const uiItem *item,
|
|
|
|
|
const uiItem *next_item,
|
|
|
|
|
const bool is_box)
|
UI: add support for uiLayout based panels
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 initial use case for this are panels in the geometry nodes modifier. This patch provides
a better solution compared to what was attempted in #108565.
### Problems with Existing Approaches
Currently, there are two ways to create these expandable sections:
* One can define a new `Panel` type for each expandable section and use the `parent_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.
* It does not work so well for dynamic amounts of panels (e.g. like what we need for
the geometry nodes modifier to organize the inputs).
* Typically, Blender uses a immediate-ui approach, but subpanels break that currently
and need extra handling.
* The order of panels is not very explicit.
* One can't interleave subpanels and other ui elements, subpanels always come at the
end of the parent panel.
* Custom solution using existing `uiLayout`. This is done in the material properties. It
also has a few problems:
* Custom solutions tend to work slightly different in different places. So the UI is less unified.
* Can't drag open/close multiple panels.
* The background color for subpanels does not change.
### Solution
A possible solution to all of these problems is to add support for panels to `uiLayout` directly:
```cpp
/* Add elements before subpanel. */
if (uiLayout *panel_layout = uiLayoutPanel(layout, ...)) {
/* Add elements in subpanel, but only of the panel is open. */
}
/* Add elements after subpanel. */
```
Integrating subpanels with `uiLayout` has some benefits:
* Subpanels are treated like any other sub-layout and don't have unnecessary boilerplate.
* It becomes trivial to have a dynamic number of potentially nested subpanels.
* Resolves all mentioned problems of custom subpanel solutions.
### 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 negligible. Therefor, a much simpler solution
is possible: the open/close state can be stored in the modifier directly. This is actually
how it was implemented before 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 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 (not included)
Adding a Python API is fairly straight forward. 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:
```python
if panel := layout.panel("Mesh Settings", ...):
# Add layout elements in the panel if it's open.
```
Pull Request: https://projects.blender.org/blender/blender/pulls/113584
2023-12-22 17:57:57 +01:00
|
|
|
{
|
|
|
|
|
if (next_item == nullptr) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2025-04-24 17:22:28 +02:00
|
|
|
if (item->type_ == uiItemType::LayoutPanelHeader &&
|
|
|
|
|
next_item->type_ == uiItemType::LayoutPanelHeader)
|
2025-03-31 15:30:58 +02:00
|
|
|
{
|
UI: add support for uiLayout based panels
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 initial use case for this are panels in the geometry nodes modifier. This patch provides
a better solution compared to what was attempted in #108565.
### Problems with Existing Approaches
Currently, there are two ways to create these expandable sections:
* One can define a new `Panel` type for each expandable section and use the `parent_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.
* It does not work so well for dynamic amounts of panels (e.g. like what we need for
the geometry nodes modifier to organize the inputs).
* Typically, Blender uses a immediate-ui approach, but subpanels break that currently
and need extra handling.
* The order of panels is not very explicit.
* One can't interleave subpanels and other ui elements, subpanels always come at the
end of the parent panel.
* Custom solution using existing `uiLayout`. This is done in the material properties. It
also has a few problems:
* Custom solutions tend to work slightly different in different places. So the UI is less unified.
* Can't drag open/close multiple panels.
* The background color for subpanels does not change.
### Solution
A possible solution to all of these problems is to add support for panels to `uiLayout` directly:
```cpp
/* Add elements before subpanel. */
if (uiLayout *panel_layout = uiLayoutPanel(layout, ...)) {
/* Add elements in subpanel, but only of the panel is open. */
}
/* Add elements after subpanel. */
```
Integrating subpanels with `uiLayout` has some benefits:
* Subpanels are treated like any other sub-layout and don't have unnecessary boilerplate.
* It becomes trivial to have a dynamic number of potentially nested subpanels.
* Resolves all mentioned problems of custom subpanel solutions.
### 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 negligible. Therefor, a much simpler solution
is possible: the open/close state can be stored in the modifier directly. This is actually
how it was implemented before 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 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 (not included)
Adding a Python API is fairly straight forward. 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:
```python
if panel := layout.panel("Mesh Settings", ...):
# Add layout elements in the panel if it's open.
```
Pull Request: https://projects.blender.org/blender/blender/pulls/113584
2023-12-22 17:57:57 +01:00
|
|
|
/* No extra space between layout panel headers. */
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2025-04-24 17:22:28 +02:00
|
|
|
if (item->type_ == uiItemType::LayoutPanelBody &&
|
|
|
|
|
!ELEM(next_item->type_, uiItemType::LayoutPanelHeader, uiItemType::LayoutPanelBody))
|
UI: add support for uiLayout based panels
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 initial use case for this are panels in the geometry nodes modifier. This patch provides
a better solution compared to what was attempted in #108565.
### Problems with Existing Approaches
Currently, there are two ways to create these expandable sections:
* One can define a new `Panel` type for each expandable section and use the `parent_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.
* It does not work so well for dynamic amounts of panels (e.g. like what we need for
the geometry nodes modifier to organize the inputs).
* Typically, Blender uses a immediate-ui approach, but subpanels break that currently
and need extra handling.
* The order of panels is not very explicit.
* One can't interleave subpanels and other ui elements, subpanels always come at the
end of the parent panel.
* Custom solution using existing `uiLayout`. This is done in the material properties. It
also has a few problems:
* Custom solutions tend to work slightly different in different places. So the UI is less unified.
* Can't drag open/close multiple panels.
* The background color for subpanels does not change.
### Solution
A possible solution to all of these problems is to add support for panels to `uiLayout` directly:
```cpp
/* Add elements before subpanel. */
if (uiLayout *panel_layout = uiLayoutPanel(layout, ...)) {
/* Add elements in subpanel, but only of the panel is open. */
}
/* Add elements after subpanel. */
```
Integrating subpanels with `uiLayout` has some benefits:
* Subpanels are treated like any other sub-layout and don't have unnecessary boilerplate.
* It becomes trivial to have a dynamic number of potentially nested subpanels.
* Resolves all mentioned problems of custom subpanel solutions.
### 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 negligible. Therefor, a much simpler solution
is possible: the open/close state can be stored in the modifier directly. This is actually
how it was implemented before 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 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 (not included)
Adding a Python API is fairly straight forward. 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:
```python
if panel := layout.panel("Mesh Settings", ...):
# Add layout elements in the panel if it's open.
```
Pull Request: https://projects.blender.org/blender/blender/pulls/113584
2023-12-22 17:57:57 +01:00
|
|
|
{
|
|
|
|
|
/* One for the end of the panel and one at the start of the parent panel. */
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
if (!is_box) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2025-04-23 16:37:14 +02:00
|
|
|
if (item != litem->items_.first()) {
|
UI: add support for uiLayout based panels
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 initial use case for this are panels in the geometry nodes modifier. This patch provides
a better solution compared to what was attempted in #108565.
### Problems with Existing Approaches
Currently, there are two ways to create these expandable sections:
* One can define a new `Panel` type for each expandable section and use the `parent_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.
* It does not work so well for dynamic amounts of panels (e.g. like what we need for
the geometry nodes modifier to organize the inputs).
* Typically, Blender uses a immediate-ui approach, but subpanels break that currently
and need extra handling.
* The order of panels is not very explicit.
* One can't interleave subpanels and other ui elements, subpanels always come at the
end of the parent panel.
* Custom solution using existing `uiLayout`. This is done in the material properties. It
also has a few problems:
* Custom solutions tend to work slightly different in different places. So the UI is less unified.
* Can't drag open/close multiple panels.
* The background color for subpanels does not change.
### Solution
A possible solution to all of these problems is to add support for panels to `uiLayout` directly:
```cpp
/* Add elements before subpanel. */
if (uiLayout *panel_layout = uiLayoutPanel(layout, ...)) {
/* Add elements in subpanel, but only of the panel is open. */
}
/* Add elements after subpanel. */
```
Integrating subpanels with `uiLayout` has some benefits:
* Subpanels are treated like any other sub-layout and don't have unnecessary boilerplate.
* It becomes trivial to have a dynamic number of potentially nested subpanels.
* Resolves all mentioned problems of custom subpanel solutions.
### 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 negligible. Therefor, a much simpler solution
is possible: the open/close state can be stored in the modifier directly. This is actually
how it was implemented before 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 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 (not included)
Adding a Python API is fairly straight forward. 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:
```python
if panel := layout.panel("Mesh Settings", ...):
# Add layout elements in the panel if it's open.
```
Pull Request: https://projects.blender.org/blender/blender/pulls/113584
2023-12-22 17:57:57 +01:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
/* single-column layout */
|
2017-03-26 18:02:11 +03:00
|
|
|
static void ui_litem_estimate_column(uiLayout *litem, bool is_box)
|
2009-03-13 13:38:41 +00:00
|
|
|
{
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
int itemw, itemh;
|
2017-03-28 00:07:31 +03:00
|
|
|
bool min_size_flag = true;
|
2009-03-13 13:38:41 +00:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->w_ = 0;
|
|
|
|
|
litem->h_ = 0;
|
2009-03-13 13:38:41 +00:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
for (auto *iter = litem->items_.begin(); iter != litem->items_.end(); iter++) {
|
2024-07-10 14:46:06 +02:00
|
|
|
uiItem *item = *iter;
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
ui_item_size(item, &itemw, &itemh);
|
2009-04-16 12:17:58 +00:00
|
|
|
|
2025-04-24 17:22:28 +02:00
|
|
|
min_size_flag = min_size_flag && bool(item->flag_ & uiItemInternalFlag::FixedSize);
|
2017-03-28 00:07:31 +03:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->w_ = std::max(litem->w_, itemw);
|
|
|
|
|
litem->h_ += itemh;
|
2009-03-13 13:38:41 +00:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
const uiItem *next_item = (item == litem->items_.last()) ? nullptr : *(iter + 1);
|
2024-07-10 14:46:06 +02:00
|
|
|
const int spaces_num = spaces_after_column_item(litem, item, next_item, is_box);
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->h_ += spaces_num * litem->space_;
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
}
|
2018-05-23 10:47:12 +02:00
|
|
|
|
2017-03-28 00:07:31 +03:00
|
|
|
if (min_size_flag) {
|
2025-04-24 17:22:28 +02:00
|
|
|
litem->flag_ |= uiItemInternalFlag::FixedSize;
|
2017-03-28 00:07:31 +03:00
|
|
|
}
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
}
|
2009-03-13 13:38:41 +00:00
|
|
|
|
2020-09-15 12:25:15 -06:00
|
|
|
static void ui_litem_layout_column(uiLayout *litem, bool is_box, bool is_menu)
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
const int x = litem->x_;
|
|
|
|
|
int y = litem->y_;
|
2009-03-13 13:38:41 +00:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
for (auto *iter = litem->items_.begin(); iter != litem->items_.end(); iter++) {
|
2024-07-10 14:46:06 +02:00
|
|
|
uiItem *item = *iter;
|
2020-12-18 12:39:50 -06:00
|
|
|
int itemw, itemh;
|
2020-09-15 12:25:15 -06:00
|
|
|
ui_item_size(item, &itemw, &itemh);
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
|
|
|
|
|
y -= itemh;
|
2025-04-23 16:37:14 +02:00
|
|
|
ui_item_position(item, x, y, is_menu ? itemw : litem->w_, itemh);
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
const uiItem *next_item = (item == litem->items_.last()) ? nullptr : *(iter + 1);
|
2024-07-10 14:46:06 +02:00
|
|
|
const int spaces_num = spaces_after_column_item(litem, item, next_item, is_box);
|
2025-04-23 14:54:06 +02:00
|
|
|
y -= spaces_num * litem->space_;
|
2017-07-27 10:27:29 +03:00
|
|
|
|
2017-07-27 11:44:51 +02:00
|
|
|
if (is_box) {
|
2025-04-24 17:22:28 +02:00
|
|
|
item->flag_ |= uiItemInternalFlag::BoxItem;
|
2017-07-27 11:44:51 +02:00
|
|
|
}
|
2009-04-15 15:09:36 +00:00
|
|
|
}
|
|
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->h_ = litem->y_ - y;
|
|
|
|
|
litem->x_ = x;
|
|
|
|
|
litem->y_ = y;
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
}
|
|
|
|
|
|
Pie Menus C code backend.
This commit merges the code in the pie-menu branch.
As per decisions taken the last few days, there are no pie menus
included and there will be an official add-on including overrides of
some keys with pie menus. However, people will now be able to use the
new code in python.
Full Documentation is in http://wiki.blender.org/index.php/Dev:Ref/
Thanks:
Campbell Barton, Dalai Felinto and Ton Roosendaal for the code review
and design comments
Jonathan Williamson, Pawel Lyczkowski, Pablo Vazquez among others for
suggestions during the development.
Special Thanks to Sean Olson, for his support, suggestions, testing and
merciless bugging so that I would finish the pie menu code. Without him
we wouldn't be here. Also to the rest of the developers of the original
python add-on, Patrick Moore and Dan Eicher and finally to Matt Ebb, who
did the research and first implementation and whose code I used to get
started.
2014-08-11 10:39:59 +02:00
|
|
|
/* calculates the angle of a specified button in a radial menu,
|
|
|
|
|
* stores a float vector in unit circle */
|
|
|
|
|
static RadialDirection ui_get_radialbut_vec(float vec[2], short itemnum)
|
|
|
|
|
{
|
2016-02-16 14:50:26 +01:00
|
|
|
if (itemnum >= PIE_MAX_ITEMS) {
|
|
|
|
|
itemnum %= PIE_MAX_ITEMS;
|
|
|
|
|
printf("Warning: Pie menus with more than %i items are currently unsupported\n",
|
|
|
|
|
PIE_MAX_ITEMS);
|
2015-05-26 12:08:29 +02:00
|
|
|
}
|
Pie Menus C code backend.
This commit merges the code in the pie-menu branch.
As per decisions taken the last few days, there are no pie menus
included and there will be an official add-on including overrides of
some keys with pie menus. However, people will now be able to use the
new code in python.
Full Documentation is in http://wiki.blender.org/index.php/Dev:Ref/
Thanks:
Campbell Barton, Dalai Felinto and Ton Roosendaal for the code review
and design comments
Jonathan Williamson, Pawel Lyczkowski, Pablo Vazquez among others for
suggestions during the development.
Special Thanks to Sean Olson, for his support, suggestions, testing and
merciless bugging so that I would finish the pie menu code. Without him
we wouldn't be here. Also to the rest of the developers of the original
python add-on, Patrick Moore and Dan Eicher and finally to Matt Ebb, who
did the research and first implementation and whose code I used to get
started.
2014-08-11 10:39:59 +02:00
|
|
|
|
2022-11-25 23:48:02 -06:00
|
|
|
const RadialDirection dir = RadialDirection(ui_radial_dir_order[itemnum]);
|
2014-08-13 15:11:19 +02:00
|
|
|
ui_but_pie_dir(dir, vec);
|
Pie Menus C code backend.
This commit merges the code in the pie-menu branch.
As per decisions taken the last few days, there are no pie menus
included and there will be an official add-on including overrides of
some keys with pie menus. However, people will now be able to use the
new code in python.
Full Documentation is in http://wiki.blender.org/index.php/Dev:Ref/
Thanks:
Campbell Barton, Dalai Felinto and Ton Roosendaal for the code review
and design comments
Jonathan Williamson, Pawel Lyczkowski, Pablo Vazquez among others for
suggestions during the development.
Special Thanks to Sean Olson, for his support, suggestions, testing and
merciless bugging so that I would finish the pie menu code. Without him
we wouldn't be here. Also to the rest of the developers of the original
python add-on, Patrick Moore and Dan Eicher and finally to Matt Ebb, who
did the research and first implementation and whose code I used to get
started.
2014-08-11 10:39:59 +02:00
|
|
|
|
|
|
|
|
return dir;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool ui_item_is_radial_displayable(uiItem *item)
|
|
|
|
|
{
|
|
|
|
|
|
2025-04-24 17:22:28 +02:00
|
|
|
if ((item->type_ == uiItemType::Button) &&
|
2024-07-10 14:46:06 +02:00
|
|
|
((static_cast<uiButtonItem *>(item))->but->type == UI_BTYPE_LABEL))
|
|
|
|
|
{
|
Pie Menus C code backend.
This commit merges the code in the pie-menu branch.
As per decisions taken the last few days, there are no pie menus
included and there will be an official add-on including overrides of
some keys with pie menus. However, people will now be able to use the
new code in python.
Full Documentation is in http://wiki.blender.org/index.php/Dev:Ref/
Thanks:
Campbell Barton, Dalai Felinto and Ton Roosendaal for the code review
and design comments
Jonathan Williamson, Pawel Lyczkowski, Pablo Vazquez among others for
suggestions during the development.
Special Thanks to Sean Olson, for his support, suggestions, testing and
merciless bugging so that I would finish the pie menu code. Without him
we wouldn't be here. Also to the rest of the developers of the original
python add-on, Patrick Moore and Dan Eicher and finally to Matt Ebb, who
did the research and first implementation and whose code I used to get
started.
2014-08-11 10:39:59 +02:00
|
|
|
return false;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
Pie Menus C code backend.
This commit merges the code in the pie-menu branch.
As per decisions taken the last few days, there are no pie menus
included and there will be an official add-on including overrides of
some keys with pie menus. However, people will now be able to use the
new code in python.
Full Documentation is in http://wiki.blender.org/index.php/Dev:Ref/
Thanks:
Campbell Barton, Dalai Felinto and Ton Roosendaal for the code review
and design comments
Jonathan Williamson, Pawel Lyczkowski, Pablo Vazquez among others for
suggestions during the development.
Special Thanks to Sean Olson, for his support, suggestions, testing and
merciless bugging so that I would finish the pie menu code. Without him
we wouldn't be here. Also to the rest of the developers of the original
python add-on, Patrick Moore and Dan Eicher and finally to Matt Ebb, who
did the research and first implementation and whose code I used to get
started.
2014-08-11 10:39:59 +02:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool ui_item_is_radial_drawable(uiButtonItem *bitem)
|
|
|
|
|
{
|
|
|
|
|
|
2019-03-25 10:15:20 +11:00
|
|
|
if (ELEM(bitem->but->type, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE, UI_BTYPE_SEPR_SPACER)) {
|
Pie Menus C code backend.
This commit merges the code in the pie-menu branch.
As per decisions taken the last few days, there are no pie menus
included and there will be an official add-on including overrides of
some keys with pie menus. However, people will now be able to use the
new code in python.
Full Documentation is in http://wiki.blender.org/index.php/Dev:Ref/
Thanks:
Campbell Barton, Dalai Felinto and Ton Roosendaal for the code review
and design comments
Jonathan Williamson, Pawel Lyczkowski, Pablo Vazquez among others for
suggestions during the development.
Special Thanks to Sean Olson, for his support, suggestions, testing and
merciless bugging so that I would finish the pie menu code. Without him
we wouldn't be here. Also to the rest of the developers of the original
python add-on, Patrick Moore and Dan Eicher and finally to Matt Ebb, who
did the research and first implementation and whose code I used to get
started.
2014-08-11 10:39:59 +02:00
|
|
|
return false;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
Pie Menus C code backend.
This commit merges the code in the pie-menu branch.
As per decisions taken the last few days, there are no pie menus
included and there will be an official add-on including overrides of
some keys with pie menus. However, people will now be able to use the
new code in python.
Full Documentation is in http://wiki.blender.org/index.php/Dev:Ref/
Thanks:
Campbell Barton, Dalai Felinto and Ton Roosendaal for the code review
and design comments
Jonathan Williamson, Pawel Lyczkowski, Pablo Vazquez among others for
suggestions during the development.
Special Thanks to Sean Olson, for his support, suggestions, testing and
merciless bugging so that I would finish the pie menu code. Without him
we wouldn't be here. Also to the rest of the developers of the original
python add-on, Patrick Moore and Dan Eicher and finally to Matt Ebb, who
did the research and first implementation and whose code I used to get
started.
2014-08-11 10:39:59 +02:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ui_litem_layout_radial(uiLayout *litem)
|
|
|
|
|
{
|
2020-12-18 12:39:50 -06:00
|
|
|
int itemh, itemw;
|
Pie Menus C code backend.
This commit merges the code in the pie-menu branch.
As per decisions taken the last few days, there are no pie menus
included and there will be an official add-on including overrides of
some keys with pie menus. However, people will now be able to use the
new code in python.
Full Documentation is in http://wiki.blender.org/index.php/Dev:Ref/
Thanks:
Campbell Barton, Dalai Felinto and Ton Roosendaal for the code review
and design comments
Jonathan Williamson, Pawel Lyczkowski, Pablo Vazquez among others for
suggestions during the development.
Special Thanks to Sean Olson, for his support, suggestions, testing and
merciless bugging so that I would finish the pie menu code. Without him
we wouldn't be here. Also to the rest of the developers of the original
python add-on, Patrick Moore and Dan Eicher and finally to Matt Ebb, who
did the research and first implementation and whose code I used to get
started.
2014-08-11 10:39:59 +02:00
|
|
|
int itemnum = 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Pie Menus C code backend.
This commit merges the code in the pie-menu branch.
As per decisions taken the last few days, there are no pie menus
included and there will be an official add-on including overrides of
some keys with pie menus. However, people will now be able to use the
new code in python.
Full Documentation is in http://wiki.blender.org/index.php/Dev:Ref/
Thanks:
Campbell Barton, Dalai Felinto and Ton Roosendaal for the code review
and design comments
Jonathan Williamson, Pawel Lyczkowski, Pablo Vazquez among others for
suggestions during the development.
Special Thanks to Sean Olson, for his support, suggestions, testing and
merciless bugging so that I would finish the pie menu code. Without him
we wouldn't be here. Also to the rest of the developers of the original
python add-on, Patrick Moore and Dan Eicher and finally to Matt Ebb, who
did the research and first implementation and whose code I used to get
started.
2014-08-11 10:39:59 +02:00
|
|
|
/* For the radial layout we will use Matt Ebb's design
|
|
|
|
|
* for radiation, see http://mattebb.com/weblog/radiation/
|
2023-02-12 14:37:16 +11:00
|
|
|
* also the old code at #5103. */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-03-17 04:19:05 +01:00
|
|
|
const int pie_radius = U.pie_menu_radius * UI_SCALE_FAC;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
const int x = litem->x_;
|
|
|
|
|
const int y = litem->y_;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-03-05 09:09:05 +11:00
|
|
|
int minx = x, miny = y, maxx = x, maxy = y;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->root_->block->pie_data.pie_dir_mask = 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
for (uiItem *item : litem->items_) {
|
2023-09-21 20:15:09 +10:00
|
|
|
/* Not all button types are drawn in a radial menu, do filtering here. */
|
|
|
|
|
if (!ui_item_is_radial_displayable(item)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2023-09-14 16:10:36 +10:00
|
|
|
|
2023-09-21 20:15:09 +10:00
|
|
|
float vec[2];
|
|
|
|
|
const RadialDirection dir = ui_get_radialbut_vec(vec, itemnum);
|
|
|
|
|
const float factor[2] = {
|
|
|
|
|
(vec[0] > 0.01f) ? 0.0f : ((vec[0] < -0.01f) ? -1.0f : -0.5f),
|
|
|
|
|
(vec[1] > 0.99f) ? 0.0f : ((vec[1] < -0.99f) ? -1.0f : -0.5f),
|
|
|
|
|
};
|
|
|
|
|
itemnum++;
|
|
|
|
|
|
|
|
|
|
/* Enable for non-buttons because a direction may reference a layout, see: #112610. */
|
|
|
|
|
bool use_dir = true;
|
|
|
|
|
|
2025-04-24 17:22:28 +02:00
|
|
|
if (item->type_ == uiItemType::Button) {
|
2024-07-10 14:46:06 +02:00
|
|
|
uiButtonItem *bitem = static_cast<uiButtonItem *>(item);
|
2023-09-21 20:15:09 +10:00
|
|
|
|
|
|
|
|
bitem->but->pie_dir = dir;
|
|
|
|
|
/* Scale the buttons. */
|
|
|
|
|
bitem->but->rect.ymax *= 1.5f;
|
|
|
|
|
/* Add a little bit more here to include number. */
|
|
|
|
|
bitem->but->rect.xmax += 1.5f * UI_UNIT_X;
|
|
|
|
|
/* Enable drawing as pie item if supported by widget. */
|
|
|
|
|
if (ui_item_is_radial_drawable(bitem)) {
|
2025-03-31 00:36:46 +02:00
|
|
|
bitem->but->emboss = blender::ui::EmbossType::PieMenu;
|
2023-09-21 20:15:09 +10:00
|
|
|
bitem->but->drawflag |= UI_BUT_ICON_LEFT;
|
2023-09-20 17:25:24 +10:00
|
|
|
}
|
2023-09-21 20:15:09 +10:00
|
|
|
|
|
|
|
|
if (ELEM(bitem->but->type, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE)) {
|
|
|
|
|
use_dir = false;
|
2017-06-20 20:15:04 +03:00
|
|
|
}
|
2023-09-21 20:15:09 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-09-21 20:15:09 +10:00
|
|
|
if (use_dir) {
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->root_->block->pie_data.pie_dir_mask |= 1 << int(dir);
|
2023-09-21 20:15:09 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-09-21 20:15:09 +10:00
|
|
|
ui_item_size(item, &itemw, &itemh);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-09-21 20:15:09 +10:00
|
|
|
ui_item_position(item,
|
|
|
|
|
x + (vec[0] * pie_radius) + (factor[0] * itemw),
|
|
|
|
|
y + (vec[1] * pie_radius) + (factor[1] * itemh),
|
|
|
|
|
itemw,
|
|
|
|
|
itemh);
|
|
|
|
|
|
|
|
|
|
minx = min_ii(minx, x + (vec[0] * pie_radius) - (itemw / 2));
|
|
|
|
|
maxx = max_ii(maxx, x + (vec[0] * pie_radius) + (itemw / 2));
|
|
|
|
|
miny = min_ii(miny, y + (vec[1] * pie_radius) - (itemh / 2));
|
|
|
|
|
maxy = max_ii(maxy, y + (vec[1] * pie_radius) + (itemh / 2));
|
Pie Menus C code backend.
This commit merges the code in the pie-menu branch.
As per decisions taken the last few days, there are no pie menus
included and there will be an official add-on including overrides of
some keys with pie menus. However, people will now be able to use the
new code in python.
Full Documentation is in http://wiki.blender.org/index.php/Dev:Ref/
Thanks:
Campbell Barton, Dalai Felinto and Ton Roosendaal for the code review
and design comments
Jonathan Williamson, Pawel Lyczkowski, Pablo Vazquez among others for
suggestions during the development.
Special Thanks to Sean Olson, for his support, suggestions, testing and
merciless bugging so that I would finish the pie menu code. Without him
we wouldn't be here. Also to the rest of the developers of the original
python add-on, Patrick Moore and Dan Eicher and finally to Matt Ebb, who
did the research and first implementation and whose code I used to get
started.
2014-08-11 10:39:59 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->x_ = minx;
|
|
|
|
|
litem->y_ = miny;
|
|
|
|
|
litem->w_ = maxx - minx;
|
|
|
|
|
litem->h_ = maxy - miny;
|
Pie Menus C code backend.
This commit merges the code in the pie-menu branch.
As per decisions taken the last few days, there are no pie menus
included and there will be an official add-on including overrides of
some keys with pie menus. However, people will now be able to use the
new code in python.
Full Documentation is in http://wiki.blender.org/index.php/Dev:Ref/
Thanks:
Campbell Barton, Dalai Felinto and Ton Roosendaal for the code review
and design comments
Jonathan Williamson, Pawel Lyczkowski, Pablo Vazquez among others for
suggestions during the development.
Special Thanks to Sean Olson, for his support, suggestions, testing and
merciless bugging so that I would finish the pie menu code. Without him
we wouldn't be here. Also to the rest of the developers of the original
python add-on, Patrick Moore and Dan Eicher and finally to Matt Ebb, who
did the research and first implementation and whose code I used to get
started.
2014-08-11 10:39:59 +02:00
|
|
|
}
|
|
|
|
|
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
/* root layout */
|
2022-11-25 23:48:02 -06:00
|
|
|
static void ui_litem_estimate_root(uiLayout * /*litem*/)
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
{
|
|
|
|
|
/* nothing to do */
|
|
|
|
|
}
|
|
|
|
|
|
Pie Menus C code backend.
This commit merges the code in the pie-menu branch.
As per decisions taken the last few days, there are no pie menus
included and there will be an official add-on including overrides of
some keys with pie menus. However, people will now be able to use the
new code in python.
Full Documentation is in http://wiki.blender.org/index.php/Dev:Ref/
Thanks:
Campbell Barton, Dalai Felinto and Ton Roosendaal for the code review
and design comments
Jonathan Williamson, Pawel Lyczkowski, Pablo Vazquez among others for
suggestions during the development.
Special Thanks to Sean Olson, for his support, suggestions, testing and
merciless bugging so that I would finish the pie menu code. Without him
we wouldn't be here. Also to the rest of the developers of the original
python add-on, Patrick Moore and Dan Eicher and finally to Matt Ebb, who
did the research and first implementation and whose code I used to get
started.
2014-08-11 10:39:59 +02:00
|
|
|
static void ui_litem_layout_root_radial(uiLayout *litem)
|
|
|
|
|
{
|
|
|
|
|
/* first item is pie menu title, align on center of menu */
|
2025-04-23 16:37:14 +02:00
|
|
|
uiItem *item = litem->items_.first();
|
Pie Menus C code backend.
This commit merges the code in the pie-menu branch.
As per decisions taken the last few days, there are no pie menus
included and there will be an official add-on including overrides of
some keys with pie menus. However, people will now be able to use the
new code in python.
Full Documentation is in http://wiki.blender.org/index.php/Dev:Ref/
Thanks:
Campbell Barton, Dalai Felinto and Ton Roosendaal for the code review
and design comments
Jonathan Williamson, Pawel Lyczkowski, Pablo Vazquez among others for
suggestions during the development.
Special Thanks to Sean Olson, for his support, suggestions, testing and
merciless bugging so that I would finish the pie menu code. Without him
we wouldn't be here. Also to the rest of the developers of the original
python add-on, Patrick Moore and Dan Eicher and finally to Matt Ebb, who
did the research and first implementation and whose code I used to get
started.
2014-08-11 10:39:59 +02:00
|
|
|
|
2025-04-24 17:22:28 +02:00
|
|
|
if (item->type_ == uiItemType::Button) {
|
Pie Menus C code backend.
This commit merges the code in the pie-menu branch.
As per decisions taken the last few days, there are no pie menus
included and there will be an official add-on including overrides of
some keys with pie menus. However, people will now be able to use the
new code in python.
Full Documentation is in http://wiki.blender.org/index.php/Dev:Ref/
Thanks:
Campbell Barton, Dalai Felinto and Ton Roosendaal for the code review
and design comments
Jonathan Williamson, Pawel Lyczkowski, Pablo Vazquez among others for
suggestions during the development.
Special Thanks to Sean Olson, for his support, suggestions, testing and
merciless bugging so that I would finish the pie menu code. Without him
we wouldn't be here. Also to the rest of the developers of the original
python add-on, Patrick Moore and Dan Eicher and finally to Matt Ebb, who
did the research and first implementation and whose code I used to get
started.
2014-08-11 10:39:59 +02:00
|
|
|
int itemh, itemw, x, y;
|
2025-04-23 16:37:14 +02:00
|
|
|
x = litem->x_;
|
|
|
|
|
y = litem->y_;
|
Pie Menus C code backend.
This commit merges the code in the pie-menu branch.
As per decisions taken the last few days, there are no pie menus
included and there will be an official add-on including overrides of
some keys with pie menus. However, people will now be able to use the
new code in python.
Full Documentation is in http://wiki.blender.org/index.php/Dev:Ref/
Thanks:
Campbell Barton, Dalai Felinto and Ton Roosendaal for the code review
and design comments
Jonathan Williamson, Pawel Lyczkowski, Pablo Vazquez among others for
suggestions during the development.
Special Thanks to Sean Olson, for his support, suggestions, testing and
merciless bugging so that I would finish the pie menu code. Without him
we wouldn't be here. Also to the rest of the developers of the original
python add-on, Patrick Moore and Dan Eicher and finally to Matt Ebb, who
did the research and first implementation and whose code I used to get
started.
2014-08-11 10:39:59 +02:00
|
|
|
|
|
|
|
|
ui_item_size(item, &itemw, &itemh);
|
|
|
|
|
|
2018-11-21 19:25:13 +01:00
|
|
|
ui_item_position(
|
2023-03-17 04:19:05 +01:00
|
|
|
item, x - itemw / 2, y + UI_SCALE_FAC * (U.pie_menu_threshold + 9.0f), itemw, itemh);
|
Pie Menus C code backend.
This commit merges the code in the pie-menu branch.
As per decisions taken the last few days, there are no pie menus
included and there will be an official add-on including overrides of
some keys with pie menus. However, people will now be able to use the
new code in python.
Full Documentation is in http://wiki.blender.org/index.php/Dev:Ref/
Thanks:
Campbell Barton, Dalai Felinto and Ton Roosendaal for the code review
and design comments
Jonathan Williamson, Pawel Lyczkowski, Pablo Vazquez among others for
suggestions during the development.
Special Thanks to Sean Olson, for his support, suggestions, testing and
merciless bugging so that I would finish the pie menu code. Without him
we wouldn't be here. Also to the rest of the developers of the original
python add-on, Patrick Moore and Dan Eicher and finally to Matt Ebb, who
did the research and first implementation and whose code I used to get
started.
2014-08-11 10:39:59 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
static void ui_litem_layout_root(uiLayout *litem)
|
|
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
if (litem->root_->type == UI_LAYOUT_HEADER) {
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
ui_litem_layout_row(litem);
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2025-04-23 16:37:14 +02:00
|
|
|
else if (litem->root_->type == UI_LAYOUT_PIEMENU) {
|
Pie Menus C code backend.
This commit merges the code in the pie-menu branch.
As per decisions taken the last few days, there are no pie menus
included and there will be an official add-on including overrides of
some keys with pie menus. However, people will now be able to use the
new code in python.
Full Documentation is in http://wiki.blender.org/index.php/Dev:Ref/
Thanks:
Campbell Barton, Dalai Felinto and Ton Roosendaal for the code review
and design comments
Jonathan Williamson, Pawel Lyczkowski, Pablo Vazquez among others for
suggestions during the development.
Special Thanks to Sean Olson, for his support, suggestions, testing and
merciless bugging so that I would finish the pie menu code. Without him
we wouldn't be here. Also to the rest of the developers of the original
python add-on, Patrick Moore and Dan Eicher and finally to Matt Ebb, who
did the research and first implementation and whose code I used to get
started.
2014-08-11 10:39:59 +02:00
|
|
|
ui_litem_layout_root_radial(litem);
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2025-04-23 16:37:14 +02:00
|
|
|
else if (litem->root_->type == UI_LAYOUT_MENU) {
|
2020-09-15 12:25:15 -06:00
|
|
|
ui_litem_layout_column(litem, false, true);
|
|
|
|
|
}
|
2019-03-25 10:15:20 +11:00
|
|
|
else {
|
2020-09-15 12:25:15 -06:00
|
|
|
ui_litem_layout_column(litem, false, false);
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
}
|
|
|
|
|
|
UI: add support for uiLayout based panels
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 initial use case for this are panels in the geometry nodes modifier. This patch provides
a better solution compared to what was attempted in #108565.
### Problems with Existing Approaches
Currently, there are two ways to create these expandable sections:
* One can define a new `Panel` type for each expandable section and use the `parent_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.
* It does not work so well for dynamic amounts of panels (e.g. like what we need for
the geometry nodes modifier to organize the inputs).
* Typically, Blender uses a immediate-ui approach, but subpanels break that currently
and need extra handling.
* The order of panels is not very explicit.
* One can't interleave subpanels and other ui elements, subpanels always come at the
end of the parent panel.
* Custom solution using existing `uiLayout`. This is done in the material properties. It
also has a few problems:
* Custom solutions tend to work slightly different in different places. So the UI is less unified.
* Can't drag open/close multiple panels.
* The background color for subpanels does not change.
### Solution
A possible solution to all of these problems is to add support for panels to `uiLayout` directly:
```cpp
/* Add elements before subpanel. */
if (uiLayout *panel_layout = uiLayoutPanel(layout, ...)) {
/* Add elements in subpanel, but only of the panel is open. */
}
/* Add elements after subpanel. */
```
Integrating subpanels with `uiLayout` has some benefits:
* Subpanels are treated like any other sub-layout and don't have unnecessary boilerplate.
* It becomes trivial to have a dynamic number of potentially nested subpanels.
* Resolves all mentioned problems of custom subpanel solutions.
### 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 negligible. Therefor, a much simpler solution
is possible: the open/close state can be stored in the modifier directly. This is actually
how it was implemented before 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 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 (not included)
Adding a Python API is fairly straight forward. 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:
```python
if panel := layout.panel("Mesh Settings", ...):
# Add layout elements in the panel if it's open.
```
Pull Request: https://projects.blender.org/blender/blender/pulls/113584
2023-12-22 17:57:57 +01:00
|
|
|
/* panel header layout */
|
|
|
|
|
static void ui_litem_estimate_panel_header(uiLayout *litem)
|
|
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
BLI_assert(litem->items_.size() == 1);
|
|
|
|
|
uiItem *item = litem->items_.first();
|
UI: add support for uiLayout based panels
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 initial use case for this are panels in the geometry nodes modifier. This patch provides
a better solution compared to what was attempted in #108565.
### Problems with Existing Approaches
Currently, there are two ways to create these expandable sections:
* One can define a new `Panel` type for each expandable section and use the `parent_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.
* It does not work so well for dynamic amounts of panels (e.g. like what we need for
the geometry nodes modifier to organize the inputs).
* Typically, Blender uses a immediate-ui approach, but subpanels break that currently
and need extra handling.
* The order of panels is not very explicit.
* One can't interleave subpanels and other ui elements, subpanels always come at the
end of the parent panel.
* Custom solution using existing `uiLayout`. This is done in the material properties. It
also has a few problems:
* Custom solutions tend to work slightly different in different places. So the UI is less unified.
* Can't drag open/close multiple panels.
* The background color for subpanels does not change.
### Solution
A possible solution to all of these problems is to add support for panels to `uiLayout` directly:
```cpp
/* Add elements before subpanel. */
if (uiLayout *panel_layout = uiLayoutPanel(layout, ...)) {
/* Add elements in subpanel, but only of the panel is open. */
}
/* Add elements after subpanel. */
```
Integrating subpanels with `uiLayout` has some benefits:
* Subpanels are treated like any other sub-layout and don't have unnecessary boilerplate.
* It becomes trivial to have a dynamic number of potentially nested subpanels.
* Resolves all mentioned problems of custom subpanel solutions.
### 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 negligible. Therefor, a much simpler solution
is possible: the open/close state can be stored in the modifier directly. This is actually
how it was implemented before 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 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 (not included)
Adding a Python API is fairly straight forward. 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:
```python
if panel := layout.panel("Mesh Settings", ...):
# Add layout elements in the panel if it's open.
```
Pull Request: https://projects.blender.org/blender/blender/pulls/113584
2023-12-22 17:57:57 +01:00
|
|
|
|
|
|
|
|
int w, h;
|
|
|
|
|
ui_item_size(item, &w, &h);
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->w_ = w;
|
|
|
|
|
litem->h_ = h;
|
UI: add support for uiLayout based panels
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 initial use case for this are panels in the geometry nodes modifier. This patch provides
a better solution compared to what was attempted in #108565.
### Problems with Existing Approaches
Currently, there are two ways to create these expandable sections:
* One can define a new `Panel` type for each expandable section and use the `parent_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.
* It does not work so well for dynamic amounts of panels (e.g. like what we need for
the geometry nodes modifier to organize the inputs).
* Typically, Blender uses a immediate-ui approach, but subpanels break that currently
and need extra handling.
* The order of panels is not very explicit.
* One can't interleave subpanels and other ui elements, subpanels always come at the
end of the parent panel.
* Custom solution using existing `uiLayout`. This is done in the material properties. It
also has a few problems:
* Custom solutions tend to work slightly different in different places. So the UI is less unified.
* Can't drag open/close multiple panels.
* The background color for subpanels does not change.
### Solution
A possible solution to all of these problems is to add support for panels to `uiLayout` directly:
```cpp
/* Add elements before subpanel. */
if (uiLayout *panel_layout = uiLayoutPanel(layout, ...)) {
/* Add elements in subpanel, but only of the panel is open. */
}
/* Add elements after subpanel. */
```
Integrating subpanels with `uiLayout` has some benefits:
* Subpanels are treated like any other sub-layout and don't have unnecessary boilerplate.
* It becomes trivial to have a dynamic number of potentially nested subpanels.
* Resolves all mentioned problems of custom subpanel solutions.
### 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 negligible. Therefor, a much simpler solution
is possible: the open/close state can be stored in the modifier directly. This is actually
how it was implemented before 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 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 (not included)
Adding a Python API is fairly straight forward. 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:
```python
if panel := layout.panel("Mesh Settings", ...):
# Add layout elements in the panel if it's open.
```
Pull Request: https://projects.blender.org/blender/blender/pulls/113584
2023-12-22 17:57:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ui_litem_layout_panel_header(uiLayout *litem)
|
|
|
|
|
{
|
2024-07-10 14:46:06 +02:00
|
|
|
uiLayoutItemPanelHeader *header_litem = static_cast<uiLayoutItemPanelHeader *>(litem);
|
2025-04-23 16:37:14 +02:00
|
|
|
Panel *panel = litem->root_->block->panel;
|
UI: add support for uiLayout based panels
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 initial use case for this are panels in the geometry nodes modifier. This patch provides
a better solution compared to what was attempted in #108565.
### Problems with Existing Approaches
Currently, there are two ways to create these expandable sections:
* One can define a new `Panel` type for each expandable section and use the `parent_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.
* It does not work so well for dynamic amounts of panels (e.g. like what we need for
the geometry nodes modifier to organize the inputs).
* Typically, Blender uses a immediate-ui approach, but subpanels break that currently
and need extra handling.
* The order of panels is not very explicit.
* One can't interleave subpanels and other ui elements, subpanels always come at the
end of the parent panel.
* Custom solution using existing `uiLayout`. This is done in the material properties. It
also has a few problems:
* Custom solutions tend to work slightly different in different places. So the UI is less unified.
* Can't drag open/close multiple panels.
* The background color for subpanels does not change.
### Solution
A possible solution to all of these problems is to add support for panels to `uiLayout` directly:
```cpp
/* Add elements before subpanel. */
if (uiLayout *panel_layout = uiLayoutPanel(layout, ...)) {
/* Add elements in subpanel, but only of the panel is open. */
}
/* Add elements after subpanel. */
```
Integrating subpanels with `uiLayout` has some benefits:
* Subpanels are treated like any other sub-layout and don't have unnecessary boilerplate.
* It becomes trivial to have a dynamic number of potentially nested subpanels.
* Resolves all mentioned problems of custom subpanel solutions.
### 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 negligible. Therefor, a much simpler solution
is possible: the open/close state can be stored in the modifier directly. This is actually
how it was implemented before 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 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 (not included)
Adding a Python API is fairly straight forward. 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:
```python
if panel := layout.panel("Mesh Settings", ...):
# Add layout elements in the panel if it's open.
```
Pull Request: https://projects.blender.org/blender/blender/pulls/113584
2023-12-22 17:57:57 +01:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
BLI_assert(litem->items_.size() == 1);
|
|
|
|
|
uiItem *item = litem->items_.first();
|
UI: add support for uiLayout based panels
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 initial use case for this are panels in the geometry nodes modifier. This patch provides
a better solution compared to what was attempted in #108565.
### Problems with Existing Approaches
Currently, there are two ways to create these expandable sections:
* One can define a new `Panel` type for each expandable section and use the `parent_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.
* It does not work so well for dynamic amounts of panels (e.g. like what we need for
the geometry nodes modifier to organize the inputs).
* Typically, Blender uses a immediate-ui approach, but subpanels break that currently
and need extra handling.
* The order of panels is not very explicit.
* One can't interleave subpanels and other ui elements, subpanels always come at the
end of the parent panel.
* Custom solution using existing `uiLayout`. This is done in the material properties. It
also has a few problems:
* Custom solutions tend to work slightly different in different places. So the UI is less unified.
* Can't drag open/close multiple panels.
* The background color for subpanels does not change.
### Solution
A possible solution to all of these problems is to add support for panels to `uiLayout` directly:
```cpp
/* Add elements before subpanel. */
if (uiLayout *panel_layout = uiLayoutPanel(layout, ...)) {
/* Add elements in subpanel, but only of the panel is open. */
}
/* Add elements after subpanel. */
```
Integrating subpanels with `uiLayout` has some benefits:
* Subpanels are treated like any other sub-layout and don't have unnecessary boilerplate.
* It becomes trivial to have a dynamic number of potentially nested subpanels.
* Resolves all mentioned problems of custom subpanel solutions.
### 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 negligible. Therefor, a much simpler solution
is possible: the open/close state can be stored in the modifier directly. This is actually
how it was implemented before 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 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 (not included)
Adding a Python API is fairly straight forward. 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:
```python
if panel := layout.panel("Mesh Settings", ...):
# Add layout elements in the panel if it's open.
```
Pull Request: https://projects.blender.org/blender/blender/pulls/113584
2023-12-22 17:57:57 +01:00
|
|
|
|
|
|
|
|
int w, h;
|
|
|
|
|
ui_item_size(item, &w, &h);
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->y_ -= h;
|
|
|
|
|
ui_item_position(item, litem->x_, litem->y_, litem->w_, h);
|
2024-07-02 13:29:14 +10:00
|
|
|
const float offset = UI_style_get_dpi()->panelspace;
|
2025-04-23 16:37:14 +02:00
|
|
|
panel->runtime->layout_panels.headers.append({float(litem->y_) - offset,
|
|
|
|
|
float(litem->y_ + litem->h_) - offset,
|
UI: add support for uiLayout based panels
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 initial use case for this are panels in the geometry nodes modifier. This patch provides
a better solution compared to what was attempted in #108565.
### Problems with Existing Approaches
Currently, there are two ways to create these expandable sections:
* One can define a new `Panel` type for each expandable section and use the `parent_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.
* It does not work so well for dynamic amounts of panels (e.g. like what we need for
the geometry nodes modifier to organize the inputs).
* Typically, Blender uses a immediate-ui approach, but subpanels break that currently
and need extra handling.
* The order of panels is not very explicit.
* One can't interleave subpanels and other ui elements, subpanels always come at the
end of the parent panel.
* Custom solution using existing `uiLayout`. This is done in the material properties. It
also has a few problems:
* Custom solutions tend to work slightly different in different places. So the UI is less unified.
* Can't drag open/close multiple panels.
* The background color for subpanels does not change.
### Solution
A possible solution to all of these problems is to add support for panels to `uiLayout` directly:
```cpp
/* Add elements before subpanel. */
if (uiLayout *panel_layout = uiLayoutPanel(layout, ...)) {
/* Add elements in subpanel, but only of the panel is open. */
}
/* Add elements after subpanel. */
```
Integrating subpanels with `uiLayout` has some benefits:
* Subpanels are treated like any other sub-layout and don't have unnecessary boilerplate.
* It becomes trivial to have a dynamic number of potentially nested subpanels.
* Resolves all mentioned problems of custom subpanel solutions.
### 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 negligible. Therefor, a much simpler solution
is possible: the open/close state can be stored in the modifier directly. This is actually
how it was implemented before 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 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 (not included)
Adding a Python API is fairly straight forward. 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:
```python
if panel := layout.panel("Mesh Settings", ...):
# Add layout elements in the panel if it's open.
```
Pull Request: https://projects.blender.org/blender/blender/pulls/113584
2023-12-22 17:57:57 +01:00
|
|
|
header_litem->open_prop_owner,
|
|
|
|
|
header_litem->open_prop_name});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* panel body layout */
|
|
|
|
|
static void ui_litem_estimate_panel_body(uiLayout *litem)
|
|
|
|
|
{
|
|
|
|
|
ui_litem_estimate_column(litem, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ui_litem_layout_panel_body(uiLayout *litem)
|
|
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
Panel *panel = litem->root_->block->panel;
|
UI: add support for uiLayout based panels
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 initial use case for this are panels in the geometry nodes modifier. This patch provides
a better solution compared to what was attempted in #108565.
### Problems with Existing Approaches
Currently, there are two ways to create these expandable sections:
* One can define a new `Panel` type for each expandable section and use the `parent_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.
* It does not work so well for dynamic amounts of panels (e.g. like what we need for
the geometry nodes modifier to organize the inputs).
* Typically, Blender uses a immediate-ui approach, but subpanels break that currently
and need extra handling.
* The order of panels is not very explicit.
* One can't interleave subpanels and other ui elements, subpanels always come at the
end of the parent panel.
* Custom solution using existing `uiLayout`. This is done in the material properties. It
also has a few problems:
* Custom solutions tend to work slightly different in different places. So the UI is less unified.
* Can't drag open/close multiple panels.
* The background color for subpanels does not change.
### Solution
A possible solution to all of these problems is to add support for panels to `uiLayout` directly:
```cpp
/* Add elements before subpanel. */
if (uiLayout *panel_layout = uiLayoutPanel(layout, ...)) {
/* Add elements in subpanel, but only of the panel is open. */
}
/* Add elements after subpanel. */
```
Integrating subpanels with `uiLayout` has some benefits:
* Subpanels are treated like any other sub-layout and don't have unnecessary boilerplate.
* It becomes trivial to have a dynamic number of potentially nested subpanels.
* Resolves all mentioned problems of custom subpanel solutions.
### 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 negligible. Therefor, a much simpler solution
is possible: the open/close state can be stored in the modifier directly. This is actually
how it was implemented before 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 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 (not included)
Adding a Python API is fairly straight forward. 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:
```python
if panel := layout.panel("Mesh Settings", ...):
# Add layout elements in the panel if it's open.
```
Pull Request: https://projects.blender.org/blender/blender/pulls/113584
2023-12-22 17:57:57 +01:00
|
|
|
ui_litem_layout_column(litem, false, false);
|
2024-07-02 13:29:14 +10:00
|
|
|
const float offset = UI_style_get_dpi()->panelspace;
|
|
|
|
|
panel->runtime->layout_panels.bodies.append({
|
2025-04-23 16:37:14 +02:00
|
|
|
float(litem->y_ - litem->space_) - offset,
|
|
|
|
|
float(litem->y_ + litem->h_ + litem->space_) - offset,
|
2024-07-02 13:29:14 +10:00
|
|
|
});
|
UI: add support for uiLayout based panels
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 initial use case for this are panels in the geometry nodes modifier. This patch provides
a better solution compared to what was attempted in #108565.
### Problems with Existing Approaches
Currently, there are two ways to create these expandable sections:
* One can define a new `Panel` type for each expandable section and use the `parent_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.
* It does not work so well for dynamic amounts of panels (e.g. like what we need for
the geometry nodes modifier to organize the inputs).
* Typically, Blender uses a immediate-ui approach, but subpanels break that currently
and need extra handling.
* The order of panels is not very explicit.
* One can't interleave subpanels and other ui elements, subpanels always come at the
end of the parent panel.
* Custom solution using existing `uiLayout`. This is done in the material properties. It
also has a few problems:
* Custom solutions tend to work slightly different in different places. So the UI is less unified.
* Can't drag open/close multiple panels.
* The background color for subpanels does not change.
### Solution
A possible solution to all of these problems is to add support for panels to `uiLayout` directly:
```cpp
/* Add elements before subpanel. */
if (uiLayout *panel_layout = uiLayoutPanel(layout, ...)) {
/* Add elements in subpanel, but only of the panel is open. */
}
/* Add elements after subpanel. */
```
Integrating subpanels with `uiLayout` has some benefits:
* Subpanels are treated like any other sub-layout and don't have unnecessary boilerplate.
* It becomes trivial to have a dynamic number of potentially nested subpanels.
* Resolves all mentioned problems of custom subpanel solutions.
### 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 negligible. Therefor, a much simpler solution
is possible: the open/close state can be stored in the modifier directly. This is actually
how it was implemented before 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 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 (not included)
Adding a Python API is fairly straight forward. 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:
```python
if panel := layout.panel("Mesh Settings", ...):
# Add layout elements in the panel if it's open.
```
Pull Request: https://projects.blender.org/blender/blender/pulls/113584
2023-12-22 17:57:57 +01:00
|
|
|
}
|
|
|
|
|
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
/* box layout */
|
|
|
|
|
static void ui_litem_estimate_box(uiLayout *litem)
|
|
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
const uiStyle *style = litem->root_->style;
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
|
2017-03-26 18:02:11 +03:00
|
|
|
ui_litem_estimate_column(litem, true);
|
2019-10-28 05:00:56 +11:00
|
|
|
|
|
|
|
|
int boxspace = style->boxspace;
|
2025-04-23 16:37:14 +02:00
|
|
|
if (litem->root_->type == UI_LAYOUT_HEADER) {
|
2019-10-28 05:00:56 +11:00
|
|
|
boxspace = 0;
|
|
|
|
|
}
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->w_ += 2 * boxspace;
|
|
|
|
|
litem->h_ += 2 * boxspace;
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ui_litem_layout_box(uiLayout *litem)
|
|
|
|
|
{
|
2024-07-10 14:46:06 +02:00
|
|
|
uiLayoutItemBx *box = static_cast<uiLayoutItemBx *>(litem);
|
2025-04-23 16:37:14 +02:00
|
|
|
const uiStyle *style = litem->root_->style;
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
|
2019-10-28 05:00:56 +11:00
|
|
|
int boxspace = style->boxspace;
|
2025-04-23 16:37:14 +02:00
|
|
|
if (litem->root_->type == UI_LAYOUT_HEADER) {
|
2019-10-28 05:00:56 +11:00
|
|
|
boxspace = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
const int w = litem->w_;
|
|
|
|
|
const int h = litem->h_;
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->x_ += boxspace;
|
|
|
|
|
litem->y_ -= boxspace;
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
|
2019-03-25 10:15:20 +11:00
|
|
|
if (w != 0) {
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->w_ -= 2 * boxspace;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
|
|
|
|
if (h != 0) {
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->h_ -= 2 * boxspace;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
|
2020-09-15 12:25:15 -06:00
|
|
|
ui_litem_layout_column(litem, true, false);
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->x_ -= boxspace;
|
|
|
|
|
litem->y_ -= boxspace;
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
|
2019-03-25 10:15:20 +11:00
|
|
|
if (w != 0) {
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->w_ += 2 * boxspace;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
|
|
|
|
if (h != 0) {
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->h_ += 2 * boxspace;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
|
|
|
|
|
/* roundbox around the sublayout */
|
2020-12-18 12:39:50 -06:00
|
|
|
uiBut *but = box->roundbox;
|
2025-04-23 16:37:14 +02:00
|
|
|
but->rect.xmin = litem->x_;
|
|
|
|
|
but->rect.ymin = litem->y_;
|
|
|
|
|
but->rect.xmax = litem->x_ + litem->w_;
|
|
|
|
|
but->rect.ymax = litem->y_ + litem->h_;
|
2009-04-15 15:09:36 +00:00
|
|
|
}
|
|
|
|
|
|
2009-04-11 01:52:27 +00:00
|
|
|
/* multi-column layout, automatically flowing to the next */
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
static void ui_litem_estimate_column_flow(uiLayout *litem)
|
2009-04-11 01:52:27 +00:00
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
const uiStyle *style = litem->root_->style;
|
2024-07-10 14:46:06 +02:00
|
|
|
uiLayoutItemFlow *flow = static_cast<uiLayoutItemFlow *>(litem);
|
2020-12-18 12:39:50 -06:00
|
|
|
int itemw, itemh, maxw = 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-04-11 01:52:27 +00:00
|
|
|
/* compute max needed width and total height */
|
2020-12-18 12:39:50 -06:00
|
|
|
int toth = 0;
|
|
|
|
|
int totitem = 0;
|
2025-04-23 16:37:14 +02:00
|
|
|
for (uiItem *item : litem->items_) {
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
ui_item_size(item, &itemw, &itemh);
|
2024-01-22 15:58:18 +01:00
|
|
|
maxw = std::max(maxw, itemw);
|
2009-04-16 12:17:58 +00:00
|
|
|
toth += itemh;
|
2009-04-11 01:52:27 +00:00
|
|
|
totitem++;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (flow->number <= 0) {
|
2009-04-11 01:52:27 +00:00
|
|
|
/* auto compute number of columns, not very good */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (maxw == 0) {
|
2012-03-30 01:51:25 +00:00
|
|
|
flow->totcol = 1;
|
2009-04-11 01:52:27 +00:00
|
|
|
return;
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
flow->totcol = max_ii(litem->root_->emw / maxw, 1);
|
2012-10-24 05:06:40 +00:00
|
|
|
flow->totcol = min_ii(flow->totcol, totitem);
|
2009-04-11 01:52:27 +00:00
|
|
|
}
|
2019-03-26 21:16:13 +11:00
|
|
|
else {
|
2012-03-30 01:51:25 +00:00
|
|
|
flow->totcol = flow->number;
|
2019-03-26 21:16:13 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-04-11 01:52:27 +00:00
|
|
|
/* compute sizes */
|
2020-12-18 12:39:50 -06:00
|
|
|
int x = 0;
|
|
|
|
|
int y = 0;
|
|
|
|
|
int emy = 0;
|
|
|
|
|
int miny = 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-30 01:51:25 +00:00
|
|
|
maxw = 0;
|
2021-01-04 17:02:13 +11:00
|
|
|
const int emh = toth / flow->totcol;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-04-11 01:52:27 +00:00
|
|
|
/* create column per column */
|
2020-12-18 12:39:50 -06:00
|
|
|
int col = 0;
|
2025-04-23 16:37:14 +02:00
|
|
|
for (uiItem *item : litem->items_) {
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
ui_item_size(item, &itemw, &itemh);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
y -= itemh + style->buttonspacey;
|
2012-11-07 12:31:05 +00:00
|
|
|
miny = min_ii(miny, y);
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
emy -= itemh;
|
2012-11-07 12:31:05 +00:00
|
|
|
maxw = max_ii(itemw, maxw);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-04-16 12:17:58 +00:00
|
|
|
/* decide to go to next one */
|
2012-03-30 01:51:25 +00:00
|
|
|
if (col < flow->totcol - 1 && emy <= -emh) {
|
2025-04-23 14:54:06 +02:00
|
|
|
x += maxw + litem->space_;
|
2012-03-30 01:51:25 +00:00
|
|
|
maxw = 0;
|
|
|
|
|
y = 0;
|
2012-08-01 17:52:14 +00:00
|
|
|
emy = 0; /* need to reset height again for next column */
|
2009-04-11 01:52:27 +00:00
|
|
|
col++;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->w_ = x;
|
|
|
|
|
litem->h_ = litem->y_ - miny;
|
2009-04-11 01:52:27 +00:00
|
|
|
}
|
|
|
|
|
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
static void ui_litem_layout_column_flow(uiLayout *litem)
|
2009-03-13 13:38:41 +00:00
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
const uiStyle *style = litem->root_->style;
|
2024-07-10 14:46:06 +02:00
|
|
|
uiLayoutItemFlow *flow = static_cast<uiLayoutItemFlow *>(litem);
|
2020-12-18 12:39:50 -06:00
|
|
|
int col, emh, itemw, itemh;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
/* compute max needed width and total height */
|
2020-12-18 12:39:50 -06:00
|
|
|
int toth = 0;
|
2025-04-23 16:37:14 +02:00
|
|
|
for (uiItem *item : litem->items_) {
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
ui_item_size(item, &itemw, &itemh);
|
|
|
|
|
toth += itemh;
|
2009-03-13 13:38:41 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
/* compute sizes */
|
2025-04-23 16:37:14 +02:00
|
|
|
int x = litem->x_;
|
|
|
|
|
int y = litem->y_;
|
2020-12-18 12:39:50 -06:00
|
|
|
int emy = 0;
|
|
|
|
|
int miny = 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-30 01:51:25 +00:00
|
|
|
emh = toth / flow->totcol;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
/* create column per column */
|
2012-03-30 01:51:25 +00:00
|
|
|
col = 0;
|
2025-04-23 16:37:14 +02:00
|
|
|
int w = (litem->w_ - (flow->totcol - 1) * style->columnspace) / flow->totcol;
|
|
|
|
|
for (uiItem *item : litem->items_) {
|
2016-10-13 10:21:38 +02:00
|
|
|
ui_item_size(item, &itemw, &itemh);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-23 14:54:06 +02:00
|
|
|
itemw = (litem->alignment_ == UI_LAYOUT_ALIGN_EXPAND) ? w : min_ii(w, itemw);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
y -= itemh;
|
|
|
|
|
emy -= itemh;
|
2016-10-12 21:28:11 +02:00
|
|
|
ui_item_position(item, x, y, itemw, itemh);
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
y -= style->buttonspacey;
|
2012-10-24 05:06:40 +00:00
|
|
|
miny = min_ii(miny, y);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
/* decide to go to next one */
|
2012-03-30 01:51:25 +00:00
|
|
|
if (col < flow->totcol - 1 && emy <= -emh) {
|
2016-10-13 10:21:38 +02:00
|
|
|
x += w + style->columnspace;
|
2025-04-23 16:37:14 +02:00
|
|
|
y = litem->y_;
|
2012-08-01 17:52:14 +00:00
|
|
|
emy = 0; /* need to reset height again for next column */
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
col++;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
const int remaining_width = litem->w_ - (x - litem->x_);
|
2019-04-17 09:05:56 +02:00
|
|
|
const int remaining_width_between_columns = (flow->totcol - col - 1) * style->columnspace;
|
|
|
|
|
const int remaining_columns = flow->totcol - col;
|
|
|
|
|
w = (remaining_width - remaining_width_between_columns) / remaining_columns;
|
2009-03-13 13:38:41 +00:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->h_ = litem->y_ - miny;
|
|
|
|
|
litem->x_ = x;
|
|
|
|
|
litem->y_ = miny;
|
2009-03-13 13:38:41 +00:00
|
|
|
}
|
|
|
|
|
|
2018-06-09 16:50:05 +02:00
|
|
|
/* multi-column and multi-row layout. */
|
2022-11-25 23:48:02 -06:00
|
|
|
struct UILayoutGridFlowInput {
|
2018-09-27 15:49:59 +02:00
|
|
|
/* General layout control settings. */
|
2022-11-25 23:48:02 -06:00
|
|
|
bool row_major : 1; /* Fill rows before columns */
|
|
|
|
|
bool even_columns : 1; /* All columns will have same width. */
|
|
|
|
|
bool even_rows : 1; /* All rows will have same height. */
|
|
|
|
|
int space_x; /* Space between columns. */
|
|
|
|
|
int space_y; /* Space between rows. */
|
|
|
|
|
/* Real data about current position and size of this layout item
|
|
|
|
|
* (either estimated, or final values). */
|
|
|
|
|
int litem_w; /* Layout item width. */
|
|
|
|
|
int litem_x; /* Layout item X position. */
|
|
|
|
|
int litem_y; /* Layout item Y position. */
|
2018-06-09 16:50:05 +02:00
|
|
|
/* Actual number of columns and rows to generate (computed from first pass usually). */
|
2022-11-25 23:48:02 -06:00
|
|
|
int tot_columns; /* Number of columns. */
|
|
|
|
|
int tot_rows; /* Number of rows. */
|
|
|
|
|
};
|
2018-06-09 16:50:05 +02:00
|
|
|
|
2022-11-25 23:48:02 -06:00
|
|
|
struct UILayoutGridFlowOutput {
|
2018-06-09 16:50:05 +02:00
|
|
|
int *tot_items; /* Total number of items in this grid layout. */
|
|
|
|
|
/* Width / X pos data. */
|
|
|
|
|
float *global_avg_w; /* Computed average width of the columns. */
|
|
|
|
|
int *cos_x_array; /* Computed X coordinate of each column. */
|
|
|
|
|
int *widths_array; /* Computed width of each column. */
|
|
|
|
|
int *tot_w; /* Computed total width. */
|
|
|
|
|
/* Height / Y pos data. */
|
|
|
|
|
int *global_max_h; /* Computed height of the tallest item in the grid. */
|
|
|
|
|
int *cos_y_array; /* Computed Y coordinate of each column. */
|
|
|
|
|
int *heights_array; /* Computed height of each column. */
|
|
|
|
|
int *tot_h; /* Computed total height. */
|
2022-11-25 23:48:02 -06:00
|
|
|
};
|
2018-06-09 16:50:05 +02:00
|
|
|
|
2024-07-10 14:46:06 +02:00
|
|
|
static void ui_litem_grid_flow_compute(blender::Span<uiItem *> items,
|
2022-11-25 23:48:02 -06:00
|
|
|
const UILayoutGridFlowInput *parameters,
|
2018-06-09 16:50:05 +02:00
|
|
|
UILayoutGridFlowOutput *results)
|
|
|
|
|
{
|
|
|
|
|
float tot_w = 0.0f, tot_h = 0.0f;
|
|
|
|
|
float global_avg_w = 0.0f, global_totweight_w = 0.0f;
|
|
|
|
|
int global_max_h = 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-11-25 23:48:02 -06:00
|
|
|
BLI_assert(parameters->tot_columns != 0 ||
|
|
|
|
|
(results->cos_x_array == nullptr && results->widths_array == nullptr &&
|
|
|
|
|
results->tot_w == nullptr));
|
|
|
|
|
BLI_assert(parameters->tot_rows != 0 ||
|
|
|
|
|
(results->cos_y_array == nullptr && results->heights_array == nullptr &&
|
|
|
|
|
results->tot_h == nullptr));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-09 16:50:05 +02:00
|
|
|
if (results->tot_items) {
|
|
|
|
|
*results->tot_items = 0;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-07-10 14:46:06 +02:00
|
|
|
if (items.is_empty()) {
|
2018-06-09 16:50:05 +02:00
|
|
|
if (results->global_avg_w) {
|
|
|
|
|
*results->global_avg_w = 0.0f;
|
|
|
|
|
}
|
|
|
|
|
if (results->global_max_h) {
|
|
|
|
|
*results->global_max_h = 0;
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-11-25 23:48:02 -06:00
|
|
|
blender::Array<float, 64> avg_w(parameters->tot_columns, 0.0f);
|
|
|
|
|
blender::Array<float, 64> totweight_w(parameters->tot_columns, 0.0f);
|
|
|
|
|
blender::Array<int, 64> max_h(parameters->tot_rows, 0);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-08-18 21:46:29 -04:00
|
|
|
int i = 0;
|
2024-07-10 14:46:06 +02:00
|
|
|
for (const uiItem *item : items) {
|
2018-06-09 16:50:05 +02:00
|
|
|
int item_w, item_h;
|
|
|
|
|
ui_item_size(item, &item_w, &item_h);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-01-03 11:04:16 +11:00
|
|
|
global_avg_w += float(item_w * item_w);
|
2022-12-08 13:04:50 +11:00
|
|
|
global_totweight_w += float(item_w);
|
2018-06-09 16:50:05 +02:00
|
|
|
global_max_h = max_ii(global_max_h, item_h);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-09 16:50:05 +02:00
|
|
|
if (parameters->tot_rows != 0 && parameters->tot_columns != 0) {
|
|
|
|
|
const int index_col = parameters->row_major ? i % parameters->tot_columns :
|
|
|
|
|
i / parameters->tot_rows;
|
|
|
|
|
const int index_row = parameters->row_major ? i / parameters->tot_columns :
|
|
|
|
|
i % parameters->tot_rows;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-12-08 13:04:50 +11:00
|
|
|
avg_w[index_col] += float(item_w * item_w);
|
|
|
|
|
totweight_w[index_col] += float(item_w);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-09 16:50:05 +02:00
|
|
|
max_h[index_row] = max_ii(max_h[index_row], item_h);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-09 16:50:05 +02:00
|
|
|
if (results->tot_items) {
|
|
|
|
|
(*results->tot_items)++;
|
|
|
|
|
}
|
2020-08-18 21:46:29 -04:00
|
|
|
i++;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2018-06-09 16:50:05 +02:00
|
|
|
/* Finalize computing of column average sizes */
|
|
|
|
|
global_avg_w /= global_totweight_w;
|
|
|
|
|
if (parameters->tot_columns != 0) {
|
|
|
|
|
for (i = 0; i < parameters->tot_columns; i++) {
|
|
|
|
|
avg_w[i] /= totweight_w[i];
|
|
|
|
|
tot_w += avg_w[i];
|
|
|
|
|
}
|
|
|
|
|
if (parameters->even_columns) {
|
|
|
|
|
tot_w = ceilf(global_avg_w) * parameters->tot_columns;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2018-06-09 16:50:05 +02:00
|
|
|
/* Finalize computing of rows max sizes */
|
|
|
|
|
if (parameters->tot_rows != 0) {
|
|
|
|
|
for (i = 0; i < parameters->tot_rows; i++) {
|
|
|
|
|
tot_h += max_h[i];
|
|
|
|
|
}
|
|
|
|
|
if (parameters->even_rows) {
|
|
|
|
|
tot_h = global_max_h * parameters->tot_columns;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2018-06-09 16:50:05 +02:00
|
|
|
/* Compute positions and sizes of all cells. */
|
2022-11-25 23:48:02 -06:00
|
|
|
if (results->cos_x_array != nullptr && results->widths_array != nullptr) {
|
2018-06-09 16:50:05 +02:00
|
|
|
/* We enlarge/narrow columns evenly to match available width. */
|
2023-01-03 11:04:16 +11:00
|
|
|
const float wfac = float(parameters->litem_w -
|
|
|
|
|
(parameters->tot_columns - 1) * parameters->space_x) /
|
2018-06-09 16:50:05 +02:00
|
|
|
tot_w;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-09 16:50:05 +02:00
|
|
|
for (int col = 0; col < parameters->tot_columns; col++) {
|
2018-06-14 22:44:53 +02:00
|
|
|
results->cos_x_array[col] = (col ? results->cos_x_array[col - 1] +
|
|
|
|
|
results->widths_array[col - 1] + parameters->space_x :
|
|
|
|
|
parameters->litem_x);
|
2018-06-09 16:50:05 +02:00
|
|
|
if (parameters->even_columns) {
|
2018-06-14 22:44:53 +02:00
|
|
|
/* (< remaining width > - < space between remaining columns >) / < remaining columns > */
|
|
|
|
|
results->widths_array[col] = (((parameters->litem_w -
|
|
|
|
|
(results->cos_x_array[col] - parameters->litem_x)) -
|
|
|
|
|
(parameters->tot_columns - col - 1) * parameters->space_x) /
|
|
|
|
|
(parameters->tot_columns - col));
|
2018-06-09 16:50:05 +02:00
|
|
|
}
|
|
|
|
|
else if (col == parameters->tot_columns - 1) {
|
|
|
|
|
/* Last column copes width rounding errors... */
|
|
|
|
|
results->widths_array[col] = parameters->litem_w -
|
|
|
|
|
(results->cos_x_array[col] - parameters->litem_x);
|
|
|
|
|
}
|
|
|
|
|
else {
|
2023-01-03 11:04:16 +11:00
|
|
|
results->widths_array[col] = int(avg_w[col] * wfac);
|
2018-06-09 16:50:05 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
2022-11-25 23:48:02 -06:00
|
|
|
if (results->cos_y_array != nullptr && results->heights_array != nullptr) {
|
2018-06-09 16:50:05 +02:00
|
|
|
for (int row = 0; row < parameters->tot_rows; row++) {
|
|
|
|
|
if (parameters->even_rows) {
|
|
|
|
|
results->heights_array[row] = global_max_h;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
results->heights_array[row] = max_h[row];
|
|
|
|
|
}
|
2018-06-14 22:44:53 +02:00
|
|
|
results->cos_y_array[row] = (row ? results->cos_y_array[row - 1] - parameters->space_y -
|
|
|
|
|
results->heights_array[row] :
|
|
|
|
|
parameters->litem_y - results->heights_array[row]);
|
2018-06-09 16:50:05 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2018-06-09 16:50:05 +02:00
|
|
|
if (results->global_avg_w) {
|
|
|
|
|
*results->global_avg_w = global_avg_w;
|
|
|
|
|
}
|
|
|
|
|
if (results->global_max_h) {
|
|
|
|
|
*results->global_max_h = global_max_h;
|
|
|
|
|
}
|
|
|
|
|
if (results->tot_w) {
|
2022-12-08 13:04:50 +11:00
|
|
|
*results->tot_w = int(tot_w) + parameters->space_x * (parameters->tot_columns - 1);
|
2018-06-09 16:50:05 +02:00
|
|
|
}
|
|
|
|
|
if (results->tot_h) {
|
|
|
|
|
*results->tot_h = tot_h + parameters->space_y * (parameters->tot_rows - 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ui_litem_estimate_grid_flow(uiLayout *litem)
|
|
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
const uiStyle *style = litem->root_->style;
|
2024-07-10 14:46:06 +02:00
|
|
|
uiLayoutItemGridFlow *gflow = static_cast<uiLayoutItemGridFlow *>(litem);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-09 16:50:05 +02:00
|
|
|
const int space_x = style->columnspace;
|
|
|
|
|
const int space_y = style->buttonspacey;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-09 16:50:05 +02:00
|
|
|
/* Estimate average needed width and height per item. */
|
|
|
|
|
{
|
|
|
|
|
float avg_w;
|
|
|
|
|
int max_h;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-11-25 23:48:02 -06:00
|
|
|
UILayoutGridFlowInput input{};
|
|
|
|
|
input.row_major = gflow->row_major;
|
|
|
|
|
input.even_columns = gflow->even_columns;
|
|
|
|
|
input.even_rows = gflow->even_rows;
|
2025-04-23 16:37:14 +02:00
|
|
|
input.litem_w = litem->w_;
|
|
|
|
|
input.litem_x = litem->x_;
|
|
|
|
|
input.litem_y = litem->y_;
|
2022-11-25 23:48:02 -06:00
|
|
|
input.space_x = space_x;
|
|
|
|
|
input.space_y = space_y;
|
|
|
|
|
UILayoutGridFlowOutput output{};
|
|
|
|
|
output.tot_items = &gflow->tot_items;
|
|
|
|
|
output.global_avg_w = &avg_w;
|
|
|
|
|
output.global_max_h = &max_h;
|
2025-04-23 16:37:14 +02:00
|
|
|
ui_litem_grid_flow_compute(litem->items_, &input, &output);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-09 16:50:05 +02:00
|
|
|
if (gflow->tot_items == 0) {
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->w_ = litem->h_ = 0;
|
2018-06-09 16:50:05 +02:00
|
|
|
gflow->tot_columns = gflow->tot_rows = 0;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-17 08:44:38 +02:00
|
|
|
/* Even in varying column width case,
|
|
|
|
|
* we fix our columns number from weighted average width of items,
|
|
|
|
|
* a proper solving of required width would be too costly,
|
|
|
|
|
* and this should give reasonably good results in all reasonable cases. */
|
2018-07-01 09:23:51 +02:00
|
|
|
if (gflow->columns_len > 0) {
|
|
|
|
|
gflow->tot_columns = gflow->columns_len;
|
2018-06-09 16:50:05 +02:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (avg_w == 0.0f) {
|
|
|
|
|
gflow->tot_columns = 1;
|
|
|
|
|
}
|
|
|
|
|
else {
|
2025-04-23 16:37:14 +02:00
|
|
|
gflow->tot_columns = min_ii(max_ii(int(litem->w_ / avg_w), 1), gflow->tot_items);
|
2018-06-09 16:50:05 +02:00
|
|
|
}
|
|
|
|
|
}
|
2023-01-03 11:04:16 +11:00
|
|
|
gflow->tot_rows = int(ceilf(float(gflow->tot_items) / gflow->tot_columns));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-09 16:50:05 +02:00
|
|
|
/* Try to tweak number of columns and rows to get better filling of last column or row,
|
|
|
|
|
* and apply 'modulo' value to number of columns or rows.
|
|
|
|
|
* Note that modulo does not prevent ending with fewer columns/rows than modulo, if mandatory
|
|
|
|
|
* to avoid empty column/row. */
|
|
|
|
|
{
|
2018-07-01 09:23:51 +02:00
|
|
|
const int modulo = (gflow->columns_len < -1) ? -gflow->columns_len : 0;
|
2018-06-09 16:50:05 +02:00
|
|
|
const int step = modulo ? modulo : 1;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-09 16:50:05 +02:00
|
|
|
if (gflow->row_major) {
|
2018-09-27 15:49:59 +02:00
|
|
|
/* Adjust number of columns to be multiple of given modulo. */
|
2018-06-09 16:50:05 +02:00
|
|
|
if (modulo && gflow->tot_columns % modulo != 0 && gflow->tot_columns > modulo) {
|
|
|
|
|
gflow->tot_columns = gflow->tot_columns - (gflow->tot_columns % modulo);
|
|
|
|
|
}
|
|
|
|
|
/* Find smallest number of columns conserving computed optimal number of rows. */
|
2023-01-03 11:04:16 +11:00
|
|
|
for (gflow->tot_rows = int(ceilf(float(gflow->tot_items) / gflow->tot_columns));
|
2018-06-09 16:50:05 +02:00
|
|
|
(gflow->tot_columns - step) > 0 &&
|
2023-01-03 11:04:16 +11:00
|
|
|
int(ceilf(float(gflow->tot_items) / (gflow->tot_columns - step))) <= gflow->tot_rows;
|
2019-03-26 21:16:13 +11:00
|
|
|
gflow->tot_columns -= step)
|
|
|
|
|
{
|
|
|
|
|
/* pass */
|
|
|
|
|
}
|
2018-06-09 16:50:05 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2018-09-27 15:49:59 +02:00
|
|
|
/* Adjust number of rows to be multiple of given modulo. */
|
2018-06-09 16:50:05 +02:00
|
|
|
if (modulo && gflow->tot_rows % modulo != 0) {
|
|
|
|
|
gflow->tot_rows = min_ii(gflow->tot_rows + modulo - (gflow->tot_rows % modulo),
|
|
|
|
|
gflow->tot_items);
|
|
|
|
|
}
|
|
|
|
|
/* Find smallest number of rows conserving computed optimal number of columns. */
|
2023-01-03 11:04:16 +11:00
|
|
|
for (gflow->tot_columns = int(ceilf(float(gflow->tot_items) / gflow->tot_rows));
|
2018-06-09 16:50:05 +02:00
|
|
|
(gflow->tot_rows - step) > 0 &&
|
2023-01-03 11:04:16 +11:00
|
|
|
int(ceilf(float(gflow->tot_items) / (gflow->tot_rows - step))) <= gflow->tot_columns;
|
2019-03-26 21:16:13 +11:00
|
|
|
gflow->tot_rows -= step)
|
|
|
|
|
{
|
|
|
|
|
/* pass */
|
|
|
|
|
}
|
2018-06-09 16:50:05 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-01-15 23:24:20 +11:00
|
|
|
/* Set evenly-spaced axes size
|
|
|
|
|
* (quick optimization in case we have even columns and rows). */
|
2018-06-09 16:50:05 +02:00
|
|
|
if (gflow->even_columns && gflow->even_rows) {
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->w_ = int(gflow->tot_columns * avg_w) + space_x * (gflow->tot_columns - 1);
|
|
|
|
|
litem->h_ = int(gflow->tot_rows * max_h) + space_y * (gflow->tot_rows - 1);
|
2018-06-09 16:50:05 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-09 16:50:05 +02:00
|
|
|
/* Now that we have our final number of columns and rows,
|
|
|
|
|
* we can compute actual needed space for non-evenly sized axes. */
|
|
|
|
|
{
|
|
|
|
|
int tot_w, tot_h;
|
2022-11-25 23:48:02 -06:00
|
|
|
UILayoutGridFlowInput input{};
|
|
|
|
|
input.row_major = gflow->row_major;
|
|
|
|
|
input.even_columns = gflow->even_columns;
|
|
|
|
|
input.even_rows = gflow->even_rows;
|
2025-04-23 16:37:14 +02:00
|
|
|
input.litem_w = litem->w_;
|
|
|
|
|
input.litem_x = litem->x_;
|
|
|
|
|
input.litem_y = litem->y_;
|
2022-11-25 23:48:02 -06:00
|
|
|
input.space_x = space_x;
|
|
|
|
|
input.space_y = space_y;
|
|
|
|
|
input.tot_columns = gflow->tot_columns;
|
|
|
|
|
input.tot_rows = gflow->tot_rows;
|
|
|
|
|
UILayoutGridFlowOutput output{};
|
|
|
|
|
output.tot_w = &tot_w;
|
|
|
|
|
output.tot_h = &tot_h;
|
2025-04-23 16:37:14 +02:00
|
|
|
ui_litem_grid_flow_compute(litem->items_, &input, &output);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->w_ = tot_w;
|
|
|
|
|
litem->h_ = tot_h;
|
2018-06-09 16:50:05 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ui_litem_layout_grid_flow(uiLayout *litem)
|
|
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
const uiStyle *style = litem->root_->style;
|
2024-07-10 14:46:06 +02:00
|
|
|
uiLayoutItemGridFlow *gflow = static_cast<uiLayoutItemGridFlow *>(litem);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-09 16:50:05 +02:00
|
|
|
if (gflow->tot_items == 0) {
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->w_ = litem->h_ = 0;
|
2018-06-09 16:50:05 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-09 16:50:05 +02:00
|
|
|
BLI_assert(gflow->tot_columns > 0);
|
|
|
|
|
BLI_assert(gflow->tot_rows > 0);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-09 16:50:05 +02:00
|
|
|
const int space_x = style->columnspace;
|
|
|
|
|
const int space_y = style->buttonspacey;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-11-25 23:48:02 -06:00
|
|
|
blender::Array<int, 64> widths(gflow->tot_columns);
|
|
|
|
|
blender::Array<int, 64> heights(gflow->tot_rows);
|
|
|
|
|
blender::Array<int, 64> cos_x(gflow->tot_columns);
|
|
|
|
|
blender::Array<int, 64> cos_y(gflow->tot_rows);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-09 16:50:05 +02:00
|
|
|
/* This time we directly compute coordinates and sizes of all cells. */
|
2022-11-25 23:48:02 -06:00
|
|
|
UILayoutGridFlowInput input{};
|
|
|
|
|
input.row_major = gflow->row_major;
|
|
|
|
|
input.even_columns = gflow->even_columns;
|
|
|
|
|
input.even_rows = gflow->even_rows;
|
2025-04-23 16:37:14 +02:00
|
|
|
input.litem_w = litem->w_;
|
|
|
|
|
input.litem_x = litem->x_;
|
|
|
|
|
input.litem_y = litem->y_;
|
2022-11-25 23:48:02 -06:00
|
|
|
input.space_x = space_x;
|
|
|
|
|
input.space_y = space_y;
|
|
|
|
|
input.tot_columns = gflow->tot_columns;
|
|
|
|
|
input.tot_rows = gflow->tot_rows;
|
|
|
|
|
UILayoutGridFlowOutput output{};
|
|
|
|
|
output.cos_x_array = cos_x.data();
|
|
|
|
|
output.cos_y_array = cos_y.data();
|
|
|
|
|
output.widths_array = widths.data();
|
|
|
|
|
output.heights_array = heights.data();
|
2025-04-23 16:37:14 +02:00
|
|
|
ui_litem_grid_flow_compute(litem->items_, &input, &output);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-07-10 14:46:06 +02:00
|
|
|
int i = 0;
|
2025-04-23 16:37:14 +02:00
|
|
|
for (uiItem *item : litem->items_) {
|
2018-06-09 16:50:05 +02:00
|
|
|
const int col = gflow->row_major ? i % gflow->tot_columns : i / gflow->tot_rows;
|
|
|
|
|
const int row = gflow->row_major ? i / gflow->tot_columns : i % gflow->tot_rows;
|
|
|
|
|
int item_w, item_h;
|
|
|
|
|
ui_item_size(item, &item_w, &item_h);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-09 16:50:05 +02:00
|
|
|
const int w = widths[col];
|
|
|
|
|
const int h = heights[row];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-23 14:54:06 +02:00
|
|
|
item_w = (litem->alignment_ == UI_LAYOUT_ALIGN_EXPAND) ? w : min_ii(w, item_w);
|
|
|
|
|
item_h = (litem->alignment_ == UI_LAYOUT_ALIGN_EXPAND) ? h : min_ii(h, item_h);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-09 16:50:05 +02:00
|
|
|
ui_item_position(item, cos_x[col], cos_y[row], item_w, item_h);
|
2024-07-10 14:46:06 +02:00
|
|
|
i++;
|
2018-06-09 16:50:05 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->h_ = litem->y_ - cos_y[gflow->tot_rows - 1];
|
|
|
|
|
litem->x_ = (cos_x[gflow->tot_columns - 1] - litem->x_) + widths[gflow->tot_columns - 1];
|
|
|
|
|
litem->y_ = litem->y_ - litem->h_;
|
2018-06-09 16:50:05 +02:00
|
|
|
}
|
|
|
|
|
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
/* free layout */
|
2009-10-09 10:45:11 +00:00
|
|
|
static void ui_litem_estimate_absolute(uiLayout *litem)
|
2009-03-13 13:38:41 +00:00
|
|
|
{
|
2020-12-18 12:39:50 -06:00
|
|
|
int minx = 1e6;
|
|
|
|
|
int miny = 1e6;
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->w_ = 0;
|
|
|
|
|
litem->h_ = 0;
|
2009-03-13 13:38:41 +00:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
for (uiItem *item : litem->items_) {
|
2020-12-18 12:39:50 -06:00
|
|
|
int itemx, itemy, itemw, itemh;
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
ui_item_offset(item, &itemx, &itemy);
|
|
|
|
|
ui_item_size(item, &itemw, &itemh);
|
2009-04-16 12:17:58 +00:00
|
|
|
|
2012-10-24 05:06:40 +00:00
|
|
|
minx = min_ii(minx, itemx);
|
|
|
|
|
miny = min_ii(miny, itemy);
|
2009-04-16 12:17:58 +00:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->w_ = std::max(litem->w_, itemx + itemw);
|
|
|
|
|
litem->h_ = std::max(litem->h_, itemy + itemh);
|
2009-04-16 12:17:58 +00:00
|
|
|
}
|
|
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->w_ -= minx;
|
|
|
|
|
litem->h_ -= miny;
|
2009-04-16 12:17:58 +00:00
|
|
|
}
|
|
|
|
|
|
2009-10-09 10:45:11 +00:00
|
|
|
static void ui_litem_layout_absolute(uiLayout *litem)
|
2009-04-16 12:17:58 +00:00
|
|
|
{
|
2012-03-30 01:51:25 +00:00
|
|
|
float scalex = 1.0f, scaley = 1.0f;
|
2020-12-18 12:39:50 -06:00
|
|
|
int x, y, newx, newy, itemx, itemy, itemh, itemw;
|
2009-04-16 12:17:58 +00:00
|
|
|
|
2020-12-18 12:39:50 -06:00
|
|
|
int minx = 1e6;
|
|
|
|
|
int miny = 1e6;
|
|
|
|
|
int totw = 0;
|
|
|
|
|
int toth = 0;
|
2009-03-13 13:38:41 +00:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
for (uiItem *item : litem->items_) {
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
ui_item_offset(item, &itemx, &itemy);
|
|
|
|
|
ui_item_size(item, &itemw, &itemh);
|
2009-04-16 12:17:58 +00:00
|
|
|
|
2012-10-24 05:06:40 +00:00
|
|
|
minx = min_ii(minx, itemx);
|
|
|
|
|
miny = min_ii(miny, itemy);
|
2009-03-13 13:38:41 +00:00
|
|
|
|
2012-10-24 05:06:40 +00:00
|
|
|
totw = max_ii(totw, itemx + itemw);
|
|
|
|
|
toth = max_ii(toth, itemy + itemh);
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
}
|
2009-03-13 13:38:41 +00:00
|
|
|
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
totw -= minx;
|
|
|
|
|
toth -= miny;
|
2009-03-13 13:38:41 +00:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
if (litem->w_ && totw > 0) {
|
|
|
|
|
scalex = float(litem->w_) / float(totw);
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2025-04-23 16:37:14 +02:00
|
|
|
if (litem->h_ && toth > 0) {
|
|
|
|
|
scaley = float(litem->h_) / float(toth);
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2018-05-23 10:47:12 +02:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
x = litem->x_;
|
|
|
|
|
y = litem->y_ - scaley * toth;
|
2009-03-13 13:38:41 +00:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
for (uiItem *item : litem->items_) {
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
ui_item_offset(item, &itemx, &itemy);
|
|
|
|
|
ui_item_size(item, &itemw, &itemh);
|
2009-03-13 13:38:41 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (scalex != 1.0f) {
|
2012-03-30 01:51:25 +00:00
|
|
|
newx = (itemx - minx) * scalex;
|
|
|
|
|
itemw = (itemx - minx + itemw) * scalex - newx;
|
|
|
|
|
itemx = minx + newx;
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
}
|
2009-03-13 13:38:41 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (scaley != 1.0f) {
|
2012-03-30 01:51:25 +00:00
|
|
|
newy = (itemy - miny) * scaley;
|
|
|
|
|
itemh = (itemy - miny + itemh) * scaley - newy;
|
|
|
|
|
itemy = miny + newy;
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
}
|
2009-03-13 13:38:41 +00:00
|
|
|
|
2012-03-30 01:51:25 +00:00
|
|
|
ui_item_position(item, x + itemx - minx, y + itemy - miny, itemw, itemh);
|
2009-03-13 13:38:41 +00:00
|
|
|
}
|
|
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->w_ = scalex * totw;
|
|
|
|
|
litem->h_ = litem->y_ - y;
|
|
|
|
|
litem->x_ = x + litem->w_;
|
|
|
|
|
litem->y_ = y;
|
2009-03-13 13:38:41 +00:00
|
|
|
}
|
|
|
|
|
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
/* split layout */
|
|
|
|
|
static void ui_litem_estimate_split(uiLayout *litem)
|
2009-04-22 18:39:44 +00:00
|
|
|
{
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
ui_litem_estimate_row(litem);
|
2025-04-24 17:22:28 +02:00
|
|
|
litem->flag_ &= ~uiItemInternalFlag::FixedSize;
|
2009-04-22 18:39:44 +00:00
|
|
|
}
|
|
|
|
|
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
static void ui_litem_layout_split(uiLayout *litem)
|
2009-03-13 13:38:41 +00:00
|
|
|
{
|
2024-07-10 14:46:06 +02:00
|
|
|
uiLayoutItemSplit *split = static_cast<uiLayoutItemSplit *>(litem);
|
2020-12-18 12:39:50 -06:00
|
|
|
float extra_pixel = 0.0f;
|
2025-04-23 16:37:14 +02:00
|
|
|
const int tot = int(litem->items_.size());
|
2011-03-19 05:06:06 +00:00
|
|
|
|
2019-03-25 10:15:20 +11:00
|
|
|
if (tot == 0) {
|
2011-03-19 05:06:06 +00:00
|
|
|
return;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2009-03-13 13:38:41 +00:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
int x = litem->x_;
|
|
|
|
|
const int y = litem->y_;
|
2009-03-13 13:38:41 +00:00
|
|
|
|
2022-12-08 13:04:50 +11:00
|
|
|
const float percentage = (split->percentage == 0.0f) ? 1.0f / float(tot) : split->percentage;
|
2018-05-23 10:47:12 +02:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
const int w = (litem->w_ - (tot - 1) * litem->space_);
|
2020-12-18 12:39:50 -06:00
|
|
|
int colw = w * percentage;
|
2023-11-07 16:33:19 +11:00
|
|
|
colw = std::max(colw, 0);
|
2009-04-22 18:39:44 +00:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
const uiItem *item_last = litem->items_.last();
|
|
|
|
|
for (uiItem *item : litem->items_) {
|
2024-07-10 14:46:06 +02:00
|
|
|
const bool is_item_last = (item == item_last);
|
2020-12-18 12:39:50 -06:00
|
|
|
int itemh;
|
2022-11-25 23:48:02 -06:00
|
|
|
ui_item_size(item, nullptr, &itemh);
|
2009-04-22 18:39:44 +00:00
|
|
|
|
2012-03-30 01:51:25 +00:00
|
|
|
ui_item_position(item, x, y - itemh, colw, itemh);
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
x += colw;
|
2009-04-22 18:39:44 +00:00
|
|
|
|
2024-07-10 14:46:06 +02:00
|
|
|
if (!is_item_last) {
|
2023-01-03 11:04:16 +11:00
|
|
|
const float width = extra_pixel + (w - int(w * percentage)) / (float(tot) - 1);
|
2022-12-08 13:04:50 +11:00
|
|
|
extra_pixel = width - int(width);
|
|
|
|
|
colw = int(width);
|
2023-11-07 16:33:19 +11:00
|
|
|
colw = std::max(colw, 0);
|
2009-06-07 13:20:41 +00:00
|
|
|
|
2025-04-23 14:54:06 +02:00
|
|
|
x += litem->space_;
|
2009-06-07 13:20:41 +00:00
|
|
|
}
|
2009-04-22 18:39:44 +00:00
|
|
|
}
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->w_ = x - litem->x_;
|
|
|
|
|
litem->h_ = litem->y_ - y;
|
|
|
|
|
litem->x_ = x;
|
|
|
|
|
litem->y_ = y;
|
2009-03-13 13:38:41 +00:00
|
|
|
}
|
|
|
|
|
|
2009-10-21 20:58:10 +00:00
|
|
|
/* overlap layout */
|
|
|
|
|
static void ui_litem_estimate_overlap(uiLayout *litem)
|
|
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->w_ = 0;
|
|
|
|
|
litem->h_ = 0;
|
2009-10-21 20:58:10 +00:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
for (uiItem *item : litem->items_) {
|
2020-12-18 12:39:50 -06:00
|
|
|
int itemw, itemh;
|
2009-10-21 20:58:10 +00:00
|
|
|
ui_item_size(item, &itemw, &itemh);
|
|
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->w_ = std::max(itemw, litem->w_);
|
|
|
|
|
litem->h_ = std::max(itemh, litem->h_);
|
2009-10-21 20:58:10 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ui_litem_layout_overlap(uiLayout *litem)
|
|
|
|
|
{
|
|
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
const int x = litem->x_;
|
|
|
|
|
const int y = litem->y_;
|
2009-10-21 20:58:10 +00:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
for (uiItem *item : litem->items_) {
|
2020-12-18 12:39:50 -06:00
|
|
|
int itemw, itemh;
|
2009-10-21 20:58:10 +00:00
|
|
|
ui_item_size(item, &itemw, &itemh);
|
2025-04-23 16:37:14 +02:00
|
|
|
ui_item_position(item, x, y - itemh, litem->w_, itemh);
|
2009-10-21 20:58:10 +00:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->h_ = std::max(litem->h_, itemh);
|
2009-10-21 20:58:10 +00:00
|
|
|
}
|
|
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->x_ = x;
|
|
|
|
|
litem->y_ = y - litem->h_;
|
2009-10-21 20:58:10 +00:00
|
|
|
}
|
|
|
|
|
|
2018-05-13 12:28:35 +02:00
|
|
|
static void ui_litem_init_from_parent(uiLayout *litem, uiLayout *layout, int align)
|
2009-03-13 13:38:41 +00:00
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->root_ = layout->root_;
|
2025-04-23 14:54:06 +02:00
|
|
|
litem->align_ = align;
|
2021-07-05 12:47:46 +10:00
|
|
|
/* Children of grid-flow layout shall never have "ideal big size" returned as estimated size. */
|
2025-04-24 17:22:28 +02:00
|
|
|
litem->variable_size_ = layout->variable_size_ || layout->type_ == uiItemType::LayoutGridFlow;
|
2025-04-23 14:54:06 +02:00
|
|
|
litem->active_ = true;
|
|
|
|
|
litem->enabled_ = true;
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->context_ = layout->context_;
|
2025-04-23 14:54:06 +02:00
|
|
|
litem->redalert_ = layout->redalert_;
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->w_ = layout->w_;
|
2025-04-23 14:54:06 +02:00
|
|
|
litem->emboss_ = layout->emboss_;
|
2025-04-24 17:22:28 +02:00
|
|
|
litem->flag_ = (layout->flag_ & (uiItemInternalFlag::PropSep | uiItemInternalFlag::PropDecorate |
|
|
|
|
|
uiItemInternalFlag::InsidePropSep));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
if (layout->child_items_layout_) {
|
|
|
|
|
layout->child_items_layout_->items_.append(litem);
|
|
|
|
|
litem->parent_ = layout->child_items_layout_;
|
2018-10-25 15:27:31 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2025-04-23 16:37:14 +02:00
|
|
|
layout->items_.append(litem);
|
|
|
|
|
litem->parent_ = layout;
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-06 14:08:10 +01:00
|
|
|
static void ui_layout_heading_set(uiLayout *layout, const StringRef heading)
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
heading.copy_utf8_truncated(layout->heading_);
|
2018-05-13 12:28:35 +02:00
|
|
|
}
|
|
|
|
|
|
2025-04-25 19:45:25 +02:00
|
|
|
uiLayout &uiLayout::row(bool align)
|
2018-05-13 12:28:35 +02:00
|
|
|
{
|
2024-07-10 14:46:06 +02:00
|
|
|
uiLayout *litem = MEM_new<uiLayout>(__func__);
|
2025-04-25 19:45:25 +02:00
|
|
|
ui_litem_init_from_parent(litem, this, align);
|
2018-05-13 12:28:35 +02:00
|
|
|
|
2025-04-24 17:22:28 +02:00
|
|
|
litem->type_ = uiItemType::LayoutRow;
|
2025-05-07 22:51:26 +02:00
|
|
|
litem->space_ = (align) ? 0 : root_->style->buttonspacex;
|
2009-03-13 13:38:41 +00:00
|
|
|
|
2025-05-07 22:51:26 +02:00
|
|
|
UI_block_layout_set_current(root_->block, litem);
|
2009-05-19 17:13:33 +00:00
|
|
|
|
2025-04-25 19:45:25 +02:00
|
|
|
return *litem;
|
2009-03-13 13:38:41 +00:00
|
|
|
}
|
|
|
|
|
|
2025-05-06 17:13:30 +02:00
|
|
|
PanelLayout uiLayout::panel_prop(const bContext *C,
|
|
|
|
|
PointerRNA *open_prop_owner,
|
|
|
|
|
const StringRefNull open_prop_name)
|
UI: add support for uiLayout based panels
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 initial use case for this are panels in the geometry nodes modifier. This patch provides
a better solution compared to what was attempted in #108565.
### Problems with Existing Approaches
Currently, there are two ways to create these expandable sections:
* One can define a new `Panel` type for each expandable section and use the `parent_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.
* It does not work so well for dynamic amounts of panels (e.g. like what we need for
the geometry nodes modifier to organize the inputs).
* Typically, Blender uses a immediate-ui approach, but subpanels break that currently
and need extra handling.
* The order of panels is not very explicit.
* One can't interleave subpanels and other ui elements, subpanels always come at the
end of the parent panel.
* Custom solution using existing `uiLayout`. This is done in the material properties. It
also has a few problems:
* Custom solutions tend to work slightly different in different places. So the UI is less unified.
* Can't drag open/close multiple panels.
* The background color for subpanels does not change.
### Solution
A possible solution to all of these problems is to add support for panels to `uiLayout` directly:
```cpp
/* Add elements before subpanel. */
if (uiLayout *panel_layout = uiLayoutPanel(layout, ...)) {
/* Add elements in subpanel, but only of the panel is open. */
}
/* Add elements after subpanel. */
```
Integrating subpanels with `uiLayout` has some benefits:
* Subpanels are treated like any other sub-layout and don't have unnecessary boilerplate.
* It becomes trivial to have a dynamic number of potentially nested subpanels.
* Resolves all mentioned problems of custom subpanel solutions.
### 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 negligible. Therefor, a much simpler solution
is possible: the open/close state can be stored in the modifier directly. This is actually
how it was implemented before 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 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 (not included)
Adding a Python API is fairly straight forward. 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:
```python
if panel := layout.panel("Mesh Settings", ...):
# Add layout elements in the panel if it's open.
```
Pull Request: https://projects.blender.org/blender/blender/pulls/113584
2023-12-22 17:57:57 +01:00
|
|
|
{
|
|
|
|
|
const ARegion *region = CTX_wm_region(C);
|
|
|
|
|
|
2025-03-04 14:29:00 -05:00
|
|
|
const bool is_real_open = RNA_boolean_get(open_prop_owner, open_prop_name.c_str());
|
UI: add support for uiLayout based panels
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 initial use case for this are panels in the geometry nodes modifier. This patch provides
a better solution compared to what was attempted in #108565.
### Problems with Existing Approaches
Currently, there are two ways to create these expandable sections:
* One can define a new `Panel` type for each expandable section and use the `parent_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.
* It does not work so well for dynamic amounts of panels (e.g. like what we need for
the geometry nodes modifier to organize the inputs).
* Typically, Blender uses a immediate-ui approach, but subpanels break that currently
and need extra handling.
* The order of panels is not very explicit.
* One can't interleave subpanels and other ui elements, subpanels always come at the
end of the parent panel.
* Custom solution using existing `uiLayout`. This is done in the material properties. It
also has a few problems:
* Custom solutions tend to work slightly different in different places. So the UI is less unified.
* Can't drag open/close multiple panels.
* The background color for subpanels does not change.
### Solution
A possible solution to all of these problems is to add support for panels to `uiLayout` directly:
```cpp
/* Add elements before subpanel. */
if (uiLayout *panel_layout = uiLayoutPanel(layout, ...)) {
/* Add elements in subpanel, but only of the panel is open. */
}
/* Add elements after subpanel. */
```
Integrating subpanels with `uiLayout` has some benefits:
* Subpanels are treated like any other sub-layout and don't have unnecessary boilerplate.
* It becomes trivial to have a dynamic number of potentially nested subpanels.
* Resolves all mentioned problems of custom subpanel solutions.
### 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 negligible. Therefor, a much simpler solution
is possible: the open/close state can be stored in the modifier directly. This is actually
how it was implemented before 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 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 (not included)
Adding a Python API is fairly straight forward. 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:
```python
if panel := layout.panel("Mesh Settings", ...):
# Add layout elements in the panel if it's open.
```
Pull Request: https://projects.blender.org/blender/blender/pulls/113584
2023-12-22 17:57:57 +01:00
|
|
|
const bool search_filter_active = region->flag & RGN_FLAG_SEARCH_FILTER_ACTIVE;
|
|
|
|
|
const bool is_open = is_real_open || search_filter_active;
|
|
|
|
|
|
UI: Add ability to configure the header row of layout panels
There are many instances where customizing the header row is desired so
return both the header row layout and the main body layout.
For consistency and correctness, the arrow symbol and the is_open check
are always performed so callers only need to perform layout tasks.
The C++ side now receives a `PanelLayout` structure containing both:
```cpp
PanelLayout panel_layout = uiLayoutPanelWithHeader( ... );
uiItemL(panel_layout.header, ... );
if (panel_layout.body) {
...
}
```
And the Python side receives a tuple:
```python
header, body = layout.panel( ... )
header.label(...)
if body:
...
```
```python
import bpy
from bpy.props import BoolProperty
class LayoutDemoPanel(bpy.types.Panel):
bl_label = "Layout Panel Demo"
bl_idname = "SCENE_PT_layout_panel"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "scene"
def draw(self, context):
layout = self.layout
scene = context.scene
layout.label(text="Basic Panels")
header, panel = layout.panel("my_panel_id", default_closed=True)
header.label(text="Hello World")
if panel:
panel.label(text="Success")
header, panel = layout.panel_prop(scene, "show_demo_panel")
header.label(text="My Panel")
if panel:
panel.prop(scene, "frame_start")
panel.prop(scene, "frame_end")
layout.label(text="Customized headers")
# Add a checkbox to the Panel header. text must be None for this panel
header, panel = layout.panel("my_panel_id-2", default_closed=True)
header.prop(scene, "use_checkmark", text="") # text must be empty for the checkbox
header.label(text="Checkmark at beginning")
if panel:
panel.label(text="Success")
header, panel = layout.panel("my_panel_id-3", default_closed=True)
header.label(text="Buttons at the end")
header.operator("mesh.primitive_cube_add", text="", icon='EXPORT')
header.operator("mesh.primitive_cube_add", text="", icon='X')
if panel:
panel.label(text="Success")
header, panel = layout.panel("my_panel_id-4", default_closed=True)
header.prop(scene, "use_checkmark2", text="")
header.label(text="Both")
header.operator("mesh.primitive_cube_add", text="", icon='EXPORT')
header.operator("mesh.primitive_cube_add", text="", icon='X')
if panel:
panel.label(text="Success")
bpy.utils.register_class(LayoutDemoPanel)
bpy.types.Scene.show_demo_panel = BoolProperty(default=False)
bpy.types.Scene.use_checkmark = BoolProperty(default=False)
bpy.types.Scene.use_checkmark2 = BoolProperty(default=False)
```
Pull Request: https://projects.blender.org/blender/blender/pulls/117248
2024-01-26 10:11:22 +01:00
|
|
|
PanelLayout panel_layout{};
|
UI: add support for uiLayout based panels
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 initial use case for this are panels in the geometry nodes modifier. This patch provides
a better solution compared to what was attempted in #108565.
### Problems with Existing Approaches
Currently, there are two ways to create these expandable sections:
* One can define a new `Panel` type for each expandable section and use the `parent_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.
* It does not work so well for dynamic amounts of panels (e.g. like what we need for
the geometry nodes modifier to organize the inputs).
* Typically, Blender uses a immediate-ui approach, but subpanels break that currently
and need extra handling.
* The order of panels is not very explicit.
* One can't interleave subpanels and other ui elements, subpanels always come at the
end of the parent panel.
* Custom solution using existing `uiLayout`. This is done in the material properties. It
also has a few problems:
* Custom solutions tend to work slightly different in different places. So the UI is less unified.
* Can't drag open/close multiple panels.
* The background color for subpanels does not change.
### Solution
A possible solution to all of these problems is to add support for panels to `uiLayout` directly:
```cpp
/* Add elements before subpanel. */
if (uiLayout *panel_layout = uiLayoutPanel(layout, ...)) {
/* Add elements in subpanel, but only of the panel is open. */
}
/* Add elements after subpanel. */
```
Integrating subpanels with `uiLayout` has some benefits:
* Subpanels are treated like any other sub-layout and don't have unnecessary boilerplate.
* It becomes trivial to have a dynamic number of potentially nested subpanels.
* Resolves all mentioned problems of custom subpanel solutions.
### 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 negligible. Therefor, a much simpler solution
is possible: the open/close state can be stored in the modifier directly. This is actually
how it was implemented before 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 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 (not included)
Adding a Python API is fairly straight forward. 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:
```python
if panel := layout.panel("Mesh Settings", ...):
# Add layout elements in the panel if it's open.
```
Pull Request: https://projects.blender.org/blender/blender/pulls/113584
2023-12-22 17:57:57 +01:00
|
|
|
{
|
2024-07-10 14:46:06 +02:00
|
|
|
uiLayoutItemPanelHeader *header_litem = MEM_new<uiLayoutItemPanelHeader>(__func__);
|
2025-05-06 17:13:30 +02:00
|
|
|
ui_litem_init_from_parent(header_litem, this, false);
|
2025-04-24 17:22:28 +02:00
|
|
|
header_litem->type_ = uiItemType::LayoutPanelHeader;
|
UI: add support for uiLayout based panels
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 initial use case for this are panels in the geometry nodes modifier. This patch provides
a better solution compared to what was attempted in #108565.
### Problems with Existing Approaches
Currently, there are two ways to create these expandable sections:
* One can define a new `Panel` type for each expandable section and use the `parent_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.
* It does not work so well for dynamic amounts of panels (e.g. like what we need for
the geometry nodes modifier to organize the inputs).
* Typically, Blender uses a immediate-ui approach, but subpanels break that currently
and need extra handling.
* The order of panels is not very explicit.
* One can't interleave subpanels and other ui elements, subpanels always come at the
end of the parent panel.
* Custom solution using existing `uiLayout`. This is done in the material properties. It
also has a few problems:
* Custom solutions tend to work slightly different in different places. So the UI is less unified.
* Can't drag open/close multiple panels.
* The background color for subpanels does not change.
### Solution
A possible solution to all of these problems is to add support for panels to `uiLayout` directly:
```cpp
/* Add elements before subpanel. */
if (uiLayout *panel_layout = uiLayoutPanel(layout, ...)) {
/* Add elements in subpanel, but only of the panel is open. */
}
/* Add elements after subpanel. */
```
Integrating subpanels with `uiLayout` has some benefits:
* Subpanels are treated like any other sub-layout and don't have unnecessary boilerplate.
* It becomes trivial to have a dynamic number of potentially nested subpanels.
* Resolves all mentioned problems of custom subpanel solutions.
### 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 negligible. Therefor, a much simpler solution
is possible: the open/close state can be stored in the modifier directly. This is actually
how it was implemented before 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 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 (not included)
Adding a Python API is fairly straight forward. 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:
```python
if panel := layout.panel("Mesh Settings", ...):
# Add layout elements in the panel if it's open.
```
Pull Request: https://projects.blender.org/blender/blender/pulls/113584
2023-12-22 17:57:57 +01:00
|
|
|
|
|
|
|
|
header_litem->open_prop_owner = *open_prop_owner;
|
2025-03-04 14:29:00 -05:00
|
|
|
STRNCPY(header_litem->open_prop_name, open_prop_name.c_str());
|
UI: add support for uiLayout based panels
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 initial use case for this are panels in the geometry nodes modifier. This patch provides
a better solution compared to what was attempted in #108565.
### Problems with Existing Approaches
Currently, there are two ways to create these expandable sections:
* One can define a new `Panel` type for each expandable section and use the `parent_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.
* It does not work so well for dynamic amounts of panels (e.g. like what we need for
the geometry nodes modifier to organize the inputs).
* Typically, Blender uses a immediate-ui approach, but subpanels break that currently
and need extra handling.
* The order of panels is not very explicit.
* One can't interleave subpanels and other ui elements, subpanels always come at the
end of the parent panel.
* Custom solution using existing `uiLayout`. This is done in the material properties. It
also has a few problems:
* Custom solutions tend to work slightly different in different places. So the UI is less unified.
* Can't drag open/close multiple panels.
* The background color for subpanels does not change.
### Solution
A possible solution to all of these problems is to add support for panels to `uiLayout` directly:
```cpp
/* Add elements before subpanel. */
if (uiLayout *panel_layout = uiLayoutPanel(layout, ...)) {
/* Add elements in subpanel, but only of the panel is open. */
}
/* Add elements after subpanel. */
```
Integrating subpanels with `uiLayout` has some benefits:
* Subpanels are treated like any other sub-layout and don't have unnecessary boilerplate.
* It becomes trivial to have a dynamic number of potentially nested subpanels.
* Resolves all mentioned problems of custom subpanel solutions.
### 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 negligible. Therefor, a much simpler solution
is possible: the open/close state can be stored in the modifier directly. This is actually
how it was implemented before 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 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 (not included)
Adding a Python API is fairly straight forward. 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:
```python
if panel := layout.panel("Mesh Settings", ...):
# Add layout elements in the panel if it's open.
```
Pull Request: https://projects.blender.org/blender/blender/pulls/113584
2023-12-22 17:57:57 +01:00
|
|
|
|
2025-04-25 19:45:25 +02:00
|
|
|
uiLayout *row = &header_litem->row(true);
|
UI: Add ability to configure the header row of layout panels
There are many instances where customizing the header row is desired so
return both the header row layout and the main body layout.
For consistency and correctness, the arrow symbol and the is_open check
are always performed so callers only need to perform layout tasks.
The C++ side now receives a `PanelLayout` structure containing both:
```cpp
PanelLayout panel_layout = uiLayoutPanelWithHeader( ... );
uiItemL(panel_layout.header, ... );
if (panel_layout.body) {
...
}
```
And the Python side receives a tuple:
```python
header, body = layout.panel( ... )
header.label(...)
if body:
...
```
```python
import bpy
from bpy.props import BoolProperty
class LayoutDemoPanel(bpy.types.Panel):
bl_label = "Layout Panel Demo"
bl_idname = "SCENE_PT_layout_panel"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "scene"
def draw(self, context):
layout = self.layout
scene = context.scene
layout.label(text="Basic Panels")
header, panel = layout.panel("my_panel_id", default_closed=True)
header.label(text="Hello World")
if panel:
panel.label(text="Success")
header, panel = layout.panel_prop(scene, "show_demo_panel")
header.label(text="My Panel")
if panel:
panel.prop(scene, "frame_start")
panel.prop(scene, "frame_end")
layout.label(text="Customized headers")
# Add a checkbox to the Panel header. text must be None for this panel
header, panel = layout.panel("my_panel_id-2", default_closed=True)
header.prop(scene, "use_checkmark", text="") # text must be empty for the checkbox
header.label(text="Checkmark at beginning")
if panel:
panel.label(text="Success")
header, panel = layout.panel("my_panel_id-3", default_closed=True)
header.label(text="Buttons at the end")
header.operator("mesh.primitive_cube_add", text="", icon='EXPORT')
header.operator("mesh.primitive_cube_add", text="", icon='X')
if panel:
panel.label(text="Success")
header, panel = layout.panel("my_panel_id-4", default_closed=True)
header.prop(scene, "use_checkmark2", text="")
header.label(text="Both")
header.operator("mesh.primitive_cube_add", text="", icon='EXPORT')
header.operator("mesh.primitive_cube_add", text="", icon='X')
if panel:
panel.label(text="Success")
bpy.utils.register_class(LayoutDemoPanel)
bpy.types.Scene.show_demo_panel = BoolProperty(default=False)
bpy.types.Scene.use_checkmark = BoolProperty(default=False)
bpy.types.Scene.use_checkmark2 = BoolProperty(default=False)
```
Pull Request: https://projects.blender.org/blender/blender/pulls/117248
2024-01-26 10:11:22 +01:00
|
|
|
uiLayoutSetUnitsY(row, 1.2f);
|
UI: add support for uiLayout based panels
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 initial use case for this are panels in the geometry nodes modifier. This patch provides
a better solution compared to what was attempted in #108565.
### Problems with Existing Approaches
Currently, there are two ways to create these expandable sections:
* One can define a new `Panel` type for each expandable section and use the `parent_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.
* It does not work so well for dynamic amounts of panels (e.g. like what we need for
the geometry nodes modifier to organize the inputs).
* Typically, Blender uses a immediate-ui approach, but subpanels break that currently
and need extra handling.
* The order of panels is not very explicit.
* One can't interleave subpanels and other ui elements, subpanels always come at the
end of the parent panel.
* Custom solution using existing `uiLayout`. This is done in the material properties. It
also has a few problems:
* Custom solutions tend to work slightly different in different places. So the UI is less unified.
* Can't drag open/close multiple panels.
* The background color for subpanels does not change.
### Solution
A possible solution to all of these problems is to add support for panels to `uiLayout` directly:
```cpp
/* Add elements before subpanel. */
if (uiLayout *panel_layout = uiLayoutPanel(layout, ...)) {
/* Add elements in subpanel, but only of the panel is open. */
}
/* Add elements after subpanel. */
```
Integrating subpanels with `uiLayout` has some benefits:
* Subpanels are treated like any other sub-layout and don't have unnecessary boilerplate.
* It becomes trivial to have a dynamic number of potentially nested subpanels.
* Resolves all mentioned problems of custom subpanel solutions.
### 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 negligible. Therefor, a much simpler solution
is possible: the open/close state can be stored in the modifier directly. This is actually
how it was implemented before 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 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 (not included)
Adding a Python API is fairly straight forward. 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:
```python
if panel := layout.panel("Mesh Settings", ...):
# Add layout elements in the panel if it's open.
```
Pull Request: https://projects.blender.org/blender/blender/pulls/113584
2023-12-22 17:57:57 +01:00
|
|
|
|
UI: Add ability to configure the header row of layout panels
There are many instances where customizing the header row is desired so
return both the header row layout and the main body layout.
For consistency and correctness, the arrow symbol and the is_open check
are always performed so callers only need to perform layout tasks.
The C++ side now receives a `PanelLayout` structure containing both:
```cpp
PanelLayout panel_layout = uiLayoutPanelWithHeader( ... );
uiItemL(panel_layout.header, ... );
if (panel_layout.body) {
...
}
```
And the Python side receives a tuple:
```python
header, body = layout.panel( ... )
header.label(...)
if body:
...
```
```python
import bpy
from bpy.props import BoolProperty
class LayoutDemoPanel(bpy.types.Panel):
bl_label = "Layout Panel Demo"
bl_idname = "SCENE_PT_layout_panel"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "scene"
def draw(self, context):
layout = self.layout
scene = context.scene
layout.label(text="Basic Panels")
header, panel = layout.panel("my_panel_id", default_closed=True)
header.label(text="Hello World")
if panel:
panel.label(text="Success")
header, panel = layout.panel_prop(scene, "show_demo_panel")
header.label(text="My Panel")
if panel:
panel.prop(scene, "frame_start")
panel.prop(scene, "frame_end")
layout.label(text="Customized headers")
# Add a checkbox to the Panel header. text must be None for this panel
header, panel = layout.panel("my_panel_id-2", default_closed=True)
header.prop(scene, "use_checkmark", text="") # text must be empty for the checkbox
header.label(text="Checkmark at beginning")
if panel:
panel.label(text="Success")
header, panel = layout.panel("my_panel_id-3", default_closed=True)
header.label(text="Buttons at the end")
header.operator("mesh.primitive_cube_add", text="", icon='EXPORT')
header.operator("mesh.primitive_cube_add", text="", icon='X')
if panel:
panel.label(text="Success")
header, panel = layout.panel("my_panel_id-4", default_closed=True)
header.prop(scene, "use_checkmark2", text="")
header.label(text="Both")
header.operator("mesh.primitive_cube_add", text="", icon='EXPORT')
header.operator("mesh.primitive_cube_add", text="", icon='X')
if panel:
panel.label(text="Success")
bpy.utils.register_class(LayoutDemoPanel)
bpy.types.Scene.show_demo_panel = BoolProperty(default=False)
bpy.types.Scene.use_checkmark = BoolProperty(default=False)
bpy.types.Scene.use_checkmark2 = BoolProperty(default=False)
```
Pull Request: https://projects.blender.org/blender/blender/pulls/117248
2024-01-26 10:11:22 +01:00
|
|
|
uiBlock *block = uiLayoutGetBlock(row);
|
2023-12-22 22:14:06 +01:00
|
|
|
const int icon = is_open ? ICON_DOWNARROW_HLT : ICON_RIGHTARROW;
|
2025-05-06 17:13:30 +02:00
|
|
|
const int width = ui_text_icon_width(this, "", icon, false);
|
2024-03-01 14:26:45 -05:00
|
|
|
uiDefIconTextBut(
|
|
|
|
|
block, UI_BTYPE_LABEL, 0, icon, "", 0, 0, width, UI_UNIT_Y, nullptr, 0.0f, 0.0f, "");
|
UI: Add ability to configure the header row of layout panels
There are many instances where customizing the header row is desired so
return both the header row layout and the main body layout.
For consistency and correctness, the arrow symbol and the is_open check
are always performed so callers only need to perform layout tasks.
The C++ side now receives a `PanelLayout` structure containing both:
```cpp
PanelLayout panel_layout = uiLayoutPanelWithHeader( ... );
uiItemL(panel_layout.header, ... );
if (panel_layout.body) {
...
}
```
And the Python side receives a tuple:
```python
header, body = layout.panel( ... )
header.label(...)
if body:
...
```
```python
import bpy
from bpy.props import BoolProperty
class LayoutDemoPanel(bpy.types.Panel):
bl_label = "Layout Panel Demo"
bl_idname = "SCENE_PT_layout_panel"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "scene"
def draw(self, context):
layout = self.layout
scene = context.scene
layout.label(text="Basic Panels")
header, panel = layout.panel("my_panel_id", default_closed=True)
header.label(text="Hello World")
if panel:
panel.label(text="Success")
header, panel = layout.panel_prop(scene, "show_demo_panel")
header.label(text="My Panel")
if panel:
panel.prop(scene, "frame_start")
panel.prop(scene, "frame_end")
layout.label(text="Customized headers")
# Add a checkbox to the Panel header. text must be None for this panel
header, panel = layout.panel("my_panel_id-2", default_closed=True)
header.prop(scene, "use_checkmark", text="") # text must be empty for the checkbox
header.label(text="Checkmark at beginning")
if panel:
panel.label(text="Success")
header, panel = layout.panel("my_panel_id-3", default_closed=True)
header.label(text="Buttons at the end")
header.operator("mesh.primitive_cube_add", text="", icon='EXPORT')
header.operator("mesh.primitive_cube_add", text="", icon='X')
if panel:
panel.label(text="Success")
header, panel = layout.panel("my_panel_id-4", default_closed=True)
header.prop(scene, "use_checkmark2", text="")
header.label(text="Both")
header.operator("mesh.primitive_cube_add", text="", icon='EXPORT')
header.operator("mesh.primitive_cube_add", text="", icon='X')
if panel:
panel.label(text="Success")
bpy.utils.register_class(LayoutDemoPanel)
bpy.types.Scene.show_demo_panel = BoolProperty(default=False)
bpy.types.Scene.use_checkmark = BoolProperty(default=False)
bpy.types.Scene.use_checkmark2 = BoolProperty(default=False)
```
Pull Request: https://projects.blender.org/blender/blender/pulls/117248
2024-01-26 10:11:22 +01:00
|
|
|
|
|
|
|
|
panel_layout.header = row;
|
UI: add support for uiLayout based panels
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 initial use case for this are panels in the geometry nodes modifier. This patch provides
a better solution compared to what was attempted in #108565.
### Problems with Existing Approaches
Currently, there are two ways to create these expandable sections:
* One can define a new `Panel` type for each expandable section and use the `parent_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.
* It does not work so well for dynamic amounts of panels (e.g. like what we need for
the geometry nodes modifier to organize the inputs).
* Typically, Blender uses a immediate-ui approach, but subpanels break that currently
and need extra handling.
* The order of panels is not very explicit.
* One can't interleave subpanels and other ui elements, subpanels always come at the
end of the parent panel.
* Custom solution using existing `uiLayout`. This is done in the material properties. It
also has a few problems:
* Custom solutions tend to work slightly different in different places. So the UI is less unified.
* Can't drag open/close multiple panels.
* The background color for subpanels does not change.
### Solution
A possible solution to all of these problems is to add support for panels to `uiLayout` directly:
```cpp
/* Add elements before subpanel. */
if (uiLayout *panel_layout = uiLayoutPanel(layout, ...)) {
/* Add elements in subpanel, but only of the panel is open. */
}
/* Add elements after subpanel. */
```
Integrating subpanels with `uiLayout` has some benefits:
* Subpanels are treated like any other sub-layout and don't have unnecessary boilerplate.
* It becomes trivial to have a dynamic number of potentially nested subpanels.
* Resolves all mentioned problems of custom subpanel solutions.
### 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 negligible. Therefor, a much simpler solution
is possible: the open/close state can be stored in the modifier directly. This is actually
how it was implemented before 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 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 (not included)
Adding a Python API is fairly straight forward. 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:
```python
if panel := layout.panel("Mesh Settings", ...):
# Add layout elements in the panel if it's open.
```
Pull Request: https://projects.blender.org/blender/blender/pulls/113584
2023-12-22 17:57:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!is_open) {
|
UI: Add ability to configure the header row of layout panels
There are many instances where customizing the header row is desired so
return both the header row layout and the main body layout.
For consistency and correctness, the arrow symbol and the is_open check
are always performed so callers only need to perform layout tasks.
The C++ side now receives a `PanelLayout` structure containing both:
```cpp
PanelLayout panel_layout = uiLayoutPanelWithHeader( ... );
uiItemL(panel_layout.header, ... );
if (panel_layout.body) {
...
}
```
And the Python side receives a tuple:
```python
header, body = layout.panel( ... )
header.label(...)
if body:
...
```
```python
import bpy
from bpy.props import BoolProperty
class LayoutDemoPanel(bpy.types.Panel):
bl_label = "Layout Panel Demo"
bl_idname = "SCENE_PT_layout_panel"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "scene"
def draw(self, context):
layout = self.layout
scene = context.scene
layout.label(text="Basic Panels")
header, panel = layout.panel("my_panel_id", default_closed=True)
header.label(text="Hello World")
if panel:
panel.label(text="Success")
header, panel = layout.panel_prop(scene, "show_demo_panel")
header.label(text="My Panel")
if panel:
panel.prop(scene, "frame_start")
panel.prop(scene, "frame_end")
layout.label(text="Customized headers")
# Add a checkbox to the Panel header. text must be None for this panel
header, panel = layout.panel("my_panel_id-2", default_closed=True)
header.prop(scene, "use_checkmark", text="") # text must be empty for the checkbox
header.label(text="Checkmark at beginning")
if panel:
panel.label(text="Success")
header, panel = layout.panel("my_panel_id-3", default_closed=True)
header.label(text="Buttons at the end")
header.operator("mesh.primitive_cube_add", text="", icon='EXPORT')
header.operator("mesh.primitive_cube_add", text="", icon='X')
if panel:
panel.label(text="Success")
header, panel = layout.panel("my_panel_id-4", default_closed=True)
header.prop(scene, "use_checkmark2", text="")
header.label(text="Both")
header.operator("mesh.primitive_cube_add", text="", icon='EXPORT')
header.operator("mesh.primitive_cube_add", text="", icon='X')
if panel:
panel.label(text="Success")
bpy.utils.register_class(LayoutDemoPanel)
bpy.types.Scene.show_demo_panel = BoolProperty(default=False)
bpy.types.Scene.use_checkmark = BoolProperty(default=False)
bpy.types.Scene.use_checkmark2 = BoolProperty(default=False)
```
Pull Request: https://projects.blender.org/blender/blender/pulls/117248
2024-01-26 10:11:22 +01:00
|
|
|
return panel_layout;
|
UI: add support for uiLayout based panels
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 initial use case for this are panels in the geometry nodes modifier. This patch provides
a better solution compared to what was attempted in #108565.
### Problems with Existing Approaches
Currently, there are two ways to create these expandable sections:
* One can define a new `Panel` type for each expandable section and use the `parent_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.
* It does not work so well for dynamic amounts of panels (e.g. like what we need for
the geometry nodes modifier to organize the inputs).
* Typically, Blender uses a immediate-ui approach, but subpanels break that currently
and need extra handling.
* The order of panels is not very explicit.
* One can't interleave subpanels and other ui elements, subpanels always come at the
end of the parent panel.
* Custom solution using existing `uiLayout`. This is done in the material properties. It
also has a few problems:
* Custom solutions tend to work slightly different in different places. So the UI is less unified.
* Can't drag open/close multiple panels.
* The background color for subpanels does not change.
### Solution
A possible solution to all of these problems is to add support for panels to `uiLayout` directly:
```cpp
/* Add elements before subpanel. */
if (uiLayout *panel_layout = uiLayoutPanel(layout, ...)) {
/* Add elements in subpanel, but only of the panel is open. */
}
/* Add elements after subpanel. */
```
Integrating subpanels with `uiLayout` has some benefits:
* Subpanels are treated like any other sub-layout and don't have unnecessary boilerplate.
* It becomes trivial to have a dynamic number of potentially nested subpanels.
* Resolves all mentioned problems of custom subpanel solutions.
### 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 negligible. Therefor, a much simpler solution
is possible: the open/close state can be stored in the modifier directly. This is actually
how it was implemented before 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 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 (not included)
Adding a Python API is fairly straight forward. 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:
```python
if panel := layout.panel("Mesh Settings", ...):
# Add layout elements in the panel if it's open.
```
Pull Request: https://projects.blender.org/blender/blender/pulls/113584
2023-12-22 17:57:57 +01:00
|
|
|
}
|
|
|
|
|
|
2024-07-10 14:46:06 +02:00
|
|
|
uiLayoutItemPanelBody *body_litem = MEM_new<uiLayoutItemPanelBody>(__func__);
|
2025-04-24 17:22:28 +02:00
|
|
|
body_litem->type_ = uiItemType::LayoutPanelBody;
|
2025-05-06 17:13:30 +02:00
|
|
|
body_litem->space_ = root_->style->templatespace;
|
|
|
|
|
ui_litem_init_from_parent(body_litem, this, false);
|
|
|
|
|
UI_block_layout_set_current(root_->block, body_litem);
|
2024-07-10 14:46:06 +02:00
|
|
|
panel_layout.body = body_litem;
|
UI: Add ability to configure the header row of layout panels
There are many instances where customizing the header row is desired so
return both the header row layout and the main body layout.
For consistency and correctness, the arrow symbol and the is_open check
are always performed so callers only need to perform layout tasks.
The C++ side now receives a `PanelLayout` structure containing both:
```cpp
PanelLayout panel_layout = uiLayoutPanelWithHeader( ... );
uiItemL(panel_layout.header, ... );
if (panel_layout.body) {
...
}
```
And the Python side receives a tuple:
```python
header, body = layout.panel( ... )
header.label(...)
if body:
...
```
```python
import bpy
from bpy.props import BoolProperty
class LayoutDemoPanel(bpy.types.Panel):
bl_label = "Layout Panel Demo"
bl_idname = "SCENE_PT_layout_panel"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "scene"
def draw(self, context):
layout = self.layout
scene = context.scene
layout.label(text="Basic Panels")
header, panel = layout.panel("my_panel_id", default_closed=True)
header.label(text="Hello World")
if panel:
panel.label(text="Success")
header, panel = layout.panel_prop(scene, "show_demo_panel")
header.label(text="My Panel")
if panel:
panel.prop(scene, "frame_start")
panel.prop(scene, "frame_end")
layout.label(text="Customized headers")
# Add a checkbox to the Panel header. text must be None for this panel
header, panel = layout.panel("my_panel_id-2", default_closed=True)
header.prop(scene, "use_checkmark", text="") # text must be empty for the checkbox
header.label(text="Checkmark at beginning")
if panel:
panel.label(text="Success")
header, panel = layout.panel("my_panel_id-3", default_closed=True)
header.label(text="Buttons at the end")
header.operator("mesh.primitive_cube_add", text="", icon='EXPORT')
header.operator("mesh.primitive_cube_add", text="", icon='X')
if panel:
panel.label(text="Success")
header, panel = layout.panel("my_panel_id-4", default_closed=True)
header.prop(scene, "use_checkmark2", text="")
header.label(text="Both")
header.operator("mesh.primitive_cube_add", text="", icon='EXPORT')
header.operator("mesh.primitive_cube_add", text="", icon='X')
if panel:
panel.label(text="Success")
bpy.utils.register_class(LayoutDemoPanel)
bpy.types.Scene.show_demo_panel = BoolProperty(default=False)
bpy.types.Scene.use_checkmark = BoolProperty(default=False)
bpy.types.Scene.use_checkmark2 = BoolProperty(default=False)
```
Pull Request: https://projects.blender.org/blender/blender/pulls/117248
2024-01-26 10:11:22 +01:00
|
|
|
|
|
|
|
|
return panel_layout;
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-07 02:55:25 +02:00
|
|
|
PanelLayout uiLayout::panel_prop_with_bool_header(const bContext *C,
|
|
|
|
|
PointerRNA *open_prop_owner,
|
|
|
|
|
const StringRefNull open_prop_name,
|
|
|
|
|
PointerRNA *bool_prop_owner,
|
|
|
|
|
const StringRefNull bool_prop_name,
|
|
|
|
|
const std::optional<StringRefNull> label)
|
2025-02-28 19:07:02 +01:00
|
|
|
{
|
2025-05-07 22:51:26 +02:00
|
|
|
PanelLayout panel_layout = this->panel_prop(C, open_prop_owner, open_prop_name);
|
2025-02-28 19:07:02 +01:00
|
|
|
|
2025-05-07 02:55:25 +02:00
|
|
|
uiLayout *panel_header = panel_layout.header;
|
2025-04-24 17:22:28 +02:00
|
|
|
panel_header->flag_ &= ~(uiItemInternalFlag::PropSep | uiItemInternalFlag::PropDecorate |
|
|
|
|
|
uiItemInternalFlag::InsidePropSep);
|
2025-05-08 20:45:37 +02:00
|
|
|
panel_header->prop(bool_prop_owner, bool_prop_name, UI_ITEM_NONE, label, ICON_NONE);
|
2025-02-28 19:07:02 +01:00
|
|
|
|
2025-05-07 02:55:25 +02:00
|
|
|
return panel_layout;
|
2025-02-28 19:07:02 +01:00
|
|
|
}
|
|
|
|
|
|
2025-05-06 17:13:30 +02:00
|
|
|
uiLayout *uiLayout::panel_prop(const bContext *C,
|
|
|
|
|
PointerRNA *open_prop_owner,
|
|
|
|
|
const StringRefNull open_prop_name,
|
|
|
|
|
const StringRef label)
|
2024-01-30 17:44:56 +01:00
|
|
|
{
|
2025-05-07 22:51:26 +02:00
|
|
|
PanelLayout panel_layout = this->panel_prop(C, open_prop_owner, open_prop_name);
|
2025-05-08 17:21:08 +02:00
|
|
|
panel_layout.header->label(label, ICON_NONE);
|
2024-01-30 17:44:56 +01:00
|
|
|
|
2025-05-06 17:13:30 +02:00
|
|
|
return panel_layout.body;
|
2024-01-30 17:44:56 +01:00
|
|
|
}
|
|
|
|
|
|
2025-05-06 07:58:02 +02:00
|
|
|
PanelLayout uiLayout::panel(const bContext *C, const StringRef idname, const bool default_closed)
|
2024-01-30 17:44:56 +01:00
|
|
|
{
|
2025-05-06 07:58:02 +02:00
|
|
|
Panel *root_panel = uiLayoutGetRootPanel(this);
|
|
|
|
|
BLI_assert(root_panel != nullptr);
|
2024-01-30 17:44:56 +01:00
|
|
|
|
2025-05-06 07:58:02 +02:00
|
|
|
LayoutPanelState *state = BKE_panel_layout_panel_state_ensure(
|
|
|
|
|
root_panel, idname, default_closed);
|
2025-01-24 16:45:32 +01:00
|
|
|
PointerRNA state_ptr = RNA_pointer_create_discrete(nullptr, &RNA_LayoutPanelState, state);
|
2024-01-30 17:44:56 +01:00
|
|
|
|
2025-05-07 22:51:26 +02:00
|
|
|
return this->panel_prop(C, &state_ptr, "is_open");
|
2024-01-30 17:44:56 +01:00
|
|
|
}
|
|
|
|
|
|
2025-05-06 07:58:02 +02:00
|
|
|
uiLayout *uiLayout::panel(const bContext *C,
|
|
|
|
|
const StringRef idname,
|
|
|
|
|
const bool default_closed,
|
|
|
|
|
const StringRef label)
|
UI: Add ability to configure the header row of layout panels
There are many instances where customizing the header row is desired so
return both the header row layout and the main body layout.
For consistency and correctness, the arrow symbol and the is_open check
are always performed so callers only need to perform layout tasks.
The C++ side now receives a `PanelLayout` structure containing both:
```cpp
PanelLayout panel_layout = uiLayoutPanelWithHeader( ... );
uiItemL(panel_layout.header, ... );
if (panel_layout.body) {
...
}
```
And the Python side receives a tuple:
```python
header, body = layout.panel( ... )
header.label(...)
if body:
...
```
```python
import bpy
from bpy.props import BoolProperty
class LayoutDemoPanel(bpy.types.Panel):
bl_label = "Layout Panel Demo"
bl_idname = "SCENE_PT_layout_panel"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "scene"
def draw(self, context):
layout = self.layout
scene = context.scene
layout.label(text="Basic Panels")
header, panel = layout.panel("my_panel_id", default_closed=True)
header.label(text="Hello World")
if panel:
panel.label(text="Success")
header, panel = layout.panel_prop(scene, "show_demo_panel")
header.label(text="My Panel")
if panel:
panel.prop(scene, "frame_start")
panel.prop(scene, "frame_end")
layout.label(text="Customized headers")
# Add a checkbox to the Panel header. text must be None for this panel
header, panel = layout.panel("my_panel_id-2", default_closed=True)
header.prop(scene, "use_checkmark", text="") # text must be empty for the checkbox
header.label(text="Checkmark at beginning")
if panel:
panel.label(text="Success")
header, panel = layout.panel("my_panel_id-3", default_closed=True)
header.label(text="Buttons at the end")
header.operator("mesh.primitive_cube_add", text="", icon='EXPORT')
header.operator("mesh.primitive_cube_add", text="", icon='X')
if panel:
panel.label(text="Success")
header, panel = layout.panel("my_panel_id-4", default_closed=True)
header.prop(scene, "use_checkmark2", text="")
header.label(text="Both")
header.operator("mesh.primitive_cube_add", text="", icon='EXPORT')
header.operator("mesh.primitive_cube_add", text="", icon='X')
if panel:
panel.label(text="Success")
bpy.utils.register_class(LayoutDemoPanel)
bpy.types.Scene.show_demo_panel = BoolProperty(default=False)
bpy.types.Scene.use_checkmark = BoolProperty(default=False)
bpy.types.Scene.use_checkmark2 = BoolProperty(default=False)
```
Pull Request: https://projects.blender.org/blender/blender/pulls/117248
2024-01-26 10:11:22 +01:00
|
|
|
{
|
2025-05-07 22:51:26 +02:00
|
|
|
PanelLayout panel_layout = this->panel(C, idname, default_closed);
|
2025-05-08 17:21:08 +02:00
|
|
|
panel_layout.header->label(label, ICON_NONE);
|
UI: Add ability to configure the header row of layout panels
There are many instances where customizing the header row is desired so
return both the header row layout and the main body layout.
For consistency and correctness, the arrow symbol and the is_open check
are always performed so callers only need to perform layout tasks.
The C++ side now receives a `PanelLayout` structure containing both:
```cpp
PanelLayout panel_layout = uiLayoutPanelWithHeader( ... );
uiItemL(panel_layout.header, ... );
if (panel_layout.body) {
...
}
```
And the Python side receives a tuple:
```python
header, body = layout.panel( ... )
header.label(...)
if body:
...
```
```python
import bpy
from bpy.props import BoolProperty
class LayoutDemoPanel(bpy.types.Panel):
bl_label = "Layout Panel Demo"
bl_idname = "SCENE_PT_layout_panel"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "scene"
def draw(self, context):
layout = self.layout
scene = context.scene
layout.label(text="Basic Panels")
header, panel = layout.panel("my_panel_id", default_closed=True)
header.label(text="Hello World")
if panel:
panel.label(text="Success")
header, panel = layout.panel_prop(scene, "show_demo_panel")
header.label(text="My Panel")
if panel:
panel.prop(scene, "frame_start")
panel.prop(scene, "frame_end")
layout.label(text="Customized headers")
# Add a checkbox to the Panel header. text must be None for this panel
header, panel = layout.panel("my_panel_id-2", default_closed=True)
header.prop(scene, "use_checkmark", text="") # text must be empty for the checkbox
header.label(text="Checkmark at beginning")
if panel:
panel.label(text="Success")
header, panel = layout.panel("my_panel_id-3", default_closed=True)
header.label(text="Buttons at the end")
header.operator("mesh.primitive_cube_add", text="", icon='EXPORT')
header.operator("mesh.primitive_cube_add", text="", icon='X')
if panel:
panel.label(text="Success")
header, panel = layout.panel("my_panel_id-4", default_closed=True)
header.prop(scene, "use_checkmark2", text="")
header.label(text="Both")
header.operator("mesh.primitive_cube_add", text="", icon='EXPORT')
header.operator("mesh.primitive_cube_add", text="", icon='X')
if panel:
panel.label(text="Success")
bpy.utils.register_class(LayoutDemoPanel)
bpy.types.Scene.show_demo_panel = BoolProperty(default=False)
bpy.types.Scene.use_checkmark = BoolProperty(default=False)
bpy.types.Scene.use_checkmark2 = BoolProperty(default=False)
```
Pull Request: https://projects.blender.org/blender/blender/pulls/117248
2024-01-26 10:11:22 +01:00
|
|
|
|
2025-05-06 07:58:02 +02:00
|
|
|
return panel_layout.body;
|
UI: add support for uiLayout based panels
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 initial use case for this are panels in the geometry nodes modifier. This patch provides
a better solution compared to what was attempted in #108565.
### Problems with Existing Approaches
Currently, there are two ways to create these expandable sections:
* One can define a new `Panel` type for each expandable section and use the `parent_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.
* It does not work so well for dynamic amounts of panels (e.g. like what we need for
the geometry nodes modifier to organize the inputs).
* Typically, Blender uses a immediate-ui approach, but subpanels break that currently
and need extra handling.
* The order of panels is not very explicit.
* One can't interleave subpanels and other ui elements, subpanels always come at the
end of the parent panel.
* Custom solution using existing `uiLayout`. This is done in the material properties. It
also has a few problems:
* Custom solutions tend to work slightly different in different places. So the UI is less unified.
* Can't drag open/close multiple panels.
* The background color for subpanels does not change.
### Solution
A possible solution to all of these problems is to add support for panels to `uiLayout` directly:
```cpp
/* Add elements before subpanel. */
if (uiLayout *panel_layout = uiLayoutPanel(layout, ...)) {
/* Add elements in subpanel, but only of the panel is open. */
}
/* Add elements after subpanel. */
```
Integrating subpanels with `uiLayout` has some benefits:
* Subpanels are treated like any other sub-layout and don't have unnecessary boilerplate.
* It becomes trivial to have a dynamic number of potentially nested subpanels.
* Resolves all mentioned problems of custom subpanel solutions.
### 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 negligible. Therefor, a much simpler solution
is possible: the open/close state can be stored in the modifier directly. This is actually
how it was implemented before 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 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 (not included)
Adding a Python API is fairly straight forward. 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:
```python
if panel := layout.panel("Mesh Settings", ...):
# Add layout elements in the panel if it's open.
```
Pull Request: https://projects.blender.org/blender/blender/pulls/113584
2023-12-22 17:57:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool uiLayoutEndsWithPanelHeader(const uiLayout &layout)
|
|
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
if (layout.items_.is_empty()) {
|
UI: add support for uiLayout based panels
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 initial use case for this are panels in the geometry nodes modifier. This patch provides
a better solution compared to what was attempted in #108565.
### Problems with Existing Approaches
Currently, there are two ways to create these expandable sections:
* One can define a new `Panel` type for each expandable section and use the `parent_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.
* It does not work so well for dynamic amounts of panels (e.g. like what we need for
the geometry nodes modifier to organize the inputs).
* Typically, Blender uses a immediate-ui approach, but subpanels break that currently
and need extra handling.
* The order of panels is not very explicit.
* One can't interleave subpanels and other ui elements, subpanels always come at the
end of the parent panel.
* Custom solution using existing `uiLayout`. This is done in the material properties. It
also has a few problems:
* Custom solutions tend to work slightly different in different places. So the UI is less unified.
* Can't drag open/close multiple panels.
* The background color for subpanels does not change.
### Solution
A possible solution to all of these problems is to add support for panels to `uiLayout` directly:
```cpp
/* Add elements before subpanel. */
if (uiLayout *panel_layout = uiLayoutPanel(layout, ...)) {
/* Add elements in subpanel, but only of the panel is open. */
}
/* Add elements after subpanel. */
```
Integrating subpanels with `uiLayout` has some benefits:
* Subpanels are treated like any other sub-layout and don't have unnecessary boilerplate.
* It becomes trivial to have a dynamic number of potentially nested subpanels.
* Resolves all mentioned problems of custom subpanel solutions.
### 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 negligible. Therefor, a much simpler solution
is possible: the open/close state can be stored in the modifier directly. This is actually
how it was implemented before 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 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 (not included)
Adding a Python API is fairly straight forward. 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:
```python
if panel := layout.panel("Mesh Settings", ...):
# Add layout elements in the panel if it's open.
```
Pull Request: https://projects.blender.org/blender/blender/pulls/113584
2023-12-22 17:57:57 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
2025-04-23 16:37:14 +02:00
|
|
|
const uiItem *item = layout.items_.last();
|
2025-04-24 17:22:28 +02:00
|
|
|
return item->type_ == uiItemType::LayoutPanelHeader;
|
UI: add support for uiLayout based panels
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 initial use case for this are panels in the geometry nodes modifier. This patch provides
a better solution compared to what was attempted in #108565.
### Problems with Existing Approaches
Currently, there are two ways to create these expandable sections:
* One can define a new `Panel` type for each expandable section and use the `parent_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.
* It does not work so well for dynamic amounts of panels (e.g. like what we need for
the geometry nodes modifier to organize the inputs).
* Typically, Blender uses a immediate-ui approach, but subpanels break that currently
and need extra handling.
* The order of panels is not very explicit.
* One can't interleave subpanels and other ui elements, subpanels always come at the
end of the parent panel.
* Custom solution using existing `uiLayout`. This is done in the material properties. It
also has a few problems:
* Custom solutions tend to work slightly different in different places. So the UI is less unified.
* Can't drag open/close multiple panels.
* The background color for subpanels does not change.
### Solution
A possible solution to all of these problems is to add support for panels to `uiLayout` directly:
```cpp
/* Add elements before subpanel. */
if (uiLayout *panel_layout = uiLayoutPanel(layout, ...)) {
/* Add elements in subpanel, but only of the panel is open. */
}
/* Add elements after subpanel. */
```
Integrating subpanels with `uiLayout` has some benefits:
* Subpanels are treated like any other sub-layout and don't have unnecessary boilerplate.
* It becomes trivial to have a dynamic number of potentially nested subpanels.
* Resolves all mentioned problems of custom subpanel solutions.
### 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 negligible. Therefor, a much simpler solution
is possible: the open/close state can be stored in the modifier directly. This is actually
how it was implemented before 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 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 (not included)
Adding a Python API is fairly straight forward. 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:
```python
if panel := layout.panel("Mesh Settings", ...):
# Add layout elements in the panel if it's open.
```
Pull Request: https://projects.blender.org/blender/blender/pulls/113584
2023-12-22 17:57:57 +01:00
|
|
|
}
|
|
|
|
|
|
2025-04-26 02:17:31 +02:00
|
|
|
uiLayout &uiLayout::row(bool align, const StringRef heading)
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
{
|
2025-05-07 22:51:26 +02:00
|
|
|
uiLayout &litem = this->row(align);
|
2025-04-26 02:17:31 +02:00
|
|
|
ui_layout_heading_set(&litem, heading);
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
return litem;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-26 21:07:34 +02:00
|
|
|
uiLayout &uiLayout::column(bool align)
|
2009-04-15 15:09:36 +00:00
|
|
|
{
|
2024-07-10 14:46:06 +02:00
|
|
|
uiLayout *litem = MEM_new<uiLayout>(__func__);
|
2025-04-26 21:07:34 +02:00
|
|
|
ui_litem_init_from_parent(litem, this, align);
|
2018-05-13 12:28:35 +02:00
|
|
|
|
2025-04-24 17:22:28 +02:00
|
|
|
litem->type_ = uiItemType::LayoutColumn;
|
2025-05-07 22:51:26 +02:00
|
|
|
litem->space_ = (align) ? 0 : root_->style->buttonspacey;
|
2009-04-15 15:09:36 +00:00
|
|
|
|
2025-05-07 22:51:26 +02:00
|
|
|
UI_block_layout_set_current(root_->block, litem);
|
2009-05-19 17:13:33 +00:00
|
|
|
|
2025-04-26 21:07:34 +02:00
|
|
|
return *litem;
|
2009-04-15 15:09:36 +00:00
|
|
|
}
|
|
|
|
|
|
2025-04-27 17:09:52 +02:00
|
|
|
uiLayout &uiLayout::column(bool align, const StringRef heading)
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
{
|
2025-05-07 22:51:26 +02:00
|
|
|
uiLayout &litem = this->column(align);
|
2025-04-27 17:09:52 +02:00
|
|
|
ui_layout_heading_set(&litem, heading);
|
UI: Better split layout support for checkboxes
Makes the following layout changes possible:
{F8473498} {F8473499} {F8473502}
The next commit will contain many layout changes to make good use of
these new possibilities. The result should be more consistent, easier to
read and should give a more organized impression. Additionally, it
should be possible to replace many sub-panels with compacter layouts.
Main changes:
* Checkboxes now respect the property split layouts
* Add support for row and column headers (i.e.
`uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the
first property added to this layout doesn't insert anything into the label
split column, the heading is inserted there. Otherwise, it's inserted as own
item.
* Add support for manually inserting decorators for an existing item
(`uiLayout.prop_decorator()`). That way layout creators can manually insert
this, which was the only way I saw to support property split layouts with a
checkbox before the actual property. {F8471883}
* Autogenerated layouts for operator properties look bad if there are only
checkboxes (which only use half the region width). So before creating the
layout, we iterate over visible properties and disable split layout if all
are booleans. I think this is fine, if needed we could also add layout hints
to operators.
* `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller
used to be responsible for this. Code that didn't handle these so far never
used macros I think, so this change should be invisible.
* Remove manual property split layout from autogenerated operator properties
layout.
* Padding of checkboxes is tweaked to make their label visually more connected
to the checkboxes.
* Support split layout for menus (should work for `uiLayout.menu()`,
`.operator_menu_enum()`, `.prop_menu_enum()`, maybe more)
Maniphest Task: https://developer.blender.org/T65965
Differential Revision: https://developer.blender.org/D7427
Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
|
|
|
return litem;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-30 08:27:31 +02:00
|
|
|
uiLayout &uiLayout::column_flow(int number, bool align)
|
2009-03-13 13:38:41 +00:00
|
|
|
{
|
2024-07-10 14:46:06 +02:00
|
|
|
uiLayoutItemFlow *flow = MEM_new<uiLayoutItemFlow>(__func__);
|
2025-04-30 08:27:31 +02:00
|
|
|
ui_litem_init_from_parent(flow, this, align);
|
2018-05-13 12:28:35 +02:00
|
|
|
|
2025-04-24 17:22:28 +02:00
|
|
|
flow->type_ = uiItemType::LayoutColumnFlow;
|
2025-05-07 22:51:26 +02:00
|
|
|
flow->space_ = (flow->align_) ? 0 : root_->style->columnspace;
|
2012-03-30 01:51:25 +00:00
|
|
|
flow->number = number;
|
2009-03-13 13:38:41 +00:00
|
|
|
|
2025-05-07 22:51:26 +02:00
|
|
|
UI_block_layout_set_current(root_->block, flow);
|
2009-05-19 17:13:33 +00:00
|
|
|
|
2025-04-30 08:27:31 +02:00
|
|
|
return *flow;
|
2009-03-13 13:38:41 +00:00
|
|
|
}
|
|
|
|
|
|
2025-04-30 08:27:31 +02:00
|
|
|
uiLayout &uiLayout::grid_flow(
|
|
|
|
|
bool row_major, int columns_len, bool even_columns, bool even_rows, bool align)
|
2018-06-09 16:50:05 +02:00
|
|
|
{
|
2024-07-10 14:46:06 +02:00
|
|
|
uiLayoutItemGridFlow *flow = MEM_new<uiLayoutItemGridFlow>(__func__);
|
2025-04-24 17:22:28 +02:00
|
|
|
flow->type_ = uiItemType::LayoutGridFlow;
|
2025-04-30 08:27:31 +02:00
|
|
|
ui_litem_init_from_parent(flow, this, align);
|
2018-06-09 16:50:05 +02:00
|
|
|
|
2025-05-07 22:51:26 +02:00
|
|
|
flow->space_ = (flow->align_) ? 0 : root_->style->columnspace;
|
2018-06-09 16:50:05 +02:00
|
|
|
flow->row_major = row_major;
|
2018-07-01 09:23:51 +02:00
|
|
|
flow->columns_len = columns_len;
|
2018-06-09 16:50:05 +02:00
|
|
|
flow->even_columns = even_columns;
|
|
|
|
|
flow->even_rows = even_rows;
|
|
|
|
|
|
2025-05-07 22:51:26 +02:00
|
|
|
UI_block_layout_set_current(root_->block, flow);
|
2018-06-09 16:50:05 +02:00
|
|
|
|
2025-04-30 08:27:31 +02:00
|
|
|
return *flow;
|
2018-06-09 16:50:05 +02:00
|
|
|
}
|
|
|
|
|
|
2009-10-21 20:58:10 +00:00
|
|
|
static uiLayoutItemBx *ui_layout_box(uiLayout *layout, int type)
|
2009-04-11 01:52:27 +00:00
|
|
|
{
|
2024-07-10 14:46:06 +02:00
|
|
|
uiLayoutItemBx *box = MEM_new<uiLayoutItemBx>(__func__);
|
|
|
|
|
ui_litem_init_from_parent(box, layout, false);
|
2018-05-13 12:28:35 +02:00
|
|
|
|
2025-04-24 17:22:28 +02:00
|
|
|
box->type_ = uiItemType::LayoutBox;
|
2025-04-23 16:37:14 +02:00
|
|
|
box->space_ = layout->root_->style->columnspace;
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
UI_block_layout_set_current(layout->root_->block, box);
|
2009-05-19 17:13:33 +00:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
box->roundbox = uiDefBut(layout->root_->block, type, 0, "", 0, 0, 0, 0, nullptr, 0.0, 0.0, "");
|
2009-05-21 15:34:09 +00:00
|
|
|
|
2009-10-21 20:58:10 +00:00
|
|
|
return box;
|
2009-04-11 01:52:27 +00:00
|
|
|
}
|
2009-03-13 13:38:41 +00:00
|
|
|
|
2025-05-07 23:29:49 +02:00
|
|
|
uiLayout &uiLayout::menu_pie()
|
Pie Menus C code backend.
This commit merges the code in the pie-menu branch.
As per decisions taken the last few days, there are no pie menus
included and there will be an official add-on including overrides of
some keys with pie menus. However, people will now be able to use the
new code in python.
Full Documentation is in http://wiki.blender.org/index.php/Dev:Ref/
Thanks:
Campbell Barton, Dalai Felinto and Ton Roosendaal for the code review
and design comments
Jonathan Williamson, Pawel Lyczkowski, Pablo Vazquez among others for
suggestions during the development.
Special Thanks to Sean Olson, for his support, suggestions, testing and
merciless bugging so that I would finish the pie menu code. Without him
we wouldn't be here. Also to the rest of the developers of the original
python add-on, Patrick Moore and Dan Eicher and finally to Matt Ebb, who
did the research and first implementation and whose code I used to get
started.
2014-08-11 10:39:59 +02:00
|
|
|
{
|
|
|
|
|
/* radial layouts are only valid for radial menus */
|
2025-05-07 23:29:49 +02:00
|
|
|
if (root_->type != UI_LAYOUT_PIEMENU) {
|
|
|
|
|
return *ui_item_local_sublayout(this, this, false);
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
Pie Menus C code backend.
This commit merges the code in the pie-menu branch.
As per decisions taken the last few days, there are no pie menus
included and there will be an official add-on including overrides of
some keys with pie menus. However, people will now be able to use the
new code in python.
Full Documentation is in http://wiki.blender.org/index.php/Dev:Ref/
Thanks:
Campbell Barton, Dalai Felinto and Ton Roosendaal for the code review
and design comments
Jonathan Williamson, Pawel Lyczkowski, Pablo Vazquez among others for
suggestions during the development.
Special Thanks to Sean Olson, for his support, suggestions, testing and
merciless bugging so that I would finish the pie menu code. Without him
we wouldn't be here. Also to the rest of the developers of the original
python add-on, Patrick Moore and Dan Eicher and finally to Matt Ebb, who
did the research and first implementation and whose code I used to get
started.
2014-08-11 10:39:59 +02:00
|
|
|
|
|
|
|
|
/* only one radial wheel per root layout is allowed, so check and return that, if it exists */
|
2025-05-07 23:29:49 +02:00
|
|
|
for (uiItem *item : root_->layout->items_) {
|
2025-04-24 17:22:28 +02:00
|
|
|
if (item->type_ == uiItemType::LayoutRadial) {
|
2024-07-10 14:46:06 +02:00
|
|
|
uiLayout *litem = static_cast<uiLayout *>(item);
|
2025-05-07 23:29:49 +02:00
|
|
|
UI_block_layout_set_current(root_->block, litem);
|
|
|
|
|
return *litem;
|
Pie Menus C code backend.
This commit merges the code in the pie-menu branch.
As per decisions taken the last few days, there are no pie menus
included and there will be an official add-on including overrides of
some keys with pie menus. However, people will now be able to use the
new code in python.
Full Documentation is in http://wiki.blender.org/index.php/Dev:Ref/
Thanks:
Campbell Barton, Dalai Felinto and Ton Roosendaal for the code review
and design comments
Jonathan Williamson, Pawel Lyczkowski, Pablo Vazquez among others for
suggestions during the development.
Special Thanks to Sean Olson, for his support, suggestions, testing and
merciless bugging so that I would finish the pie menu code. Without him
we wouldn't be here. Also to the rest of the developers of the original
python add-on, Patrick Moore and Dan Eicher and finally to Matt Ebb, who
did the research and first implementation and whose code I used to get
started.
2014-08-11 10:39:59 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-10 14:46:06 +02:00
|
|
|
uiLayout *litem = MEM_new<uiLayout>(__func__);
|
2025-05-07 23:29:49 +02:00
|
|
|
ui_litem_init_from_parent(litem, this, false);
|
2018-05-13 12:28:35 +02:00
|
|
|
|
2025-04-24 17:22:28 +02:00
|
|
|
litem->type_ = uiItemType::LayoutRadial;
|
Pie Menus C code backend.
This commit merges the code in the pie-menu branch.
As per decisions taken the last few days, there are no pie menus
included and there will be an official add-on including overrides of
some keys with pie menus. However, people will now be able to use the
new code in python.
Full Documentation is in http://wiki.blender.org/index.php/Dev:Ref/
Thanks:
Campbell Barton, Dalai Felinto and Ton Roosendaal for the code review
and design comments
Jonathan Williamson, Pawel Lyczkowski, Pablo Vazquez among others for
suggestions during the development.
Special Thanks to Sean Olson, for his support, suggestions, testing and
merciless bugging so that I would finish the pie menu code. Without him
we wouldn't be here. Also to the rest of the developers of the original
python add-on, Patrick Moore and Dan Eicher and finally to Matt Ebb, who
did the research and first implementation and whose code I used to get
started.
2014-08-11 10:39:59 +02:00
|
|
|
|
2025-05-07 23:29:49 +02:00
|
|
|
UI_block_layout_set_current(root_->block, litem);
|
Pie Menus C code backend.
This commit merges the code in the pie-menu branch.
As per decisions taken the last few days, there are no pie menus
included and there will be an official add-on including overrides of
some keys with pie menus. However, people will now be able to use the
new code in python.
Full Documentation is in http://wiki.blender.org/index.php/Dev:Ref/
Thanks:
Campbell Barton, Dalai Felinto and Ton Roosendaal for the code review
and design comments
Jonathan Williamson, Pawel Lyczkowski, Pablo Vazquez among others for
suggestions during the development.
Special Thanks to Sean Olson, for his support, suggestions, testing and
merciless bugging so that I would finish the pie menu code. Without him
we wouldn't be here. Also to the rest of the developers of the original
python add-on, Patrick Moore and Dan Eicher and finally to Matt Ebb, who
did the research and first implementation and whose code I used to get
started.
2014-08-11 10:39:59 +02:00
|
|
|
|
2025-05-07 23:29:49 +02:00
|
|
|
return *litem;
|
Pie Menus C code backend.
This commit merges the code in the pie-menu branch.
As per decisions taken the last few days, there are no pie menus
included and there will be an official add-on including overrides of
some keys with pie menus. However, people will now be able to use the
new code in python.
Full Documentation is in http://wiki.blender.org/index.php/Dev:Ref/
Thanks:
Campbell Barton, Dalai Felinto and Ton Roosendaal for the code review
and design comments
Jonathan Williamson, Pawel Lyczkowski, Pablo Vazquez among others for
suggestions during the development.
Special Thanks to Sean Olson, for his support, suggestions, testing and
merciless bugging so that I would finish the pie menu code. Without him
we wouldn't be here. Also to the rest of the developers of the original
python add-on, Patrick Moore and Dan Eicher and finally to Matt Ebb, who
did the research and first implementation and whose code I used to get
started.
2014-08-11 10:39:59 +02:00
|
|
|
}
|
|
|
|
|
|
2025-05-02 19:46:26 +02:00
|
|
|
uiLayout &uiLayout::box()
|
2009-07-21 01:26:17 +00:00
|
|
|
{
|
2025-05-02 19:46:26 +02:00
|
|
|
return *ui_layout_box(this, UI_BTYPE_ROUNDBOX);
|
2009-07-21 01:26:17 +00:00
|
|
|
}
|
|
|
|
|
|
Fix [#35750] list items in properties editor (text colors not following list item theme).
Issue goes back since we stopped using LISTROW button to draw item's name (i.e. since we have custom buttons in list items!).
This commit:
* Adds a new flag to uiBlock, UI_BLOCK_LIST_ITEM, to mark blocks used for each list item.
* Adds a new button type, LISTLABEL, which basically behaves exactly as LABEL, but uses wcol_list_item color set.
* When uiItemL is called, it checks whether current block has UI_BLOCK_LIST_ITEM set, and if so, switch produced button to LISTLABEL type.
* Adds a new helper func, ui_layout_list_set_labels_active, called after the active list item has been "drawn", to set all LISTLABEL buttons as UI_SELECT.
Note custom widget_state_label() was removed, in interface_widgets.c, as it did nothing more than default widget_state().
Thanks to Brecht for the review and advices.
2013-06-26 07:28:55 +00:00
|
|
|
void ui_layout_list_set_labels_active(uiLayout *layout)
|
|
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
for (uiItem *item : layout->items_) {
|
2025-04-24 17:22:28 +02:00
|
|
|
if (item->type_ != uiItemType::Button) {
|
2024-07-10 14:46:06 +02:00
|
|
|
ui_layout_list_set_labels_active(static_cast<uiLayout *>(item));
|
2013-11-09 18:44:37 +00:00
|
|
|
}
|
2024-07-10 14:46:06 +02:00
|
|
|
else {
|
|
|
|
|
uiButtonItem *bitem = static_cast<uiButtonItem *>(item);
|
|
|
|
|
if (bitem->but->flag & UI_BUT_LIST_ITEM) {
|
|
|
|
|
UI_but_flag_enable(bitem->but, UI_SELECT);
|
|
|
|
|
}
|
Fix [#35750] list items in properties editor (text colors not following list item theme).
Issue goes back since we stopped using LISTROW button to draw item's name (i.e. since we have custom buttons in list items!).
This commit:
* Adds a new flag to uiBlock, UI_BLOCK_LIST_ITEM, to mark blocks used for each list item.
* Adds a new button type, LISTLABEL, which basically behaves exactly as LABEL, but uses wcol_list_item color set.
* When uiItemL is called, it checks whether current block has UI_BLOCK_LIST_ITEM set, and if so, switch produced button to LISTLABEL type.
* Adds a new helper func, ui_layout_list_set_labels_active, called after the active list item has been "drawn", to set all LISTLABEL buttons as UI_SELECT.
Note custom widget_state_label() was removed, in interface_widgets.c, as it did nothing more than default widget_state().
Thanks to Brecht for the review and advices.
2013-06-26 07:28:55 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-07 20:38:40 +02:00
|
|
|
uiLayout &uiLayout::list_box(uiList *ui_list, PointerRNA *actptr, PropertyRNA *actprop)
|
2009-07-21 01:26:17 +00:00
|
|
|
{
|
2025-05-07 20:38:40 +02:00
|
|
|
uiLayoutItemBx *item_box = ui_layout_box(this, UI_BTYPE_LISTBOX);
|
|
|
|
|
uiBut *but = item_box->roundbox;
|
2009-07-21 01:26:17 +00:00
|
|
|
|
2012-12-28 10:32:49 +00:00
|
|
|
but->custom_data = ui_list;
|
This commit frees list ui items from their dependencies to Panel, and hence from all the limitations this implied (mostly, the "only one list per panel" one).
It introduces a new (py-extendable and registrable) RNA type, UIList (roughly similar to Panel one), which currently contains only "standard" list's scroll pos and size (but may be expended to include e.g. some filtering data, etc.). This now makes lists completely independent from Panels!
This UIList has a draw_item callback which allows to customize items' drawing from python, that all addons can now use. Incidentally, this also greatly simplifies the C code of this widget, as we do not code any "special case" here anymore!
To make all this work, other changes were also necessary:
* Now all buttons (uiBut struct) have a 'custom_data' void pointer, used currently to store the uiList struct associated with a given uiLayoutListBox.
* DynamicPaintSurface now exposes a new bool, use_color_preview (readonly), saying whether that surface has some 3D view preview data or not.
* UILayout class has now four new (static) functions, to get the actual icon of any RNA object (important e.g. with materials or textures), and to get an enum item's UI name, description and icon.
* UILayout's label() func now takes an optional 'icon_value' integer parameter, which if not zero will override the 'icon' one (mandatory to use "custom" icons as generated for material/texture/... previews).
Note: not sure whether we should add that one to all UILayout's prop funcs?
Note: will update addons using template list asap.
2012-12-28 09:20:16 +00:00
|
|
|
|
2012-03-30 01:51:25 +00:00
|
|
|
but->rnapoin = *actptr;
|
|
|
|
|
but->rnaprop = actprop;
|
2009-10-21 20:58:10 +00:00
|
|
|
|
2013-07-09 23:40:53 +00:00
|
|
|
/* only for the undo string */
|
|
|
|
|
if (but->flag & UI_BUT_UNDO) {
|
|
|
|
|
but->tip = RNA_property_description(actprop);
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-07 20:38:40 +02:00
|
|
|
return *item_box;
|
2009-07-21 01:26:17 +00:00
|
|
|
}
|
|
|
|
|
|
2025-05-07 17:03:15 +02:00
|
|
|
uiLayout &uiLayout::absolute(bool align)
|
2009-03-13 13:38:41 +00:00
|
|
|
{
|
2024-07-10 14:46:06 +02:00
|
|
|
uiLayout *litem = MEM_new<uiLayout>(__func__);
|
2025-05-07 17:03:15 +02:00
|
|
|
ui_litem_init_from_parent(litem, this, align);
|
2018-05-13 12:28:35 +02:00
|
|
|
|
2025-04-24 17:22:28 +02:00
|
|
|
litem->type_ = uiItemType::LayoutAbsolute;
|
2009-03-13 13:38:41 +00:00
|
|
|
|
2025-05-07 17:03:15 +02:00
|
|
|
UI_block_layout_set_current(root_->block, litem);
|
2009-05-19 17:13:33 +00:00
|
|
|
|
2025-05-07 17:03:15 +02:00
|
|
|
return *litem;
|
2009-04-16 12:17:58 +00:00
|
|
|
}
|
|
|
|
|
|
2025-05-07 17:03:15 +02:00
|
|
|
uiBlock *uiLayout::absolute_block()
|
2009-05-19 17:13:33 +00:00
|
|
|
{
|
2025-05-07 17:03:15 +02:00
|
|
|
uiBlock *block = uiLayoutGetBlock(this);
|
|
|
|
|
absolute(false);
|
2009-05-19 17:13:33 +00:00
|
|
|
|
|
|
|
|
return block;
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-07 20:38:40 +02:00
|
|
|
uiLayout &uiLayout::overlap()
|
2009-10-21 20:58:10 +00:00
|
|
|
{
|
2024-07-10 14:46:06 +02:00
|
|
|
uiLayout *litem = MEM_new<uiLayout>(__func__);
|
2025-05-07 20:38:40 +02:00
|
|
|
ui_litem_init_from_parent(litem, this, false);
|
2018-05-13 12:28:35 +02:00
|
|
|
|
2025-04-24 17:22:28 +02:00
|
|
|
litem->type_ = uiItemType::LayoutOverlap;
|
2009-10-21 20:58:10 +00:00
|
|
|
|
2025-05-07 20:38:40 +02:00
|
|
|
UI_block_layout_set_current(root_->block, litem);
|
2009-10-21 20:58:10 +00:00
|
|
|
|
2025-05-07 20:38:40 +02:00
|
|
|
return *litem;
|
2009-10-21 20:58:10 +00:00
|
|
|
}
|
|
|
|
|
|
2025-05-03 20:51:42 +02:00
|
|
|
uiLayout &uiLayout::split(float percentage, bool align)
|
2009-04-16 12:17:58 +00:00
|
|
|
{
|
2024-07-10 14:46:06 +02:00
|
|
|
uiLayoutItemSplit *split = MEM_new<uiLayoutItemSplit>(__func__);
|
2025-05-03 20:51:42 +02:00
|
|
|
ui_litem_init_from_parent(split, this, align);
|
2018-05-13 12:28:35 +02:00
|
|
|
|
2025-04-24 17:22:28 +02:00
|
|
|
split->type_ = uiItemType::LayoutSplit;
|
2025-05-03 20:51:42 +02:00
|
|
|
split->space_ = root_->style->columnspace;
|
2012-03-30 01:51:25 +00:00
|
|
|
split->percentage = percentage;
|
2009-05-19 17:13:33 +00:00
|
|
|
|
2025-05-03 20:51:42 +02:00
|
|
|
UI_block_layout_set_current(root_->block, split);
|
2009-04-16 12:17:58 +00:00
|
|
|
|
2025-05-03 20:51:42 +02:00
|
|
|
return *split;
|
2009-03-13 13:38:41 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-04 02:05:11 +00:00
|
|
|
void uiLayoutSetActive(uiLayout *layout, bool active)
|
2009-05-28 23:37:55 +00:00
|
|
|
{
|
2025-04-23 14:54:06 +02:00
|
|
|
layout->active_ = active;
|
2009-05-28 23:37:55 +00:00
|
|
|
}
|
|
|
|
|
|
2019-03-27 21:39:44 +11:00
|
|
|
void uiLayoutSetActiveDefault(uiLayout *layout, bool active_default)
|
|
|
|
|
{
|
2025-04-23 14:54:06 +02:00
|
|
|
layout->active_default_ = active_default;
|
2019-03-27 21:39:44 +11:00
|
|
|
}
|
|
|
|
|
|
2019-03-20 22:40:38 +11:00
|
|
|
void uiLayoutSetActivateInit(uiLayout *layout, bool activate_init)
|
|
|
|
|
{
|
2025-04-23 14:54:06 +02:00
|
|
|
layout->activate_init_ = activate_init;
|
2019-03-20 22:40:38 +11:00
|
|
|
}
|
|
|
|
|
|
2013-04-04 02:05:11 +00:00
|
|
|
void uiLayoutSetEnabled(uiLayout *layout, bool enabled)
|
2009-05-28 23:37:55 +00:00
|
|
|
{
|
2025-04-23 14:54:06 +02:00
|
|
|
layout->enabled_ = enabled;
|
2009-05-28 23:37:55 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-04 02:05:11 +00:00
|
|
|
void uiLayoutSetRedAlert(uiLayout *layout, bool redalert)
|
2009-05-28 23:37:55 +00:00
|
|
|
{
|
2025-04-23 14:54:06 +02:00
|
|
|
layout->redalert_ = redalert;
|
2009-05-28 23:37:55 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-04 02:05:11 +00:00
|
|
|
void uiLayoutSetKeepAspect(uiLayout *layout, bool keepaspect)
|
2009-05-28 23:37:55 +00:00
|
|
|
{
|
2025-04-23 14:54:06 +02:00
|
|
|
layout->keepaspect_ = keepaspect;
|
2009-05-28 23:37:55 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-04 02:05:11 +00:00
|
|
|
void uiLayoutSetAlignment(uiLayout *layout, char alignment)
|
2009-05-28 23:37:55 +00:00
|
|
|
{
|
2025-04-23 14:54:06 +02:00
|
|
|
layout->alignment_ = alignment;
|
2009-05-28 23:37:55 +00:00
|
|
|
}
|
|
|
|
|
|
2009-06-03 00:04:48 +00:00
|
|
|
void uiLayoutSetScaleX(uiLayout *layout, float scale)
|
2009-05-28 23:37:55 +00:00
|
|
|
{
|
2025-04-23 14:54:06 +02:00
|
|
|
layout->scale_[0] = scale;
|
2009-06-03 00:04:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void uiLayoutSetScaleY(uiLayout *layout, float scale)
|
|
|
|
|
{
|
2025-04-23 14:54:06 +02:00
|
|
|
layout->scale_[1] = scale;
|
2009-05-28 23:37:55 +00:00
|
|
|
}
|
|
|
|
|
|
2018-09-26 17:44:35 +02:00
|
|
|
void uiLayoutSetUnitsX(uiLayout *layout, float unit)
|
2018-09-25 20:59:04 +02:00
|
|
|
{
|
2025-04-23 14:54:06 +02:00
|
|
|
layout->units_[0] = unit;
|
2018-09-25 20:59:04 +02:00
|
|
|
}
|
|
|
|
|
|
2018-09-26 17:44:35 +02:00
|
|
|
void uiLayoutSetUnitsY(uiLayout *layout, float unit)
|
2018-09-25 20:59:04 +02:00
|
|
|
{
|
2025-04-23 14:54:06 +02:00
|
|
|
layout->units_[1] = unit;
|
2018-09-25 20:59:04 +02:00
|
|
|
}
|
|
|
|
|
|
2025-03-31 00:36:46 +02:00
|
|
|
void uiLayoutSetEmboss(uiLayout *layout, blender::ui::EmbossType emboss)
|
2018-05-13 12:57:31 +02:00
|
|
|
{
|
2025-04-23 14:54:06 +02:00
|
|
|
layout->emboss_ = emboss;
|
2018-05-13 12:57:31 +02:00
|
|
|
}
|
|
|
|
|
|
2018-05-28 16:40:27 +02:00
|
|
|
bool uiLayoutGetPropSep(uiLayout *layout)
|
|
|
|
|
{
|
2025-04-24 17:22:28 +02:00
|
|
|
return bool(layout->flag_ & uiItemInternalFlag::PropSep);
|
2018-05-28 16:40:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
|
|
|
|
|
{
|
2025-04-24 17:22:28 +02:00
|
|
|
SET_FLAG_FROM_TEST(layout->flag_, is_sep, uiItemInternalFlag::PropSep);
|
2018-05-28 16:40:27 +02:00
|
|
|
}
|
|
|
|
|
|
2018-06-16 14:48:21 +02:00
|
|
|
bool uiLayoutGetPropDecorate(uiLayout *layout)
|
|
|
|
|
{
|
2025-04-24 17:22:28 +02:00
|
|
|
return bool(layout->flag_ & uiItemInternalFlag::PropDecorate);
|
2018-06-16 14:48:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
|
|
|
|
|
{
|
2025-04-24 17:22:28 +02:00
|
|
|
SET_FLAG_FROM_TEST(layout->flag_, is_sep, uiItemInternalFlag::PropDecorate);
|
2018-06-16 14:48:21 +02:00
|
|
|
}
|
|
|
|
|
|
2024-04-16 12:18:45 +02:00
|
|
|
void uiLayoutSetSearchWeight(uiLayout *layout, const float weight)
|
|
|
|
|
{
|
2025-04-23 14:54:06 +02:00
|
|
|
layout->search_weight_ = weight;
|
2024-04-16 12:18:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float uiLayoutGetSearchWeight(uiLayout *layout)
|
|
|
|
|
{
|
2025-04-23 14:54:06 +02:00
|
|
|
return layout->search_weight_;
|
2024-04-16 12:18:45 +02:00
|
|
|
}
|
|
|
|
|
|
Python: add Python API for layout panels
This adds a Python API for layout panels that have been introduced in #113584.
Two new methods on `UILayout` are added:
* `.panel(idname, text="...", default_closed=False) -> Optional[UILayout]`
* `.panel_prop(owner, prop_name, text="...") -> Optional[UILayout]`
Both create a panel and return `None` if the panel is collapsed. The difference lies
in how the open-close-state is stored. The first method internally manages the
open-close-state based on the provided identifier. The second one allows for
providing a boolean property that stores whether the panel is open. This is useful
when creating a dynamic of panels and when it is difficult to create a unique idname.
For the `.panel(...)` method, a new internal map on `Panel` is created which keeps
track of all the panel states based on the idname. Currently, there is no mechanism
for freeing any elements once they have been added to the map. This is unlikely to
cause a problem anytime soon, but we might need some kind of garbage collection
in the future.
```python
import bpy
from bpy.props import BoolProperty
class LayoutDemoPanel(bpy.types.Panel):
bl_label = "Layout Panel Demo"
bl_idname = "SCENE_PT_layout_panel"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "scene"
def draw(self, context):
layout = self.layout
scene = context.scene
layout.label(text="Before")
if panel := layout.panel("my_panel_id", text="Hello World", default_closed=False):
panel.label(text="Success")
if panel := layout.panel_prop(scene, "show_demo_panel", text="My Panel"):
panel.prop(scene, "frame_start")
panel.prop(scene, "frame_end")
layout.label(text="After")
bpy.utils.register_class(LayoutDemoPanel)
bpy.types.Scene.show_demo_panel = BoolProperty(default=False)
```
Pull Request: https://projects.blender.org/blender/blender/pulls/116949
2024-01-11 19:08:45 +01:00
|
|
|
Panel *uiLayoutGetRootPanel(uiLayout *layout)
|
|
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
return layout->root_->block->panel;
|
Python: add Python API for layout panels
This adds a Python API for layout panels that have been introduced in #113584.
Two new methods on `UILayout` are added:
* `.panel(idname, text="...", default_closed=False) -> Optional[UILayout]`
* `.panel_prop(owner, prop_name, text="...") -> Optional[UILayout]`
Both create a panel and return `None` if the panel is collapsed. The difference lies
in how the open-close-state is stored. The first method internally manages the
open-close-state based on the provided identifier. The second one allows for
providing a boolean property that stores whether the panel is open. This is useful
when creating a dynamic of panels and when it is difficult to create a unique idname.
For the `.panel(...)` method, a new internal map on `Panel` is created which keeps
track of all the panel states based on the idname. Currently, there is no mechanism
for freeing any elements once they have been added to the map. This is unlikely to
cause a problem anytime soon, but we might need some kind of garbage collection
in the future.
```python
import bpy
from bpy.props import BoolProperty
class LayoutDemoPanel(bpy.types.Panel):
bl_label = "Layout Panel Demo"
bl_idname = "SCENE_PT_layout_panel"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "scene"
def draw(self, context):
layout = self.layout
scene = context.scene
layout.label(text="Before")
if panel := layout.panel("my_panel_id", text="Hello World", default_closed=False):
panel.label(text="Success")
if panel := layout.panel_prop(scene, "show_demo_panel", text="My Panel"):
panel.prop(scene, "frame_start")
panel.prop(scene, "frame_end")
layout.label(text="After")
bpy.utils.register_class(LayoutDemoPanel)
bpy.types.Scene.show_demo_panel = BoolProperty(default=False)
```
Pull Request: https://projects.blender.org/blender/blender/pulls/116949
2024-01-11 19:08:45 +01:00
|
|
|
}
|
|
|
|
|
|
2013-04-04 02:05:11 +00:00
|
|
|
bool uiLayoutGetActive(uiLayout *layout)
|
2009-05-28 23:37:55 +00:00
|
|
|
{
|
2025-04-23 14:54:06 +02:00
|
|
|
return layout->active_;
|
2009-05-28 23:37:55 +00:00
|
|
|
}
|
|
|
|
|
|
2019-03-27 21:39:44 +11:00
|
|
|
bool uiLayoutGetActiveDefault(uiLayout *layout)
|
|
|
|
|
{
|
2025-04-23 14:54:06 +02:00
|
|
|
return layout->active_default_;
|
2019-03-27 21:39:44 +11:00
|
|
|
}
|
|
|
|
|
|
2019-03-20 22:40:38 +11:00
|
|
|
bool uiLayoutGetActivateInit(uiLayout *layout)
|
|
|
|
|
{
|
2025-04-23 14:54:06 +02:00
|
|
|
return layout->activate_init_;
|
2019-03-20 22:40:38 +11:00
|
|
|
}
|
|
|
|
|
|
2013-04-04 02:05:11 +00:00
|
|
|
bool uiLayoutGetEnabled(uiLayout *layout)
|
2009-05-28 23:37:55 +00:00
|
|
|
{
|
2025-04-23 14:54:06 +02:00
|
|
|
return layout->enabled_;
|
2009-05-28 23:37:55 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-04 02:05:11 +00:00
|
|
|
bool uiLayoutGetRedAlert(uiLayout *layout)
|
2009-05-28 23:37:55 +00:00
|
|
|
{
|
2025-04-23 14:54:06 +02:00
|
|
|
return layout->redalert_;
|
2009-05-28 23:37:55 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-04 02:05:11 +00:00
|
|
|
bool uiLayoutGetKeepAspect(uiLayout *layout)
|
2009-05-28 23:37:55 +00:00
|
|
|
{
|
2025-04-23 14:54:06 +02:00
|
|
|
return layout->keepaspect_;
|
2009-05-28 23:37:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int uiLayoutGetAlignment(uiLayout *layout)
|
|
|
|
|
{
|
2025-04-23 14:54:06 +02:00
|
|
|
return layout->alignment_;
|
2009-05-28 23:37:55 +00:00
|
|
|
}
|
|
|
|
|
|
2009-08-16 13:01:40 +00:00
|
|
|
int uiLayoutGetWidth(uiLayout *layout)
|
|
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
return layout->w_;
|
2009-08-16 13:01:40 +00:00
|
|
|
}
|
|
|
|
|
|
2009-06-03 00:04:48 +00:00
|
|
|
float uiLayoutGetScaleX(uiLayout *layout)
|
|
|
|
|
{
|
2025-04-23 14:54:06 +02:00
|
|
|
return layout->scale_[0];
|
2009-06-03 00:04:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float uiLayoutGetScaleY(uiLayout *layout)
|
2009-05-28 23:37:55 +00:00
|
|
|
{
|
2025-04-23 14:54:06 +02:00
|
|
|
return layout->scale_[1];
|
2009-05-28 23:37:55 +00:00
|
|
|
}
|
|
|
|
|
|
2018-09-26 17:44:35 +02:00
|
|
|
float uiLayoutGetUnitsX(uiLayout *layout)
|
2018-09-25 20:59:04 +02:00
|
|
|
{
|
2025-04-23 14:54:06 +02:00
|
|
|
return layout->units_[0];
|
2018-09-25 20:59:04 +02:00
|
|
|
}
|
|
|
|
|
|
2018-09-26 17:44:35 +02:00
|
|
|
float uiLayoutGetUnitsY(uiLayout *layout)
|
2018-09-25 20:59:04 +02:00
|
|
|
{
|
2025-04-23 14:54:06 +02:00
|
|
|
return layout->units_[1];
|
2018-09-25 20:59:04 +02:00
|
|
|
}
|
|
|
|
|
|
2025-03-31 00:36:46 +02:00
|
|
|
blender::ui::EmbossType uiLayoutGetEmboss(uiLayout *layout)
|
2018-05-13 12:57:31 +02:00
|
|
|
{
|
2025-04-23 14:54:06 +02:00
|
|
|
if (layout->emboss_ == blender::ui::EmbossType::Undefined) {
|
2025-04-23 16:37:14 +02:00
|
|
|
return layout->root_->block->emboss;
|
2018-05-13 12:57:31 +02:00
|
|
|
}
|
2025-04-23 14:54:06 +02:00
|
|
|
return layout->emboss_;
|
2018-05-13 12:57:31 +02:00
|
|
|
}
|
|
|
|
|
|
2024-07-29 23:52:38 +02:00
|
|
|
int uiLayoutListItemPaddingWidth()
|
|
|
|
|
{
|
|
|
|
|
return 5 * UI_SCALE_FAC;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void uiLayoutListItemAddPadding(uiLayout *layout)
|
|
|
|
|
{
|
|
|
|
|
uiBlock *block = uiLayoutGetBlock(layout);
|
2025-04-25 19:45:25 +02:00
|
|
|
uiLayout *row = &layout->row(true);
|
2024-07-29 23:52:38 +02:00
|
|
|
uiLayoutSetFixedSize(row, true);
|
|
|
|
|
|
|
|
|
|
uiDefBut(
|
|
|
|
|
block, UI_BTYPE_SEPR, 0, "", 0, 0, uiLayoutListItemPaddingWidth(), 0, nullptr, 0.0, 0.0, "");
|
|
|
|
|
|
|
|
|
|
/* Restore. */
|
|
|
|
|
UI_block_layout_set_current(block, layout);
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-15 11:25:49 -05:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Block Layout Search Filtering
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
/* Disabled for performance reasons, but this could be turned on in the future. */
|
|
|
|
|
// #define PROPERTY_SEARCH_USE_TOOLTIPS
|
|
|
|
|
|
2020-09-24 11:22:30 -05:00
|
|
|
static bool block_search_panel_label_matches(const uiBlock *block, const char *search_string)
|
2020-09-15 11:25:49 -05:00
|
|
|
{
|
2022-11-25 23:48:02 -06:00
|
|
|
if ((block->panel != nullptr) && (block->panel->type != nullptr)) {
|
2020-09-24 11:22:30 -05:00
|
|
|
if (BLI_strcasestr(block->panel->type->label, search_string)) {
|
2020-09-15 11:25:49 -05:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns true if a button or the data / operator it represents matches the search filter.
|
|
|
|
|
*/
|
|
|
|
|
static bool button_matches_search_filter(uiBut *but, const char *search_filter)
|
|
|
|
|
{
|
|
|
|
|
/* Do the shorter checks first for better performance in case there is a match. */
|
2024-01-16 21:04:17 +01:00
|
|
|
if (BLI_strcasestr(but->str.c_str(), search_filter)) {
|
2020-09-15 11:25:49 -05:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-25 23:48:02 -06:00
|
|
|
if (but->optype != nullptr) {
|
2020-09-15 11:25:49 -05:00
|
|
|
if (BLI_strcasestr(but->optype->name, search_filter)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-25 23:48:02 -06:00
|
|
|
if (but->rnaprop != nullptr) {
|
2020-09-15 11:25:49 -05:00
|
|
|
if (BLI_strcasestr(RNA_property_ui_name(but->rnaprop), search_filter)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
#ifdef PROPERTY_SEARCH_USE_TOOLTIPS
|
|
|
|
|
if (BLI_strcasestr(RNA_property_description(but->rnaprop), search_filter)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2020-09-16 15:28:02 +10:00
|
|
|
/* Search through labels of enum property items if they are in a drop-down menu.
|
2020-09-15 11:25:49 -05:00
|
|
|
* Unfortunately we have no #bContext here so we cannot search through RNA enums
|
|
|
|
|
* with dynamic entries (or "itemf" functions) which require context. */
|
|
|
|
|
if (but->type == UI_BTYPE_MENU) {
|
|
|
|
|
PointerRNA *ptr = &but->rnapoin;
|
|
|
|
|
PropertyRNA *enum_prop = but->rnaprop;
|
|
|
|
|
int items_len;
|
2022-11-25 23:48:02 -06:00
|
|
|
const EnumPropertyItem *items_array = nullptr;
|
2020-09-15 11:25:49 -05:00
|
|
|
bool free;
|
2022-11-25 23:48:02 -06:00
|
|
|
RNA_property_enum_items_gettexted(nullptr, ptr, enum_prop, &items_array, &items_len, &free);
|
|
|
|
|
if (items_array == nullptr) {
|
2020-09-15 11:25:49 -05:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-10 14:21:04 +11:00
|
|
|
bool found = false;
|
2020-09-15 11:25:49 -05:00
|
|
|
for (int i = 0; i < items_len; i++) {
|
2022-11-25 23:48:02 -06:00
|
|
|
/* Check for nullptr name field which enums use for separators. */
|
|
|
|
|
if (items_array[i].name == nullptr) {
|
2020-09-16 13:05:28 -05:00
|
|
|
continue;
|
|
|
|
|
}
|
2020-09-15 11:25:49 -05:00
|
|
|
if (BLI_strcasestr(items_array[i].name, search_filter)) {
|
2024-01-10 14:21:04 +11:00
|
|
|
found = true;
|
|
|
|
|
break;
|
2020-09-15 11:25:49 -05:00
|
|
|
}
|
|
|
|
|
}
|
2024-01-10 14:21:04 +11:00
|
|
|
if (free) {
|
|
|
|
|
MEM_freeN((EnumPropertyItem *)items_array);
|
|
|
|
|
}
|
|
|
|
|
if (found) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2020-09-15 11:25:49 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Test for a search result within a specific button group.
|
|
|
|
|
*/
|
2022-12-18 21:45:32 -06:00
|
|
|
static bool button_group_has_search_match(const uiButtonGroup &group, const char *search_filter)
|
2020-09-15 11:25:49 -05:00
|
|
|
{
|
2022-12-18 21:45:32 -06:00
|
|
|
for (uiBut *but : group.buttons) {
|
2020-09-15 11:25:49 -05:00
|
|
|
if (button_matches_search_filter(but, search_filter)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Apply the search filter, tagging all buttons with whether they match or not.
|
|
|
|
|
* Tag every button in the group as a result if any button in the group matches.
|
|
|
|
|
*
|
|
|
|
|
* \note It would be great to return early here if we found a match, but because
|
|
|
|
|
* the results may be visible we have to continue searching the entire block.
|
|
|
|
|
*
|
|
|
|
|
* \return True if the block has any search results.
|
|
|
|
|
*/
|
2020-09-24 11:22:30 -05:00
|
|
|
static bool block_search_filter_tag_buttons(uiBlock *block, const char *search_filter)
|
2020-09-15 11:25:49 -05:00
|
|
|
{
|
|
|
|
|
bool has_result = false;
|
2022-12-18 21:45:32 -06:00
|
|
|
for (const uiButtonGroup &group : block->button_groups) {
|
|
|
|
|
if (button_group_has_search_match(group, search_filter)) {
|
2020-10-02 17:00:41 -05:00
|
|
|
has_result = true;
|
|
|
|
|
}
|
|
|
|
|
else {
|
2022-12-18 21:45:32 -06:00
|
|
|
for (uiBut *but : group.buttons) {
|
2020-10-02 17:00:41 -05:00
|
|
|
but->flag |= UI_SEARCH_FILTER_NO_MATCH;
|
2020-09-15 11:25:49 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return has_result;
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-24 11:22:30 -05:00
|
|
|
bool UI_block_apply_search_filter(uiBlock *block, const char *search_filter)
|
2020-09-15 11:25:49 -05:00
|
|
|
{
|
2022-11-25 23:48:02 -06:00
|
|
|
if (search_filter == nullptr || search_filter[0] == '\0') {
|
2020-09-15 11:25:49 -05:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-17 10:28:57 -05:00
|
|
|
Panel *panel = block->panel;
|
|
|
|
|
|
2024-04-25 12:02:14 +10:00
|
|
|
if (panel != nullptr) {
|
|
|
|
|
/* Panels for active blocks should always have a valid `panel->type`,
|
|
|
|
|
* otherwise they wouldn't be created. */
|
2020-11-17 10:28:57 -05:00
|
|
|
if (panel->type->flag & PANEL_TYPE_NO_SEARCH) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2020-11-17 10:07:38 -05:00
|
|
|
}
|
|
|
|
|
|
2020-09-24 11:22:30 -05:00
|
|
|
const bool panel_label_matches = block_search_panel_label_matches(block, search_filter);
|
2020-09-15 11:25:49 -05:00
|
|
|
|
2020-09-24 11:22:30 -05:00
|
|
|
const bool has_result = (panel_label_matches) ?
|
|
|
|
|
true :
|
|
|
|
|
block_search_filter_tag_buttons(block, search_filter);
|
2020-09-15 11:25:49 -05:00
|
|
|
|
2022-11-25 23:48:02 -06:00
|
|
|
if (panel != nullptr) {
|
2020-09-23 16:24:20 -05:00
|
|
|
if (has_result) {
|
|
|
|
|
ui_panel_tag_search_filter_match(block->panel);
|
|
|
|
|
}
|
2020-09-15 11:25:49 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return has_result;
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-06 16:12:47 +10:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Layout
|
|
|
|
|
* \{ */
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
|
2013-05-08 12:54:33 +00:00
|
|
|
static void ui_item_scale(uiLayout *litem, const float scale[2])
|
2009-06-03 00:04:48 +00:00
|
|
|
{
|
|
|
|
|
int x, y, w, h;
|
|
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
for (auto riter = litem->items_.rbegin(); riter != litem->items_.rend(); riter++) {
|
2024-07-10 14:46:06 +02:00
|
|
|
uiItem *item = *riter;
|
2025-04-24 17:22:28 +02:00
|
|
|
if (item->type_ != uiItemType::Button) {
|
2024-07-10 14:46:06 +02:00
|
|
|
uiLayout *subitem = static_cast<uiLayout *>(item);
|
2018-06-26 11:57:22 +02:00
|
|
|
ui_item_scale(subitem, scale);
|
|
|
|
|
}
|
|
|
|
|
|
2009-06-03 00:04:48 +00:00
|
|
|
ui_item_size(item, &w, &h);
|
|
|
|
|
ui_item_offset(item, &x, &y);
|
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (scale[0] != 0.0f) {
|
2009-06-03 00:04:48 +00:00
|
|
|
x *= scale[0];
|
|
|
|
|
w *= scale[0];
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (scale[1] != 0.0f) {
|
2009-06-03 00:04:48 +00:00
|
|
|
y *= scale[1];
|
|
|
|
|
h *= scale[1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ui_item_position(item, x, y, w, h);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
static void ui_item_estimate(uiItem *item)
|
2009-03-13 13:38:41 +00:00
|
|
|
{
|
2025-04-24 17:22:28 +02:00
|
|
|
if (item->type_ != uiItemType::Button) {
|
2024-07-10 14:46:06 +02:00
|
|
|
uiLayout *litem = static_cast<uiLayout *>(item);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
if (litem->items_.is_empty()) {
|
|
|
|
|
litem->w_ = 0;
|
|
|
|
|
litem->h_ = 0;
|
2009-05-19 17:13:33 +00:00
|
|
|
return;
|
2017-08-08 15:52:14 +03:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
for (uiItem *subitem : litem->items_) {
|
2024-07-10 14:46:06 +02:00
|
|
|
ui_item_estimate(subitem);
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-23 14:54:06 +02:00
|
|
|
if (litem->scale_[0] != 0.0f || litem->scale_[1] != 0.0f) {
|
|
|
|
|
ui_item_scale(litem, litem->scale_);
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-24 17:22:28 +02:00
|
|
|
switch (litem->type_) {
|
2025-03-31 15:30:58 +02:00
|
|
|
case uiItemType::LayoutColumn:
|
2017-03-26 18:02:11 +03:00
|
|
|
ui_litem_estimate_column(litem, false);
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
break;
|
2025-03-31 15:30:58 +02:00
|
|
|
case uiItemType::LayoutColumnFlow:
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
ui_litem_estimate_column_flow(litem);
|
2009-04-16 12:17:58 +00:00
|
|
|
break;
|
2025-03-31 15:30:58 +02:00
|
|
|
case uiItemType::LayoutGridFlow:
|
2018-06-09 16:50:05 +02:00
|
|
|
ui_litem_estimate_grid_flow(litem);
|
|
|
|
|
break;
|
2025-03-31 15:30:58 +02:00
|
|
|
case uiItemType::LayoutRow:
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
ui_litem_estimate_row(litem);
|
|
|
|
|
break;
|
2025-03-31 15:30:58 +02:00
|
|
|
case uiItemType::LayoutPanelHeader:
|
UI: add support for uiLayout based panels
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 initial use case for this are panels in the geometry nodes modifier. This patch provides
a better solution compared to what was attempted in #108565.
### Problems with Existing Approaches
Currently, there are two ways to create these expandable sections:
* One can define a new `Panel` type for each expandable section and use the `parent_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.
* It does not work so well for dynamic amounts of panels (e.g. like what we need for
the geometry nodes modifier to organize the inputs).
* Typically, Blender uses a immediate-ui approach, but subpanels break that currently
and need extra handling.
* The order of panels is not very explicit.
* One can't interleave subpanels and other ui elements, subpanels always come at the
end of the parent panel.
* Custom solution using existing `uiLayout`. This is done in the material properties. It
also has a few problems:
* Custom solutions tend to work slightly different in different places. So the UI is less unified.
* Can't drag open/close multiple panels.
* The background color for subpanels does not change.
### Solution
A possible solution to all of these problems is to add support for panels to `uiLayout` directly:
```cpp
/* Add elements before subpanel. */
if (uiLayout *panel_layout = uiLayoutPanel(layout, ...)) {
/* Add elements in subpanel, but only of the panel is open. */
}
/* Add elements after subpanel. */
```
Integrating subpanels with `uiLayout` has some benefits:
* Subpanels are treated like any other sub-layout and don't have unnecessary boilerplate.
* It becomes trivial to have a dynamic number of potentially nested subpanels.
* Resolves all mentioned problems of custom subpanel solutions.
### 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 negligible. Therefor, a much simpler solution
is possible: the open/close state can be stored in the modifier directly. This is actually
how it was implemented before 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 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 (not included)
Adding a Python API is fairly straight forward. 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:
```python
if panel := layout.panel("Mesh Settings", ...):
# Add layout elements in the panel if it's open.
```
Pull Request: https://projects.blender.org/blender/blender/pulls/113584
2023-12-22 17:57:57 +01:00
|
|
|
ui_litem_estimate_panel_header(litem);
|
|
|
|
|
break;
|
2025-03-31 15:30:58 +02:00
|
|
|
case uiItemType::LayoutPanelBody:
|
UI: add support for uiLayout based panels
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 initial use case for this are panels in the geometry nodes modifier. This patch provides
a better solution compared to what was attempted in #108565.
### Problems with Existing Approaches
Currently, there are two ways to create these expandable sections:
* One can define a new `Panel` type for each expandable section and use the `parent_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.
* It does not work so well for dynamic amounts of panels (e.g. like what we need for
the geometry nodes modifier to organize the inputs).
* Typically, Blender uses a immediate-ui approach, but subpanels break that currently
and need extra handling.
* The order of panels is not very explicit.
* One can't interleave subpanels and other ui elements, subpanels always come at the
end of the parent panel.
* Custom solution using existing `uiLayout`. This is done in the material properties. It
also has a few problems:
* Custom solutions tend to work slightly different in different places. So the UI is less unified.
* Can't drag open/close multiple panels.
* The background color for subpanels does not change.
### Solution
A possible solution to all of these problems is to add support for panels to `uiLayout` directly:
```cpp
/* Add elements before subpanel. */
if (uiLayout *panel_layout = uiLayoutPanel(layout, ...)) {
/* Add elements in subpanel, but only of the panel is open. */
}
/* Add elements after subpanel. */
```
Integrating subpanels with `uiLayout` has some benefits:
* Subpanels are treated like any other sub-layout and don't have unnecessary boilerplate.
* It becomes trivial to have a dynamic number of potentially nested subpanels.
* Resolves all mentioned problems of custom subpanel solutions.
### 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 negligible. Therefor, a much simpler solution
is possible: the open/close state can be stored in the modifier directly. This is actually
how it was implemented before 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 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 (not included)
Adding a Python API is fairly straight forward. 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:
```python
if panel := layout.panel("Mesh Settings", ...):
# Add layout elements in the panel if it's open.
```
Pull Request: https://projects.blender.org/blender/blender/pulls/113584
2023-12-22 17:57:57 +01:00
|
|
|
ui_litem_estimate_panel_body(litem);
|
|
|
|
|
break;
|
2025-03-31 15:30:58 +02:00
|
|
|
case uiItemType::LayoutBox:
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
ui_litem_estimate_box(litem);
|
|
|
|
|
break;
|
2025-03-31 15:30:58 +02:00
|
|
|
case uiItemType::LayoutRoot:
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
ui_litem_estimate_root(litem);
|
|
|
|
|
break;
|
2025-03-31 15:30:58 +02:00
|
|
|
case uiItemType::LayoutAbsolute:
|
2009-10-09 10:45:11 +00:00
|
|
|
ui_litem_estimate_absolute(litem);
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
break;
|
2025-03-31 15:30:58 +02:00
|
|
|
case uiItemType::LayoutSplit:
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
ui_litem_estimate_split(litem);
|
2009-04-16 12:17:58 +00:00
|
|
|
break;
|
2025-03-31 15:30:58 +02:00
|
|
|
case uiItemType::LayoutOverlap:
|
2009-10-21 20:58:10 +00:00
|
|
|
ui_litem_estimate_overlap(litem);
|
|
|
|
|
break;
|
2009-04-16 12:17:58 +00:00
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-09-26 17:44:35 +02:00
|
|
|
/* Force fixed size. */
|
2025-04-23 14:54:06 +02:00
|
|
|
if (litem->units_[0] > 0) {
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->w_ = UI_UNIT_X * litem->units_[0];
|
2018-09-25 20:59:04 +02:00
|
|
|
}
|
2025-04-23 14:54:06 +02:00
|
|
|
if (litem->units_[1] > 0) {
|
2025-04-23 16:37:14 +02:00
|
|
|
litem->h_ = UI_UNIT_Y * litem->units_[1];
|
2018-09-25 20:59:04 +02:00
|
|
|
}
|
2009-04-16 12:17:58 +00:00
|
|
|
}
|
2009-03-13 13:38:41 +00:00
|
|
|
}
|
|
|
|
|
|
2011-10-03 01:01:01 +00:00
|
|
|
static void ui_item_align(uiLayout *litem, short nr)
|
2009-03-13 13:38:41 +00:00
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
for (auto riter = litem->items_.rbegin(); riter != litem->items_.rend(); riter++) {
|
2024-07-10 14:46:06 +02:00
|
|
|
uiItem *item = *riter;
|
2025-04-24 17:22:28 +02:00
|
|
|
if (item->type_ == uiItemType::Button) {
|
2024-07-10 14:46:06 +02:00
|
|
|
uiButtonItem *bitem = static_cast<uiButtonItem *>(item);
|
2015-11-06 18:39:56 +01:00
|
|
|
#ifndef USE_UIBUT_SPATIAL_ALIGN
|
2012-03-24 06:38:07 +00:00
|
|
|
if (ui_but_can_align(bitem->but))
|
2015-11-06 18:39:56 +01:00
|
|
|
#endif
|
2015-11-07 17:36:10 +11:00
|
|
|
{
|
|
|
|
|
if (!bitem->but->alignnr) {
|
2012-03-30 01:51:25 +00:00
|
|
|
bitem->but->alignnr = nr;
|
2015-11-07 17:36:10 +11:00
|
|
|
}
|
|
|
|
|
}
|
2009-05-19 17:13:33 +00:00
|
|
|
}
|
2025-04-24 17:22:28 +02:00
|
|
|
else if (item->type_ == uiItemType::LayoutAbsolute) {
|
2012-10-07 09:48:59 +00:00
|
|
|
/* pass */
|
|
|
|
|
}
|
2025-04-24 17:22:28 +02:00
|
|
|
else if (item->type_ == uiItemType::LayoutOverlap) {
|
2012-10-07 09:48:59 +00:00
|
|
|
/* pass */
|
|
|
|
|
}
|
2025-04-24 17:22:28 +02:00
|
|
|
else if (item->type_ == uiItemType::LayoutBox) {
|
2024-07-10 14:46:06 +02:00
|
|
|
uiLayoutItemBx *box = static_cast<uiLayoutItemBx *>(item);
|
2017-03-26 18:02:11 +03:00
|
|
|
if (!box->roundbox->alignnr) {
|
|
|
|
|
box->roundbox->alignnr = nr;
|
|
|
|
|
}
|
2009-05-21 15:34:09 +00:00
|
|
|
}
|
2024-07-10 14:46:06 +02:00
|
|
|
else {
|
|
|
|
|
uiLayout *litem = static_cast<uiLayout *>(item);
|
2025-04-23 14:54:06 +02:00
|
|
|
if (litem->align_) {
|
2024-07-10 14:46:06 +02:00
|
|
|
ui_item_align(litem, nr);
|
|
|
|
|
}
|
2013-08-23 16:53:37 +00:00
|
|
|
}
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
}
|
2009-03-13 13:38:41 +00:00
|
|
|
}
|
|
|
|
|
|
2022-05-12 15:53:12 +02:00
|
|
|
static void ui_item_flag(uiLayout *litem, int flag)
|
2009-05-28 23:37:55 +00:00
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
for (auto riter = litem->items_.rbegin(); riter != litem->items_.rend(); riter++) {
|
2024-07-10 14:46:06 +02:00
|
|
|
uiItem *item = *riter;
|
2025-04-24 17:22:28 +02:00
|
|
|
if (item->type_ == uiItemType::Button) {
|
2024-07-10 14:46:06 +02:00
|
|
|
uiButtonItem *bitem = static_cast<uiButtonItem *>(item);
|
2009-05-28 23:37:55 +00:00
|
|
|
bitem->but->flag |= flag;
|
|
|
|
|
}
|
2019-03-26 21:16:13 +11:00
|
|
|
else {
|
2024-07-10 14:46:06 +02:00
|
|
|
ui_item_flag(static_cast<uiLayout *>(item), flag);
|
2019-03-26 21:16:13 +11:00
|
|
|
}
|
2009-05-28 23:37:55 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-05-27 00:03:49 +00:00
|
|
|
static void ui_item_layout(uiItem *item)
|
2009-03-13 13:38:41 +00:00
|
|
|
{
|
2025-04-24 17:22:28 +02:00
|
|
|
if (item->type_ != uiItemType::Button) {
|
2024-07-10 14:46:06 +02:00
|
|
|
uiLayout *litem = static_cast<uiLayout *>(item);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
if (litem->items_.is_empty()) {
|
2009-05-19 17:13:33 +00:00
|
|
|
return;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-23 14:54:06 +02:00
|
|
|
if (litem->align_) {
|
2025-04-23 16:37:14 +02:00
|
|
|
ui_item_align(litem, ++litem->root_->block->alignnr);
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2025-04-23 14:54:06 +02:00
|
|
|
if (!litem->active_) {
|
2009-05-28 23:37:55 +00:00
|
|
|
ui_item_flag(litem, UI_BUT_INACTIVE);
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2025-04-23 14:54:06 +02:00
|
|
|
if (!litem->enabled_) {
|
2009-05-28 23:37:55 +00:00
|
|
|
ui_item_flag(litem, UI_BUT_DISABLED);
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-24 17:22:28 +02:00
|
|
|
switch (litem->type_) {
|
2025-03-31 15:30:58 +02:00
|
|
|
case uiItemType::LayoutColumn:
|
2020-09-15 12:25:15 -06:00
|
|
|
ui_litem_layout_column(litem, false, false);
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
break;
|
2025-03-31 15:30:58 +02:00
|
|
|
case uiItemType::LayoutColumnFlow:
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
ui_litem_layout_column_flow(litem);
|
|
|
|
|
break;
|
2025-03-31 15:30:58 +02:00
|
|
|
case uiItemType::LayoutGridFlow:
|
2018-06-09 16:50:05 +02:00
|
|
|
ui_litem_layout_grid_flow(litem);
|
|
|
|
|
break;
|
2025-03-31 15:30:58 +02:00
|
|
|
case uiItemType::LayoutRow:
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
ui_litem_layout_row(litem);
|
|
|
|
|
break;
|
2025-03-31 15:30:58 +02:00
|
|
|
case uiItemType::LayoutPanelHeader:
|
UI: add support for uiLayout based panels
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 initial use case for this are panels in the geometry nodes modifier. This patch provides
a better solution compared to what was attempted in #108565.
### Problems with Existing Approaches
Currently, there are two ways to create these expandable sections:
* One can define a new `Panel` type for each expandable section and use the `parent_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.
* It does not work so well for dynamic amounts of panels (e.g. like what we need for
the geometry nodes modifier to organize the inputs).
* Typically, Blender uses a immediate-ui approach, but subpanels break that currently
and need extra handling.
* The order of panels is not very explicit.
* One can't interleave subpanels and other ui elements, subpanels always come at the
end of the parent panel.
* Custom solution using existing `uiLayout`. This is done in the material properties. It
also has a few problems:
* Custom solutions tend to work slightly different in different places. So the UI is less unified.
* Can't drag open/close multiple panels.
* The background color for subpanels does not change.
### Solution
A possible solution to all of these problems is to add support for panels to `uiLayout` directly:
```cpp
/* Add elements before subpanel. */
if (uiLayout *panel_layout = uiLayoutPanel(layout, ...)) {
/* Add elements in subpanel, but only of the panel is open. */
}
/* Add elements after subpanel. */
```
Integrating subpanels with `uiLayout` has some benefits:
* Subpanels are treated like any other sub-layout and don't have unnecessary boilerplate.
* It becomes trivial to have a dynamic number of potentially nested subpanels.
* Resolves all mentioned problems of custom subpanel solutions.
### 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 negligible. Therefor, a much simpler solution
is possible: the open/close state can be stored in the modifier directly. This is actually
how it was implemented before 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 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 (not included)
Adding a Python API is fairly straight forward. 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:
```python
if panel := layout.panel("Mesh Settings", ...):
# Add layout elements in the panel if it's open.
```
Pull Request: https://projects.blender.org/blender/blender/pulls/113584
2023-12-22 17:57:57 +01:00
|
|
|
ui_litem_layout_panel_header(litem);
|
|
|
|
|
break;
|
2025-03-31 15:30:58 +02:00
|
|
|
case uiItemType::LayoutPanelBody:
|
UI: add support for uiLayout based panels
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 initial use case for this are panels in the geometry nodes modifier. This patch provides
a better solution compared to what was attempted in #108565.
### Problems with Existing Approaches
Currently, there are two ways to create these expandable sections:
* One can define a new `Panel` type for each expandable section and use the `parent_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.
* It does not work so well for dynamic amounts of panels (e.g. like what we need for
the geometry nodes modifier to organize the inputs).
* Typically, Blender uses a immediate-ui approach, but subpanels break that currently
and need extra handling.
* The order of panels is not very explicit.
* One can't interleave subpanels and other ui elements, subpanels always come at the
end of the parent panel.
* Custom solution using existing `uiLayout`. This is done in the material properties. It
also has a few problems:
* Custom solutions tend to work slightly different in different places. So the UI is less unified.
* Can't drag open/close multiple panels.
* The background color for subpanels does not change.
### Solution
A possible solution to all of these problems is to add support for panels to `uiLayout` directly:
```cpp
/* Add elements before subpanel. */
if (uiLayout *panel_layout = uiLayoutPanel(layout, ...)) {
/* Add elements in subpanel, but only of the panel is open. */
}
/* Add elements after subpanel. */
```
Integrating subpanels with `uiLayout` has some benefits:
* Subpanels are treated like any other sub-layout and don't have unnecessary boilerplate.
* It becomes trivial to have a dynamic number of potentially nested subpanels.
* Resolves all mentioned problems of custom subpanel solutions.
### 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 negligible. Therefor, a much simpler solution
is possible: the open/close state can be stored in the modifier directly. This is actually
how it was implemented before 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 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 (not included)
Adding a Python API is fairly straight forward. 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:
```python
if panel := layout.panel("Mesh Settings", ...):
# Add layout elements in the panel if it's open.
```
Pull Request: https://projects.blender.org/blender/blender/pulls/113584
2023-12-22 17:57:57 +01:00
|
|
|
ui_litem_layout_panel_body(litem);
|
|
|
|
|
break;
|
2025-03-31 15:30:58 +02:00
|
|
|
case uiItemType::LayoutBox:
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
ui_litem_layout_box(litem);
|
|
|
|
|
break;
|
2025-03-31 15:30:58 +02:00
|
|
|
case uiItemType::LayoutRoot:
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
ui_litem_layout_root(litem);
|
|
|
|
|
break;
|
2025-03-31 15:30:58 +02:00
|
|
|
case uiItemType::LayoutAbsolute:
|
2009-10-09 10:45:11 +00:00
|
|
|
ui_litem_layout_absolute(litem);
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
break;
|
2025-03-31 15:30:58 +02:00
|
|
|
case uiItemType::LayoutSplit:
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
ui_litem_layout_split(litem);
|
|
|
|
|
break;
|
2025-03-31 15:30:58 +02:00
|
|
|
case uiItemType::LayoutOverlap:
|
2009-10-21 20:58:10 +00:00
|
|
|
ui_litem_layout_overlap(litem);
|
|
|
|
|
break;
|
2025-03-31 15:30:58 +02:00
|
|
|
case uiItemType::LayoutRadial:
|
Pie Menus C code backend.
This commit merges the code in the pie-menu branch.
As per decisions taken the last few days, there are no pie menus
included and there will be an official add-on including overrides of
some keys with pie menus. However, people will now be able to use the
new code in python.
Full Documentation is in http://wiki.blender.org/index.php/Dev:Ref/
Thanks:
Campbell Barton, Dalai Felinto and Ton Roosendaal for the code review
and design comments
Jonathan Williamson, Pawel Lyczkowski, Pablo Vazquez among others for
suggestions during the development.
Special Thanks to Sean Olson, for his support, suggestions, testing and
merciless bugging so that I would finish the pie menu code. Without him
we wouldn't be here. Also to the rest of the developers of the original
python add-on, Patrick Moore and Dan Eicher and finally to Matt Ebb, who
did the research and first implementation and whose code I used to get
started.
2014-08-11 10:39:59 +02:00
|
|
|
ui_litem_layout_radial(litem);
|
|
|
|
|
break;
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
for (uiItem *subitem : litem->items_) {
|
2025-04-24 17:22:28 +02:00
|
|
|
if (bool(item->flag_ & uiItemInternalFlag::BoxItem)) {
|
|
|
|
|
subitem->flag_ |= uiItemInternalFlag::BoxItem;
|
2017-07-27 11:44:51 +02:00
|
|
|
}
|
2009-05-27 00:03:49 +00:00
|
|
|
ui_item_layout(subitem);
|
2017-07-27 10:27:29 +03:00
|
|
|
}
|
2017-07-27 11:44:51 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2025-04-24 17:22:28 +02:00
|
|
|
if (bool(item->flag_ & uiItemInternalFlag::BoxItem)) {
|
2024-07-10 14:46:06 +02:00
|
|
|
uiButtonItem *bitem = static_cast<uiButtonItem *>(item);
|
2017-07-27 10:27:29 +03:00
|
|
|
bitem->but->drawflag |= UI_BUT_BOX_ITEM;
|
|
|
|
|
}
|
2009-04-22 18:39:44 +00:00
|
|
|
}
|
2009-04-11 01:52:27 +00:00
|
|
|
}
|
|
|
|
|
|
2019-03-25 12:19:55 +11:00
|
|
|
static void ui_layout_end(uiBlock *block, uiLayout *layout, int *r_x, int *r_y)
|
2009-04-22 18:39:44 +00:00
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
if (layout->root_->handlefunc) {
|
|
|
|
|
UI_block_func_handle_set(block, layout->root_->handlefunc, layout->root_->argv);
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2009-04-22 18:39:44 +00:00
|
|
|
|
2024-07-10 14:46:06 +02:00
|
|
|
ui_item_estimate(layout);
|
|
|
|
|
ui_item_layout(layout);
|
2009-04-22 18:39:44 +00:00
|
|
|
|
2019-03-25 12:19:55 +11:00
|
|
|
if (r_x) {
|
2025-04-23 16:37:14 +02:00
|
|
|
*r_x = layout->x_;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2019-03-25 12:19:55 +11:00
|
|
|
if (r_y) {
|
2025-04-23 16:37:14 +02:00
|
|
|
*r_y = layout->y_;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
}
|
2009-04-22 18:39:44 +00:00
|
|
|
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
static void ui_layout_free(uiLayout *layout)
|
|
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
for (uiItem *item : layout->items_) {
|
2025-04-24 17:22:28 +02:00
|
|
|
if (item->type_ == uiItemType::Button) {
|
2024-07-10 14:46:06 +02:00
|
|
|
uiButtonItem *bitem = static_cast<uiButtonItem *>(item);
|
2020-09-28 12:04:39 +02:00
|
|
|
|
2022-11-25 23:48:02 -06:00
|
|
|
bitem->but->layout = nullptr;
|
2024-07-10 14:46:06 +02:00
|
|
|
MEM_delete(item);
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
|
|
|
|
else {
|
2024-07-10 14:46:06 +02:00
|
|
|
uiLayout *litem = static_cast<uiLayout *>(item);
|
|
|
|
|
ui_layout_free(litem);
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2009-04-22 18:39:44 +00:00
|
|
|
}
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
|
2024-07-10 14:46:06 +02:00
|
|
|
MEM_delete(layout);
|
2009-04-22 18:39:44 +00:00
|
|
|
}
|
|
|
|
|
|
2014-01-17 00:23:00 +01:00
|
|
|
static void ui_layout_add_padding_button(uiLayoutRoot *root)
|
|
|
|
|
{
|
|
|
|
|
if (root->padding) {
|
|
|
|
|
/* add an invisible button for padding */
|
|
|
|
|
uiBlock *block = root->block;
|
|
|
|
|
uiLayout *prev_layout = block->curlayout;
|
|
|
|
|
|
|
|
|
|
block->curlayout = root->layout;
|
2024-03-01 14:26:45 -05:00
|
|
|
uiDefBut(
|
|
|
|
|
block, UI_BTYPE_SEPR, 0, "", 0, 0, root->padding, root->padding, nullptr, 0.0, 0.0, "");
|
2014-01-17 00:23:00 +01:00
|
|
|
block->curlayout = prev_layout;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-15 17:32:25 +11:00
|
|
|
uiLayout *UI_block_layout(uiBlock *block,
|
|
|
|
|
int dir,
|
|
|
|
|
int type,
|
|
|
|
|
int x,
|
|
|
|
|
int y,
|
|
|
|
|
int size,
|
|
|
|
|
int em,
|
|
|
|
|
int padding,
|
|
|
|
|
const uiStyle *style)
|
2009-03-13 13:38:41 +00:00
|
|
|
{
|
2025-03-05 16:35:09 +01:00
|
|
|
uiLayoutRoot *root = MEM_callocN<uiLayoutRoot>(__func__);
|
2012-03-30 01:51:25 +00:00
|
|
|
root->type = type;
|
|
|
|
|
root->style = style;
|
|
|
|
|
root->block = block;
|
2014-01-17 00:23:00 +01:00
|
|
|
root->padding = padding;
|
2012-03-30 01:51:25 +00:00
|
|
|
root->opcontext = WM_OP_INVOKE_REGION_WIN;
|
2009-04-22 18:39:44 +00:00
|
|
|
|
2024-07-10 14:46:06 +02:00
|
|
|
uiLayout *layout = MEM_new<uiLayout>(__func__);
|
2025-04-24 17:22:28 +02:00
|
|
|
layout->type_ = (type == UI_LAYOUT_VERT_BAR) ? uiItemType::LayoutColumn : uiItemType::LayoutRoot;
|
2009-03-13 13:38:41 +00:00
|
|
|
|
2025-03-31 18:23:16 +02:00
|
|
|
/* Only used when 'uiItemInternalFlag::PropSep' is set. */
|
2025-04-24 17:22:28 +02:00
|
|
|
layout->flag_ = uiItemInternalFlag::PropDecorate;
|
2018-06-16 14:48:21 +02:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
layout->x_ = x;
|
|
|
|
|
layout->y_ = y;
|
|
|
|
|
layout->root_ = root;
|
2025-04-23 14:54:06 +02:00
|
|
|
layout->space_ = style->templatespace;
|
|
|
|
|
layout->active_ = true;
|
|
|
|
|
layout->enabled_ = true;
|
2025-04-23 16:37:14 +02:00
|
|
|
layout->context_ = nullptr;
|
2025-04-23 14:54:06 +02:00
|
|
|
layout->emboss_ = blender::ui::EmbossType::Undefined;
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
|
2020-11-06 12:30:59 +11:00
|
|
|
if (ELEM(type, UI_LAYOUT_MENU, UI_LAYOUT_PIEMENU)) {
|
2025-04-23 14:54:06 +02:00
|
|
|
layout->space_ = 0;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (dir == UI_LAYOUT_HORIZONTAL) {
|
2025-04-23 16:37:14 +02:00
|
|
|
layout->h_ = size;
|
|
|
|
|
layout->root_->emh = em * UI_UNIT_Y;
|
2009-05-19 17:13:33 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2025-04-23 16:37:14 +02:00
|
|
|
layout->w_ = size;
|
|
|
|
|
layout->root_->emw = em * UI_UNIT_X;
|
2009-03-13 13:38:41 +00:00
|
|
|
}
|
2009-05-19 17:13:33 +00:00
|
|
|
|
2012-03-30 01:51:25 +00:00
|
|
|
block->curlayout = layout;
|
|
|
|
|
root->layout = layout;
|
2009-05-19 17:13:33 +00:00
|
|
|
BLI_addtail(&block->layouts, root);
|
2014-01-17 00:23:00 +01:00
|
|
|
|
|
|
|
|
ui_layout_add_padding_button(root);
|
2018-05-23 10:47:12 +02:00
|
|
|
|
2009-05-19 17:13:33 +00:00
|
|
|
return layout;
|
2009-03-13 13:38:41 +00:00
|
|
|
}
|
|
|
|
|
|
2009-05-28 23:37:55 +00:00
|
|
|
uiBlock *uiLayoutGetBlock(uiLayout *layout)
|
2009-03-13 13:38:41 +00:00
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
return layout->root_->block;
|
2009-03-13 13:38:41 +00:00
|
|
|
}
|
|
|
|
|
|
2023-06-18 01:39:21 +02:00
|
|
|
wmOperatorCallContext uiLayoutGetOperatorContext(uiLayout *layout)
|
2009-06-09 10:30:11 +00:00
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
return layout->root_->opcontext;
|
2009-06-09 10:30:11 +00:00
|
|
|
}
|
|
|
|
|
|
2014-11-09 21:20:40 +01:00
|
|
|
void UI_block_layout_set_current(uiBlock *block, uiLayout *layout)
|
2009-03-13 13:38:41 +00:00
|
|
|
{
|
2012-03-30 01:51:25 +00:00
|
|
|
block->curlayout = layout;
|
2009-03-13 13:38:41 +00:00
|
|
|
}
|
|
|
|
|
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
void ui_layout_add_but(uiLayout *layout, uiBut *but)
|
2009-03-13 13:38:41 +00:00
|
|
|
{
|
2024-07-10 14:46:06 +02:00
|
|
|
uiButtonItem *bitem = MEM_new<uiButtonItem>(__func__);
|
2025-04-24 17:22:28 +02:00
|
|
|
bitem->type_ = uiItemType::Button;
|
2012-03-30 01:51:25 +00:00
|
|
|
bitem->but = but;
|
2017-02-02 17:30:50 +03:00
|
|
|
|
|
|
|
|
int w, h;
|
|
|
|
|
ui_item_size((uiItem *)bitem, &w, &h);
|
|
|
|
|
/* XXX uiBut hasn't scaled yet
|
|
|
|
|
* we can flag the button as not expandable, depending on its size */
|
2024-01-16 21:04:17 +01:00
|
|
|
if (w <= 2 * UI_UNIT_X && but->str.empty()) {
|
2025-04-24 17:22:28 +02:00
|
|
|
bitem->flag_ |= uiItemInternalFlag::FixedSize;
|
2017-08-12 11:00:19 +03:00
|
|
|
}
|
2017-02-02 17:30:50 +03:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
if (layout->child_items_layout_) {
|
|
|
|
|
layout->child_items_layout_->items_.append(bitem);
|
2018-10-25 15:27:31 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2025-04-23 16:37:14 +02:00
|
|
|
layout->items_.append(bitem);
|
2018-10-25 15:27:31 +02:00
|
|
|
}
|
2020-08-07 14:34:11 +02:00
|
|
|
but->layout = layout;
|
2025-04-23 14:54:06 +02:00
|
|
|
but->search_weight = layout->search_weight_;
|
2009-05-28 23:13:42 +00:00
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
if (layout->context_) {
|
|
|
|
|
but->context = layout->context_;
|
|
|
|
|
layout->context_->used = true;
|
2009-05-28 23:13:42 +00:00
|
|
|
}
|
2018-05-13 12:57:31 +02:00
|
|
|
|
2025-04-23 14:54:06 +02:00
|
|
|
if (layout->emboss_ != blender::ui::EmbossType::Undefined) {
|
|
|
|
|
but->emboss = layout->emboss_;
|
2018-05-13 12:57:31 +02:00
|
|
|
}
|
2020-09-15 09:38:19 -05:00
|
|
|
|
2020-10-02 17:00:41 -05:00
|
|
|
ui_button_group_add_but(uiLayoutGetBlock(layout), but);
|
2009-03-13 13:38:41 +00:00
|
|
|
}
|
|
|
|
|
|
2021-10-06 11:20:15 +02:00
|
|
|
static uiButtonItem *ui_layout_find_button_item(const uiLayout *layout, const uiBut *but)
|
2020-08-07 14:34:11 +02:00
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
const blender::Vector<uiItem *> &child_list = layout->child_items_layout_ ?
|
|
|
|
|
layout->child_items_layout_->items_ :
|
|
|
|
|
layout->items_;
|
2020-08-07 14:34:11 +02:00
|
|
|
|
2024-07-10 14:46:06 +02:00
|
|
|
for (uiItem *item : child_list) {
|
2025-04-24 17:22:28 +02:00
|
|
|
if (item->type_ == uiItemType::Button) {
|
2024-07-10 14:46:06 +02:00
|
|
|
uiButtonItem *bitem = static_cast<uiButtonItem *>(item);
|
2020-08-07 14:34:11 +02:00
|
|
|
|
2021-10-06 11:20:15 +02:00
|
|
|
if (bitem->but == but) {
|
|
|
|
|
return bitem;
|
2020-08-07 14:34:11 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2024-07-10 14:46:06 +02:00
|
|
|
uiButtonItem *nested_item = ui_layout_find_button_item(static_cast<uiLayout *>(item), but);
|
2021-10-06 11:20:15 +02:00
|
|
|
if (nested_item) {
|
|
|
|
|
return nested_item;
|
2020-08-07 14:34:11 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-25 23:48:02 -06:00
|
|
|
return nullptr;
|
2021-10-06 11:20:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ui_layout_remove_but(uiLayout *layout, const uiBut *but)
|
|
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
blender::Vector<uiItem *> &child_list = layout->child_items_layout_ ?
|
|
|
|
|
layout->child_items_layout_->items_ :
|
|
|
|
|
layout->items_;
|
2024-07-10 14:46:06 +02:00
|
|
|
const int64_t removed_num = child_list.remove_if([but](auto item) {
|
2025-04-24 17:22:28 +02:00
|
|
|
if (item->type_ == uiItemType::Button) {
|
2024-07-10 14:46:06 +02:00
|
|
|
uiButtonItem *bitem = static_cast<uiButtonItem *>(item);
|
|
|
|
|
return (bitem->but == but);
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
});
|
2021-10-06 11:20:15 +02:00
|
|
|
|
2024-07-10 14:46:06 +02:00
|
|
|
BLI_assert(removed_num <= 1);
|
|
|
|
|
UNUSED_VARS_NDEBUG(removed_num);
|
2021-10-06 11:20:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ui_layout_replace_but_ptr(uiLayout *layout, const void *old_but_ptr, uiBut *new_but)
|
|
|
|
|
{
|
2022-11-25 23:48:02 -06:00
|
|
|
uiButtonItem *bitem = ui_layout_find_button_item(layout,
|
|
|
|
|
static_cast<const uiBut *>(old_but_ptr));
|
2021-10-06 11:20:15 +02:00
|
|
|
if (!bitem) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bitem->but = new_but;
|
|
|
|
|
return true;
|
2020-08-07 14:34:11 +02:00
|
|
|
}
|
|
|
|
|
|
2019-09-19 16:14:47 +02:00
|
|
|
void uiLayoutSetFixedSize(uiLayout *layout, bool fixed_size)
|
|
|
|
|
{
|
|
|
|
|
if (fixed_size) {
|
2025-04-24 17:22:28 +02:00
|
|
|
layout->flag_ |= uiItemInternalFlag::FixedSize;
|
2019-09-19 16:14:47 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2025-04-24 17:22:28 +02:00
|
|
|
layout->flag_ &= ~uiItemInternalFlag::FixedSize;
|
2019-09-19 16:14:47 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool uiLayoutGetFixedSize(uiLayout *layout)
|
|
|
|
|
{
|
2025-04-24 17:22:28 +02:00
|
|
|
return bool(layout->flag_ & uiItemInternalFlag::FixedSize);
|
2019-09-19 16:14:47 +02:00
|
|
|
}
|
|
|
|
|
|
2021-11-05 14:56:22 +01:00
|
|
|
void uiLayoutSetOperatorContext(uiLayout *layout, wmOperatorCallContext opcontext)
|
2009-03-13 13:38:41 +00:00
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
layout->root_->opcontext = opcontext;
|
2009-03-13 13:38:41 +00:00
|
|
|
}
|
|
|
|
|
|
2009-05-28 23:37:55 +00:00
|
|
|
void uiLayoutSetFunc(uiLayout *layout, uiMenuHandleFunc handlefunc, void *argv)
|
2009-04-22 18:39:44 +00:00
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
layout->root_->handlefunc = handlefunc;
|
|
|
|
|
layout->root_->argv = argv;
|
2009-04-22 18:39:44 +00:00
|
|
|
}
|
|
|
|
|
|
2020-10-13 13:10:41 -05:00
|
|
|
void UI_block_layout_free(uiBlock *block)
|
|
|
|
|
{
|
|
|
|
|
LISTBASE_FOREACH_MUTABLE (uiLayoutRoot *, root, &block->layouts) {
|
|
|
|
|
ui_layout_free(root->layout);
|
|
|
|
|
MEM_freeN(root);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-25 12:19:55 +11:00
|
|
|
void UI_block_layout_resolve(uiBlock *block, int *r_x, int *r_y)
|
2009-03-13 13:38:41 +00:00
|
|
|
{
|
2014-06-15 01:40:15 +10:00
|
|
|
BLI_assert(block->active);
|
|
|
|
|
|
2019-03-25 12:19:55 +11:00
|
|
|
if (r_x) {
|
|
|
|
|
*r_x = 0;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2019-03-25 12:19:55 +11:00
|
|
|
if (r_y) {
|
|
|
|
|
*r_y = 0;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2009-03-13 13:38:41 +00:00
|
|
|
|
2022-11-25 23:48:02 -06:00
|
|
|
block->curlayout = nullptr;
|
2009-05-19 17:13:33 +00:00
|
|
|
|
2020-09-15 09:38:19 -05:00
|
|
|
LISTBASE_FOREACH_MUTABLE (uiLayoutRoot *, root, &block->layouts) {
|
2014-01-17 00:23:00 +01:00
|
|
|
ui_layout_add_padding_button(root);
|
|
|
|
|
|
2022-11-25 23:48:02 -06:00
|
|
|
/* nullptr in advance so we don't interfere when adding button */
|
2019-03-25 12:19:55 +11:00
|
|
|
ui_layout_end(block, root->layout, r_x, r_y);
|
2020-09-15 11:25:49 -05:00
|
|
|
ui_layout_free(root->layout);
|
2020-10-02 17:00:41 -05:00
|
|
|
MEM_freeN(root);
|
2009-03-29 19:44:39 +00:00
|
|
|
}
|
|
|
|
|
|
2020-09-15 09:38:19 -05:00
|
|
|
BLI_listbase_clear(&block->layouts);
|
2009-03-13 13:38:41 +00:00
|
|
|
}
|
|
|
|
|
|
2022-01-03 19:20:00 +01:00
|
|
|
bool UI_block_layout_needs_resolving(const uiBlock *block)
|
|
|
|
|
{
|
|
|
|
|
return !BLI_listbase_is_empty(&block->layouts);
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-06 14:08:10 +01:00
|
|
|
void uiLayoutSetContextPointer(uiLayout *layout, StringRef name, PointerRNA *ptr)
|
2009-03-13 13:38:41 +00:00
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
uiBlock *block = layout->root_->block;
|
|
|
|
|
layout->context_ = CTX_store_add(block->contexts, name, ptr);
|
2009-03-29 19:44:39 +00:00
|
|
|
}
|
2009-03-25 14:34:17 +00:00
|
|
|
|
2024-12-06 14:08:10 +01:00
|
|
|
void uiLayoutSetContextString(uiLayout *layout, StringRef name, blender::StringRef value)
|
2024-05-27 18:46:19 +02:00
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
uiBlock *block = layout->root_->block;
|
|
|
|
|
layout->context_ = CTX_store_add(block->contexts, name, value);
|
2024-05-27 18:46:19 +02:00
|
|
|
}
|
|
|
|
|
|
2024-12-10 14:49:11 +01:00
|
|
|
void uiLayoutSetContextInt(uiLayout *layout, StringRef name, int64_t value)
|
|
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
uiBlock *block = layout->root_->block;
|
|
|
|
|
layout->context_ = CTX_store_add(block->contexts, name, value);
|
2024-12-10 14:49:11 +01:00
|
|
|
}
|
|
|
|
|
|
2020-12-11 22:20:31 +01:00
|
|
|
bContextStore *uiLayoutGetContextStore(uiLayout *layout)
|
|
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
return layout->context_;
|
2020-12-11 22:20:31 +01:00
|
|
|
}
|
|
|
|
|
|
2023-08-31 11:59:58 -04:00
|
|
|
void uiLayoutContextCopy(uiLayout *layout, const bContextStore *context)
|
2012-04-03 15:18:59 +00:00
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
uiBlock *block = layout->root_->block;
|
|
|
|
|
layout->context_ = CTX_store_add_all(block->contexts, context);
|
2012-04-03 15:18:59 +00:00
|
|
|
}
|
|
|
|
|
|
UI: Add support for showing socket descriptions in tooltips
Currently, hovering over a socket itself shows no tooltip at all, while
hovering over its value field shows "Default value", which is not helpful.
This patch therefore implements socket tooltips following the proposal at
https://blender.community/c/rightclickselect/2Qgbbc/.
A lot of the basic functionality was already implemented for Geometry Nodes,
where hovering over the socket itself shows introspection info.
This patch extends this by:
- Supporting dynamic tooltips on labels, which is important for good tooltip
coverage in a socket's region of the node.
- Adding a function to setting a dynamic tooltip for an entire uiLayout, which
avoids needing to set it manually for a wide variety of socket types.
- Hiding the property label field in a tooltip when dynamic tooltip is also
provided. If really needed, this label can be restored through the dynamic
tooltip, but in all current cases the label is actually pointless anyways
since the dynamic tooltip gives more accurate and specific information.
- Adding dynamic tooltips to a socket's UI layout row if it has a description
configured, both in the Node Editor as well as in the Material Properties.
Note that the patch does not add any actual tooltip content yet, just the
infrastructure to show them. By default, sockets without a description still
show the old "Default value" tooltip.
For an example of how to add socket descriptions, check the Cylinder node
in the Geometry Nodes.
Differential Revision: https://developer.blender.org/D9967
2022-04-11 02:02:12 +02:00
|
|
|
void uiLayoutSetTooltipFunc(uiLayout *layout,
|
|
|
|
|
uiButToolTipFunc func,
|
|
|
|
|
void *arg,
|
|
|
|
|
uiCopyArgFunc copy_arg,
|
|
|
|
|
uiFreeArgFunc free_arg)
|
|
|
|
|
{
|
|
|
|
|
bool arg_used = false;
|
|
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
for (uiItem *item : layout->items_) {
|
UI: Add support for showing socket descriptions in tooltips
Currently, hovering over a socket itself shows no tooltip at all, while
hovering over its value field shows "Default value", which is not helpful.
This patch therefore implements socket tooltips following the proposal at
https://blender.community/c/rightclickselect/2Qgbbc/.
A lot of the basic functionality was already implemented for Geometry Nodes,
where hovering over the socket itself shows introspection info.
This patch extends this by:
- Supporting dynamic tooltips on labels, which is important for good tooltip
coverage in a socket's region of the node.
- Adding a function to setting a dynamic tooltip for an entire uiLayout, which
avoids needing to set it manually for a wide variety of socket types.
- Hiding the property label field in a tooltip when dynamic tooltip is also
provided. If really needed, this label can be restored through the dynamic
tooltip, but in all current cases the label is actually pointless anyways
since the dynamic tooltip gives more accurate and specific information.
- Adding dynamic tooltips to a socket's UI layout row if it has a description
configured, both in the Node Editor as well as in the Material Properties.
Note that the patch does not add any actual tooltip content yet, just the
infrastructure to show them. By default, sockets without a description still
show the old "Default value" tooltip.
For an example of how to add socket descriptions, check the Cylinder node
in the Geometry Nodes.
Differential Revision: https://developer.blender.org/D9967
2022-04-11 02:02:12 +02:00
|
|
|
/* Each button will call free_arg for "its" argument, so we need to
|
|
|
|
|
* duplicate the allocation for each button after the first. */
|
2022-11-25 23:48:02 -06:00
|
|
|
if (copy_arg != nullptr && arg_used) {
|
UI: Add support for showing socket descriptions in tooltips
Currently, hovering over a socket itself shows no tooltip at all, while
hovering over its value field shows "Default value", which is not helpful.
This patch therefore implements socket tooltips following the proposal at
https://blender.community/c/rightclickselect/2Qgbbc/.
A lot of the basic functionality was already implemented for Geometry Nodes,
where hovering over the socket itself shows introspection info.
This patch extends this by:
- Supporting dynamic tooltips on labels, which is important for good tooltip
coverage in a socket's region of the node.
- Adding a function to setting a dynamic tooltip for an entire uiLayout, which
avoids needing to set it manually for a wide variety of socket types.
- Hiding the property label field in a tooltip when dynamic tooltip is also
provided. If really needed, this label can be restored through the dynamic
tooltip, but in all current cases the label is actually pointless anyways
since the dynamic tooltip gives more accurate and specific information.
- Adding dynamic tooltips to a socket's UI layout row if it has a description
configured, both in the Node Editor as well as in the Material Properties.
Note that the patch does not add any actual tooltip content yet, just the
infrastructure to show them. By default, sockets without a description still
show the old "Default value" tooltip.
For an example of how to add socket descriptions, check the Cylinder node
in the Geometry Nodes.
Differential Revision: https://developer.blender.org/D9967
2022-04-11 02:02:12 +02:00
|
|
|
arg = copy_arg(arg);
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-24 17:22:28 +02:00
|
|
|
if (item->type_ == uiItemType::Button) {
|
2024-07-10 14:46:06 +02:00
|
|
|
uiButtonItem *bitem = static_cast<uiButtonItem *>(item);
|
UI: Add support for showing socket descriptions in tooltips
Currently, hovering over a socket itself shows no tooltip at all, while
hovering over its value field shows "Default value", which is not helpful.
This patch therefore implements socket tooltips following the proposal at
https://blender.community/c/rightclickselect/2Qgbbc/.
A lot of the basic functionality was already implemented for Geometry Nodes,
where hovering over the socket itself shows introspection info.
This patch extends this by:
- Supporting dynamic tooltips on labels, which is important for good tooltip
coverage in a socket's region of the node.
- Adding a function to setting a dynamic tooltip for an entire uiLayout, which
avoids needing to set it manually for a wide variety of socket types.
- Hiding the property label field in a tooltip when dynamic tooltip is also
provided. If really needed, this label can be restored through the dynamic
tooltip, but in all current cases the label is actually pointless anyways
since the dynamic tooltip gives more accurate and specific information.
- Adding dynamic tooltips to a socket's UI layout row if it has a description
configured, both in the Node Editor as well as in the Material Properties.
Note that the patch does not add any actual tooltip content yet, just the
infrastructure to show them. By default, sockets without a description still
show the old "Default value" tooltip.
For an example of how to add socket descriptions, check the Cylinder node
in the Geometry Nodes.
Differential Revision: https://developer.blender.org/D9967
2022-04-11 02:02:12 +02:00
|
|
|
if (bitem->but->type == UI_BTYPE_DECORATOR) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
UI_but_func_tooltip_set(bitem->but, func, arg, free_arg);
|
2023-03-09 14:38:51 +01:00
|
|
|
arg_used = true;
|
UI: Add support for showing socket descriptions in tooltips
Currently, hovering over a socket itself shows no tooltip at all, while
hovering over its value field shows "Default value", which is not helpful.
This patch therefore implements socket tooltips following the proposal at
https://blender.community/c/rightclickselect/2Qgbbc/.
A lot of the basic functionality was already implemented for Geometry Nodes,
where hovering over the socket itself shows introspection info.
This patch extends this by:
- Supporting dynamic tooltips on labels, which is important for good tooltip
coverage in a socket's region of the node.
- Adding a function to setting a dynamic tooltip for an entire uiLayout, which
avoids needing to set it manually for a wide variety of socket types.
- Hiding the property label field in a tooltip when dynamic tooltip is also
provided. If really needed, this label can be restored through the dynamic
tooltip, but in all current cases the label is actually pointless anyways
since the dynamic tooltip gives more accurate and specific information.
- Adding dynamic tooltips to a socket's UI layout row if it has a description
configured, both in the Node Editor as well as in the Material Properties.
Note that the patch does not add any actual tooltip content yet, just the
infrastructure to show them. By default, sockets without a description still
show the old "Default value" tooltip.
For an example of how to add socket descriptions, check the Cylinder node
in the Geometry Nodes.
Differential Revision: https://developer.blender.org/D9967
2022-04-11 02:02:12 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2024-07-10 14:46:06 +02:00
|
|
|
uiLayoutSetTooltipFunc(static_cast<uiLayout *>(item), func, arg, copy_arg, free_arg);
|
2023-03-09 14:38:51 +01:00
|
|
|
arg_used = true;
|
UI: Add support for showing socket descriptions in tooltips
Currently, hovering over a socket itself shows no tooltip at all, while
hovering over its value field shows "Default value", which is not helpful.
This patch therefore implements socket tooltips following the proposal at
https://blender.community/c/rightclickselect/2Qgbbc/.
A lot of the basic functionality was already implemented for Geometry Nodes,
where hovering over the socket itself shows introspection info.
This patch extends this by:
- Supporting dynamic tooltips on labels, which is important for good tooltip
coverage in a socket's region of the node.
- Adding a function to setting a dynamic tooltip for an entire uiLayout, which
avoids needing to set it manually for a wide variety of socket types.
- Hiding the property label field in a tooltip when dynamic tooltip is also
provided. If really needed, this label can be restored through the dynamic
tooltip, but in all current cases the label is actually pointless anyways
since the dynamic tooltip gives more accurate and specific information.
- Adding dynamic tooltips to a socket's UI layout row if it has a description
configured, both in the Node Editor as well as in the Material Properties.
Note that the patch does not add any actual tooltip content yet, just the
infrastructure to show them. By default, sockets without a description still
show the old "Default value" tooltip.
For an example of how to add socket descriptions, check the Cylinder node
in the Geometry Nodes.
Differential Revision: https://developer.blender.org/D9967
2022-04-11 02:02:12 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-23 08:22:48 +02:00
|
|
|
if (free_arg != nullptr && !arg_used) {
|
UI: Add support for showing socket descriptions in tooltips
Currently, hovering over a socket itself shows no tooltip at all, while
hovering over its value field shows "Default value", which is not helpful.
This patch therefore implements socket tooltips following the proposal at
https://blender.community/c/rightclickselect/2Qgbbc/.
A lot of the basic functionality was already implemented for Geometry Nodes,
where hovering over the socket itself shows introspection info.
This patch extends this by:
- Supporting dynamic tooltips on labels, which is important for good tooltip
coverage in a socket's region of the node.
- Adding a function to setting a dynamic tooltip for an entire uiLayout, which
avoids needing to set it manually for a wide variety of socket types.
- Hiding the property label field in a tooltip when dynamic tooltip is also
provided. If really needed, this label can be restored through the dynamic
tooltip, but in all current cases the label is actually pointless anyways
since the dynamic tooltip gives more accurate and specific information.
- Adding dynamic tooltips to a socket's UI layout row if it has a description
configured, both in the Node Editor as well as in the Material Properties.
Note that the patch does not add any actual tooltip content yet, just the
infrastructure to show them. By default, sockets without a description still
show the old "Default value" tooltip.
For an example of how to add socket descriptions, check the Cylinder node
in the Geometry Nodes.
Differential Revision: https://developer.blender.org/D9967
2022-04-11 02:02:12 +02:00
|
|
|
/* Free the original copy of arg in case the layout is empty. */
|
|
|
|
|
free_arg(arg);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-02 18:19:11 +11:00
|
|
|
void uiLayoutSetContextFromBut(uiLayout *layout, uiBut *but)
|
|
|
|
|
{
|
|
|
|
|
if (but->opptr) {
|
|
|
|
|
uiLayoutSetContextPointer(layout, "button_operator", but->opptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (but->rnapoin.data && but->rnaprop) {
|
|
|
|
|
/* TODO: index could be supported as well */
|
2025-01-24 16:45:32 +01:00
|
|
|
PointerRNA ptr_prop = RNA_pointer_create_discrete(nullptr, &RNA_Property, but->rnaprop);
|
2017-11-02 18:19:11 +11:00
|
|
|
uiLayoutSetContextPointer(layout, "button_prop", &ptr_prop);
|
|
|
|
|
uiLayoutSetContextPointer(layout, "button_pointer", &but->rnapoin);
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-11-28 17:45:23 +00:00
|
|
|
|
2020-09-02 12:54:06 +10:00
|
|
|
wmOperatorType *UI_but_operatortype_get_from_enum_menu(uiBut *but, PropertyRNA **r_prop)
|
|
|
|
|
{
|
2022-11-25 23:48:02 -06:00
|
|
|
if (r_prop != nullptr) {
|
|
|
|
|
*r_prop = nullptr;
|
2020-09-02 12:54:06 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (but->menu_create_func == menu_item_enum_opname_menu) {
|
2022-11-25 23:48:02 -06:00
|
|
|
MenuItemLevel *lvl = static_cast<MenuItemLevel *>(but->func_argN);
|
2020-09-02 12:54:06 +10:00
|
|
|
wmOperatorType *ot = WM_operatortype_find(lvl->opname, false);
|
2022-11-25 23:48:02 -06:00
|
|
|
if ((ot != nullptr) && (r_prop != nullptr)) {
|
2020-09-02 12:54:06 +10:00
|
|
|
*r_prop = RNA_struct_type_find_property(ot->srna, lvl->propname);
|
|
|
|
|
}
|
|
|
|
|
return ot;
|
|
|
|
|
}
|
2022-11-25 23:48:02 -06:00
|
|
|
return nullptr;
|
2020-09-02 12:54:06 +10:00
|
|
|
}
|
|
|
|
|
|
2024-01-18 23:12:09 -05:00
|
|
|
MenuType *UI_but_menutype_get(const uiBut *but)
|
2011-11-14 14:42:47 +00:00
|
|
|
{
|
2012-03-24 06:38:07 +00:00
|
|
|
if (but->menu_create_func == ui_item_menutype_func) {
|
2011-11-14 14:42:47 +00:00
|
|
|
return (MenuType *)but->poin;
|
|
|
|
|
}
|
2022-11-25 23:48:02 -06:00
|
|
|
return nullptr;
|
2011-11-14 14:42:47 +00:00
|
|
|
}
|
2017-11-02 18:19:11 +11:00
|
|
|
|
2024-01-18 23:12:09 -05:00
|
|
|
PanelType *UI_but_paneltype_get(const uiBut *but)
|
2018-04-22 17:16:39 +02:00
|
|
|
{
|
|
|
|
|
if (but->menu_create_func == ui_item_paneltype_func) {
|
|
|
|
|
return (PanelType *)but->poin;
|
|
|
|
|
}
|
2022-11-25 23:48:02 -06:00
|
|
|
return nullptr;
|
2018-04-22 17:16:39 +02:00
|
|
|
}
|
|
|
|
|
|
2024-07-07 20:00:35 +02:00
|
|
|
std::optional<blender::StringRefNull> UI_but_asset_shelf_type_idname_get(const uiBut *but)
|
|
|
|
|
{
|
|
|
|
|
return UI_asset_shelf_idname_from_button_context(but);
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-25 23:48:02 -06:00
|
|
|
void UI_menutype_draw(bContext *C, MenuType *mt, uiLayout *layout)
|
2017-11-02 18:19:11 +11:00
|
|
|
{
|
2022-11-25 23:48:02 -06:00
|
|
|
Menu menu{};
|
|
|
|
|
menu.layout = layout;
|
|
|
|
|
menu.type = mt;
|
2017-11-02 18:19:11 +11:00
|
|
|
|
|
|
|
|
if (G.debug & G_DEBUG_WM) {
|
|
|
|
|
printf("%s: opening menu \"%s\"\n", __func__, mt->idname);
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-06 18:16:45 +02:00
|
|
|
uiBlock *block = uiLayoutGetBlock(layout);
|
2023-10-12 17:54:59 +02:00
|
|
|
if (bool(mt->flag & MenuTypeFlag::SearchOnKeyPress)) {
|
|
|
|
|
UI_block_flag_enable(block, UI_BLOCK_NO_ACCELERATOR_KEYS);
|
|
|
|
|
}
|
2022-11-01 17:36:36 +01:00
|
|
|
if (mt->listener) {
|
|
|
|
|
/* Forward the menu type listener to the block we're drawing in. */
|
2023-09-26 18:37:28 +02:00
|
|
|
ui_block_add_dynamic_listener(block, mt->listener);
|
2022-11-01 17:36:36 +01:00
|
|
|
}
|
|
|
|
|
|
2025-05-08 04:28:22 +02:00
|
|
|
bContextStore context_store;
|
2025-04-23 16:37:14 +02:00
|
|
|
if (layout->context_) {
|
2025-05-08 04:28:22 +02:00
|
|
|
context_store = *layout->context_;
|
2017-11-02 18:19:11 +11:00
|
|
|
}
|
2025-05-08 04:28:22 +02:00
|
|
|
const bContextStore *previous_context_store = CTX_store_get(C);
|
|
|
|
|
if (previous_context_store) {
|
|
|
|
|
context_store.entries.extend(previous_context_store->entries);
|
|
|
|
|
}
|
|
|
|
|
CTX_store_set(C, &context_store);
|
2017-11-02 18:19:11 +11:00
|
|
|
|
|
|
|
|
mt->draw(C, &menu);
|
|
|
|
|
|
2025-05-08 04:28:22 +02:00
|
|
|
CTX_store_set(C, previous_context_store);
|
2017-11-02 18:19:11 +11:00
|
|
|
}
|
2018-05-25 12:19:04 +02:00
|
|
|
|
2020-07-20 19:46:08 +02:00
|
|
|
static bool ui_layout_has_panel_label(const uiLayout *layout, const PanelType *pt)
|
|
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
for (uiItem *subitem : layout->items_) {
|
2025-04-24 17:22:28 +02:00
|
|
|
if (subitem->type_ == uiItemType::Button) {
|
2024-07-10 14:46:06 +02:00
|
|
|
uiButtonItem *bitem = static_cast<uiButtonItem *>(subitem);
|
2023-02-23 19:06:18 +01:00
|
|
|
if (!(bitem->but->flag & UI_HIDDEN) &&
|
2024-01-20 21:47:16 -05:00
|
|
|
bitem->but->str == CTX_IFACE_(pt->translation_context, pt->label))
|
2023-02-23 19:06:18 +01:00
|
|
|
{
|
2020-07-20 19:46:08 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2024-07-10 14:46:06 +02:00
|
|
|
uiLayout *litem = static_cast<uiLayout *>(subitem);
|
2020-07-20 19:46:08 +02:00
|
|
|
if (ui_layout_has_panel_label(litem, pt)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-10 12:43:10 +02:00
|
|
|
static void ui_paneltype_draw_impl(bContext *C, PanelType *pt, uiLayout *layout, bool show_header)
|
2018-05-25 12:19:04 +02:00
|
|
|
{
|
2024-03-22 17:36:45 +11:00
|
|
|
uiBlock *block = uiLayoutGetBlock(layout);
|
2023-10-10 18:17:31 +02:00
|
|
|
Panel *panel = BKE_panel_new(pt);
|
2018-06-09 17:36:28 +02:00
|
|
|
panel->flag = PNL_POPOVER;
|
|
|
|
|
|
2023-09-26 18:37:28 +02:00
|
|
|
if (pt->listener) {
|
2024-03-22 17:36:45 +11:00
|
|
|
ui_block_add_dynamic_listener(block, pt->listener);
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-22 17:09:02 +01:00
|
|
|
/* This check may be paranoid, this function might run outside the context of a popup or can run
|
2024-03-26 17:54:30 +11:00
|
|
|
* in popovers that are not supposed to support refreshing, see #ui_popover_create_block. */
|
2024-03-22 17:09:02 +01:00
|
|
|
if (block->handle && block->handle->region) {
|
2024-03-22 19:05:16 +11:00
|
|
|
/* Allow popovers to contain collapsible sections, see #uiItemPopoverPanel. */
|
2024-03-22 17:36:45 +11:00
|
|
|
UI_popup_dummy_panel_set(block->handle->region, block);
|
2023-09-26 18:37:28 +02:00
|
|
|
}
|
|
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
uiItem *item_last = layout->items_.is_empty() ? nullptr : layout->items_.last();
|
2018-06-29 17:46:16 +02:00
|
|
|
|
|
|
|
|
/* Draw main panel. */
|
2018-07-10 12:43:10 +02:00
|
|
|
if (show_header) {
|
2025-04-25 19:45:25 +02:00
|
|
|
uiLayout *row = &layout->row(false);
|
2018-07-10 12:43:10 +02:00
|
|
|
if (pt->draw_header) {
|
|
|
|
|
panel->layout = row;
|
|
|
|
|
pt->draw_header(C, panel);
|
2022-11-25 23:48:02 -06:00
|
|
|
panel->layout = nullptr;
|
2018-07-10 12:43:10 +02:00
|
|
|
}
|
2020-07-20 19:46:08 +02:00
|
|
|
|
|
|
|
|
/* draw_header() is often used to add a checkbox to the header. If we add the label like below
|
|
|
|
|
* the label is disconnected from the checkbox, adding a weird looking gap. As workaround, let
|
|
|
|
|
* the checkbox add the label instead. */
|
|
|
|
|
if (!ui_layout_has_panel_label(row, pt)) {
|
2025-05-08 17:21:08 +02:00
|
|
|
row->label(CTX_IFACE_(pt->translation_context, pt->label), ICON_NONE);
|
2020-07-20 19:46:08 +02:00
|
|
|
}
|
2018-05-25 12:19:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
panel->layout = layout;
|
|
|
|
|
pt->draw(C, panel);
|
2022-11-25 23:48:02 -06:00
|
|
|
panel->layout = nullptr;
|
2023-10-10 18:17:31 +02:00
|
|
|
BLI_assert(panel->runtime->custom_data_ptr == nullptr);
|
2018-05-25 12:19:04 +02:00
|
|
|
|
2023-10-10 18:17:31 +02:00
|
|
|
BKE_panel_free(panel);
|
2018-06-09 14:21:39 +02:00
|
|
|
|
2018-06-29 17:46:16 +02:00
|
|
|
/* Draw child panels. */
|
2020-04-03 19:15:01 +02:00
|
|
|
LISTBASE_FOREACH (LinkData *, link, &pt->children) {
|
2022-11-25 23:48:02 -06:00
|
|
|
PanelType *child_pt = static_cast<PanelType *>(link->data);
|
2018-06-29 17:46:16 +02:00
|
|
|
|
2022-11-25 23:48:02 -06:00
|
|
|
if (child_pt->poll == nullptr || child_pt->poll(C, child_pt)) {
|
2018-06-29 17:46:16 +02:00
|
|
|
/* Add space if something was added to the layout. */
|
2025-04-23 16:37:14 +02:00
|
|
|
if (!layout->items_.is_empty() && item_last != layout->items_.last()) {
|
2025-05-13 17:54:26 +02:00
|
|
|
layout->separator();
|
2025-04-23 16:37:14 +02:00
|
|
|
item_last = layout->items_.last();
|
2018-06-09 14:21:39 +02:00
|
|
|
}
|
2018-06-29 17:46:16 +02:00
|
|
|
|
2025-04-26 21:07:34 +02:00
|
|
|
uiLayout *col = &layout->column(false);
|
2018-07-10 12:43:10 +02:00
|
|
|
ui_paneltype_draw_impl(C, child_pt, col, true);
|
2018-06-09 14:21:39 +02:00
|
|
|
}
|
2018-06-29 17:46:16 +02:00
|
|
|
}
|
2018-06-09 14:21:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UI_paneltype_draw(bContext *C, PanelType *pt, uiLayout *layout)
|
|
|
|
|
{
|
2025-04-23 16:37:14 +02:00
|
|
|
if (layout->context_) {
|
|
|
|
|
CTX_store_set(C, layout->context_);
|
2018-06-09 14:21:39 +02:00
|
|
|
}
|
|
|
|
|
|
2018-05-25 12:19:04 +02:00
|
|
|
ui_paneltype_draw_impl(C, pt, layout, false);
|
|
|
|
|
|
2025-04-23 16:37:14 +02:00
|
|
|
if (layout->context_) {
|
2022-11-25 23:48:02 -06:00
|
|
|
CTX_store_set(C, nullptr);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2018-05-25 12:19:04 +02:00
|
|
|
}
|
2019-09-06 16:12:47 +10:00
|
|
|
|
|
|
|
|
/** \} */
|
2020-09-01 15:23:55 +10:00
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
2020-09-06 01:45:38 +10:00
|
|
|
/** \name Layout (Debugging/Introspection)
|
2020-09-01 15:23:55 +10:00
|
|
|
*
|
|
|
|
|
* Serialize the layout as a Python compatible dictionary,
|
|
|
|
|
*
|
|
|
|
|
* \note Proper string escaping isn't used,
|
|
|
|
|
* triple quotes are used to prevent single quotes from interfering with Python syntax.
|
|
|
|
|
* If we want this to be fool-proof, we would need full Python compatible string escape support.
|
|
|
|
|
* As we don't use triple quotes in the UI it's good-enough in practice.
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2024-07-10 14:46:06 +02:00
|
|
|
static void ui_layout_introspect_button(DynStr *ds, const uiButtonItem *bitem)
|
2020-09-01 15:23:55 +10:00
|
|
|
{
|
|
|
|
|
uiBut *but = bitem->but;
|
2022-12-08 13:04:50 +11:00
|
|
|
BLI_dynstr_appendf(ds, "'type':%d, ", int(but->type));
|
2024-01-22 14:54:44 -05:00
|
|
|
BLI_dynstr_appendf(ds, "'draw_string':'''%s''', ", but->drawstr.c_str());
|
2020-09-01 15:23:55 +10:00
|
|
|
/* Not exactly needed, rna has this. */
|
2025-02-14 15:12:48 -05:00
|
|
|
BLI_dynstr_appendf(ds, "'tip':'''%s''', ", std::string(but->tip).c_str());
|
2020-09-01 15:23:55 +10:00
|
|
|
|
|
|
|
|
if (but->optype) {
|
2024-01-29 16:33:06 -05:00
|
|
|
std::string opstr = WM_operator_pystring_ex(static_cast<bContext *>(but->block->evil_C),
|
|
|
|
|
nullptr,
|
|
|
|
|
false,
|
|
|
|
|
true,
|
|
|
|
|
but->optype,
|
|
|
|
|
but->opptr);
|
|
|
|
|
BLI_dynstr_appendf(ds, "'operator':'''%s''', ", opstr.c_str());
|
2020-09-01 15:23:55 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
2022-11-25 23:48:02 -06:00
|
|
|
PropertyRNA *prop = nullptr;
|
2020-09-01 15:23:55 +10:00
|
|
|
wmOperatorType *ot = UI_but_operatortype_get_from_enum_menu(but, &prop);
|
|
|
|
|
if (ot) {
|
2024-01-29 16:33:06 -05:00
|
|
|
std::string opstr = WM_operator_pystring_ex(
|
2022-11-25 23:48:02 -06:00
|
|
|
static_cast<bContext *>(but->block->evil_C), nullptr, false, true, ot, nullptr);
|
2024-01-29 16:33:06 -05:00
|
|
|
BLI_dynstr_appendf(ds, "'operator':'''%s''', ", opstr.c_str());
|
2020-09-01 15:23:55 +10:00
|
|
|
BLI_dynstr_appendf(ds, "'property':'''%s''', ", prop ? RNA_property_identifier(prop) : "");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (but->rnaprop) {
|
|
|
|
|
BLI_dynstr_appendf(ds,
|
|
|
|
|
"'rna':'%s.%s[%d]', ",
|
|
|
|
|
RNA_struct_identifier(but->rnapoin.type),
|
|
|
|
|
RNA_property_identifier(but->rnaprop),
|
|
|
|
|
but->rnaindex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-10 14:46:06 +02:00
|
|
|
static void ui_layout_introspect_items(DynStr *ds, blender::Span<uiItem *> items)
|
2020-09-01 15:23:55 +10:00
|
|
|
{
|
|
|
|
|
BLI_dynstr_append(ds, "[");
|
|
|
|
|
|
2024-07-10 14:46:06 +02:00
|
|
|
for (const uiItem *item : items) {
|
2020-09-01 15:23:55 +10:00
|
|
|
|
|
|
|
|
BLI_dynstr_append(ds, "{");
|
|
|
|
|
|
2025-03-31 15:30:58 +02:00
|
|
|
#define CASE_ITEM(type, name) \
|
|
|
|
|
case type: { \
|
2020-09-01 15:23:55 +10:00
|
|
|
BLI_dynstr_append(ds, "'type': '"); \
|
2025-03-31 15:30:58 +02:00
|
|
|
BLI_dynstr_append(ds, name); \
|
2020-09-01 15:23:55 +10:00
|
|
|
BLI_dynstr_append(ds, "', "); \
|
|
|
|
|
break; \
|
|
|
|
|
} \
|
|
|
|
|
((void)0)
|
|
|
|
|
|
2025-04-24 17:22:28 +02:00
|
|
|
switch (item->type_) {
|
2025-03-31 15:30:58 +02:00
|
|
|
CASE_ITEM(uiItemType::Button, "BUTTON");
|
|
|
|
|
CASE_ITEM(uiItemType::LayoutRow, "LAYOUT_ROW");
|
|
|
|
|
CASE_ITEM(uiItemType::LayoutPanelHeader, "LAYOUT_PANEL_HEADER");
|
|
|
|
|
CASE_ITEM(uiItemType::LayoutPanelBody, "LAYOUT_PANEL_BODY");
|
|
|
|
|
CASE_ITEM(uiItemType::LayoutColumn, "LAYOUT_COLUMN");
|
|
|
|
|
CASE_ITEM(uiItemType::LayoutColumnFlow, "LAYOUT_COLUMN_FLOW");
|
|
|
|
|
CASE_ITEM(uiItemType::LayoutRowFlow, "LAYOUT_ROW_FLOW");
|
|
|
|
|
CASE_ITEM(uiItemType::LayoutBox, "LAYOUT_BOX");
|
|
|
|
|
CASE_ITEM(uiItemType::LayoutAbsolute, "LAYOUT_ABSOLUTE");
|
|
|
|
|
CASE_ITEM(uiItemType::LayoutSplit, "LAYOUT_SPLIT");
|
|
|
|
|
CASE_ITEM(uiItemType::LayoutOverlap, "LAYOUT_OVERLAP");
|
|
|
|
|
CASE_ITEM(uiItemType::LayoutRoot, "LAYOUT_ROOT");
|
|
|
|
|
CASE_ITEM(uiItemType::LayoutGridFlow, "LAYOUT_GRID_FLOW");
|
|
|
|
|
CASE_ITEM(uiItemType::LayoutRadial, "LAYOUT_RADIAL");
|
2020-09-01 15:23:55 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#undef CASE_ITEM
|
|
|
|
|
|
2025-04-24 17:22:28 +02:00
|
|
|
switch (item->type_) {
|
2025-03-31 15:30:58 +02:00
|
|
|
case uiItemType::Button:
|
2024-07-10 14:46:06 +02:00
|
|
|
ui_layout_introspect_button(ds, static_cast<const uiButtonItem *>(item));
|
2020-09-01 15:23:55 +10:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
BLI_dynstr_append(ds, "'items':");
|
2025-04-23 16:37:14 +02:00
|
|
|
ui_layout_introspect_items(ds, (static_cast<const uiLayout *>(item))->items_);
|
2020-09-01 15:23:55 +10:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BLI_dynstr_append(ds, "}");
|
|
|
|
|
|
2024-07-10 14:46:06 +02:00
|
|
|
if (item != items.last()) {
|
2020-09-01 15:23:55 +10:00
|
|
|
BLI_dynstr_append(ds, ", ");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* Don't use a comma here as it's not needed and
|
|
|
|
|
* causes the result to evaluate to a tuple of 1. */
|
|
|
|
|
BLI_dynstr_append(ds, "]");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *UI_layout_introspect(uiLayout *layout)
|
|
|
|
|
{
|
|
|
|
|
DynStr *ds = BLI_dynstr_new();
|
2024-07-10 14:46:06 +02:00
|
|
|
uiLayout layout_copy(*layout);
|
|
|
|
|
blender::Vector<uiItem *> layout_dummy_list(1, static_cast<uiItem *>(&layout_copy));
|
|
|
|
|
ui_layout_introspect_items(ds, layout_dummy_list);
|
2020-09-01 15:23:55 +10:00
|
|
|
const char *result = BLI_dynstr_get_cstring(ds);
|
|
|
|
|
BLI_dynstr_free(ds);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
2020-12-06 11:17:51 -08:00
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Alert Box with Big Icon
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2024-01-29 18:52:18 +01:00
|
|
|
uiLayout *uiItemsAlertBox(uiBlock *block,
|
|
|
|
|
const uiStyle *style,
|
|
|
|
|
const int dialog_width,
|
|
|
|
|
const eAlertIcon icon,
|
|
|
|
|
const int icon_size)
|
2020-12-06 11:17:51 -08:00
|
|
|
{
|
|
|
|
|
/* By default, the space between icon and text/buttons will be equal to the 'columnspace',
|
2021-07-30 22:20:13 +10:00
|
|
|
* this extra padding will add some space by increasing the left column width,
|
|
|
|
|
* making the icon placement more symmetrical, between the block edge and the text. */
|
2023-03-17 04:19:05 +01:00
|
|
|
const float icon_padding = 5.0f * UI_SCALE_FAC;
|
2020-12-06 11:17:51 -08:00
|
|
|
/* Calculate the factor of the fixed icon column depending on the block width. */
|
2022-12-08 13:04:50 +11:00
|
|
|
const float split_factor = (float(icon_size) + icon_padding) /
|
2023-01-03 11:04:16 +11:00
|
|
|
float(dialog_width - style->columnspace);
|
2020-12-06 11:17:51 -08:00
|
|
|
|
|
|
|
|
uiLayout *block_layout = UI_block_layout(
|
|
|
|
|
block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, dialog_width, 0, 0, style);
|
|
|
|
|
|
|
|
|
|
/* Split layout to put alert icon on left side. */
|
2025-05-03 20:51:42 +02:00
|
|
|
uiLayout *split_block = &block_layout->split(split_factor, false);
|
2020-12-06 11:17:51 -08:00
|
|
|
|
|
|
|
|
/* Alert icon on the left. */
|
2025-04-25 19:45:25 +02:00
|
|
|
uiLayout *layout = &split_block->row(false);
|
2020-12-06 11:17:51 -08:00
|
|
|
/* Using 'align_left' with 'row' avoids stretching the icon along the width of column. */
|
|
|
|
|
uiLayoutSetAlignment(layout, UI_LAYOUT_ALIGN_LEFT);
|
|
|
|
|
uiDefButAlert(block, icon, 0, 0, icon_size, icon_size);
|
|
|
|
|
|
|
|
|
|
/* The rest of the content on the right. */
|
2025-04-26 21:07:34 +02:00
|
|
|
layout = &split_block->column(false);
|
2020-12-06 11:17:51 -08:00
|
|
|
|
|
|
|
|
return layout;
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-29 18:52:18 +01:00
|
|
|
uiLayout *uiItemsAlertBox(uiBlock *block, const int size, const eAlertIcon icon)
|
|
|
|
|
{
|
|
|
|
|
const uiStyle *style = UI_style_get_dpi();
|
2025-02-12 18:30:52 +01:00
|
|
|
const short icon_size = 40 * UI_SCALE_FAC;
|
2024-07-19 21:57:49 +02:00
|
|
|
const int dialog_width = icon_size + (style->widget.points * size * UI_SCALE_FAC);
|
2024-01-29 18:52:18 +01:00
|
|
|
return uiItemsAlertBox(block, style, dialog_width, icon, icon_size);
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-06 11:17:51 -08:00
|
|
|
/** \} */
|