New Window Operator (to replace Duplicate Window)

A user doesn't want to necessarily create a new Screen only because she
wants a new window.

This patch allows the user to pick the screen to use for the new Window.
If the screen picked is the active one, it duplicates it (as the old
behaviour in Blender).

Patch with contributions and fixes by Julian Eisel (Severin)

Subscribers: venomgfx

Differential Revision: https://developer.blender.org/D2555
This commit is contained in:
Dalai Felinto 2017-03-13 10:43:49 +01:00
parent 4dacda58f9
commit 7bc76f8a3c
Notes: blender-bot 2023-02-13 12:01:56 +01:00
Referenced by commit 8892c7869e, Fix "search for unknown operator 'WM_OT_window_duplicate'" warning
8 changed files with 156 additions and 31 deletions

View File

@ -7,7 +7,7 @@ kc = wm.keyconfigs.new('3dsmax')
# Map Window
km = kc.keymaps.new('Window', space_type='EMPTY', region_type='WINDOW', modal=False)
kmi = km.keymap_items.new('wm.window_duplicate', 'W', 'PRESS', ctrl=True, alt=True)
kmi = km.keymap_items.new('wm.window_new', 'W', 'PRESS', ctrl=True, alt=True)
kmi = km.keymap_items.new('wm.read_homefile', 'N', 'PRESS', ctrl=True)
kmi = km.keymap_items.new('wm.save_homefile', 'U', 'PRESS', ctrl=True)
kmi = km.keymap_items.new('wm.call_menu', 'O', 'PRESS', shift=True, ctrl=True)

View File

@ -8,7 +8,7 @@ kc = wm.keyconfigs.new(os.path.splitext(os.path.basename(__file__))[0])
# Map Window
km = kc.keymaps.new('Window', space_type='EMPTY', region_type='WINDOW', modal=False)
kmi = km.keymap_items.new('wm.window_duplicate', 'W', 'PRESS', ctrl=True, alt=True)
kmi = km.keymap_items.new('wm.window_new', 'W', 'PRESS', ctrl=True, alt=True)
kmi = km.keymap_items.new('wm.read_homefile', 'N', 'PRESS', ctrl=True)
kmi = km.keymap_items.new('wm.save_homefile', 'U', 'PRESS', ctrl=True)
kmi = km.keymap_items.new('wm.call_menu', 'O', 'PRESS', shift=True, ctrl=True)

View File

@ -281,7 +281,7 @@ class INFO_MT_window(Menu):
layout = self.layout
layout.operator("wm.window_duplicate")
layout.operator("wm.window_new")
layout.operator("wm.window_fullscreen_toggle", icon='FULLSCREEN_ENTER')
layout.separator()

View File

