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