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