@ -4399,7 +4399,7 @@ static void operator_enum_search_cb(const struct bContext *C, void *but, const c
for (item = item_array; item->identifier; item++) {
/* note: need to give the index rather than the identifier because the enum can be freed */
if (BLI_strcasestr(item->name, str)) {
if (false == UI_search_item_add(items, item->name, SET_INT_IN_POINTER(item->value), 0))
if (false == UI_search_item_add(items, item->name, SET_INT_IN_POINTER(item->value), item->icon))
break;
}
}

View File

@ -238,6 +238,7 @@ void WM_operator_view3d_unit_defaults(struct bContext *C, struct wmOperator *op
int WM_operator_smooth_viewtx_get(const struct wmOperator *op);
int WM_menu_invoke_ex(struct bContext *C, struct wmOperator *op, int opcontext);
int WM_menu_invoke (struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
int WM_enum_search_invoke_previews(struct bContext *C, struct wmOperator *op, short prv_cols, short prv_rows);
int WM_enum_search_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
/* invoke callback, confirm menu + exec */
int WM_operator_confirm (struct bContext *C, struct wmOperator *op, const struct wmEvent *event);

View File

@ -1107,46 +1107,70 @@ int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
return WM_menu_invoke_ex(C, op, WM_OP_INVOKE_REGION_WIN);
}
struct EnumSearchMenu {
wmOperator *op; /* the operator that will be executed when selecting an item */
bool use_previews;
short prv_cols, prv_rows;
};
/* generic enum search invoke popup */
static uiBlock *wm_enum_search_menu(bContext *C, ARegion *ar, void *arg_op)
static uiBlock *wm_enum_search_menu(bContext *C, ARegion *ar, void *arg)
{
static char search[256] = "";
wmEvent event;
struct EnumSearchMenu *search_menu = arg;
wmWindow *win = CTX_wm_window(C);
wmOperator *op = search_menu->op;
/* template_ID uses 4 * widget_unit for width, we use a bit more, some items may have a suffix to show */
const int width = search_menu->use_previews ? 5 * U.widget_unit * search_menu->prv_cols : UI_searchbox_size_x();
const int height = search_menu->use_previews ? 5 * U.widget_unit * search_menu->prv_rows : UI_searchbox_size_y();
static char search[256] = "";
uiBlock *block;
uiBut *but;
wmOperator *op = (wmOperator *)arg_op;
block = UI_block_begin(C, ar, "_popup", UI_EMBOSS);
UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_SEARCH_MENU);
search[0] = '\0';
BLI_assert(search_menu->use_previews || (search_menu->prv_cols == 0 && search_menu->prv_rows == 0));
#if 0 /* ok, this isn't so easy... */
uiDefBut(block, UI_BTYPE_LABEL, 0, RNA_struct_ui_name(op->type->srna), 10, 10, UI_searchbox_size_x(), UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
#endif
but = uiDefSearchButO_ptr(block, op->type, op->ptr->data, search, 0, ICON_VIEWZOOM, sizeof(search),
10, 10, UI_searchbox_size_x(), UI_UNIT_Y, 0, 0, "");
10, 10, width, UI_UNIT_Y, search_menu->prv_rows, search_menu->prv_cols, "");
/* fake button, it holds space for search items */
uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 10 - UI_searchbox_size_y(), UI_searchbox_size_x(), UI_searchbox_size_y(), NULL, 0, 0, 0, 0, NULL);
uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 10 - UI_searchbox_size_y(), width, height, NULL, 0, 0, 0, 0, NULL);
UI_block_bounds_set_popup(block, 6, 0, -UI_UNIT_Y); /* move it downwards, mouse over button */
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);
UI_but_focus_on_enter_event(win, but);
return block;
}
/**
* Similar to #WM_enum_search_invoke, but draws previews. Also, this can't
* be used as invoke callback directly since it needs additional info.
*/
int WM_enum_search_invoke_previews(
bContext *C, wmOperator *op, short prv_cols, short prv_rows)
{
static struct EnumSearchMenu search_menu;
search_menu.op = op;
search_menu.use_previews = true;
search_menu.prv_cols = prv_cols;
search_menu.prv_rows = prv_rows;
UI_popup_block_invoke(C, wm_enum_search_menu, &search_menu);
return OPERATOR_INTERFACE;
}
int WM_enum_search_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
UI_popup_block_invoke(C, wm_enum_search_menu, op);
static struct EnumSearchMenu search_menu;
search_menu.op = op;
UI_popup_block_invoke(C, wm_enum_search_menu, &search_menu);
return OPERATOR_INTERFACE;
}
@ -2079,14 +2103,22 @@ static void WM_OT_window_close(wmOperatorType *ot)
ot->poll = WM_operator_winactive;
}
static void WM_OT_window_duplicate(wmOperatorType *ot)
static void WM_OT_window_new(wmOperatorType *ot)
{
ot->name = "Duplicate Window";
ot->idname = "WM_OT_window_duplicate";
ot->description = "Duplicate the current Blender window";
ot->exec = wm_window_duplicate_exec;
PropertyRNA *prop;
ot->name = "New Window";
ot->idname = "WM_OT_window_new";
ot->description = "Create a new Blender window";
ot->exec = wm_window_new_exec;
ot->invoke = wm_window_new_invoke;
ot->poll = wm_operator_winactive_normal;
prop = RNA_def_enum(ot->srna, "screen", DummyRNA_NULL_items, 0, "Screen", "");
RNA_def_enum_funcs(prop, wm_window_new_screen_itemf);
RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
ot->prop = prop;
}
static void WM_OT_window_fullscreen_toggle(wmOperatorType *ot)
@ -4177,7 +4209,7 @@ void wm_operatortype_init(void)
global_ops_hash = BLI_ghash_str_new_ex("wm_operatortype_init gh", 2048);
WM_operatortype_append(WM_OT_window_close);
WM_operatortype_append(WM_OT_window_duplicate);
WM_operatortype_append(WM_OT_window_new);
WM_operatortype_append(WM_OT_read_history);
WM_operatortype_append(WM_OT_read_homefile);
WM_operatortype_append(WM_OT_read_factory_settings);

View File

