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