Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacques Lucke <mail@jlucke.com>2019-05-14 15:13:02 +0300
committerJacques Lucke <mail@jlucke.com>2019-05-14 15:21:17 +0300
commit687385b963f4389b3d714fed264bb0ff24bc43f5 (patch)
treeb45b5c6492361425533230e4267e848d7c383715 /source/blender/windowmanager
parent37f87ae81bc31134cf985277d877afb7b922dbbc (diff)
UI: Confirm dialog when closing an unsaved file
The complexity in this patch comes from the fact that the current operator system does not support multi-step user interactions well. More specifically, for this to work, we need to show a confirm dialog and a file browser afterwards. We decided that it is easier to keep everything in a single operator, instead of creating separate operators that invoke each other. So, now the `WM_OT_open_mainfile` operator invokes itself in different states. It implements a simple finite state machine to manage the states. The dialog itself is expected to be improved in a future commit. See D4829 for more details. Reviewers: brecht Differential Revision: https://developer.blender.org/D4829
Diffstat (limited to 'source/blender/windowmanager')
-rw-r--r--source/blender/windowmanager/WM_api.h3
-rw-r--r--source/blender/windowmanager/intern/wm_files.c113
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c14
3 files changed, 119 insertions, 11 deletions
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index f1037dadf85..780add8eb88 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -373,7 +373,8 @@ int WM_operator_confirm_message_ex(struct bContext *C,
struct wmOperator *op,
const char *title,
const int icon,
- const char *message);
+ const char *message,
+ const short opcontext);
int WM_operator_confirm_message(struct bContext *C, struct wmOperator *op, const char *message);
/* operator api */
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index cf02709f051..20266be0eac 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -2017,13 +2017,83 @@ static bool wm_file_read_opwrap(bContext *C,
return success;
}
-/* currently fits in a pointer */
-struct FileRuntime {
- bool is_untrusted;
+/* Generic operator state utilities
+ *********************************************/
+
+static void create_operator_state(wmOperatorType *ot, int first_state)
+{
+ PropertyRNA *prop = RNA_def_int(
+ ot->srna, "state", first_state, INT32_MIN, INT32_MAX, "State", "", INT32_MIN, INT32_MAX);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+}
+
+static int get_operator_state(wmOperator *op)
+{
+ return RNA_int_get(op->ptr, "state");
+}
+
+static void set_next_operator_state(wmOperator *op, int state)
+{
+ RNA_int_set(op->ptr, "state", state);
+}
+
+typedef struct OperatorDispatchTarget {
+ int state;
+ int (*run)(bContext *C, wmOperator *op);
+} OperatorDispatchTarget;
+
+static int operator_state_dispatch(bContext *C, wmOperator *op, OperatorDispatchTarget *targets)
+{
+ int state = get_operator_state(op);
+ for (int i = 0; targets[i].run; i++) {
+ OperatorDispatchTarget target = targets[i];
+ if (target.state == state) {
+ return target.run(C, op);
+ }
+ }
+ BLI_assert(false);
+ return OPERATOR_CANCELLED;
+}
+
+/* Open Mainfile operator
+ ********************************************/
+
+enum {
+ OPEN_MAINFILE_STATE_DISCARD_CHANGES,
+ OPEN_MAINFILE_STATE_SELECT_FILE_PATH,
+ OPEN_MAINFILE_STATE_OPEN,
};
-static int wm_open_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+static int wm_open_mainfile_dispatch(bContext *C, wmOperator *op);
+
+static int wm_open_mainfile__discard_changes(bContext *C, wmOperator *op)
{
+ if (RNA_boolean_get(op->ptr, "display_file_selector")) {
+ set_next_operator_state(op, OPEN_MAINFILE_STATE_SELECT_FILE_PATH);
+ }
+ else {
+ set_next_operator_state(op, OPEN_MAINFILE_STATE_OPEN);
+ }
+
+ wmWindowManager *wm = CTX_wm_manager(C);
+ if (U.uiflag & USER_SAVE_PROMPT && !wm->file_saved) {
+ return WM_operator_confirm_message_ex(C,
+ op,
+ "Warning",
+ ICON_INFO,
+ "Changes in current file will be lost. Continue?",
+ WM_OP_INVOKE_DEFAULT);
+ }
+ else {
+ return wm_open_mainfile_dispatch(C, op);
+ }
+}
+
+static int wm_open_mainfile__select_file_path(bContext *C, wmOperator *op)
+{
+ set_next_operator_state(op, OPEN_MAINFILE_STATE_OPEN);
+
Main *bmain = CTX_data_main(C);
const char *openname = BKE_main_blendfile_path(bmain);
@@ -2051,7 +2121,7 @@ static int wm_open_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *U
return OPERATOR_RUNNING_MODAL;
}
-static int wm_open_mainfile_exec(bContext *C, wmOperator *op)
+static int wm_open_mainfile__open(bContext *C, wmOperator *op)
{
char filepath[FILE_MAX];
bool success;
@@ -2089,6 +2159,33 @@ static int wm_open_mainfile_exec(bContext *C, wmOperator *op)
}
}
+static OperatorDispatchTarget wm_open_mainfile_dispatch_targets[] = {
+ {OPEN_MAINFILE_STATE_DISCARD_CHANGES, wm_open_mainfile__discard_changes},
+ {OPEN_MAINFILE_STATE_SELECT_FILE_PATH, wm_open_mainfile__select_file_path},
+ {OPEN_MAINFILE_STATE_OPEN, wm_open_mainfile__open},
+ {0, NULL},
+};
+
+static int wm_open_mainfile_dispatch(bContext *C, wmOperator *op)
+{
+ return operator_state_dispatch(C, op, wm_open_mainfile_dispatch_targets);
+}
+
+static int wm_open_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ return wm_open_mainfile_dispatch(C, op);
+}
+
+static int wm_open_mainfile_exec(bContext *C, wmOperator *op)
+{
+ return wm_open_mainfile__open(C, op);
+}
+
+/* currently fits in a pointer */
+struct FileRuntime {
+ bool is_untrusted;
+};
+
static bool wm_open_mainfile_check(bContext *UNUSED(C), wmOperator *op)
{
struct FileRuntime *file_info = (struct FileRuntime *)&op->customdata;
@@ -2169,6 +2266,12 @@ void WM_OT_open_mainfile(wmOperatorType *ot)
"Trusted Source",
"Allow .blend file to execute scripts automatically, default available from "
"system preferences");
+
+ PropertyRNA *prop = RNA_def_boolean(
+ ot->srna, "display_file_selector", true, "Display File Selector", "");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ create_operator_state(ot, OPEN_MAINFILE_STATE_DISCARD_CHANGES);
}
/** \} */
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 98b79fc75ce..6817a9c8719 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -884,8 +884,12 @@ int WM_enum_search_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(eve
}
/* Can't be used as an invoke directly, needs message arg (can be NULL) */
-int WM_operator_confirm_message_ex(
- bContext *C, wmOperator *op, const char *title, const int icon, const char *message)
+int WM_operator_confirm_message_ex(bContext *C,
+ wmOperator *op,
+ const char *title,
+ const int icon,
+ const char *message,
+ const short opcontext)
{
uiPopupMenu *pup;
uiLayout *layout;
@@ -900,8 +904,7 @@ int WM_operator_confirm_message_ex(
pup = UI_popup_menu_begin(C, title, icon);
layout = UI_popup_menu_layout(pup);
- uiItemFullO_ptr(
- layout, op->type, message, ICON_NONE, properties, WM_OP_EXEC_REGION_WIN, 0, NULL);
+ uiItemFullO_ptr(layout, op->type, message, ICON_NONE, properties, opcontext, 0, NULL);
UI_popup_menu_end(C, pup);
return OPERATOR_INTERFACE;
@@ -909,7 +912,8 @@ int WM_operator_confirm_message_ex(
int WM_operator_confirm_message(bContext *C, wmOperator *op, const char *message)
{
- return WM_operator_confirm_message_ex(C, op, IFACE_("OK?"), ICON_QUESTION, message);
+ return WM_operator_confirm_message_ex(
+ C, op, IFACE_("OK?"), ICON_QUESTION, message, WM_OP_EXEC_REGION_WIN);
}
int WM_operator_confirm(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))