UI: Add user defined context menu

- Add/Remove from RMB context menu.
- Stored in user preferences.
- Access from Q key.

See T55027.
This commit is contained in:
Campbell Barton 2018-06-23 16:31:28 +02:00
parent 2fa231a86b
commit 85c1e61375
Notes: blender-bot 2023-02-14 08:42:53 +01:00
Referenced by issue #55027, 2.8 UI Tools: Favourites Bar / Specials Menu Design
15 changed files with 239 additions and 142 deletions

View File

@ -121,9 +121,6 @@ typedef struct SpaceType {
/* region type definitions */
ListBase regiontypes;
/* tool shelf definitions */
ListBase toolshelf;
/* read and write... */
/* default keymaps to add */

View File

@ -241,6 +241,15 @@ void BKE_blender_userdef_data_free(UserDef *userdef, bool clear_fonts)
BLI_freelistN(&userdef->uifonts);
BLI_freelistN(&userdef->themes);
for (bUserMenuItem *umi = userdef->user_menu_items.first, *umi_next; umi; umi = umi_next) {
umi_next = umi->next;
if (umi->prop) {
IDP_FreeProperty(umi->prop);
MEM_freeN(umi->prop);
}
MEM_freeN(umi);
}
#undef U
}

View File

@ -88,8 +88,6 @@ static void spacetype_free(SpaceType *st)
}
BLI_freelistN(&st->regiontypes);
BLI_freelistN(&st->toolshelf);
}
void BKE_spacetypes_free(void)

View File

@ -8713,6 +8713,12 @@ static BHead *read_userdef(BlendFileData *bfd, FileData *fd, BHead *bhead)
user->uifonts.first = user->uifonts.last= NULL;
link_list(fd, &user->uistyles);
link_list(fd, &user->user_menu_items);
for (bUserMenuItem *umi = user->user_menu_items.first; umi; umi = umi->next) {
umi->prop = newdataadr(fd, umi->prop);
IDP_DirectLinkGroup_OrFree(&umi->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
}
/* free fd->datamap again */
oldnewmap_free_unused(fd->datamap);

View File

@ -1258,6 +1258,13 @@ static void write_userdef(WriteData *wd, const UserDef *userdef)
for (const uiStyle *style = userdef->uistyles.first; style; style = style->next) {
writestruct(wd, DATA, uiStyle, 1, style);
}
for (const bUserMenuItem *umi = userdef->user_menu_items.first; umi; umi = umi->next) {
writestruct(wd, DATA, bUserMenuItem, 1, umi);
if (umi->prop) {
IDP_WriteProperty(umi->prop, wd);
}
}
}
static void write_boid_state(WriteData *wd, BoidState *state)

View File

