]> git.lyx.org Git - lyx.git/blob - src/frontends/xforms/FormParagraph.C
doxygen fixes
[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
82         // OBS FIX LOOK HERE
83
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     vector<string> units_vec = getLatexUnits();
137 #if 0
138     for (vector<string>::iterator it = units_vec.begin();
139        it != units_vec.end(); ++it) {
140        if (contains(*it, "%"))
141                it = units_vec.erase(it, it+1) - 1;
142     }
143 #else
144     // Something similar to this is a better way to erase
145     vector<string>::iterator del =
146             remove_if(units_vec.begin(), units_vec.end(),
147                       bind2nd(contains_functor(), "%"));
148     units_vec.erase(del, units_vec.end());
149 #endif
150     
151     string units = getStringFromVector(units_vec, "|");
152
153     fl_addto_choice(dialog_->choice_value_space_above,  units.c_str());
154     fl_addto_choice(dialog_->choice_value_space_below, units.c_str());
155
156     // Manage the ok, apply, restore and cancel/close buttons
157     bc_.setOK(dialog_->button_ok);
158     bc_.setApply(dialog_->button_apply);
159     bc_.setCancel(dialog_->button_cancel);
160     bc_.setRestore(dialog_->button_restore);
161
162     bc_.addReadOnly (dialog_->group_radio_alignment);
163     // bc_.addReadOnly (dialog_->radio_align_right);
164     // bc_.addReadOnly (dialog_->radio_align_left);
165     // bc_.addReadOnly (dialog_->radio_align_block);
166     // bc_.addReadOnly (dialog_->radio_align_center);
167     bc_.addReadOnly (dialog_->check_lines_top);
168     bc_.addReadOnly (dialog_->check_lines_bottom);
169     bc_.addReadOnly (dialog_->check_pagebreaks_top);
170     bc_.addReadOnly (dialog_->check_pagebreaks_bottom);
171     bc_.addReadOnly (dialog_->choice_space_above);
172     bc_.addReadOnly (dialog_->input_space_above);
173     bc_.addReadOnly (dialog_->check_space_above);
174     bc_.addReadOnly (dialog_->choice_space_below);
175     bc_.addReadOnly (dialog_->input_space_below);
176     bc_.addReadOnly (dialog_->check_space_below);
177     bc_.addReadOnly (dialog_->choice_linespacing);
178     bc_.addReadOnly (dialog_->input_linespacing); 
179     bc_.addReadOnly (dialog_->check_noindent);
180     bc_.addReadOnly (dialog_->input_labelwidth);
181 }
182
183
184 void FormParagraph::apply()
185 {
186     if (!lv_->view()->available() || !dialog_.get())
187         return;
188
189     VSpace space_top, space_bottom;
190     LyXAlignment align;
191     string labelwidthstring;
192     bool noindent;
193
194     // If a vspace kind is "Length" but there's no text in
195     // the input field, reset the kind to "None". 
196     if ((fl_get_choice (dialog_->choice_space_above) == 7) &&
197         !*(fl_get_input (dialog_->input_space_above)))
198     {
199         fl_set_choice (dialog_->choice_space_above, 1);
200     }
201     if ((fl_get_choice (dialog_->choice_space_below) == 7) &&
202         !*(fl_get_input (dialog_->input_space_below)))
203     {
204         fl_set_choice (dialog_->choice_space_below, 1);
205     }
206    
207     bool line_top = fl_get_button(dialog_->check_lines_top);
208     bool line_bottom = fl_get_button(dialog_->check_lines_bottom);
209     bool pagebreak_top = fl_get_button(dialog_->check_pagebreaks_top);
210     bool pagebreak_bottom = fl_get_button(dialog_->check_pagebreaks_bottom);
211     
212     switch (fl_get_choice (dialog_->choice_space_above)) {
213     case 1:
214         space_top = VSpace(VSpace::NONE);
215         break;
216     case 2:
217         space_top = VSpace(VSpace::DEFSKIP);
218         break;
219     case 3:
220         space_top = VSpace(VSpace::SMALLSKIP);
221         break;
222     case 4:
223         space_top = VSpace(VSpace::MEDSKIP);
224         break;
225     case 5:
226         space_top = VSpace(VSpace::BIGSKIP);
227         break;
228     case 6:
229         space_top = VSpace(VSpace::VFILL);
230         break;
231     case 7:
232     {
233             string const length =
234                     getLengthFromWidgets(dialog_->input_space_above,
235                                          dialog_->choice_value_space_above);
236         space_top =
237                 VSpace(LyXGlueLength(length));
238         break;
239     }
240     }
241
242     if (fl_get_button (dialog_->check_space_above))
243         space_top.setKeep (true);
244     switch (fl_get_choice (dialog_->choice_space_below)) {
245     case 1:
246         space_bottom = VSpace(VSpace::NONE);
247         break;
248     case 2:
249         space_bottom = VSpace(VSpace::DEFSKIP);
250         break;
251     case 3:
252         space_bottom = VSpace(VSpace::SMALLSKIP);
253         break;
254     case 4:
255         space_bottom = VSpace(VSpace::MEDSKIP);
256         break;
257     case 5:
258         space_bottom = VSpace(VSpace::BIGSKIP);
259         break;
260     case 6:
261         space_bottom = VSpace(VSpace::VFILL);
262         break;
263     case 7:
264         string const length =
265                 getLengthFromWidgets(dialog_->input_space_below,
266                                      dialog_->choice_value_space_below);
267         space_bottom = VSpace(LyXGlueLength(length));
268         break;
269     }
270     if (fl_get_button (dialog_->check_space_below))
271         space_bottom.setKeep (true);
272
273     if (fl_get_button(dialog_->radio_align_left))
274         align = LYX_ALIGN_LEFT;
275     else if (fl_get_button(dialog_->radio_align_right))
276         align = LYX_ALIGN_RIGHT;
277     else if (fl_get_button(dialog_->radio_align_center))
278         align = LYX_ALIGN_CENTER;
279     else 
280         align = LYX_ALIGN_BLOCK;
281    
282     labelwidthstring = fl_get_input(dialog_->input_labelwidth);
283     noindent = fl_get_button(dialog_->check_noindent);
284     Spacing::Space linespacing = Spacing::Default;
285     string other_linespacing;
286     switch (fl_get_choice(dialog_->choice_linespacing)) {
287         case 1: linespacing = Spacing::Default; break;
288         case 2: linespacing = Spacing::Single; break;
289         case 3: linespacing = Spacing::Onehalf; break;
290         case 4: linespacing = Spacing::Double; break;
291         case 5:
292             linespacing = Spacing::Other;
293             other_linespacing = fl_get_input(dialog_->input_linespacing);
294             break;
295     }
296
297     Spacing const spacing(linespacing, other_linespacing);
298     LyXText * text(lv_->view()->getLyXText());
299     text->setParagraph(lv_->view(), line_top, line_bottom, pagebreak_top,
300                        pagebreak_bottom, space_top, space_bottom, spacing,
301                        align, labelwidthstring, noindent);
302
303
304     // Actually apply these settings
305     lv_->view()->update(text, 
306                         BufferView::SELECT | BufferView::FITCUR | BufferView::CHANGE);
307     lv_->buffer()->markDirty();
308     setMinibuffer(lv_, _("Paragraph layout set"));
309 }
310
311
312 void FormParagraph::update()
313 {
314     if (!dialog_.get())
315         return;
316
317     // Do this first; some objects may be de/activated subsequently.
318     bc_.readOnly(lv_->buffer()->isReadonly());
319
320     Buffer * buf = lv_->view()->buffer();
321
322     /// Record the paragraph
323     par_ = getCurrentParagraph();
324
325     fl_set_input(dialog_->input_labelwidth,
326                  par_->getLabelWidthString().c_str());
327     setEnabled(dialog_->input_labelwidth,
328                (par_->getLabelWidthString() != _("Senseless with this layout!")));
329
330     fl_set_button(dialog_->radio_align_right, 0);
331     fl_set_button(dialog_->radio_align_left, 0);
332     fl_set_button(dialog_->radio_align_center, 0);
333     fl_set_button(dialog_->radio_align_block, 0);
334
335     LyXTextClass const & tclass = textclasslist[buf->params.textclass];
336     
337     int align = par_->getAlign();
338     if (align == LYX_ALIGN_LAYOUT)
339             align = tclass[par_->layout()].align;
340
341     switch (align) {
342     case LYX_ALIGN_RIGHT:
343         fl_set_button(dialog_->radio_align_right, 1);
344         break;
345     case LYX_ALIGN_LEFT:
346         fl_set_button(dialog_->radio_align_left, 1);
347         break;
348     case LYX_ALIGN_CENTER:
349         fl_set_button(dialog_->radio_align_center, 1);
350         break;
351     default:
352         fl_set_button(dialog_->radio_align_block, 1);
353         break;
354     }
355
356     LyXAlignment alignpos = tclass[par_->layout()].alignpossible;
357
358     setEnabled(dialog_->radio_align_block,  bool(alignpos & LYX_ALIGN_BLOCK));
359     setEnabled(dialog_->radio_align_center, bool(alignpos & LYX_ALIGN_CENTER));
360     setEnabled(dialog_->radio_align_left,   bool(alignpos & LYX_ALIGN_LEFT));
361     setEnabled(dialog_->radio_align_right,  bool(alignpos & LYX_ALIGN_RIGHT));
362     
363     // no inset-text-owned paragraph may have pagebreaks
364     setEnabled(dialog_->check_pagebreaks_top, !par_->inInset());
365     setEnabled(dialog_->check_pagebreaks_bottom, !par_->inInset());
366
367     fl_set_button(dialog_->check_lines_top,
368                   par_->params().lineTop());
369     fl_set_button(dialog_->check_lines_bottom,
370                   par_->params().lineBottom());
371     fl_set_button(dialog_->check_pagebreaks_top,
372                   par_->params().pagebreakTop());
373     fl_set_button(dialog_->check_pagebreaks_bottom,
374                   par_->params().pagebreakBottom());
375     fl_set_button(dialog_->check_noindent,
376                   par_->params().noindent());
377
378     int linespacing;
379     Spacing const space = par_->params().spacing();
380
381     switch (space.getSpace()) {
382         default: linespacing = 1; break;
383         case Spacing::Single: linespacing = 2; break;
384         case Spacing::Onehalf: linespacing = 3; break;
385         case Spacing::Double: linespacing = 4; break;
386         case Spacing::Other: linespacing = 5; break;
387     }
388  
389     fl_set_choice(dialog_->choice_linespacing, linespacing);
390     if (space.getSpace() == Spacing::Other) {
391         string const sp = tostr(space.getValue());
392         fl_set_input(dialog_->input_linespacing, sp.c_str());
393         setEnabled(dialog_->input_linespacing, true);
394     } else {
395         fl_set_input(dialog_->input_linespacing, "");
396         setEnabled(dialog_->input_linespacing, false);
397     }
398
399     fl_set_input (dialog_->input_space_above, "");
400
401     setEnabled(dialog_->input_space_above, false);
402     setEnabled(dialog_->choice_value_space_above, false);
403     switch (par_->params().spaceTop().kind()) {
404     case VSpace::NONE:
405         fl_set_choice (dialog_->choice_space_above, 1);
406         break;
407     case VSpace::DEFSKIP:
408         fl_set_choice (dialog_->choice_space_above, 2);
409         break;
410     case VSpace::SMALLSKIP:
411         fl_set_choice (dialog_->choice_space_above, 3);
412         break;
413     case VSpace::MEDSKIP:
414         fl_set_choice (dialog_->choice_space_above, 4);
415         break;
416     case VSpace::BIGSKIP:
417         fl_set_choice (dialog_->choice_space_above, 5);
418         break;
419     case VSpace::VFILL:
420         fl_set_choice (dialog_->choice_space_above, 6);
421         break;
422     case VSpace::LENGTH:
423     {
424         fl_set_choice (dialog_->choice_space_above, 7);
425         setEnabled(dialog_->input_space_above, true);
426         setEnabled(dialog_->choice_value_space_above, true);
427         bool const metric = lyxrc.default_papersize > 3;
428         string const default_unit = metric ? "cm" : "in";
429         string const length = par_->params().spaceTop().length().asString();
430         updateWidgetsFromLengthString(dialog_->input_space_above,
431                                               dialog_->choice_value_space_above,
432                                               length, default_unit);
433         break;
434     }
435     }
436     
437     fl_set_button (dialog_->check_space_above,
438            par_->params().spaceTop().keep());
439     fl_set_input (dialog_->input_space_below, "");
440
441     setEnabled(dialog_->input_space_below, false);
442     setEnabled(dialog_->choice_value_space_below, false);
443     switch (par_->params().spaceBottom().kind()) {
444     case VSpace::NONE:
445         fl_set_choice (dialog_->choice_space_below, 1);
446         break;
447     case VSpace::DEFSKIP:
448         fl_set_choice (dialog_->choice_space_below, 2);
449         break;
450     case VSpace::SMALLSKIP:
451         fl_set_choice (dialog_->choice_space_below, 3);
452         break;
453     case VSpace::MEDSKIP:
454         fl_set_choice (dialog_->choice_space_below, 4);
455         break;
456     case VSpace::BIGSKIP:
457         fl_set_choice (dialog_->choice_space_below, 5);
458         break;
459     case VSpace::VFILL:
460         fl_set_choice (dialog_->choice_space_below, 6);
461         break;
462     case VSpace::LENGTH:
463     {
464         fl_set_choice (dialog_->choice_space_below, 7);
465         setEnabled(dialog_->input_space_below, true);
466         setEnabled(dialog_->choice_value_space_below, true);
467         bool const metric = lyxrc.default_papersize > 3;
468         string const default_unit = metric ? "cm" : "in";
469         string const length =
470                 par_->params().spaceBottom().length().asString();
471         updateWidgetsFromLengthString(dialog_->input_space_below,
472                                               dialog_->choice_value_space_below,
473                                               length, default_unit);
474         break;
475     }
476     }
477
478     fl_set_button(dialog_->check_space_below,
479                   par_->params().spaceBottom().keep());
480     fl_set_button(dialog_->check_noindent,
481                   par_->params().noindent());
482 }
483
484
485 bool FormParagraph::input(FL_OBJECT * ob, long)
486 {
487     bool valid = true; 
488
489     fl_hide_object(dialog_->text_warning);
490
491     // First check the buttons which are exclusive and you have to
492     // check only the actuall de/activated button.
493     //
494     // "Synchronize" the choices and input fields, making it
495     // impossible to commit senseless data.
496
497     if (ob == dialog_->choice_space_above) {
498         if (fl_get_choice (dialog_->choice_space_above) != 7) {
499             fl_set_input (dialog_->input_space_above, "");
500             setEnabled (dialog_->input_space_above, false);
501             setEnabled (dialog_->choice_value_space_above, false);
502         } else {
503             setEnabled (dialog_->input_space_above, !lv_->buffer()->isReadonly());
504             setEnabled (dialog_->choice_value_space_above, !lv_->buffer()->isReadonly());
505             bool const metric = lyxrc.default_papersize > 3;
506             int const default_unit = metric ? 8 : 9;
507             if (strip(fl_get_input(dialog_->input_space_above)).empty())
508                 fl_set_choice(dialog_->choice_value_space_above,
509                               default_unit);
510         }
511     }
512     if (ob == dialog_->choice_space_below) {
513         if (fl_get_choice (dialog_->choice_space_below) != 7) {
514             fl_set_input (dialog_->input_space_below, "");
515             setEnabled (dialog_->input_space_below, false);
516             setEnabled (dialog_->choice_value_space_below, false);
517         } else {
518             setEnabled (dialog_->input_space_below, !lv_->buffer()->isReadonly());
519             setEnabled (dialog_->choice_value_space_below, !lv_->buffer()->isReadonly());
520             bool const metric = lyxrc.default_papersize > 3;
521             int const default_unit = metric ? 8 : 9;
522             if (strip(fl_get_input(dialog_->input_space_below)).empty())
523                     fl_set_choice(dialog_->choice_value_space_below,
524                                   default_unit);
525         }
526     }
527  
528     //
529     // warnings if input is senseless
530     //
531     string input = fl_get_input (dialog_->input_space_above);
532     bool invalid = false;
533
534     if (fl_get_choice(dialog_->choice_space_above)==7)
535         invalid = !input.empty() && !isValidGlueLength(input) && !isStrDbl(input);
536
537     input = fl_get_input (dialog_->input_space_below);
538
539     if (fl_get_choice(dialog_->choice_space_below)==7)
540         invalid = invalid
541                 || (!input.empty() && !isValidGlueLength(input) && !isStrDbl(input));
542
543     if (ob == dialog_->input_space_above || ob == dialog_->input_space_below) {
544         if (invalid) {
545             fl_set_object_label(dialog_->text_warning,
546                 _("Warning: Invalid Length (valid example: 10mm)"));
547             fl_show_object(dialog_->text_warning);
548             return false;
549         } else {
550             fl_hide_object(dialog_->text_warning);
551             return true;
552         }
553     }
554
555     if (fl_get_choice (dialog_->choice_linespacing) == 5)
556         setEnabled (dialog_->input_linespacing, true);
557     else {
558         setEnabled (dialog_->input_linespacing, false);
559         fl_set_input (dialog_->input_linespacing, "");
560     }
561
562     double spacing(strToDbl(fl_get_input(dialog_->input_linespacing)));
563
564     if (fl_get_choice (dialog_->choice_linespacing) == 5
565         && int(spacing) == 0)
566         valid = false;
567
568     return valid;
569 }