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