From e1178266e713ae7184fc60c3ecb93d42d8b28a53 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Thu, 23 Aug 2018 16:13:52 +0200 Subject: Workspace: support reordering of workspaces from RMB menu. Drag and drop will follow later, it's a bit complicated to make this work reliable in the current UI code. --- source/blender/blenkernel/BKE_library.h | 3 + source/blender/blenkernel/intern/library.c | 95 ++++++++++++++++++++++ .../blenloader/intern/versioning_defaults.c | 42 ++++++++-- .../editors/interface/interface_templates.c | 9 +- source/blender/editors/screen/workspace_edit.c | 56 ++++++++++++- source/blender/makesdna/DNA_workspace_types.h | 5 +- 6 files changed, 199 insertions(+), 11 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index 50447e02fe5..050e9368a43 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -214,6 +214,9 @@ void BKE_id_tag_clear_atomic(struct ID *id, int tag); bool BKE_id_is_in_gobal_main(struct ID *id); +void BKE_id_ordered_list(struct ListBase *ordered_lb, const struct ListBase *lb); +void BKE_id_reorder(const struct ListBase *lb, struct ID *id, struct ID *relative, bool after); + /* use when "" is given to new_id() */ #define ID_FALLBACK_NAME N_("Untitled") diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 04ebaaf80b7..84aa75abc72 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -2596,3 +2596,98 @@ bool BKE_id_is_in_gobal_main(ID *id) /* We do not want to fail when id is NULL here, even though this is a bit strange behavior... */ return (id == NULL || BLI_findindex(which_libbase(G_MAIN, GS(id->name)), id) != -1); } + +/************************* Datablock order in UI **************************/ + +static int *id_order_get(ID *id) +{ + /* Only for workspace tabs currently. */ + switch (GS(id->name)) { + case ID_WS: + return &((WorkSpace *)id)->order; + default: + return NULL; + } +} + +static int id_order_compare(const void *a, const void *b) +{ + ID *id_a = ((LinkData *)a)->data; + ID *id_b = ((LinkData *)b)->data; + + int *order_a = id_order_get(id_a); + int *order_b = id_order_get(id_b); + + if (order_a && order_b) { + if (*order_a < *order_b) { + return -1; + } + else if (*order_a > *order_b) { + return 1; + } + } + + return strcmp(id_a->name, id_b->name); +} + +/** + * Returns ordered list of datablocks for display in the UI. + * Result is list of LinkData of IDs that must be freed. + */ +void BKE_id_ordered_list(ListBase *ordered_lb, const ListBase *lb) +{ + BLI_listbase_clear(ordered_lb); + + for (ID *id = lb->first; id; id = id->next) { + BLI_addtail(ordered_lb, BLI_genericNodeN(id)); + } + + BLI_listbase_sort(ordered_lb, id_order_compare); + + int num = 0; + for (LinkData *link = ordered_lb->first; link; link = link->next) { + int *order = id_order_get(link->data); + if (order) { + *order = num++; + } + } +} + +/** + * Reorder ID in the list, before or after the "relative" ID. + */ +void BKE_id_reorder(const ListBase *lb, ID *id, ID *relative, bool after) +{ + int *id_order = id_order_get(id); + int relative_order; + + if (relative) { + relative_order = *id_order_get(relative); + } + else { + relative_order = (after) ? BLI_listbase_count(lb) : 0; + } + + if (after) { + /* Insert after. */ + for (ID *other = lb->first; other; other = other->next) { + int *order = id_order_get(other); + if (*order > relative_order) { + (*order)++; + } + } + + *id_order = relative_order + 1; + } + else { + /* Insert before. */ + for (ID *other = lb->first; other; other = other->next) { + int *order = id_order_get(other); + if (*order < relative_order) { + (*order)--; + } + } + + *id_order = relative_order - 1; + } +} diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c index 1fd82d01cf5..abbc8f4c4a4 100644 --- a/source/blender/blenloader/intern/versioning_defaults.c +++ b/source/blender/blenloader/intern/versioning_defaults.c @@ -79,20 +79,46 @@ void BLO_update_defaults_startup_blend(Main *bmain) for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) { const char *name = workspace->id.name + 2; - if (STREQ(name, "2D Animation")) { - workspace->object_mode = OB_MODE_GPENCIL_PAINT; - } - if (STREQ(name, "3D Animation")) { - workspace->object_mode = OB_MODE_POSE; - } - else if (STREQ(name, "Texture Paint")) { - workspace->object_mode = OB_MODE_TEXTURE_PAINT; + if (STREQ(name, "Modeling")) { + workspace->order = 0; } else if (STREQ(name, "Sculpting")) { workspace->object_mode = OB_MODE_SCULPT; + workspace->order = 1; } else if (STREQ(name, "UV Editing")) { workspace->object_mode = OB_MODE_EDIT; + workspace->order = 2; + } + else if (STREQ(name, "Texture Paint")) { + workspace->object_mode = OB_MODE_TEXTURE_PAINT; + workspace->order = 3; + } + else if (STREQ(name, "Shading")) { + workspace->order = 4; + } + else if (STREQ(name, "3D Animation")) { + workspace->object_mode = OB_MODE_POSE; + workspace->order = 5; + } + else if (STREQ(name, "Rendering")) { + workspace->order = 6; + } + else if (STREQ(name, "Compositing")) { + workspace->order = 7; + } + else if (STREQ(name, "2D Animation")) { + workspace->object_mode = OB_MODE_GPENCIL_PAINT; + workspace->order = 8; + } + else if (STREQ(name, "Video Editing")) { + workspace->order = 9; + } + else if (STREQ(name, "Motion Tracking")) { + workspace->order = 10; + } + else if (STREQ(name, "Scripting")) { + workspace->order = 11; } } diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index a72d1df019a..f39f26e0d00 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -850,7 +850,11 @@ static void template_ID_tabs( uiBlock *block = uiLayoutGetBlock(layout); uiStyle *style = UI_style_get_dpi(); - for (ID *id = template->idlb->first; id; id = id->next) { + ListBase ordered; + BKE_id_ordered_list(&ordered, template->idlb); + + for (LinkData *link = ordered.first; link; link = link->next) { + ID *id = link->data; const int name_width = UI_fontstyle_string_width(&style->widgetlabel, id->name + 2); const int but_width = name_width + UI_UNIT_X; @@ -860,11 +864,14 @@ static void template_ID_tabs( sizeof(id->name) - 2, 0.0f, 0.0f, ""); UI_but_funcN_set(&tab->but, template_ID_set_property_cb, MEM_dupallocN(template), id); tab->but.custom_data = (void *)id; + tab->but.dragpoin = id; tab->menu = mt; UI_but_drawflag_enable(&tab->but, but_align); } + BLI_freelistN(&ordered); + if (flag & UI_ID_ADD_NEW) { const bool editable = RNA_property_editable(&template->ptr, template->prop); uiBut *but; diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c index 77fc20a98a5..db60bfc9fb6 100644 --- a/source/blender/editors/screen/workspace_edit.c +++ b/source/blender/editors/screen/workspace_edit.c @@ -272,6 +272,11 @@ static WorkSpace *workspace_context_get(bContext *C) return WM_window_get_active_workspace(win); } +static bool workspace_context_poll(bContext *C) +{ + return workspace_context_get(C) != NULL; +} + static int workspace_new_exec(bContext *C, wmOperator *UNUSED(op)) { Main *bmain = CTX_data_main(C); @@ -293,8 +298,8 @@ static void WORKSPACE_OT_duplicate(wmOperatorType *ot) ot->idname = "WORKSPACE_OT_duplicate"; /* api callbacks */ + ot->poll = workspace_context_poll; ot->exec = workspace_new_exec; - ot->poll = WM_operator_winactive; } static int workspace_delete_exec(bContext *C, wmOperator *UNUSED(op)) @@ -313,6 +318,7 @@ static void WORKSPACE_OT_delete(wmOperatorType *ot) ot->idname = "WORKSPACE_OT_delete"; /* api callbacks */ + ot->poll = workspace_context_poll; ot->exec = workspace_delete_exec; } @@ -519,12 +525,60 @@ static void WORKSPACE_OT_add_menu(wmOperatorType *ot) ot->invoke = workspace_add_invoke; } +static int workspace_reorder_to_back_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Main *bmain = CTX_data_main(C); + WorkSpace *workspace = workspace_context_get(C); + + BKE_id_reorder(&bmain->workspaces, &workspace->id, NULL, true); + WM_event_add_notifier(C, NC_WINDOW, NULL); + + return OPERATOR_INTERFACE; +} + +static void WORKSPACE_OT_reorder_to_back(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Workspace Reorder to Back"; + ot->description = "Reorder workspace to be first in the list"; + ot->idname = "WORKSPACE_OT_reorder_to_back"; + + /* api callbacks */ + ot->poll = workspace_context_poll; + ot->exec = workspace_reorder_to_back_exec; +} + +static int workspace_reorder_to_front_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Main *bmain = CTX_data_main(C); + WorkSpace *workspace = workspace_context_get(C); + + BKE_id_reorder(&bmain->workspaces, &workspace->id, NULL, false); + WM_event_add_notifier(C, NC_WINDOW, NULL); + + return OPERATOR_INTERFACE; +} + +static void WORKSPACE_OT_reorder_to_front(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Workspace Reorder to Front"; + ot->description = "Reorder workspace to be first in the list"; + ot->idname = "WORKSPACE_OT_reorder_to_front"; + + /* api callbacks */ + ot->poll = workspace_context_poll; + ot->exec = workspace_reorder_to_front_exec; +} + void ED_operatortypes_workspace(void) { WM_operatortype_append(WORKSPACE_OT_duplicate); WM_operatortype_append(WORKSPACE_OT_delete); WM_operatortype_append(WORKSPACE_OT_add_menu); WM_operatortype_append(WORKSPACE_OT_append_activate); + WM_operatortype_append(WORKSPACE_OT_reorder_to_back); + WM_operatortype_append(WORKSPACE_OT_reorder_to_front); } /** \} Workspace Operators */ diff --git a/source/blender/makesdna/DNA_workspace_types.h b/source/blender/makesdna/DNA_workspace_types.h index fd56c246c96..ad047a85c18 100644 --- a/source/blender/makesdna/DNA_workspace_types.h +++ b/source/blender/makesdna/DNA_workspace_types.h @@ -144,12 +144,15 @@ typedef struct WorkSpace { char tools_space_type; /** Type is different for each space-type. */ char tools_mode; - char _pad[6]; + char _pad[2]; int object_mode; int flags DNA_PRIVATE_WORKSPACE; /* enum eWorkSpaceFlags */ + /* Number for workspace tab reordering in the UI. */ + int order; + /* Info text from modal operators (runtime). */ char *status_text; } WorkSpace; -- cgit v1.2.3