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