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"
29 #include "support/LAssert.h"
30 #include "support/lstrings.h"
31 #include "support/tostr.h"
33 #include "lyx_forms.h"
35 using namespace lyx::support;
45 string defaultUnit("cm");
47 void validateVSpaceWidgets(FL_OBJECT * choice_type, FL_OBJECT * input_length);
49 VSpace const setVSpaceFromWidgets(FL_OBJECT * choice_type,
50 FL_OBJECT * input_length,
51 FL_OBJECT * choice_length,
52 FL_OBJECT * check_keep);
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);
63 typedef FormController<ControlParagraph, FormView<FD_paragraph> > base_class;
65 FormParagraph::FormParagraph(Dialog & parent)
66 : base_class(parent, _("Paragraph Settings"))
70 void FormParagraph::build()
73 dialog_.reset(build_paragraph(this));
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);
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);
88 bcview().addReadOnly(dialog_->check_noindent);
89 bcview().addReadOnly(dialog_->choice_linespacing);
90 bcview().addReadOnly(dialog_->input_linespacing);
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);
98 bcview().addReadOnly(dialog_->input_labelwidth);
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);
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);
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);
119 // limit these inputs to unsigned floats
120 fl_set_input_filter(dialog_->input_linespacing, fl_unsigned_float_filter);
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);
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());
132 string const linespacing = _("Default|Single|OneHalf|Double|Custom");
133 fl_addto_choice(dialog_->choice_linespacing, linespacing.c_str());
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());
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());
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);
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);
165 // set default unit for custom length
166 switch (lyxrc.default_papersize) {
169 case PAPER_LEGALPAPER:
170 case PAPER_EXECUTIVEPAPER:
183 void FormParagraph::apply()
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);
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);
199 controller().params().spaceTop(space_above);
201 validateVSpaceWidgets(dialog_->choice_space_below,
202 dialog_->input_space_below);
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);
210 controller().params().spaceBottom(space_below);
212 // lines and pagebreaks
213 bool const line_above = fl_get_button(dialog_->check_line_above);
214 controller().params().lineTop(line_above);
216 bool const line_below = fl_get_button(dialog_->check_line_below);
217 controller().params().lineBottom(line_below);
219 bool const pagebreak_above =
220 fl_get_button(dialog_->check_pagebreak_above);
221 controller().params().pagebreakTop(pagebreak_above);
223 bool const pagebreak_below =
224 fl_get_button(dialog_->check_pagebreak_below);
225 controller().params().pagebreakBottom(pagebreak_below);
229 LyXAlignment const alignment =
230 static_cast<LyXAlignment>(alignment_.get());
231 controller().params().align(alignment);
234 string const labelwidthstring =
235 getString(dialog_->input_labelwidth);
236 controller().params().labelWidthString(labelwidthstring);
239 bool const noindent = fl_get_button(dialog_->check_noindent);
240 controller().params().noindent(noindent);
243 Spacing::Space linespacing = Spacing::Default;
245 switch (fl_get_choice(dialog_->choice_linespacing)) {
247 linespacing = Spacing::Default;
250 linespacing = Spacing::Single;
253 linespacing = Spacing::Onehalf;
256 linespacing = Spacing::Double;
259 // reset to default if input is empty
260 other = getString(dialog_->input_linespacing);
261 if (!other.empty()) {
262 linespacing = Spacing::Other;
264 linespacing = Spacing::Default;
265 fl_set_choice(dialog_->choice_linespacing, 1);
269 Spacing const spacing(linespacing, other);
270 controller().params().spacing(spacing);
274 void FormParagraph::update()
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!"));
286 alignment_.set(controller().params().align());
288 // mark default alignment
289 LyXAlignment const default_alignment = controller().alignDefault();
291 string label = _("Block");
292 if (default_alignment == LYX_ALIGN_BLOCK) {
293 label += _(" (default)");
295 fl_set_object_label(dialog_->radio_align_block, label.c_str());
296 fl_set_button_shortcut(dialog_->radio_align_block, "#B", 1);
299 if (default_alignment == LYX_ALIGN_CENTER) {
300 label += _(" (default)");
302 fl_set_object_label(dialog_->radio_align_center, label.c_str());
303 fl_set_button_shortcut(dialog_->radio_align_center, "#C", 1);
306 if (default_alignment == LYX_ALIGN_LEFT) {
307 label += _(" (default)");
309 fl_set_object_label(dialog_->radio_align_left, label.c_str());
310 fl_set_button_shortcut(dialog_->radio_align_left, "#L", 1);
313 if (default_alignment == LYX_ALIGN_RIGHT) {
314 label = _(" (default)");
316 fl_set_object_label(dialog_->radio_align_right, label.c_str());
317 fl_set_button_shortcut(dialog_->radio_align_right, "#R", 1);
319 // Ensure that there's no crud left on the screen from this change
321 fl_redraw_form(form());
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));
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);
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());
351 Spacing const space = controller().params().spacing();
354 switch (space.getSpace()) {
358 case Spacing::Double:
361 case Spacing::Onehalf:
364 case Spacing::Single:
367 case Spacing::Default:
372 fl_set_choice(dialog_->choice_linespacing, pos);
374 bool const spacing_other = space.getSpace() == Spacing::Other;
375 setEnabled(dialog_->input_linespacing, spacing_other);
377 string const sp = tostr(space.getValue());
378 fl_set_input(dialog_->input_linespacing, sp.c_str());
380 fl_set_input(dialog_->input_linespacing, "");
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);
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);
398 fl_set_button(dialog_->check_noindent,
399 controller().params().noindent());
403 ButtonPolicy::SMInput FormParagraph::input(FL_OBJECT * ob, long)
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);
414 fl_get_choice(dialog_->choice_space_above) != 1;
415 setEnabled(dialog_->check_space_above, space);
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);
424 fl_get_choice(dialog_->choice_space_below) != 1;
425 setEnabled(dialog_->check_space_below, space);
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);
433 return ButtonPolicy::SMI_VALID;
439 void validateVSpaceWidgets(FL_OBJECT * choice_type, FL_OBJECT * input_length)
442 Assert(choice_type && choice_type->objclass == FL_CHOICE &&
443 input_length && input_length->objclass == FL_INPUT);
445 if (fl_get_choice(choice_type) != 7)
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));
452 fl_set_choice(choice_type, 1);
456 VSpace const setVSpaceFromWidgets(FL_OBJECT * choice_type,
457 FL_OBJECT * input_length,
458 FL_OBJECT * choice_length,
459 FL_OBJECT * check_keep)
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);
468 switch (fl_get_choice(choice_type)) {
470 space = VSpace(VSpace::NONE);
473 space = VSpace(VSpace::DEFSKIP);
476 space = VSpace(VSpace::SMALLSKIP);
479 space = VSpace(VSpace::MEDSKIP);
482 space = VSpace(VSpace::BIGSKIP);
485 space = VSpace(VSpace::VFILL);
489 string const length =
490 getLengthFromWidgets(input_length, choice_length);
491 space = VSpace(LyXGlueLength(length));
496 if (fl_get_button(check_keep))
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)
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);
515 fl_set_button(check_keep, space.keep());
518 switch (space.kind()) {
522 case VSpace::DEFSKIP:
525 case VSpace::SMALLSKIP:
528 case VSpace::MEDSKIP:
531 case VSpace::BIGSKIP:
541 fl_set_choice(choice_type, pos);
543 bool const custom_vspace = space.kind() == VSpace::LENGTH;
544 setEnabled(input_length, custom_vspace);
545 setEnabled(choice_length, custom_vspace);
547 string const length = space.length().asString();
548 updateWidgetsFromLengthString(input_length, choice_length,
549 length, defaultUnit);
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());