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