UI: Move rename buffer management to new view base class
Renaming is a nice example of a feature that shouldn't need a specific implementation for a specific view type (e.g. grid or tree view). So it's something that can be supported in the general view code. Individual views can use it "for free" then. This ports the view level part of the renaming code, the view item level part of it can be ported once we have a common base class for the view items.
This commit is contained in:
parent
c355be6fae
commit
e86c2f7288
Notes:
blender-bot
2023-02-13 15:02:53 +01:00
Referenced by issue #102684, Grease Pencil: Crash when trying to sculpt on object with Dot Dash modifier Referenced by issue #99313, Crash when importing a file using python from the command line with an asset browser open
|
@ -6,17 +6,31 @@
|
|||
* Base for all views (UIs to display data sets), supporting common features.
|
||||
* https://wiki.blender.org/wiki/Source/Interface/Views
|
||||
*
|
||||
* The base class manages reconstruction, most importantly keeping state over reconstructions.
|
||||
* One of the most important responsibilities of the base class is managing reconstruction,
|
||||
* enabling state that is persistent over reconstructions/redraws.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
|
||||
#include "BLI_span.hh"
|
||||
|
||||
struct wmNotifier;
|
||||
|
||||
namespace blender::ui {
|
||||
|
||||
class AbstractView {
|
||||
bool is_reconstructed_ = false;
|
||||
/**
|
||||
* Only one item can be renamed at a time. So rather than giving each item an own rename buffer
|
||||
* (which just adds unused memory in most cases), have one here that is managed by the view.
|
||||
*
|
||||
* This fixed-size buffer is needed because that's what the rename button requires. In future we
|
||||
* may be able to bind the button to a `std::string` or similar.
|
||||
*/
|
||||
std::unique_ptr<std::array<char, MAX_NAME>> rename_buffer_;
|
||||
|
||||
public:
|
||||
virtual ~AbstractView() = default;
|
||||
|
@ -24,6 +38,14 @@ class AbstractView {
|
|||
/** Listen to a notifier, returning true if a redraw is needed. */
|
||||
virtual bool listen(const wmNotifier &) const;
|
||||
|
||||
/** Only one item can be renamed at a time. */
|
||||
bool is_renaming() const;
|
||||
/** \return If renaming was started successfully. */
|
||||
bool begin_renaming();
|
||||
void end_renaming();
|
||||
Span<char> get_rename_buffer() const;
|
||||
MutableSpan<char> get_rename_buffer();
|
||||
|
||||
protected:
|
||||
AbstractView() = default;
|
||||
|
||||
|
|
|
@ -117,20 +117,11 @@ class AbstractTreeView : public AbstractView, public TreeViewItemContainer {
|
|||
friend class AbstractTreeViewItem;
|
||||
friend class TreeViewBuilder;
|
||||
|
||||
/**
|
||||
* Only one item can be renamed at a time. So the tree is informed about the renaming state to
|
||||
* enforce that.
|
||||
*/
|
||||
std::unique_ptr<std::array<char, MAX_NAME>> rename_buffer_;
|
||||
|
||||
public:
|
||||
virtual ~AbstractTreeView() = default;
|
||||
|
||||
void foreach_item(ItemIterFn iter_fn, IterOptions options = IterOptions::None) const;
|
||||
|
||||
/** Only one item can be renamed at a time. */
|
||||
bool is_renaming() const;
|
||||
|
||||
protected:
|
||||
virtual void build_tree() = 0;
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ void AbstractView::update_from_old(uiBlock &new_block)
|
|||
return;
|
||||
}
|
||||
|
||||
const uiViewHandle *old_view_handle = ui_block_view_find_matching_in_old_block(
|
||||
uiViewHandle *old_view_handle = ui_block_view_find_matching_in_old_block(
|
||||
&new_block, reinterpret_cast<uiViewHandle *>(this));
|
||||
if (old_view_handle == nullptr) {
|
||||
/* Initial construction, nothing to update. */
|
||||
|
@ -35,7 +35,15 @@ void AbstractView::update_from_old(uiBlock &new_block)
|
|||
return;
|
||||
}
|
||||
|
||||
update_children_from_old(reinterpret_cast<const AbstractView &>(*old_view_handle));
|
||||
AbstractView &old_view = reinterpret_cast<AbstractView &>(*old_view_handle);
|
||||
|
||||
/* Update own persistent data. */
|
||||
/* Keep the rename buffer persistent while renaming! The rename button uses the buffer's
|
||||
* pointer to identify itself over redraws. */
|
||||
rename_buffer_ = std::move(old_view.rename_buffer_);
|
||||
old_view.rename_buffer_ = nullptr;
|
||||
|
||||
update_children_from_old(old_view);
|
||||
|
||||
/* Finished (re-)constructing the tree. */
|
||||
is_reconstructed_ = true;
|
||||
|
@ -43,10 +51,52 @@ void AbstractView::update_from_old(uiBlock &new_block)
|
|||
|
||||
/** \} */
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/** \name Default implementations of virtual functions
|
||||
* \{ */
|
||||
|
||||
bool AbstractView::listen(const wmNotifier & /*notifier*/) const
|
||||
{
|
||||
/* Nothing by default. */
|
||||
return false;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/** \name Renaming
|
||||
* \{ */
|
||||
|
||||
bool AbstractView::is_renaming() const
|
||||
{
|
||||
return rename_buffer_ != nullptr;
|
||||
}
|
||||
|
||||
bool AbstractView::begin_renaming()
|
||||
{
|
||||
if (is_renaming()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
rename_buffer_ = std::make_unique<decltype(rename_buffer_)::element_type>();
|
||||
return true;
|
||||
}
|
||||
|
||||
void AbstractView::end_renaming()
|
||||
{
|
||||
BLI_assert(is_renaming());
|
||||
rename_buffer_ = nullptr;
|
||||
}
|
||||
|
||||
Span<char> AbstractView::get_rename_buffer() const
|
||||
{
|
||||
return *rename_buffer_;
|
||||
}
|
||||
MutableSpan<char> AbstractView::get_rename_buffer()
|
||||
{
|
||||
return *rename_buffer_;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
} // namespace blender::ui
|
||||
|
|
|
@ -68,23 +68,9 @@ void AbstractTreeView::foreach_item(ItemIterFn iter_fn, IterOptions options) con
|
|||
foreach_item_recursive(iter_fn, options);
|
||||
}
|
||||
|
||||
bool AbstractTreeView::is_renaming() const
|
||||
{
|
||||
return rename_buffer_ != nullptr;
|
||||
}
|
||||
|
||||
void AbstractTreeView::update_children_from_old(const AbstractView &old_view)
|
||||
{
|
||||
/* TODO: Get rid of const cast. */
|
||||
AbstractTreeView &old_tree_view = const_cast<AbstractTreeView &>(
|
||||
dynamic_cast<const AbstractTreeView &>(old_view));
|
||||
|
||||
/* TODO: Move to AbstractView. */
|
||||
/* Update own persistent data. */
|
||||
/* Keep the rename buffer persistent while renaming! The rename button uses the buffer's
|
||||
* pointer to identify itself over redraws. */
|
||||
rename_buffer_ = std::move(old_tree_view.rename_buffer_);
|
||||
old_tree_view.rename_buffer_ = nullptr;
|
||||
const AbstractTreeView &old_tree_view = dynamic_cast<const AbstractTreeView &>(old_view);
|
||||
|
||||
update_children_from_old_recursive(*this, old_tree_view);
|
||||
}
|
||||
|
@ -233,7 +219,7 @@ AbstractTreeViewItem *AbstractTreeViewItem::find_tree_item_from_rename_button(
|
|||
AbstractTreeViewItem *item = reinterpret_cast<AbstractTreeViewItem *>(tree_row_but->tree_item);
|
||||
const AbstractTreeView &tree_view = item->get_tree_view();
|
||||
|
||||
if (item->is_renaming() && (tree_view.rename_buffer_->data() == rename_but.poin)) {
|
||||
if (item->is_renaming() && (tree_view.get_rename_buffer().data() == rename_but.poin)) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
@ -248,7 +234,7 @@ void AbstractTreeViewItem::rename_button_fn(bContext *UNUSED(C), void *arg, char
|
|||
BLI_assert(item);
|
||||
|
||||
const AbstractTreeView &tree_view = item->get_tree_view();
|
||||
item->rename(tree_view.rename_buffer_->data());
|
||||
item->rename(tree_view.get_rename_buffer().data());
|
||||
item->end_renaming();
|
||||
}
|
||||
|
||||
|
@ -270,9 +256,9 @@ void AbstractTreeViewItem::add_rename_button(uiLayout &row)
|
|||
0,
|
||||
UI_UNIT_X * 10,
|
||||
UI_UNIT_Y,
|
||||
tree_view.rename_buffer_->data(),
|
||||
tree_view.get_rename_buffer().data(),
|
||||
1.0f,
|
||||
tree_view.rename_buffer_->max_size(),
|
||||
tree_view.get_rename_buffer().size(),
|
||||
0,
|
||||
0,
|
||||
"");
|
||||
|
@ -372,10 +358,11 @@ void AbstractTreeViewItem::begin_renaming()
|
|||
return;
|
||||
}
|
||||
|
||||
is_renaming_ = true;
|
||||
if (tree_view.begin_renaming()) {
|
||||
is_renaming_ = true;
|
||||
}
|
||||
|
||||
tree_view.rename_buffer_ = std::make_unique<decltype(tree_view.rename_buffer_)::element_type>();
|
||||
std::copy(std::begin(label_), std::end(label_), std::begin(*tree_view.rename_buffer_));
|
||||
std::copy(std::begin(label_), std::end(label_), std::begin(tree_view.get_rename_buffer()));
|
||||
}
|
||||
|
||||
void AbstractTreeViewItem::end_renaming()
|
||||
|
@ -387,7 +374,7 @@ void AbstractTreeViewItem::end_renaming()
|
|||
is_renaming_ = false;
|
||||
|
||||
AbstractTreeView &tree_view = get_tree_view();
|
||||
tree_view.rename_buffer_ = nullptr;
|
||||
tree_view.end_renaming();
|
||||
}
|
||||
|
||||
AbstractTreeView &AbstractTreeViewItem::get_tree_view() const
|
||||
|
|
Loading…
Reference in New Issue