]> git.lyx.org Git - lyx.git/blob - src/frontends/xforms/FormGraphics.C
594087e67c4a816a5a92e2a890085770619f39c6
[lyx.git] / src / frontends / xforms / FormGraphics.C
1 /* This file is part of
2  * ====================================================== 
3  *
4  *           LyX, The Document Processor
5  *
6  *           Copyright 2000-2001 The LyX Team.
7  *
8  * ======================================================
9  *
10  * \file FormGraphics.C
11  * \author Baruch Even, baruch.even@writeme.com
12  * \author Herbert Voss, voss@perce.de
13  */
14
15 #include <config.h> 
16
17 #ifdef __GNUG__
18 #pragma implementation
19 #endif 
20
21 #include "xformsBC.h"
22 #include "ControlGraphics.h"
23 #include "FormGraphics.h"
24 #include "form_graphics.h"
25
26 #include "xforms_helpers.h"
27 #include "input_validators.h"
28 #include "debug.h" // for lyxerr
29 #include "support/lstrings.h"  // for strToDbl & tostr
30 #include "support/FileInfo.h"
31 #include "support/filetools.h"  // for MakeAbsPath etc
32 #include "insets/insetgraphicsParams.h"
33 #include "lyxrc.h" // for lyxrc.display_graphics
34
35 using std::endl;
36
37 namespace {
38
39 // Bound the number of input characters
40 int const SCALE_MAXDIGITS = 3;
41 int const WIDTH_MAXDIGITS = 10;
42 int const HEIGHT_MAXDIGITS = 10;
43 int const ROTATE_MAXCHARS = 4;
44 int const FILENAME_MAXCHARS = 1024;
45  
46 } // namespace anon
47
48
49 typedef FormCB<ControlGraphics, FormDB<FD_form_graphics> > base_class;
50
51 FormGraphics::FormGraphics(ControlGraphics & c)
52         : base_class(c, _("Graphics"))
53 {}
54
55
56 void FormGraphics::redraw()
57 {
58         if(form() && form()->visible)
59                 fl_redraw_form(form());
60         else
61                 return;
62         FL_FORM * outer_form = fl_get_active_folder(dialog_->tabFolder);
63         if (outer_form && outer_form->visible)
64                 fl_redraw_form(outer_form);
65 }
66
67
68 void FormGraphics::build()
69 {
70         dialog_.reset(build_graphics());
71
72         // Manage the ok, apply, restore and cancel/close buttons
73         bc().setOK(dialog_->button_ok);
74         bc().setCancel(dialog_->button_cancel);
75         bc().setRestore(dialog_->button_restore);
76         bc().setRestore(dialog_->button_help);
77
78         // the file section
79         file_.reset(build_file());
80
81         fl_set_input_return (file_->input_filename, FL_RETURN_CHANGED);
82         fl_set_input_return (file_->input_subcaption, FL_RETURN_CHANGED);
83         fl_set_input_return (file_->input_rotate_angle, FL_RETURN_CHANGED);
84         fl_set_input_maxchars(file_->input_filename,  FILENAME_MAXCHARS);
85         fl_set_input_maxchars(file_->input_rotate_angle, ROTATE_MAXCHARS);
86         fl_set_input_filter(file_->input_rotate_angle, fl_float_filter);
87
88         string const choice_origin = 
89             "center|"                                   // c
90             "leftTop|leftBottom|leftBaseline|"          // lt lb lB
91             "centerTop|centerBottom|centerBaseline|"    // ct cb cB
92             "rightTop|rightBottom|rightBaseline";       // rt rb rB
93         fl_addto_choice(file_->choice_origin, choice_origin.c_str());
94
95         bc().addReadOnly(file_->button_browse);
96         bc().addReadOnly(file_->check_subcaption);
97         bc().addReadOnly(file_->button_clip);
98         bc().addReadOnly(file_->button_draft);
99
100         // the lyxview section
101         lyxview_.reset(build_lyxview());
102
103         fl_set_input_return (lyxview_->input_lyxwidth, FL_RETURN_CHANGED);
104         fl_set_input_return (lyxview_->input_lyxheight, FL_RETURN_CHANGED);
105         fl_set_input_return (lyxview_->input_lyxscale, FL_RETURN_CHANGED);
106
107         fl_addto_choice(lyxview_->choice_width_lyxwidth, choice_Length_WithUnit.c_str());
108         fl_addto_choice(lyxview_->choice_width_lyxheight, choice_Length_WithUnit.c_str());
109         fl_addto_choice(lyxview_->choice_display,
110                 _(" Default | Monochrome | Grayscale | Color | Do not display "));
111         fl_set_choice(lyxview_->choice_display, 1);
112
113         bc().addReadOnly(lyxview_->choice_display);
114
115         // the size section
116         size_.reset(build_size());
117
118         fl_set_input_return (size_->input_scale, FL_RETURN_CHANGED);
119         fl_set_input_return (size_->input_width, FL_RETURN_CHANGED);
120         fl_set_input_return (size_->input_height, FL_RETURN_CHANGED);
121
122         fl_set_input_maxchars(size_->input_scale, SCALE_MAXDIGITS);
123         fl_set_input_maxchars(size_->input_width, WIDTH_MAXDIGITS);
124         fl_set_input_maxchars(size_->input_height, HEIGHT_MAXDIGITS);
125
126         fl_set_input_filter(size_->input_scale,  fl_unsigned_float_filter);
127
128         fl_addto_choice(size_->choice_width_units, choice_Length_All.c_str());
129         fl_addto_choice(size_->choice_height_units, choice_Length_All.c_str());
130
131         bc().addReadOnly(size_->button_default);
132         bc().addReadOnly(size_->button_wh);
133         bc().addReadOnly(size_->button_scale);
134         bc().addReadOnly(size_->check_aspectratio);
135
136         // the bounding box selection
137         bbox_.reset(build_bbox());
138         fl_set_input_return (bbox_->input_bb_x0, FL_RETURN_CHANGED);
139         fl_set_input_return (bbox_->input_bb_y0, FL_RETURN_CHANGED);
140         fl_set_input_return (bbox_->input_bb_x1, FL_RETURN_CHANGED);
141         fl_set_input_return (bbox_->input_bb_y1, FL_RETURN_CHANGED);
142
143         string const bb_units = "pt|cm|in";
144         fl_addto_choice(bbox_->choice_bb_x0, bb_units.c_str());
145         fl_addto_choice(bbox_->choice_bb_y0, bb_units.c_str());
146         fl_addto_choice(bbox_->choice_bb_x1, bb_units.c_str());
147         fl_addto_choice(bbox_->choice_bb_y1, bb_units.c_str());
148         bc().addReadOnly(bbox_->button_getBB);
149
150         // the rotate section
151         special_.reset(build_special());
152
153         fl_set_input_return (special_->input_special, FL_RETURN_CHANGED);
154
155         // add the different tabfolders
156         fl_addto_tabfolder(dialog_->tabFolder, _("File"), file_->form);
157         fl_addto_tabfolder(dialog_->tabFolder, _("LyXView"), lyxview_->form);
158         fl_addto_tabfolder(dialog_->tabFolder, _("Size"), size_->form);
159         fl_addto_tabfolder(dialog_->tabFolder, _("Bounding Box"), bbox_->form);
160         fl_addto_tabfolder(dialog_->tabFolder, _("Extras"), special_->form);
161 }
162
163
164 void FormGraphics::apply()
165 {
166         // Create the parameters structure and fill the data from the dialog.
167         InsetGraphicsParams & igp = controller().params();
168         // the file section
169         igp.filename = getStringFromInput(file_->input_filename);
170         igp.subcaption = fl_get_button(file_->check_subcaption);
171         igp.subcaptionText = getStringFromInput(file_->input_subcaption);
172         igp.rotateAngle =
173                 strToDbl(getStringFromInput(file_->input_rotate_angle));
174         while (igp.rotateAngle < 0.0 || igp.rotateAngle > 360.0) {
175                 if (igp.rotateAngle < 0.0) {
176                         igp.rotateAngle += 360.0;
177                 } else if (igp.rotateAngle > 360.0) {
178                         igp.rotateAngle -= 360.0;
179                 }
180         }
181         if (fl_get_choice(file_->choice_origin) > 0)
182             igp.rotateOrigin = fl_get_choice_text(file_->choice_origin);
183         else
184             igp.rotateOrigin = string();
185         igp.scale = strToInt(getStringFromInput(size_->input_scale));
186         igp.keepAspectRatio = fl_get_button(size_->check_aspectratio);
187
188         // the lyxview section
189         switch (fl_get_choice(lyxview_->choice_display)) {
190         case 1:
191                 igp.display = InsetGraphicsParams::DEFAULT;             
192                 break;
193         case 2:
194                 igp.display = InsetGraphicsParams::MONOCHROME;          
195                 break;
196         case 3:
197                 igp.display = InsetGraphicsParams::GRAYSCALE;           
198                 break;
199         case 4:
200                 igp.display = InsetGraphicsParams::COLOR;               
201                 break;
202         case 5:
203                 igp.display = InsetGraphicsParams::NONE;                
204                 break;
205         }
206         igp.lyxwidth = LyXLength(getLengthFromWidgets(lyxview_->input_lyxwidth,
207                 lyxview_->choice_width_lyxwidth));
208         igp.lyxheight = LyXLength(getLengthFromWidgets(lyxview_->input_lyxheight,
209                 lyxview_->choice_width_lyxheight));
210
211         // the size section
212         igp.draft = fl_get_button(file_->button_draft);
213         igp.clip = fl_get_button(file_->button_clip);
214         if (fl_get_button(size_->button_default))
215             igp.size_type = InsetGraphicsParams::DEFAULT_SIZE;
216         else if (fl_get_button(size_->button_wh))
217             igp.size_type = InsetGraphicsParams::WH;
218         else
219             igp.size_type = InsetGraphicsParams::SCALE;
220         igp.width = LyXLength(getLengthFromWidgets(size_->input_width,
221                 size_->choice_width_units));
222         igp.height = LyXLength(getLengthFromWidgets(size_->input_height,
223                 size_->choice_height_units));
224
225         // the bb section
226         if (!controller().bbChanged)            // different to the original one?
227             igp.bb = string();                  // don't write anything     
228         else {
229             string bb;
230             if (getStringFromInput(bbox_->input_bb_x0).empty())
231                 bb = "0 ";
232             else
233                 bb = getLengthFromWidgets(bbox_->input_bb_x0,
234                         bbox_->choice_bb_x0)+" ";
235             if (getStringFromInput(bbox_->input_bb_y0).empty())
236                 bb += "0 ";
237             else
238                 bb += (getLengthFromWidgets(bbox_->input_bb_y0,
239                         bbox_->choice_bb_y0)+" ");
240             if (getStringFromInput(bbox_->input_bb_x1).empty())
241                 bb += "0 ";
242             else
243                 bb += (getLengthFromWidgets(bbox_->input_bb_x1,
244                         bbox_->choice_bb_x1)+" ");
245             if (getStringFromInput(bbox_->input_bb_y1).empty())
246                 bb += "0 ";
247             else
248                 bb += (getLengthFromWidgets(bbox_->input_bb_y1,
249                         bbox_->choice_bb_y1)+" ");
250             igp.bb = bb;
251         }
252
253         // the special section
254         igp.special = getStringFromInput(special_->input_special);
255 }
256
257
258 void FormGraphics::update() {   
259         string unit = "cm";
260         if (lyxrc.default_papersize < 3)
261             unit = "in";
262         string const defaultUnit = string(unit); 
263         // Update dialog with details from inset
264         InsetGraphicsParams & igp = controller().params();
265
266         // the file section
267         fl_set_input(file_->input_filename, igp.filename.c_str());
268         fl_set_button(file_->check_subcaption, igp.subcaption);
269         fl_set_input(file_->input_subcaption, igp.subcaptionText.c_str());
270         setEnabled(file_->input_subcaption,
271                    fl_get_button(file_->check_subcaption));
272         fl_set_input(file_->input_rotate_angle,
273                      tostr(igp.rotateAngle).c_str());
274         if (igp.rotateOrigin.empty())
275             fl_set_choice(file_->choice_origin,0);
276         else
277             fl_set_choice_text(file_->choice_origin,igp.rotateOrigin.c_str());
278         fl_set_button(file_->button_draft, igp.draft);
279         fl_set_button(file_->button_clip, igp.clip);
280
281         // the lyxview section
282         switch (igp.display) {
283         case InsetGraphicsParams::DEFAULT:
284                 fl_set_choice(lyxview_->choice_display, 1);
285                 break;
286         case InsetGraphicsParams::MONOCHROME:
287                 fl_set_choice(lyxview_->choice_display, 2);
288                 break;
289         case InsetGraphicsParams::GRAYSCALE:
290                 fl_set_choice(lyxview_->choice_display, 3);
291                 break;
292         case InsetGraphicsParams::COLOR:
293                 fl_set_choice(lyxview_->choice_display, 4);
294                 break;
295         case InsetGraphicsParams::NONE:
296                 fl_set_choice(lyxview_->choice_display, 5);
297                 break;
298         }
299         updateWidgetsFromLength(lyxview_->input_lyxwidth,
300                 lyxview_->choice_width_lyxwidth, igp.lyxwidth,defaultUnit);
301         updateWidgetsFromLength(lyxview_->input_lyxheight,
302                 lyxview_->choice_width_lyxheight, igp.lyxheight,defaultUnit);
303
304         // the size section
305         // Update the draft and clip mode
306         updateWidgetsFromLength(size_->input_width,
307                 size_->choice_width_units,igp.width,defaultUnit);
308         updateWidgetsFromLength(size_->input_height,
309                 size_->choice_height_units,igp.height,defaultUnit);
310         fl_set_input(size_->input_scale, tostr(igp.scale).c_str());
311         switch (igp.size_type) {
312             case InsetGraphicsParams::DEFAULT_SIZE: {
313                 fl_set_button(size_->button_default,1);
314                 setEnabled(size_->input_width, 0);
315                 setEnabled(size_->choice_width_units, 0);
316                 setEnabled(size_->input_height, 0);
317                 setEnabled(size_->choice_height_units, 0);
318                 setEnabled(size_->input_scale, 0);
319                 break;
320             }
321             case InsetGraphicsParams::WH: {
322                 fl_set_button(size_->button_wh, 1);
323                 setEnabled(size_->input_width, 1);
324                 setEnabled(size_->choice_width_units, 1);
325                 setEnabled(size_->input_height, 1);
326                 setEnabled(size_->choice_height_units, 1);
327                 setEnabled(size_->input_scale, 0);
328                 break;
329             }
330             case InsetGraphicsParams::SCALE: {
331                 fl_set_button(size_->button_scale, 1);
332                 setEnabled(size_->input_width, 0);
333                 setEnabled(size_->choice_width_units, 0);
334                 setEnabled(size_->input_height, 0);
335                 setEnabled(size_->choice_height_units, 0);
336                 setEnabled(size_->input_scale, 1);
337                 break;
338             }
339         }
340         fl_set_button(size_->check_aspectratio, igp.keepAspectRatio);
341         
342         // the bb section               
343         // set the bounding box values, if exists. First we need the whole
344         // path, because the controller knows nothing about the doc-dir
345         lyxerr << "GraphicsUpdate::BoundingBox = " << igp.bb << "\n";
346         controller().bbChanged = false;
347         if (igp.bb.empty()) {
348             string const fileWithAbsPath = MakeAbsPath(igp.filename, OnlyPath(igp.filename));   
349             string bb = controller().readBB(fileWithAbsPath);
350             lyxerr << "file::BoundingBox = " << bb << "\n";
351             if (!bb.empty()) {          
352                 // get the values from the file
353                 // in this case we always have the point-unit
354                 fl_set_input(bbox_->input_bb_x0, token(bb,' ',0).c_str());
355                 fl_set_input(bbox_->input_bb_y0, token(bb,' ',1).c_str());
356                 fl_set_input(bbox_->input_bb_x1, token(bb,' ',2).c_str());
357                 fl_set_input(bbox_->input_bb_y1, token(bb,' ',3).c_str());
358             }
359         } else {                                // get the values from the inset
360             controller().bbChanged = true;
361             LyXLength anyLength;
362             anyLength = LyXLength(token(igp.bb,' ',0));
363             updateWidgetsFromLength(bbox_->input_bb_x0,
364                         bbox_->choice_bb_x0,anyLength,"pt");
365             anyLength = LyXLength(token(igp.bb,' ',1));
366             updateWidgetsFromLength(bbox_->input_bb_y0,
367                         bbox_->choice_bb_y0,anyLength,"pt");
368             anyLength = LyXLength(token(igp.bb,' ',2));
369             updateWidgetsFromLength(bbox_->input_bb_x1,
370                         bbox_->choice_bb_x1,anyLength,"pt");
371             anyLength = LyXLength(token(igp.bb,' ',3));
372             updateWidgetsFromLength(bbox_->input_bb_y1,
373                         bbox_->choice_bb_y1,anyLength,"pt");
374         }
375
376         // the special section
377         fl_set_input(special_->input_special, igp.special.c_str());
378 }
379
380
381 namespace {
382
383 bool isValid(FL_OBJECT * ob)
384 {
385         string const input = getStringFromInput(ob);
386         return input.empty() || isValidLength(input) || isStrDbl(input);
387 }
388
389 } // namespace anon
390
391  
392         
393 ButtonPolicy::SMInput FormGraphics::input(FL_OBJECT * ob, long)
394 {
395         if (ob == file_->button_browse) {
396                 // Get the filename from the dialog
397                 string const in_name = getStringFromInput(file_->input_filename);
398                 string const out_name = controller().Browse(in_name);
399                 if (out_name != in_name && !out_name.empty()) {
400                         fl_set_input(file_->input_filename, out_name.c_str());
401                 }
402         } else if (!controller().bbChanged && 
403                     ((ob == bbox_->input_bb_x0) || (ob == bbox_->input_bb_y0) ||
404                     (ob == bbox_->input_bb_x1) || (ob == bbox_->input_bb_y1) ||
405                     (ob == bbox_->choice_bb_x0) || (ob == bbox_->choice_bb_y0) ||
406                     (ob == bbox_->choice_bb_x1) || (ob == bbox_->choice_bb_y1))) {
407             controller().bbChanged = true; 
408         } else if (ob == size_->button_default) {
409                 setEnabled(size_->input_width, 0);
410                 setEnabled(size_->choice_width_units, 0);
411                 setEnabled(size_->input_height, 0);
412                 setEnabled(size_->choice_height_units, 0);
413                 setEnabled(size_->input_scale, 0);
414         } else if (ob == size_->button_wh) {
415                 setEnabled(size_->input_width, 1);
416                 setEnabled(size_->choice_width_units, 1);
417                 setEnabled(size_->input_height, 1);
418                 setEnabled(size_->choice_height_units, 1);
419                 setEnabled(size_->input_scale, 0);
420         } else if (ob == size_->button_scale) {
421                 setEnabled(size_->input_width, 0);
422                 setEnabled(size_->choice_width_units, 0);
423                 setEnabled(size_->input_height, 0);
424                 setEnabled(size_->choice_height_units, 0);
425                 setEnabled(size_->input_scale, 1);
426         } else if (ob == file_->check_subcaption) {
427                 setEnabled(file_->input_subcaption,
428                            fl_get_button(file_->check_subcaption));
429         } else if (ob == bbox_->button_getBB) {
430             string const filename = getStringFromInput(file_->input_filename);
431             if (!filename.empty()) {
432                 string const fileWithAbsPath = MakeAbsPath(filename, OnlyPath(filename));       
433                 string bb = controller().readBB(fileWithAbsPath);
434                 lyxerr << "getBB::BoundingBox = " << bb << "\n";
435                 if (!bb.empty()) {              
436                     fl_set_input(bbox_->input_bb_x0, token(bb,' ',0).c_str());
437                     fl_set_input(bbox_->input_bb_y0, token(bb,' ',1).c_str());
438                     fl_set_input(bbox_->input_bb_x1, token(bb,' ',2).c_str());
439                     fl_set_input(bbox_->input_bb_y1, token(bb,' ',3).c_str());
440                 }
441                 controller().bbChanged = false;
442             }
443         } else if (ob == dialog_->button_help) {
444             controller().help();
445         }
446
447         // check if the input is valid
448         bool invalid = !isValid(bbox_->input_bb_x0);
449         invalid = invalid || !isValid(bbox_->input_bb_x1);
450         invalid = invalid || !isValid(bbox_->input_bb_y0);
451         invalid = invalid || !isValid(bbox_->input_bb_y1);
452         invalid = invalid || !isValid(size_->input_width);
453         invalid = invalid || !isValid(size_->input_height);
454         invalid = invalid || !isValid(lyxview_->input_lyxwidth);
455         invalid = invalid || !isValid(lyxview_->input_lyxheight);
456
457         // deactivate OK/ Apply buttons and
458         // spit out warnings if invalid
459         if (ob == bbox_->input_bb_x0 || ob == bbox_->input_bb_x1 || 
460             ob == bbox_->input_bb_y0 || ob == bbox_->input_bb_y1 || 
461             ob == size_->input_width || ob == size_->input_height || 
462             ob == lyxview_->input_lyxwidth || ob == lyxview_->input_lyxheight) {
463                 if (invalid) {
464                         fl_set_object_label(dialog_->text_warning,
465                                 _("Warning: Invalid Length!"));
466                         fl_show_object(dialog_->text_warning);
467                         return ButtonPolicy::SMI_INVALID;
468                 } else {
469                         fl_hide_object(dialog_->text_warning);
470                 }
471         }
472
473         return ButtonPolicy::SMI_VALID;
474 }
475