]> git.lyx.org Git - lyx.git/blob - src/frontends/gtk/GGraphics.C
enable Font cache only for MacOSX and inline width() for other platform.
[lyx.git] / src / frontends / gtk / GGraphics.C
1 /**
2  * \file GGraphics.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 "GGraphics.h"
22 #include "ControlGraphics.h"
23
24 #include "ghelpers.h"
25
26 #include "controllers/helper_funcs.h"
27
28 #include "insets/insetgraphicsParams.h"
29 #include "paper.h"
30 #include "lyxrc.h" // for lyxrc.default_papersize
31
32 #include "support/convert.h"
33 #include "support/lyxlib.h"  // for float_equal
34 #include "support/lstrings.h"
35
36 #include "debug.h"
37
38 using std::vector;
39 using std::string;
40
41 namespace lyx {
42
43 using support::float_equal;
44 using support::token;
45
46 namespace frontend {
47
48 namespace {
49 string defaultUnit("cm");
50 } // namespace anon
51
52 GGraphics::GGraphics(Dialog & parent)
53         : GViewCB<ControlGraphics, GViewGladeB>(parent, lyx::to_utf8(_("Graphics")), false)
54 {}
55
56
57 void GGraphics::doBuild()
58 {
59         string const gladeName = findGladeFile("graphics");
60         xml_ = Gnome::Glade::Xml::create(gladeName);
61
62         Gtk::Button * button;
63         xml_->get_widget("Close", button);
64         setCancel(button);
65         xml_->get_widget("Ok", button);
66         setOK(button);
67         xml_->get_widget("Apply", button);
68         setApply(button);
69         xml_->get_widget("Restore", button);
70         setRestore(button);
71
72         xml_->get_widget("Notebook", notebook_);
73
74         // File Page
75         xml_->get_widget("File", fileentry_);
76         xml_->get_widget("DisplayScale", displayscalespin_);
77         xml_->get_widget("OutputScale", outputscalespin_);
78         xml_->get_widget("Browse", browsebutton_);
79         xml_->get_widget("Edit", editbutton_);
80         xml_->get_widget("Display", displaycombo_);
81         xml_->get_widget_derived("Width", widthlengthentry_);
82         xml_->get_widget_derived("Height", heightlengthentry_);
83         xml_->get_widget("MaintainAspectRatio", aspectcheck_);
84
85         xml_->get_widget("SetScaling", setscalingradio_);
86         xml_->get_widget("SetSize", setsizeradio_);
87
88         // Bounding Box Page
89         xml_->get_widget("ClipToBoundingBox", clipcheck_);
90         xml_->get_widget("RightTopX", righttopxspin_);
91         xml_->get_widget("RightTopY", righttopyspin_);
92         xml_->get_widget("LeftBottomX", leftbottomxspin_);
93         xml_->get_widget("LeftBottomY", leftbottomyspin_);
94         xml_->get_widget("BoundingUnits", bbunitscombo_);
95         xml_->get_widget("GetFromFile", bbfromfilebutton_);
96
97         // Extra Page
98         xml_->get_widget("Angle", anglespin_);
99         xml_->get_widget("Origin", origincombo_);
100         xml_->get_widget("UseSubfigure", subfigcheck_);
101         xml_->get_widget("SubfigureCaption", subfigentry_);
102         xml_->get_widget("LatexOptions", latexoptsentry_);
103         xml_->get_widget("DraftMode", draftcheck_);
104         xml_->get_widget("UnzipOnExport", unzipcheck_);
105
106         // Setup the columnrecord we use for combos
107         cols_.add(stringcol_);
108
109         // The file page
110
111         // Disable for read-only documents.
112         bcview().addReadOnly(browsebutton_);
113         bcview().addReadOnly(aspectcheck_);
114
115         fileentry_->signal_changed().connect(
116                 sigc::mem_fun(*this, &GGraphics::onInput));
117         displayscalespin_->signal_changed().connect(
118                 sigc::mem_fun(*this, &GGraphics::onInput));
119         displaycombo_->signal_changed().connect(
120                 sigc::mem_fun(*this, &GGraphics::onInput));
121         outputscalespin_->signal_changed().connect(
122                 sigc::mem_fun(*this, &GGraphics::onInput));
123         heightlengthentry_->signal_changed().connect(
124                 sigc::mem_fun(*this, &GGraphics::onInput));
125         widthlengthentry_->signal_changed().connect(
126                 sigc::mem_fun(*this, &GGraphics::onInput));
127         aspectcheck_->signal_toggled().connect(
128                 sigc::mem_fun(*this, &GGraphics::onInput));
129
130         setscalingradio_->signal_toggled().connect(
131                 sigc::mem_fun(*this, &GGraphics::onSizingModeChange));
132         setsizeradio_->signal_toggled().connect(
133                 sigc::mem_fun(*this, &GGraphics::onSizingModeChange));
134
135         browsebutton_->signal_clicked().connect(
136                 sigc::mem_fun(*this, &GGraphics::onBrowseClicked));
137
138         editbutton_->signal_clicked().connect(
139                 sigc::mem_fun(*this, &GGraphics::onEditClicked));
140
141         // the bounding box page
142         leftbottomxspin_->signal_changed().connect(
143                 sigc::mem_fun(*this, &GGraphics::onBBChange));
144         leftbottomyspin_->signal_changed().connect(
145                 sigc::mem_fun(*this, &GGraphics::onBBChange));
146         righttopxspin_->signal_changed().connect(
147                 sigc::mem_fun(*this, &GGraphics::onBBChange));
148         righttopyspin_->signal_changed().connect(
149                 sigc::mem_fun(*this, &GGraphics::onBBChange));
150         bbunitscombo_->signal_changed().connect(
151                 sigc::mem_fun(*this, &GGraphics::onBBChange));
152         clipcheck_->signal_toggled().connect(
153                 sigc::mem_fun(*this, &GGraphics::onBBChange));
154
155         bbfromfilebutton_->signal_clicked().connect(
156                 sigc::mem_fun(*this, &GGraphics::onBBFromFileClicked));
157
158         // disable for read-only documents
159         bcview().addReadOnly(bbfromfilebutton_);
160         bcview().addReadOnly(clipcheck_);
161         PopulateComboBox(bbunitscombo_, getBBUnits());
162
163
164         // the extra section
165
166         // disable for read-only documents
167         bcview().addReadOnly(anglespin_);
168         bcview().addReadOnly(origincombo_);
169         bcview().addReadOnly(subfigcheck_);
170         bcview().addReadOnly(latexoptsentry_);
171         bcview().addReadOnly(draftcheck_);
172         bcview().addReadOnly(unzipcheck_);
173
174         anglespin_->signal_changed().connect(
175                 sigc::mem_fun(*this, &GGraphics::onInput));
176         origincombo_->signal_changed().connect(
177                 sigc::mem_fun(*this, &GGraphics::onInput));
178         subfigentry_->signal_changed().connect(
179                 sigc::mem_fun(*this, &GGraphics::onInput));
180         latexoptsentry_->signal_changed().connect(
181                 sigc::mem_fun(*this, &GGraphics::onInput));
182         draftcheck_->signal_toggled().connect(
183                 sigc::mem_fun(*this, &GGraphics::onInput));
184         unzipcheck_->signal_toggled().connect(
185                 sigc::mem_fun(*this, &GGraphics::onInput));
186
187         subfigcheck_->signal_toggled().connect(
188                 sigc::mem_fun(*this, &GGraphics::onSubFigCheckToggled));
189
190         vector<RotationOriginPair> origindata = getRotationOriginData();
191
192         // Store the identifiers for later
193         origins_ = getSecond(origindata);
194         PopulateComboBox(origincombo_, getFirst(origindata));
195 }
196
197
198 void GGraphics::onSizingModeChange()
199 {
200         bool const scalingmode = setscalingradio_->get_active();
201
202         outputscalespin_->set_sensitive(scalingmode);
203         widthlengthentry_->set_sensitive(!scalingmode);
204         heightlengthentry_->set_sensitive(!scalingmode);
205         aspectcheck_->set_sensitive(!scalingmode);
206         bc().input(ButtonPolicy::SMI_VALID);
207 }
208
209
210 void GGraphics::PopulateComboBox(Gtk::ComboBox * combo,
211                                   vector<string> const & strings)
212 {
213         Glib::RefPtr<Gtk::ListStore> model = Gtk::ListStore::create(cols_);
214         vector<string>::const_iterator it = strings.begin();
215         vector<string>::const_iterator end = strings.end();
216         for (int rowindex = 0; it != end; ++it, ++rowindex) {
217                 Gtk::TreeModel::iterator row = model->append();
218                 (*row)[stringcol_] = *it;
219         }
220
221         combo->set_model(model);
222         Gtk::CellRendererText * cell = Gtk::manage(new Gtk::CellRendererText);
223         combo->pack_start(*cell, true);
224         combo->add_attribute(*cell, "text", 0);
225 }
226
227
228 void GGraphics::apply()
229 {
230         // Create the parameters structure and fill the data from the dialog.
231         InsetGraphicsParams & igp = controller().params();
232
233         // the file section
234         igp.filename.set(fileentry_->get_text(),
235                          kernel().bufferFilepath());
236
237         igp.lyxscale =
238                 static_cast<int>(displayscalespin_->get_adjustment()->get_value());
239         if (igp.lyxscale == 0) {
240                 igp.lyxscale = 100;
241         }
242
243         switch (displaycombo_->get_active_row_number()) {
244         case 4:
245                 igp.display = graphics::NoDisplay;
246                 break;
247         case 3:
248                 igp.display = graphics::ColorDisplay;
249                 break;
250         case 2:
251                 igp.display = graphics::GrayscaleDisplay;
252                 break;
253         case 1:
254                 igp.display = graphics::MonochromeDisplay;
255                 break;
256         case 0:
257                 igp.display = graphics::DefaultDisplay;
258         }
259
260         if (setscalingradio_->get_active()) {
261                 float scaleValue = outputscalespin_->get_adjustment()->get_value();
262                 igp.scale = convert<string>(scaleValue);
263                 if (float_equal(scaleValue, 0.0, 0.05))
264                         igp.scale = string();
265                 igp.width = LyXLength();
266         } else {
267                 igp.scale = string();
268                 igp.width = widthlengthentry_->get_length();
269         }
270
271         igp.height = heightlengthentry_->get_length();
272
273         igp.keepAspectRatio = aspectcheck_->get_active();
274         igp.draft = draftcheck_->get_active();
275         igp.noUnzip = !unzipcheck_->get_active();
276
277         // the bb section
278
279         if (!controller().bbChanged) {
280                 // don't write anything
281                 igp.bb.erase();
282         } else {
283                 Glib::ustring const bbunit = (*bbunitscombo_->get_active())[stringcol_];
284                 string bb;
285
286                 if (leftbottomxspin_->get_text().empty())
287                         bb = "0";
288                 else
289                         bb = leftbottomxspin_->get_text() + bbunit;
290
291                 bb += ' ';
292
293                 if (leftbottomyspin_->get_text().empty())
294                         bb += "0";
295                 else
296                         bb += leftbottomyspin_->get_text() + bbunit;
297
298                 bb += ' ';
299
300                 if (righttopxspin_->get_text().empty())
301                         bb += "0";
302                 else
303                         bb += righttopxspin_->get_text() + bbunit;
304
305                 bb += ' ';
306
307                 if (righttopyspin_->get_text().empty())
308                         bb += "0";
309                 else
310                         bb += righttopyspin_->get_text() + bbunit;
311
312                 /// The bounding box with "xLB yLB yRT yRT ", divided by a space!
313                 igp.bb = bb;
314         }
315         igp.clip = clipcheck_->get_active();
316
317         // the extra section
318         igp.rotateAngle = convert<string>(anglespin_->get_adjustment()->get_value());
319
320         int const origin_pos = origincombo_->get_active_row_number();
321         igp.rotateOrigin = origins_[origin_pos];
322
323         igp.subcaption = subfigcheck_->get_active();
324         igp.subcaptionText = subfigentry_->get_text();
325
326         igp.special = latexoptsentry_->get_text();
327 }
328
329
330 void GGraphics::update() {
331         // set the right default unit
332         defaultUnit = getDefaultUnit();
333
334         // Update dialog with details from inset
335         InsetGraphicsParams & igp = controller().params();
336
337         // the file section
338         string const name =
339                 igp.filename.outputFilename(kernel().bufferFilepath());
340         fileentry_->set_text(name);
341         displayscalespin_->get_adjustment()->set_value(igp.lyxscale);
342
343
344         switch (igp.display) {
345         case graphics::NoDisplay:
346                 displaycombo_->set_active(4);
347                 break;
348         case graphics::ColorDisplay:
349                 displaycombo_->set_active(3);
350                 break;
351         case graphics::GrayscaleDisplay:
352                 displaycombo_->set_active(2);
353                 break;
354         case graphics::MonochromeDisplay:
355                 displaycombo_->set_active(1);
356                 break;
357         case graphics::DefaultDisplay:
358                 displaycombo_->set_active(0);
359         }
360
361         outputscalespin_->get_adjustment()->set_value(convert<double>(igp.scale));
362
363         widthlengthentry_->set_length(igp.width);
364         heightlengthentry_->set_length(igp.height);
365
366         if (!igp.scale.empty()
367                 && !float_equal(convert<double>(igp.scale), 0.0, 0.05)) {
368                 // scaling sizing mode
369                 setscalingradio_->set_active(true);
370         } else if (!igp.width.empty() && !igp.height.empty()) {
371                 setsizeradio_->set_active(true);
372         } else {
373                 outputscalespin_->get_adjustment()->set_value(100.0);
374                 setscalingradio_->set_active(true);
375         }
376         onSizingModeChange();
377
378         aspectcheck_->set_active(igp.keepAspectRatio);
379         draftcheck_->set_active(igp.draft);
380         unzipcheck_->set_active(!igp.noUnzip);
381
382         // the bb section
383         // set the bounding box values, if exists. First we need the whole
384         // path, because the controller knows nothing about the doc-dir
385         updateBB(igp.filename.absFilename(), igp.bb);
386         clipcheck_->set_active(igp.clip);
387
388         // the extra section
389         anglespin_->get_adjustment()->set_value(convert<double>(igp.rotateAngle));
390
391         int origin_pos;
392         if (igp.rotateOrigin.empty()) {
393                 origin_pos = 0;
394         } else {
395                 origin_pos = findPos(origins_, igp.rotateOrigin);
396         }
397         origincombo_->set_active(origin_pos);
398
399
400         subfigcheck_->set_active(igp.subcaption);
401         subfigentry_->set_text(igp.subcaptionText);
402         subfigentry_->set_sensitive(subfigcheck_->get_active());
403         latexoptsentry_->set_text(igp.special);
404
405         // open dialog in the file-tab, whenever filename is empty
406         if (igp.filename.empty()) {
407                 notebook_->set_current_page(0);
408         }
409
410
411         bc().input(ButtonPolicy::SMI_INVALID);
412 }
413
414
415 void GGraphics::updateBB(string const & filename, string const & bb_inset)
416 {
417         // Update dialog with details from inset
418         // set the bounding box values, if exists. First we need the whole
419         // path, because the controller knows nothing about the doc-dir
420
421         if (bb_inset.empty()) {
422                 lyxerr[Debug::GRAPHICS]
423                         << "GGraphics::updateBB() [no BoundingBox]\n";
424                 string const bb = controller().readBB(filename);
425                 if (!bb.empty()) {
426                         // get the values from the file
427                         // in this case we always have the point-unit
428                         leftbottomxspin_->set_text(token(bb, ' ', 0));
429                         leftbottomyspin_->set_text(token(bb, ' ', 1));
430                         righttopxspin_->set_text(token(bb, ' ', 2));
431                         righttopyspin_->set_text(token(bb, ' ', 3));
432                 } else {
433                         // no bb from file
434                         leftbottomxspin_->set_text("");
435                         leftbottomyspin_->set_text("");
436                         righttopxspin_->set_text("");
437                         righttopyspin_->set_text("");
438                 }
439                 unitsComboFromLength(bbunitscombo_, stringcol_,
440                                      LyXLength("bp"), defaultUnit);
441         } else {
442                 // get the values from the inset
443                 lyxerr[Debug::GRAPHICS]
444                         << "FormGraphics::updateBB(): igp has BoundingBox"
445                         << " ["<< bb_inset << "]\n";
446
447                 LyXLength anyLength;
448                 anyLength = LyXLength(token(bb_inset, ' ', 0));
449
450                 unitsComboFromLength(bbunitscombo_, stringcol_, anyLength, defaultUnit);
451
452                 leftbottomxspin_->get_adjustment()->set_value(anyLength.value());
453
454                 anyLength = LyXLength(token(bb_inset, ' ', 1));
455                 leftbottomyspin_->get_adjustment()->set_value(anyLength.value());
456
457                 anyLength = LyXLength(token(bb_inset, ' ', 2));
458                 righttopxspin_->get_adjustment()->set_value(anyLength.value());
459
460                 anyLength = LyXLength(token(bb_inset, ' ', 3));
461                 righttopyspin_->get_adjustment()->set_value(anyLength.value());
462         }
463         controller().bbChanged = false;
464 }
465
466
467 void GGraphics::onBrowseClicked()
468 {
469         // Get the filename from the dialog
470         string const in_name = fileentry_->get_text();
471         string const out_name = controller().browse(in_name);
472         lyxerr[Debug::GRAPHICS]
473                 << "[FormGraphics]out_name: " << out_name << "\n";
474         if (out_name != in_name && !out_name.empty()) {
475                 fileentry_->set_text(out_name);
476         }
477         if (controller().isFilenameValid(out_name) &&
478             !controller().bbChanged) {
479                 updateBB(out_name, string());
480         }
481
482         bc().input(ButtonPolicy::SMI_VALID);
483 }
484
485
486 void GGraphics::onBBChange()
487 {
488         controller().bbChanged = true;
489         bc().input(ButtonPolicy::SMI_VALID);
490 }
491
492
493 void GGraphics::onBBFromFileClicked()
494 {
495         string const filename = fileentry_->get_text();
496         if (!filename.empty()) {
497                 string bb = controller().readBB(filename);
498                 if (!bb.empty()) {
499                         leftbottomxspin_->set_text(token(bb, ' ', 0));
500                         leftbottomyspin_->set_text(token(bb, ' ', 1));
501                         righttopxspin_->set_text(token(bb, ' ', 2));
502                         righttopyspin_->set_text(token(bb, ' ', 3));
503                         unitsComboFromLength(bbunitscombo_, stringcol_,
504                                              LyXLength("bp"), defaultUnit);
505                 }
506                 controller().bbChanged = false;
507         } else {
508                 leftbottomxspin_->set_text("");
509                 leftbottomyspin_->set_text("");
510                 righttopxspin_->set_text("");
511                 righttopyspin_->set_text("");
512                 unitsComboFromLength(bbunitscombo_, stringcol_,
513                                      LyXLength("bp"), defaultUnit);
514         }
515         bc().input(ButtonPolicy::SMI_VALID);
516 }
517
518
519 void GGraphics::onSubFigCheckToggled()
520 {
521         subfigentry_->set_sensitive(subfigcheck_->get_active());
522         bc().input(ButtonPolicy::SMI_VALID);
523 }
524
525
526 void GGraphics::onEditClicked()
527 {
528         controller().editGraphics();
529 }
530
531
532 void GGraphics::onInput()
533 {
534         bc().input(ButtonPolicy::SMI_VALID);
535 }
536
537 } // namespace frontend
538 } // namespace lyx