Revert "UI: Tree-view scrolling and resizing support"
This reverts commit 6a1210ff3f.
This commit is contained in:
@@ -1020,8 +1020,6 @@ def km_user_interface(_params):
|
||||
("ui.list_start_filter", {"type": 'F', "value": 'PRESS', "ctrl": True}, None),
|
||||
# UI views (polls check if there's a UI view under the cursor).
|
||||
("ui.view_start_filter", {"type": 'F', "value": 'PRESS', "ctrl": True}, None),
|
||||
("ui.view_scroll", {"type": 'WHEELUPMOUSE', "value": 'ANY'}, None),
|
||||
("ui.view_scroll", {"type": 'WHEELDOWNMOUSE', "value": 'ANY'}, None),
|
||||
])
|
||||
|
||||
return keymap
|
||||
|
||||
@@ -47,11 +47,6 @@ namespace blender::ui {
|
||||
class AbstractViewItem;
|
||||
class AbstractViewItemDragController;
|
||||
|
||||
enum class ViewScrollDirection {
|
||||
UP,
|
||||
DOWN,
|
||||
};
|
||||
|
||||
class AbstractView {
|
||||
friend class AbstractViewItem;
|
||||
friend struct ::ViewLink;
|
||||
@@ -91,13 +86,10 @@ class AbstractView {
|
||||
*/
|
||||
virtual bool begin_filtering(const bContext &C) const;
|
||||
|
||||
virtual void draw_overlays(const ARegion ®ion, const uiBlock &block) const;
|
||||
virtual void draw_overlays(const ARegion ®ion) const;
|
||||
|
||||
virtual void foreach_view_item(FunctionRef<void(AbstractViewItem &)> iter_fn) const = 0;
|
||||
|
||||
virtual bool supports_scrolling() const;
|
||||
virtual void scroll(ViewScrollDirection direction);
|
||||
|
||||
/**
|
||||
* Makes \a item valid for display in this view. Behavior is undefined for items not registered
|
||||
* with this.
|
||||
|
||||
@@ -112,36 +112,29 @@ using TreeViewOrItem = TreeViewItemContainer;
|
||||
* \{ */
|
||||
|
||||
class AbstractTreeView : public AbstractView, public TreeViewItemContainer {
|
||||
/* Shared pointer so the pointer can be kept persistent over redraws. The grip button gets a
|
||||
* pointer to modify the value on resizing, and it uses it to identify the button over redraws.*/
|
||||
/* TODO support region zoom. */
|
||||
std::shared_ptr<int> custom_height_ = nullptr;
|
||||
std::shared_ptr<int> scroll_value_ = nullptr;
|
||||
int min_rows_ = 0;
|
||||
|
||||
friend class AbstractTreeViewItem;
|
||||
friend class TreeViewBuilder;
|
||||
friend class TreeViewLayoutBuilder;
|
||||
friend class TreeViewItemDropTarget;
|
||||
|
||||
public:
|
||||
/* virtual */ ~AbstractTreeView() override = default;
|
||||
|
||||
void draw_overlays(const ARegion ®ion, const uiBlock &block) const override;
|
||||
void draw_overlays(const ARegion ®ion) const override;
|
||||
|
||||
void foreach_item(ItemIterFn iter_fn, IterOptions options = IterOptions::None) const;
|
||||
|
||||
void scroll(ViewScrollDirection direction) override;
|
||||
|
||||
/**
|
||||
* \param xy: The mouse coordinates in window space.
|
||||
*/
|
||||
AbstractTreeViewItem *find_hovered(const ARegion ®ion, const int2 &xy);
|
||||
|
||||
/** Visual feature: Define a number of item rows the view will show by default. If there
|
||||
/** Visual feature: Define a number of item rows the view will always show at minimum. If there
|
||||
* are fewer items, empty dummy items will be added. These contribute to the view bounds, so the
|
||||
* drop target of the view includes them, but they are not interactive (e.g. no mouse-hover
|
||||
* highlight). */
|
||||
void set_default_rows(int min_rows);
|
||||
void set_min_rows(int min_rows);
|
||||
|
||||
protected:
|
||||
virtual void build_tree() = 0;
|
||||
@@ -153,18 +146,14 @@ class AbstractTreeView : public AbstractView, public TreeViewItemContainer {
|
||||
const TreeViewOrItem &old_items);
|
||||
static AbstractTreeViewItem *find_matching_child(const AbstractTreeViewItem &lookup_item,
|
||||
const TreeViewOrItem &items);
|
||||
std::optional<int> tot_visible_row_count() const;
|
||||
|
||||
bool supports_scrolling() const override;
|
||||
void draw_hierarchy_lines(const ARegion ®ion) const;
|
||||
void draw_hierarchy_lines_recursive(const ARegion ®ion,
|
||||
const TreeViewOrItem &parent,
|
||||
const uint pos,
|
||||
const float aspect) const;
|
||||
|
||||
void draw_hierarchy_lines(const ARegion ®ion, const uiBlock &block) const;
|
||||
void get_hierarchy_lines(const ARegion ®ion,
|
||||
const TreeViewOrItem &parent,
|
||||
const float aspect,
|
||||
Vector<std::pair<int2, int2>> &lines,
|
||||
int &visible_item_index) const;
|
||||
|
||||
int count_visible_descendants(const AbstractTreeViewItem &parent) const;
|
||||
AbstractTreeViewItem *find_last_visible_descendant(const AbstractTreeViewItem &parent) const;
|
||||
};
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -52,7 +52,6 @@
|
||||
#include "RNA_types.hh"
|
||||
|
||||
#include "UI_interface.hh"
|
||||
#include "UI_abstract_view.hh"
|
||||
|
||||
#include "interface_intern.hh"
|
||||
|
||||
@@ -2404,23 +2403,18 @@ static void UI_OT_list_start_filter(wmOperatorType *ot)
|
||||
/** \name UI View Start Filter Operator
|
||||
* \{ */
|
||||
|
||||
static AbstractView *get_view_focused(bContext *C)
|
||||
static bool ui_view_focused_poll(bContext *C)
|
||||
{
|
||||
const wmWindow *win = CTX_wm_window(C);
|
||||
if (!(win && win->eventstate)) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
const ARegion *region = CTX_wm_region(C);
|
||||
if (!region) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
return reinterpret_cast<AbstractView*>(UI_region_view_find_at(region, win->eventstate->xy, 0));
|
||||
}
|
||||
|
||||
static bool ui_view_focused_poll(bContext *C)
|
||||
{
|
||||
const AbstractView *view = get_view_focused(C);
|
||||
const uiViewHandle *view = UI_region_view_find_at(region, win->eventstate->xy, 0);
|
||||
return view != nullptr;
|
||||
}
|
||||
|
||||
@@ -2501,72 +2495,6 @@ static void UI_OT_view_drop(wmOperatorType *ot)
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name UI View Drop Operator
|
||||
* \{ */
|
||||
|
||||
static bool ui_view_scroll_poll(bContext *C)
|
||||
{
|
||||
const AbstractView *view = get_view_focused(C);
|
||||
if (!view) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return view->supports_scrolling();
|
||||
}
|
||||
|
||||
static int ui_view_scroll_invoke(bContext *C, wmOperator * /*op*/, const wmEvent *event)
|
||||
{
|
||||
ARegion *region = CTX_wm_region(C);
|
||||
int type = event->type;
|
||||
bool invert_direction = false;
|
||||
|
||||
if (type == MOUSEPAN) {
|
||||
int dummy_val;
|
||||
ui_pan_to_scroll(event, &type, &dummy_val);
|
||||
|
||||
/* 'ui_pan_to_scroll' gives the absolute direction. */
|
||||
if (event->flag & WM_EVENT_SCROLL_INVERT) {
|
||||
invert_direction = true;
|
||||
}
|
||||
}
|
||||
|
||||
AbstractView *view = get_view_focused(C);
|
||||
std::optional<ViewScrollDirection> direction =
|
||||
[type, invert_direction]() -> std::optional<ViewScrollDirection> {
|
||||
switch (type) {
|
||||
case WHEELUPMOUSE:
|
||||
return invert_direction ? ViewScrollDirection::DOWN : ViewScrollDirection::UP;
|
||||
case WHEELDOWNMOUSE:
|
||||
return invert_direction ? ViewScrollDirection::UP : ViewScrollDirection::DOWN;
|
||||
default:
|
||||
return std::nullopt;
|
||||
}
|
||||
}();
|
||||
if (!direction) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
BLI_assert(view->supports_scrolling());
|
||||
view->scroll(*direction);
|
||||
|
||||
ED_region_tag_redraw(region);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void UI_OT_view_scroll(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "View Scroll";
|
||||
ot->idname = "UI_OT_view_scroll";
|
||||
|
||||
ot->invoke = ui_view_scroll_invoke;
|
||||
ot->poll = ui_view_scroll_poll;
|
||||
|
||||
ot->flag = OPTYPE_INTERNAL;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name UI View Item Rename Operator
|
||||
*
|
||||
@@ -2710,7 +2638,6 @@ void ED_operatortypes_ui()
|
||||
|
||||
WM_operatortype_append(UI_OT_view_start_filter);
|
||||
WM_operatortype_append(UI_OT_view_drop);
|
||||
WM_operatortype_append(UI_OT_view_scroll);
|
||||
WM_operatortype_append(UI_OT_view_item_rename);
|
||||
|
||||
WM_operatortype_append(UI_OT_override_type_set_button);
|
||||
|
||||
@@ -473,7 +473,7 @@ void uiTemplateBoneCollectionTree(uiLayout *layout, bContext *C)
|
||||
*block,
|
||||
"Bone Collection Tree View",
|
||||
std::make_unique<blender::ui::bonecollections::BoneCollectionTreeView>(*armature));
|
||||
tree_view->set_default_rows(3);
|
||||
tree_view->set_min_rows(3);
|
||||
|
||||
ui::TreeViewBuilder::build_tree_view(*tree_view, *layout);
|
||||
}
|
||||
|
||||
@@ -410,7 +410,7 @@ void uiTemplateGreasePencilLayerTree(uiLayout *layout, bContext *C)
|
||||
*block,
|
||||
"Grease Pencil Layer Tree View",
|
||||
std::make_unique<blender::ui::greasepencil::LayerTreeView>(grease_pencil));
|
||||
tree_view->set_default_rows(3);
|
||||
tree_view->set_min_rows(3);
|
||||
|
||||
ui::TreeViewBuilder::build_tree_view(*tree_view, *layout);
|
||||
}
|
||||
|
||||
@@ -399,7 +399,7 @@ void uiTemplateLightLinkingCollection(uiLayout *layout,
|
||||
*block,
|
||||
"Light Linking Collection Tree View",
|
||||
std::make_unique<blender::ui::light_linking::CollectionView>(*context_layout, *collection));
|
||||
tree_view->set_default_rows(3);
|
||||
tree_view->set_min_rows(3);
|
||||
|
||||
blender::ui::TreeViewBuilder::build_tree_view(*tree_view, *layout);
|
||||
}
|
||||
|
||||
@@ -517,7 +517,7 @@ void uiTemplateNodeTreeInterface(uiLayout *layout, PointerRNA *ptr)
|
||||
*block,
|
||||
"Node Tree Declaration Tree View",
|
||||
std::make_unique<blender::ui::nodes::NodeTreeInterfaceView>(nodetree, interface));
|
||||
tree_view->set_default_rows(3);
|
||||
tree_view->set_min_rows(3);
|
||||
|
||||
blender::ui::TreeViewBuilder::build_tree_view(*tree_view, *layout);
|
||||
}
|
||||
|
||||
@@ -111,21 +111,11 @@ bool AbstractView::begin_filtering(const bContext & /*C*/) const
|
||||
return false;
|
||||
}
|
||||
|
||||
void AbstractView::draw_overlays(const ARegion & /*region*/, const uiBlock & /*block*/) const
|
||||
void AbstractView::draw_overlays(const ARegion & /*region*/) const
|
||||
{
|
||||
/* Nothing by default. */
|
||||
}
|
||||
|
||||
bool AbstractView::supports_scrolling() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void AbstractView::scroll(ViewScrollDirection /*direction*/)
|
||||
{
|
||||
BLI_assert_msg(false, "Unsupported for this view type");
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
@@ -145,7 +145,7 @@ void ui_block_views_listen(const uiBlock *block, const wmRegionListenerParams *l
|
||||
void ui_block_views_draw_overlays(const ARegion *region, const uiBlock *block)
|
||||
{
|
||||
LISTBASE_FOREACH (ViewLink *, view_link, &block->views) {
|
||||
view_link->view->draw_overlays(*region, *block);
|
||||
view_link->view->draw_overlays(*region);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#include "interface_intern.hh"
|
||||
|
||||
#include "UI_interface.hh"
|
||||
#include "UI_view2d.hh"
|
||||
|
||||
#include "WM_api.hh"
|
||||
#include "WM_types.hh"
|
||||
@@ -116,119 +115,74 @@ AbstractTreeViewItem *AbstractTreeView::find_hovered(const ARegion ®ion, cons
|
||||
return hovered_item;
|
||||
}
|
||||
|
||||
void AbstractTreeView::set_default_rows(int default_rows)
|
||||
void AbstractTreeView::set_min_rows(int min_rows)
|
||||
{
|
||||
custom_height_ = std::make_unique<int>(default_rows * padded_item_height());
|
||||
min_rows_ = min_rows;
|
||||
}
|
||||
|
||||
int AbstractTreeView::count_visible_descendants(const AbstractTreeViewItem &parent) const
|
||||
AbstractTreeViewItem *AbstractTreeView::find_last_visible_descendant(
|
||||
const AbstractTreeViewItem &parent) const
|
||||
{
|
||||
if (parent.is_collapsed()) {
|
||||
return 0;
|
||||
}
|
||||
int count = 0;
|
||||
for (const auto &item : parent.children_) {
|
||||
if (!item->is_filtered_visible()) {
|
||||
continue;
|
||||
}
|
||||
count++;
|
||||
count += count_visible_descendants(*item);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return count;
|
||||
AbstractTreeViewItem *last_descendant = parent.children_.last().get();
|
||||
while (!last_descendant->children_.is_empty() && !last_descendant->is_collapsed()) {
|
||||
last_descendant = last_descendant->children_.last().get();
|
||||
}
|
||||
|
||||
return last_descendant;
|
||||
}
|
||||
|
||||
|
||||
void AbstractTreeView::get_hierarchy_lines(const ARegion ®ion,
|
||||
const TreeViewOrItem &parent,
|
||||
const float aspect,
|
||||
Vector<std::pair<int2, int2>> &lines,
|
||||
int &visible_item_index) const
|
||||
void AbstractTreeView::draw_hierarchy_lines_recursive(const ARegion ®ion,
|
||||
const TreeViewOrItem &parent,
|
||||
const uint pos,
|
||||
const float aspect) const
|
||||
{
|
||||
const int scroll_ofs = scroll_value_ ? *scroll_value_ : 0;
|
||||
const int max_visible_row_count = tot_visible_row_count().value_or(
|
||||
std::numeric_limits<int>::max());
|
||||
|
||||
for (const auto &item : parent.children_) {
|
||||
if (!item->is_filtered_visible()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const int item_index = visible_item_index;
|
||||
visible_item_index++;
|
||||
|
||||
if (!item->is_collapsible() || item->is_collapsed()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Draw a hierarchy line for the descendants of this item. */
|
||||
draw_hierarchy_lines_recursive(region, *item, pos, aspect);
|
||||
|
||||
const AbstractTreeViewItem *first_descendant = item->children_.first().get();
|
||||
const int descendant_count = count_visible_descendants(*item);
|
||||
|
||||
const int first_descendant_index = item_index + 1;
|
||||
const int last_descendant_index = first_descendant_index + descendant_count;
|
||||
|
||||
const AbstractTreeViewItem *last_descendant = find_last_visible_descendant(*item);
|
||||
if (!first_descendant->view_item_but_ || !last_descendant || !last_descendant->view_item_but_)
|
||||
{
|
||||
const bool line_ends_above_visible = last_descendant_index < scroll_ofs;
|
||||
if (line_ends_above_visible) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const bool line_starts_below_visible = first_descendant_index >
|
||||
(scroll_ofs + long(max_visible_row_count));
|
||||
/* Can return here even, following items won't be in view anymore. */
|
||||
if (line_starts_below_visible) {
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
const uiButViewItem &first_child_but = *first_descendant->view_item_button();
|
||||
const uiButViewItem &last_child_but = *last_descendant->view_item_button();
|
||||
|
||||
const int x = ((first_descendant->indent_width() + (5 * UI_SCALE_FAC) -
|
||||
(0.5f * UI_ICON_SIZE) + U.pixelsize + UI_SCALE_FAC) /
|
||||
aspect);
|
||||
const int ymax = std::max(0, first_descendant_index - scroll_ofs) * padded_item_height();
|
||||
const int ymin = std::min(max_visible_row_count, last_descendant_index - scroll_ofs) *
|
||||
padded_item_height();
|
||||
lines.append(std::make_pair(int2(x, ymax), int2(x, ymin)));
|
||||
BLI_assert(first_child_but.block == last_child_but.block);
|
||||
const uiBlock *block = first_child_but.block;
|
||||
|
||||
this->get_hierarchy_lines(region, *item, aspect, lines, visible_item_index);
|
||||
rcti first_child_rect;
|
||||
ui_but_to_pixelrect(&first_child_rect, ®ion, block, &first_child_but);
|
||||
rcti last_child_rect;
|
||||
ui_but_to_pixelrect(&last_child_rect, ®ion, block, &last_child_but);
|
||||
|
||||
const float x = first_child_rect.xmin + ((first_descendant->indent_width() -
|
||||
(0.5f * UI_ICON_SIZE) + U.pixelsize + UI_SCALE_FAC) /
|
||||
aspect);
|
||||
const int first_child_top = first_child_rect.ymax - (2.0f * UI_SCALE_FAC / aspect);
|
||||
const int last_child_bottom = last_child_rect.ymin + (4.0f * UI_SCALE_FAC / aspect);
|
||||
immBegin(GPU_PRIM_LINES, 2);
|
||||
immVertex2f(pos, x, first_child_top);
|
||||
immVertex2f(pos, x, last_child_bottom);
|
||||
immEnd();
|
||||
}
|
||||
}
|
||||
|
||||
static uiButViewItem *find_first_view_item_but(const uiBlock &block, const AbstractTreeView &view)
|
||||
{
|
||||
LISTBASE_FOREACH (uiBut *, but, &block.buttons) {
|
||||
if (but->type != UI_BTYPE_VIEW_ITEM) {
|
||||
continue;
|
||||
}
|
||||
uiButViewItem *view_item_but = static_cast<uiButViewItem *>(but);
|
||||
AbstractViewItem *view_item = reinterpret_cast<AbstractViewItem *>(view_item_but->view_item);
|
||||
if (&view_item->get_view() == &view) {
|
||||
return view_item_but;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void AbstractTreeView::draw_hierarchy_lines(const ARegion ®ion, const uiBlock &block) const
|
||||
void AbstractTreeView::draw_hierarchy_lines(const ARegion ®ion) const
|
||||
{
|
||||
const float aspect = (region.v2d.flag & V2D_IS_INIT) ?
|
||||
BLI_rctf_size_y(®ion.v2d.cur) /
|
||||
(BLI_rcti_size_y(®ion.v2d.mask) + 1) :
|
||||
1.0f;
|
||||
|
||||
uiButViewItem *first_item_but = find_first_view_item_but(block, *this);
|
||||
if (!first_item_but) {
|
||||
return;
|
||||
}
|
||||
|
||||
Vector<std::pair<int2, int2>> lines;
|
||||
int index = 0;
|
||||
get_hierarchy_lines(region, *this, aspect, lines, index);
|
||||
if (lines.is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
GPUVertFormat *format = immVertexFormat();
|
||||
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
|
||||
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
|
||||
@@ -236,34 +190,22 @@ void AbstractTreeView::draw_hierarchy_lines(const ARegion ®ion, const uiBlock
|
||||
|
||||
GPU_line_width(1.0f / aspect);
|
||||
GPU_blend(GPU_BLEND_ALPHA);
|
||||
|
||||
rcti first_item_but_pixel_rect;
|
||||
ui_but_to_pixelrect(&first_item_but_pixel_rect, ®ion, &block, first_item_but);
|
||||
int2 top_left{first_item_but_pixel_rect.xmin, first_item_but_pixel_rect.ymax};
|
||||
|
||||
for (const auto &line : lines) {
|
||||
immBegin(GPU_PRIM_LINES, 2);
|
||||
immVertex2f(pos, top_left.x + line.first.x, top_left.y - line.first.y);
|
||||
immVertex2f(pos, top_left.x + line.second.x, top_left.y - line.second.y);
|
||||
immEnd();
|
||||
}
|
||||
draw_hierarchy_lines_recursive(region, *this, pos, aspect);
|
||||
GPU_blend(GPU_BLEND_NONE);
|
||||
|
||||
immUnbindProgram();
|
||||
}
|
||||
|
||||
void AbstractTreeView::draw_overlays(const ARegion ®ion, const uiBlock &block) const
|
||||
void AbstractTreeView::draw_overlays(const ARegion ®ion) const
|
||||
{
|
||||
draw_hierarchy_lines(region, block);
|
||||
draw_hierarchy_lines(region);
|
||||
}
|
||||
|
||||
void AbstractTreeView::update_children_from_old(const AbstractView &old_view)
|
||||
{
|
||||
const AbstractTreeView &old_tree_view = dynamic_cast<const AbstractTreeView &>(old_view);
|
||||
|
||||
custom_height_ = old_tree_view.custom_height_;
|
||||
scroll_value_ = old_tree_view.scroll_value_;
|
||||
this->update_children_from_old_recursive(*this, old_tree_view);
|
||||
update_children_from_old_recursive(*this, old_tree_view);
|
||||
}
|
||||
|
||||
void AbstractTreeView::update_children_from_old_recursive(const TreeViewOrItem &new_items,
|
||||
@@ -295,31 +237,6 @@ AbstractTreeViewItem *AbstractTreeView::find_matching_child(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::optional<int> AbstractTreeView::tot_visible_row_count() const
|
||||
{
|
||||
if (!custom_height_) {
|
||||
return {};
|
||||
}
|
||||
if (*custom_height_ < UI_UNIT_Y) {
|
||||
return 1;
|
||||
}
|
||||
return round_fl_to_int(float(*custom_height_) / padded_item_height());
|
||||
}
|
||||
|
||||
bool AbstractTreeView::supports_scrolling() const
|
||||
{
|
||||
return custom_height_ && scroll_value_;
|
||||
}
|
||||
|
||||
void AbstractTreeView::scroll(ViewScrollDirection direction)
|
||||
{
|
||||
if (!supports_scrolling()) {
|
||||
return;
|
||||
}
|
||||
/* Scroll value will be sanitized/clamped when drawing. */
|
||||
*scroll_value_ += ((direction == ViewScrollDirection::UP) ? -1 : 1);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
TreeViewItemDropTarget::TreeViewItemDropTarget(AbstractTreeViewItem &view_item,
|
||||
@@ -696,7 +613,7 @@ class TreeViewLayoutBuilder {
|
||||
friend TreeViewBuilder;
|
||||
|
||||
public:
|
||||
void build_from_tree(AbstractTreeView &tree_view);
|
||||
void build_from_tree(const AbstractTreeView &tree_view);
|
||||
void build_row(AbstractTreeViewItem &item) const;
|
||||
|
||||
uiBlock &block() const;
|
||||
@@ -711,99 +628,18 @@ TreeViewLayoutBuilder::TreeViewLayoutBuilder(uiLayout &layout) : block_(*uiLayou
|
||||
{
|
||||
}
|
||||
|
||||
static int count_visible_items(AbstractTreeView &tree_view)
|
||||
{
|
||||
int item_count = 0;
|
||||
tree_view.foreach_item([&](AbstractTreeViewItem &) { item_count++; },
|
||||
AbstractTreeView::IterOptions::SkipCollapsed |
|
||||
AbstractTreeView::IterOptions::SkipFiltered);
|
||||
return item_count;
|
||||
}
|
||||
|
||||
void TreeViewLayoutBuilder::build_from_tree(AbstractTreeView &tree_view)
|
||||
void TreeViewLayoutBuilder::build_from_tree(const AbstractTreeView &tree_view)
|
||||
{
|
||||
uiLayout &parent_layout = current_layout();
|
||||
uiBlock *block = uiLayoutGetBlock(&parent_layout);
|
||||
|
||||
uiLayout *col = nullptr;
|
||||
if (true) {
|
||||
uiLayout *box = uiLayoutBox(&parent_layout);
|
||||
col = uiLayoutColumn(box, true);
|
||||
}
|
||||
else {
|
||||
col = uiLayoutColumn(&parent_layout, true);
|
||||
}
|
||||
/* Row for the tree-view and the scroll bar. */
|
||||
uiLayout *row = uiLayoutRow(col, false);
|
||||
uiLayout *box = uiLayoutBox(&parent_layout);
|
||||
uiLayoutColumn(box, true);
|
||||
|
||||
const std::optional<int> visible_row_count = tree_view.tot_visible_row_count();
|
||||
const int tot_items = count_visible_items(tree_view);
|
||||
tree_view.foreach_item([this](AbstractTreeViewItem &item) { build_row(item); },
|
||||
AbstractTreeView::IterOptions::SkipCollapsed |
|
||||
AbstractTreeView::IterOptions::SkipFiltered);
|
||||
|
||||
/* Column for the tree view. */
|
||||
uiLayoutColumn(row, true);
|
||||
|
||||
/* Clamp scroll-value to valid range. */
|
||||
if (tree_view.scroll_value_ && visible_row_count) {
|
||||
*tree_view.scroll_value_ = std::clamp(
|
||||
*tree_view.scroll_value_, 0, tot_items - *visible_row_count);
|
||||
}
|
||||
|
||||
const int first_visible_index = tree_view.scroll_value_ ? *tree_view.scroll_value_ : 0;
|
||||
const int max_visible_index = visible_row_count ? first_visible_index + *visible_row_count - 1 :
|
||||
std::numeric_limits<int>::max();
|
||||
int index = 0;
|
||||
tree_view.foreach_item(
|
||||
[&, this](AbstractTreeViewItem &item) {
|
||||
if ((index >= first_visible_index) && (index <= max_visible_index)) {
|
||||
this->build_row(item);
|
||||
}
|
||||
index++;
|
||||
},
|
||||
AbstractTreeView::IterOptions::SkipCollapsed | AbstractTreeView::IterOptions::SkipFiltered);
|
||||
|
||||
if (tree_view.custom_height_) {
|
||||
uiLayoutColumn(row, false);
|
||||
|
||||
*tree_view.custom_height_ = visible_row_count.value_or(1) * padded_item_height();
|
||||
if (!tree_view.scroll_value_) {
|
||||
tree_view.scroll_value_ = std::make_unique<int>(0);
|
||||
}
|
||||
|
||||
if (visible_row_count && (tot_items > *visible_row_count)) {
|
||||
uiDefButI(block,
|
||||
UI_BTYPE_SCROLL,
|
||||
0,
|
||||
"",
|
||||
0,
|
||||
0,
|
||||
V2D_SCROLL_WIDTH,
|
||||
*tree_view.custom_height_,
|
||||
tree_view.scroll_value_.get(),
|
||||
0,
|
||||
tot_items - *visible_row_count,
|
||||
*visible_row_count,
|
||||
0.0,
|
||||
"");
|
||||
}
|
||||
|
||||
UI_block_layout_set_current(block, col);
|
||||
uiDefIconButI(block,
|
||||
UI_BTYPE_GRIP,
|
||||
0,
|
||||
ICON_GRIP,
|
||||
0,
|
||||
0,
|
||||
UI_UNIT_X * 10,
|
||||
UI_UNIT_Y * 0.5f,
|
||||
tree_view.custom_height_.get(),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
"");
|
||||
}
|
||||
|
||||
UI_block_layout_set_current(block, &parent_layout);
|
||||
UI_block_layout_set_current(&block(), &parent_layout);
|
||||
}
|
||||
|
||||
void TreeViewLayoutBuilder::build_row(AbstractTreeViewItem &item) const
|
||||
@@ -859,21 +695,16 @@ uiLayout &TreeViewLayoutBuilder::current_layout() const
|
||||
|
||||
void TreeViewBuilder::ensure_min_rows_items(AbstractTreeView &tree_view)
|
||||
{
|
||||
const std::optional<int> visible_rows = tree_view.tot_visible_row_count();
|
||||
if (!visible_rows) {
|
||||
return;
|
||||
}
|
||||
|
||||
int tot_visible_items = 0;
|
||||
tree_view.foreach_item(
|
||||
[&tot_visible_items](AbstractTreeViewItem & /*item*/) { tot_visible_items++; },
|
||||
AbstractTreeView::IterOptions::SkipCollapsed | AbstractTreeView::IterOptions::SkipFiltered);
|
||||
|
||||
if (tot_visible_items >= *visible_rows) {
|
||||
if (tot_visible_items >= tree_view.min_rows_) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < (*visible_rows - tot_visible_items); i++) {
|
||||
for (int i = 0; i < (tree_view.min_rows_ - tot_visible_items); i++) {
|
||||
BasicTreeViewItem &new_item = tree_view.add_tree_item<BasicTreeViewItem>("");
|
||||
new_item.disable_interaction();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user