Files
test2/source/blender/editors/interface/templates/interface_templates.cc
Campbell Barton 3933f45f52 Cleanup: move doc-strings to declarations
Move into headers or to the top of the function body for internal
implementation details, in some cases remove duplicate doc-strings.
2025-04-18 22:58:36 +10:00

313 lines
10 KiB
C++

/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup edinterface
*/
#include "BKE_library.hh"
#include "BKE_screen.hh"
#include "BLI_string_ref.hh"
#include "ED_fileselect.hh"
#include "ED_screen.hh"
#include "RNA_access.hh"
#include "UI_interface.hh"
#include "interface_intern.hh"
#include "interface_templates_intern.hh"
using blender::StringRefNull;
/* -------------------------------------------------------------------- */
/** \name Search Menu Helpers
* \{ */
int template_search_textbut_width(PointerRNA *ptr, PropertyRNA *name_prop)
{
char str[UI_MAX_DRAW_STR];
int buf_len = 0;
BLI_assert(RNA_property_type(name_prop) == PROP_STRING);
const char *name = RNA_property_string_get_alloc(ptr, name_prop, str, sizeof(str), &buf_len);
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
const int margin = UI_UNIT_X * 0.75f;
const int estimated_width = UI_fontstyle_string_width(fstyle, name) + margin;
if (name != str) {
MEM_freeN((void *)name);
}
/* Clamp to some min/max width. */
return std::clamp(
estimated_width, TEMPLATE_SEARCH_TEXTBUT_MIN_WIDTH, TEMPLATE_SEARCH_TEXTBUT_MIN_WIDTH * 4);
}
int template_search_textbut_height()
{
return TEMPLATE_SEARCH_TEXTBUT_HEIGHT;
}
void template_add_button_search_menu(const bContext *C,
uiLayout *layout,
uiBlock *block,
PointerRNA *ptr,
PropertyRNA *prop,
uiBlockCreateFunc block_func,
void *block_argN,
const std::optional<blender::StringRef> tip,
const bool use_previews,
const bool editable,
const bool live_icon,
uiButArgNFree func_argN_free_fn,
uiButArgNCopy func_argN_copy_fn)
{
const PointerRNA active_ptr = RNA_property_pointer_get(ptr, prop);
ID *id = (active_ptr.data && RNA_struct_is_ID(active_ptr.type)) ?
static_cast<ID *>(active_ptr.data) :
nullptr;
const ID *idfrom = ptr->owner_id;
const StructRNA *type = active_ptr.type ? active_ptr.type : RNA_property_pointer_type(ptr, prop);
uiBut *but;
if (use_previews) {
ARegion *region = CTX_wm_region(C);
/* Ugly tool header exception. */
const bool use_big_size = (region->regiontype != RGN_TYPE_TOOL_HEADER);
/* Ugly exception for screens here,
* drawing their preview in icon size looks ugly/useless */
const bool use_preview_icon = use_big_size || (id && (GS(id->name) != ID_SCR));
const short width = UI_UNIT_X * (use_big_size ? 6 : 1.6f);
const short height = UI_UNIT_Y * (use_big_size ? 6 : 1);
uiLayout *col = nullptr;
if (use_big_size) {
/* Assume column layout here. To be more correct, we should check if the layout passed to
* template_id is a column one, but this should work well in practice. */
col = uiLayoutColumn(layout, true);
}
but = uiDefBlockButN(block,
block_func,
block_argN,
"",
0,
0,
width,
height,
tip,
func_argN_free_fn,
func_argN_copy_fn);
if (use_preview_icon) {
const int icon = id ? ui_id_icon_get(C, id, use_big_size) : RNA_struct_ui_icon(type);
ui_def_but_icon(but, icon, UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
}
else {
ui_def_but_icon(but, RNA_struct_ui_icon(type), UI_HAS_ICON);
UI_but_drawflag_enable(but, UI_BUT_ICON_LEFT);
}
if ((idfrom && !ID_IS_EDITABLE(idfrom)) || !editable) {
UI_but_flag_enable(but, UI_BUT_DISABLED);
}
if (use_big_size) {
uiLayoutRow(col ? col : layout, true);
}
}
else {
but = uiDefBlockButN(block,
block_func,
block_argN,
"",
0,
0,
UI_UNIT_X * 1.6,
UI_UNIT_Y,
tip,
func_argN_free_fn,
func_argN_copy_fn);
if (live_icon) {
const int icon = id ? ui_id_icon_get(C, id, false) : RNA_struct_ui_icon(type);
ui_def_but_icon(but, icon, UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
}
else {
ui_def_but_icon(but, RNA_struct_ui_icon(type), UI_HAS_ICON);
}
if (id) {
/* default dragging of icon for id browse buttons */
UI_but_drag_set_id(but, id);
}
UI_but_drawflag_enable(but, UI_BUT_ICON_LEFT);
if ((idfrom && !ID_IS_EDITABLE(idfrom)) || !editable) {
UI_but_flag_enable(but, UI_BUT_DISABLED);
}
}
}
uiBlock *template_common_search_menu(const bContext *C,
ARegion *region,
uiButSearchUpdateFn search_update_fn,
void *search_arg,
uiButHandleFunc search_exec_fn,
void *active_item,
uiButSearchTooltipFn item_tooltip_fn,
const int preview_rows,
const int preview_cols,
float scale)
{
static char search[256];
wmWindow *win = CTX_wm_window(C);
uiBut *but;
/* clear initial search string, then all items show */
search[0] = 0;
uiBlock *block = UI_block_begin(C, region, "_popup", blender::ui::EmbossType::Emboss);
UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_SEARCH_MENU);
UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
/* preview thumbnails */
if (preview_rows > 0 && preview_cols > 0) {
const int w = 4 * U.widget_unit * preview_cols * scale;
const int h = 5 * U.widget_unit * preview_rows * scale;
/* fake button, it holds space for search items */
uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 26, w, h, nullptr, 0, 0, std::nullopt);
but = uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 0, w, UI_UNIT_Y, "");
UI_but_search_preview_grid_size_set(but, preview_rows, preview_cols);
}
/* list view */
else {
const int searchbox_width = int(float(UI_searchbox_size_x()) * 1.4f);
const int searchbox_height = UI_searchbox_size_y();
/* fake button, it holds space for search items */
uiDefBut(block,
UI_BTYPE_LABEL,
0,
"",
10,
15,
searchbox_width,
searchbox_height,
nullptr,
0,
0,
std::nullopt);
but = uiDefSearchBut(block,
search,
0,
ICON_VIEWZOOM,
sizeof(search),
10,
0,
searchbox_width,
UI_UNIT_Y - 1,
"");
}
UI_but_func_search_set(but,
ui_searchbox_create_generic,
search_update_fn,
search_arg,
false,
nullptr,
search_exec_fn,
active_item);
UI_but_func_search_set_tooltip(but, item_tooltip_fn);
UI_block_bounds_set_normal(block, 0.3f * U.widget_unit);
UI_block_direction_set(block, UI_DIR_DOWN);
/* give search-field focus */
UI_but_focus_on_enter_event(win, but);
/* this type of search menu requires undo */
but->flag |= UI_BUT_UNDO;
return block;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Header Template
* \{ */
void uiTemplateHeader(uiLayout *layout, bContext *C)
{
uiBlock *block = uiLayoutAbsoluteBlock(layout);
ED_area_header_switchbutton(C, block, 0);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name RNA Path Builder Template
* \{ */
void uiTemplatePathBuilder(uiLayout *layout,
PointerRNA *ptr,
const StringRefNull propname,
PointerRNA * /*root_ptr*/,
const std::optional<StringRefNull> text)
{
/* check that properties are valid */
PropertyRNA *propPath = RNA_struct_find_property(ptr, propname.c_str());
if (!propPath || RNA_property_type(propPath) != PROP_STRING) {
RNA_warning(
"path property not found: %s.%s", RNA_struct_identifier(ptr->type), propname.c_str());
return;
}
/* Start drawing UI Elements using standard defines */
uiLayout *row = uiLayoutRow(layout, true);
/* Path (existing string) Widget */
uiItemR(row, ptr, propname, UI_ITEM_NONE, text, ICON_RNA);
/* TODO: attach something to this to make allow
* searching of nested properties to 'build' the path */
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Node Socket Icon Template
* \{ */
void uiTemplateNodeSocket(uiLayout *layout, bContext * /*C*/, const float color[4])
{
uiBlock *block = uiLayoutGetBlock(layout);
UI_block_align_begin(block);
/* XXX using explicit socket colors is not quite ideal.
* Eventually it should be possible to use theme colors for this purpose,
* but this requires a better design for extendable color palettes in user preferences. */
uiBut *but = uiDefBut(
block, UI_BTYPE_NODE_SOCKET, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, nullptr, 0, 0, "");
rgba_float_to_uchar(but->col, color);
UI_block_align_end(block);
}
/* -------------------------------------------------------------------- */
/** \name FileSelectParams Path Button Template
* \{ */
void uiTemplateFileSelectPath(uiLayout *layout, bContext *C, FileSelectParams *params)
{
bScreen *screen = CTX_wm_screen(C);
SpaceFile *sfile = CTX_wm_space_file(C);
ED_file_path_button(screen, sfile, params, uiLayoutGetBlock(layout));
}
/** \} */