]> git.lyx.org Git - lyx.git/blob - src/frontends/gtk/GBox.C
some tabular fixes for the problems reported by Helge
[lyx.git] / src / frontends / gtk / GBox.C
1 /**
2  * \file GBox.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author John Spray
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 // Too hard to make concept checks work with this file
14 #ifdef _GLIBCXX_CONCEPT_CHECKS
15 #undef _GLIBCXX_CONCEPT_CHECKS
16 #endif
17 #ifdef _GLIBCPP_CONCEPT_CHECKS
18 #undef _GLIBCPP_CONCEPT_CHECKS
19 #endif
20
21 #include "GBox.h"
22
23 #include "ghelpers.h"
24
25 #include "controllers/ControlBox.h"
26
27 #include "insets/insetbox.h"
28 #include "lengthcommon.h"
29 #include "lyxrc.h" // to set the default length values
30
31 using std::string;
32 using std::vector;
33
34 namespace lyx {
35 namespace frontend {
36
37 namespace {
38 string defaultUnit("cm");
39 } // namespace anon
40
41 GBox::GBox(Dialog & parent)
42         : GViewCB<ControlBox, GViewGladeB>(parent, _("Box Settings"), false)
43 {}
44
45
46 void GBox::doBuild()
47 {
48         string const gladeName = findGladeFile("box");
49         xml_ = Gnome::Glade::Xml::create(gladeName);
50
51         Gtk::Button * closebutton;
52         xml_->get_widget("Close", closebutton);
53         setCancel(closebutton);
54
55         xml_->get_widget("Type", typecombo_);
56         bcview().addReadOnly(typecombo_);
57         xml_->get_widget("InnerBox", innerboxcombo_);
58         bcview().addReadOnly(innerboxcombo_);
59         xml_->get_widget("WidthUnits", widthunitscombo_);
60         bcview().addReadOnly(widthunitscombo_);
61         xml_->get_widget("HeightUnits", heightunitscombo_);
62         bcview().addReadOnly(heightunitscombo_);
63         xml_->get_widget("BoxVertical", boxvertcombo_);
64         bcview().addReadOnly(boxvertcombo_);
65         xml_->get_widget("ContentVertical", contentvertcombo_);
66         bcview().addReadOnly(contentvertcombo_);
67         xml_->get_widget("ContentHorizontal", contenthorzcombo_);
68         bcview().addReadOnly(contenthorzcombo_);
69         xml_->get_widget("Width", widthspin_);
70         bcview().addReadOnly(widthspin_);
71         xml_->get_widget("Height", heightspin_);
72         bcview().addReadOnly(heightspin_);
73
74         cols_.add(stringcol_);
75
76         // fill the box type choice
77         box_gui_tokens(ids_, gui_names_);
78         PopulateComboBox(typecombo_, gui_names_);
79         typecombo_->signal_changed().connect(
80                 sigc::mem_fun(*this, &GBox::onTypeComboChanged));
81
82         // set up innerbox (populated in setInnerType)
83         innerboxstore_ = Gtk::ListStore::create(cols_);
84         innerboxcombo_->set_model(innerboxstore_);
85         Gtk::CellRendererText * cell = Gtk::manage(new Gtk::CellRendererText);
86         innerboxcombo_->pack_start(*cell, true);
87         innerboxcombo_->add_attribute(*cell, "text", 0);
88
89         innerboxcombo_->signal_changed().connect(
90                 sigc::mem_fun(*this, &GBox::onInnerBoxComboChanged));
91
92         boxvertcombo_->signal_changed().connect(
93                 sigc::mem_fun(*this, &GBox::onAlignChanged));
94         contenthorzcombo_->signal_changed().connect(
95                 sigc::mem_fun(*this, &GBox::onAlignChanged));
96         contentvertcombo_->signal_changed().connect(
97                 sigc::mem_fun(*this, &GBox::onAlignChanged));
98
99         heightunitscombo_->signal_changed().connect(
100                 sigc::mem_fun(*this, &GBox::onHeightChanged));
101         widthunitscombo_->signal_changed().connect(
102                 sigc::mem_fun(*this, &GBox::onWidthChanged));
103
104         heightspin_->signal_value_changed().connect(
105                 sigc::mem_fun(*this, &GBox::onHeightChanged));
106         widthspin_->signal_value_changed().connect(
107                 sigc::mem_fun(*this, &GBox::onWidthChanged));
108
109
110         widthunitsstore_ = Gtk::ListStore::create(cols_);
111         widthunitscombo_->set_model(widthunitsstore_);
112         cell = Gtk::manage(new Gtk::CellRendererText);
113         widthunitscombo_->pack_start(*cell, true);
114         widthunitscombo_->add_attribute(*cell, "text", 0);
115         //widthunitscombo_ is populated in setSpecial
116
117         box_gui_tokens_special_length(ids_spec_, gui_names_spec_);
118         vector<string> heightunits = buildLengthUnitList(true);
119         // Append special entries, skipping the first item "None"
120         heightunits.insert(heightunits.end(),
121                 ++gui_names_spec_.begin(), gui_names_spec_.end());
122
123         PopulateComboBox(heightunitscombo_, heightunits);
124 }
125
126
127 void GBox::PopulateComboBox(Gtk::ComboBox * combo,
128                                   vector<string> const & strings
129                                   )
130 {
131         Glib::RefPtr<Gtk::ListStore> model = Gtk::ListStore::create(cols_);
132         vector<string>::const_iterator it = strings.begin();
133         vector<string>::const_iterator end = strings.end();
134         for(; it != end; ++it)
135                 (*model->append())[stringcol_] = *it;
136
137         combo->set_model(model);
138         Gtk::CellRendererText * cell = Gtk::manage(new Gtk::CellRendererText);
139         combo->pack_start(*cell, true);
140         combo->add_attribute(*cell, "text", 0);
141 }
142
143
144 void GBox::update()
145 {
146         applylock_ = true;
147
148         defaultUnit = getDefaultUnit();
149
150         char c = controller().params().pos;
151         boxvertcombo_->set_active(string("tcb").find(c, 0));
152         c = controller().params().inner_pos;
153         contentvertcombo_->set_active(string("tcbs").find(c, 0));
154         c = controller().params().hor_pos;
155         contenthorzcombo_->set_active(string("lcrs").find(c, 0));
156
157         string type(controller().params().type);
158         for (size_t i = 0; i < gui_names_.size(); ++i) {
159                 if (type == ids_[i])
160                         typecombo_->set_active(i);
161         }
162
163         applylock_ = false;
164         updateInnerBoxCombo();
165         applylock_ = true;
166
167         bool ibox = controller().params().inner_box;
168         boxvertcombo_->set_sensitive(ibox);
169         contentvertcombo_->set_sensitive(ibox);
170         contenthorzcombo_->set_sensitive(!ibox);
171         setSpecial(ibox);
172
173         widthspin_->get_adjustment()->set_value(controller().params().width.value());
174         unitsComboFromLength(widthunitscombo_, stringcol_,
175                              controller().params().width, defaultUnit);
176
177         string const special(controller().params().special);
178         if (!special.empty() && special != "none") {
179                 string spc;
180                 for (size_t i = 0; i < gui_names_spec_.size(); ++i) {
181                         if (special == ids_spec_[i])
182                                 spc = gui_names_spec_[i];
183                 }
184                 for (size_t j = 0; j
185                         < widthunitsstore_->children().size(); ++j) {
186                         if (widthunitsstore_->children()[j][stringcol_] == spc)
187                                 widthunitscombo_->set_active(j);
188                 }
189         }
190
191         heightspin_->get_adjustment()->set_value(controller().params().height.value());
192         unitsComboFromLength(heightunitscombo_, stringcol_,
193                              controller().params().height, defaultUnit);
194
195         string const height_special(controller().params().height_special);
196         if (!height_special.empty() && height_special != "none") {
197                 string hspc;
198                 for (size_t i = 0; i < gui_names_spec_.size(); ++i) {
199                         if (height_special == ids_spec_[i]) {
200                                 hspc = gui_names_spec_[i];
201                         }
202                 }
203                 for (size_t j = 0; j < heightunitscombo_->get_model()->children().size(); ++j) {
204                         if (heightunitscombo_->get_model()->children()[j][stringcol_] == hspc) {
205                                 heightunitscombo_->set_active(j);
206                         }
207                 }
208         }
209
210         heightspin_->set_sensitive(ibox);
211         heightunitscombo_->set_sensitive(ibox);
212         applylock_ = false;
213 }
214
215
216 void GBox::setSpecial(bool ibox)
217 {
218         bool const oldlock = applylock_;
219         applylock_ = true;
220
221         unsigned int const initselection = widthunitscombo_->get_active_row_number();
222         widthunitsstore_->clear();
223         vector<string> normalunits = buildLengthUnitList(true);
224         if (ibox) {
225                 vector<string>::const_iterator it = normalunits.begin();
226                 vector<string>::const_iterator end = normalunits.end();
227                 for(; it != end; ++it)
228                         (*widthunitsstore_->append())[stringcol_] = *it;
229         } else {
230                 vector<string>::const_iterator it = normalunits.begin();
231                 vector<string>::const_iterator end = normalunits.end();
232                 for(; it != end; ++it)
233                         (*widthunitsstore_->append())[stringcol_] = *it;
234                 // Skip the first item "None"
235                 it = ++gui_names_spec_.begin();
236                 end = gui_names_spec_.end();
237                 for(; it != end; ++it)
238                         (*widthunitsstore_->append())[stringcol_] = *it;
239         }
240
241         size_t const store_size = widthunitsstore_->children().size();
242         if (initselection >= store_size) {
243                 widthunitscombo_->set_active(0);
244                 onWidthChanged();
245         } else {
246                 widthunitscombo_->set_active(initselection);
247         }
248         applylock_ = oldlock;
249 }
250
251
252 void GBox::updateInnerBoxCombo()
253 {
254         bool const oldlock = applylock_;
255         applylock_ = true;
256         // with "frameless" boxes, inner box is mandatory (i.e. is the actual box)
257         // we have to remove "none" then and adjust the combo
258
259         // default: minipage
260         int i = 2;
261         if (!controller().params().inner_box)
262                 // none
263                 i = 0;
264         if (controller().params().use_parbox)
265                 // parbox
266                 i = 1;
267         bool frameless = (controller().params().type == "Frameless");
268
269         int const oldsize = innerboxstore_->children().size();
270         // Store the initial selection in 0,1,2 format
271         int oldselection = -1;
272         if (oldsize == 2)
273                 oldselection = innerboxcombo_->get_active_row_number() + 1;
274         else if (oldsize == 3)
275                 oldselection = innerboxcombo_->get_active_row_number();
276
277         if (frameless && oldsize != 2) {
278                 innerboxstore_->clear();
279                 (*innerboxstore_->append())[stringcol_] = _("Parbox");
280                 (*innerboxstore_->append())[stringcol_] = _("Minipage");
281                 // Cope when the backend asks for no inner box in
282                 // a frameless box
283                 if (i == 0) {
284                         applylock_ = false;
285                         innerboxcombo_->set_active(i);
286                         applylock_ = true;
287                 } else
288                         innerboxcombo_->set_active(i - 1);
289         } else if (!frameless && oldsize != 3) {
290                 innerboxstore_->clear();
291                 (*innerboxstore_->append())[stringcol_] = _("None");
292                 (*innerboxstore_->append())[stringcol_] = _("Parbox");
293                 (*innerboxstore_->append())[stringcol_] = _("Minipage");
294                 innerboxcombo_->set_active(i);
295         } else {
296                 // we're not changing the liststore, just selecting i
297                 if (frameless)
298                         innerboxcombo_->set_active(i - 1);
299                 else
300                         innerboxcombo_->set_active(i);
301         }
302
303         // Update the width units list if we've changed inner box type
304         if (i != oldselection)
305                 setSpecial(i != 0);
306
307         applylock_ = oldlock;
308 }
309
310
311 void GBox::onInnerBoxComboChanged()
312 {
313         if (applylock_)
314                 return;
315
316         controller().params().use_parbox =
317                 (*innerboxcombo_->get_active())[stringcol_] ==  _("Parbox");
318
319         bool const ibox = (*innerboxcombo_->get_active())[stringcol_] != _("None");
320         controller().params().inner_box = ibox;
321         setSpecial(ibox);
322
323         boxvertcombo_->set_sensitive(ibox);
324         contentvertcombo_->set_sensitive(ibox);
325         contenthorzcombo_->set_sensitive(!ibox);
326         heightspin_->set_sensitive(ibox);
327         heightunitscombo_->set_sensitive(ibox);
328         // wtf? form_->set_sensitive(ibox);
329
330         controller().dispatchParams();
331 }
332
333
334 void GBox::onTypeComboChanged()
335 {
336         int const index = typecombo_->get_active_row_number();
337         controller().params().type = ids_[index];
338
339         bool frameless = (index == 0);
340         if (frameless) {
341                 boxvertcombo_->set_sensitive(true);
342                 contentvertcombo_->set_sensitive(true);
343                 contenthorzcombo_->set_sensitive(false);
344                 heightspin_->set_sensitive(true);
345                 heightunitscombo_->set_sensitive(true);
346                 //wtf? form_->setSpecial(true);
347         }
348         //int itype = innerboxcombo_->get_active_row_number();
349         controller().dispatchParams();
350
351         updateInnerBoxCombo();
352 }
353
354
355 void GBox::onHeightChanged()
356 {
357         if (applylock_)
358                 return;
359
360         // "None"
361         int i = 0;
362         bool spec = false;
363         Glib::ustring special = (*heightunitscombo_->get_active())[stringcol_];
364         for (size_t j = 1; j < gui_names_spec_.size() ; ++j) {
365                 if (gui_names_spec_[j] == special) {
366                         i=j;
367                         spec = true;
368                 }
369         }
370         controller().params().height_special = ids_spec_[i];
371
372         string height;
373         if (spec) {
374                 height = heightspin_->get_text();
375                 // beware: bogosity! the unit is simply ignored in this case
376                 height += "in";
377         } else {
378                 Glib::ustring const heightunit =
379                         (*heightunitscombo_->get_active())[stringcol_];
380                 height = heightspin_->get_text() + heightunit;
381         }
382
383         controller().params().height = LyXLength(height);
384         controller().dispatchParams();
385 }
386
387
388 void GBox::onWidthChanged()
389 {
390         if (applylock_)
391                 return;
392
393         int i = 0;
394         bool spec = false;
395         Glib::ustring special = (*widthunitscombo_->get_active())[stringcol_];
396         for (size_t j = 1; j < gui_names_spec_.size() ; ++j) {
397                 if (gui_names_spec_[j] == special) {
398                         i = j;
399                         spec = true;
400                 }
401         }
402         controller().params().special = ids_spec_[i];
403
404         string width;
405         if (spec) {
406                 width = widthspin_->get_text();
407                 // beware: bogosity! the unit is simply ignored in this case
408                 width += "in";
409         } else {
410                 Glib::ustring const widthunit =
411                         (*widthunitscombo_->get_active())[stringcol_];
412                 width = widthspin_->get_text() + widthunit;
413         }
414
415         controller().params().width = LyXLength(width);
416         controller().dispatchParams();
417 }
418
419
420 void GBox::onAlignChanged()
421 {
422         if (applylock_)
423                 return;
424
425         controller().params().pos =
426                 "tcb"[boxvertcombo_->get_active_row_number()];
427         controller().params().inner_pos =
428                 "tcbs"[contenthorzcombo_->get_active_row_number()];
429         controller().params().hor_pos =
430                 "lcrs"[contentvertcombo_->get_active_row_number()];
431
432         controller().dispatchParams();
433 }
434
435 } // namespace frontend
436 } // namespace lyx