@ -58,6 +58,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
#include "WM_api.h"
#include "WM_types.h"
@ -71,6 +72,7 @@
#include "ED_fileselect.h"
#include "UI_interface.h"
#include "UI_interface_icons.h"
#include "PIL_time.h"
@ -79,6 +81,8 @@
#include "GPU_init_exit.h"
#include "GPU_immediate.h"
#include "UI_resources.h"
/* for assert */
#ifndef NDEBUG
# include "BLI_threads.h"
@ -244,6 +248,25 @@ wmWindow *wm_window_new(bContext *C)
return win;
}
/**
* A higher level version of copy that tests the new window can be added.
*/
static wmWindow *wm_window_new_test(bContext *C)
{
wmWindow *win = wm_window_new(C);
WM_check(C);
if (win->ghostwin) {
WM_event_add_notifier(C, NC_WINDOW | NA_ADDED, NULL);
return win;
}
else {
wmWindowManager *wm = CTX_wm_manager(C);
wm_window_close(C, wm, win);
return NULL;
}
}
/* part of wm_window.c api */
wmWindow *wm_window_copy(bContext *C, wmWindow *win_src)
@ -723,17 +746,79 @@ int wm_window_close_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
/* operator callback */
int wm_window_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
/* new window operator callback */
int wm_window_new_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
wmWindow *win_src = CTX_wm_window(C);
bool ok;
const int screen_id = RNA_enum_get(op->ptr, "screen");
bScreen *screen = BLI_findlink(&bmain->screen, screen_id);
wmWindow *win_dst;
ok = (wm_window_copy_test(C, win_src) != NULL);
if (screen->winid) {
/* Screen is already used, duplicate window and screen */
win_dst = wm_window_copy_test(C, win_src);
}
else if ((win_dst = wm_window_new_test(C))) {
/* New window with a different screen */
win_dst->screen = screen;
screen->winid = win_dst->winid;
CTX_wm_window_set(C, win_dst);
ED_screen_refresh(CTX_wm_manager(C), win_dst);
}
return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
return (win_dst != NULL) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
int wm_window_new_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Main *bmain = CTX_data_main(C);
if (BLI_listbase_count_ex(&bmain->screen, 2) == 1) {
RNA_enum_set(op->ptr, "screen", 0);
return wm_window_new_exec(C, op);
}
else {
return WM_enum_search_invoke_previews(C, op, 6, 2);
}
}
struct EnumPropertyItem *wm_window_new_screen_itemf(
bContext *C, struct PointerRNA *UNUSED(ptr), struct PropertyRNA *UNUSED(prop), bool *r_free)
{
Main *bmain = CTX_data_main(C);
EnumPropertyItem *item = NULL;
EnumPropertyItem tmp = {0, "", 0, "", ""};
int value = 0, totitem = 0;
int count_act_screens = 0;
/* XXX setting max number of windows to 20. We'd need support
* for dynamic strings in EnumPropertyItem.name to avoid this. */
static char active_screens[20][MAX_NAME + 12];
for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
if (screen->winid) {
BLI_snprintf(active_screens[count_act_screens], sizeof(*active_screens), "%s (Duplicate)",
screen->id.name + 2);
tmp.name = active_screens[count_act_screens++];
}
else {
tmp.name = screen->id.name + 2;
}
tmp.value = value;
tmp.identifier = screen->id.name;
UI_id_icon_render(C, CTX_data_scene(C), &screen->id, true, false);
tmp.icon = BKE_icon_id_ensure(&screen->id);
RNA_enum_item_add(&item, &totitem, &tmp);
value++;
}
RNA_enum_item_end(&item, &totitem);
*r_free = true;
return item;
}
/* fullscreen operator callback */
int wm_window_fullscreen_toggle_exec(bContext *C, wmOperator *UNUSED(op))

View File

@ -32,7 +32,11 @@
#ifndef __WM_WINDOW_H__
#define __WM_WINDOW_H__
struct EnumPropertyItem;
struct wmEvent;
struct wmOperator;
struct PointerRNA;
struct PropertyRNA;
/* *************** internal api ************** */
void wm_ghost_init (bContext *C);
@ -78,9 +82,12 @@ void wm_window_IME_end (wmWindow *win);
/* *************** window operators ************** */
int wm_window_close_exec(bContext *C, struct wmOperator *op);
int wm_window_duplicate_exec(bContext *C, struct wmOperator *op);
int wm_window_fullscreen_toggle_exec(bContext *C, struct wmOperator *op);
struct EnumPropertyItem *wm_window_new_screen_itemf(bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free);
int wm_window_new_exec(bContext *C, struct wmOperator *op);
int wm_window_new_invoke(bContext *C, struct wmOperator *op, const struct wmEvent *event);
/* Initial (unmaximized) size to start with for
* systems that can't find it for themselves (X11).
* Clamped by real desktop limits */