]> git.lyx.org Git - lyx.git/blob - src/frontends/xforms/FormParagraph.C
Really dull and boring header shit
[lyx.git] / src / frontends / xforms / FormParagraph.C
1 /**
2  * \file FormParagraph.C
3  * See the file COPYING.
4  *
5  * \author Jürgen Vigna
6  *
7  * Full author contact details are available in file CREDITS
8  */
9
10 #include <config.h>
11
12 #ifdef __GNUG__
13 #pragma implementation
14 #endif
15
16 #include FORMS_H_LOCATION
17
18 #include "FormParagraph.h"
19 #include "forms/form_paragraph.h"
20 #include "ControlParagraph.h"
21 #include "ParagraphParameters.h"
22 #include "xforms_helpers.h"
23 #include "lyxrc.h" // to set the deafult length values
24 #include "input_validators.h"
25 #include "helper_funcs.h"
26 #include "gettext.h"
27 #include "xformsBC.h"
28 #include "layout.h" // LyXAlignment
29
30 #include "support/lstrings.h"
31 #include "support/LAssert.h"
32 #include FORMS_H_LOCATION
33
34 #include <functional>
35
36 using std::vector;
37 using std::bind2nd;
38 using std::remove_if;
39
40 typedef FormCB<ControlParagraph, FormDB<FD_paragraph> > base_class;
41
42 FormParagraph::FormParagraph()
43         : base_class(_("Paragraph Layout"), false)
44 {}
45
46 void FormParagraph::build()
47 {
48         // the tabbed folder
49         dialog_.reset(build_paragraph(this));
50
51         // Allow the base class to control messages
52         setMessageWidget(dialog_->text_warning);
53
54         fl_addto_choice(dialog_->choice_space_above,
55                         _(" None | Defskip | Smallskip "
56                           "| Medskip | Bigskip | VFill | Length "));
57         fl_addto_choice(dialog_->choice_space_below,
58                         _(" None | Defskip | Smallskip "
59                           "| Medskip | Bigskip | VFill | Length "));
60
61         fl_addto_choice(dialog_->choice_linespacing,
62                         _(" Default | Single | OneHalf | Double | Custom "));
63
64         fl_set_input_return(dialog_->input_space_above, FL_RETURN_CHANGED);
65         fl_set_input_return(dialog_->input_space_below, FL_RETURN_CHANGED);
66         fl_set_input_return(dialog_->input_labelwidth,  FL_RETURN_CHANGED);
67         fl_set_input_return(dialog_->input_linespacing, FL_RETURN_CHANGED);
68         fl_set_input_filter(dialog_->input_linespacing, fl_unsigned_float_filter);
69
70         setPrehandler(dialog_->input_space_above);
71         setPrehandler(dialog_->input_space_below);
72         setPrehandler(dialog_->input_labelwidth);
73         setPrehandler(dialog_->input_linespacing);
74
75         // Create the contents of the unit choices
76         // Don't include the "%" terms...
77         vector<string> units_vec = getLatexUnits();
78
79         vector<string>::iterator del =
80                 remove_if(units_vec.begin(), units_vec.end(),
81                           bind2nd(contains_functor(), "%"));
82         units_vec.erase(del, units_vec.end());
83
84         string units = getStringFromVector(units_vec, "|");
85
86         fl_addto_choice(dialog_->choice_value_space_above, units.c_str());
87         fl_addto_choice(dialog_->choice_value_space_below, units.c_str());
88
89         // Manage the ok, apply, restore and cancel/close buttons
90         bc().setOK(dialog_->button_ok);
91         bc().setApply(dialog_->button_apply);
92         bc().setCancel(dialog_->button_close);
93         bc().setRestore(dialog_->button_restore);
94
95         bc().addReadOnly(dialog_->radio_align_right);
96         bc().addReadOnly(dialog_->radio_align_left);
97         bc().addReadOnly(dialog_->radio_align_block);
98         bc().addReadOnly(dialog_->radio_align_center);
99         bc().addReadOnly(dialog_->check_lines_top);
100         bc().addReadOnly(dialog_->check_lines_bottom);
101         bc().addReadOnly(dialog_->check_pagebreaks_top);
102         bc().addReadOnly(dialog_->check_pagebreaks_bottom);
103         bc().addReadOnly(dialog_->choice_space_above);
104         bc().addReadOnly(dialog_->input_space_above);
105         bc().addReadOnly(dialog_->check_space_above);
106         bc().addReadOnly(dialog_->choice_space_below);
107         bc().addReadOnly(dialog_->input_space_below);
108         bc().addReadOnly(dialog_->check_space_below);
109         bc().addReadOnly(dialog_->choice_linespacing);
110         bc().addReadOnly(dialog_->input_linespacing);
111         bc().addReadOnly(dialog_->check_noindent);
112         bc().addReadOnly(dialog_->input_labelwidth);
113 }
114
115 namespace {
116
117 VSpace setVSpaceFromWidgets(FL_OBJECT * choice_type,
118                             FL_OBJECT * input_length,
119                             FL_OBJECT * choice_length,
120                             FL_OBJECT * check_keep)
121 {
122         // Paranoia check!
123         lyx::Assert(choice_type   && choice_type->objclass   == FL_CHOICE &&
124                     input_length  && input_length->objclass  == FL_INPUT &&
125                     choice_length && choice_length->objclass == FL_CHOICE &&
126                     check_keep    && check_keep->objclass    == FL_CHECKBUTTON);
127
128         VSpace space;
129
130         switch (fl_get_choice(choice_type)) {
131         case 1:
132                 space = VSpace(VSpace::NONE);
133                 break;
134         case 2:
135                 space = VSpace(VSpace::DEFSKIP);
136                 break;
137         case 3:
138                 space = VSpace(VSpace::SMALLSKIP);
139                 break;
140         case 4:
141                 space = VSpace(VSpace::MEDSKIP);
142                 break;
143         case 5:
144                 space = VSpace(VSpace::BIGSKIP);
145                 break;
146         case 6:
147                 space = VSpace(VSpace::VFILL);
148                 break;
149         case 7:
150         {
151                 string const length =
152                         getLengthFromWidgets(input_length, choice_length);
153                 space = VSpace(LyXGlueLength(length));
154                 break;
155         }
156         }
157
158         if (fl_get_button(check_keep))
159                 space.setKeep(true);
160
161         return space;
162 }
163
164 void validateVSpaceWidgets(FL_OBJECT * choice_type, FL_OBJECT * input_length)
165 {
166         // Paranoia check!
167         lyx::Assert(choice_type  && choice_type->objclass   == FL_CHOICE &&
168                     input_length && input_length->objclass  == FL_INPUT);
169
170         if (fl_get_choice(choice_type) != 7)
171                 return;
172
173         // If a vspace kind is "Length" but there's no text in
174         // the input field, reset the kind to "None".
175         string const input = rtrim(getString(input_length));
176         if (input.empty())
177                 fl_set_choice(choice_type, 1);
178 }
179
180 } // namespace anon
181
182 void FormParagraph::apply()
183 {
184         if (!form()) return;
185
186         /* spacing */
187         // If a vspace kind is "Length" but there's no text in
188         // the input field, reset the kind to "None".
189         validateVSpaceWidgets(dialog_->choice_space_above,
190                               dialog_->input_space_above);
191
192         VSpace const space_top =
193                 setVSpaceFromWidgets(dialog_->choice_space_above,
194                                      dialog_->input_space_above,
195                                      dialog_->choice_value_space_above,
196                                      dialog_->check_space_above);
197
198         controller().params().spaceTop(space_top);
199
200         validateVSpaceWidgets(dialog_->choice_space_below,
201                               dialog_->input_space_below);
202
203         VSpace const space_bottom =
204                 setVSpaceFromWidgets(dialog_->choice_space_below,
205                                      dialog_->input_space_below,
206                                      dialog_->choice_value_space_below,
207                                      dialog_->check_space_below);
208
209         controller().params().spaceBottom(space_bottom);
210
211         /* lines and pagebreaks */
212         bool const line_top = fl_get_button(dialog_->check_lines_top);
213         controller().params().lineTop(line_top);
214
215         bool const line_bottom = fl_get_button(dialog_->check_lines_bottom);
216         controller().params().lineBottom(line_bottom);
217
218         bool const pagebreak_top = fl_get_button(dialog_->check_pagebreaks_top);
219         controller().params().pagebreakTop(pagebreak_top);
220
221         bool const pagebreak_bottom = fl_get_button(dialog_->check_pagebreaks_bottom);
222         controller().params().pagebreakBottom(pagebreak_bottom);
223
224
225         /* alignment */
226         LyXAlignment align;
227         if (fl_get_button(dialog_->radio_align_left))
228                 align = LYX_ALIGN_LEFT;
229         else if (fl_get_button(dialog_->radio_align_right))
230                 align = LYX_ALIGN_RIGHT;
231         else if (fl_get_button(dialog_->radio_align_center))
232                 align = LYX_ALIGN_CENTER;
233         else
234                 align = LYX_ALIGN_BLOCK;
235         controller().params().align(align);
236
237         /* label width */
238         string const labelwidthstring =
239                 getString(dialog_->input_labelwidth);
240         controller().params().labelWidthString(labelwidthstring);
241
242         /* indendation */
243         bool const noindent = fl_get_button(dialog_->check_noindent);
244         controller().params().noindent(noindent);
245
246         /* get spacing */
247         Spacing::Space linespacing = Spacing::Default;
248         string other;
249         switch (fl_get_choice(dialog_->choice_linespacing)) {
250         case 1:
251                 linespacing = Spacing::Default;
252                 break;
253         case 2:
254                 linespacing = Spacing::Single;
255                 break;
256         case 3:
257                 linespacing = Spacing::Onehalf;
258                 break;
259         case 4:
260                 linespacing = Spacing::Double;
261                 break;
262         case 5:
263                 linespacing = Spacing::Other;
264                 other = getString(dialog_->input_linespacing);
265                 break;
266         }
267
268         Spacing const spacing(linespacing, other);
269         controller().params().spacing(spacing);
270
271 }
272
273 namespace {
274
275 void setWidgetsFromVSpace(VSpace const & space,
276                           FL_OBJECT * choice_type,
277                           FL_OBJECT * input_length,
278                           FL_OBJECT * choice_length,
279                           FL_OBJECT * check_keep)
280 {
281         // Paranoia check!
282         lyx::Assert(choice_type   && choice_type->objclass   == FL_CHOICE &&
283                     input_length  && input_length->objclass  == FL_INPUT &&
284                     choice_length && choice_length->objclass == FL_CHOICE &&
285                     check_keep    && check_keep->objclass    == FL_CHECKBUTTON);
286
287         fl_set_input(input_length, "");
288         setEnabled(input_length,  false);
289         setEnabled(choice_length, false);
290
291         switch (space.kind()) {
292         case VSpace::NONE:
293                 fl_set_choice(choice_type, 1);
294                 break;
295         case VSpace::DEFSKIP:
296                 fl_set_choice(choice_type, 2);
297                 break;
298         case VSpace::SMALLSKIP:
299                 fl_set_choice(choice_type, 3);
300                 break;
301         case VSpace::MEDSKIP:
302                 fl_set_choice(choice_type, 4);
303                 break;
304         case VSpace::BIGSKIP:
305                 fl_set_choice(choice_type, 5);
306                 break;
307         case VSpace::VFILL:
308                 fl_set_choice(choice_type, 6);
309                 break;
310         case VSpace::LENGTH:
311         {
312                 fl_set_choice(choice_type, 7);
313
314                 setEnabled(input_length,  true);
315                 setEnabled(choice_length, true);
316
317                 bool const metric = lyxrc.default_papersize > 3;
318                 string const default_unit = metric ? "cm" : "in";
319                 string const length = space.length().asString();
320
321                 updateWidgetsFromLengthString(input_length, choice_length,
322                                               length, default_unit);
323                 break;
324         }
325         }
326
327         fl_set_button(check_keep, space.keep());
328 }
329
330 } // namespace anon
331
332 void FormParagraph::update()
333 {
334         if (!dialog_.get())
335                 return;
336
337         /* label width */
338         string labelwidth = controller().params().labelWidthString();
339         fl_set_input(dialog_->input_labelwidth, labelwidth.c_str());
340         setEnabled(dialog_->input_labelwidth,
341                    labelwidth != _("Senseless with this layout!"));
342
343         /* alignment */
344         fl_set_button(dialog_->radio_align_right, 0);
345         fl_set_button(dialog_->radio_align_left, 0);
346         fl_set_button(dialog_->radio_align_center, 0);
347         fl_set_button(dialog_->radio_align_block, 0);
348
349         LyXAlignment align = controller().params().align();
350
351         switch (align) {
352         case LYX_ALIGN_RIGHT:
353                 fl_set_button(dialog_->radio_align_right, 1);
354                 break;
355         case LYX_ALIGN_LEFT:
356                 fl_set_button(dialog_->radio_align_left, 1);
357                 break;
358         case LYX_ALIGN_CENTER:
359                 fl_set_button(dialog_->radio_align_center, 1);
360                 break;
361         default:
362                 fl_set_button(dialog_->radio_align_block, 1);
363                 break;
364         }
365
366         LyXAlignment alignpos = controller().alignPossible();
367
368         setEnabled(dialog_->radio_align_block,  bool(alignpos & LYX_ALIGN_BLOCK));
369         setEnabled(dialog_->radio_align_center, bool(alignpos & LYX_ALIGN_CENTER));
370         setEnabled(dialog_->radio_align_left,   bool(alignpos & LYX_ALIGN_LEFT));
371         setEnabled(dialog_->radio_align_right,  bool(alignpos & LYX_ALIGN_RIGHT));
372
373         // no inset-text-owned paragraph may have pagebreaks
374         bool ininset = controller().inInset();
375         setEnabled(dialog_->check_pagebreaks_top, !ininset);
376         setEnabled(dialog_->check_pagebreaks_bottom, !ininset);
377
378         /* lines, pagebreaks and indent */
379         fl_set_button(dialog_->check_lines_top,
380                       controller().params().lineTop());
381         fl_set_button(dialog_->check_lines_bottom,
382                       controller().params().lineBottom());
383         fl_set_button(dialog_->check_pagebreaks_top,
384                       controller().params().pagebreakTop());
385         fl_set_button(dialog_->check_pagebreaks_bottom,
386                       controller().params().pagebreakBottom());
387         fl_set_button(dialog_->check_noindent,
388                       controller().params().noindent());
389
390         /* linespacing */
391         int linespacing;
392         Spacing const space = controller().params().spacing();
393
394         switch (space.getSpace()) {
395         default: linespacing = 1; break;
396         case Spacing::Single: linespacing = 2; break;
397         case Spacing::Onehalf: linespacing = 3; break;
398         case Spacing::Double: linespacing = 4; break;
399         case Spacing::Other: linespacing = 5; break;
400         }
401
402         fl_set_choice(dialog_->choice_linespacing, linespacing);
403         if (space.getSpace() == Spacing::Other) {
404                 string const sp = tostr(space.getValue());
405                 fl_set_input(dialog_->input_linespacing, sp.c_str());
406                 setEnabled(dialog_->input_linespacing, true);
407         } else {
408                 fl_set_input(dialog_->input_linespacing, "");
409                 setEnabled(dialog_->input_linespacing, false);
410         }
411
412         /* vspace top */
413         setWidgetsFromVSpace(controller().params().spaceTop(),
414                              dialog_->choice_space_above,
415                              dialog_->input_space_above,
416                              dialog_->choice_value_space_above,
417                              dialog_->check_space_above);
418
419         /* vspace bottom */
420         setWidgetsFromVSpace(controller().params().spaceBottom(),
421                              dialog_->choice_space_below,
422                              dialog_->input_space_below,
423                              dialog_->choice_value_space_below,
424                              dialog_->check_space_below);
425
426         /* no indent */
427         fl_set_button(dialog_->check_noindent,
428                       controller().params().noindent());
429 }
430
431 namespace {
432
433 void synchronizeSpaceWidgets(FL_OBJECT * choice_type,
434                              FL_OBJECT * input_length,
435                              FL_OBJECT * choice_length)
436 {
437         // Paranoia check!
438         lyx::Assert(choice_type   && choice_type->objclass   == FL_CHOICE &&
439                     input_length  && input_length->objclass  == FL_INPUT &&
440                     choice_length && choice_length->objclass == FL_CHOICE);
441
442         if (fl_get_choice(choice_type) != 7) {
443                 fl_set_input(input_length, "");
444                 setEnabled(input_length, false);
445                 setEnabled(choice_length, false);
446
447         } else {
448                 setEnabled(input_length, true);
449                 setEnabled(choice_length, true);
450
451                 string const length = getString(input_length);
452
453                 if (rtrim(length).empty()) {
454                         bool const metric = lyxrc.default_papersize > 3;
455                         int const default_unit = metric ? 8 : 9;
456
457                         fl_set_choice(choice_length, default_unit);
458                 }
459         }
460 }
461
462 bool validSpaceWidgets(FL_OBJECT * choice_type, FL_OBJECT * input_length)
463 {
464         // Paranoia check!
465         lyx::Assert(choice_type  && choice_type->objclass   == FL_CHOICE &&
466                     input_length && input_length->objclass  == FL_INPUT);
467
468         if (fl_get_choice(choice_type) != 7)
469                 return true;
470
471         string const input = getString(input_length);
472         return (input.empty() ||
473                 isValidGlueLength(input) ||
474                 isStrDbl(input));
475 }
476
477 } // namespace anon
478
479 ButtonPolicy::SMInput FormParagraph::input(FL_OBJECT * ob, long)
480 {
481         clearMessage();
482
483         // First check the buttons which are exclusive and you have to
484         // check only the actuall de/activated button.
485         //
486         // "Synchronize" the choices and input fields, making it
487         // impossible to commit senseless data.
488         if (ob == dialog_->choice_space_above) {
489                 synchronizeSpaceWidgets(dialog_->choice_space_above,
490                                         dialog_->input_space_above,
491                                         dialog_->choice_value_space_above);
492         }
493
494         if (ob == dialog_->choice_space_below) {
495                 synchronizeSpaceWidgets(dialog_->choice_space_below,
496                                         dialog_->input_space_below,
497                                         dialog_->choice_value_space_below);
498         }
499
500         // Display a warning if the input is senseless
501         bool valid = (validSpaceWidgets(dialog_->choice_space_above,
502                                         dialog_->input_space_above) &&
503                       validSpaceWidgets(dialog_->choice_space_below,
504                                         dialog_->input_space_below));
505
506         if (!valid) {
507                 postWarning(_("Invalid Length (valid example: 10mm)"));
508         }
509
510         int const choice_spacing = fl_get_choice(dialog_->choice_linespacing);
511
512         if (choice_spacing == 5)
513                 setEnabled(dialog_->input_linespacing, true);
514         else {
515                 fl_set_input(dialog_->input_linespacing, "");
516                 setEnabled(dialog_->input_linespacing, false);
517         }
518
519         double const spacing =
520                 strToDbl(getString(dialog_->input_linespacing));
521
522         if (choice_spacing == 5 && int(spacing) == 0)
523                 valid = false;
524
525         return ButtonPolicy::SMI_VALID;
526 }