forked from bartvdbraak/blender
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.
This commit is contained in:
parent
6acf8642e5
commit
e1178266e7
@ -613,6 +613,11 @@ class TOPBAR_MT_workspace_menu(Menu):
|
||||
if len(bpy.data.workspaces) > 1:
|
||||
layout.operator("workspace.delete", text="Delete")
|
||||
|
||||
layout.separator()
|
||||
|
||||
layout.operator("workspace.reorder_to_front", text="Reorder to Front")
|
||||
layout.operator("workspace.reorder_to_back", text="Reorder to Back")
|
||||
|
||||
|
||||
class TOPBAR_PT_active_tool(Panel):
|
||||
bl_space_type = 'PROPERTIES'
|
||||
|
@ -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")
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user