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