Refactor: UI: Use a Vector to store buttons in UI blocks
This changes the ui-blocks buttons storage from Listbase to Vector. Major changes that might cause a performance considerations are in `ui_but_update_from_old_block` that requires to track buttons when restoring button state between block redraws or in `uiItemFullR` that may needs to insert uiButs in the middle of the vector to add decorators. This might not be as fast as removing or inserting elements in the middle of a listbase container. Also buttons currently don't know its position in the container, so to get the previous and next button its required to make a lookup of the button in the container. `UI_block_update_from_old> ui_but_update_from_old_block` restores the state of buttons between frames, this is done by sequentially testing if a button is the same as an old button, however since UI can be created procedurally some old buttons may not be drawn while editing other button data, this requires an extra track of what buttons may not match to a new button while comparing for restoring state, but still this buttons may be candidates to match to an new button. Not functional changes expected. Ref: #117604 Co-authored-by: Julian Eisel <julian@blender.org> Pull Request: https://projects.blender.org/blender/blender/pulls/127128
This commit is contained in:
committed by
Julian Eisel
parent
8b1118451b
commit
7682258ff9
@@ -25,6 +25,7 @@
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_rect.h"
|
||||
#include "BLI_set.hh"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_string_utf8.h"
|
||||
#include "BLI_vector.hh"
|
||||
@@ -258,10 +259,50 @@ void ui_region_to_window(const ARegion *region, int *x, int *y)
|
||||
*y += region->winrct.ymin;
|
||||
}
|
||||
|
||||
int uiBlock::but_index(const uiBut *but) const
|
||||
{
|
||||
BLI_assert(!buttons.is_empty() && but);
|
||||
auto index = std::distance(
|
||||
buttons.begin(),
|
||||
std::find_if(buttons.begin(), buttons.end(), [but](const std::unique_ptr<uiBut> &test) {
|
||||
return test.get() == but;
|
||||
}));
|
||||
BLI_assert(index != std::distance(buttons.begin(), buttons.end()));
|
||||
return index;
|
||||
}
|
||||
|
||||
uiBut *uiBlock::next_but(const uiBut *but) const
|
||||
{
|
||||
const int idx = this->but_index(but) + 1;
|
||||
return idx < this->buttons.size() ? this->buttons[idx].get() : nullptr;
|
||||
}
|
||||
|
||||
uiBut *uiBlock::prev_but(const uiBut *but) const
|
||||
{
|
||||
const int idx = this->but_index(but) - 1;
|
||||
return idx >= 0 ? this->buttons[idx].get() : nullptr;
|
||||
}
|
||||
|
||||
void uiBlock::remove_but(const uiBut *but)
|
||||
{
|
||||
int64_t target_index = this->but_index(but);
|
||||
this->buttons.remove(target_index);
|
||||
}
|
||||
|
||||
uiBut *uiBlock::first_but() const
|
||||
{
|
||||
return !this->buttons.is_empty() ? this->buttons.first().get() : nullptr;
|
||||
}
|
||||
|
||||
uiBut *uiBlock::last_but() const
|
||||
{
|
||||
return !this->buttons.is_empty() ? this->buttons.last().get() : nullptr;
|
||||
}
|
||||
|
||||
static void ui_update_flexible_spacing(const ARegion *region, uiBlock *block)
|
||||
{
|
||||
int sepr_flex_len = 0;
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
if (but->type == UI_BTYPE_SEPR_SPACER) {
|
||||
sepr_flex_len++;
|
||||
}
|
||||
@@ -272,7 +313,7 @@ static void ui_update_flexible_spacing(const ARegion *region, uiBlock *block)
|
||||
}
|
||||
|
||||
rcti rect;
|
||||
ui_but_to_pixelrect(&rect, region, block, static_cast<const uiBut *>(block->buttons.last));
|
||||
ui_but_to_pixelrect(&rect, region, block, block->buttons.last().get());
|
||||
const float buttons_width = float(rect.xmax) + UI_HEADER_OFFSET;
|
||||
const float region_width = float(region->sizex) * UI_SCALE_FAC;
|
||||
|
||||
@@ -282,9 +323,9 @@ static void ui_update_flexible_spacing(const ARegion *region, uiBlock *block)
|
||||
|
||||
/* We could get rid of this loop if we agree on a max number of spacer */
|
||||
Vector<int, 8> spacers_pos;
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
if (but->type == UI_BTYPE_SEPR_SPACER) {
|
||||
ui_but_to_pixelrect(&rect, region, block, but);
|
||||
ui_but_to_pixelrect(&rect, region, block, but.get());
|
||||
spacers_pos.append(rect.xmax + UI_HEADER_OFFSET);
|
||||
}
|
||||
}
|
||||
@@ -293,7 +334,7 @@ static void ui_update_flexible_spacing(const ARegion *region, uiBlock *block)
|
||||
const float segment_width = region_width / float(sepr_flex_len);
|
||||
float offset = 0, remaining_space = region_width - buttons_width;
|
||||
int i = 0;
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
BLI_rctf_translate(&but->rect, offset / view_scale_x, 0);
|
||||
if (but->type == UI_BTYPE_SEPR_SPACER) {
|
||||
/* How much the next block overlap with the current segment */
|
||||
@@ -348,7 +389,7 @@ void ui_region_winrct_get_no_margin(const ARegion *region, rcti *r_rect)
|
||||
|
||||
void UI_block_translate(uiBlock *block, float x, float y)
|
||||
{
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
BLI_rctf_translate(&but->rect, x, y);
|
||||
}
|
||||
|
||||
@@ -363,16 +404,20 @@ static bool ui_but_is_row_alignment_group(const uiBut *left, const uiBut *right)
|
||||
|
||||
static void ui_block_bounds_calc_text(uiBlock *block, float offset)
|
||||
{
|
||||
if (block->buttons.is_empty()) {
|
||||
return;
|
||||
}
|
||||
const uiStyle *style = UI_style_get();
|
||||
uiBut *col_bt;
|
||||
std::unique_ptr<uiBut> *col_bt;
|
||||
int i = 0, j, x1addval = offset;
|
||||
|
||||
UI_fontstyle_set(&style->widget);
|
||||
std::unique_ptr<uiBut> *end = block->buttons.end();
|
||||
|
||||
uiBut *init_col_bt = static_cast<uiBut *>(block->buttons.first);
|
||||
LISTBASE_FOREACH (uiBut *, bt, &block->buttons) {
|
||||
if (!ELEM(bt->type, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE, UI_BTYPE_SEPR_SPACER)) {
|
||||
j = BLF_width(style->widget.uifont_id, bt->drawstr.c_str(), bt->drawstr.size());
|
||||
std::unique_ptr<uiBut> *init_col_bt = block->buttons.begin();
|
||||
for (std::unique_ptr<uiBut> *bt = init_col_bt; bt < end; bt++) {
|
||||
if (!ELEM((*bt)->type, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE, UI_BTYPE_SEPR_SPACER)) {
|
||||
j = BLF_width(style->widget.uifont_id, (*bt)->drawstr.c_str(), (*bt)->drawstr.size());
|
||||
|
||||
i = std::max(j, i);
|
||||
}
|
||||
@@ -380,27 +425,27 @@ static void ui_block_bounds_calc_text(uiBlock *block, float offset)
|
||||
/* Skip all buttons that are in a horizontal alignment group.
|
||||
* We don't want to split them apart (but still check the row's width and apply current
|
||||
* offsets). */
|
||||
if (bt->next && ui_but_is_row_alignment_group(bt, bt->next)) {
|
||||
if (bt + 1 < end && ui_but_is_row_alignment_group((*bt).get(), bt[1].get())) {
|
||||
int width = 0;
|
||||
const int alignnr = bt->alignnr;
|
||||
for (col_bt = bt; col_bt && col_bt->alignnr == alignnr; col_bt = col_bt->next) {
|
||||
width += BLI_rctf_size_x(&col_bt->rect);
|
||||
col_bt->rect.xmin += x1addval;
|
||||
col_bt->rect.xmax += x1addval;
|
||||
const int alignnr = (*bt)->alignnr;
|
||||
for (col_bt = bt; col_bt < end && (*col_bt)->alignnr == alignnr; col_bt++) {
|
||||
width += BLI_rctf_size_x(&(*col_bt)->rect);
|
||||
(*col_bt)->rect.xmin += x1addval;
|
||||
(*col_bt)->rect.xmax += x1addval;
|
||||
}
|
||||
i = std::max(width, i);
|
||||
/* Give the following code the last button in the alignment group, there might have to be a
|
||||
* split immediately after. */
|
||||
bt = col_bt ? col_bt->prev : nullptr;
|
||||
bt = col_bt != end ? col_bt-- : nullptr;
|
||||
}
|
||||
|
||||
if (bt && bt->next && bt->rect.xmin < bt->next->rect.xmin) {
|
||||
if (bt < end && (bt + 1 < end) && (*bt)->rect.xmin < bt[1]->rect.xmin) {
|
||||
/* End of this column, and it's not the last one. */
|
||||
for (col_bt = init_col_bt; col_bt->prev != bt; col_bt = col_bt->next) {
|
||||
col_bt->rect.xmin = x1addval;
|
||||
col_bt->rect.xmax = x1addval + i + block->bounds;
|
||||
for (col_bt = init_col_bt; (col_bt - 1) != bt; col_bt++) {
|
||||
(*col_bt)->rect.xmin = x1addval;
|
||||
(*col_bt)->rect.xmax = x1addval + i + block->bounds;
|
||||
|
||||
ui_but_update(col_bt); /* clips text again */
|
||||
ui_but_update((*col_bt).get()); /* clips text again */
|
||||
}
|
||||
|
||||
/* And we prepare next column. */
|
||||
@@ -411,28 +456,28 @@ static void ui_block_bounds_calc_text(uiBlock *block, float offset)
|
||||
}
|
||||
|
||||
/* Last column. */
|
||||
for (col_bt = init_col_bt; col_bt; col_bt = col_bt->next) {
|
||||
for (col_bt = init_col_bt; col_bt < end; col_bt++) {
|
||||
/* Recognize a horizontally arranged alignment group and skip its items. */
|
||||
if (col_bt->next && ui_but_is_row_alignment_group(col_bt, col_bt->next)) {
|
||||
const int alignnr = col_bt->alignnr;
|
||||
for (; col_bt && col_bt->alignnr == alignnr; col_bt = col_bt->next) {
|
||||
if ((col_bt + 1 < end) && ui_but_is_row_alignment_group((*col_bt).get(), col_bt[1].get())) {
|
||||
const int alignnr = (*col_bt)->alignnr;
|
||||
for (; col_bt < end && (*col_bt)->alignnr == alignnr; col_bt++) {
|
||||
/* pass */
|
||||
}
|
||||
}
|
||||
if (!col_bt) {
|
||||
if (col_bt == end) {
|
||||
break;
|
||||
}
|
||||
|
||||
col_bt->rect.xmin = x1addval;
|
||||
col_bt->rect.xmax = max_ff(x1addval + i + block->bounds, offset + block->minbounds);
|
||||
(*col_bt)->rect.xmin = x1addval;
|
||||
(*col_bt)->rect.xmax = max_ff(x1addval + i + block->bounds, offset + block->minbounds);
|
||||
|
||||
ui_but_update(col_bt); /* clips text again */
|
||||
ui_but_update((*col_bt).get()); /* clips text again */
|
||||
}
|
||||
}
|
||||
|
||||
void ui_block_bounds_calc(uiBlock *block)
|
||||
{
|
||||
if (BLI_listbase_is_empty(&block->buttons)) {
|
||||
if (block->buttons.is_empty()) {
|
||||
if (block->panel) {
|
||||
block->rect.xmin = 0.0;
|
||||
block->rect.xmax = block->panel->sizex;
|
||||
@@ -444,7 +489,7 @@ void ui_block_bounds_calc(uiBlock *block)
|
||||
|
||||
BLI_rctf_init_minmax(&block->rect);
|
||||
|
||||
LISTBASE_FOREACH (uiBut *, bt, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &bt : block->buttons) {
|
||||
BLI_rctf_union(&block->rect, &bt->rect);
|
||||
}
|
||||
|
||||
@@ -457,7 +502,7 @@ void ui_block_bounds_calc(uiBlock *block)
|
||||
block->rect.xmax = block->rect.xmin + max_ff(BLI_rctf_size_x(&block->rect), block->minbounds);
|
||||
|
||||
/* hardcoded exception... but that one is annoying with larger safety */
|
||||
uiBut *bt = static_cast<uiBut *>(block->buttons.first);
|
||||
uiBut *bt = block->first_but();
|
||||
const int xof = ((bt && STRPREFIX(bt->str.c_str(), "ERROR")) ? 10 : 40) * UI_SCALE_FAC;
|
||||
|
||||
block->safety.xmin = block->rect.xmin - xof;
|
||||
@@ -797,21 +842,43 @@ static bool ui_but_equals_old(const uiBut *but, const uiBut *oldbut)
|
||||
return true;
|
||||
}
|
||||
|
||||
uiBut *ui_but_find_old(uiBlock *block_old, const uiBut *but_new)
|
||||
static uiBut *ui_but_find_old(uiBlock *block_old,
|
||||
const uiBut *but_new,
|
||||
const blender::Set<const uiBut *> &ignore_old_buttons)
|
||||
{
|
||||
LISTBASE_FOREACH (uiBut *, but, &block_old->buttons) {
|
||||
if (ui_but_equals_old(but_new, but)) {
|
||||
return but;
|
||||
for (const std::unique_ptr<uiBut> &but : block_old->buttons) {
|
||||
if (!ignore_old_buttons.contains(but.get()) && ui_but_equals_old(but_new, but.get())) {
|
||||
return but.get();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uiBut *ui_but_find_old(uiBlock *block_old, const uiBut *but_new)
|
||||
{
|
||||
return ui_but_find_old(block_old, but_new, {});
|
||||
}
|
||||
|
||||
static std::optional<int64_t> ui_but_find_old_idx(
|
||||
uiBlock *block_old,
|
||||
const uiBut *but_new,
|
||||
const blender::Set<const uiBut *> &ignore_old_buttons = {})
|
||||
{
|
||||
int64_t i = 0;
|
||||
for (const std::unique_ptr<uiBut> &but : block_old->buttons) {
|
||||
if (!ignore_old_buttons.contains(but.get()) && ui_but_equals_old(but_new, but.get())) {
|
||||
return i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
uiBut *ui_but_find_new(uiBlock *block_new, const uiBut *but_old)
|
||||
{
|
||||
LISTBASE_FOREACH (uiBut *, but, &block_new->buttons) {
|
||||
if (ui_but_equals_old(but, but_old)) {
|
||||
return but;
|
||||
for (const std::unique_ptr<uiBut> &but : block_new->buttons) {
|
||||
if (ui_but_equals_old(but.get(), but_old)) {
|
||||
return but.get();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
@@ -960,49 +1027,84 @@ static void ui_but_update_old_active_from_new(uiBut *oldbut, uiBut *but)
|
||||
}
|
||||
|
||||
/**
|
||||
* \return true when \a but_p is set (only done for active buttons).
|
||||
* Optimization:
|
||||
* \a but_old_idx is used to avoid having to lookup the matching button from the old
|
||||
* block on every iteration. On most redraws, button order doesn't change, so the index of the new
|
||||
* button is the index of the matching old button. Only if they don't match using the expected
|
||||
* index, a lookup has to be performed. Even if individual buttons are inserted or removed, likely
|
||||
* at some point the following buttons (if any) will match again, so successive indices will
|
||||
* produce successive matches again. Think of \a but_old_idx as a cursor that indicates the
|
||||
* likely/expected position of the matching button in the old block. This optimization brings
|
||||
* the whole button updating to O(n) amortized time instead of O(n^2).
|
||||
*
|
||||
* \param matched_old_buttons: Collects all previously found matches in the old block. These should
|
||||
* be ignored when looking up further matches.
|
||||
* \param but_uptr: The owning pointer for the button to update. The pointed to button may be
|
||||
* replaced, in which case the function will return true.
|
||||
* \param but_old_idx: Index into the old-button vector indicating the likely/expected position of
|
||||
* the matching button in the old block, for the optimization explained above. Value is optional
|
||||
* because sometimes the expected position of the following matching button can not be determined,
|
||||
* in which case a full lookup will have to be performed.
|
||||
*
|
||||
* \return true when the button pointed to by \a but_uptr is replaced (only done for active
|
||||
* buttons).
|
||||
*/
|
||||
static bool ui_but_update_from_old_block(const bContext *C,
|
||||
uiBlock *block,
|
||||
uiBut **but_p,
|
||||
uiBut **but_old_p)
|
||||
static bool ui_but_update_from_old_block(uiBlock *block,
|
||||
blender::Set<const uiBut *> &matched_old_buttons,
|
||||
std::unique_ptr<uiBut> *but_uptr,
|
||||
std::optional<int64_t> *but_old_idx)
|
||||
{
|
||||
uiBlock *oldblock = block->oldblock;
|
||||
uiBut *but = *but_p;
|
||||
uiBut *but = but_uptr->get();
|
||||
|
||||
#if 0
|
||||
/* Simple method - search every time. Keep this for easy testing of the "fast path." */
|
||||
uiBut *oldbut = ui_but_find_old(oldblock, but);
|
||||
uiBut *oldbut = ui_but_find_old(oldblock, but, matched_old_buttons);
|
||||
UNUSED_VARS(but_old_p);
|
||||
#else
|
||||
BLI_assert(*but_old_p == nullptr || BLI_findindex(&oldblock->buttons, *but_old_p) != -1);
|
||||
BLI_assert(!but_old_idx->has_value() || oldblock->buttons.index_range().contains(**but_old_idx));
|
||||
|
||||
/* As long as old and new buttons are aligned, avoid loop-in-loop (calling #ui_but_find_old). */
|
||||
uiBut *oldbut;
|
||||
if (LIKELY(*but_old_p && ui_but_equals_old(but, *but_old_p))) {
|
||||
oldbut = *but_old_p;
|
||||
std::unique_ptr<uiBut> *oldbut_uptr;
|
||||
if (LIKELY(but_old_idx->has_value() &&
|
||||
/* Ignore previously matched buttons. */
|
||||
!matched_old_buttons.contains(oldblock->buttons[**but_old_idx].get()) &&
|
||||
ui_but_equals_old(but, oldblock->buttons[**but_old_idx].get())))
|
||||
{
|
||||
oldbut_uptr = &oldblock->buttons[**but_old_idx];
|
||||
}
|
||||
else {
|
||||
/* Fallback to block search. */
|
||||
oldbut = ui_but_find_old(oldblock, but);
|
||||
*but_old_idx = ui_but_find_old_idx(oldblock, but, matched_old_buttons);
|
||||
oldbut_uptr = but_old_idx->has_value() ? &oldblock->buttons[**but_old_idx] : nullptr;
|
||||
}
|
||||
(*but_old_p) = oldbut ? oldbut->next : nullptr;
|
||||
/* Increase for next iteration. */
|
||||
*but_old_idx = (but_old_idx->has_value() &&
|
||||
(but_old_idx->value() + 1 < oldblock->buttons.size())) ?
|
||||
std::optional{but_old_idx->value() + 1} :
|
||||
std::nullopt;
|
||||
#endif
|
||||
|
||||
bool found_active = false;
|
||||
|
||||
if (!oldbut) {
|
||||
if (!oldbut_uptr) {
|
||||
return false;
|
||||
}
|
||||
uiBut *oldbut = oldbut_uptr->get();
|
||||
|
||||
BLI_assert(!matched_old_buttons.contains(oldbut));
|
||||
|
||||
if (oldbut->active || oldbut->semi_modal_state) {
|
||||
/* Move button over from oldblock to new block. */
|
||||
BLI_remlink(&oldblock->buttons, oldbut);
|
||||
BLI_insertlinkafter(&block->buttons, but, oldbut);
|
||||
oldbut_uptr->swap(*but_uptr);
|
||||
BLI_assert(but_uptr->get() == oldbut);
|
||||
/* `but` was moved to oldblock, taking oldbut place. */
|
||||
BLI_assert(!matched_old_buttons.contains(but));
|
||||
matched_old_buttons.add(but);
|
||||
|
||||
/* Add the old button to the button groups in the new block. */
|
||||
ui_button_group_replace_but_ptr(block, but, oldbut);
|
||||
oldbut->block = block;
|
||||
*but_p = oldbut;
|
||||
|
||||
ui_but_update_old_active_from_new(oldbut, but);
|
||||
|
||||
@@ -1010,12 +1112,10 @@ static bool ui_but_update_from_old_block(const bContext *C,
|
||||
UI_butstore_register_update(block, oldbut, but);
|
||||
}
|
||||
|
||||
BLI_remlink(&block->buttons, but);
|
||||
ui_but_free(C, but);
|
||||
|
||||
found_active = true;
|
||||
}
|
||||
else {
|
||||
matched_old_buttons.add(oldbut);
|
||||
int flag_copy = UI_BUT_DRAG_MULTI;
|
||||
|
||||
/* Stupid special case: The active button may be inside (as in, overlapped on top) a row
|
||||
@@ -1025,11 +1125,6 @@ static bool ui_but_update_from_old_block(const bContext *C,
|
||||
}
|
||||
|
||||
but->flag = (but->flag & ~flag_copy) | (oldbut->flag & flag_copy);
|
||||
|
||||
/* ensures one button can get activated, and in case the buttons
|
||||
* draw are the same this gives O(1) lookup for each button */
|
||||
BLI_remlink(&oldblock->buttons, oldbut);
|
||||
ui_but_free(C, oldbut);
|
||||
}
|
||||
|
||||
return found_active;
|
||||
@@ -1065,11 +1160,11 @@ bool UI_but_active_only_ex(
|
||||
}
|
||||
else if ((found == true) && (isactive == false)) {
|
||||
if (remove_on_failure) {
|
||||
BLI_remlink(&block->buttons, but);
|
||||
if (but->layout) {
|
||||
ui_layout_remove_but(but->layout, but);
|
||||
}
|
||||
ui_but_free(C, but);
|
||||
block->remove_but(but);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1089,11 +1184,11 @@ bool UI_block_active_only_flagged_buttons(const bContext *C, ARegion *region, ui
|
||||
BLI_assert(block->endblock);
|
||||
|
||||
bool done = false;
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
if (but->flag & UI_BUT_ACTIVATE_ON_INIT) {
|
||||
but->flag &= ~UI_BUT_ACTIVATE_ON_INIT;
|
||||
if (ui_but_is_editable(but)) {
|
||||
if (UI_but_active_only_ex(C, region, block, but, false)) {
|
||||
if (ui_but_is_editable(but.get())) {
|
||||
if (UI_but_active_only_ex(C, region, block, but.get(), false)) {
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
@@ -1104,7 +1199,7 @@ bool UI_block_active_only_flagged_buttons(const bContext *C, ARegion *region, ui
|
||||
if (done) {
|
||||
/* Run this in a second pass since it's possible activating the button
|
||||
* removes the buttons being looped over. */
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
but->flag &= ~UI_BUT_ACTIVATE_ON_INIT;
|
||||
}
|
||||
}
|
||||
@@ -1153,7 +1248,7 @@ static void ui_menu_block_set_keyaccels(uiBlock *block)
|
||||
/* 2 Passes: One for first letter only, second for any letter if the first pass fails.
|
||||
* Run first pass on all buttons so first word chars always get first priority. */
|
||||
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
if (!ELEM(but->type,
|
||||
UI_BTYPE_BUT,
|
||||
UI_BTYPE_BUT_MENU,
|
||||
@@ -1569,21 +1664,21 @@ static void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block)
|
||||
}
|
||||
|
||||
if (block->flag & UI_BLOCK_PIE_MENU) {
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
if (but->pie_dir != UI_RADIAL_NONE) {
|
||||
const std::string str = ui_but_pie_direction_string(but);
|
||||
ui_but_add_shortcut(but, str.c_str(), false);
|
||||
const std::string str = ui_but_pie_direction_string(but.get());
|
||||
ui_but_add_shortcut(but.get(), str.c_str(), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
if (block->flag & UI_BLOCK_SHOW_SHORTCUT_ALWAYS) {
|
||||
/* Skip icon-only buttons (as used in the toolbar). */
|
||||
if (but->drawstr[0] == '\0') {
|
||||
continue;
|
||||
}
|
||||
if (((block->flag & UI_BLOCK_POPOVER) == 0) && UI_but_is_tool(but)) {
|
||||
if (((block->flag & UI_BLOCK_POPOVER) == 0) && UI_but_is_tool(but.get())) {
|
||||
/* For non-popovers, shown in shortcut only
|
||||
* (has special shortcut handling code). */
|
||||
continue;
|
||||
@@ -1593,13 +1688,13 @@ static void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (const std::optional<std::string> str = ui_but_event_operator_string(C, but)) {
|
||||
ui_but_add_shortcut(but, str->c_str(), false);
|
||||
if (const std::optional<std::string> str = ui_but_event_operator_string(C, but.get())) {
|
||||
ui_but_add_shortcut(but.get(), str->c_str(), false);
|
||||
}
|
||||
else if (const std::optional<std::string> str = ui_but_event_property_operator_string(C,
|
||||
but))
|
||||
else if (const std::optional<std::string> str = ui_but_event_property_operator_string(
|
||||
C, but.get()))
|
||||
{
|
||||
ui_but_add_shortcut(but, str->c_str(), false);
|
||||
ui_but_add_shortcut(but.get(), str->c_str(), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1846,22 +1941,28 @@ void UI_block_update_from_old(const bContext *C, uiBlock *block)
|
||||
return;
|
||||
}
|
||||
|
||||
uiBut *but_old = static_cast<uiBut *>(block->oldblock->buttons.first);
|
||||
|
||||
if (BLI_listbase_is_empty(&block->oldblock->butstore) == false) {
|
||||
UI_butstore_update(block);
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
if (ui_but_update_from_old_block(C, block, &but, &but_old)) {
|
||||
ui_but_update(but);
|
||||
std::optional<int64_t> but_old_idx = block->oldblock->buttons.is_empty() ? std::nullopt :
|
||||
std::optional{0};
|
||||
blender::Set<const uiBut *> matched_old_buttons;
|
||||
matched_old_buttons.reserve(block->oldblock->buttons.size());
|
||||
for (std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
if (ui_but_update_from_old_block(block, matched_old_buttons, &but, &but_old_idx)) {
|
||||
ui_but_update(but.get());
|
||||
|
||||
/* redraw dynamic tooltip if we have one open */
|
||||
if (but->tip_func) {
|
||||
UI_but_tooltip_refresh((bContext *)C, but);
|
||||
UI_but_tooltip_refresh((bContext *)C, but.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const std::unique_ptr<uiBut> &but : block->oldblock->buttons) {
|
||||
ui_but_free(C, but.get());
|
||||
}
|
||||
block->oldblock->buttons.clear_and_shrink();
|
||||
|
||||
block->auto_open = block->oldblock->auto_open;
|
||||
block->auto_open_last = block->oldblock->auto_open_last;
|
||||
@@ -1947,8 +2048,8 @@ void UI_block_end_ex(const bContext *C,
|
||||
BLI_assert(block->active);
|
||||
|
||||
/* Extend button data. This needs to be done before the block updating. */
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
ui_but_predefined_extra_operator_icons_add(but);
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
ui_but_predefined_extra_operator_icons_add(but.get());
|
||||
}
|
||||
|
||||
UI_block_update_from_old(C, block);
|
||||
@@ -1957,32 +2058,32 @@ void UI_block_end_ex(const bContext *C,
|
||||
* on matching buttons, we need this to make button event handling non
|
||||
* blocking, while still allowing buttons to be remade each redraw as it
|
||||
* is expected by blender code */
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
/* temp? Proper check for graying out */
|
||||
if (but->optype) {
|
||||
wmOperatorType *ot = but->optype;
|
||||
|
||||
if (ot == nullptr || !ui_but_context_poll_operator((bContext *)C, ot, but)) {
|
||||
if (ot == nullptr || !ui_but_context_poll_operator((bContext *)C, ot, but.get())) {
|
||||
but->flag |= UI_BUT_DISABLED;
|
||||
}
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (uiButExtraOpIcon *, op_icon, &but->extra_op_icons) {
|
||||
if (!ui_but_context_poll_operator_ex((bContext *)C, but, op_icon->optype_params)) {
|
||||
if (!ui_but_context_poll_operator_ex((bContext *)C, but.get(), op_icon->optype_params)) {
|
||||
op_icon->disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(
|
||||
depsgraph, (scene) ? scene->r.cfra : 0.0f);
|
||||
ui_but_anim_flag(but, &anim_eval_context);
|
||||
ui_but_override_flag(bmain, but);
|
||||
ui_but_anim_flag(but.get(), &anim_eval_context);
|
||||
ui_but_override_flag(bmain, but.get());
|
||||
if (UI_but_is_decorator(but)) {
|
||||
ui_but_anim_decorate_update_from_flag((uiButDecorator *)but);
|
||||
ui_but_anim_decorate_update_from_flag((uiButDecorator *)but.get());
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
ui_but_validate(but);
|
||||
ui_but_validate(but.get());
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -2159,12 +2260,12 @@ void UI_block_draw(const bContext *C, uiBlock *block)
|
||||
UI_widgetbase_draw_cache_begin();
|
||||
|
||||
/* widgets */
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
if (but->flag & (UI_HIDDEN | UI_SCROLLED)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ui_but_to_pixelrect(&rect, region, block, but);
|
||||
ui_but_to_pixelrect(&rect, region, block, but.get());
|
||||
/* Optimization: Don't draw buttons that are not visible (outside view bounds). */
|
||||
if (!ui_but_pixelrect_in_view(region, &rect)) {
|
||||
continue;
|
||||
@@ -2173,7 +2274,7 @@ void UI_block_draw(const bContext *C, uiBlock *block)
|
||||
/* XXX: figure out why invalid coordinates happen when closing render window */
|
||||
/* and material preview is redrawn in main window (temp fix for bug #23848) */
|
||||
if (rect.xmin < rect.xmax && rect.ymin < rect.ymax) {
|
||||
ui_draw_but(C, region, &style, but, &rect);
|
||||
ui_draw_but(C, region, &style, but.get(), &rect);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2191,7 +2292,7 @@ static void ui_block_message_subscribe(ARegion *region, wmMsgBus *mbus, uiBlock
|
||||
{
|
||||
uiBut *but_prev = nullptr;
|
||||
/* possibly we should keep the region this block is contained in? */
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
if (but->rnapoin.type && but->rnaprop) {
|
||||
/* quick check to avoid adding buttons representing a vector, multiple times. */
|
||||
if ((but_prev && (but_prev->rnaprop == but->rnaprop) &&
|
||||
@@ -2205,7 +2306,7 @@ static void ui_block_message_subscribe(ARegion *region, wmMsgBus *mbus, uiBlock
|
||||
value.user_data = region;
|
||||
value.notify = ED_region_do_msg_notify_tag_redraw;
|
||||
WM_msg_subscribe_rna(mbus, &but->rnapoin, but->rnaprop, &value, __func__);
|
||||
but_prev = but;
|
||||
but_prev = but.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2816,9 +2917,9 @@ uiBut *ui_but_drag_multi_edit_get(uiBut *but)
|
||||
|
||||
BLI_assert(but->flag & UI_BUT_DRAG_MULTI);
|
||||
|
||||
LISTBASE_FOREACH (uiBut *, but_iter, &but->block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but_iter : but->block->buttons) {
|
||||
if (but_iter->editstr) {
|
||||
return_but = but_iter;
|
||||
return_but = but_iter.get();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -3537,69 +3638,10 @@ static void ui_but_free_type_specific(uiBut *but)
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the proper type of data is destructed, from a generic #uiBut pointer. Should always
|
||||
* match behavior of #ui_but_new.
|
||||
* Frees internal data owned by the #but, however this does not free the #but itself, the
|
||||
* #but is managed with a #std::unique_ptr, this must be called before the #std::unique_ptr owner
|
||||
* is destroyed.
|
||||
*/
|
||||
static void ui_but_mem_delete(const uiBut *but)
|
||||
{
|
||||
switch (but->type) {
|
||||
case UI_BTYPE_NUM:
|
||||
MEM_delete(reinterpret_cast<const uiButNumber *>(but));
|
||||
break;
|
||||
case UI_BTYPE_NUM_SLIDER:
|
||||
MEM_delete(reinterpret_cast<const uiButNumberSlider *>(but));
|
||||
break;
|
||||
case UI_BTYPE_COLOR:
|
||||
MEM_delete(reinterpret_cast<const uiButColor *>(but));
|
||||
break;
|
||||
case UI_BTYPE_DECORATOR:
|
||||
MEM_delete(reinterpret_cast<const uiButDecorator *>(but));
|
||||
break;
|
||||
case UI_BTYPE_TAB:
|
||||
MEM_delete(reinterpret_cast<const uiButTab *>(but));
|
||||
break;
|
||||
case UI_BTYPE_SEARCH_MENU:
|
||||
MEM_delete(reinterpret_cast<const uiButSearch *>(but));
|
||||
break;
|
||||
case UI_BTYPE_PROGRESS:
|
||||
MEM_delete(reinterpret_cast<const uiButProgress *>(but));
|
||||
break;
|
||||
case UI_BTYPE_SEPR_LINE:
|
||||
MEM_delete(reinterpret_cast<const uiButSeparatorLine *>(but));
|
||||
break;
|
||||
case UI_BTYPE_HSVCUBE:
|
||||
MEM_delete(reinterpret_cast<const uiButHSVCube *>(but));
|
||||
break;
|
||||
case UI_BTYPE_COLORBAND:
|
||||
MEM_delete(reinterpret_cast<const uiButColorBand *>(but));
|
||||
break;
|
||||
case UI_BTYPE_CURVE:
|
||||
MEM_delete(reinterpret_cast<const uiButCurveMapping *>(but));
|
||||
break;
|
||||
case UI_BTYPE_CURVEPROFILE:
|
||||
MEM_delete(reinterpret_cast<const uiButCurveProfile *>(but));
|
||||
break;
|
||||
case UI_BTYPE_HOTKEY_EVENT:
|
||||
MEM_delete(reinterpret_cast<const uiButHotkeyEvent *>(but));
|
||||
break;
|
||||
case UI_BTYPE_VIEW_ITEM:
|
||||
MEM_delete(reinterpret_cast<const uiButViewItem *>(but));
|
||||
break;
|
||||
case UI_BTYPE_LABEL:
|
||||
MEM_delete(reinterpret_cast<const uiButLabel *>(but));
|
||||
break;
|
||||
case UI_BTYPE_SCROLL:
|
||||
MEM_delete(reinterpret_cast<const uiButScrollBar *>(but));
|
||||
break;
|
||||
default:
|
||||
BLI_assert_msg(MEM_allocN_len(but) == sizeof(uiBut),
|
||||
"Derived button type needs type specific deletion");
|
||||
MEM_delete(but);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* can be called with C==nullptr */
|
||||
static void ui_but_free(const bContext *C, uiBut *but)
|
||||
{
|
||||
if (but->opptr) {
|
||||
@@ -3655,8 +3697,6 @@ static void ui_but_free(const bContext *C, uiBut *but)
|
||||
ui_but_extra_operator_icons_free(but);
|
||||
|
||||
BLI_assert(UI_butstore_is_registered(but->block, but) == false);
|
||||
|
||||
ui_but_mem_delete(but);
|
||||
}
|
||||
|
||||
static void ui_block_free_active_operator(uiBlock *block)
|
||||
@@ -3686,9 +3726,10 @@ void UI_block_free(const bContext *C, uiBlock *block)
|
||||
{
|
||||
UI_butstore_clear(block);
|
||||
|
||||
while (uiBut *but = static_cast<uiBut *>(BLI_pophead(&block->buttons))) {
|
||||
ui_but_free(C, but);
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
ui_but_free(C, but.get());
|
||||
}
|
||||
block->buttons.clear();
|
||||
|
||||
if (block->unit) {
|
||||
MEM_freeN((void *)block->unit);
|
||||
@@ -4161,64 +4202,62 @@ void ui_block_cm_to_display_space_v3(uiBlock *block, float pixel[3])
|
||||
|
||||
/**
|
||||
* Factory function: Allocate button and set #uiBut.type.
|
||||
*
|
||||
* \note #ui_but_mem_delete is the matching 'destructor' function.
|
||||
*/
|
||||
static uiBut *ui_but_new(const eButType type)
|
||||
static std::unique_ptr<uiBut> ui_but_new(const eButType type)
|
||||
{
|
||||
uiBut *but = nullptr;
|
||||
std::unique_ptr<uiBut> but{};
|
||||
|
||||
switch (type) {
|
||||
case UI_BTYPE_NUM:
|
||||
but = MEM_new<uiButNumber>("uiButNumber");
|
||||
but = std::make_unique<uiButNumber>();
|
||||
break;
|
||||
case UI_BTYPE_NUM_SLIDER:
|
||||
but = MEM_new<uiButNumberSlider>("uiButNumber");
|
||||
but = std::make_unique<uiButNumberSlider>();
|
||||
break;
|
||||
case UI_BTYPE_COLOR:
|
||||
but = MEM_new<uiButColor>("uiButColor");
|
||||
but = std::make_unique<uiButColor>();
|
||||
break;
|
||||
case UI_BTYPE_DECORATOR:
|
||||
but = MEM_new<uiButDecorator>("uiButDecorator");
|
||||
but = std::make_unique<uiButDecorator>();
|
||||
break;
|
||||
case UI_BTYPE_TAB:
|
||||
but = MEM_new<uiButTab>("uiButTab");
|
||||
but = std::make_unique<uiButTab>();
|
||||
break;
|
||||
case UI_BTYPE_SEARCH_MENU:
|
||||
but = MEM_new<uiButSearch>("uiButSearch");
|
||||
but = std::make_unique<uiButSearch>();
|
||||
break;
|
||||
case UI_BTYPE_PROGRESS:
|
||||
but = MEM_new<uiButProgress>("uiButProgress");
|
||||
but = std::make_unique<uiButProgress>();
|
||||
break;
|
||||
case UI_BTYPE_SEPR_LINE:
|
||||
but = MEM_new<uiButSeparatorLine>("uiButSeparatorLine");
|
||||
but = std::make_unique<uiButSeparatorLine>();
|
||||
break;
|
||||
case UI_BTYPE_HSVCUBE:
|
||||
but = MEM_new<uiButHSVCube>("uiButHSVCube");
|
||||
but = std::make_unique<uiButHSVCube>();
|
||||
break;
|
||||
case UI_BTYPE_COLORBAND:
|
||||
but = MEM_new<uiButColorBand>("uiButColorBand");
|
||||
but = std::make_unique<uiButColorBand>();
|
||||
break;
|
||||
case UI_BTYPE_CURVE:
|
||||
but = MEM_new<uiButCurveMapping>("uiButCurveMapping");
|
||||
but = std::make_unique<uiButCurveMapping>();
|
||||
break;
|
||||
case UI_BTYPE_CURVEPROFILE:
|
||||
but = MEM_new<uiButCurveProfile>("uiButCurveProfile");
|
||||
but = std::make_unique<uiButCurveProfile>();
|
||||
break;
|
||||
case UI_BTYPE_HOTKEY_EVENT:
|
||||
but = MEM_new<uiButHotkeyEvent>("uiButHotkeyEvent");
|
||||
but = std::make_unique<uiButHotkeyEvent>();
|
||||
break;
|
||||
case UI_BTYPE_VIEW_ITEM:
|
||||
but = MEM_new<uiButViewItem>("uiButViewItem");
|
||||
but = std::make_unique<uiButViewItem>();
|
||||
break;
|
||||
case UI_BTYPE_LABEL:
|
||||
but = MEM_new<uiButLabel>("uiButLabel");
|
||||
but = std::make_unique<uiButLabel>();
|
||||
break;
|
||||
case UI_BTYPE_SCROLL:
|
||||
but = MEM_new<uiButScrollBar>("uiButScrollBar");
|
||||
but = std::make_unique<uiButScrollBar>();
|
||||
break;
|
||||
default:
|
||||
but = MEM_new<uiBut>("uiBut");
|
||||
but = std::make_unique<uiBut>();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -4233,17 +4272,17 @@ uiBut *ui_but_change_type(uiBut *but, eButType new_type)
|
||||
return but;
|
||||
}
|
||||
|
||||
uiBut *insert_after_but = but->prev;
|
||||
const int64_t but_index = but->block->but_index(but);
|
||||
|
||||
/* Remove old button address */
|
||||
BLI_remlink(&but->block->buttons, but);
|
||||
std::unique_ptr<uiBut> old_but_ptr = std::move(but->block->buttons[but_index]);
|
||||
|
||||
const uiBut *old_but_ptr = but;
|
||||
/* Button may have pointer to a member within itself, this will have to be updated. */
|
||||
const bool has_poin_ptr_to_self = but->poin == (char *)but;
|
||||
|
||||
/* Copy construct button with the new type. */
|
||||
but = ui_but_new(new_type);
|
||||
but->block->buttons[but_index] = ui_but_new(new_type);
|
||||
but = but->block->buttons[but_index].get();
|
||||
*but = *old_but_ptr;
|
||||
/* We didn't mean to override this :) */
|
||||
but->type = new_type;
|
||||
@@ -4251,22 +4290,18 @@ uiBut *ui_but_change_type(uiBut *but, eButType new_type)
|
||||
but->poin = (char *)but;
|
||||
}
|
||||
|
||||
BLI_insertlinkafter(&but->block->buttons, insert_after_but, but);
|
||||
|
||||
if (but->layout) {
|
||||
const bool found_layout = ui_layout_replace_but_ptr(but->layout, old_but_ptr, but);
|
||||
const bool found_layout = ui_layout_replace_but_ptr(but->layout, old_but_ptr.get(), but);
|
||||
BLI_assert(found_layout);
|
||||
UNUSED_VARS_NDEBUG(found_layout);
|
||||
ui_button_group_replace_but_ptr(uiLayoutGetBlock(but->layout), old_but_ptr, but);
|
||||
ui_button_group_replace_but_ptr(uiLayoutGetBlock(but->layout), old_but_ptr.get(), but);
|
||||
}
|
||||
#ifdef WITH_PYTHON
|
||||
if (UI_editsource_enable_check()) {
|
||||
UI_editsource_but_replace(old_but_ptr, but);
|
||||
UI_editsource_but_replace(old_but_ptr.get(), but);
|
||||
}
|
||||
#endif
|
||||
|
||||
ui_but_mem_delete(old_but_ptr);
|
||||
|
||||
return but;
|
||||
}
|
||||
|
||||
@@ -4297,7 +4332,8 @@ static uiBut *ui_def_but(uiBlock *block,
|
||||
}
|
||||
}
|
||||
|
||||
uiBut *but = ui_but_new((eButType)(type & BUTTYPE));
|
||||
block->buttons.append(ui_but_new((eButType)(type & BUTTYPE)));
|
||||
uiBut *but = block->buttons.last().get();
|
||||
|
||||
but->pointype = (eButPointerType)(type & UI_BUT_POIN_TYPES);
|
||||
but->bit = type & UI_BUT_POIN_BIT;
|
||||
@@ -4407,8 +4443,6 @@ static uiBut *ui_def_but(uiBlock *block,
|
||||
but->dragflag |= UI_BUT_DRAG_FULL_BUT;
|
||||
}
|
||||
|
||||
BLI_addtail(&block->buttons, but);
|
||||
|
||||
if (block->curlayout) {
|
||||
ui_layout_add_but(block->curlayout, but);
|
||||
}
|
||||
@@ -4528,8 +4562,9 @@ static void ui_def_but_rna__menu(bContext *C, uiLayout *layout, void *but_p)
|
||||
const char *title = RNA_property_ui_name(but->rnaprop);
|
||||
|
||||
/* Is there a non-blank label before this button on the same row? */
|
||||
const bool prior_label = but->prev && but->prev->type == UI_BTYPE_LABEL && but->prev->str[0] &&
|
||||
but->prev->alignnr == but->alignnr;
|
||||
uiBut *but_prev = but->block->prev_but(but);
|
||||
const bool prior_label = but_prev && but_prev->type == UI_BTYPE_LABEL && but_prev->str[0] &&
|
||||
but_prev->alignnr == but->alignnr;
|
||||
|
||||
/* When true, store a copy of the description and use the tool-tip callback to return that copy.
|
||||
* This way, further calls to #EnumPropertyRNA::item_fn which occur when evaluating shortcuts
|
||||
|
||||
@@ -376,10 +376,10 @@ void ui_block_align_calc(uiBlock *block, const ARegion *region)
|
||||
/* First loop: we count number of buttons belonging to an align group,
|
||||
* and clear their align flag.
|
||||
* Tabs get some special treatment here, they get aligned to region border. */
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
/* special case: tabs need to be aligned to a region border, drawflag tells which one */
|
||||
if (but->type == UI_BTYPE_TAB) {
|
||||
ui_block_align_but_to_region(but, region);
|
||||
ui_block_align_but_to_region(but.get(), region);
|
||||
}
|
||||
else {
|
||||
/* Clear old align flags. */
|
||||
@@ -411,9 +411,9 @@ void ui_block_align_calc(uiBlock *block, const ARegion *region)
|
||||
|
||||
/* Second loop: we initialize our ButAlign data for each button. */
|
||||
butal = butal_array;
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
if (but->alignnr != 0) {
|
||||
butal->but = but;
|
||||
butal->but = but.get();
|
||||
butal->borders[LEFT] = &but->rect.xmin;
|
||||
butal->borders[RIGHT] = &but->rect.xmax;
|
||||
butal->borders[DOWN] = &but->rect.ymin;
|
||||
|
||||
@@ -129,16 +129,22 @@ static uiBut *ui_but_anim_decorate_find_attached_button(uiButDecorator *but)
|
||||
|
||||
BLI_assert(UI_but_is_decorator(but));
|
||||
BLI_assert(but->decorated_rnapoin.data && but->decorated_rnaprop);
|
||||
|
||||
LISTBASE_CIRCULAR_BACKWARD_BEGIN (uiBut *, &but->block->buttons, but_iter, but->prev) {
|
||||
if (but->block->buttons.is_empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
int i = but->block->but_index(but);
|
||||
i = i > 0 ? i - 1 : but->block->buttons.size() - 1;
|
||||
const int start = i;
|
||||
do {
|
||||
but_iter = but->block->buttons[i].get();
|
||||
if (but_iter != but &&
|
||||
ui_but_rna_equals_ex(
|
||||
but_iter, &but->decorated_rnapoin, but->decorated_rnaprop, but->decorated_rnaindex))
|
||||
{
|
||||
return but_iter;
|
||||
}
|
||||
}
|
||||
LISTBASE_CIRCULAR_BACKWARD_END(uiBut *, &but->block->buttons, but_iter, but->prev);
|
||||
i = i > 0 ? i - 1 : but->block->buttons.size() - 1;
|
||||
} while (i != start);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ static Vector<rcti> button_section_bounds_calc(const ARegion *region, const bool
|
||||
continue;
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
if (but->type == UI_BTYPE_SEPR_SPACER) {
|
||||
/* Start a new section. */
|
||||
if (has_section_content) {
|
||||
@@ -89,7 +89,7 @@ static Vector<rcti> button_section_bounds_calc(const ARegion *region, const bool
|
||||
}
|
||||
|
||||
rcti but_pixelrect;
|
||||
ui_but_to_pixelrect(&but_pixelrect, region, block, but);
|
||||
ui_but_to_pixelrect(&but_pixelrect, region, block, but.get());
|
||||
BLI_rcti_do_minmax_rcti(&cur_section_bounds, &but_pixelrect);
|
||||
has_section_content = true;
|
||||
}
|
||||
|
||||
@@ -1444,7 +1444,7 @@ void ui_popup_context_menu_for_panel(bContext *C, ARegion *region, Panel *panel)
|
||||
/* evil, force shortcut flag */
|
||||
{
|
||||
uiBlock *block = uiLayoutGetBlock(layout);
|
||||
uiBut *but = static_cast<uiBut *>(block->buttons.last);
|
||||
uiBut *but = block->buttons.last().get();
|
||||
but->flag |= UI_BUT_HAS_SEP_CHAR;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -622,22 +622,25 @@ static bool ui_but_find_select_in_enum__cmp(const uiBut *but_a, const uiBut *but
|
||||
|
||||
uiBut *ui_but_find_select_in_enum(uiBut *but, int direction)
|
||||
{
|
||||
uiBut *but_iter = but;
|
||||
uiBlock *block = but->block;
|
||||
int i = block->but_index(but);
|
||||
uiBut *but_found = nullptr;
|
||||
BLI_assert(ELEM(direction, -1, 1));
|
||||
|
||||
while ((but_iter->prev) && ui_but_find_select_in_enum__cmp(but_iter->prev, but)) {
|
||||
but_iter = but_iter->prev;
|
||||
while (i > 0 && ui_but_find_select_in_enum__cmp(block->buttons[i - 1].get(), but)) {
|
||||
i--;
|
||||
}
|
||||
|
||||
while (but_iter && ui_but_find_select_in_enum__cmp(but_iter, but)) {
|
||||
if (but_iter->flag & UI_SELECT) {
|
||||
but_found = but_iter;
|
||||
while (i < block->buttons.size() &&
|
||||
ui_but_find_select_in_enum__cmp(block->buttons[i].get(), but))
|
||||
{
|
||||
if (block->buttons[i]->flag & UI_SELECT) {
|
||||
but_found = block->buttons[i].get();
|
||||
if (direction == 1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
but_iter = but_iter->next;
|
||||
i++;
|
||||
}
|
||||
|
||||
return but_found;
|
||||
@@ -1200,9 +1203,10 @@ static void ui_apply_but_ROW(bContext *C, uiBlock *block, uiBut *but, uiHandleBu
|
||||
ui_apply_but_func(C, but);
|
||||
|
||||
/* states of other row buttons */
|
||||
LISTBASE_FOREACH (uiBut *, bt, &block->buttons) {
|
||||
if (bt != but && bt->poin == but->poin && ELEM(bt->type, UI_BTYPE_ROW, UI_BTYPE_LISTROW)) {
|
||||
ui_but_update_edited(bt);
|
||||
for (const std::unique_ptr<uiBut> &bt : block->buttons) {
|
||||
if (bt.get() != but && bt->poin == but->poin && ELEM(bt->type, UI_BTYPE_ROW, UI_BTYPE_LISTROW))
|
||||
{
|
||||
ui_but_update_edited(bt.get());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1427,16 +1431,19 @@ static uiButMultiState *ui_multibut_lookup(uiHandleButtonData *data, const uiBut
|
||||
|
||||
static void ui_multibut_restore(bContext *C, uiHandleButtonData *data, uiBlock *block)
|
||||
{
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
if (but->flag & UI_BUT_DRAG_MULTI) {
|
||||
uiButMultiState *mbut_state = ui_multibut_lookup(data, but);
|
||||
uiButMultiState *mbut_state = ui_multibut_lookup(data, but.get());
|
||||
if (mbut_state) {
|
||||
ui_but_value_set(but, mbut_state->origvalue);
|
||||
ui_but_value_set(but.get(), mbut_state->origvalue);
|
||||
|
||||
# ifdef USE_ALLSELECT
|
||||
if (!mbut_state->select_others.elems.is_empty()) {
|
||||
ui_selectcontext_apply(
|
||||
C, but, &mbut_state->select_others, mbut_state->origvalue, mbut_state->origvalue);
|
||||
ui_selectcontext_apply(C,
|
||||
but.get(),
|
||||
&mbut_state->select_others,
|
||||
mbut_state->origvalue,
|
||||
mbut_state->origvalue);
|
||||
}
|
||||
# else
|
||||
UNUSED_VARS(C);
|
||||
@@ -1492,7 +1499,7 @@ static bool ui_multibut_states_tag(uiBut *but_active,
|
||||
data->multi_data.has_mbuts = false;
|
||||
|
||||
/* follow ui_but_find_mouse_over_ex logic */
|
||||
LISTBASE_FOREACH (uiBut *, but, &but_active->block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : but_active->block->buttons) {
|
||||
bool drag_prev = false;
|
||||
bool drag_curr = false;
|
||||
|
||||
@@ -1502,11 +1509,11 @@ static bool ui_multibut_states_tag(uiBut *but_active,
|
||||
drag_prev = true;
|
||||
}
|
||||
|
||||
if (ui_but_is_interactive(but, false)) {
|
||||
if (ui_but_is_interactive(but.get(), false)) {
|
||||
|
||||
/* drag checks */
|
||||
if (but_active != but) {
|
||||
if (ui_but_is_compatible(but_active, but)) {
|
||||
if (but_active != but.get()) {
|
||||
if (ui_but_is_compatible(but_active, but.get())) {
|
||||
|
||||
BLI_assert(but->active == nullptr);
|
||||
|
||||
@@ -1534,9 +1541,9 @@ static void ui_multibut_states_create(uiBut *but_active, uiHandleButtonData *dat
|
||||
|
||||
data->multi_data.bs_mbuts = UI_butstore_create(but_active->block);
|
||||
|
||||
LISTBASE_FOREACH (uiBut *, but, &but_active->block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : but_active->block->buttons) {
|
||||
if (but->flag & UI_BUT_DRAG_MULTI) {
|
||||
ui_multibut_add(data, but);
|
||||
ui_multibut_add(data, but.get());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1562,12 +1569,12 @@ static void ui_multibut_states_apply(bContext *C, uiHandleButtonData *data, uiBl
|
||||
BLI_assert(data->multi_data.init == uiHandleButtonMulti::INIT_ENABLE);
|
||||
BLI_assert(data->multi_data.skip == false);
|
||||
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
if (!(but->flag & UI_BUT_DRAG_MULTI)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uiButMultiState *mbut_state = ui_multibut_lookup(data, but);
|
||||
uiButMultiState *mbut_state = ui_multibut_lookup(data, but.get());
|
||||
|
||||
if (mbut_state == nullptr) {
|
||||
/* Highly unlikely. */
|
||||
@@ -1578,13 +1585,13 @@ static void ui_multibut_states_apply(bContext *C, uiHandleButtonData *data, uiBl
|
||||
}
|
||||
|
||||
void *active_back;
|
||||
ui_but_execute_begin(C, region, but, &active_back);
|
||||
ui_but_execute_begin(C, region, but.get(), &active_back);
|
||||
|
||||
# ifdef USE_ALLSELECT
|
||||
if (data->select_others.is_enabled) {
|
||||
/* init once! */
|
||||
if (mbut_state->select_others.elems.is_empty()) {
|
||||
ui_selectcontext_begin(C, but, &mbut_state->select_others);
|
||||
ui_selectcontext_begin(C, but.get(), &mbut_state->select_others);
|
||||
}
|
||||
if (mbut_state->select_others.elems.is_empty()) {
|
||||
mbut_state->select_others.elems.clear();
|
||||
@@ -1602,7 +1609,7 @@ static void ui_multibut_states_apply(bContext *C, uiHandleButtonData *data, uiBl
|
||||
if (data->text_edit.edit_string) {
|
||||
/* Entering text (set all). */
|
||||
but->active->value = data->value;
|
||||
ui_but_string_set(C, but, data->text_edit.edit_string);
|
||||
ui_but_string_set(C, but.get(), data->text_edit.edit_string);
|
||||
}
|
||||
else {
|
||||
/* Dragging (use delta). */
|
||||
@@ -1617,7 +1624,7 @@ static void ui_multibut_states_apply(bContext *C, uiHandleButtonData *data, uiBl
|
||||
CLAMP(but->active->value, double(but->softmin), double(but->softmax));
|
||||
}
|
||||
|
||||
ui_but_execute_end(C, region, but, active_back);
|
||||
ui_but_execute_end(C, region, but.get(), active_back);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1693,32 +1700,32 @@ static bool ui_drag_toggle_set_xy_xy(
|
||||
ui_window_to_block_fl(region, block, &xy_a_block[0], &xy_a_block[1]);
|
||||
ui_window_to_block_fl(region, block, &xy_b_block[0], &xy_b_block[1]);
|
||||
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
/* NOTE: ctrl is always true here because (at least for now)
|
||||
* we always want to consider text control in this case, even when not embossed. */
|
||||
|
||||
if (!ui_but_is_interactive(but, true)) {
|
||||
if (!ui_but_is_interactive(but.get(), true)) {
|
||||
continue;
|
||||
}
|
||||
if (!BLI_rctf_isect_segment(&but->rect, xy_a_block, xy_b_block)) {
|
||||
continue;
|
||||
}
|
||||
if (!ui_drag_toggle_but_is_supported(but)) {
|
||||
if (!ui_drag_toggle_but_is_supported(but.get())) {
|
||||
continue;
|
||||
}
|
||||
/* is it pressed? */
|
||||
const int pushed_state_but = ui_drag_toggle_but_pushed_state(but);
|
||||
const int pushed_state_but = ui_drag_toggle_but_pushed_state(but.get());
|
||||
if (pushed_state_but == pushed_state) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* execute the button */
|
||||
UI_but_execute(C, region, but);
|
||||
UI_but_execute(C, region, but.get());
|
||||
if (do_check) {
|
||||
ui_but_update_edited(but);
|
||||
ui_but_update_edited(but.get());
|
||||
}
|
||||
if (U.runtime.is_dirty == false) {
|
||||
ui_but_update_preferences_dirty(but);
|
||||
ui_but_update_preferences_dirty(but.get());
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
@@ -3679,7 +3686,8 @@ static void ui_textedit_next_but(uiBlock *block, uiBut *actbut, uiHandleButtonDa
|
||||
return;
|
||||
}
|
||||
|
||||
for (uiBut *but = actbut->next; but; but = but->next) {
|
||||
for (int64_t i = block->but_index(actbut) + 1; i < block->buttons.size(); i++) {
|
||||
uiBut *but = block->buttons[i].get();
|
||||
if (ui_but_is_editable_as_text(but)) {
|
||||
if (!(but->flag & (UI_BUT_DISABLED | UI_HIDDEN))) {
|
||||
data->postbut = but;
|
||||
@@ -3688,10 +3696,13 @@ static void ui_textedit_next_but(uiBlock *block, uiBut *actbut, uiHandleButtonDa
|
||||
}
|
||||
}
|
||||
}
|
||||
for (uiBut *but = static_cast<uiBut *>(block->buttons.first); but != actbut; but = but->next) {
|
||||
if (ui_but_is_editable_as_text(but)) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
if (but.get() == actbut) {
|
||||
break;
|
||||
}
|
||||
if (ui_but_is_editable_as_text(but.get())) {
|
||||
if (!(but->flag & (UI_BUT_DISABLED | UI_HIDDEN))) {
|
||||
data->postbut = but;
|
||||
data->postbut = but.get();
|
||||
data->posttype = BUTTON_ACTIVATE_TEXT_EDITING;
|
||||
return;
|
||||
}
|
||||
@@ -3712,7 +3723,8 @@ static void ui_textedit_prev_but(uiBlock *block, uiBut *actbut, uiHandleButtonDa
|
||||
return;
|
||||
}
|
||||
|
||||
for (uiBut *but = actbut->prev; but; but = but->prev) {
|
||||
for (int i = block->but_index(actbut) - 1; i >= 0; i--) {
|
||||
uiBut *but = block->buttons[i].get();
|
||||
if (ui_but_is_editable_as_text(but)) {
|
||||
if (!(but->flag & (UI_BUT_DISABLED | UI_HIDDEN))) {
|
||||
data->postbut = but;
|
||||
@@ -3721,7 +3733,11 @@ static void ui_textedit_prev_but(uiBlock *block, uiBut *actbut, uiHandleButtonDa
|
||||
}
|
||||
}
|
||||
}
|
||||
for (uiBut *but = static_cast<uiBut *>(block->buttons.last); but != actbut; but = but->prev) {
|
||||
for (int i = block->buttons.size() - 1; i >= 0; i--) {
|
||||
uiBut *but = block->buttons[i].get();
|
||||
if (but == actbut) {
|
||||
break;
|
||||
}
|
||||
if (ui_but_is_editable_as_text(but)) {
|
||||
if (!(but->flag & (UI_BUT_DISABLED | UI_HIDDEN))) {
|
||||
data->postbut = but;
|
||||
@@ -4931,7 +4947,8 @@ static int ui_do_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data, cons
|
||||
const int direction = (type == WHEELDOWNMOUSE) ? -1 : 1;
|
||||
uiBut *but_select = ui_but_find_select_in_enum(but, direction);
|
||||
if (but_select) {
|
||||
uiBut *but_other = (direction == -1) ? but_select->next : but_select->prev;
|
||||
uiBut *but_other = (direction == -1) ? but_select->block->next_but(but_select) :
|
||||
but_select->block->prev_but(but_select);
|
||||
if (but_other && ui_but_find_select_in_enum__cmp(but, but_other)) {
|
||||
ARegion *region = data->region;
|
||||
|
||||
@@ -8860,12 +8877,12 @@ static void button_activate_exit(
|
||||
|
||||
#ifdef USE_DRAG_MULTINUM
|
||||
if (data->multi_data.has_mbuts) {
|
||||
LISTBASE_FOREACH (uiBut *, bt, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &bt : block->buttons) {
|
||||
if (bt->flag & UI_BUT_DRAG_MULTI) {
|
||||
bt->flag &= ~UI_BUT_DRAG_MULTI;
|
||||
|
||||
if (!data->cancel) {
|
||||
ui_apply_but_autokey(C, bt);
|
||||
ui_apply_but_autokey(C, bt.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8916,7 +8933,7 @@ static void button_activate_exit(
|
||||
|
||||
/* Disable tool-tips until mouse-move + last active flag. */
|
||||
LISTBASE_FOREACH (uiBlock *, block_iter, &data->region->runtime->uiblocks) {
|
||||
LISTBASE_FOREACH (uiBut *, bt, &block_iter->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &bt : block_iter->buttons) {
|
||||
bt->flag &= ~UI_BUT_LAST_ACTIVE;
|
||||
}
|
||||
|
||||
@@ -9021,15 +9038,15 @@ static uiBut *ui_context_button_active(const ARegion *region, bool (*but_check_c
|
||||
|
||||
/* find active button */
|
||||
LISTBASE_FOREACH (uiBlock *, block, ®ion->runtime->uiblocks) {
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
if (but->flag & UI_BUT_ACTIVE_OVERRIDE) {
|
||||
active_but_override = but;
|
||||
active_but_override = but.get();
|
||||
}
|
||||
if (but->active) {
|
||||
active_but_real = but;
|
||||
active_but_real = but.get();
|
||||
}
|
||||
if (but->flag & UI_BUT_LAST_ACTIVE) {
|
||||
active_but_last = but;
|
||||
active_but_last = but.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9199,20 +9216,20 @@ void UI_context_update_anim_flag(const bContext *C)
|
||||
uiBut *activebut = nullptr;
|
||||
|
||||
LISTBASE_FOREACH (uiBlock *, block, ®ion->runtime->uiblocks) {
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
ui_but_anim_flag(but, &anim_eval_context);
|
||||
ui_but_override_flag(CTX_data_main(C), but);
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
ui_but_anim_flag(but.get(), &anim_eval_context);
|
||||
ui_but_override_flag(CTX_data_main(C), but.get());
|
||||
if (UI_but_is_decorator(but)) {
|
||||
ui_but_anim_decorate_update_from_flag((uiButDecorator *)but);
|
||||
ui_but_anim_decorate_update_from_flag((uiButDecorator *)but.get());
|
||||
}
|
||||
|
||||
ED_region_tag_redraw(region);
|
||||
|
||||
if (but->active) {
|
||||
activebut = but;
|
||||
activebut = but.get();
|
||||
}
|
||||
else if (!activebut && (but->flag & UI_BUT_LAST_ACTIVE)) {
|
||||
activebut = but;
|
||||
activebut = but.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9259,9 +9276,9 @@ void ui_but_update_view_for_active(const bContext *C, const uiBlock *block)
|
||||
static uiBut *ui_but_find_open_event(ARegion *region, const wmEvent *event)
|
||||
{
|
||||
LISTBASE_FOREACH (uiBlock *, block, ®ion->runtime->uiblocks) {
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
if (but == event->customdata) {
|
||||
return but;
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
if (but.get() == event->customdata) {
|
||||
return but.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9446,9 +9463,9 @@ static void foreach_semi_modal_but_as_active(bContext *C,
|
||||
* every actually a use-case for multiple semi-active buttons at the same time. */
|
||||
|
||||
LISTBASE_FOREACH (uiBlock *, block, ®ion->runtime->uiblocks) {
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
if ((but->flag2 & UI_BUT2_FORCE_SEMI_MODAL_ACTIVE) || but->semi_modal_state) {
|
||||
with_but_active_as_semi_modal(C, region, but, [&]() { fn(but); });
|
||||
with_but_active_as_semi_modal(C, region, but.get(), [&]() { fn(but.get()); });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10090,8 +10107,8 @@ static int ui_handle_viewlist_items_hover(const wmEvent *event, ARegion *region)
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (uiBlock *, block, ®ion->runtime->uiblocks) {
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
if (but == highlight_row_but) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
if (but.get() == highlight_row_but) {
|
||||
continue;
|
||||
}
|
||||
if (!ELEM(but->type, UI_BTYPE_VIEW_ITEM, UI_BTYPE_LISTROW)) {
|
||||
@@ -10382,7 +10399,7 @@ static void ui_menu_scroll_apply_offset_y(ARegion *region, uiBlock *block, float
|
||||
if (dy < 0.0f) {
|
||||
/* Stop at top item, extra 0.5 UI_UNIT_Y makes it snap nicer. */
|
||||
float ymax = -FLT_MAX;
|
||||
LISTBASE_FOREACH (uiBut *, bt, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &bt : block->buttons) {
|
||||
ymax = max_ff(ymax, bt->rect.ymax);
|
||||
}
|
||||
if (ymax + dy - UI_UNIT_Y * 0.5f < block->rect.ymax - scroll_pad) {
|
||||
@@ -10392,7 +10409,7 @@ static void ui_menu_scroll_apply_offset_y(ARegion *region, uiBlock *block, float
|
||||
else {
|
||||
/* Stop at bottom item, extra 0.5 UI_UNIT_Y makes it snap nicer. */
|
||||
float ymin = FLT_MAX;
|
||||
LISTBASE_FOREACH (uiBut *, bt, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &bt : block->buttons) {
|
||||
ymin = min_ff(ymin, bt->rect.ymin);
|
||||
}
|
||||
if (ymin + dy + UI_UNIT_Y * 0.5f > block->rect.ymin + scroll_pad) {
|
||||
@@ -10406,7 +10423,7 @@ static void ui_menu_scroll_apply_offset_y(ARegion *region, uiBlock *block, float
|
||||
ui_layout_panel_popup_scroll_apply(block->panel, dy);
|
||||
|
||||
/* apply scroll offset */
|
||||
LISTBASE_FOREACH (uiBut *, bt, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &bt : block->buttons) {
|
||||
bt->rect.ymin += dy;
|
||||
bt->rect.ymax += dy;
|
||||
}
|
||||
@@ -11015,7 +11032,7 @@ static int ui_handle_menu_event(bContext *C,
|
||||
}
|
||||
|
||||
count = 0;
|
||||
for (but = static_cast<uiBut *>(block->buttons.first); but; but = but->next) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
bool doit = false;
|
||||
|
||||
if (!ELEM(but->type,
|
||||
@@ -11056,7 +11073,7 @@ static int ui_handle_menu_event(bContext *C,
|
||||
activate = BUTTON_ACTIVATE_APPLY;
|
||||
}
|
||||
|
||||
ui_handle_button_activate(C, region, but, activate);
|
||||
ui_handle_button_activate(C, region, but.get(), activate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -11122,17 +11139,17 @@ static int ui_handle_menu_event(bContext *C,
|
||||
}
|
||||
|
||||
/* Accelerator keys that allow "pressing" a menu entry by pressing a single key. */
|
||||
LISTBASE_FOREACH (uiBut *, but_iter, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but_iter : block->buttons) {
|
||||
if (!(but_iter->flag & UI_BUT_DISABLED) && but_iter->menu_key == event->type) {
|
||||
if (ELEM(but_iter->type,
|
||||
UI_BTYPE_BUT,
|
||||
UI_BTYPE_ICON_TOGGLE,
|
||||
UI_BTYPE_ICON_TOGGLE_N))
|
||||
{
|
||||
UI_but_execute(C, region, but_iter);
|
||||
UI_but_execute(C, region, but_iter.get());
|
||||
}
|
||||
else {
|
||||
ui_handle_button_activate_by_type(C, region, but_iter);
|
||||
ui_handle_button_activate_by_type(C, region, but_iter.get());
|
||||
}
|
||||
return WM_UI_HANDLER_BREAK;
|
||||
}
|
||||
@@ -11421,9 +11438,9 @@ static int ui_but_pie_menu_apply(bContext *C,
|
||||
static uiBut *ui_block_pie_dir_activate(uiBlock *block, const wmEvent *event, RadialDirection dir)
|
||||
{
|
||||
if ((block->flag & UI_BLOCK_NUMSELECT) && event->val == KM_PRESS) {
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
if (but->pie_dir == dir && !ELEM(but->type, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE)) {
|
||||
return but;
|
||||
return but.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11505,7 +11522,7 @@ static int ui_pie_handler(bContext *C, const wmEvent *event, uiPopupBlockHandle
|
||||
block->pie_data.flags |= UI_PIE_ANIMATION_FINISHED;
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
if (but->pie_dir != UI_RADIAL_NONE) {
|
||||
float vec[2];
|
||||
float center[2];
|
||||
@@ -11668,9 +11685,9 @@ static int ui_pie_handler(bContext *C, const wmEvent *event, uiPopupBlockHandle
|
||||
if (ELEM(event->val, KM_PRESS, KM_DBL_CLICK) &&
|
||||
((event->modifier & (KM_SHIFT | KM_CTRL | KM_OSKEY)) == 0))
|
||||
{
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
if (but->menu_key == event->type) {
|
||||
ui_but_pie_button_activate(C, but, menu);
|
||||
ui_but_pie_button_activate(C, but.get(), menu);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12235,12 +12252,12 @@ bool UI_textbutton_activate_rna(const bContext *C,
|
||||
uiBut *but_text = nullptr;
|
||||
|
||||
LISTBASE_FOREACH (uiBlock *, block, ®ion->runtime->uiblocks) {
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
if (but->type == UI_BTYPE_TEXT) {
|
||||
if (but->rnaprop && but->rnapoin.data == rna_poin_data) {
|
||||
if (STREQ(RNA_property_identifier(but->rnaprop), rna_prop_id)) {
|
||||
block_text = block;
|
||||
but_text = but;
|
||||
but_text = but.get();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -12270,10 +12287,10 @@ bool UI_textbutton_activate_but(const bContext *C, uiBut *actbut)
|
||||
uiBut *but_text = nullptr;
|
||||
|
||||
LISTBASE_FOREACH (uiBlock *, block, ®ion->runtime->uiblocks) {
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
if (but == actbut && but->type == UI_BTYPE_TEXT) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
if (but.get() == actbut && but->type == UI_BTYPE_TEXT) {
|
||||
block_text = block;
|
||||
but_text = but;
|
||||
but_text = but.get();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -12299,11 +12316,11 @@ bool UI_textbutton_activate_but(const bContext *C, uiBut *actbut)
|
||||
void UI_region_free_active_but_all(bContext *C, ARegion *region)
|
||||
{
|
||||
LISTBASE_FOREACH (uiBlock *, block, ®ion->runtime->uiblocks) {
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
if (but->active == nullptr) {
|
||||
continue;
|
||||
}
|
||||
ui_but_active_free(C, but);
|
||||
ui_but_active_free(C, but.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12381,7 +12398,7 @@ static uiBlockInteraction_Handle *ui_block_interaction_begin(bContext *C,
|
||||
uiBlockInteraction_Handle *interaction = MEM_cnew<uiBlockInteraction_Handle>(__func__);
|
||||
|
||||
int unique_retval_ids_len = 0;
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
if (but->active || (but->flag & UI_BUT_DRAG_MULTI)) {
|
||||
unique_retval_ids_len++;
|
||||
}
|
||||
@@ -12390,7 +12407,7 @@ static uiBlockInteraction_Handle *ui_block_interaction_begin(bContext *C,
|
||||
int *unique_retval_ids = static_cast<int *>(
|
||||
MEM_mallocN(sizeof(*unique_retval_ids) * unique_retval_ids_len, __func__));
|
||||
unique_retval_ids_len = 0;
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
if (but->active || (but->flag & UI_BUT_DRAG_MULTI)) {
|
||||
unique_retval_ids[unique_retval_ids_len++] = but->retval;
|
||||
}
|
||||
|
||||
@@ -171,7 +171,6 @@ enum {
|
||||
#define PIE_MAX_ITEMS 8
|
||||
|
||||
struct uiBut {
|
||||
uiBut *next = nullptr, *prev = nullptr;
|
||||
|
||||
/** Pointer back to the layout item holding this button. */
|
||||
uiLayout *layout = nullptr;
|
||||
@@ -336,6 +335,8 @@ struct uiBut {
|
||||
uiBut(const uiBut &other) = default;
|
||||
/** Mostly shallow copy, just like copy constructor above. */
|
||||
uiBut &operator=(const uiBut &other) = default;
|
||||
|
||||
virtual ~uiBut() = default;
|
||||
};
|
||||
|
||||
/** Derived struct for #UI_BTYPE_NUM */
|
||||
@@ -557,7 +558,7 @@ struct uiBlockDynamicListener {
|
||||
struct uiBlock {
|
||||
uiBlock *next, *prev;
|
||||
|
||||
ListBase buttons;
|
||||
blender::Vector<std::unique_ptr<uiBut>> buttons;
|
||||
Panel *panel;
|
||||
uiBlock *oldblock;
|
||||
|
||||
@@ -673,6 +674,13 @@ struct uiBlock {
|
||||
char display_device[64];
|
||||
|
||||
PieMenuData pie_data;
|
||||
|
||||
void remove_but(const uiBut *but);
|
||||
[[nodiscard]] uiBut *first_but() const;
|
||||
[[nodiscard]] uiBut *last_but() const;
|
||||
int but_index(const uiBut *but) const;
|
||||
[[nodiscard]] uiBut *next_but(const uiBut *but) const;
|
||||
[[nodiscard]] uiBut *prev_but(const uiBut *but) const;
|
||||
};
|
||||
|
||||
struct uiSafetyRct {
|
||||
@@ -680,7 +688,6 @@ struct uiSafetyRct {
|
||||
rctf parent;
|
||||
rctf safety;
|
||||
};
|
||||
|
||||
/* `interface.cc` */
|
||||
|
||||
void ui_fontscale(float *points, float aspect);
|
||||
|
||||
@@ -529,8 +529,8 @@ static void ui_layer_but_cb(bContext *C, void *arg_but, void *arg_index)
|
||||
|
||||
RNA_property_update(C, ptr, prop);
|
||||
|
||||
LISTBASE_FOREACH (uiBut *, cbut, &but->block->buttons) {
|
||||
ui_but_update(cbut);
|
||||
for (const std::unique_ptr<uiBut> &cbut : but->block->buttons) {
|
||||
ui_but_update(cbut.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -946,14 +946,13 @@ static void ui_item_enum_expand_tabs(uiLayout *layout,
|
||||
const int h,
|
||||
const bool icon_only)
|
||||
{
|
||||
uiBut *last = static_cast<uiBut *>(block->buttons.last);
|
||||
const int start_size = block->buttons.size();
|
||||
|
||||
ui_item_enum_expand_exec(layout, block, ptr, prop, uiname, h, UI_BTYPE_TAB, icon_only);
|
||||
BLI_assert(last != block->buttons.last);
|
||||
BLI_assert(start_size != block->buttons.size());
|
||||
|
||||
for (uiBut *tab = last ? last->next : static_cast<uiBut *>(block->buttons.first); tab;
|
||||
tab = tab->next)
|
||||
{
|
||||
for (int i = start_size; i < block->buttons.size(); i++) {
|
||||
uiBut *tab = block->buttons[i].get();
|
||||
UI_but_drawflag_enable(tab, ui_but_align_opposite_to_area_align_get(CTX_wm_region(C)));
|
||||
if (icon_only) {
|
||||
UI_but_drawflag_enable(tab, UI_BUT_HAS_TOOLTIP_LABEL);
|
||||
@@ -966,11 +965,9 @@ static void ui_item_enum_expand_tabs(uiLayout *layout,
|
||||
const int highlight_array_len = RNA_property_array_length(ptr_highlight, prop_highlight);
|
||||
blender::Array<bool, 64> highlight_array(highlight_array_len);
|
||||
RNA_property_boolean_get_array(ptr_highlight, prop_highlight, highlight_array.data());
|
||||
int i = 0;
|
||||
for (uiBut *tab_but = last ? last->next : static_cast<uiBut *>(block->buttons.first);
|
||||
(tab_but != nullptr) && (i < highlight_array_len);
|
||||
tab_but = tab_but->next, i++)
|
||||
{
|
||||
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();
|
||||
SET_FLAG_FROM_TEST(tab_but->flag, !highlight_array[i], UI_BUT_INACTIVE);
|
||||
}
|
||||
}
|
||||
@@ -1164,10 +1161,10 @@ void UI_context_active_but_prop_get_filebrowser(const bContext *C,
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (uiBlock *, block, ®ion->runtime->uiblocks) {
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
if (but && but->rnapoin.data) {
|
||||
if (RNA_property_type(but->rnaprop) == PROP_STRING) {
|
||||
prevbut = but;
|
||||
prevbut = but.get();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1578,7 +1575,7 @@ void uiItemsFullEnumO_items(uiLayout *layout,
|
||||
flag,
|
||||
nullptr);
|
||||
|
||||
uiBut *but = static_cast<uiBut *>(block->buttons.last);
|
||||
uiBut *but = block->buttons.last().get();
|
||||
|
||||
if (active == (i - 1)) {
|
||||
but->flag |= UI_SELECT_DRAW;
|
||||
@@ -1596,7 +1593,7 @@ void uiItemsFullEnumO_items(uiLayout *layout,
|
||||
if (item->icon || radial) {
|
||||
uiItemL(target, item->name, item->icon);
|
||||
|
||||
but = static_cast<uiBut *>(block->buttons.last);
|
||||
but = block->buttons.last().get();
|
||||
}
|
||||
else {
|
||||
/* Do not use uiItemL here, as our root layout is a menu one,
|
||||
@@ -2340,7 +2337,7 @@ void uiItemFullR(uiLayout *layout,
|
||||
ui_decorate.layout = uiLayoutColumn(layout_row, true);
|
||||
ui_decorate.layout->space = 0;
|
||||
UI_block_layout_set_current(block, layout);
|
||||
ui_decorate.but = static_cast<uiBut *>(block->buttons.last);
|
||||
ui_decorate.but = block->last_but();
|
||||
|
||||
/* Clear after. */
|
||||
layout->flag |= UI_ITEM_PROP_DECORATE_NO_PAD;
|
||||
@@ -2494,8 +2491,14 @@ void uiItemFullR(uiLayout *layout,
|
||||
|
||||
#ifdef UI_PROP_DECORATE
|
||||
if (ui_decorate.use_prop_decorate) {
|
||||
uiBut *but_decorate = ui_decorate.but ? ui_decorate.but->next :
|
||||
static_cast<uiBut *>(block->buttons.first);
|
||||
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;
|
||||
tmp.reserve(block->buttons.capacity());
|
||||
while (but_decorate && but_decorate != block->buttons.last().get()) {
|
||||
tmp.append(block->buttons.pop_last());
|
||||
}
|
||||
const bool use_blank_decorator = (flag & UI_ITEM_R_FORCE_BLANK_DECORATE);
|
||||
uiLayout *layout_col = uiLayoutColumn(ui_decorate.layout, false);
|
||||
layout_col->space = 0;
|
||||
@@ -2508,13 +2511,18 @@ void uiItemFullR(uiLayout *layout,
|
||||
|
||||
/* The icons are set in 'ui_but_anim_flag' */
|
||||
uiItemDecoratorR_prop(layout_col, ptr_dec, prop_dec, but_decorate->rnaindex);
|
||||
but = static_cast<uiBut *>(block->buttons.last);
|
||||
but = block->buttons.last().get();
|
||||
|
||||
/* Order the decorator after the button we decorate, this is used so we can always
|
||||
* do a quick lookup. */
|
||||
BLI_remlink(&block->buttons, but);
|
||||
BLI_insertlinkafter(&block->buttons, but_decorate, but);
|
||||
but_decorate = but->next;
|
||||
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());
|
||||
}
|
||||
BLI_assert(ELEM(i, 1, ui_decorate.len));
|
||||
|
||||
@@ -2561,17 +2569,16 @@ void uiItemFullR_with_popover(uiLayout *layout,
|
||||
const char *panel_type)
|
||||
{
|
||||
uiBlock *block = layout->root->block;
|
||||
uiBut *but = static_cast<uiBut *>(block->buttons.last);
|
||||
int i = block->buttons.size();
|
||||
uiItemFullR(layout, ptr, prop, index, value, flag, name, icon);
|
||||
but = but->next;
|
||||
while (but) {
|
||||
for (; i < block->buttons.size(); i++) {
|
||||
uiBut *but = block->buttons[i].get();
|
||||
if (but->rnaprop == prop && ELEM(but->type, UI_BTYPE_MENU, UI_BTYPE_COLOR)) {
|
||||
ui_but_rna_menu_convert_to_panel_type(but, panel_type);
|
||||
break;
|
||||
}
|
||||
but = but->next;
|
||||
}
|
||||
if (but == nullptr) {
|
||||
if (i == block->buttons.size()) {
|
||||
const StringRefNull propname = RNA_property_identifier(prop);
|
||||
ui_item_disabled(layout, panel_type);
|
||||
RNA_warning("property could not use a popover: %s.%s (%s)",
|
||||
@@ -2592,17 +2599,17 @@ void uiItemFullR_with_menu(uiLayout *layout,
|
||||
const char *menu_type)
|
||||
{
|
||||
uiBlock *block = layout->root->block;
|
||||
uiBut *but = static_cast<uiBut *>(block->buttons.last);
|
||||
int i = block->buttons.size();
|
||||
uiItemFullR(layout, ptr, prop, index, value, flag, name, icon);
|
||||
but = but->next;
|
||||
while (but) {
|
||||
while (i < block->buttons.size()) {
|
||||
uiBut *but = block->buttons[i].get();
|
||||
if (but->rnaprop == prop && but->type == UI_BTYPE_MENU) {
|
||||
ui_but_rna_menu_convert_to_menu_type(but, menu_type);
|
||||
break;
|
||||
}
|
||||
but = but->next;
|
||||
i++;
|
||||
}
|
||||
if (but == nullptr) {
|
||||
if (i == block->buttons.size()) {
|
||||
const StringRefNull propname = RNA_property_identifier(prop);
|
||||
ui_item_disabled(layout, menu_type);
|
||||
RNA_warning("property could not use a menu: %s.%s (%s)",
|
||||
@@ -2727,7 +2734,7 @@ void uiItemsEnumR(uiLayout *layout, PointerRNA *ptr, const StringRefNull propnam
|
||||
for (int i = 0; i < totitem; i++) {
|
||||
if (item[i].identifier[0]) {
|
||||
uiItemEnumR_prop(column, item[i].name, item[i].icon, ptr, prop, item[i].value);
|
||||
ui_but_tip_from_enum_item(static_cast<uiBut *>(block->buttons.last), &item[i]);
|
||||
ui_but_tip_from_enum_item(block->buttons.last().get(), &item[i]);
|
||||
}
|
||||
else {
|
||||
if (item[i].name) {
|
||||
@@ -2736,7 +2743,7 @@ void uiItemsEnumR(uiLayout *layout, PointerRNA *ptr, const StringRefNull propnam
|
||||
}
|
||||
|
||||
uiItemL(column, item[i].name, ICON_NONE);
|
||||
uiBut *bt = static_cast<uiBut *>(block->buttons.last);
|
||||
uiBut *bt = block->buttons.last().get();
|
||||
bt->drawflag = UI_BUT_TEXT_LEFT;
|
||||
|
||||
ui_but_tip_from_enum_item(bt, &item[i]);
|
||||
|
||||
@@ -868,7 +868,7 @@ static void ui_offset_panel_block(uiBlock *block)
|
||||
|
||||
const int ofsy = block->panel->sizey - style->panelspace;
|
||||
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
but->rect.ymin += ofsy;
|
||||
but->rect.ymax += ofsy;
|
||||
}
|
||||
@@ -949,7 +949,7 @@ static void panel_remove_invisible_layouts_recursive(Panel *panel, const Panel *
|
||||
if (parent_panel != nullptr && UI_panel_is_closed(parent_panel)) {
|
||||
/* The parent panel is closed, so this panel can be completely removed. */
|
||||
UI_block_set_search_only(block, true);
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
but->flag |= UI_HIDDEN;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,7 +306,8 @@ static uiBut *ui_but_find(const ARegion *region,
|
||||
const void *find_custom_data)
|
||||
{
|
||||
LISTBASE_FOREACH (uiBlock *, block, ®ion->runtime->uiblocks) {
|
||||
LISTBASE_FOREACH_BACKWARD (uiBut *, but, &block->buttons) {
|
||||
for (int i = block->buttons.size() - 1; i >= 0; i--) {
|
||||
uiBut *but = block->buttons[i].get();
|
||||
if (find_poll && find_poll(but, find_custom_data) == false) {
|
||||
continue;
|
||||
}
|
||||
@@ -333,7 +334,8 @@ uiBut *ui_but_find_mouse_over_ex(const ARegion *region,
|
||||
float mx = xy[0], my = xy[1];
|
||||
ui_window_to_block_fl(region, block, &mx, &my);
|
||||
|
||||
LISTBASE_FOREACH_BACKWARD (uiBut *, but, &block->buttons) {
|
||||
for (int i = block->buttons.size() - 1; i >= 0; i--) {
|
||||
uiBut *but = block->buttons[i].get();
|
||||
if (find_poll && find_poll(but, find_custom_data) == false) {
|
||||
continue;
|
||||
}
|
||||
@@ -385,7 +387,8 @@ uiBut *ui_but_find_rect_over(const ARegion *region, const rcti *rect_px)
|
||||
rctf rect_block;
|
||||
ui_window_to_block_rctf(region, block, &rect_block, &rect_px_fl);
|
||||
|
||||
LISTBASE_FOREACH_BACKWARD (uiBut *, but, &block->buttons) {
|
||||
for (int i = block->buttons.size() - 1; i >= 0; i--) {
|
||||
uiBut *but = block->buttons[i].get();
|
||||
if (ui_but_is_interactive(but, labeledit)) {
|
||||
/* No pie menu support. */
|
||||
BLI_assert(but->pie_dir == UI_RADIAL_NONE);
|
||||
@@ -415,7 +418,8 @@ uiBut *ui_list_find_mouse_over_ex(const ARegion *region, const int xy[2])
|
||||
LISTBASE_FOREACH (uiBlock *, block, ®ion->runtime->uiblocks) {
|
||||
float mx = xy[0], my = xy[1];
|
||||
ui_window_to_block_fl(region, block, &mx, &my);
|
||||
LISTBASE_FOREACH_BACKWARD (uiBut *, but, &block->buttons) {
|
||||
for (int i = block->buttons.size() - 1; i >= 0; i--) {
|
||||
uiBut *but = block->buttons[i].get();
|
||||
if (but->type == UI_BTYPE_LISTBOX && ui_but_contains_pt(but, mx, my)) {
|
||||
return but;
|
||||
}
|
||||
@@ -543,8 +547,8 @@ uiBut *ui_view_item_find_search_highlight(const ARegion *region)
|
||||
|
||||
uiBut *ui_but_prev(uiBut *but)
|
||||
{
|
||||
while (but->prev) {
|
||||
but = but->prev;
|
||||
for (int idx = but->block->but_index(but) - 1; idx >= 0; idx--) {
|
||||
but = but->block->buttons[idx].get();
|
||||
if (ui_but_is_editable(but)) {
|
||||
return but;
|
||||
}
|
||||
@@ -554,8 +558,8 @@ uiBut *ui_but_prev(uiBut *but)
|
||||
|
||||
uiBut *ui_but_next(uiBut *but)
|
||||
{
|
||||
while (but->next) {
|
||||
but = but->next;
|
||||
for (int i = but->block->but_index(but) + 1; i < but->block->buttons.size(); i++) {
|
||||
but = but->block->buttons[i].get();
|
||||
if (ui_but_is_editable(but)) {
|
||||
return but;
|
||||
}
|
||||
@@ -565,9 +569,9 @@ uiBut *ui_but_next(uiBut *but)
|
||||
|
||||
uiBut *ui_but_first(uiBlock *block)
|
||||
{
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
if (ui_but_is_editable(but)) {
|
||||
return but;
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
if (ui_but_is_editable(but.get())) {
|
||||
return but.get();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
@@ -575,12 +579,11 @@ uiBut *ui_but_first(uiBlock *block)
|
||||
|
||||
uiBut *ui_but_last(uiBlock *block)
|
||||
{
|
||||
uiBut *but = static_cast<uiBut *>(block->buttons.last);
|
||||
while (but) {
|
||||
for (int i = block->buttons.size() - 1; i >= 0; i--) {
|
||||
uiBut *but = block->buttons[i].get();
|
||||
if (ui_but_is_editable(but)) {
|
||||
return but;
|
||||
}
|
||||
but = but->prev;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@@ -649,9 +652,9 @@ size_t ui_but_tip_len_only_first_line(const uiBut *but)
|
||||
|
||||
uiBut *ui_block_active_but_get(const uiBlock *block)
|
||||
{
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
if (but->active) {
|
||||
return but;
|
||||
return but.get();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -682,7 +685,11 @@ bool ui_block_is_popup_any(const uiBlock *block)
|
||||
|
||||
static const uiBut *ui_but_next_non_separator(const uiBut *but)
|
||||
{
|
||||
for (; but; but = but->next) {
|
||||
if (!but) {
|
||||
return nullptr;
|
||||
}
|
||||
for (int i = but->block->but_index(but); i < but->block->buttons.size(); i++) {
|
||||
but = but->block->buttons[i].get();
|
||||
if (!ELEM(but->type, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE)) {
|
||||
return but;
|
||||
}
|
||||
@@ -692,13 +699,13 @@ static const uiBut *ui_but_next_non_separator(const uiBut *but)
|
||||
|
||||
bool UI_block_is_empty_ex(const uiBlock *block, const bool skip_title)
|
||||
{
|
||||
const uiBut *but = static_cast<const uiBut *>(block->buttons.first);
|
||||
const uiBut *but = block->first_but();
|
||||
if (skip_title) {
|
||||
/* Skip the first label, since popups often have a title,
|
||||
* we may want to consider the block empty in this case. */
|
||||
but = ui_but_next_non_separator(but);
|
||||
if (but && but->type == UI_BTYPE_LABEL) {
|
||||
but = but->next;
|
||||
but = block->next_but(but);
|
||||
}
|
||||
}
|
||||
return (ui_but_next_non_separator(but) == nullptr);
|
||||
@@ -712,7 +719,7 @@ bool UI_block_is_empty(const uiBlock *block)
|
||||
bool UI_block_can_add_separator(const uiBlock *block)
|
||||
{
|
||||
if (ui_block_is_menu(block) && !ui_block_is_pie_menu(block)) {
|
||||
const uiBut *but = static_cast<const uiBut *>(block->buttons.last);
|
||||
const uiBut *but = block->last_but();
|
||||
return (but && !ELEM(but->type, UI_BTYPE_SEPR_LINE, UI_BTYPE_SEPR));
|
||||
}
|
||||
return true;
|
||||
@@ -720,7 +727,7 @@ bool UI_block_can_add_separator(const uiBlock *block)
|
||||
|
||||
bool UI_block_has_active_default_button(const uiBlock *block)
|
||||
{
|
||||
LISTBASE_FOREACH (const uiBut *, but, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
if ((but->flag & UI_BUT_ACTIVE_DEFAULT) && ((but->flag & UI_HIDDEN) == 0)) {
|
||||
return true;
|
||||
}
|
||||
@@ -780,9 +787,9 @@ uiBut *ui_region_find_active_but(ARegion *region)
|
||||
uiBut *ui_region_find_first_but_test_flag(ARegion *region, int flag_include, int flag_exclude)
|
||||
{
|
||||
LISTBASE_FOREACH (uiBlock *, block, ®ion->runtime->uiblocks) {
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
if (((but->flag & flag_include) == flag_include) && ((but->flag & flag_exclude) == 0)) {
|
||||
return but;
|
||||
return but.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1022,7 +1022,8 @@ std::optional<std::string> UI_key_event_operator_string(const bContext *C,
|
||||
short event_type = KM_NOTHING;
|
||||
|
||||
uiBut *listbox = nullptr;
|
||||
LISTBASE_FOREACH_BACKWARD (uiBut *, but_iter, &but->block->buttons) {
|
||||
for (int i = but->block->buttons.size() - 1; i >= 0; i--) {
|
||||
uiBut *but_iter = but->block->buttons[i].get();
|
||||
if ((but_iter->type == UI_BTYPE_LISTBOX) && ui_but_contains_rect(but_iter, &but->rect)) {
|
||||
listbox = but_iter;
|
||||
break;
|
||||
|
||||
@@ -2593,10 +2593,10 @@ static bool draw_emboss(const uiBut *but)
|
||||
if (but->drawflag & UI_BUT_ALIGN_DOWN) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uiBut *but_next = but->block->next_but(but);
|
||||
if (but->type == UI_BTYPE_TAB &&
|
||||
(BLI_rctf_size_y(&but->block->rect) > BLI_rctf_size_x(&but->block->rect)) &&
|
||||
!(but->next == nullptr || but->next->type == UI_BTYPE_SEPR))
|
||||
!(but_next == nullptr || but_next->type == UI_BTYPE_SEPR))
|
||||
{
|
||||
/* Vertical tabs, emboss at end and before separators. */
|
||||
return false;
|
||||
|
||||
@@ -195,16 +195,16 @@ static void ui_update_color_picker_buts_rgba(uiBut *from_but,
|
||||
{
|
||||
ui_color_picker_update_hsv(cpicker, from_but, rgba_scene_linear);
|
||||
|
||||
LISTBASE_FOREACH (uiBut *, bt, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &bt : block->buttons) {
|
||||
if (bt->custom_data != cpicker) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bt->rnaprop) {
|
||||
ui_but_v4_set(bt, rgba_scene_linear);
|
||||
ui_but_v4_set(bt.get(), rgba_scene_linear);
|
||||
/* original button that created the color picker already does undo
|
||||
* push, so disable it on RNA buttons in the color picker block */
|
||||
UI_but_flag_disable(bt, UI_BUT_UNDO);
|
||||
UI_but_flag_disable(bt.get(), UI_BUT_UNDO);
|
||||
}
|
||||
else if (bt->type == UI_BTYPE_TEXT) {
|
||||
/* Hex text input field. */
|
||||
@@ -231,7 +231,7 @@ static void ui_update_color_picker_buts_rgba(uiBut *from_but,
|
||||
memcpy(bt->poin, col, col_len + 1); /* +1 offset for the # symbol. */
|
||||
}
|
||||
|
||||
ui_but_update(bt);
|
||||
ui_but_update(bt.get());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,7 +339,7 @@ static void ui_popup_close_cb(bContext * /*C*/, void *bt1, void * /*arg*/)
|
||||
static void ui_colorpicker_hide_reveal(uiBlock *block, ePickerType colormode)
|
||||
{
|
||||
/* tag buttons */
|
||||
LISTBASE_FOREACH (uiBut *, bt, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &bt : block->buttons) {
|
||||
if ((bt->func == ui_colorpicker_rgba_update_cb) && (bt->type == UI_BTYPE_NUM_SLIDER) &&
|
||||
(bt->rnaindex != 3))
|
||||
{
|
||||
@@ -853,7 +853,7 @@ static int ui_colorpicker_wheel_cb(const bContext * /*C*/, uiBlock *block, const
|
||||
}
|
||||
|
||||
if (add != 0.0f) {
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
if (but->type == UI_BTYPE_HSVCUBE && but->active == nullptr) {
|
||||
uiPopupBlockHandle *popup = block->handle;
|
||||
ColorPicker *cpicker = static_cast<ColorPicker *>(but->custom_data);
|
||||
@@ -861,8 +861,8 @@ static int ui_colorpicker_wheel_cb(const bContext * /*C*/, uiBlock *block, const
|
||||
|
||||
/* Get the RGBA Color. */
|
||||
float rgba_perceptual[4];
|
||||
ui_but_v4_get(but, rgba_perceptual);
|
||||
ui_scene_linear_to_perceptual_space(but, rgba_perceptual);
|
||||
ui_but_v4_get(but.get(), rgba_perceptual);
|
||||
ui_scene_linear_to_perceptual_space(but.get(), rgba_perceptual);
|
||||
|
||||
/* Convert it to HSV. */
|
||||
ui_color_picker_rgb_to_hsv_compat(rgba_perceptual, hsv_perceptual);
|
||||
@@ -874,11 +874,11 @@ static int ui_colorpicker_wheel_cb(const bContext * /*C*/, uiBlock *block, const
|
||||
float rgba_scene_linear[4];
|
||||
rgba_scene_linear[3] = rgba_perceptual[3]; /* Transfer Alpha component. */
|
||||
ui_color_picker_hsv_to_rgb(hsv_perceptual, rgba_scene_linear);
|
||||
ui_perceptual_to_scene_linear_space(but, rgba_scene_linear);
|
||||
ui_but_v4_set(but, rgba_scene_linear);
|
||||
ui_perceptual_to_scene_linear_space(but.get(), rgba_scene_linear);
|
||||
ui_but_v4_set(but.get(), rgba_scene_linear);
|
||||
|
||||
/* Update all other Color Picker buttons to reflect the color change. */
|
||||
ui_update_color_picker_buts_rgba(but, block, cpicker, rgba_scene_linear);
|
||||
ui_update_color_picker_buts_rgba(but.get(), block, cpicker, rgba_scene_linear);
|
||||
if (popup) {
|
||||
popup->menuretval = UI_RETURN_UPDATE;
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ static uiBut *ui_popup_menu_memory__internal(uiBlock *block, uiBut *but)
|
||||
}
|
||||
|
||||
/* get */
|
||||
LISTBASE_FOREACH (uiBut *, but_iter, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but_iter : block->buttons) {
|
||||
/* Prevent labels (typically headings), from being returned in the case the text
|
||||
* happens to matches one of the menu items.
|
||||
* Skip separators too as checking them is redundant. */
|
||||
@@ -136,7 +136,7 @@ static uiBut *ui_popup_menu_memory__internal(uiBlock *block, uiBut *but)
|
||||
}
|
||||
if (mem[hash_mod] == ui_popup_string_hash(but_iter->str, but_iter->flag & UI_BUT_HAS_SEP_CHAR))
|
||||
{
|
||||
return but_iter;
|
||||
return but_iter.get();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,16 +318,16 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi
|
||||
/* position mouse at 0.8*width of the button and below the tile
|
||||
* on the first item */
|
||||
offset[0] = 0;
|
||||
LISTBASE_FOREACH (uiBut *, but_iter, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but_iter : block->buttons) {
|
||||
offset[0] = min_ii(offset[0],
|
||||
-(but_iter->rect.xmin + 0.8f * BLI_rctf_size_x(&but_iter->rect)));
|
||||
}
|
||||
|
||||
offset[1] = 2.1 * UI_UNIT_Y;
|
||||
|
||||
LISTBASE_FOREACH (uiBut *, but_iter, &block->buttons) {
|
||||
if (ui_but_is_editable(but_iter)) {
|
||||
but_activate = but_iter;
|
||||
for (const std::unique_ptr<uiBut> &but_iter : block->buttons) {
|
||||
if (ui_but_is_editable(but_iter.get())) {
|
||||
but_activate = but_iter.get();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -812,7 +812,7 @@ void UI_popup_block_template_confirm_op(uiLayout *layout,
|
||||
return nullptr;
|
||||
}
|
||||
uiBlock *block = uiLayoutGetBlock(row);
|
||||
const uiBut *but_ref = (uiBut *)block->buttons.last;
|
||||
const uiBut *but_ref = block->last_but();
|
||||
uiItemFullO_ptr(row,
|
||||
ot,
|
||||
confirm_text,
|
||||
@@ -822,10 +822,10 @@ void UI_popup_block_template_confirm_op(uiLayout *layout,
|
||||
UI_ITEM_NONE,
|
||||
r_ptr);
|
||||
|
||||
if (but_ref == block->buttons.last) {
|
||||
if (block->buttons.is_empty() || but_ref == block->buttons.last().get()) {
|
||||
return nullptr;
|
||||
}
|
||||
return static_cast<uiBut *>(block->buttons.last);
|
||||
return block->buttons.last().get();
|
||||
};
|
||||
|
||||
auto cancel_fn = [&row, &cancel_text, &show_cancel]() -> uiBut * {
|
||||
|
||||
@@ -209,12 +209,12 @@ static uiBlock *ui_block_func_POPOVER(bContext *C, uiPopupBlockHandle *handle, v
|
||||
if (!handle->refresh) {
|
||||
uiBut *but = nullptr;
|
||||
uiBut *but_first = nullptr;
|
||||
LISTBASE_FOREACH (uiBut *, but_iter, &block->buttons) {
|
||||
if ((but_first == nullptr) && ui_but_is_editable(but_iter)) {
|
||||
but_first = but_iter;
|
||||
for (const std::unique_ptr<uiBut> &but_iter : block->buttons) {
|
||||
if ((but_first == nullptr) && ui_but_is_editable(but_iter.get())) {
|
||||
but_first = but_iter.get();
|
||||
}
|
||||
if (but_iter->flag & (UI_SELECT | UI_SELECT_DRAW)) {
|
||||
but = but_iter;
|
||||
but = but_iter.get();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,10 +93,10 @@ static void ui_popup_block_position(wmWindow *window,
|
||||
|
||||
/* Compute block size in window space, based on buttons contained in it. */
|
||||
if (block->rect.xmin == 0.0f && block->rect.xmax == 0.0f) {
|
||||
if (block->buttons.first) {
|
||||
if (!block->buttons.is_empty()) {
|
||||
BLI_rctf_init_minmax(&block->rect);
|
||||
|
||||
LISTBASE_FOREACH (uiBut *, bt, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &bt : block->buttons) {
|
||||
if (block->content_hints & UI_BLOCK_CONTAINS_SUBMENU_BUT) {
|
||||
bt->rect.xmax += UI_MENU_SUBMENU_PADDING;
|
||||
}
|
||||
@@ -116,7 +116,7 @@ static void ui_popup_block_position(wmWindow *window,
|
||||
const float max_radius = (0.5f * U.widget_unit);
|
||||
|
||||
if (delta >= 0 && delta < max_radius) {
|
||||
LISTBASE_FOREACH (uiBut *, bt, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &bt : block->buttons) {
|
||||
/* Only trim the right most buttons in multi-column popovers. */
|
||||
if (bt->rect.xmax == block->rect.xmax) {
|
||||
bt->rect.xmax -= delta;
|
||||
@@ -311,13 +311,13 @@ static void ui_popup_block_position(wmWindow *window,
|
||||
}
|
||||
|
||||
/* Apply offset, buttons in window coords. */
|
||||
LISTBASE_FOREACH (uiBut *, bt, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &bt : block->buttons) {
|
||||
ui_block_to_window_rctf(butregion, but->block, &bt->rect, &bt->rect);
|
||||
|
||||
BLI_rctf_translate(&bt->rect, offset_x, offset_y);
|
||||
|
||||
/* ui_but_update recalculates drawstring size in pixels */
|
||||
ui_but_update(bt);
|
||||
ui_but_update(bt.get());
|
||||
}
|
||||
|
||||
BLI_rctf_translate(&block->rect, offset_x, offset_y);
|
||||
@@ -503,7 +503,7 @@ static void ui_popup_block_clip(wmWindow *window, uiBlock *block)
|
||||
|
||||
/* ensure menu items draw inside left/right boundary */
|
||||
const float xofs = block->rect.xmin - xmin_orig;
|
||||
LISTBASE_FOREACH (uiBut *, bt, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &bt : block->buttons) {
|
||||
bt->rect.xmin += xofs;
|
||||
bt->rect.xmax += xofs;
|
||||
}
|
||||
@@ -513,16 +513,16 @@ void ui_popup_block_scrolltest(uiBlock *block)
|
||||
{
|
||||
block->flag &= ~(UI_BLOCK_CLIPBOTTOM | UI_BLOCK_CLIPTOP);
|
||||
|
||||
LISTBASE_FOREACH (uiBut *, bt, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &bt : block->buttons) {
|
||||
bt->flag &= ~UI_SCROLLED;
|
||||
}
|
||||
|
||||
if (block->buttons.first == block->buttons.last) {
|
||||
if (block->buttons.size() < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* mark buttons that are outside boundary */
|
||||
LISTBASE_FOREACH (uiBut *, bt, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &bt : block->buttons) {
|
||||
if (bt->rect.ymin < block->rect.ymin) {
|
||||
bt->flag |= UI_SCROLLED;
|
||||
block->flag |= UI_BLOCK_CLIPBOTTOM;
|
||||
@@ -534,7 +534,7 @@ void ui_popup_block_scrolltest(uiBlock *block)
|
||||
}
|
||||
|
||||
/* mark buttons overlapping arrows, if we have them */
|
||||
LISTBASE_FOREACH (uiBut *, bt, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &bt : block->buttons) {
|
||||
if (block->flag & UI_BLOCK_CLIPBOTTOM) {
|
||||
if (bt->rect.ymin < block->rect.ymin + UI_MENU_SCROLL_ARROW) {
|
||||
bt->flag |= UI_SCROLLED;
|
||||
@@ -776,7 +776,7 @@ uiBlock *ui_popup_block_refresh(bContext *C,
|
||||
|
||||
/* lastly set the buttons at the center of the pie menu, ready for animation */
|
||||
if (U.pie_animation_timeout > 0) {
|
||||
LISTBASE_FOREACH (uiBut *, but_iter, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but_iter : block->buttons) {
|
||||
if (but_iter->pie_dir != UI_RADIAL_NONE) {
|
||||
BLI_rctf_recenter(&but_iter->rect, UNPACK2(block->pie_data.pie_center_spawned));
|
||||
}
|
||||
@@ -820,7 +820,7 @@ uiBlock *ui_popup_block_refresh(bContext *C,
|
||||
/* Popups can change size, fix scroll offset if a panel was closed. */
|
||||
float ymin = FLT_MAX;
|
||||
float ymax = -FLT_MAX;
|
||||
LISTBASE_FOREACH (uiBut *, bt, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &bt : block->buttons) {
|
||||
ymin = min_ff(ymin, bt->rect.ymin);
|
||||
ymax = max_ff(ymax, bt->rect.ymax);
|
||||
}
|
||||
@@ -830,7 +830,7 @@ uiBlock *ui_popup_block_refresh(bContext *C,
|
||||
handle->scrolloffset = std::clamp(handle->scrolloffset, scroll_min, scroll_max);
|
||||
/* apply scroll offset */
|
||||
if (handle->scrolloffset != 0.0f) {
|
||||
LISTBASE_FOREACH (uiBut *, bt, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &bt : block->buttons) {
|
||||
bt->rect.ymin += handle->scrolloffset;
|
||||
bt->rect.ymax += handle->scrolloffset;
|
||||
}
|
||||
|
||||
@@ -315,12 +315,12 @@ static ARegion *wm_searchbox_tooltip_init(
|
||||
*r_exit_on_event = true;
|
||||
|
||||
LISTBASE_FOREACH (uiBlock *, block, ®ion->runtime->uiblocks) {
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
if (but->type != UI_BTYPE_SEARCH_MENU) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uiButSearch *search_but = (uiButSearch *)but;
|
||||
uiButSearch *search_but = (uiButSearch *)but.get();
|
||||
if (!search_but->item_tooltip_fn) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ void template_asset_shelf_popover(uiLayout &layout,
|
||||
ed::asset::shelf::ensure_asset_library_fetched(C, *shelf_type);
|
||||
|
||||
uiItemPopoverPanel(row, &C, "ASSETSHELF_PT_popover_panel", name, icon);
|
||||
uiBut *but = static_cast<uiBut *>(block->buttons.last);
|
||||
uiBut *but = block->buttons.last().get();
|
||||
if (use_preview_icon) {
|
||||
ui_def_but_icon(but, icon, UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
|
||||
/* Avoid small annoyance where asset shelf popover gets spawned unintentionally on mouse hover,
|
||||
|
||||
@@ -370,7 +370,8 @@ static void colorband_buttons_layout(uiLayout *layout,
|
||||
}
|
||||
|
||||
/* Some special (rather awkward) treatment to update UI state on certain property changes. */
|
||||
LISTBASE_FOREACH_BACKWARD (uiBut *, but, &block->buttons) {
|
||||
for (int i = block->buttons.size() - 1; i >= 0; i--) {
|
||||
uiBut *but = block->buttons[i].get();
|
||||
if (but->rnapoin.data != ptr.data) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -82,14 +82,18 @@ void uiTemplateKeymapItemProperties(uiLayout *layout, PointerRNA *ptr)
|
||||
PointerRNA propptr = RNA_pointer_get(ptr, "properties");
|
||||
|
||||
if (propptr.data) {
|
||||
uiBut *but = static_cast<uiBut *>(uiLayoutGetBlock(layout)->buttons.last);
|
||||
uiBlock *block = uiLayoutGetBlock(layout);
|
||||
int i = uiLayoutGetBlock(layout)->buttons.size() - 1;
|
||||
|
||||
WM_operator_properties_sanitize(&propptr, false);
|
||||
template_keymap_item_properties(layout, nullptr, &propptr);
|
||||
|
||||
if (i < 0) {
|
||||
return;
|
||||
}
|
||||
/* attach callbacks to compensate for missing properties update,
|
||||
* we don't know which keymap (item) is being modified there */
|
||||
for (; but; but = but->next) {
|
||||
for (; i < block->buttons.size(); i++) {
|
||||
uiBut *but = block->buttons[i].get();
|
||||
/* operator buttons may store props for use (file selector, #36492) */
|
||||
if (but->rnaprop) {
|
||||
UI_but_func_set(but, keymap_item_modified, ptr->data, nullptr);
|
||||
|
||||
@@ -182,9 +182,9 @@ static eAutoPropButsReturn template_operator_property_buts_draw_single(
|
||||
if (block->oldblock == nullptr) {
|
||||
const bool is_popup = (block->flag & UI_BLOCK_KEEP_OPEN) != 0;
|
||||
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : block->buttons) {
|
||||
/* no undo for buttons for operator redo panels */
|
||||
UI_but_flag_disable(but, UI_BUT_UNDO);
|
||||
UI_but_flag_disable(but.get(), UI_BUT_UNDO);
|
||||
|
||||
/* only for popups, see #36109. */
|
||||
|
||||
@@ -193,7 +193,7 @@ static eAutoPropButsReturn template_operator_property_buts_draw_single(
|
||||
*/
|
||||
if (is_popup) {
|
||||
if ((but->rnaprop == op->type->prop) && ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_NUM)) {
|
||||
UI_but_focus_on_enter_event(CTX_wm_window(C), but);
|
||||
UI_but_focus_on_enter_event(CTX_wm_window(C), but.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -669,29 +669,30 @@ static MenuSearch_Data *menu_items_from_ui_create(bContext *C,
|
||||
|
||||
UI_block_end(C, block);
|
||||
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
for (const int i : block->buttons.index_range()) {
|
||||
const std::unique_ptr<uiBut> &but = block->buttons[i];
|
||||
MenuType *mt_from_but = nullptr;
|
||||
/* Support menu titles with dynamic from initial labels
|
||||
* (used by edit-mesh context menu). */
|
||||
if (but->type == UI_BTYPE_LABEL) {
|
||||
|
||||
/* Check if the label is the title. */
|
||||
uiBut *but_test = but->prev;
|
||||
while (but_test && but_test->type == UI_BTYPE_SEPR) {
|
||||
but_test = but_test->prev;
|
||||
const std::unique_ptr<uiBut> *but_test = block->buttons.begin() + i - 1;
|
||||
while (but_test >= block->buttons.begin() && (*but_test)->type == UI_BTYPE_SEPR) {
|
||||
but_test--;
|
||||
}
|
||||
|
||||
if (but_test == nullptr) {
|
||||
if (but_test < block->buttons.begin()) {
|
||||
menu_display_name_map.add(mt,
|
||||
scope.linear_allocator().copy_string(but->drawstr).c_str());
|
||||
}
|
||||
}
|
||||
else if (menu_items_from_ui_create_item_from_button(
|
||||
data, scope, mt, but, wm_context, current_menu.self_as_parent))
|
||||
data, scope, mt, but.get(), wm_context, current_menu.self_as_parent))
|
||||
{
|
||||
/* pass */
|
||||
}
|
||||
else if ((mt_from_but = UI_but_menutype_get(but))) {
|
||||
else if ((mt_from_but = UI_but_menutype_get(but.get()))) {
|
||||
const bool uses_context = but->context &&
|
||||
bool(mt_from_but->flag & MenuTypeFlag::ContextDependent);
|
||||
const bool tagged_first_time = menu_tagged.add(mt_from_but);
|
||||
@@ -769,7 +770,7 @@ static MenuSearch_Data *menu_items_from_ui_create(bContext *C,
|
||||
* could be used as a more general way to know if poll succeeded,
|
||||
* at this point it's not set - this could be further investigated. */
|
||||
bool poll_success = true;
|
||||
if (PanelType *pt = UI_but_paneltype_get(but)) {
|
||||
if (PanelType *pt = UI_but_paneltype_get(but.get())) {
|
||||
if (pt->poll && (pt->poll(C, pt) == false)) {
|
||||
poll_success = false;
|
||||
}
|
||||
@@ -786,9 +787,9 @@ static MenuSearch_Data *menu_items_from_ui_create(bContext *C,
|
||||
menu_parent->drawstr = scope.linear_allocator().copy_string(but->drawstr);
|
||||
menu_parent->parent = current_menu.self_as_parent;
|
||||
|
||||
LISTBASE_FOREACH (uiBut *, sub_but, &sub_block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &sub_but : sub_block->buttons) {
|
||||
menu_items_from_ui_create_item_from_button(
|
||||
data, scope, mt, sub_but, wm_context, menu_parent);
|
||||
data, scope, mt, sub_but.get(), wm_context, menu_parent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -413,7 +413,7 @@ void uiTemplateStatusInfo(uiLayout *layout, bContext *C)
|
||||
uiLayoutSetEmboss(row, UI_EMBOSS_NONE);
|
||||
/* This operator also works fine for blocked extensions. */
|
||||
uiItemO(row, "", ICON_ERROR, "EXTENSIONS_OT_userpref_show_for_update");
|
||||
uiBut *but = static_cast<uiBut *>(uiLayoutGetBlock(layout)->buttons.last);
|
||||
uiBut *but = uiLayoutGetBlock(layout)->buttons.last().get();
|
||||
uchar color[4];
|
||||
UI_GetThemeColor4ubv(TH_TEXT, color);
|
||||
copy_v4_v4_uchar(but->col, color);
|
||||
@@ -438,7 +438,7 @@ void uiTemplateStatusInfo(uiLayout *layout, bContext *C)
|
||||
else {
|
||||
uiLayoutSetEmboss(row, UI_EMBOSS_NONE);
|
||||
uiItemO(row, "", ICON_INTERNET_OFFLINE, "EXTENSIONS_OT_userpref_show_online");
|
||||
uiBut *but = static_cast<uiBut *>(uiLayoutGetBlock(layout)->buttons.last);
|
||||
uiBut *but = uiLayoutGetBlock(layout)->buttons.last().get();
|
||||
uchar color[4];
|
||||
UI_GetThemeColor4ubv(TH_TEXT, color);
|
||||
copy_v4_v4_uchar(but->col, color);
|
||||
@@ -462,7 +462,7 @@ void uiTemplateStatusInfo(uiLayout *layout, bContext *C)
|
||||
}
|
||||
uiLayoutSetEmboss(row, UI_EMBOSS_NONE);
|
||||
uiItemO(row, "", icon, "EXTENSIONS_OT_userpref_show_for_update");
|
||||
uiBut *but = static_cast<uiBut *>(uiLayoutGetBlock(layout)->buttons.last);
|
||||
uiBut *but = uiLayoutGetBlock(layout)->buttons.last().get();
|
||||
uchar color[4];
|
||||
UI_GetThemeColor4ubv(TH_TEXT, color);
|
||||
copy_v4_v4_uchar(but->col, color);
|
||||
|
||||
@@ -166,12 +166,12 @@ static AbstractViewItem *find_item_from_rename_button(const uiBut &rename_but)
|
||||
/* A minimal sanity check, can't do much more here. */
|
||||
BLI_assert(rename_but.type == UI_BTYPE_TEXT && rename_but.poin);
|
||||
|
||||
LISTBASE_FOREACH (uiBut *, but, &rename_but.block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : rename_but.block->buttons) {
|
||||
if (but->type != UI_BTYPE_VIEW_ITEM) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uiButViewItem *view_item_but = (uiButViewItem *)but;
|
||||
uiButViewItem *view_item_but = (uiButViewItem *)but.get();
|
||||
AbstractViewItem *item = reinterpret_cast<AbstractViewItem *>(view_item_but->view_item);
|
||||
const AbstractView &view = item->get_view();
|
||||
|
||||
|
||||
@@ -97,11 +97,11 @@ void ViewLink::views_bounds_calc(const uiBlock &block)
|
||||
views_bounds.add(link->view.get(), minmax);
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (uiBut *, but, &block.buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : block.buttons) {
|
||||
if (but->type != UI_BTYPE_VIEW_ITEM) {
|
||||
continue;
|
||||
}
|
||||
uiButViewItem *view_item_but = static_cast<uiButViewItem *>(but);
|
||||
uiButViewItem *view_item_but = static_cast<uiButViewItem *>(but.get());
|
||||
if (!view_item_but->view_item) {
|
||||
continue;
|
||||
}
|
||||
@@ -344,11 +344,11 @@ uiButViewItem *ui_block_view_find_matching_view_item_but_in_old_block(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (uiBut *, old_but, &old_block->buttons) {
|
||||
for (const std::unique_ptr<uiBut> &old_but : old_block->buttons) {
|
||||
if (old_but->type != UI_BTYPE_VIEW_ITEM) {
|
||||
continue;
|
||||
}
|
||||
uiButViewItem *old_item_but = (uiButViewItem *)old_but;
|
||||
uiButViewItem *old_item_but = (uiButViewItem *)old_but.get();
|
||||
if (!old_item_but->view_item) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -240,11 +240,11 @@ void AbstractTreeView::get_hierarchy_lines(const ARegion ®ion,
|
||||
|
||||
static uiButViewItem *find_first_view_item_but(const uiBlock &block, const AbstractTreeView &view)
|
||||
{
|
||||
LISTBASE_FOREACH (uiBut *, but, &block.buttons) {
|
||||
for (const std::unique_ptr<uiBut> &but : block.buttons) {
|
||||
if (but->type != UI_BTYPE_VIEW_ITEM) {
|
||||
continue;
|
||||
}
|
||||
uiButViewItem *view_item_but = static_cast<uiButViewItem *>(but);
|
||||
uiButViewItem *view_item_but = static_cast<uiButViewItem *>(but.get());
|
||||
if (&view_item_but->view_item->get_view() == &view) {
|
||||
return view_item_but;
|
||||
}
|
||||
|
||||
@@ -483,7 +483,7 @@ static void template_texture_user_menu(bContext *C, uiLayout *layout, void * /*a
|
||||
/* add label per category */
|
||||
if (!last_category || !STREQ(last_category, user->category)) {
|
||||
uiItemL(layout, IFACE_(user->category), ICON_NONE);
|
||||
but = static_cast<uiBut *>(block->buttons.last);
|
||||
but = block->buttons.last().get();
|
||||
but->drawflag = UI_BUT_TEXT_LEFT;
|
||||
}
|
||||
|
||||
|
||||
@@ -539,7 +539,7 @@ static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname)
|
||||
UI_block_layout_set_current(block, column);
|
||||
|
||||
uiItemL(column, IFACE_(cname), ICON_NODE);
|
||||
but = (uiBut *)block->buttons.last;
|
||||
but = block->buttons.last().get();
|
||||
|
||||
first = 0;
|
||||
}
|
||||
@@ -628,7 +628,7 @@ static void ui_template_node_link_menu(bContext *C, uiLayout *layout, void *but_
|
||||
|
||||
if (sock->link) {
|
||||
uiItemL(column, IFACE_("Link"), ICON_NONE);
|
||||
but = (uiBut *)block->buttons.last;
|
||||
but = block->buttons.last().get();
|
||||
but->drawflag = UI_BUT_TEXT_LEFT;
|
||||
|
||||
but = uiDefBut(block,
|
||||
|
||||
Reference in New Issue
Block a user