2b3785e2810bded674c729fdadff25c34ec30912
[blender.git] / source / blender / editors / space_info / info_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) 2008 Blender Foundation.
19  * All rights reserved.
20  *
21  * 
22  * Contributor(s): Blender Foundation
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/editors/space_info/info_ops.c
28  *  \ingroup spinfo
29  */
30
31
32 #include <string.h>
33 #include <stdio.h>
34
35 #include "DNA_packedFile_types.h"
36 #include "DNA_space_types.h"
37 #include "DNA_windowmanager_types.h"
38
39 #include "MEM_guardedalloc.h"
40
41 #include "BLI_blenlib.h"
42 #include "BLI_math.h"
43 #include "BLI_bpath.h"
44 #include "BLI_utildefines.h"
45
46 #include "BKE_context.h"
47 #include "BKE_global.h"
48 #include "BKE_image.h"
49 #include "BKE_main.h"
50 #include "BKE_packedFile.h"
51 #include "BKE_report.h"
52
53
54 #include "WM_api.h"
55 #include "WM_types.h"
56
57
58 #include "UI_interface.h"
59 #include "UI_resources.h"
60
61 #include "IMB_imbuf_types.h"
62
63 #include "RNA_access.h"
64 #include "RNA_define.h"
65
66
67 #include "info_intern.h"
68
69 /********************* pack all operator *********************/
70
71 static int pack_all_exec(bContext *C, wmOperator *op)
72 {
73         Main *bmain= CTX_data_main(C);
74
75         packAll(bmain, op->reports);
76         G.fileflags |= G_AUTOPACK;
77
78         return OPERATOR_FINISHED;
79 }
80
81 static int pack_all_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
82 {
83         Main *bmain= CTX_data_main(C);
84         Image *ima;
85         ImBuf *ibuf;
86
87         // first check for dirty images
88         for(ima=bmain->image.first; ima; ima=ima->id.next) {
89                 if(ima->ibufs.first) { /* XXX FIX */
90                         ibuf= BKE_image_get_ibuf(ima, NULL);
91                         
92                         if(ibuf && (ibuf->userflags & IB_BITMAPDIRTY))
93                                 break;
94                 }
95         }
96
97         if(ima) {
98                 uiPupMenuOkee(C, "FILE_OT_pack_all", "Some images are painted on. These changes will be lost. Continue?");
99                 return OPERATOR_CANCELLED;
100         }
101
102         return pack_all_exec(C, op);
103 }
104
105 void FILE_OT_pack_all(wmOperatorType *ot)
106 {
107         /* identifiers */
108         ot->name= "Pack All";
109         ot->idname= "FILE_OT_pack_all";
110         
111         /* api callbacks */
112         ot->exec= pack_all_exec;
113         ot->invoke= pack_all_invoke;
114
115         /* flags */
116         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
117 }
118
119 /********************* unpack all operator *********************/
120
121 static const EnumPropertyItem unpack_all_method_items[] = {
122         {PF_USE_LOCAL, "USE_LOCAL", 0, "Use files in current directory (create when necessary)", ""},
123         {PF_WRITE_LOCAL, "WRITE_LOCAL", 0, "Write files to current directory (overwrite existing files)", ""},
124         {PF_USE_ORIGINAL, "USE_ORIGINAL", 0, "Use files in original location (create when necessary)", ""},
125         {PF_WRITE_ORIGINAL, "WRITE_ORIGINAL", 0, "Write files to original location (overwrite existing files)", ""},
126         {PF_KEEP, "KEEP", 0, "Disable AutoPack, keep all packed files", ""},
127         {PF_ASK, "ASK", 0, "Ask for each file", ""},
128         {0, NULL, 0, NULL, NULL}};
129
130 static int unpack_all_exec(bContext *C, wmOperator *op)
131 {
132         Main *bmain= CTX_data_main(C);
133         int method= RNA_enum_get(op->ptr, "method");
134
135         if(method != PF_KEEP) unpackAll(bmain, op->reports, method); /* XXX PF_ASK can't work here */
136         G.fileflags &= ~G_AUTOPACK;
137
138         return OPERATOR_FINISHED;
139 }
140
141 static int unpack_all_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
142 {
143         Main *bmain= CTX_data_main(C);
144         uiPopupMenu *pup;
145         uiLayout *layout;
146         char title[128];
147         int count = 0;
148         
149         count = countPackedFiles(bmain);
150         
151         if(!count) {
152                 BKE_report(op->reports, RPT_WARNING, "No packed files. Autopack disabled");
153                 G.fileflags &= ~G_AUTOPACK;
154                 return OPERATOR_CANCELLED;
155         }
156
157         if(count == 1)
158                 sprintf(title, "Unpack 1 file");
159         else
160                 sprintf(title, "Unpack %d files", count);
161         
162         pup= uiPupMenuBegin(C, title, ICON_NONE);
163         layout= uiPupMenuLayout(pup);
164
165         uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT);
166         uiItemsEnumO(layout, "FILE_OT_unpack_all", "method");
167
168         uiPupMenuEnd(C, pup);
169
170         return OPERATOR_CANCELLED;
171 }
172
173 void FILE_OT_unpack_all(wmOperatorType *ot)
174 {
175         /* identifiers */
176         ot->name= "Unpack All";
177         ot->idname= "FILE_OT_unpack_all";
178         
179         /* api callbacks */
180         ot->exec= unpack_all_exec;
181         ot->invoke= unpack_all_invoke;
182
183         /* flags */
184         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
185
186         /* properties */
187         RNA_def_enum(ot->srna, "method", unpack_all_method_items, PF_USE_LOCAL, "Method", "How to unpack");
188 }
189
190 /********************* make paths relative operator *********************/
191
192 static int make_paths_relative_exec(bContext *C, wmOperator *op)
193 {
194         Main *bmain= CTX_data_main(C);
195
196         if(!G.relbase_valid) {
197                 BKE_report(op->reports, RPT_WARNING, "Can't set relative paths with an unsaved blend file");
198                 return OPERATOR_CANCELLED;
199         }
200
201         makeFilesRelative(bmain, bmain->name, op->reports);
202
203         /* redraw everything so any changed paths register */
204         WM_main_add_notifier(NC_WINDOW, NULL);
205
206         return OPERATOR_FINISHED;
207 }
208
209 void FILE_OT_make_paths_relative(wmOperatorType *ot)
210 {
211         /* identifiers */
212         ot->name= "Make All Paths Relative";
213         ot->idname= "FILE_OT_make_paths_relative";
214         
215         /* api callbacks */
216         ot->exec= make_paths_relative_exec;
217
218         /* flags */
219         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
220 }
221
222 /********************* make paths absolute operator *********************/
223
224 static int make_paths_absolute_exec(bContext *C, wmOperator *op)
225 {
226         Main *bmain= CTX_data_main(C);
227
228         if(!G.relbase_valid) {
229                 BKE_report(op->reports, RPT_WARNING, "Can't set absolute paths with an unsaved blend file");
230                 return OPERATOR_CANCELLED;
231         }
232
233         makeFilesAbsolute(bmain, bmain->name, op->reports);
234
235         /* redraw everything so any changed paths register */
236         WM_main_add_notifier(NC_WINDOW, NULL);
237
238         return OPERATOR_FINISHED;
239 }
240
241 void FILE_OT_make_paths_absolute(wmOperatorType *ot)
242 {
243         /* identifiers */
244         ot->name= "Make All Paths Absolute";
245         ot->idname= "FILE_OT_make_paths_absolute";
246         
247         /* api callbacks */
248         ot->exec= make_paths_absolute_exec;
249
250         /* flags */
251         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
252 }
253
254 /********************* report missing files operator *********************/
255
256 static int report_missing_files_exec(bContext *UNUSED(C), wmOperator *op)
257 {
258         /* run the missing file check */
259         checkMissingFiles(G.main, op->reports);
260         
261         return OPERATOR_FINISHED;
262 }
263
264 void FILE_OT_report_missing_files(wmOperatorType *ot)
265 {
266         /* identifiers */
267         ot->name= "Report Missing Files";
268         ot->idname= "FILE_OT_report_missing_files";
269         
270         /* api callbacks */
271         ot->exec= report_missing_files_exec;
272
273         /* flags */
274         ot->flag= 0; /* only reports so no need to undo/register */
275 }
276
277 /********************* find missing files operator *********************/
278
279 static int find_missing_files_exec(bContext *UNUSED(C), wmOperator *op)
280 {
281         char *path;
282         
283         path= RNA_string_get_alloc(op->ptr, "filepath", NULL, 0);
284         findMissingFiles(G.main, path);
285         MEM_freeN(path);
286
287         return OPERATOR_FINISHED;
288 }
289
290 static int find_missing_files_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
291 {
292         /* XXX file open button text "Find Missing Files" */
293         WM_event_add_fileselect(C, op); 
294         return OPERATOR_RUNNING_MODAL;
295 }
296
297 void FILE_OT_find_missing_files(wmOperatorType *ot)
298 {
299         /* identifiers */
300         ot->name= "Find Missing Files";
301         ot->idname= "FILE_OT_find_missing_files";
302         
303         /* api callbacks */
304         ot->exec= find_missing_files_exec;
305         ot->invoke= find_missing_files_invoke;
306
307         /* flags */
308         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
309
310         /* properties */
311         WM_operator_properties_filesel(ot, 0, FILE_SPECIAL, FILE_OPENFILE, WM_FILESEL_FILEPATH);
312 }
313
314 /********************* report box operator *********************/
315
316 /* Hard to decide whether to keep this as an operator, 
317  * or turn it into a hardcoded ui control feature, 
318  * handling TIMER events for all regions in interface_handlers.c
319  * Not sure how good that is to be accessing UI data from 
320  * inactive regions, so use this for now. --matt
321  */
322
323 #define INFO_TIMEOUT            5.0f
324 #define INFO_COLOR_TIMEOUT      3.0f
325 #define ERROR_TIMEOUT           10.0f
326 #define ERROR_COLOR_TIMEOUT     6.0f
327 #define COLLAPSE_TIMEOUT        0.25f
328 static int update_reports_display_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
329 {
330         wmWindowManager *wm= CTX_wm_manager(C);
331         ReportList *reports= CTX_wm_reports(C);
332         Report *report;
333         ReportTimerInfo *rti;
334         float progress=0.0, color_progress=0.0;
335         float neutral_col[3] = {0.35, 0.35, 0.35};
336         float neutral_grey= 0.6;
337         float timeout=0.0, color_timeout=0.0;
338         int send_note= 0;
339         
340         /* escape if not our timer */
341         if(             (reports->reporttimer==NULL) ||
342                         (reports->reporttimer != event->customdata) ||
343                         ((report= BKE_reports_last_displayable(reports))==NULL) /* may have been deleted */
344         ) {
345                 return OPERATOR_PASS_THROUGH;
346         }
347
348         rti = (ReportTimerInfo *)reports->reporttimer->customdata;
349         
350         timeout = (report->type & RPT_ERROR_ALL)?ERROR_TIMEOUT:INFO_TIMEOUT;
351         color_timeout = (report->type & RPT_ERROR_ALL)?ERROR_COLOR_TIMEOUT:INFO_COLOR_TIMEOUT;
352         
353         /* clear the report display after timeout */
354         if ((float)reports->reporttimer->duration > timeout) {
355                 WM_event_remove_timer(wm, NULL, reports->reporttimer);
356                 reports->reporttimer = NULL;
357                 
358                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_INFO, NULL);
359                 
360                 return (OPERATOR_FINISHED|OPERATOR_PASS_THROUGH);
361         }
362
363         if (rti->widthfac == 0.0f) {
364                 /* initialise colors based on report type */
365                 if(report->type & RPT_ERROR_ALL) {
366                         rti->col[0] = 1.0;
367                         rti->col[1] = 0.2;
368                         rti->col[2] = 0.0;
369                 } else if(report->type & RPT_WARNING_ALL) {
370                         rti->col[0] = 1.0;
371                         rti->col[1] = 1.0;
372                         rti->col[2] = 0.0;
373                 } else if(report->type & RPT_INFO_ALL) {
374                         rti->col[0] = 0.3;
375                         rti->col[1] = 0.45;
376                         rti->col[2] = 0.7;
377                 }
378                 rti->greyscale = 0.75;
379                 rti->widthfac=1.0;
380         }
381         
382         progress = (float)reports->reporttimer->duration / timeout;
383         color_progress = (float)reports->reporttimer->duration / color_timeout;
384         
385         /* save us from too many draws */
386         if(color_progress <= 1.0f) {
387                 send_note= 1;
388                 
389                 /* fade colors out sharply according to progress through fade-out duration */
390                 interp_v3_v3v3(rti->col, rti->col, neutral_col, color_progress);
391                 rti->greyscale = interpf(neutral_grey, rti->greyscale, color_progress);
392         }
393
394         /* collapse report at end of timeout */
395         if (progress*timeout > timeout - COLLAPSE_TIMEOUT) {
396                 rti->widthfac = (progress*timeout - (timeout - COLLAPSE_TIMEOUT)) / COLLAPSE_TIMEOUT;
397                 rti->widthfac = 1.0f - rti->widthfac;
398                 send_note= 1;
399         }
400         
401         if(send_note) {
402                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_INFO, NULL);
403         }
404         
405         return (OPERATOR_FINISHED|OPERATOR_PASS_THROUGH);
406 }
407
408 void INFO_OT_reports_display_update(wmOperatorType *ot)
409 {
410         /* identifiers */
411         ot->name= "Update Reports Display";
412         ot->idname= "INFO_OT_reports_display_update";
413         
414         /* api callbacks */
415         ot->invoke= update_reports_display_invoke;
416         
417         /* flags */
418         ot->flag= 0;
419         
420         /* properties */
421 }
422
423 /* report operators */