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