2 * \file FormParagraph.C
3 * See the file COPYING.
7 * Full author contact details are available in file CREDITS
13 #pragma implementation
16 #include FORMS_H_LOCATION
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"
28 #include "layout.h" // LyXAlignment
30 #include "support/lstrings.h"
31 #include "support/LAssert.h"
32 #include FORMS_H_LOCATION
40 typedef FormCB<ControlParagraph, FormDB<FD_paragraph> > base_class;
42 FormParagraph::FormParagraph()
43 : base_class(_("Paragraph Layout"), false)
46 void FormParagraph::build()
49 dialog_.reset(build_paragraph(this));
51 // Allow the base class to control messages
52 setMessageWidget(dialog_->text_warning);
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 "));
61 fl_addto_choice(dialog_->choice_linespacing,
62 _(" Default | Single | OneHalf | Double | Custom "));
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);
70 setPrehandler(dialog_->input_space_above);
71 setPrehandler(dialog_->input_space_below);
72 setPrehandler(dialog_->input_labelwidth);
73 setPrehandler(dialog_->input_linespacing);
75 // Create the contents of the unit choices
76 // Don't include the "%" terms...
77 vector<string> units_vec = getLatexUnits();
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());
84 string units = getStringFromVector(units_vec, "|");
86 fl_addto_choice(dialog_->choice_value_space_above, units.c_str());
87 fl_addto_choice(dialog_->choice_value_space_below, units.c_str());
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);
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);
117 VSpace setVSpaceFromWidgets(FL_OBJECT * choice_type,
118 FL_OBJECT * input_length,
119 FL_OBJECT * choice_length,
120 FL_OBJECT * check_keep)
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);
130 switch (fl_get_choice(choice_type)) {
132 space = VSpace(VSpace::NONE);
135 space = VSpace(VSpace::DEFSKIP);
138 space = VSpace(VSpace::SMALLSKIP);
141 space = VSpace(VSpace::MEDSKIP);
144 space = VSpace(VSpace::BIGSKIP);
147 space = VSpace(VSpace::VFILL);
151 string const length =
152 getLengthFromWidgets(input_length, choice_length);
153 space = VSpace(LyXGlueLength(length));
158 if (fl_get_button(check_keep))
164 void validateVSpaceWidgets(FL_OBJECT * choice_type, FL_OBJECT * input_length)
167 lyx::Assert(choice_type && choice_type->objclass == FL_CHOICE &&
168 input_length && input_length->objclass == FL_INPUT);
170 if (fl_get_choice(choice_type) != 7)
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));
177 fl_set_choice(choice_type, 1);
182 void FormParagraph::apply()
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);
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);
198 controller().params().spaceTop(space_top);
200 validateVSpaceWidgets(dialog_->choice_space_below,
201 dialog_->input_space_below);
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);
209 controller().params().spaceBottom(space_bottom);
211 /* lines and pagebreaks */
212 bool const line_top = fl_get_button(dialog_->check_lines_top);
213 controller().params().lineTop(line_top);
215 bool const line_bottom = fl_get_button(dialog_->check_lines_bottom);
216 controller().params().lineBottom(line_bottom);
218 bool const pagebreak_top = fl_get_button(dialog_->check_pagebreaks_top);
219 controller().params().pagebreakTop(pagebreak_top);
221 bool const pagebreak_bottom = fl_get_button(dialog_->check_pagebreaks_bottom);
222 controller().params().pagebreakBottom(pagebreak_bottom);
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;
234 align = LYX_ALIGN_BLOCK;
235 controller().params().align(align);
238 string const labelwidthstring =
239 getString(dialog_->input_labelwidth);
240 controller().params().labelWidthString(labelwidthstring);
243 bool const noindent = fl_get_button(dialog_->check_noindent);
244 controller().params().noindent(noindent);
247 Spacing::Space linespacing = Spacing::Default;
249 switch (fl_get_choice(dialog_->choice_linespacing)) {
251 linespacing = Spacing::Default;
254 linespacing = Spacing::Single;
257 linespacing = Spacing::Onehalf;
260 linespacing = Spacing::Double;
263 linespacing = Spacing::Other;
264 other = getString(dialog_->input_linespacing);
268 Spacing const spacing(linespacing, other);
269 controller().params().spacing(spacing);
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)
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);
287 fl_set_input(input_length, "");
288 setEnabled(input_length, false);
289 setEnabled(choice_length, false);
291 switch (space.kind()) {
293 fl_set_choice(choice_type, 1);
295 case VSpace::DEFSKIP:
296 fl_set_choice(choice_type, 2);
298 case VSpace::SMALLSKIP:
299 fl_set_choice(choice_type, 3);
301 case VSpace::MEDSKIP:
302 fl_set_choice(choice_type, 4);
304 case VSpace::BIGSKIP:
305 fl_set_choice(choice_type, 5);
308 fl_set_choice(choice_type, 6);
312 fl_set_choice(choice_type, 7);
314 setEnabled(input_length, true);
315 setEnabled(choice_length, true);
317 bool const metric = lyxrc.default_papersize > 3;
318 string const default_unit = metric ? "cm" : "in";
319 string const length = space.length().asString();
321 updateWidgetsFromLengthString(input_length, choice_length,
322 length, default_unit);
327 fl_set_button(check_keep, space.keep());
332 void FormParagraph::update()
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!"));
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);
349 LyXAlignment align = controller().params().align();
352 case LYX_ALIGN_RIGHT:
353 fl_set_button(dialog_->radio_align_right, 1);
356 fl_set_button(dialog_->radio_align_left, 1);
358 case LYX_ALIGN_CENTER:
359 fl_set_button(dialog_->radio_align_center, 1);
362 fl_set_button(dialog_->radio_align_block, 1);
366 LyXAlignment alignpos = controller().alignPossible();
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));
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);
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());
392 Spacing const space = controller().params().spacing();
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;
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);
408 fl_set_input(dialog_->input_linespacing, "");
409 setEnabled(dialog_->input_linespacing, false);
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);
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);
427 fl_set_button(dialog_->check_noindent,
428 controller().params().noindent());
433 void synchronizeSpaceWidgets(FL_OBJECT * choice_type,
434 FL_OBJECT * input_length,
435 FL_OBJECT * choice_length)
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);
442 if (fl_get_choice(choice_type) != 7) {
443 fl_set_input(input_length, "");
444 setEnabled(input_length, false);
445 setEnabled(choice_length, false);
448 setEnabled(input_length, true);
449 setEnabled(choice_length, true);
451 string const length = getString(input_length);
453 if (rtrim(length).empty()) {
454 bool const metric = lyxrc.default_papersize > 3;
455 int const default_unit = metric ? 8 : 9;
457 fl_set_choice(choice_length, default_unit);
462 bool validSpaceWidgets(FL_OBJECT * choice_type, FL_OBJECT * input_length)
465 lyx::Assert(choice_type && choice_type->objclass == FL_CHOICE &&
466 input_length && input_length->objclass == FL_INPUT);
468 if (fl_get_choice(choice_type) != 7)
471 string const input = getString(input_length);
472 return (input.empty() ||
473 isValidGlueLength(input) ||
479 ButtonPolicy::SMInput FormParagraph::input(FL_OBJECT * ob, long)
483 // First check the buttons which are exclusive and you have to
484 // check only the actuall de/activated button.
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);
494 if (ob == dialog_->choice_space_below) {
495 synchronizeSpaceWidgets(dialog_->choice_space_below,
496 dialog_->input_space_below,
497 dialog_->choice_value_space_below);
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));
507 postWarning(_("Invalid Length (valid example: 10mm)"));
510 int const choice_spacing = fl_get_choice(dialog_->choice_linespacing);
512 if (choice_spacing == 5)
513 setEnabled(dialog_->input_linespacing, true);
515 fl_set_input(dialog_->input_linespacing, "");
516 setEnabled(dialog_->input_linespacing, false);
519 double const spacing =
520 strToDbl(getString(dialog_->input_linespacing));
522 if (choice_spacing == 5 && int(spacing) == 0)
525 return ButtonPolicy::SMI_VALID;