]> git.lyx.org Git - lyx.git/blob - src/frontends/xforms/FormParagraph.C
c489de5156ff357f2eee067624246d0db8e1a405
[lyx.git] / src / frontends / xforms / FormParagraph.C
1 /**
2  * \file FormParagraph.C
3  * Copyright 2000-2001 The LyX Team.
4  * See the file COPYING.
5  *
6  * \author Jürgen Vigna, jug@sad.it
7  */
8
9 #include <config.h>
10
11 #ifdef __GNUG_
12 #pragma implementation
13 #endif
14
15 #include FORMS_H_LOCATION
16
17 #include "FormParagraph.h"
18 #include "form_paragraph.h"
19 #include "Dialogs.h"
20 #include "Liason.h"
21 #include "LyXView.h"
22 #include "buffer.h"
23 #include "lyxtext.h"
24 #include "xforms_helpers.h"
25 #include "lyxrc.h" // to set the deafult length values
26 #include "BufferView.h"
27 #include "lyxtextclasslist.h"
28 #include "Spacing.h"
29 #include "ParagraphParameters.h"
30 #include "input_validators.h"
31 #include "helper_funcs.h"
32
33 #include "support/lstrings.h"
34
35 #include <functional>
36
37 using Liason::setMinibuffer;
38 using SigC::slot;
39 using std::vector;
40 using std::bind2nd;
41 using std::remove_if;
42
43
44 FormParagraph::FormParagraph(LyXView * lv, Dialogs * d)
45         : FormBaseBD(lv, d, _("Paragraph Layout")), par_(0)
46 {
47     // let the dialog be shown
48     // This is a permanent connection so we won't bother
49     // storing a copy because we won't be disconnecting.
50     d->showParagraph.connect(slot(this, &FormParagraph::show));
51 }
52
53
54 void FormParagraph::connect()
55 {
56         cp_ = d_->updateParagraph
57                 .connect(slot(this, &FormParagraph::changedParagraph));
58         FormBaseBD::connect();
59 }
60
61
62 void FormParagraph::disconnect()
63 {
64         cp_.disconnect();
65         FormBaseBD::disconnect();
66 }
67
68
69 Paragraph const * FormParagraph::getCurrentParagraph() const
70 {
71         return lv_->view()->getLyXText()->cursor.par();
72 }
73
74
75 void FormParagraph::changedParagraph()
76 {
77         /// Record the paragraph
78         Paragraph const * const p = getCurrentParagraph();
79         if (p == 0 || p == par_)
80                 return;
81 #ifdef WITH_WARNINGS
82 #warning Please someone of you GUII people have a look at this!
83 #endif
84         // shouldn't we chage the par_ pointer too?
85         // anyway for me the below function does just nothing!
86         // (Jug 20020108)
87
88         // For now don't bother checking if the params are different,
89         // just activate the Apply button
90         bc().valid();
91 }
92
93
94 void FormParagraph::redraw()
95 {
96         if (form() && form()->visible)
97                 fl_redraw_form(form());
98 }
99
100
101 FL_FORM * FormParagraph::form() const
102 {
103     if (dialog_.get()) return dialog_->form;
104     return 0;
105 }
106
107
108 void FormParagraph::build()
109 {
110     // the tabbed folder
111     dialog_.reset(build_paragraph());
112
113     fl_addto_choice(dialog_->choice_space_above,
114                     _(" None | Defskip | Smallskip "
115                       "| Medskip | Bigskip | VFill | Length "));
116     fl_addto_choice(dialog_->choice_space_below,
117                     _(" None | Defskip | Smallskip "
118                       "| Medskip | Bigskip | VFill | Length ")); 
119
120     fl_addto_choice(dialog_->choice_linespacing,
121                     _(" Default | Single | OneHalf | Double | Other "));
122  
123     fl_set_input_return(dialog_->input_space_above, FL_RETURN_CHANGED);
124     fl_set_input_return(dialog_->input_space_below, FL_RETURN_CHANGED);
125     fl_set_input_return(dialog_->input_labelwidth, FL_RETURN_CHANGED);
126     fl_set_input_return(dialog_->input_linespacing, FL_RETURN_CHANGED);
127     fl_set_input_filter(dialog_->input_linespacing, fl_unsigned_float_filter);
128
129     setPrehandler(dialog_->input_space_above);
130     setPrehandler(dialog_->input_space_below);
131     setPrehandler(dialog_->input_labelwidth);
132     setPrehandler(dialog_->input_linespacing);
133
134     // Create the contents of the unit choices
135     // Don't include the "%" terms...
136 #warning A bit dangerous... (Lgb)
137     vector<string> units_vec = getLatexUnits();
138 #if 0
139     for (vector<string>::iterator it = units_vec.begin();
140        it != units_vec.end(); ++it) {
141        if (contains(*it, "%"))
142                it = units_vec.erase(it, it+1) - 1;
143     }
144 #else
145     // Something similar to this is a better way to erase
146     vector<string>::iterator del =
147             remove_if(units_vec.begin(), units_vec.end(),
148                       bind2nd(contains_functor(), "%"));
149     units_vec.erase(del, units_vec.end());
150 #endif
151     
152     string units = getStringFromVector(units_vec, "|");
153
154     fl_addto_choice(dialog_->choice_value_space_above,  units.c_str());
155     fl_addto_choice(dialog_->choice_value_space_below, units.c_str());
156
157     // Manage the ok, apply, restore and cancel/close buttons
158     bc_.setOK(dialog_->button_ok);
159     bc_.setApply(dialog_->button_apply);
160     bc_.setCancel(dialog_->button_cancel);
161     bc_.setRestore(dialog_->button_restore);
162
163     bc_.addReadOnly (dialog_->group_radio_alignment);
164     // bc_.addReadOnly (dialog_->radio_align_right);
165     // bc_.addReadOnly (dialog_->radio_align_left);
166     // bc_.addReadOnly (dialog_->radio_align_block);
167     // bc_.addReadOnly (dialog_->radio_align_center);
168     bc_.addReadOnly (dialog_->check_lines_top);
169     bc_.addReadOnly (dialog_->check_lines_bottom);
170     bc_.addReadOnly (dialog_->check_pagebreaks_top);
171     bc_.addReadOnly (dialog_->check_pagebreaks_bottom);
172     bc_.addReadOnly (dialog_->choice_space_above);
173     bc_.addReadOnly (dialog_->input_space_above);
174     bc_.addReadOnly (dialog_->check_space_above);
175     bc_.addReadOnly (dialog_->choice_space_below);
176     bc_.addReadOnly (dialog_->input_space_below);
177     bc_.addReadOnly (dialog_->check_space_below);
178     bc_.addReadOnly (dialog_->choice_linespacing);
179     bc_.addReadOnly (dialog_->input_linespacing); 
180     bc_.addReadOnly (dialog_->check_noindent);
181     bc_.addReadOnly (dialog_->input_labelwidth);
182 }
183
184
185 void FormParagraph::apply()
186 {
187     if (!lv_->view()->available() || !dialog_.get())
188         return;
189
190     VSpace space_top, space_bottom;
191     LyXAlignment align;
192     string labelwidthstring;
193     bool noindent;
194
195     // If a vspace kind is "Length" but there's no text in
196     // the input field, reset the kind to "None". 
197     if ((fl_get_choice (dialog_->choice_space_above) == 7) &&
198         !*(fl_get_input (dialog_->input_space_above)))
199     {
200         fl_set_choice (dialog_->choice_space_above, 1);
201     }
202     if ((fl_get_choice (dialog_->choice_space_below) == 7) &&
203         !*(fl_get_input (dialog_->input_space_below)))
204     {
205         fl_set_choice (dialog_->choice_space_below, 1);
206     }
207    
208     bool line_top = fl_get_button(dialog_->check_lines_top);
209     bool line_bottom = fl_get_button(dialog_->check_lines_bottom);
210     bool pagebreak_top = fl_get_button(dialog_->check_pagebreaks_top);
211     bool pagebreak_bottom = fl_get_button(dialog_->check_pagebreaks_bottom);
212     
213     switch (fl_get_choice (dialog_->choice_space_above)) {
214     case 1:
215         space_top = VSpace(VSpace::NONE);
216         break;
217     case 2:
218         space_top = VSpace(VSpace::DEFSKIP);
219         break;
220     case 3:
221         space_top = VSpace(VSpace::SMALLSKIP);
222         break;
223     case 4:
224         space_top = VSpace(VSpace::MEDSKIP);
225         break;
226     case 5:
227         space_top = VSpace(VSpace::BIGSKIP);
228         break;
229     case 6:
230         space_top = VSpace(VSpace::VFILL);
231         break;
232     case 7:
233     {
234             string const length =
235                     getLengthFromWidgets(dialog_->input_space_above,
236                                          dialog_->choice_value_space_above);
237         space_top =
238                 VSpace(LyXGlueLength(length));
239         break;
240     }
241     }
242
243     if (fl_get_button (dialog_->check_space_above))
244         space_top.setKeep (true);
245     switch (fl_get_choice (dialog_->choice_space_below)) {
246     case 1:
247         space_bottom = VSpace(VSpace::NONE);
248         break;
249     case 2:
250         space_bottom = VSpace(VSpace::DEFSKIP);
251         break;
252     case 3:
253         space_bottom = VSpace(VSpace::SMALLSKIP);
254         break;
255     case 4:
256         space_bottom = VSpace(VSpace::MEDSKIP);
257         break;
258     case 5:
259         space_bottom = VSpace(VSpace::BIGSKIP);
260         break;
261     case 6:
262         space_bottom = VSpace(VSpace::VFILL);
263         break;
264     case 7:
265         string const length =
266                 getLengthFromWidgets(dialog_->input_space_below,
267                                      dialog_->choice_value_space_below);
268         space_bottom = VSpace(LyXGlueLength(length));
269         break;
270     }
271     if (fl_get_button (dialog_->check_space_below))
272         space_bottom.setKeep (true);
273
274     if (fl_get_button(dialog_->radio_align_left))
275         align = LYX_ALIGN_LEFT;
276     else if (fl_get_button(dialog_->radio_align_right))
277         align = LYX_ALIGN_RIGHT;
278     else if (fl_get_button(dialog_->radio_align_center))
279         align = LYX_ALIGN_CENTER;
280     else 
281         align = LYX_ALIGN_BLOCK;
282    
283     labelwidthstring = fl_get_input(dialog_->input_labelwidth);
284     noindent = fl_get_button(dialog_->check_noindent);
285     Spacing::Space linespacing = Spacing::Default;
286     string other_linespacing;
287     switch (fl_get_choice(dialog_->choice_linespacing)) {
288         case 1: linespacing = Spacing::Default; break;
289         case 2: linespacing = Spacing::Single; break;
290         case 3: linespacing = Spacing::Onehalf; break;
291         case 4: linespacing = Spacing::Double; break;
292         case 5:
293             linespacing = Spacing::Other;
294             other_linespacing = fl_get_input(dialog_->input_linespacing);
295             break;
296     }
297
298     Spacing const spacing(linespacing, other_linespacing);
299     LyXText * text(lv_->view()->getLyXText());
300     text->setParagraph(lv_->view(), line_top, line_bottom, pagebreak_top,
301                        pagebreak_bottom, space_top, space_bottom, spacing,
302                        align, labelwidthstring, noindent);
303
304
305     // Actually apply these settings
306     lv_->view()->update(text, 
307                         BufferView::SELECT | BufferView::FITCUR | BufferView::CHANGE);
308     lv_->buffer()->markDirty();
309     setMinibuffer(lv_, _("Paragraph layout set"));
310 }
311
312
313 void FormParagraph::update()
314 {
315     if (!dialog_.get())
316         return;
317
318     // Do this first; some objects may be de/activated subsequently.
319     bc_.readOnly(lv_->buffer()->isReadonly());
320
321     Buffer * buf = lv_->view()->buffer();
322
323     /// Record the paragraph
324     par_ = getCurrentParagraph();
325
326     fl_set_input(dialog_->input_labelwidth,
327                  par_->getLabelWidthString().c_str());
328     setEnabled(dialog_->input_labelwidth,
329                (par_->getLabelWidthString() != _("Senseless with this layout!")));
330
331     fl_set_button(dialog_->radio_align_right, 0);
332     fl_set_button(dialog_->radio_align_left, 0);
333     fl_set_button(dialog_->radio_align_center, 0);
334     fl_set_button(dialog_->radio_align_block, 0);
335
336     LyXTextClass const & tclass = textclasslist[buf->params.textclass];
337     
338     int align = par_->getAlign();
339     if (align == LYX_ALIGN_LAYOUT)
340             align = tclass[par_->layout()].align;
341
342     switch (align) {
343     case LYX_ALIGN_RIGHT:
344         fl_set_button(dialog_->radio_align_right, 1);
345         break;
346     case LYX_ALIGN_LEFT:
347         fl_set_button(dialog_->radio_align_left, 1);
348         break;
349     case LYX_ALIGN_CENTER:
350         fl_set_button(dialog_->radio_align_center, 1);
351         break;
352     default:
353         fl_set_button(dialog_->radio_align_block, 1);
354         break;
355     }
356
357     LyXAlignment alignpos = tclass[par_->layout()].alignpossible;
358
359     setEnabled(dialog_->radio_align_block,  bool(alignpos & LYX_ALIGN_BLOCK));
360     setEnabled(dialog_->radio_align_center, bool(alignpos & LYX_ALIGN_CENTER));
361     setEnabled(dialog_->radio_align_left,   bool(alignpos & LYX_ALIGN_LEFT));
362     setEnabled(dialog_->radio_align_right,  bool(alignpos & LYX_ALIGN_RIGHT));
363     
364     // no inset-text-owned paragraph may have pagebreaks
365     setEnabled(dialog_->check_pagebreaks_top, !par_->inInset());
366     setEnabled(dialog_->check_pagebreaks_bottom, !par_->inInset());
367
368     fl_set_button(dialog_->check_lines_top,
369                   par_->params().lineTop());
370     fl_set_button(dialog_->check_lines_bottom,
371                   par_->params().lineBottom());
372     fl_set_button(dialog_->check_pagebreaks_top,
373                   par_->params().pagebreakTop());
374     fl_set_button(dialog_->check_pagebreaks_bottom,
375                   par_->params().pagebreakBottom());
376     fl_set_button(dialog_->check_noindent,
377                   par_->params().noindent());
378
379     int linespacing;
380     Spacing const space = par_->params().spacing();
381
382     switch (space.getSpace()) {
383         default: linespacing = 1; break;
384         case Spacing::Single: linespacing = 2; break;
385         case Spacing::Onehalf: linespacing = 3; break;
386         case Spacing::Double: linespacing = 4; break;
387         case Spacing::Other: linespacing = 5; break;
388     }
389  
390     fl_set_choice(dialog_->choice_linespacing, linespacing);
391     if (space.getSpace() == Spacing::Other) {
392         string const sp = tostr(space.getValue());
393         fl_set_input(dialog_->input_linespacing, sp.c_str());
394         setEnabled(dialog_->input_linespacing, true);
395     } else {
396         fl_set_input(dialog_->input_linespacing, "");
397         setEnabled(dialog_->input_linespacing, false);
398     }
399
400     fl_set_input (dialog_->input_space_above, "");
401
402     setEnabled(dialog_->input_space_above, false);
403     setEnabled(dialog_->choice_value_space_above, false);
404     switch (par_->params().spaceTop().kind()) {
405     case VSpace::NONE:
406         fl_set_choice (dialog_->choice_space_above, 1);
407         break;
408     case VSpace::DEFSKIP:
409         fl_set_choice (dialog_->choice_space_above, 2);
410         break;
411     case VSpace::SMALLSKIP:
412         fl_set_choice (dialog_->choice_space_above, 3);
413         break;
414     case VSpace::MEDSKIP:
415         fl_set_choice (dialog_->choice_space_above, 4);
416         break;
417     case VSpace::BIGSKIP:
418         fl_set_choice (dialog_->choice_space_above, 5);
419         break;
420     case VSpace::VFILL:
421         fl_set_choice (dialog_->choice_space_above, 6);
422         break;
423     case VSpace::LENGTH:
424     {
425         fl_set_choice (dialog_->choice_space_above, 7);
426         setEnabled(dialog_->input_space_above, true);
427         setEnabled(dialog_->choice_value_space_above, true);
428         bool const metric = lyxrc.default_papersize > 3;
429         string const default_unit = metric ? "cm" : "in";
430         string const length = par_->params().spaceTop().length().asString();
431         updateWidgetsFromLengthString(dialog_->input_space_above,
432                                               dialog_->choice_value_space_above,
433                                               length, default_unit);
434         break;
435     }
436     }
437     
438     fl_set_button (dialog_->check_space_above,
439            par_->params().spaceTop().keep());
440     fl_set_input (dialog_->input_space_below, "");
441
442     setEnabled(dialog_->input_space_below, false);
443     setEnabled(dialog_->choice_value_space_below, false);
444     switch (par_->params().spaceBottom().kind()) {
445     case VSpace::NONE:
446         fl_set_choice (dialog_->choice_space_below, 1);
447         break;
448     case VSpace::DEFSKIP:
449         fl_set_choice (dialog_->choice_space_below, 2);
450         break;
451     case VSpace::SMALLSKIP:
452         fl_set_choice (dialog_->choice_space_below, 3);
453         break;
454     case VSpace::MEDSKIP:
455         fl_set_choice (dialog_->choice_space_below, 4);
456         break;
457     case VSpace::BIGSKIP:
458         fl_set_choice (dialog_->choice_space_below, 5);
459         break;
460     case VSpace::VFILL:
461         fl_set_choice (dialog_->choice_space_below, 6);
462         break;
463     case VSpace::LENGTH:
464     {
465         fl_set_choice (dialog_->choice_space_below, 7);
466         setEnabled(dialog_->input_space_below, true);
467         setEnabled(dialog_->choice_value_space_below, true);
468         bool const metric = lyxrc.default_papersize > 3;
469         string const default_unit = metric ? "cm" : "in";
470         string const length =
471                 par_->params().spaceBottom().length().asString();
472         updateWidgetsFromLengthString(dialog_->input_space_below,
473                                               dialog_->choice_value_space_below,
474                                               length, default_unit);
475         break;
476     }
477     }
478
479     fl_set_button(dialog_->check_space_below,
480                   par_->params().spaceBottom().keep());
481     fl_set_button(dialog_->check_noindent,
482                   par_->params().noindent());
483 }
484
485
486 bool FormParagraph::input(FL_OBJECT * ob, long)
487 {
488     bool valid = true; 
489
490     fl_hide_object(dialog_->text_warning);
491
492     // First check the buttons which are exclusive and you have to
493     // check only the actuall de/activated button.
494     //
495     // "Synchronize" the choices and input fields, making it
496     // impossible to commit senseless data.
497
498     if (ob == dialog_->choice_space_above) {
499         if (fl_get_choice (dialog_->choice_space_above) != 7) {
500             fl_set_input (dialog_->input_space_above, "");
501             setEnabled (dialog_->input_space_above, false);
502             setEnabled (dialog_->choice_value_space_above, false);
503         } else {
504             setEnabled (dialog_->input_space_above, !lv_->buffer()->isReadonly());
505             setEnabled (dialog_->choice_value_space_above, !lv_->buffer()->isReadonly());
506             bool const metric = lyxrc.default_papersize > 3;
507             int const default_unit = metric ? 8 : 9;
508             if (strip(fl_get_input(dialog_->input_space_above)).empty())
509                 fl_set_choice(dialog_->choice_value_space_above,
510                               default_unit);
511         }
512     }
513     if (ob == dialog_->choice_space_below) {
514         if (fl_get_choice (dialog_->choice_space_below) != 7) {
515             fl_set_input (dialog_->input_space_below, "");
516             setEnabled (dialog_->input_space_below, false);
517             setEnabled (dialog_->choice_value_space_below, false);
518         } else {
519             setEnabled (dialog_->input_space_below, !lv_->buffer()->isReadonly());
520             setEnabled (dialog_->choice_value_space_below, !lv_->buffer()->isReadonly());
521             bool const metric = lyxrc.default_papersize > 3;
522             int const default_unit = metric ? 8 : 9;
523             if (strip(fl_get_input(dialog_->input_space_below)).empty())
524                     fl_set_choice(dialog_->choice_value_space_below,
525                                   default_unit);
526         }
527     }
528  
529     //
530     // warnings if input is senseless
531     //
532     string input = fl_get_input (dialog_->input_space_above);
533     bool invalid = false;
534
535     if (fl_get_choice(dialog_->choice_space_above)==7)
536         invalid = !input.empty() && !isValidGlueLength(input) && !isStrDbl(input);
537
538     input = fl_get_input (dialog_->input_space_below);
539
540     if (fl_get_choice(dialog_->choice_space_below)==7)
541         invalid = invalid
542                 || (!input.empty() && !isValidGlueLength(input) && !isStrDbl(input));
543
544     if (ob == dialog_->input_space_above || ob == dialog_->input_space_below) {
545         if (invalid) {
546             fl_set_object_label(dialog_->text_warning,
547                 _("Warning: Invalid Length (valid example: 10mm)"));
548             fl_show_object(dialog_->text_warning);
549             return false;
550         } else {
551             fl_hide_object(dialog_->text_warning);
552             return true;
553         }
554     }
555
556     if (fl_get_choice (dialog_->choice_linespacing) == 5)
557         setEnabled (dialog_->input_linespacing, true);
558     else {
559         setEnabled (dialog_->input_linespacing, false);
560         fl_set_input (dialog_->input_linespacing, "");
561     }
562
563     double spacing(strToDbl(fl_get_input(dialog_->input_linespacing)));
564
565     if (fl_get_choice (dialog_->choice_linespacing) == 5
566         && int(spacing) == 0)
567         valid = false;
568
569     return valid;
570 }