@ -60,6 +60,8 @@ struct Main;
struct wmMsgBus;
struct wmMsgSubscribeKey;
struct wmMsgSubscribeValue;
struct wmOperatorType;
struct IDProperty;
/* regions */
void ED_region_do_listen(
@ -311,6 +313,16 @@ int ED_operator_posemode_local(struct bContext *C);
int ED_operator_mask(struct bContext *C);
int ED_operator_camera(struct bContext *C);
/* screen_user_menu.c */
void ED_screen_user_menu_add(
struct bContext *C, const char *ui_name,
struct wmOperatorType *ot, struct IDProperty *prop, short opcontext);
void ED_screen_user_menu_remove(struct bUserMenuItem *umi);
struct bUserMenuItem *ED_screen_user_menu_find(
struct bContext *C,
struct wmOperatorType *ot, struct IDProperty *prop, short opcontext);
void ED_screen_user_menu_register(void);
/* Cache display helpers */
@ -333,4 +345,3 @@ void ED_area_type_hud_ensure(struct bContext *C, struct ScrArea *sa);
#define ED_KEYMAP_HEADER 64
#endif /* __ED_SCREEN_H__ */

View File

@ -6649,6 +6649,30 @@ static void popup_add_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2))
UI_popup_block_ex(C, menu_add_shortcut, NULL, menu_add_shortcut_cancel, but, NULL);
}
static void popup_user_menu_add_or_replace_func(bContext *C, void *arg1, void *arg2)
{
uiBut *but = arg1;
bUserMenuItem *umi = arg2;
if (umi) {
ED_screen_user_menu_remove(umi);
}
char drawstr[sizeof(but->drawstr)];
STRNCPY(drawstr, but->drawstr);
if (but->flag & UI_BUT_HAS_SEP_CHAR) {
char *sep = strrchr(drawstr, UI_SEP_CHAR);
if (sep) {
*sep = '\0';
}
}
ED_screen_user_menu_add(C, drawstr, but->optype, but->opptr ? but->opptr->data : NULL, but->opcontext);
}
static void popup_user_menu_remove_func(bContext *UNUSED(C), void *UNUSED(arg1), void *arg2)
{
bUserMenuItem *umi = arg2;
ED_screen_user_menu_remove(umi);
}
/**
* menu to chow when right clicking on the panel header
*/
@ -7021,6 +7045,27 @@ static bool ui_but_menu(bContext *C, uiBut *but)
UI_but_func_set(but2, popup_add_shortcut_func, but, NULL);
}
uiItemS(layout);
{
bUserMenuItem *umi = ED_screen_user_menu_find(
C, but->optype, but->opptr ? but->opptr->data : NULL, but->opcontext);
but2 = uiDefIconTextBut(
block, UI_BTYPE_BUT, 0, ICON_MENU_PANEL,
CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add to Favourites Menu"),
0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0,
"Add to a user defined context menu (stored in the user preferences)");
UI_but_func_set(but2, popup_user_menu_add_or_replace_func, but, umi);
if (umi) {
but2 = uiDefIconTextBut(
block, UI_BTYPE_BUT, 0, ICON_CANCEL,
CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove from Favourites Menu"),
0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
UI_but_func_set(but2, popup_user_menu_remove_func, NULL, umi);
}
}
/* Set the operator pointer for python access */
uiLayoutSetContextFromBut(layout, but);

View File

@ -47,6 +47,7 @@ set(SRC
screen_draw.c
screen_edit.c
screen_ops.c
screen_user_menu.c
screendump.c
workspace_edit.c
workspace_layout_edit.c

View File

@ -0,0 +1,142 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* 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.
*
* The Original Code is Copyright (C) 2009 Blender Foundation.
* All rights reserved.
*
*
* Contributor(s): Blender Foundation
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/editors/screen/screen_user_menu.c
* \ingroup spview3d
*/
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <float.h>
#include "DNA_scene_types.h"
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_screen.h"
#include "BKE_idprop.h"
#include "WM_api.h"
#include "WM_types.h"
#include "ED_screen.h"
#include "UI_interface.h"
#include "UI_resources.h"
/* -------------------------------------------------------------------- */
/** \name Utilities
* \{ */
void ED_screen_user_menu_add(
bContext *C, const char *ui_name,
wmOperatorType *ot, IDProperty *prop, short opcontext)
{
SpaceLink *sl = CTX_wm_space_data(C);
bUserMenuItem *umi = MEM_callocN(sizeof(bUserMenuItem), __func__);
umi->space_type = sl ? sl->spacetype : SPACE_EMPTY;
umi->opcontext = opcontext;
if (!STREQ(ui_name, ot->name)) {
BLI_strncpy(umi->ui_name, ui_name, OP_MAX_TYPENAME);
}
BLI_strncpy(umi->opname, ot->idname, OP_MAX_TYPENAME);
BLI_strncpy(umi->context, CTX_data_mode_string(C), OP_MAX_TYPENAME);
umi->prop = prop ? IDP_CopyProperty(prop) : NULL;
BLI_addtail(&U.user_menu_items, umi);
}
void ED_screen_user_menu_remove(bUserMenuItem *umi)
{
BLI_remlink(&U.user_menu_items, umi);
if (umi->prop) {
IDP_FreeProperty(umi->prop);
MEM_freeN(umi->prop);
}
MEM_freeN(umi);
}
bUserMenuItem *ED_screen_user_menu_find(
bContext *C,
wmOperatorType *ot, IDProperty *prop, short opcontext)
{
SpaceLink *sl = CTX_wm_space_data(C);
const char *context = CTX_data_mode_string(C);
for (bUserMenuItem *umi = U.user_menu_items.first; umi; umi = umi->next) {
if (STREQ(ot->idname, umi->opname) &&
(opcontext == umi->opcontext) &&
(IDP_EqualsProperties(prop, umi->prop)))
{
if ((ELEM(umi->space_type, SPACE_TOPBAR) || (sl->spacetype == umi->space_type)) &&
(STREQLEN(context, umi->context, OP_MAX_TYPENAME)))
{
return umi;
}
}
}
return NULL;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Menu Definition
* \{ */
static void screen_user_menu_draw(const bContext *C, Menu *menu)
{
SpaceLink *sl = CTX_wm_space_data(C);
const char *context = CTX_data_mode_string(C);
for (bUserMenuItem *umi = U.user_menu_items.first; umi; umi = umi->next) {
if ((ELEM(umi->space_type, SPACE_TOPBAR) || (sl->spacetype == umi->space_type)) &&
(STREQLEN(context, umi->context, OP_MAX_TYPENAME)))
{
IDProperty *prop = umi->prop ? IDP_CopyProperty(umi->prop) : NULL;
uiItemFullO(
menu->layout, umi->opname, umi->ui_name[0] ? umi->ui_name : NULL,
ICON_NONE, prop, umi->opcontext, 0, NULL);
}
}
}
void ED_screen_user_menu_register(void)
{
MenuType *mt = MEM_callocN(sizeof(MenuType), __func__);
strcpy(mt->idname, "SCREEN_MT_user_menu");
strcpy(mt->label, "Quick Favourites");
strcpy(mt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
mt->draw = screen_user_menu_draw;
WM_menutype_add(mt);
}
/** \} */

View File

@ -127,6 +127,8 @@ void ED_spacetypes_init(void)
ED_operatortypes_view2d();
ED_operatortypes_ui();
ED_screen_user_menu_register();
/* manipulator types */
ED_manipulatortypes_button_2d();
ED_manipulatortypes_dial_3d();

View File

@ -1541,11 +1541,6 @@ void ED_spacetype_view3d(void)
art->draw = view3d_tools_region_draw;
BLI_addhead(&st->regiontypes, art);
#if 0
/* unfinished still */
view3d_toolshelf_register(art);
#endif
/* regions: header */
art = MEM_callocN(sizeof(ARegionType), "spacetype view3d header region");
art->regionid = RGN_TYPE_HEADER;

View File

@ -235,7 +235,6 @@ struct Object *ED_view3d_cameracontrol_object_get(
/* view3d_toolbar.c */
void VIEW3D_OT_toolshelf(struct wmOperatorType *ot);
void view3d_toolshelf_register(struct ARegionType *art);
/* view3d_snap.c */
bool ED_view3d_minmax_verts(struct Object *obedit, float min[3], float max[3]);

View File

@ -28,153 +28,24 @@
* \ingroup spview3d
*/
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <float.h>
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_screen.h"
#include "WM_api.h"
#include "WM_types.h"
#include "RNA_access.h"
#include "ED_screen.h"
#include "ED_undo.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "view3d_intern.h" /* own include */
/* ******************* */
typedef struct CustomTool {
struct CustomTool *next, *prev;
char opname[OP_MAX_TYPENAME];
char context[OP_MAX_TYPENAME];
} CustomTool;
static void operator_call_cb(struct bContext *C, void *arg_listbase, void *arg2)
{
wmOperatorType *ot = arg2;
if (ot) {
CustomTool *ct = MEM_callocN(sizeof(CustomTool), "CustomTool");
BLI_addtail(arg_listbase, ct);
BLI_strncpy(ct->opname, ot->idname, OP_MAX_TYPENAME);
BLI_strncpy(ct->context, CTX_data_mode_string(C), OP_MAX_TYPENAME);
}
}
static void operator_search_cb(const struct bContext *C, void *UNUSED(arg), const char *str, uiSearchItems *items)
{
GHashIterator iter;
for (WM_operatortype_iter(&iter); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) {
wmOperatorType *ot = BLI_ghashIterator_getValue(&iter);
if (BLI_strcasestr(ot->name, str)) {
if (WM_operator_poll((bContext *)C, ot)) {
if (false == UI_search_item_add(items, ot->name, ot, 0))
break;
}
}
}
}
/* ID Search browse menu, open */
static uiBlock *tool_search_menu(bContext *C, ARegion *ar, void *arg_listbase)
{
static char search[OP_MAX_TYPENAME];
wmEvent event;
wmWindow *win = CTX_wm_window(C);
uiBlock *block;
uiBut *but;
/* clear initial search string, then all items show */
search[0] = 0;
block = UI_block_begin(C, ar, "_popup", UI_EMBOSS);
UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_SEARCH_MENU);
/* fake button, it holds space for search items */
uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 15, UI_searchbox_size_x(), UI_searchbox_size_y(), NULL, 0, 0, 0, 0, NULL);
but = uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 0, 150, 19, 0, 0, "");
UI_but_func_search_set(but, NULL, operator_search_cb, arg_listbase, operator_call_cb, NULL);
UI_block_bounds_set_normal(block, 6);
UI_block_direction_set(block, UI_DIR_DOWN);
UI_block_end(C, block);
wm_event_init_from_window(win, &event);
event.type = EVT_BUT_OPEN;
event.val = KM_PRESS;
event.customdata = but;
event.customdatafree = false;
wm_event_add(win, &event);
return block;
}
static void view3d_panel_tool_shelf(const bContext *C, Panel *pa)
{
SpaceLink *sl = CTX_wm_space_data(C);
SpaceType *st = NULL;
uiLayout *col;
const char *context = CTX_data_mode_string(C);
if (sl)
st = BKE_spacetype_from_id(sl->spacetype);
if (st && st->toolshelf.first) {
CustomTool *ct;
for (ct = st->toolshelf.first; ct; ct = ct->next) {
if (STREQLEN(context, ct->context, OP_MAX_TYPENAME)) {
col = uiLayoutColumn(pa->layout, true);
uiItemFullO(col, ct->opname, NULL, ICON_NONE, NULL, WM_OP_INVOKE_REGION_WIN, 0, NULL);
}
}
}
col = uiLayoutColumn(pa->layout, true);
uiDefBlockBut(uiLayoutGetBlock(pa->layout), tool_search_menu, &st->toolshelf, "Add Tool", 0, 0, UI_UNIT_X, UI_UNIT_Y, "Add Tool in shelf, gets saved in files");
}
void view3d_toolshelf_register(ARegionType *art)
{
PanelType *pt;
pt = MEM_callocN(sizeof(PanelType), "spacetype view3d panel tools");
strcpy(pt->idname, "VIEW3D_PT_tool_shelf");
strcpy(pt->label, N_("Tool Shelf"));
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = view3d_panel_tool_shelf;
BLI_addtail(&art->paneltypes, pt);
}
/* ********** operator to open/close toolshelf region */
static int view3d_toolshelf_toggle_exec(bContext *C, wmOperator *UNUSED(op))
@ -200,4 +71,3 @@ void VIEW3D_OT_toolshelf(wmOperatorType *ot)
/* flags */
ot->flag = 0;
}

View File

@ -430,6 +430,17 @@ typedef struct bPathCompare {
char flag, pad[7];
} bPathCompare;
typedef struct bUserMenuItem {
struct bUserMenuItem *next, *prev;
char space_type;
char opcontext;
char _pad0[6];
char ui_name[64];
char opname[64];
char context[64];
struct IDProperty *prop;
} bUserMenuItem;
typedef struct SolidLight {
int flag, pad;
float col[4], spec[4], vec[4];
@ -511,6 +522,8 @@ typedef struct UserDef {
struct ListBase user_keymaps;
struct ListBase addons;
struct ListBase autoexec_paths;
struct ListBase user_menu_items; /* bUserMenuItem */
char keyconfigstr[64];
short undosteps;

View File

@ -3992,6 +3992,8 @@ void wm_window_keymap(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "WM_OT_search_menu", F3KEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "WM_OT_search_menu", ACCENTGRAVEKEY, KM_CLICK, 0, 0);
WM_keymap_add_menu(keymap, "SCREEN_MT_user_menu", QKEY, KM_PRESS, 0, 0);
#ifdef WITH_INPUT_NDOF
WM_keymap_add_menu(keymap, "USERPREF_MT_ndof_settings", NDOF_BUTTON_MENU, KM_PRESS, 0, 0);
#endif