Depsgraph: remove EvaluationContext, pass Depsgraph instead.
[blender.git] / source / blender / editors / object / object_modes.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor(s): Blender Foundation, 2002-2008 full recode
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file blender/editors/object/object_modes.c
24  *  \ingroup edobj
25  *
26  * General utils to handle mode switching,
27  * actual mode switching logic is per-object type.
28  */
29
30 #include "DNA_object_types.h"
31 #include "DNA_scene_types.h"
32 #include "DNA_workspace_types.h"
33
34 #include "BLI_utildefines.h"
35
36 #include "BKE_context.h"
37 #include "BKE_object.h"
38 #include "BKE_paint.h"
39 #include "BKE_report.h"
40
41 #include "WM_api.h"
42 #include "WM_types.h"
43
44 #include "RNA_access.h"
45
46 #include "DEG_depsgraph.h"
47
48 #include "ED_screen.h"
49
50 #include "ED_object.h"  /* own include */
51
52 /* -------------------------------------------------------------------- */
53 /** \name High Level Mode Operations
54  *
55  * \{ */
56
57 static const char *object_mode_op_string(eObjectMode mode)
58 {
59         if (mode & OB_MODE_EDIT)
60                 return "OBJECT_OT_editmode_toggle";
61         if (mode == OB_MODE_SCULPT)
62                 return "SCULPT_OT_sculptmode_toggle";
63         if (mode == OB_MODE_VERTEX_PAINT)
64                 return "PAINT_OT_vertex_paint_toggle";
65         if (mode == OB_MODE_WEIGHT_PAINT)
66                 return "PAINT_OT_weight_paint_toggle";
67         if (mode == OB_MODE_TEXTURE_PAINT)
68                 return "PAINT_OT_texture_paint_toggle";
69         if (mode == OB_MODE_PARTICLE_EDIT)
70                 return "PARTICLE_OT_particle_edit_toggle";
71         if (mode == OB_MODE_POSE)
72                 return "OBJECT_OT_posemode_toggle";
73         if (mode == OB_MODE_GPENCIL)
74                 return "GPENCIL_OT_editmode_toggle";
75         return NULL;
76 }
77
78 /**
79  * Checks the mode to be set is compatible with the object
80  * should be made into a generic function
81  */
82 bool ED_object_mode_compat_test(const Object *ob, eObjectMode mode)
83 {
84         if (ob) {
85                 if (mode == OB_MODE_OBJECT)
86                         return true;
87                 else if (mode == OB_MODE_GPENCIL)
88                         return true; /* XXX: assume this is the case for now... */
89
90                 switch (ob->type) {
91                         case OB_MESH:
92                                 if (mode & (OB_MODE_EDIT | OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT |
93                                             OB_MODE_TEXTURE_PAINT | OB_MODE_PARTICLE_EDIT))
94                                 {
95                                         return true;
96                                 }
97                                 break;
98                         case OB_CURVE:
99                         case OB_SURF:
100                         case OB_FONT:
101                         case OB_MBALL:
102                                 if (mode & (OB_MODE_EDIT))
103                                         return true;
104                                 break;
105                         case OB_LATTICE:
106                                 if (mode & (OB_MODE_EDIT | OB_MODE_WEIGHT_PAINT))
107                                         return true;
108                                 break;
109                         case OB_ARMATURE:
110                                 if (mode & (OB_MODE_EDIT | OB_MODE_POSE))
111                                         return true;
112                                 break;
113                 }
114         }
115
116         return false;
117 }
118
119 /**
120  * Sets the mode to a compatible state (use before entering the mode).
121  *
122  * This is so each mode's exec function can call
123  */
124 bool ED_object_mode_compat_set(bContext *C, Object *ob, eObjectMode mode, ReportList *reports)
125 {
126         bool ok;
127         if (!ELEM(ob->mode, mode, OB_MODE_OBJECT)) {
128                 const char *opstring = object_mode_op_string(ob->mode);
129
130                 WM_operator_name_call(C, opstring, WM_OP_EXEC_REGION_WIN, NULL);
131                 ok = ELEM(ob->mode, mode, OB_MODE_OBJECT);
132                 if (!ok) {
133                         wmOperatorType *ot = WM_operatortype_find(opstring, false);
134                         BKE_reportf(reports, RPT_ERROR, "Unable to execute '%s', error changing modes", ot->name);
135                 }
136         }
137         else {
138                 ok = true;
139         }
140
141         return ok;
142 }
143
144 void ED_object_mode_toggle(bContext *C, eObjectMode mode)
145 {
146         if (mode != OB_MODE_OBJECT) {
147                 const char *opstring = object_mode_op_string(mode);
148
149                 if (opstring) {
150                         WM_operator_name_call(C, opstring, WM_OP_EXEC_REGION_WIN, NULL);
151                 }
152         }
153 }
154
155
156 /* Wrapper for operator  */
157 void ED_object_mode_set(bContext *C, eObjectMode mode)
158 {
159         wmWindowManager *wm = CTX_wm_manager(C);
160         wm->op_undo_depth++;
161         /* needed so we don't do undo pushes. */
162         ED_object_mode_generic_enter(C, mode);
163         wm->op_undo_depth--;
164 }
165
166 /** \} */
167
168 /* -------------------------------------------------------------------- */
169 /** \name Generic Mode Enter/Exit
170  *
171  * Supports exiting a mode without it being in the current context.
172  * This could be done for entering modes too if it's needed.
173  *
174  * \{ */
175
176 bool ED_object_mode_generic_enter(
177         struct bContext *C, eObjectMode object_mode)
178 {
179         Object *ob = CTX_data_active_object(C);
180         if (ob == NULL) {
181                 return (object_mode == OB_MODE_OBJECT);
182         }
183         if (ob->mode == object_mode) {
184                 return true;
185         }
186         wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_mode_set", false);
187         PointerRNA ptr;
188         WM_operator_properties_create_ptr(&ptr, ot);
189         RNA_enum_set(&ptr, "mode", object_mode);
190         WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr);
191         WM_operator_properties_free(&ptr);
192         return (ob->mode == object_mode);
193 }
194
195 /**
196  * Use for changing works-paces or changing active object.
197  * Caller can check #OB_MODE_ALL_MODE_DATA to test if this needs to be run.
198  */
199 static bool ed_object_mode_generic_exit_ex(
200         struct Depsgraph *depsgraph,
201         struct Scene *scene, struct Object *ob,
202         bool only_test)
203 {
204         if (ob->mode & OB_MODE_EDIT) {
205                 if (BKE_object_is_in_editmode(ob)) {
206                         if (only_test) {
207                                 return true;
208                         }
209                         ED_object_editmode_exit_ex(NULL, scene, ob, EM_FREEDATA);
210                 }
211         }
212         else if (ob->mode & OB_MODE_VERTEX_PAINT) {
213                 if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_VERTEX_PAINT)) {
214                         if (only_test) {
215                                 return true;
216                         }
217                         ED_object_vpaintmode_exit_ex(ob);
218                 }
219         }
220         else if (ob->mode & OB_MODE_WEIGHT_PAINT) {
221                 if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_WEIGHT_PAINT)) {
222                         if (only_test) {
223                                 return true;
224                         }
225                         ED_object_wpaintmode_exit_ex(ob);
226                 }
227         }
228         else if (ob->mode & OB_MODE_SCULPT) {
229                 if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_SCULPT)) {
230                         if (only_test) {
231                                 return true;
232                         }
233                         ED_object_sculptmode_exit_ex(depsgraph, scene, ob);
234                 }
235         }
236         else {
237                 if (only_test) {
238                         return false;
239                 }
240                 BLI_assert((ob->mode & OB_MODE_ALL_MODE_DATA) == 0);
241         }
242
243         return false;
244 }
245
246 void ED_object_mode_generic_exit(
247         struct Depsgraph *depsgraph,
248         struct Scene *scene, struct Object *ob)
249 {
250         ed_object_mode_generic_exit_ex(depsgraph, scene, ob, false);
251 }
252
253 bool ED_object_mode_generic_has_data(
254         struct Depsgraph *depsgraph,
255         struct Object *ob)
256 {
257         return ed_object_mode_generic_exit_ex(depsgraph, NULL, ob, true);
258 }
259
260 /** \} */