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
15 #include "ControlParagraph.h"
16 #include "FormParagraph.h"
17 #include "forms/form_paragraph.h"
20 #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"
26 #include "checkedwidgets.h"
29 #include "layout.h" // LyXAlignment
31 #include "support/lstrings.h"
32 #include "support/LAssert.h"
34 #include FORMS_H_LOCATION
46 string defaultUnit("cm");
48 void validateVSpaceWidgets(FL_OBJECT * choice_type, FL_OBJECT * input_length);
50 VSpace const setVSpaceFromWidgets(FL_OBJECT * choice_type,
51 FL_OBJECT * input_length,
52 FL_OBJECT * choice_length,
53 FL_OBJECT * check_keep);
55 void setWidgetsFromVSpace(VSpace const & space,
56 FL_OBJECT * choice_type,
57 FL_OBJECT * input_length,
58 FL_OBJECT * choice_length,
59 FL_OBJECT * check_keep);
64 typedef FormController<ControlParagraph, FormView<FD_paragraph> > base_class;
66 FormParagraph::FormParagraph(Dialog & parent)
67 : base_class(parent, _("Paragraph Layout"))
71 void FormParagraph::build()
74 dialog_.reset(build_paragraph(this));
76 // Manage the ok, apply, restore and cancel/close buttons
77 bcview().setOK(dialog_->button_ok);
78 bcview().setApply(dialog_->button_apply);
79 bcview().setCancel(dialog_->button_close);
80 bcview().setRestore(dialog_->button_restore);
82 // disable for read-only documents
83 bcview().addReadOnly(dialog_->check_line_above);
84 bcview().addReadOnly(dialog_->check_pagebreak_above);
85 bcview().addReadOnly(dialog_->choice_space_above);
86 bcview().addReadOnly(dialog_->input_space_above);
87 bcview().addReadOnly(dialog_->check_space_above);
89 bcview().addReadOnly(dialog_->check_noindent);
90 bcview().addReadOnly(dialog_->choice_linespacing);
91 bcview().addReadOnly(dialog_->input_linespacing);
93 bcview().addReadOnly(dialog_->check_line_below);
94 bcview().addReadOnly(dialog_->check_pagebreak_below);
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 a separator line above this paragraph.");
149 tooltips().init(dialog_->check_line_above, str);
150 str = _("Enforce a page break above this paragraph.");
151 tooltips().init(dialog_->check_pagebreak_above, str);
152 str = _("Add additional space above this paragraph.");
153 tooltips().init(dialog_->choice_space_above, str);
154 str = _("Never suppress space (e.g. at top of page or new page).");
155 tooltips().init(dialog_->check_space_above, str);
157 str = _("Add a separator line below this paragraph.");
158 tooltips().init(dialog_->check_line_below, str);
159 str = _("Enforce a page break below this paragraph.");
160 tooltips().init(dialog_->check_pagebreak_below, str);
161 str = _("Add additional space below this paragraph.");
162 tooltips().init(dialog_->choice_space_below, str);
163 str = _("Never suppress space (e.g. at bottom of page or new page).");
164 tooltips().init(dialog_->check_space_below, str);
166 // set default unit for custom length
167 switch (lyxrc.default_papersize) {
168 case BufferParams::PAPER_DEFAULT:
169 case BufferParams::PAPER_USLETTER:
170 case BufferParams::PAPER_LEGALPAPER:
171 case BufferParams::PAPER_EXECUTIVEPAPER:
174 case BufferParams::PAPER_A3PAPER:
175 case BufferParams::PAPER_A4PAPER:
176 case BufferParams::PAPER_A5PAPER:
177 case BufferParams::PAPER_B5PAPER:
184 void FormParagraph::apply()
189 // If a vspace choice is "Length" but there's no text in
190 // the input field, reset the choice to "None".
191 validateVSpaceWidgets(dialog_->choice_space_above,
192 dialog_->input_space_above);
194 VSpace const space_above =
195 setVSpaceFromWidgets(dialog_->choice_space_above,
196 dialog_->input_space_above,
197 dialog_->choice_unit_space_above,
198 dialog_->check_space_above);
200 controller().params().spaceTop(space_above);
202 validateVSpaceWidgets(dialog_->choice_space_below,
203 dialog_->input_space_below);
205 VSpace const space_below =
206 setVSpaceFromWidgets(dialog_->choice_space_below,
207 dialog_->input_space_below,
208 dialog_->choice_unit_space_below,
209 dialog_->check_space_below);
211 controller().params().spaceBottom(space_below);
213 // lines and pagebreaks
214 bool const line_above = fl_get_button(dialog_->check_line_above);
215 controller().params().lineTop(line_above);
217 bool const line_below = fl_get_button(dialog_->check_line_below);
218 controller().params().lineBottom(line_below);
220 bool const pagebreak_above =
221 fl_get_button(dialog_->check_pagebreak_above);
222 controller().params().pagebreakTop(pagebreak_above);
224 bool const pagebreak_below =
225 fl_get_button(dialog_->check_pagebreak_below);
226 controller().params().pagebreakBottom(pagebreak_below);
230 LyXAlignment const alignment =
231 static_cast<LyXAlignment>(alignment_.get());
232 controller().params().align(alignment);
235 string const labelwidthstring =
236 getString(dialog_->input_labelwidth);
237 controller().params().labelWidthString(labelwidthstring);
240 bool const noindent = fl_get_button(dialog_->check_noindent);
241 controller().params().noindent(noindent);
244 Spacing::Space linespacing = Spacing::Default;
246 switch (fl_get_choice(dialog_->choice_linespacing)) {
248 linespacing = Spacing::Default;
251 linespacing = Spacing::Single;
254 linespacing = Spacing::Onehalf;
257 linespacing = Spacing::Double;
260 // reset to default if input is empty
261 other = getString(dialog_->input_linespacing);
262 if (!other.empty()) {
263 linespacing = Spacing::Other;
265 linespacing = Spacing::Default;
266 fl_set_choice(dialog_->choice_linespacing, 1);
270 Spacing const spacing(linespacing, other);
271 controller().params().spacing(spacing);
275 void FormParagraph::update()
281 string const labelwidth = controller().params().labelWidthString();
282 fl_set_input(dialog_->input_labelwidth, labelwidth.c_str());
283 setEnabled(dialog_->input_labelwidth,
284 labelwidth != _("Senseless with this layout!"));
287 alignment_.set(controller().params().align());
289 // mark default alignment
290 LyXAlignment const default_alignment = controller().alignDefault();
292 string label = _("Block");
293 if (default_alignment == LYX_ALIGN_BLOCK) {
294 label += _(" (default)");
296 fl_set_object_label(dialog_->radio_align_block, label.c_str());
297 fl_set_button_shortcut(dialog_->radio_align_block, "#B", 1);
300 if (default_alignment == LYX_ALIGN_CENTER) {
301 label += _(" (default)");
303 fl_set_object_label(dialog_->radio_align_center, label.c_str());
304 fl_set_button_shortcut(dialog_->radio_align_center, "#C", 1);
307 if (default_alignment == LYX_ALIGN_LEFT) {
308 label += _(" (default)");
310 fl_set_object_label(dialog_->radio_align_left, label.c_str());
311 fl_set_button_shortcut(dialog_->radio_align_left, "#L", 1);
314 if (default_alignment == LYX_ALIGN_RIGHT) {
315 label = _(" (default)");
317 fl_set_object_label(dialog_->radio_align_right, label.c_str());
318 fl_set_button_shortcut(dialog_->radio_align_right, "#R", 1);
320 // Ensure that there's no crud left on the screen from this change
322 fl_redraw_form(form());
324 LyXAlignment alignpos = controller().alignPossible();
325 setEnabled(dialog_->radio_align_block,
326 bool(alignpos & LYX_ALIGN_BLOCK));
327 setEnabled(dialog_->radio_align_center,
328 bool(alignpos & LYX_ALIGN_CENTER));
329 setEnabled(dialog_->radio_align_left,
330 bool(alignpos & LYX_ALIGN_LEFT));
331 setEnabled(dialog_->radio_align_right,
332 bool(alignpos & LYX_ALIGN_RIGHT));
334 // no inset-text-owned paragraph may have pagebreaks
335 bool ininset = controller().inInset();
336 setEnabled(dialog_->check_pagebreak_above, !ininset);
337 setEnabled(dialog_->check_pagebreak_below, !ininset);
339 // lines, pagebreaks and indent
340 fl_set_button(dialog_->check_line_above,
341 controller().params().lineTop());
342 fl_set_button(dialog_->check_line_below,
343 controller().params().lineBottom());
344 fl_set_button(dialog_->check_pagebreak_above,
345 controller().params().pagebreakTop());
346 fl_set_button(dialog_->check_pagebreak_below,
347 controller().params().pagebreakBottom());
348 fl_set_button(dialog_->check_noindent,
349 controller().params().noindent());
352 Spacing const space = controller().params().spacing();
355 switch (space.getSpace()) {
359 case Spacing::Double:
362 case Spacing::Onehalf:
365 case Spacing::Single:
368 case Spacing::Default:
373 fl_set_choice(dialog_->choice_linespacing, pos);
375 bool const spacing_other = space.getSpace() == Spacing::Other;
376 setEnabled(dialog_->input_linespacing, spacing_other);
378 string const sp = tostr(space.getValue());
379 fl_set_input(dialog_->input_linespacing, sp.c_str());
381 fl_set_input(dialog_->input_linespacing, "");
385 setWidgetsFromVSpace(controller().params().spaceTop(),
386 dialog_->choice_space_above,
387 dialog_->input_space_above,
388 dialog_->choice_unit_space_above,
389 dialog_->check_space_above);
392 setWidgetsFromVSpace(controller().params().spaceBottom(),
393 dialog_->choice_space_below,
394 dialog_->input_space_below,
395 dialog_->choice_unit_space_below,
396 dialog_->check_space_below);
399 fl_set_button(dialog_->check_noindent,
400 controller().params().noindent());
404 ButtonPolicy::SMInput FormParagraph::input(FL_OBJECT * ob, long)
406 // Enable input when custum length is choosen,
407 // disable 'keep' when no space is choosen
408 if (ob == dialog_->choice_space_above) {
409 bool const custom_length =
410 fl_get_choice(dialog_->choice_space_above) == 7;
411 setEnabled(dialog_->input_space_above, custom_length);
412 setEnabled(dialog_->choice_unit_space_above, custom_length);
415 fl_get_choice(dialog_->choice_space_above) != 1;
416 setEnabled(dialog_->check_space_above, space);
418 } else if (ob == dialog_->choice_space_below) {
419 bool const custom_length =
420 fl_get_choice(dialog_->choice_space_below) == 7;
421 setEnabled(dialog_->input_space_below, custom_length);
422 setEnabled(dialog_->choice_unit_space_below, custom_length);
425 fl_get_choice(dialog_->choice_space_below) != 1;
426 setEnabled(dialog_->check_space_below, space);
428 } else if (ob == dialog_->choice_linespacing) {
429 bool const custom_spacing =
430 fl_get_choice(dialog_->choice_linespacing) == 5;
431 setEnabled(dialog_->input_linespacing, custom_spacing);
434 return ButtonPolicy::SMI_VALID;
440 void validateVSpaceWidgets(FL_OBJECT * choice_type, FL_OBJECT * input_length)
443 lyx::Assert(choice_type && choice_type->objclass == FL_CHOICE &&
444 input_length && input_length->objclass == FL_INPUT);
446 if (fl_get_choice(choice_type) != 7)
449 // If a vspace kind is "Length" but there's no text in
450 // the input field, reset the kind to "None".
451 string const input = rtrim(getString(input_length));
453 fl_set_choice(choice_type, 1);
457 VSpace const setVSpaceFromWidgets(FL_OBJECT * choice_type,
458 FL_OBJECT * input_length,
459 FL_OBJECT * choice_length,
460 FL_OBJECT * check_keep)
463 lyx::Assert(choice_type && choice_type->objclass == FL_CHOICE &&
464 input_length && input_length->objclass == FL_INPUT &&
465 choice_length && choice_length->objclass == FL_CHOICE &&
466 check_keep && check_keep->objclass == FL_CHECKBUTTON);
469 switch (fl_get_choice(choice_type)) {
471 space = VSpace(VSpace::NONE);
474 space = VSpace(VSpace::DEFSKIP);
477 space = VSpace(VSpace::SMALLSKIP);
480 space = VSpace(VSpace::MEDSKIP);
483 space = VSpace(VSpace::BIGSKIP);
486 space = VSpace(VSpace::VFILL);
490 string const length =
491 getLengthFromWidgets(input_length, choice_length);
492 space = VSpace(LyXGlueLength(length));
497 if (fl_get_button(check_keep))
504 void setWidgetsFromVSpace(VSpace const & space,
505 FL_OBJECT * choice_type,
506 FL_OBJECT * input_length,
507 FL_OBJECT * choice_length,
508 FL_OBJECT * check_keep)
511 lyx::Assert(choice_type && choice_type->objclass == FL_CHOICE &&
512 input_length && input_length->objclass == FL_INPUT &&
513 choice_length && choice_length->objclass == FL_CHOICE &&
514 check_keep && check_keep->objclass == FL_CHECKBUTTON);
516 fl_set_button(check_keep, space.keep());
519 switch (space.kind()) {
523 case VSpace::DEFSKIP:
526 case VSpace::SMALLSKIP:
529 case VSpace::MEDSKIP:
532 case VSpace::BIGSKIP:
542 fl_set_choice(choice_type, pos);
544 bool const custom_vspace = space.kind() == VSpace::LENGTH;
545 setEnabled(input_length, custom_vspace);
546 setEnabled(choice_length, custom_vspace);
548 string const length = space.length().asString();
549 updateWidgetsFromLengthString(input_length, choice_length,
550 length, defaultUnit);
552 bool const no_vspace = space.kind() == VSpace::NONE;
553 setEnabled(check_keep, !no_vspace);
554 fl_set_input(input_length, "");
555 fl_set_choice_text(choice_length, defaultUnit.c_str());