2 * \file FormParagraph.C
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
9 * Full author contact details are available in file CREDITS.
14 #include "FormParagraph.h"
15 #include "ControlParagraph.h"
16 #include "forms/form_paragraph.h"
18 #include "checkedwidgets.h"
19 #include "input_validators.h"
21 #include "xforms_helpers.h"
24 #include "controllers/helper_funcs.h"
26 #include "lyxrc.h" // to set the deafult length values
27 #include "ParagraphParameters.h"
31 #include "support/LAssert.h"
32 #include "support/lstrings.h"
33 #include "support/tostr.h"
35 #include "lyx_forms.h"
37 using namespace lyx::support;
47 string defaultUnit("cm");
49 void validateVSpaceWidgets(FL_OBJECT * choice_type, FL_OBJECT * input_length);
51 VSpace const setVSpaceFromWidgets(FL_OBJECT * choice_type,
52 FL_OBJECT * input_length,
53 FL_OBJECT * choice_length,
54 FL_OBJECT * check_keep);
56 void setWidgetsFromVSpace(VSpace const & space,
57 FL_OBJECT * choice_type,
58 FL_OBJECT * input_length,
59 FL_OBJECT * choice_length,
60 FL_OBJECT * check_keep);
65 typedef FormController<ControlParagraph, FormView<FD_paragraph> > base_class;
67 FormParagraph::FormParagraph(Dialog & parent)
68 : base_class(parent, _("Paragraph Settings"))
72 void FormParagraph::build()
75 dialog_.reset(build_paragraph(this));
77 // Manage the ok, apply, restore and cancel/close buttons
78 bcview().setOK(dialog_->button_ok);
79 bcview().setApply(dialog_->button_apply);
80 bcview().setCancel(dialog_->button_close);
81 bcview().setRestore(dialog_->button_restore);
83 // disable for read-only documents
84 bcview().addReadOnly(dialog_->check_line_above);
85 bcview().addReadOnly(dialog_->check_pagebreak_above);
86 bcview().addReadOnly(dialog_->choice_space_above);
87 bcview().addReadOnly(dialog_->input_space_above);
88 bcview().addReadOnly(dialog_->check_space_above);
90 bcview().addReadOnly(dialog_->check_noindent);
91 bcview().addReadOnly(dialog_->choice_linespacing);
92 bcview().addReadOnly(dialog_->input_linespacing);
94 bcview().addReadOnly(dialog_->check_line_below);
95 bcview().addReadOnly(dialog_->check_pagebreak_below);
96 bcview().addReadOnly(dialog_->choice_space_below);
97 bcview().addReadOnly(dialog_->input_space_below);
98 bcview().addReadOnly(dialog_->check_space_below);
100 bcview().addReadOnly(dialog_->input_labelwidth);
102 // check validity of "length + unit" input
103 addCheckedGlueLength(bcview(),
104 dialog_->input_space_above,
105 dialog_->choice_space_above);
106 addCheckedGlueLength(bcview(),
107 dialog_->input_space_below,
108 dialog_->choice_space_below);
110 // trigger an input event for cut&paste with middle mouse button.
111 setPrehandler(dialog_->input_space_above);
112 setPrehandler(dialog_->input_space_below);
113 setPrehandler(dialog_->input_linespacing);
114 setPrehandler(dialog_->input_labelwidth);
116 fl_set_input_return(dialog_->input_space_above, FL_RETURN_CHANGED);
117 fl_set_input_return(dialog_->input_space_below, FL_RETURN_CHANGED);
118 fl_set_input_return(dialog_->input_labelwidth, FL_RETURN_CHANGED);
119 fl_set_input_return(dialog_->input_linespacing, FL_RETURN_CHANGED);
121 // limit these inputs to unsigned floats
122 fl_set_input_filter(dialog_->input_linespacing, fl_unsigned_float_filter);
124 // add alignment radio buttons
125 alignment_.init(dialog_->radio_align_left, LYX_ALIGN_LEFT);
126 alignment_.init(dialog_->radio_align_right, LYX_ALIGN_RIGHT);
127 alignment_.init(dialog_->radio_align_block, LYX_ALIGN_BLOCK);
128 alignment_.init(dialog_->radio_align_center, LYX_ALIGN_CENTER);
130 string const parspacing = _("None|DefSkip|SmallSkip|MedSkip|BigSkip|VFill|Length");
131 fl_addto_choice(dialog_->choice_space_above, parspacing.c_str());
132 fl_addto_choice(dialog_->choice_space_below, parspacing.c_str());
134 string const linespacing = _("Default|Single|OneHalf|Double|Custom");
135 fl_addto_choice(dialog_->choice_linespacing, linespacing.c_str());
137 // Create the contents of the unit choices; don't include the "%" terms.
138 vector<string> units_vec = getLatexUnits();
139 vector<string>::iterator del =
140 remove_if(units_vec.begin(), units_vec.end(),
141 bind2nd(contains_functor(), "%"));
142 units_vec.erase(del, units_vec.end());
144 string const units = getStringFromVector(units_vec, "|");
145 fl_addto_choice(dialog_->choice_unit_space_above, units.c_str());
146 fl_addto_choice(dialog_->choice_unit_space_below, units.c_str());
148 // set up the tooltips
149 string str = _("Add a separator line above this paragraph.");
150 tooltips().init(dialog_->check_line_above, str);
151 str = _("Enforce a page break above this paragraph.");
152 tooltips().init(dialog_->check_pagebreak_above, str);
153 str = _("Add additional space above this paragraph.");
154 tooltips().init(dialog_->choice_space_above, str);
155 str = _("Never suppress space (e.g. at top of page or new page).");
156 tooltips().init(dialog_->check_space_above, str);
158 str = _("Add a separator line below this paragraph.");
159 tooltips().init(dialog_->check_line_below, str);
160 str = _("Enforce a page break below this paragraph.");
161 tooltips().init(dialog_->check_pagebreak_below, str);
162 str = _("Add additional space below this paragraph.");
163 tooltips().init(dialog_->choice_space_below, str);
164 str = _("Never suppress space (e.g. at bottom of page or new page).");
165 tooltips().init(dialog_->check_space_below, str);
167 // set default unit for custom length
168 switch (lyxrc.default_papersize) {
171 case PAPER_LEGALPAPER:
172 case PAPER_EXECUTIVEPAPER:
185 void FormParagraph::apply()
190 // If a vspace choice is "Length" but there's no text in
191 // the input field, reset the choice to "None".
192 validateVSpaceWidgets(dialog_->choice_space_above,
193 dialog_->input_space_above);
195 VSpace const space_above =
196 setVSpaceFromWidgets(dialog_->choice_space_above,
197 dialog_->input_space_above,
198 dialog_->choice_unit_space_above,
199 dialog_->check_space_above);
201 controller().params().spaceTop(space_above);
203 validateVSpaceWidgets(dialog_->choice_space_below,
204 dialog_->input_space_below);
206 VSpace const space_below =
207 setVSpaceFromWidgets(dialog_->choice_space_below,
208 dialog_->input_space_below,
209 dialog_->choice_unit_space_below,
210 dialog_->check_space_below);
212 controller().params().spaceBottom(space_below);
214 // lines and pagebreaks
215 bool const line_above = fl_get_button(dialog_->check_line_above);
216 controller().params().lineTop(line_above);
218 bool const line_below = fl_get_button(dialog_->check_line_below);
219 controller().params().lineBottom(line_below);
221 bool const pagebreak_above =
222 fl_get_button(dialog_->check_pagebreak_above);
223 controller().params().pagebreakTop(pagebreak_above);
225 bool const pagebreak_below =
226 fl_get_button(dialog_->check_pagebreak_below);
227 controller().params().pagebreakBottom(pagebreak_below);
231 LyXAlignment const alignment =
232 static_cast<LyXAlignment>(alignment_.get());
233 controller().params().align(alignment);
236 string const labelwidthstring =
237 getString(dialog_->input_labelwidth);
238 controller().params().labelWidthString(labelwidthstring);
241 bool const noindent = fl_get_button(dialog_->check_noindent);
242 controller().params().noindent(noindent);
245 Spacing::Space linespacing = Spacing::Default;
247 switch (fl_get_choice(dialog_->choice_linespacing)) {
249 linespacing = Spacing::Default;
252 linespacing = Spacing::Single;
255 linespacing = Spacing::Onehalf;
258 linespacing = Spacing::Double;
261 // reset to default if input is empty
262 other = getString(dialog_->input_linespacing);
263 if (!other.empty()) {
264 linespacing = Spacing::Other;
266 linespacing = Spacing::Default;
267 fl_set_choice(dialog_->choice_linespacing, 1);
271 Spacing const spacing(linespacing, other);
272 controller().params().spacing(spacing);
276 void FormParagraph::update()
282 string const labelwidth = controller().params().labelWidthString();
283 fl_set_input(dialog_->input_labelwidth, labelwidth.c_str());
284 setEnabled(dialog_->input_labelwidth,
285 labelwidth != _("Senseless with this layout!"));
288 alignment_.set(controller().params().align());
290 // mark default alignment
291 LyXAlignment const default_alignment = controller().alignDefault();
293 string label = _("Block");
294 if (default_alignment == LYX_ALIGN_BLOCK) {
295 label += _(" (default)");
297 fl_set_object_label(dialog_->radio_align_block, label.c_str());
298 fl_set_button_shortcut(dialog_->radio_align_block, "#B", 1);
301 if (default_alignment == LYX_ALIGN_CENTER) {
302 label += _(" (default)");
304 fl_set_object_label(dialog_->radio_align_center, label.c_str());
305 fl_set_button_shortcut(dialog_->radio_align_center, "#C", 1);
308 if (default_alignment == LYX_ALIGN_LEFT) {
309 label += _(" (default)");
311 fl_set_object_label(dialog_->radio_align_left, label.c_str());
312 fl_set_button_shortcut(dialog_->radio_align_left, "#L", 1);
315 if (default_alignment == LYX_ALIGN_RIGHT) {
316 label = _(" (default)");
318 fl_set_object_label(dialog_->radio_align_right, label.c_str());
319 fl_set_button_shortcut(dialog_->radio_align_right, "#R", 1);
321 // Ensure that there's no crud left on the screen from this change
323 fl_redraw_form(form());
325 LyXAlignment alignpos = controller().alignPossible();
326 setEnabled(dialog_->radio_align_block,
327 bool(alignpos & LYX_ALIGN_BLOCK));
328 setEnabled(dialog_->radio_align_center,
329 bool(alignpos & LYX_ALIGN_CENTER));
330 setEnabled(dialog_->radio_align_left,
331 bool(alignpos & LYX_ALIGN_LEFT));
332 setEnabled(dialog_->radio_align_right,
333 bool(alignpos & LYX_ALIGN_RIGHT));
335 // no inset-text-owned paragraph may have pagebreaks
336 bool ininset = controller().inInset();
337 setEnabled(dialog_->check_pagebreak_above, !ininset);
338 setEnabled(dialog_->check_pagebreak_below, !ininset);
340 // lines, pagebreaks and indent
341 fl_set_button(dialog_->check_line_above,
342 controller().params().lineTop());
343 fl_set_button(dialog_->check_line_below,
344 controller().params().lineBottom());
345 fl_set_button(dialog_->check_pagebreak_above,
346 controller().params().pagebreakTop());
347 fl_set_button(dialog_->check_pagebreak_below,
348 controller().params().pagebreakBottom());
349 fl_set_button(dialog_->check_noindent,
350 controller().params().noindent());
353 Spacing const space = controller().params().spacing();
356 switch (space.getSpace()) {
360 case Spacing::Double:
363 case Spacing::Onehalf:
366 case Spacing::Single:
369 case Spacing::Default:
374 fl_set_choice(dialog_->choice_linespacing, pos);
376 bool const spacing_other = space.getSpace() == Spacing::Other;
377 setEnabled(dialog_->input_linespacing, spacing_other);
379 string const sp = tostr(space.getValue());
380 fl_set_input(dialog_->input_linespacing, sp.c_str());
382 fl_set_input(dialog_->input_linespacing, "");
386 setWidgetsFromVSpace(controller().params().spaceTop(),
387 dialog_->choice_space_above,
388 dialog_->input_space_above,
389 dialog_->choice_unit_space_above,
390 dialog_->check_space_above);
393 setWidgetsFromVSpace(controller().params().spaceBottom(),
394 dialog_->choice_space_below,
395 dialog_->input_space_below,
396 dialog_->choice_unit_space_below,
397 dialog_->check_space_below);
400 fl_set_button(dialog_->check_noindent,
401 controller().params().noindent());
405 ButtonPolicy::SMInput FormParagraph::input(FL_OBJECT * ob, long)
407 // Enable input when custum length is choosen,
408 // disable 'keep' when no space is choosen
409 if (ob == dialog_->choice_space_above) {
410 bool const custom_length =
411 fl_get_choice(dialog_->choice_space_above) == 7;
412 setEnabled(dialog_->input_space_above, custom_length);
413 setEnabled(dialog_->choice_unit_space_above, custom_length);
416 fl_get_choice(dialog_->choice_space_above) != 1;
417 setEnabled(dialog_->check_space_above, space);
419 } else if (ob == dialog_->choice_space_below) {
420 bool const custom_length =
421 fl_get_choice(dialog_->choice_space_below) == 7;
422 setEnabled(dialog_->input_space_below, custom_length);
423 setEnabled(dialog_->choice_unit_space_below, custom_length);
426 fl_get_choice(dialog_->choice_space_below) != 1;
427 setEnabled(dialog_->check_space_below, space);
429 } else if (ob == dialog_->choice_linespacing) {
430 bool const custom_spacing =
431 fl_get_choice(dialog_->choice_linespacing) == 5;
432 setEnabled(dialog_->input_linespacing, custom_spacing);
435 return ButtonPolicy::SMI_VALID;
441 void validateVSpaceWidgets(FL_OBJECT * choice_type, FL_OBJECT * input_length)
444 Assert(choice_type && choice_type->objclass == FL_CHOICE &&
445 input_length && input_length->objclass == FL_INPUT);
447 if (fl_get_choice(choice_type) != 7)
450 // If a vspace kind is "Length" but there's no text in
451 // the input field, reset the kind to "None".
452 string const input = rtrim(getString(input_length));
454 fl_set_choice(choice_type, 1);
458 VSpace const setVSpaceFromWidgets(FL_OBJECT * choice_type,
459 FL_OBJECT * input_length,
460 FL_OBJECT * choice_length,
461 FL_OBJECT * check_keep)
464 Assert(choice_type && choice_type->objclass == FL_CHOICE &&
465 input_length && input_length->objclass == FL_INPUT &&
466 choice_length && choice_length->objclass == FL_CHOICE &&
467 check_keep && check_keep->objclass == FL_CHECKBUTTON);
470 switch (fl_get_choice(choice_type)) {
472 space = VSpace(VSpace::NONE);
475 space = VSpace(VSpace::DEFSKIP);
478 space = VSpace(VSpace::SMALLSKIP);
481 space = VSpace(VSpace::MEDSKIP);
484 space = VSpace(VSpace::BIGSKIP);
487 space = VSpace(VSpace::VFILL);
491 string const length =
492 getLengthFromWidgets(input_length, choice_length);
493 space = VSpace(LyXGlueLength(length));
498 if (fl_get_button(check_keep))
505 void setWidgetsFromVSpace(VSpace const & space,
506 FL_OBJECT * choice_type,
507 FL_OBJECT * input_length,
508 FL_OBJECT * choice_length,
509 FL_OBJECT * check_keep)
512 Assert(choice_type && choice_type->objclass == FL_CHOICE &&
513 input_length && input_length->objclass == FL_INPUT &&
514 choice_length && choice_length->objclass == FL_CHOICE &&
515 check_keep && check_keep->objclass == FL_CHECKBUTTON);
517 fl_set_button(check_keep, space.keep());
520 switch (space.kind()) {
524 case VSpace::DEFSKIP:
527 case VSpace::SMALLSKIP:
530 case VSpace::MEDSKIP:
533 case VSpace::BIGSKIP:
543 fl_set_choice(choice_type, pos);
545 bool const custom_vspace = space.kind() == VSpace::LENGTH;
546 setEnabled(input_length, custom_vspace);
547 setEnabled(choice_length, custom_vspace);
549 string const length = space.length().asString();
550 updateWidgetsFromLengthString(input_length, choice_length,
551 length, defaultUnit);
553 bool const no_vspace = space.kind() == VSpace::NONE;
554 setEnabled(check_keep, !no_vspace);
555 fl_set_input(input_length, "");
556 fl_set_choice_text(choice_length, defaultUnit.c_str());