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