2 * \file FormParagraph.C
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
8 * Full author contact details are available in file CREDITS
14 #pragma implementation
17 #include FORMS_H_LOCATION
19 #include "FormParagraph.h"
20 #include "forms/form_paragraph.h"
21 #include "ControlParagraph.h"
22 #include "ParagraphParameters.h"
23 #include "xforms_helpers.h"
24 #include "lyxrc.h" // to set the deafult length values
25 #include "input_validators.h"
26 #include "helper_funcs.h"
29 #include "layout.h" // LyXAlignment
31 #include "support/lstrings.h"
32 #include "support/LAssert.h"
33 #include FORMS_H_LOCATION
41 typedef FormCB<ControlParagraph, FormDB<FD_paragraph> > base_class;
43 FormParagraph::FormParagraph()
44 : base_class(_("Paragraph Layout"), false)
47 void FormParagraph::build()
50 dialog_.reset(build_paragraph(this));
52 // Allow the base class to control messages
53 setMessageWidget(dialog_->text_warning);
55 fl_addto_choice(dialog_->choice_space_above,
56 _(" None | Defskip | Smallskip "
57 "| Medskip | Bigskip | VFill | Length "));
58 fl_addto_choice(dialog_->choice_space_below,
59 _(" None | Defskip | Smallskip "
60 "| Medskip | Bigskip | VFill | Length "));
62 fl_addto_choice(dialog_->choice_linespacing,
63 _(" Default | Single | OneHalf | Double | Custom "));
65 fl_set_input_return(dialog_->input_space_above, FL_RETURN_CHANGED);
66 fl_set_input_return(dialog_->input_space_below, FL_RETURN_CHANGED);
67 fl_set_input_return(dialog_->input_labelwidth, FL_RETURN_CHANGED);
68 fl_set_input_return(dialog_->input_linespacing, FL_RETURN_CHANGED);
69 fl_set_input_filter(dialog_->input_linespacing, fl_unsigned_float_filter);
71 setPrehandler(dialog_->input_space_above);
72 setPrehandler(dialog_->input_space_below);
73 setPrehandler(dialog_->input_labelwidth);
74 setPrehandler(dialog_->input_linespacing);
76 // Create the contents of the unit choices
77 // Don't include the "%" terms...
78 vector<string> units_vec = getLatexUnits();
80 vector<string>::iterator del =
81 remove_if(units_vec.begin(), units_vec.end(),
82 bind2nd(contains_functor(), "%"));
83 units_vec.erase(del, units_vec.end());
85 string units = getStringFromVector(units_vec, "|");
87 fl_addto_choice(dialog_->choice_value_space_above, units.c_str());
88 fl_addto_choice(dialog_->choice_value_space_below, units.c_str());
90 // Manage the ok, apply, restore and cancel/close buttons
91 bc().setOK(dialog_->button_ok);
92 bc().setApply(dialog_->button_apply);
93 bc().setCancel(dialog_->button_close);
94 bc().setRestore(dialog_->button_restore);
96 bc().addReadOnly(dialog_->radio_align_right);
97 bc().addReadOnly(dialog_->radio_align_left);
98 bc().addReadOnly(dialog_->radio_align_block);
99 bc().addReadOnly(dialog_->radio_align_center);
100 bc().addReadOnly(dialog_->check_lines_top);
101 bc().addReadOnly(dialog_->check_lines_bottom);
102 bc().addReadOnly(dialog_->check_pagebreaks_top);
103 bc().addReadOnly(dialog_->check_pagebreaks_bottom);
104 bc().addReadOnly(dialog_->choice_space_above);
105 bc().addReadOnly(dialog_->input_space_above);
106 bc().addReadOnly(dialog_->check_space_above);
107 bc().addReadOnly(dialog_->choice_space_below);
108 bc().addReadOnly(dialog_->input_space_below);
109 bc().addReadOnly(dialog_->check_space_below);
110 bc().addReadOnly(dialog_->choice_linespacing);
111 bc().addReadOnly(dialog_->input_linespacing);
112 bc().addReadOnly(dialog_->check_noindent);
113 bc().addReadOnly(dialog_->input_labelwidth);
118 VSpace setVSpaceFromWidgets(FL_OBJECT * choice_type,
119 FL_OBJECT * input_length,
120 FL_OBJECT * choice_length,
121 FL_OBJECT * check_keep)
124 lyx::Assert(choice_type && choice_type->objclass == FL_CHOICE &&
125 input_length && input_length->objclass == FL_INPUT &&
126 choice_length && choice_length->objclass == FL_CHOICE &&
127 check_keep && check_keep->objclass == FL_CHECKBUTTON);
131 switch (fl_get_choice(choice_type)) {
133 space = VSpace(VSpace::NONE);
136 space = VSpace(VSpace::DEFSKIP);
139 space = VSpace(VSpace::SMALLSKIP);
142 space = VSpace(VSpace::MEDSKIP);
145 space = VSpace(VSpace::BIGSKIP);
148 space = VSpace(VSpace::VFILL);
152 string const length =
153 getLengthFromWidgets(input_length, choice_length);
154 space = VSpace(LyXGlueLength(length));
159 if (fl_get_button(check_keep))
165 void validateVSpaceWidgets(FL_OBJECT * choice_type, FL_OBJECT * input_length)
168 lyx::Assert(choice_type && choice_type->objclass == FL_CHOICE &&
169 input_length && input_length->objclass == FL_INPUT);
171 if (fl_get_choice(choice_type) != 7)
174 // If a vspace kind is "Length" but there's no text in
175 // the input field, reset the kind to "None".
176 string const input = rtrim(getString(input_length));
178 fl_set_choice(choice_type, 1);
183 void FormParagraph::apply()
188 // If a vspace kind is "Length" but there's no text in
189 // the input field, reset the kind to "None".
190 validateVSpaceWidgets(dialog_->choice_space_above,
191 dialog_->input_space_above);
193 VSpace const space_top =
194 setVSpaceFromWidgets(dialog_->choice_space_above,
195 dialog_->input_space_above,
196 dialog_->choice_value_space_above,
197 dialog_->check_space_above);
199 controller().params().spaceTop(space_top);
201 validateVSpaceWidgets(dialog_->choice_space_below,
202 dialog_->input_space_below);
204 VSpace const space_bottom =
205 setVSpaceFromWidgets(dialog_->choice_space_below,
206 dialog_->input_space_below,
207 dialog_->choice_value_space_below,
208 dialog_->check_space_below);
210 controller().params().spaceBottom(space_bottom);
212 /* lines and pagebreaks */
213 bool const line_top = fl_get_button(dialog_->check_lines_top);
214 controller().params().lineTop(line_top);
216 bool const line_bottom = fl_get_button(dialog_->check_lines_bottom);
217 controller().params().lineBottom(line_bottom);
219 bool const pagebreak_top = fl_get_button(dialog_->check_pagebreaks_top);
220 controller().params().pagebreakTop(pagebreak_top);
222 bool const pagebreak_bottom = fl_get_button(dialog_->check_pagebreaks_bottom);
223 controller().params().pagebreakBottom(pagebreak_bottom);
228 if (fl_get_button(dialog_->radio_align_left))
229 align = LYX_ALIGN_LEFT;
230 else if (fl_get_button(dialog_->radio_align_right))
231 align = LYX_ALIGN_RIGHT;
232 else if (fl_get_button(dialog_->radio_align_center))
233 align = LYX_ALIGN_CENTER;
235 align = LYX_ALIGN_BLOCK;
236 controller().params().align(align);
239 string const labelwidthstring =
240 getString(dialog_->input_labelwidth);
241 controller().params().labelWidthString(labelwidthstring);
244 bool const noindent = fl_get_button(dialog_->check_noindent);
245 controller().params().noindent(noindent);
248 Spacing::Space linespacing = Spacing::Default;
250 switch (fl_get_choice(dialog_->choice_linespacing)) {
252 linespacing = Spacing::Default;
255 linespacing = Spacing::Single;
258 linespacing = Spacing::Onehalf;
261 linespacing = Spacing::Double;
264 linespacing = Spacing::Other;
265 other = getString(dialog_->input_linespacing);
269 Spacing const spacing(linespacing, other);
270 controller().params().spacing(spacing);
276 void setWidgetsFromVSpace(VSpace const & space,
277 FL_OBJECT * choice_type,
278 FL_OBJECT * input_length,
279 FL_OBJECT * choice_length,
280 FL_OBJECT * check_keep)
283 lyx::Assert(choice_type && choice_type->objclass == FL_CHOICE &&
284 input_length && input_length->objclass == FL_INPUT &&
285 choice_length && choice_length->objclass == FL_CHOICE &&
286 check_keep && check_keep->objclass == FL_CHECKBUTTON);
288 fl_set_input(input_length, "");
289 setEnabled(input_length, false);
290 setEnabled(choice_length, false);
292 switch (space.kind()) {
294 fl_set_choice(choice_type, 1);
296 case VSpace::DEFSKIP:
297 fl_set_choice(choice_type, 2);
299 case VSpace::SMALLSKIP:
300 fl_set_choice(choice_type, 3);
302 case VSpace::MEDSKIP:
303 fl_set_choice(choice_type, 4);
305 case VSpace::BIGSKIP:
306 fl_set_choice(choice_type, 5);
309 fl_set_choice(choice_type, 6);
313 fl_set_choice(choice_type, 7);
315 setEnabled(input_length, true);
316 setEnabled(choice_length, true);
318 bool const metric = lyxrc.default_papersize > 3;
319 string const default_unit = metric ? "cm" : "in";
320 string const length = space.length().asString();
322 updateWidgetsFromLengthString(input_length, choice_length,
323 length, default_unit);
328 fl_set_button(check_keep, space.keep());
333 void FormParagraph::update()
339 string labelwidth = controller().params().labelWidthString();
340 fl_set_input(dialog_->input_labelwidth, labelwidth.c_str());
341 setEnabled(dialog_->input_labelwidth,
342 labelwidth != _("Senseless with this layout!"));
345 fl_set_button(dialog_->radio_align_right, 0);
346 fl_set_button(dialog_->radio_align_left, 0);
347 fl_set_button(dialog_->radio_align_center, 0);
348 fl_set_button(dialog_->radio_align_block, 0);
350 LyXAlignment align = controller().params().align();
353 case LYX_ALIGN_RIGHT:
354 fl_set_button(dialog_->radio_align_right, 1);
357 fl_set_button(dialog_->radio_align_left, 1);
359 case LYX_ALIGN_CENTER:
360 fl_set_button(dialog_->radio_align_center, 1);
363 fl_set_button(dialog_->radio_align_block, 1);
367 LyXAlignment alignpos = controller().alignPossible();
369 setEnabled(dialog_->radio_align_block, bool(alignpos & LYX_ALIGN_BLOCK));
370 setEnabled(dialog_->radio_align_center, bool(alignpos & LYX_ALIGN_CENTER));
371 setEnabled(dialog_->radio_align_left, bool(alignpos & LYX_ALIGN_LEFT));
372 setEnabled(dialog_->radio_align_right, bool(alignpos & LYX_ALIGN_RIGHT));
374 // no inset-text-owned paragraph may have pagebreaks
375 bool ininset = controller().inInset();
376 setEnabled(dialog_->check_pagebreaks_top, !ininset);
377 setEnabled(dialog_->check_pagebreaks_bottom, !ininset);
379 /* lines, pagebreaks and indent */
380 fl_set_button(dialog_->check_lines_top,
381 controller().params().lineTop());
382 fl_set_button(dialog_->check_lines_bottom,
383 controller().params().lineBottom());
384 fl_set_button(dialog_->check_pagebreaks_top,
385 controller().params().pagebreakTop());
386 fl_set_button(dialog_->check_pagebreaks_bottom,
387 controller().params().pagebreakBottom());
388 fl_set_button(dialog_->check_noindent,
389 controller().params().noindent());
393 Spacing const space = controller().params().spacing();
395 switch (space.getSpace()) {
396 default: linespacing = 1; break;
397 case Spacing::Single: linespacing = 2; break;
398 case Spacing::Onehalf: linespacing = 3; break;
399 case Spacing::Double: linespacing = 4; break;
400 case Spacing::Other: linespacing = 5; break;
403 fl_set_choice(dialog_->choice_linespacing, linespacing);
404 if (space.getSpace() == Spacing::Other) {
405 string const sp = tostr(space.getValue());
406 fl_set_input(dialog_->input_linespacing, sp.c_str());
407 setEnabled(dialog_->input_linespacing, true);
409 fl_set_input(dialog_->input_linespacing, "");
410 setEnabled(dialog_->input_linespacing, false);
414 setWidgetsFromVSpace(controller().params().spaceTop(),
415 dialog_->choice_space_above,
416 dialog_->input_space_above,
417 dialog_->choice_value_space_above,
418 dialog_->check_space_above);
421 setWidgetsFromVSpace(controller().params().spaceBottom(),
422 dialog_->choice_space_below,
423 dialog_->input_space_below,
424 dialog_->choice_value_space_below,
425 dialog_->check_space_below);
428 fl_set_button(dialog_->check_noindent,
429 controller().params().noindent());
434 void synchronizeSpaceWidgets(FL_OBJECT * choice_type,
435 FL_OBJECT * input_length,
436 FL_OBJECT * choice_length)
439 lyx::Assert(choice_type && choice_type->objclass == FL_CHOICE &&
440 input_length && input_length->objclass == FL_INPUT &&
441 choice_length && choice_length->objclass == FL_CHOICE);
443 if (fl_get_choice(choice_type) != 7) {
444 fl_set_input(input_length, "");
445 setEnabled(input_length, false);
446 setEnabled(choice_length, false);
449 setEnabled(input_length, true);
450 setEnabled(choice_length, true);
452 string const length = getString(input_length);
454 if (rtrim(length).empty()) {
455 bool const metric = lyxrc.default_papersize > 3;
456 int const default_unit = metric ? 8 : 9;
458 fl_set_choice(choice_length, default_unit);
463 bool validSpaceWidgets(FL_OBJECT * choice_type, FL_OBJECT * input_length)
466 lyx::Assert(choice_type && choice_type->objclass == FL_CHOICE &&
467 input_length && input_length->objclass == FL_INPUT);
469 if (fl_get_choice(choice_type) != 7)
472 string const input = getString(input_length);
473 return (input.empty() ||
474 isValidGlueLength(input) ||
480 ButtonPolicy::SMInput FormParagraph::input(FL_OBJECT * ob, long)
484 // First check the buttons which are exclusive and you have to
485 // check only the actuall de/activated button.
487 // "Synchronize" the choices and input fields, making it
488 // impossible to commit senseless data.
489 if (ob == dialog_->choice_space_above) {
490 synchronizeSpaceWidgets(dialog_->choice_space_above,
491 dialog_->input_space_above,
492 dialog_->choice_value_space_above);
495 if (ob == dialog_->choice_space_below) {
496 synchronizeSpaceWidgets(dialog_->choice_space_below,
497 dialog_->input_space_below,
498 dialog_->choice_value_space_below);
501 // Display a warning if the input is senseless
502 bool valid = (validSpaceWidgets(dialog_->choice_space_above,
503 dialog_->input_space_above) &&
504 validSpaceWidgets(dialog_->choice_space_below,
505 dialog_->input_space_below));
508 postWarning(_("Invalid Length (valid example: 10mm)"));
511 int const choice_spacing = fl_get_choice(dialog_->choice_linespacing);
513 if (choice_spacing == 5)
514 setEnabled(dialog_->input_linespacing, true);
516 fl_set_input(dialog_->input_linespacing, "");
517 setEnabled(dialog_->input_linespacing, false);
520 double const spacing =
521 strToDbl(getString(dialog_->input_linespacing));
523 if (choice_spacing == 5 && int(spacing) == 0)
526 return ButtonPolicy::SMI_VALID;