code cleanup: use const events for modal and invoke operators.
[blender.git] / source / blender / editors / space_buttons / buttons_ops.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  * The Original Code is Copyright (C) 2009 Blender Foundation.
19  * All rights reserved.
20  *
21  * Contributor(s): Blender Foundation
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/editors/space_buttons/buttons_ops.c
27  *  \ingroup spbuttons
28  */
29
30
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include "MEM_guardedalloc.h"
35
36 #include "DNA_userdef_types.h"
37
38 #include "BLI_utildefines.h"
39 #include "BLI_fileops.h"
40 #include "BLI_path_util.h"
41 #include "BLI_string.h"
42
43 #include "BLF_translation.h"
44
45 #include "BKE_context.h"
46 #include "BKE_global.h"
47 #include "BKE_main.h"
48 #include "BKE_report.h"
49
50 #include "WM_api.h"
51 #include "WM_types.h"
52
53 #include "ED_screen.h"
54 #include "ED_util.h"
55
56 #include "RNA_access.h"
57
58 #include "UI_interface.h"
59 #include "UI_resources.h"
60
61 #include "buttons_intern.h"  /* own include */
62
63 /********************** toolbox operator *********************/
64
65 static int toolbox_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
66 {
67         bScreen *sc = CTX_wm_screen(C);
68         SpaceButs *sbuts = CTX_wm_space_buts(C);
69         PointerRNA ptr;
70         uiPopupMenu *pup;
71         uiLayout *layout;
72
73         RNA_pointer_create(&sc->id, &RNA_SpaceProperties, sbuts, &ptr);
74
75         pup = uiPupMenuBegin(C, IFACE_("Align"), ICON_NONE);
76         layout = uiPupMenuLayout(pup);
77         uiItemsEnumR(layout, &ptr, "align");
78         uiPupMenuEnd(C, pup);
79
80         return OPERATOR_CANCELLED;
81 }
82
83 void BUTTONS_OT_toolbox(wmOperatorType *ot)
84 {
85         /* identifiers */
86         ot->name = "Toolbox";
87         ot->description = "Display button panel toolbox";
88         ot->idname = "BUTTONS_OT_toolbox";
89         
90         /* api callbacks */
91         ot->invoke = toolbox_invoke;
92         ot->poll = ED_operator_buttons_active;
93 }
94
95 /********************** filebrowse operator *********************/
96
97 typedef struct FileBrowseOp {
98         PointerRNA ptr;
99         PropertyRNA *prop;
100 } FileBrowseOp;
101
102 static int file_browse_exec(bContext *C, wmOperator *op)
103 {
104         FileBrowseOp *fbo = op->customdata;
105         ID *id;
106         char *str, path[FILE_MAX];
107         const char *path_prop = RNA_struct_find_property(op->ptr, "directory") ? "directory" : "filepath";
108         
109         if (RNA_struct_property_is_set(op->ptr, path_prop) == 0 || fbo == NULL)
110                 return OPERATOR_CANCELLED;
111         
112         str = RNA_string_get_alloc(op->ptr, path_prop, NULL, 0);
113
114         /* add slash for directories, important for some properties */
115         if (RNA_property_subtype(fbo->prop) == PROP_DIRPATH) {
116                 int is_relative = RNA_boolean_get(op->ptr, "relative_path");
117                 id = fbo->ptr.id.data;
118
119                 BLI_strncpy(path, str, FILE_MAX);
120                 BLI_path_abs(path, id ? ID_BLEND_PATH(G.main, id) : G.main->name);
121                 
122                 if (BLI_is_dir(path)) {
123                         if (is_relative) {
124                                 BLI_strncpy(path, str, FILE_MAX);
125                                 BLI_path_rel(path, G.main->name);
126                                 str = MEM_reallocN(str, strlen(path) + 2);
127                                 BLI_strncpy(str, path, FILE_MAX);
128                         }
129                         else {
130                                 str = MEM_reallocN(str, strlen(str) + 2);
131                         }
132                         BLI_add_slash(str);
133                 }
134                 else {
135                         char * const lslash = (char *)BLI_last_slash(str);
136                         if (lslash) lslash[1] = '\0';
137                 }
138         }
139
140         RNA_property_string_set(&fbo->ptr, fbo->prop, str);
141         RNA_property_update(C, &fbo->ptr, fbo->prop);
142         MEM_freeN(str);
143
144
145         /* special, annoying exception, filesel on redo panel [#26618] */
146         {
147                 wmOperator *redo_op = WM_operator_last_redo(C);
148                 if (redo_op) {
149                         if (fbo->ptr.data == redo_op->ptr->data) {
150                                 ED_undo_operator_repeat(C, redo_op);
151                         }
152                 }
153         }
154
155         MEM_freeN(op->customdata);
156
157         return OPERATOR_FINISHED;
158 }
159
160 static int file_browse_cancel(bContext *UNUSED(C), wmOperator *op)
161 {
162         MEM_freeN(op->customdata);
163         op->customdata = NULL;
164
165         return OPERATOR_CANCELLED;
166 }
167
168 static int file_browse_invoke(bContext *C, wmOperator *op, const wmEvent *event)
169 {
170         PointerRNA ptr;
171         PropertyRNA *prop;
172         FileBrowseOp *fbo;
173         char *str;
174
175         if (CTX_wm_space_file(C)) {
176                 BKE_report(op->reports, RPT_ERROR, "Cannot activate a file selector, one already open");
177                 return OPERATOR_CANCELLED;
178         }
179
180         uiFileBrowseContextProperty(C, &ptr, &prop);
181
182         if (!prop)
183                 return OPERATOR_CANCELLED;
184
185         str = RNA_property_string_get_alloc(&ptr, prop, NULL, 0, NULL);
186
187         /* useful yet irritating feature, Shift+Click to open the file
188          * Alt+Click to browse a folder in the OS's browser */
189         if (event->shift || event->alt) {
190                 PointerRNA props_ptr;
191
192                 if (event->alt) {
193                         char *lslash = (char *)BLI_last_slash(str);
194                         if (lslash)
195                                 *lslash = '\0';
196                 }
197
198
199                 WM_operator_properties_create(&props_ptr, "WM_OT_path_open");
200                 RNA_string_set(&props_ptr, "filepath", str);
201                 WM_operator_name_call(C, "WM_OT_path_open", WM_OP_EXEC_DEFAULT, &props_ptr);
202                 WM_operator_properties_free(&props_ptr);
203
204                 MEM_freeN(str);
205                 return OPERATOR_CANCELLED;
206         }
207         else {
208                 const char *path_prop = RNA_struct_find_property(op->ptr, "directory") ? "directory" : "filepath";
209                 fbo = MEM_callocN(sizeof(FileBrowseOp), "FileBrowseOp");
210                 fbo->ptr = ptr;
211                 fbo->prop = prop;
212                 op->customdata = fbo;
213
214                 RNA_string_set(op->ptr, path_prop, str);
215                 MEM_freeN(str);
216
217                 /* normally ED_fileselect_get_params would handle this but we need to because of stupid
218                  * user-prefs exception - campbell */
219                 if (RNA_struct_find_property(op->ptr, "relative_path")) {
220                         if (!RNA_struct_property_is_set(op->ptr, "relative_path")) {
221                                 /* annoying exception!, if were dealing with the user prefs, default relative to be off */
222                                 RNA_boolean_set(op->ptr, "relative_path", U.flag & USER_RELPATHS && (ptr.data != &U));
223                         }
224                 }
225                 WM_event_add_fileselect(C, op);
226
227                 return OPERATOR_RUNNING_MODAL;
228         }
229 }
230
231 void BUTTONS_OT_file_browse(wmOperatorType *ot)
232 {
233         /* identifiers */
234         ot->name = "Accept";
235         ot->description = "Open a file browser, Hold Shift to open the file, Alt to browse containing directory";
236         ot->idname = "BUTTONS_OT_file_browse";
237         
238         /* api callbacks */
239         ot->invoke = file_browse_invoke;
240         ot->exec = file_browse_exec;
241         ot->cancel = file_browse_cancel;
242
243         /* properties */
244         WM_operator_properties_filesel(ot, 0, FILE_SPECIAL, FILE_OPENFILE,
245                                        WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY);
246 }
247
248 /* second operator, only difference from BUTTONS_OT_file_browse is WM_FILESEL_DIRECTORY */
249 void BUTTONS_OT_directory_browse(wmOperatorType *ot)
250 {
251         /* identifiers */
252         ot->name = "Accept";
253         ot->description = "Open a directory browser, Hold Shift to open the file, Alt to browse containing directory";
254         ot->idname = "BUTTONS_OT_directory_browse";
255
256         /* api callbacks */
257         ot->invoke = file_browse_invoke;
258         ot->exec = file_browse_exec;
259         ot->cancel = file_browse_cancel;
260
261         /* properties */
262         WM_operator_properties_filesel(ot, 0, FILE_SPECIAL, FILE_OPENFILE,
263                                        WM_FILESEL_DIRECTORY | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY);
264 }