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