c723113aae719a5f02b8733e7414adf169649aac
[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), 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                 char name[FILE_MAX];
117                 int is_relative = RNA_boolean_get(op->ptr, "relative_path");
118                 id = fbo->ptr.id.data;
119
120                 BLI_strncpy(path, str, FILE_MAX);
121                 BLI_path_abs(path, id ? ID_BLEND_PATH(G.main, id) : G.main->name);
122                 
123                 if (BLI_is_dir(path)) {
124                         if (is_relative) {
125                                 BLI_strncpy(path, str, FILE_MAX);
126                                 BLI_path_rel(path, G.main->name);
127                                 str = MEM_reallocN(str, strlen(path) + 2);
128                                 BLI_strncpy(str, path, FILE_MAX);
129                         }
130                         else {
131                                 str = MEM_reallocN(str, strlen(str) + 2);
132                         }
133                         BLI_add_slash(str);
134                 }
135                 else
136                         BLI_splitdirstring(str, name);
137         }
138
139         RNA_property_string_set(&fbo->ptr, fbo->prop, str);
140         RNA_property_update(C, &fbo->ptr, fbo->prop);
141         MEM_freeN(str);
142
143
144         /* special, annoying exception, filesel on redo panel [#26618] */
145         {
146                 wmOperator *redo_op = WM_operator_last_redo(C);
147                 if (redo_op) {
148                         if (fbo->ptr.data == redo_op->ptr->data) {
149                                 ED_undo_operator_repeat(C, redo_op);
150                         }
151                 }
152         }
153
154         MEM_freeN(op->customdata);
155
156         return OPERATOR_FINISHED;
157 }
158
159 static int file_browse_cancel(bContext *UNUSED(C), wmOperator *op)
160 {
161         MEM_freeN(op->customdata);
162         op->customdata = NULL;
163
164         return OPERATOR_CANCELLED;
165 }
166
167 static int file_browse_invoke(bContext *C, wmOperator *op, wmEvent *event)
168 {
169         PointerRNA ptr;
170         PropertyRNA *prop;
171         FileBrowseOp *fbo;
172         char *str;
173
174         if (CTX_wm_space_file(C)) {
175                 BKE_report(op->reports, RPT_ERROR, "Cannot activate a file selector, one already open");
176                 return OPERATOR_CANCELLED;
177         }
178
179         uiFileBrowseContextProperty(C, &ptr, &prop);
180
181         if (!prop)
182                 return OPERATOR_CANCELLED;
183
184         str = RNA_property_string_get_alloc(&ptr, prop, NULL, 0, NULL);
185
186         /* useful yet irritating feature, Shift+Click to open the file
187          * Alt+Click to browse a folder in the OS's browser */
188         if (event->shift || event->alt) {
189                 PointerRNA props_ptr;
190
191                 if (event->alt) {
192                         char *lslash = BLI_last_slash(str);
193                         if (lslash)
194                                 *lslash = '\0';
195                 }
196
197
198                 WM_operator_properties_create(&props_ptr, "WM_OT_path_open");
199                 RNA_string_set(&props_ptr, "filepath", str);
200                 WM_operator_name_call(C, "WM_OT_path_open", WM_OP_EXEC_DEFAULT, &props_ptr);
201                 WM_operator_properties_free(&props_ptr);
202
203                 MEM_freeN(str);
204                 return OPERATOR_CANCELLED;
205         }
206         else {
207                 const char *path_prop = RNA_struct_find_property(op->ptr, "directory") ? "directory" : "filepath";
208                 fbo = MEM_callocN(sizeof(FileBrowseOp), "FileBrowseOp");
209                 fbo->ptr = ptr;
210                 fbo->prop = prop;
211                 op->customdata = fbo;
212
213                 RNA_string_set(op->ptr, path_prop, str);
214                 MEM_freeN(str);
215
216                 /* normally ED_fileselect_get_params would handle this but we need to because of stupid
217                  * user-prefs exception - campbell */
218                 if (RNA_struct_find_property(op->ptr, "relative_path")) {
219                         if (!RNA_struct_property_is_set(op->ptr, "relative_path")) {
220                                 /* annoying exception!, if were dealing with the user prefs, default relative to be off */
221                                 RNA_boolean_set(op->ptr, "relative_path", U.flag & USER_RELPATHS && (ptr.data != &U));
222                         }
223                 }
224                 WM_event_add_fileselect(C, op);
225
226                 return OPERATOR_RUNNING_MODAL;
227         }
228 }
229
230 void BUTTONS_OT_file_browse(wmOperatorType *ot)
231 {
232         /* identifiers */
233         ot->name = "Accept";
234         ot->description = "Open a file browser, Hold Shift to open the file, Alt to browse containing directory";
235         ot->idname = "BUTTONS_OT_file_browse";
236         
237         /* api callbacks */
238         ot->invoke = file_browse_invoke;
239         ot->exec = file_browse_exec;
240         ot->cancel = file_browse_cancel;
241
242         /* properties */
243         WM_operator_properties_filesel(ot, 0, FILE_SPECIAL, FILE_OPENFILE,
244                                        WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY);
245 }
246
247 /* second operator, only difference from BUTTONS_OT_file_browse is WM_FILESEL_DIRECTORY */
248 void BUTTONS_OT_directory_browse(wmOperatorType *ot)
249 {
250         /* identifiers */
251         ot->name = "Accept";
252         ot->description = "Open a directory browser, Hold Shift to open the file, Alt to browse containing directory";
253         ot->idname = "BUTTONS_OT_directory_browse";
254
255         /* api callbacks */
256         ot->invoke = file_browse_invoke;
257         ot->exec = file_browse_exec;
258         ot->cancel = file_browse_cancel;
259
260         /* properties */
261         WM_operator_properties_filesel(ot, 0, FILE_SPECIAL, FILE_OPENFILE,
262                                        WM_FILESEL_DIRECTORY | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY);
263 }