]> git.lyx.org Git - lyx.git/blob - src/frontends/xforms/FormParagraph.C
Strip out another 180 #includes.
[lyx.git] / src / frontends / xforms / FormParagraph.C
1 /**
2  * \file FormParagraph.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Jürgen Vigna
7  * \author Rob Lahaye
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include "FormParagraph.h"
15 #include "ControlParagraph.h"
16 #include "forms/form_paragraph.h"
17
18 #include "checkedwidgets.h"
19 #include "input_validators.h"
20 #include "Tooltips.h"
21 #include "xforms_helpers.h"
22 #include "xformsBC.h"
23
24 #include "controllers/helper_funcs.h"
25
26 #include "lyxrc.h" // to set the deafult length values
27 #include "ParagraphParameters.h"
28
29 #include "support/LAssert.h"
30 #include "support/lstrings.h"
31 #include "support/tostr.h"
32
33 #include "lyx_forms.h"
34
35 using namespace lyx::support;
36
37 using std::bind2nd;
38 using std::remove_if;
39 using std::vector;
40
41
42 namespace
43 {
44
45 string defaultUnit("cm");
46
47 void validateVSpaceWidgets(FL_OBJECT * choice_type, FL_OBJECT * input_length);
48
49 VSpace const setVSpaceFromWidgets(FL_OBJECT * choice_type,
50                                   FL_OBJECT * input_length,
51                                   FL_OBJECT * choice_length,
52                                   FL_OBJECT * check_keep);
53
54 void setWidgetsFromVSpace(VSpace const & space,
55                           FL_OBJECT * choice_type,
56                           FL_OBJECT * input_length,
57                           FL_OBJECT * choice_length,
58                           FL_OBJECT * check_keep);
59
60 } // namespace anon
61
62
63 typedef FormController<ControlParagraph, FormView<FD_paragraph> > base_class;
64
65 FormParagraph::FormParagraph(Dialog & parent)
66         : base_class(parent, _("Paragraph Settings"))
67 {}
68
69
70 void FormParagraph::build()
71 {
72         // the tabbed folder
73         dialog_.reset(build_paragraph(this));
74
75         // Manage the ok, apply, restore and cancel/close buttons
76         bcview().setOK(dialog_->button_ok);
77         bcview().setApply(dialog_->button_apply);
78         bcview().setCancel(dialog_->button_close);
79         bcview().setRestore(dialog_->button_restore);
80
81         // disable for read-only documents
82         bcview().addReadOnly(dialog_->check_line_above);
83         bcview().addReadOnly(dialog_->check_pagebreak_above);
84         bcview().addReadOnly(dialog_->choice_space_above);
85         bcview().addReadOnly(dialog_->input_space_above);
86         bcview().addReadOnly(dialog_->check_space_above);
87
88         bcview().addReadOnly(dialog_->check_noindent);
89         bcview().addReadOnly(dialog_->choice_linespacing);
90         bcview().addReadOnly(dialog_->input_linespacing);
91
92         bcview().addReadOnly(dialog_->check_line_below);
93         bcview().addReadOnly(dialog_->check_pagebreak_below);
94         bcview().addReadOnly(dialog_->choice_space_below);
95         bcview().addReadOnly(dialog_->input_space_below);
96         bcview().addReadOnly(dialog_->check_space_below);
97
98         bcview().addReadOnly(dialog_->input_labelwidth);
99
100         // check validity of "length + unit" input
101         addCheckedGlueLength(bcview(),
102                              dialog_->input_space_above,
103                              dialog_->choice_space_above);
104         addCheckedGlueLength(bcview(),
105                              dialog_->input_space_below,
106                              dialog_->choice_space_below);
107
108         // trigger an input event for cut&paste with middle mouse button.
109         setPrehandler(dialog_->input_space_above);
110         setPrehandler(dialog_->input_space_below);
111         setPrehandler(dialog_->input_linespacing);
112         setPrehandler(dialog_->input_labelwidth);
113
114         fl_set_input_return(dialog_->input_space_above, FL_RETURN_CHANGED);
115         fl_set_input_return(dialog_->input_space_below, FL_RETURN_CHANGED);
116         fl_set_input_return(dialog_->input_labelwidth,  FL_RETURN_CHANGED);
117         fl_set_input_return(dialog_->input_linespacing, FL_RETURN_CHANGED);
118
119         // limit these inputs to unsigned floats
120         fl_set_input_filter(dialog_->input_linespacing, fl_unsigned_float_filter);
121
122         // add alignment radio buttons
123         alignment_.init(dialog_->radio_align_left,   LYX_ALIGN_LEFT);
124         alignment_.init(dialog_->radio_align_right,  LYX_ALIGN_RIGHT);
125         alignment_.init(dialog_->radio_align_block,  LYX_ALIGN_BLOCK);
126         alignment_.init(dialog_->radio_align_center, LYX_ALIGN_CENTER);
127
128         string const parspacing = _("None|DefSkip|SmallSkip|MedSkip|BigSkip|VFill|Length");
129         fl_addto_choice(dialog_->choice_space_above, parspacing.c_str());
130         fl_addto_choice(dialog_->choice_space_below, parspacing.c_str());
131
132         string const linespacing = _("Default|Single|OneHalf|Double|Custom");
133         fl_addto_choice(dialog_->choice_linespacing, linespacing.c_str());
134
135         // Create the contents of the unit choices; don't include the "%" terms.
136         vector<string> units_vec = getLatexUnits();
137         vector<string>::iterator del =
138                 remove_if(units_vec.begin(), units_vec.end(),
139                           bind2nd(contains_functor(), "%"));
140         units_vec.erase(del, units_vec.end());
141
142         string const units = getStringFromVector(units_vec, "|");
143         fl_addto_choice(dialog_->choice_unit_space_above, units.c_str());
144         fl_addto_choice(dialog_->choice_unit_space_below, units.c_str());
145
146         // set up the tooltips
147         string str = _("Add a separator line above this paragraph.");
148         tooltips().init(dialog_->check_line_above, str);
149         str = _("Enforce a page break above this paragraph.");
150         tooltips().init(dialog_->check_pagebreak_above, str);
151         str = _("Add additional space above this paragraph.");
152         tooltips().init(dialog_->choice_space_above, str);
153         str = _("Never suppress space (e.g. at top of page or new page).");
154         tooltips().init(dialog_->check_space_above, str);
155
156         str = _("Add a separator line below this paragraph.");
157         tooltips().init(dialog_->check_line_below, str);
158         str = _("Enforce a page break below this paragraph.");
159         tooltips().init(dialog_->check_pagebreak_below, str);
160         str = _("Add additional space below this paragraph.");
161         tooltips().init(dialog_->choice_space_below, str);
162         str = _("Never suppress space (e.g. at bottom of page or new page).");
163         tooltips().init(dialog_->check_space_below, str);
164
165         // set default unit for custom length
166         switch (lyxrc.default_papersize) {
167                 case PAPER_DEFAULT:
168                 case PAPER_USLETTER:
169                 case PAPER_LEGALPAPER:
170                 case PAPER_EXECUTIVEPAPER:
171                         defaultUnit = "in";
172                         break;
173                 case PAPER_A3PAPER:
174                 case PAPER_A4PAPER:
175                 case PAPER_A5PAPER:
176                 case PAPER_B5PAPER:
177                         defaultUnit = "cm";
178                         break;
179         }
180 }
181
182
183 void FormParagraph::apply()
184 {
185         if (!form()) return;
186
187         // spacing
188         // If a vspace choice is "Length" but there's no text in
189         // the input field, reset the choice to "None".
190         validateVSpaceWidgets(dialog_->choice_space_above,
191                               dialog_->input_space_above);
192
193         VSpace const space_above =
194                 setVSpaceFromWidgets(dialog_->choice_space_above,
195                                      dialog_->input_space_above,
196                                      dialog_->choice_unit_space_above,
197                                      dialog_->check_space_above);
198
199         controller().params().spaceTop(space_above);
200
201         validateVSpaceWidgets(dialog_->choice_space_below,
202                               dialog_->input_space_below);
203
204         VSpace const space_below =
205                 setVSpaceFromWidgets(dialog_->choice_space_below,
206                                      dialog_->input_space_below,
207                                      dialog_->choice_unit_space_below,
208                                      dialog_->check_space_below);
209
210         controller().params().spaceBottom(space_below);
211
212         // lines and pagebreaks
213         bool const line_above = fl_get_button(dialog_->check_line_above);
214         controller().params().lineTop(line_above);
215
216         bool const line_below = fl_get_button(dialog_->check_line_below);
217         controller().params().lineBottom(line_below);
218
219         bool const pagebreak_above =
220                 fl_get_button(dialog_->check_pagebreak_above);
221         controller().params().pagebreakTop(pagebreak_above);
222
223         bool const pagebreak_below =
224                 fl_get_button(dialog_->check_pagebreak_below);
225         controller().params().pagebreakBottom(pagebreak_below);
226
227
228         // alignment
229         LyXAlignment const alignment =
230                 static_cast<LyXAlignment>(alignment_.get());
231         controller().params().align(alignment);
232
233         // label width
234         string const labelwidthstring =
235                 getString(dialog_->input_labelwidth);
236         controller().params().labelWidthString(labelwidthstring);
237
238         // indendation
239         bool const noindent = fl_get_button(dialog_->check_noindent);
240         controller().params().noindent(noindent);
241
242         // get spacing
243         Spacing::Space linespacing = Spacing::Default;
244         string other;
245         switch (fl_get_choice(dialog_->choice_linespacing)) {
246         case 1:
247                 linespacing = Spacing::Default;
248                 break;
249         case 2:
250                 linespacing = Spacing::Single;
251                 break;
252         case 3:
253                 linespacing = Spacing::Onehalf;
254                 break;
255         case 4:
256                 linespacing = Spacing::Double;
257                 break;
258         case 5:
259                 // reset to default if input is empty
260                 other = getString(dialog_->input_linespacing);
261                 if (!other.empty()) {
262                         linespacing = Spacing::Other;
263                 } else {
264                         linespacing = Spacing::Default;
265                         fl_set_choice(dialog_->choice_linespacing, 1);
266                 }
267                 break;
268         }
269         Spacing const spacing(linespacing, other);
270         controller().params().spacing(spacing);
271 }
272
273
274 void FormParagraph::update()
275 {
276         if (!dialog_.get())
277                 return;
278
279         // label width
280         string const labelwidth = controller().params().labelWidthString();
281         fl_set_input(dialog_->input_labelwidth, labelwidth.c_str());
282         setEnabled(dialog_->input_labelwidth,
283                    labelwidth != _("Senseless with this layout!"));
284
285         // alignment
286         alignment_.set(controller().params().align());
287
288         // mark default alignment
289         LyXAlignment const default_alignment = controller().alignDefault();
290
291         string label = _("Block");
292         if (default_alignment == LYX_ALIGN_BLOCK) {
293                 label += _(" (default)");
294         }
295         fl_set_object_label(dialog_->radio_align_block, label.c_str());
296         fl_set_button_shortcut(dialog_->radio_align_block, "#B", 1);
297
298         label = _("Center");
299         if (default_alignment == LYX_ALIGN_CENTER) {
300                 label += _(" (default)");
301         }
302         fl_set_object_label(dialog_->radio_align_center, label.c_str());
303         fl_set_button_shortcut(dialog_->radio_align_center, "#C", 1);
304
305         label = _("Left");
306         if (default_alignment == LYX_ALIGN_LEFT) {
307                 label += _(" (default)");
308         }
309         fl_set_object_label(dialog_->radio_align_left, label.c_str());
310         fl_set_button_shortcut(dialog_->radio_align_left, "#L", 1);
311
312         label = _("Right");
313         if (default_alignment == LYX_ALIGN_RIGHT) {
314                 label = _(" (default)");
315         }
316         fl_set_object_label(dialog_->radio_align_right, label.c_str());
317         fl_set_button_shortcut(dialog_->radio_align_right, "#R", 1);
318
319         // Ensure that there's no crud left on the screen from this change
320         // of labels.
321         fl_redraw_form(form());
322
323         LyXAlignment alignpos = controller().alignPossible();
324         setEnabled(dialog_->radio_align_block,
325                    bool(alignpos & LYX_ALIGN_BLOCK));
326         setEnabled(dialog_->radio_align_center,
327                    bool(alignpos & LYX_ALIGN_CENTER));
328         setEnabled(dialog_->radio_align_left,
329                    bool(alignpos & LYX_ALIGN_LEFT));
330         setEnabled(dialog_->radio_align_right,
331                    bool(alignpos & LYX_ALIGN_RIGHT));
332
333         // no inset-text-owned paragraph may have pagebreaks
334         bool ininset = controller().inInset();
335         setEnabled(dialog_->check_pagebreak_above, !ininset);
336         setEnabled(dialog_->check_pagebreak_below, !ininset);
337
338         // lines, pagebreaks and indent
339         fl_set_button(dialog_->check_line_above,
340                       controller().params().lineTop());
341         fl_set_button(dialog_->check_line_below,
342                       controller().params().lineBottom());
343         fl_set_button(dialog_->check_pagebreak_above,
344                       controller().params().pagebreakTop());
345         fl_set_button(dialog_->check_pagebreak_below,
346                       controller().params().pagebreakBottom());
347         fl_set_button(dialog_->check_noindent,
348                       controller().params().noindent());
349
350         // linespacing
351         Spacing const space = controller().params().spacing();
352
353         int pos;
354         switch (space.getSpace()) {
355         case Spacing::Other:
356                 pos = 5;
357                 break;
358         case Spacing::Double:
359                 pos = 4;
360                 break;
361         case Spacing::Onehalf:
362                 pos = 3;
363                 break;
364         case Spacing::Single:
365                 pos = 2;
366                 break;
367         case Spacing::Default:
368         default:
369                 pos = 1;
370                 break;
371         }
372         fl_set_choice(dialog_->choice_linespacing, pos);
373
374         bool const spacing_other = space.getSpace() == Spacing::Other;
375         setEnabled(dialog_->input_linespacing, spacing_other);
376         if (spacing_other) {
377                 string const sp = tostr(space.getValue());
378                 fl_set_input(dialog_->input_linespacing, sp.c_str());
379         } else {
380                 fl_set_input(dialog_->input_linespacing, "");
381         }
382
383         // vspace top
384         setWidgetsFromVSpace(controller().params().spaceTop(),
385                              dialog_->choice_space_above,
386                              dialog_->input_space_above,
387                              dialog_->choice_unit_space_above,
388                              dialog_->check_space_above);
389
390         // vspace bottom
391         setWidgetsFromVSpace(controller().params().spaceBottom(),
392                              dialog_->choice_space_below,
393                              dialog_->input_space_below,
394                              dialog_->choice_unit_space_below,
395                              dialog_->check_space_below);
396
397         // no indent
398         fl_set_button(dialog_->check_noindent,
399                       controller().params().noindent());
400 }
401
402
403 ButtonPolicy::SMInput FormParagraph::input(FL_OBJECT * ob, long)
404 {
405         // Enable input when custum length is choosen,
406         // disable 'keep' when no space is choosen
407         if (ob == dialog_->choice_space_above) {
408                 bool const custom_length =
409                         fl_get_choice(dialog_->choice_space_above) == 7;
410                 setEnabled(dialog_->input_space_above, custom_length);
411                 setEnabled(dialog_->choice_unit_space_above, custom_length);
412
413                 bool const space =
414                         fl_get_choice(dialog_->choice_space_above) != 1;
415                 setEnabled(dialog_->check_space_above, space);
416
417         } else if (ob == dialog_->choice_space_below) {
418                 bool const custom_length =
419                         fl_get_choice(dialog_->choice_space_below) == 7;
420                 setEnabled(dialog_->input_space_below, custom_length);
421                 setEnabled(dialog_->choice_unit_space_below, custom_length);
422
423                 bool const space =
424                         fl_get_choice(dialog_->choice_space_below) != 1;
425                 setEnabled(dialog_->check_space_below, space);
426
427         } else if (ob == dialog_->choice_linespacing) {
428                 bool const custom_spacing =
429                         fl_get_choice(dialog_->choice_linespacing) == 5;
430                 setEnabled(dialog_->input_linespacing, custom_spacing);
431         }
432
433         return ButtonPolicy::SMI_VALID;
434 }
435
436
437 namespace {
438
439 void validateVSpaceWidgets(FL_OBJECT * choice_type, FL_OBJECT * input_length)
440 {
441         // Paranoia check!
442         Assert(choice_type  && choice_type->objclass  == FL_CHOICE &&
443                     input_length && input_length->objclass == FL_INPUT);
444
445         if (fl_get_choice(choice_type) != 7)
446                 return;
447
448         // If a vspace kind is "Length" but there's no text in
449         // the input field, reset the kind to "None".
450         string const input = rtrim(getString(input_length));
451         if (input.empty())
452                 fl_set_choice(choice_type, 1);
453 }
454
455
456 VSpace const setVSpaceFromWidgets(FL_OBJECT * choice_type,
457                                   FL_OBJECT * input_length,
458                                   FL_OBJECT * choice_length,
459                                   FL_OBJECT * check_keep)
460 {
461         // Paranoia check!
462         Assert(choice_type   && choice_type->objclass   == FL_CHOICE &&
463                     input_length  && input_length->objclass  == FL_INPUT &&
464                     choice_length && choice_length->objclass == FL_CHOICE &&
465                     check_keep    && check_keep->objclass    == FL_CHECKBUTTON);
466
467         VSpace space;
468         switch (fl_get_choice(choice_type)) {
469         case 1:
470                 space = VSpace(VSpace::NONE);
471                 break;
472         case 2:
473                 space = VSpace(VSpace::DEFSKIP);
474                 break;
475         case 3:
476                 space = VSpace(VSpace::SMALLSKIP);
477                 break;
478         case 4:
479                 space = VSpace(VSpace::MEDSKIP);
480                 break;
481         case 5:
482                 space = VSpace(VSpace::BIGSKIP);
483                 break;
484         case 6:
485                 space = VSpace(VSpace::VFILL);
486                 break;
487         case 7:
488                 {
489                 string const length =
490                         getLengthFromWidgets(input_length, choice_length);
491                 space = VSpace(LyXGlueLength(length));
492                 break;
493                 }
494         }
495
496         if (fl_get_button(check_keep))
497                 space.setKeep(true);
498
499         return space;
500 }
501
502
503 void setWidgetsFromVSpace(VSpace const & space,
504                           FL_OBJECT * choice_type,
505                           FL_OBJECT * input_length,
506                           FL_OBJECT * choice_length,
507                           FL_OBJECT * check_keep)
508 {
509         // Paranoia check!
510         Assert(choice_type   && choice_type->objclass   == FL_CHOICE &&
511                     input_length  && input_length->objclass  == FL_INPUT &&
512                     choice_length && choice_length->objclass == FL_CHOICE &&
513                     check_keep    && check_keep->objclass    == FL_CHECKBUTTON);
514
515         fl_set_button(check_keep, space.keep());
516
517         int pos = 1;
518         switch (space.kind()) {
519         case VSpace::NONE:
520                 pos = 1;
521                 break;
522         case VSpace::DEFSKIP:
523                 pos = 2;
524                 break;
525         case VSpace::SMALLSKIP:
526                 pos = 3;
527                 break;
528         case VSpace::MEDSKIP:
529                 pos = 4;
530                 break;
531         case VSpace::BIGSKIP:
532                 pos = 5;
533                 break;
534         case VSpace::VFILL:
535                 pos = 6;
536                 break;
537         case VSpace::LENGTH:
538                 pos = 7;
539                 break;
540         }
541         fl_set_choice(choice_type, pos);
542
543         bool const custom_vspace = space.kind() == VSpace::LENGTH;
544         setEnabled(input_length, custom_vspace);
545         setEnabled(choice_length, custom_vspace);
546         if (custom_vspace) {
547                 string const length = space.length().asString();
548                 updateWidgetsFromLengthString(input_length, choice_length,
549                                               length, defaultUnit);
550         } else {
551                 bool const no_vspace = space.kind() == VSpace::NONE;
552                 setEnabled(check_keep, !no_vspace);
553                 fl_set_input(input_length, "");
554                 fl_set_choice_text(choice_length, defaultUnit.c_str());
555         }
556 }
557
558 } // namespace anon