]> git.lyx.org Git - features.git/blob - src/frontends/xforms/FormGraphics.C
9323d4287c358b870716a8cf956d6c3b328d5a4a
[features.git] / src / frontends / xforms / FormGraphics.C
1 /* FormGraphics.C
2  * FormGraphics Interface Class Implementation
3  */
4
5 #include <config.h> 
6
7 #ifdef __GNUG__
8 #pragma implementation
9 #endif 
10
11 #include "lyx_gui_misc.h"
12 #include "input_validators.h"
13 #include "FormGraphics.h"
14 #include "form_graphics.h"
15 #include "Dialogs.h"
16 #include "LyXView.h"
17 #include "BufferView.h"
18
19 #include "debug.h" // for lyxerr
20
21 #include "support/lstrings.h"  // for strToDbl & tostr
22 #include "support/FileInfo.h"  // for FileInfo
23 #include "xforms_helpers.h"     // for browseFile
24 #include "support/filetools.h" // for AddName
25 #include "insets/insetgraphics.h"
26 #include "insets/insetgraphicsParams.h"
27
28 #include "RadioButtonGroup.h"
29
30 #include "support/LAssert.h"
31
32 using std::endl;
33 using std::make_pair;
34
35 FormGraphics::FormGraphics(LyXView * lv, Dialogs * d)
36         : FormInset(lv, d, _("Graphics")),
37           inset_(0),
38           // The buttons c-tor values are the number of buttons we use
39           // This is only to reduce memory waste.
40           widthButtons(5), heightButtons(4), displayButtons(4),
41           last_image_path(".")
42 {
43         // let the dialog be shown
44         // This is a permanent connection so we won't bother
45         // storing a copy because we won't be disconnecting.
46         d->showGraphics.connect(slot(this, &FormGraphics::showDialog));
47 }
48
49
50 FormGraphics::~FormGraphics()
51 {
52         // Remove all associations for the radio buttons
53         widthButtons.reset();
54         heightButtons.reset();
55         displayButtons.reset();
56 }
57
58
59 void FormGraphics::build()
60 {
61         dialog_.reset(build_graphics());
62
63         // Workaround dumb xforms sizing bug
64         minw_ = form()->w;
65         minh_ = form()->h;
66
67         // This is the place to add settings of the dialog that did not go
68         // to the .fd file.
69
70         // Set the input widgets to issue a callback to input() whenever
71         // they change, so we can verify their content.
72         fl_set_input_return (dialog_->input_width,
73                               FL_RETURN_CHANGED);
74         fl_set_input_return (dialog_->input_height,
75                               FL_RETURN_CHANGED);
76         fl_set_input_return (dialog_->input_filename,
77                               FL_RETURN_CHANGED);
78         //    fl_set_input_return(dialog_->input_rotate_angle,
79         //            FL_RETURN_CHANGED);
80
81         // Set the maximum characters that can be written in the input texts.
82         fl_set_input_maxchars(dialog_->input_width, WIDTH_MAXDIGITS);
83         fl_set_input_maxchars(dialog_->input_height, HEIGHT_MAXDIGITS);
84         fl_set_input_maxchars(dialog_->input_filename, FILENAME_MAXCHARS);
85         fl_set_input_maxchars(dialog_->input_rotate_angle, ROTATE_MAXCHARS);
86
87         // Set input filter on width and height to make them accept only
88         // unsigned numbers.
89         fl_set_input_filter(dialog_->input_width,
90                             fl_unsigned_int_filter);
91         fl_set_input_filter(dialog_->input_height,
92                             fl_unsigned_int_filter);
93
94
95         // Add the widgets of the width radio buttons to their group
96         widthButtons.reset();
97         widthButtons.registerRadioButton(dialog_->radio_width_default,
98                                          InsetGraphicsParams::DEFAULT_SIZE);
99         widthButtons.registerRadioButton(dialog_->radio_width_cm,
100                                          InsetGraphicsParams::CM);
101         widthButtons.registerRadioButton(dialog_->radio_width_inch,
102                                          InsetGraphicsParams::INCH);
103         widthButtons.registerRadioButton(dialog_->radio_width_percent_page,
104                                          InsetGraphicsParams::PERCENT_PAGE);
105         widthButtons.registerRadioButton(dialog_->radio_width_percent_column,
106                                          InsetGraphicsParams::PERCENT_COLUMN);
107
108         // Add the widgets of the height radio buttons to their group
109         heightButtons.reset();
110         heightButtons.registerRadioButton(dialog_->radio_height_default,
111                                           InsetGraphicsParams::DEFAULT_SIZE);
112         heightButtons.registerRadioButton(dialog_->radio_height_cm,
113                                           InsetGraphicsParams::CM);
114         heightButtons.registerRadioButton(dialog_->radio_height_inch,
115                                           InsetGraphicsParams::INCH);
116         heightButtons.registerRadioButton(dialog_->radio_height_percent_page,
117                                           InsetGraphicsParams::PERCENT_PAGE);
118
119         // Add the widgets of the display radio buttons to their group
120         displayButtons.reset();
121         displayButtons.registerRadioButton(dialog_->radio_display_color,
122                                            InsetGraphicsParams::COLOR);
123         displayButtons.registerRadioButton(dialog_->radio_display_grayscale,
124                                            InsetGraphicsParams::GRAYSCALE);
125         displayButtons.registerRadioButton(dialog_->radio_display_monochrome,
126                                            InsetGraphicsParams::MONOCHROME);
127         displayButtons.registerRadioButton(dialog_->radio_no_display,
128                                            InsetGraphicsParams::NONE);
129
130         // Manage the ok, apply, restore and cancel/close buttons
131         bc().setOK(dialog_->button_ok);
132         bc().setApply(dialog_->button_apply);
133         bc().setCancel(dialog_->button_cancel);
134         bc().setUndoAll(dialog_->button_restore);
135         bc().refresh();
136
137         bc().addReadOnly(dialog_->input_filename);
138         bc().addReadOnly(dialog_->button_browse);
139         bc().addReadOnly(dialog_->input_width);
140         bc().addReadOnly(dialog_->input_height);
141         bc().addReadOnly(dialog_->radio_button_group_width);
142         bc().addReadOnly(dialog_->radio_button_group_height);
143         bc().addReadOnly(dialog_->radio_button_group_display);
144         bc().addReadOnly(dialog_->input_rotate_angle);
145         bc().addReadOnly(dialog_->check_inline);
146         bc().addReadOnly(dialog_->input_subcaption);
147         bc().addReadOnly(dialog_->check_subcaption);
148 }
149
150
151 FL_FORM * FormGraphics::form() const
152 {
153         if (dialog_.get())
154                 return dialog_->form;
155         return 0;
156 }
157
158
159 void FormGraphics::disconnect()
160 {
161         inset_ = 0;
162         FormInset::disconnect();
163 }
164
165
166 void FormGraphics::showDialog(InsetGraphics * inset)
167 {
168         // If we are connected to another inset, disconnect.
169         if (inset_)
170                 ih_.disconnect();
171
172         inset_ = inset;
173
174         ih_ = inset_->hideDialog.connect(slot(this, &FormGraphics::hide));
175         show();
176 }
177
178
179 void FormGraphics::apply()
180 {
181         Assert(inset_ != 0);
182
183         // Take all dialog details and insert them to the inset.
184
185         // Create the parameters structure and fill the data from the dialog.
186         InsetGraphicsParams igp;
187
188         igp.filename = fl_get_input(dialog_->input_filename);
189
190         igp.display = static_cast < InsetGraphicsParams::DisplayType >
191                       (displayButtons.getButton());
192
193         igp.widthResize = static_cast < InsetGraphicsParams::Resize >
194                           (widthButtons.getButton());
195         igp.widthSize = strToDbl(fl_get_input(dialog_->input_width));
196
197         igp.heightResize = static_cast < InsetGraphicsParams::Resize >
198                            (heightButtons.getButton());
199         igp.heightSize = strToDbl(fl_get_input(dialog_->input_height));
200
201         igp.rotateAngle = strToInt(fl_get_input(dialog_->input_rotate_angle));
202         if (igp.rotateAngle >= 360)
203                 igp.rotateAngle = igp.rotateAngle % 360;
204         if (igp.rotateAngle <= -360)
205                 igp.rotateAngle = - (( -igp.rotateAngle) % 360);
206
207         igp.subcaption = fl_get_button(dialog_->check_subcaption);
208         igp.subcaptionText = fl_get_input(dialog_->input_subcaption);
209
210         igp.inlineFigure = fl_get_button(dialog_->check_inline);
211
212         igp.testInvariant();
213
214         // Set the parameters in the inset, it also returns true if the new
215         // parameters are different from what was in the inset already.
216         bool changed = inset_->setParams(igp);
217
218         // Tell LyX we've got a change, and mark the document dirty, if it changed.
219         lv_->view()->updateInset(inset_, changed);
220 }
221
222
223 void FormGraphics::update()
224 {
225         Assert(inset_ != 0);
226
227         // Update dialog with details from inset
228         InsetGraphicsParams igp = inset_->getParams();
229
230         // Update the filename input field
231         fl_set_input(dialog_->input_filename,
232                      igp.filename.c_str());
233
234         // Update the display depth radio buttons
235         displayButtons.setButton(igp.display);
236
237         // Update the width radio buttons and input field
238         widthButtons.setButton(igp.widthResize);
239         fl_set_input(dialog_->input_width,
240                      tostr(igp.widthSize).c_str());
241
242         // Update the height radio buttons and input field
243         heightButtons.setButton(igp.heightResize);
244         fl_set_input(dialog_->input_height,
245                      tostr(igp.heightSize).c_str());
246
247         // Update the rotate angle
248         fl_set_input(dialog_->input_rotate_angle,
249                      tostr(igp.rotateAngle).c_str());
250
251         // Update the subcaption check button and input field
252         fl_set_button(dialog_->check_subcaption,
253                       igp.subcaption);
254         fl_set_input(dialog_->input_subcaption,
255                      igp.subcaptionText.c_str());
256
257         // Update the inline figure check button
258         fl_set_button(dialog_->check_inline,
259                       igp.inlineFigure);
260
261         // update the dialog's read only / read-write status
262         bc().readOnly(lv_->buffer()->isReadonly());
263
264         // Now make sure that the buttons are set correctly.
265         input(0, 0);
266 }
267
268
269 bool FormGraphics::input(FL_OBJECT *, long data )
270 {
271         State cb = static_cast<State>( data );
272
273         bool inputOK = true;
274
275         switch (cb) {
276         case CHECKINPUT:
277                 inputOK = checkInput();
278                 break;
279         case BROWSE:
280                 browse();
281                 break;
282         case ADVANCEDINPUT:
283                 lyxerr << "Advanced Options button depressed, "
284                        << "show advanced options dialog"
285                        << endl;
286                 break;
287         default:
288                 break;
289         }
290         
291         return inputOK;
292 }
293
294
295 bool FormGraphics::checkInput()
296 {
297         // Put verifications that the dialog shows some sane values,
298         // if not disallow clicking on ok/apply.
299         // Possibly use a label in the bottom of the dialog to give the reason.
300
301         // Is all input boxes convey a valid meaning?
302         bool inputOK = true;
303
304         // Things that we check (meaning they are incorrect states):
305         // 1. No filename specified.
306         // 2. Width radio button is not Default and width text is not a number.
307         // 3. Height radio button is not Default and height text is a not a number
308
309         // Note: radio button default means that the user asks for the image
310         // to be included as is with no size change, in this case we don't need
311         // any width or height.
312
313         // We verify now that there is a filename, it exists, it's a file
314         // and it's readable.
315         string filename = fl_get_input(dialog_->input_filename);
316         FileInfo file(filename);
317         if (filename.empty()
318                 || !file.isOK()
319                 || !file.exist()
320                 || !file.isRegular()
321                 || !file.readable()
322            )
323                 inputOK = false;
324
325         // Width radio button not default and no number.
326         if (!fl_get_button(dialog_->radio_width_default)
327                 && strToDbl(fl_get_input(dialog_->input_width)) <= 0.0) {
328
329                 inputOK = false;
330         }
331
332         // Height radio button not default and no number.
333         if (!fl_get_button(dialog_->radio_height_default)
334                 && strToDbl(fl_get_input(dialog_->input_height)) <= 0.0) {
335
336                 inputOK = false;
337         }
338
339         return inputOK;
340 }
341
342
343 // We need these in the file browser.
344 extern string system_lyxdir;
345 extern string user_lyxdir;
346
347 void FormGraphics::browse()
348 {
349         // Get the filename from the dialog
350         string const filename = fl_get_input(dialog_->input_filename);
351
352         string const title = N_("Graphics");
353         // FIXME: currently we need the second '|' to prevent mis-interpretation 
354         string const pattern = "*.(ps|png)|";
355
356         // Does user clipart directory exist?
357         string clipdir = AddName (user_lyxdir, "clipart");
358         FileInfo fileInfo(clipdir);
359         if (!(fileInfo.isOK() && fileInfo.isDir()))
360                 // No - bail out to system clipart directory
361                 clipdir = AddName (system_lyxdir, "clipart");
362         pair<string, string> dir1(N_("Clipart"), clipdir);
363         
364         // Show the file browser dialog
365         string const new_filename =
366                 browseFile(lv_, filename, title, pattern, dir1,
367                            make_pair(string(), string()));
368
369         // Save the filename to the dialog
370         if (new_filename != filename && !new_filename.empty()) {
371                 fl_set_input(dialog_->input_filename, new_filename.c_str());
372                 input(0, 0);
373         }
374 }