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/lstrings.h"
32 #include "support/tostr.h"
34 #include "lyx_forms.h"
36 using lyx::support::contains_functor;
37 using lyx::support::getStringFromVector;
38 using lyx::support::rtrim;
50 string defaultUnit("cm");
52 void validateVSpaceWidgets(FL_OBJECT * choice_type, FL_OBJECT * input_length);
54 VSpace const setVSpaceFromWidgets(FL_OBJECT * choice_type,
55 FL_OBJECT * input_length,
56 FL_OBJECT * choice_length,
57 FL_OBJECT * check_keep);
59 void setWidgetsFromVSpace(VSpace const & space,
60 FL_OBJECT * choice_type,
61 FL_OBJECT * input_length,
62 FL_OBJECT * choice_length,
63 FL_OBJECT * check_keep);
68 typedef FormController<ControlParagraph, FormView<FD_paragraph> > base_class;
70 FormParagraph::FormParagraph(Dialog & parent)
71 : base_class(parent, _("Paragraph Settings"))
75 void FormParagraph::build()
78 dialog_.reset(build_paragraph(this));
80 // Manage the ok, apply, restore and cancel/close buttons
81 bcview().setOK(dialog_->button_ok);
82 bcview().setApply(dialog_->button_apply);
83 bcview().setCancel(dialog_->button_close);
84 bcview().setRestore(dialog_->button_restore);
86 // disable for read-only documents
87 bcview().addReadOnly(dialog_->choice_space_above);
88 bcview().addReadOnly(dialog_->input_space_above);
89 bcview().addReadOnly(dialog_->check_space_above);
91 bcview().addReadOnly(dialog_->check_noindent);
92 bcview().addReadOnly(dialog_->choice_linespacing);
93 bcview().addReadOnly(dialog_->input_linespacing);
95 bcview().addReadOnly(dialog_->choice_space_below);
96 bcview().addReadOnly(dialog_->input_space_below);
97 bcview().addReadOnly(dialog_->check_space_below);
99 bcview().addReadOnly(dialog_->input_labelwidth);
101 // check validity of "length + unit" input
102 addCheckedGlueLength(bcview(),
103 dialog_->input_space_above,
104 dialog_->choice_space_above);
105 addCheckedGlueLength(bcview(),
106 dialog_->input_space_below,
107 dialog_->choice_space_below);
109 // trigger an input event for cut&paste with middle mouse button.
110 setPrehandler(dialog_->input_space_above);
111 setPrehandler(dialog_->input_space_below);
112 setPrehandler(dialog_->input_linespacing);
113 setPrehandler(dialog_->input_labelwidth);
115 fl_set_input_return(dialog_->input_space_above, FL_RETURN_CHANGED);
116 fl_set_input_return(dialog_->input_space_below, FL_RETURN_CHANGED);
117 fl_set_input_return(dialog_->input_labelwidth, FL_RETURN_CHANGED);
118 fl_set_input_return(dialog_->input_linespacing, FL_RETURN_CHANGED);
120 // limit these inputs to unsigned floats
121 fl_set_input_filter(dialog_->input_linespacing, fl_unsigned_float_filter);
123 // add alignment radio buttons
124 alignment_.init(dialog_->radio_align_left, LYX_ALIGN_LEFT);
125 alignment_.init(dialog_->radio_align_right, LYX_ALIGN_RIGHT);
126 alignment_.init(dialog_->radio_align_block, LYX_ALIGN_BLOCK);
127 alignment_.init(dialog_->radio_align_center, LYX_ALIGN_CENTER);
129 string const parspacing = _("None|DefSkip|SmallSkip|MedSkip|BigSkip|VFill|Length");
130 fl_addto_choice(dialog_->choice_space_above, parspacing.c_str());
131 fl_addto_choice(dialog_->choice_space_below, parspacing.c_str());
133 string const linespacing = _("Default|Single|OneHalf|Double|Custom");
134 fl_addto_choice(dialog_->choice_linespacing, linespacing.c_str());
136 // Create the contents of the unit choices; don't include the "%" terms.
137 vector<string> units_vec = getLatexUnits();
138 vector<string>::iterator del =
139 remove_if(units_vec.begin(), units_vec.end(),
140 bind2nd(contains_functor(), "%"));
141 units_vec.erase(del, units_vec.end());
143 string const units = getStringFromVector(units_vec, "|");
144 fl_addto_choice(dialog_->choice_unit_space_above, units.c_str());
145 fl_addto_choice(dialog_->choice_unit_space_below, units.c_str());
147 // set up the tooltips
148 string str = _("Add additional space above this paragraph.");
149 tooltips().init(dialog_->choice_space_above, str);
150 str = _("Never suppress space (e.g. at top of page or new page).");
151 tooltips().init(dialog_->check_space_above, str);
153 str = _("Add additional space below this paragraph.");
154 tooltips().init(dialog_->choice_space_below, str);
155 str = _("Never suppress space (e.g. at bottom of page or new page).");
156 tooltips().init(dialog_->check_space_below, str);
158 // set default unit for custom length
159 switch (lyxrc.default_papersize) {
162 case PAPER_LEGALPAPER:
163 case PAPER_EXECUTIVEPAPER:
176 void FormParagraph::apply()
181 // If a vspace choice is "Length" but there's no text in
182 // the input field, reset the choice to "None".
183 validateVSpaceWidgets(dialog_->choice_space_above,
184 dialog_->input_space_above);
186 VSpace const space_above =
187 setVSpaceFromWidgets(dialog_->choice_space_above,
188 dialog_->input_space_above,
189 dialog_->choice_unit_space_above,
190 dialog_->check_space_above);
192 controller().params().spaceTop(space_above);
194 validateVSpaceWidgets(dialog_->choice_space_below,
195 dialog_->input_space_below);
197 VSpace const space_below =
198 setVSpaceFromWidgets(dialog_->choice_space_below,
199 dialog_->input_space_below,
200 dialog_->choice_unit_space_below,
201 dialog_->check_space_below);
203 controller().params().spaceBottom(space_below);
206 LyXAlignment const alignment =
207 static_cast<LyXAlignment>(alignment_.get());
208 controller().params().align(alignment);
211 string const labelwidthstring =
212 getString(dialog_->input_labelwidth);
213 controller().params().labelWidthString(labelwidthstring);
216 bool const noindent = fl_get_button(dialog_->check_noindent);
217 controller().params().noindent(noindent);
220 Spacing::Space linespacing = Spacing::Default;
222 switch (fl_get_choice(dialog_->choice_linespacing)) {
224 linespacing = Spacing::Default;
227 linespacing = Spacing::Single;
230 linespacing = Spacing::Onehalf;
233 linespacing = Spacing::Double;
236 // reset to default if input is empty
237 other = getString(dialog_->input_linespacing);
238 if (!other.empty()) {
239 linespacing = Spacing::Other;
241 linespacing = Spacing::Default;
242 fl_set_choice(dialog_->choice_linespacing, 1);
246 Spacing const spacing(linespacing, other);
247 controller().params().spacing(spacing);
251 void FormParagraph::update()
257 string const labelwidth = controller().params().labelWidthString();
258 fl_set_input(dialog_->input_labelwidth, labelwidth.c_str());
259 setEnabled(dialog_->input_labelwidth,
260 labelwidth != _("Senseless with this layout!"));
263 alignment_.set(controller().params().align());
265 // mark default alignment
266 LyXAlignment const default_alignment = controller().alignDefault();
268 string label = _("Block");
269 if (default_alignment == LYX_ALIGN_BLOCK) {
270 label += _(" (default)");
272 fl_set_object_label(dialog_->radio_align_block, label.c_str());
273 fl_set_button_shortcut(dialog_->radio_align_block, "#B", 1);
276 if (default_alignment == LYX_ALIGN_CENTER) {
277 label += _(" (default)");
279 fl_set_object_label(dialog_->radio_align_center, label.c_str());
280 fl_set_button_shortcut(dialog_->radio_align_center, "#C", 1);
283 if (default_alignment == LYX_ALIGN_LEFT) {
284 label += _(" (default)");
286 fl_set_object_label(dialog_->radio_align_left, label.c_str());
287 fl_set_button_shortcut(dialog_->radio_align_left, "#L", 1);
290 if (default_alignment == LYX_ALIGN_RIGHT) {
291 label = _(" (default)");
293 fl_set_object_label(dialog_->radio_align_right, label.c_str());
294 fl_set_button_shortcut(dialog_->radio_align_right, "#R", 1);
296 // Ensure that there's no crud left on the screen from this change
298 fl_redraw_form(form());
300 LyXAlignment alignpos = controller().alignPossible();
301 setEnabled(dialog_->radio_align_block,
302 bool(alignpos & LYX_ALIGN_BLOCK));
303 setEnabled(dialog_->radio_align_center,
304 bool(alignpos & LYX_ALIGN_CENTER));
305 setEnabled(dialog_->radio_align_left,
306 bool(alignpos & LYX_ALIGN_LEFT));
307 setEnabled(dialog_->radio_align_right,
308 bool(alignpos & LYX_ALIGN_RIGHT));
310 // lines, pagebreaks and indent
311 fl_set_button(dialog_->check_noindent,
312 controller().params().noindent());
315 Spacing const space = controller().params().spacing();
318 switch (space.getSpace()) {
322 case Spacing::Double:
325 case Spacing::Onehalf:
328 case Spacing::Single:
331 case Spacing::Default:
336 fl_set_choice(dialog_->choice_linespacing, pos);
338 bool const spacing_other = space.getSpace() == Spacing::Other;
339 setEnabled(dialog_->input_linespacing, spacing_other);
341 string const sp = tostr(space.getValue());
342 fl_set_input(dialog_->input_linespacing, sp.c_str());
344 fl_set_input(dialog_->input_linespacing, "");
348 setWidgetsFromVSpace(controller().params().spaceTop(),
349 dialog_->choice_space_above,
350 dialog_->input_space_above,
351 dialog_->choice_unit_space_above,
352 dialog_->check_space_above);
355 setWidgetsFromVSpace(controller().params().spaceBottom(),
356 dialog_->choice_space_below,
357 dialog_->input_space_below,
358 dialog_->choice_unit_space_below,
359 dialog_->check_space_below);
362 fl_set_button(dialog_->check_noindent,
363 controller().params().noindent());
367 ButtonPolicy::SMInput FormParagraph::input(FL_OBJECT * ob, long)
369 // Enable input when custum length is choosen,
370 // disable 'keep' when no space is choosen
371 if (ob == dialog_->choice_space_above) {
372 bool const custom_length =
373 fl_get_choice(dialog_->choice_space_above) == 7;
374 setEnabled(dialog_->input_space_above, custom_length);
375 setEnabled(dialog_->choice_unit_space_above, custom_length);
378 fl_get_choice(dialog_->choice_space_above) != 1;
379 setEnabled(dialog_->check_space_above, space);
381 } else if (ob == dialog_->choice_space_below) {
382 bool const custom_length =
383 fl_get_choice(dialog_->choice_space_below) == 7;
384 setEnabled(dialog_->input_space_below, custom_length);
385 setEnabled(dialog_->choice_unit_space_below, custom_length);
388 fl_get_choice(dialog_->choice_space_below) != 1;
389 setEnabled(dialog_->check_space_below, space);
391 } else if (ob == dialog_->choice_linespacing) {
392 bool const custom_spacing =
393 fl_get_choice(dialog_->choice_linespacing) == 5;
394 setEnabled(dialog_->input_linespacing, custom_spacing);
397 return ButtonPolicy::SMI_VALID;
403 void validateVSpaceWidgets(FL_OBJECT * choice_type, FL_OBJECT * input_length)
406 BOOST_ASSERT(choice_type && choice_type->objclass == FL_CHOICE &&
407 input_length && input_length->objclass == FL_INPUT);
409 if (fl_get_choice(choice_type) != 7)
412 // If a vspace kind is "Length" but there's no text in
413 // the input field, reset the kind to "None".
414 string const input = rtrim(getString(input_length));
416 fl_set_choice(choice_type, 1);
420 VSpace const setVSpaceFromWidgets(FL_OBJECT * choice_type,
421 FL_OBJECT * input_length,
422 FL_OBJECT * choice_length,
423 FL_OBJECT * check_keep)
426 BOOST_ASSERT(choice_type && choice_type->objclass == FL_CHOICE &&
427 input_length && input_length->objclass == FL_INPUT &&
428 choice_length && choice_length->objclass == FL_CHOICE &&
429 check_keep && check_keep->objclass == FL_CHECKBUTTON);
432 switch (fl_get_choice(choice_type)) {
434 space = VSpace(VSpace::NONE);
437 space = VSpace(VSpace::DEFSKIP);
440 space = VSpace(VSpace::SMALLSKIP);
443 space = VSpace(VSpace::MEDSKIP);
446 space = VSpace(VSpace::BIGSKIP);
449 space = VSpace(VSpace::VFILL);
453 string const length =
454 getLengthFromWidgets(input_length, choice_length);
455 space = VSpace(LyXGlueLength(length));
460 if (fl_get_button(check_keep))
467 void setWidgetsFromVSpace(VSpace const & space,
468 FL_OBJECT * choice_type,
469 FL_OBJECT * input_length,
470 FL_OBJECT * choice_length,
471 FL_OBJECT * check_keep)
474 BOOST_ASSERT(choice_type && choice_type->objclass == FL_CHOICE &&
475 input_length && input_length->objclass == FL_INPUT &&
476 choice_length && choice_length->objclass == FL_CHOICE &&
477 check_keep && check_keep->objclass == FL_CHECKBUTTON);
479 fl_set_button(check_keep, space.keep());
482 switch (space.kind()) {
486 case VSpace::DEFSKIP:
489 case VSpace::SMALLSKIP:
492 case VSpace::MEDSKIP:
495 case VSpace::BIGSKIP:
505 fl_set_choice(choice_type, pos);
507 bool const custom_vspace = space.kind() == VSpace::LENGTH;
508 setEnabled(input_length, custom_vspace);
509 setEnabled(choice_length, custom_vspace);
511 string const length = space.length().asString();
512 updateWidgetsFromLengthString(input_length, choice_length,
513 length, defaultUnit);
515 bool const no_vspace = space.kind() == VSpace::NONE;
516 setEnabled(check_keep, !no_vspace);
517 fl_set_input(input_length, "");
518 fl_set_choice_text(choice_length, defaultUnit.c_str());