/* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** \file * \ingroup edinterface * * This part of the UI-View API is mostly needed to support persistent state of items within the * view. Views are stored in #uiBlock's, and kept alive with it until after the next redraw. So we * can compare the old view items with the new view items and keep state persistent for matching * ones. */ #include #include #include "DNA_screen_types.h" #include "BLI_listbase.h" #include "interface_intern.h" #include "UI_interface.hh" #include "UI_tree_view.hh" using namespace blender; using namespace blender::ui; /** * Wrapper to store views in a #ListBase. There's no `uiView` base class, we just store views as a * #std::variant. */ struct ViewLink : public Link { using TreeViewPtr = std::unique_ptr; std::string idname; /* Note: Can't use std::get() on this until minimum macOS deployment target is 10.14. */ std::variant view; }; template T *get_view_from_link(ViewLink &link) { auto *t_uptr = std::get_if>(&link.view); return t_uptr ? t_uptr->get() : nullptr; } /** * Override this for all available tree types. */ AbstractTreeView *UI_block_add_view(uiBlock &block, StringRef idname, std::unique_ptr tree_view) { ViewLink *view_link = OBJECT_GUARDED_NEW(ViewLink); BLI_addtail(&block.views, view_link); view_link->view = std::move(tree_view); view_link->idname = idname; return get_view_from_link(*view_link); } void ui_block_free_views(uiBlock *block) { LISTBASE_FOREACH_MUTABLE (ViewLink *, link, &block->views) { OBJECT_GUARDED_DELETE(link, ViewLink); } } /** * \param x, y: Coordinate to find a tree-row item at, in window space. */ uiTreeViewItemHandle *UI_block_tree_view_find_item_at(const ARegion *region, const int x, const int y) { uiButTreeRow *tree_row_but = (uiButTreeRow *)ui_tree_row_find_mouse_over(region, x, y); if (!tree_row_but) { return nullptr; } return tree_row_but->tree_item; } static StringRef ui_block_view_find_idname(const uiBlock &block, const AbstractTreeView &view) { /* First get the idname the of the view we're looking for. */ LISTBASE_FOREACH (ViewLink *, view_link, &block.views) { if (get_view_from_link(*view_link) == &view) { return view_link->idname; } } return {}; } uiTreeViewHandle *ui_block_view_find_matching_in_old_block(const uiBlock *new_block, const uiTreeViewHandle *new_view_handle) { const AbstractTreeView &needle_view = reinterpret_cast( *new_view_handle); uiBlock *old_block = new_block->oldblock; if (!old_block) { return nullptr; } StringRef idname = ui_block_view_find_idname(*new_block, needle_view); if (idname.is_empty()) { return nullptr; } LISTBASE_FOREACH (ViewLink *, old_view_link, &old_block->views) { if (old_view_link->idname == idname) { return reinterpret_cast( get_view_from_link(*old_view_link)); } } return nullptr; }