3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
8 * Full author contact details are available in file CREDITS.
13 // Too hard to make concept checks work with this file
14 #ifdef _GLIBCXX_CONCEPT_CHECKS
15 #undef _GLIBCXX_CONCEPT_CHECKS
17 #ifdef _GLIBCPP_CONCEPT_CHECKS
18 #undef _GLIBCPP_CONCEPT_CHECKS
21 #include "GGraphics.h"
22 #include "ControlGraphics.h"
26 #include "controllers/helper_funcs.h"
28 #include "insets/insetgraphicsParams.h"
30 #include "lyxrc.h" // for lyxrc.default_papersize
32 #include "support/convert.h"
33 #include "support/lyxlib.h" // for float_equal
34 #include "support/lstrings.h"
43 using support::float_equal;
49 string defaultUnit("cm");
52 GGraphics::GGraphics(Dialog & parent)
53 : GViewCB<ControlGraphics, GViewGladeB>(parent, _("Graphics"), false)
57 void GGraphics::doBuild()
59 string const gladeName = findGladeFile("graphics");
60 xml_ = Gnome::Glade::Xml::create(gladeName);
63 xml_->get_widget("Close", button);
65 xml_->get_widget("Ok", button);
67 xml_->get_widget("Apply", button);
69 xml_->get_widget("Restore", button);
72 xml_->get_widget("Notebook", notebook_);
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_);
85 xml_->get_widget("SetScaling", setscalingradio_);
86 xml_->get_widget("SetSize", setsizeradio_);
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_);
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_);
106 // Setup the columnrecord we use for combos
107 cols_.add(stringcol_);
111 // Disable for read-only documents.
112 bcview().addReadOnly(browsebutton_);
113 bcview().addReadOnly(aspectcheck_);
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));
130 setscalingradio_->signal_toggled().connect(
131 sigc::mem_fun(*this, &GGraphics::onSizingModeChange));
132 setsizeradio_->signal_toggled().connect(
133 sigc::mem_fun(*this, &GGraphics::onSizingModeChange));
135 browsebutton_->signal_clicked().connect(
136 sigc::mem_fun(*this, &GGraphics::onBrowseClicked));
138 editbutton_->signal_clicked().connect(
139 sigc::mem_fun(*this, &GGraphics::onEditClicked));
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));
155 bbfromfilebutton_->signal_clicked().connect(
156 sigc::mem_fun(*this, &GGraphics::onBBFromFileClicked));
158 // disable for read-only documents
159 bcview().addReadOnly(bbfromfilebutton_);
160 bcview().addReadOnly(clipcheck_);
161 PopulateComboBox(bbunitscombo_, getBBUnits());
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_);
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));
187 subfigcheck_->signal_toggled().connect(
188 sigc::mem_fun(*this, &GGraphics::onSubFigCheckToggled));
190 vector<RotationOriginPair> origindata = getRotationOriginData();
192 // Store the identifiers for later
193 origins_ = getSecond(origindata);
194 PopulateComboBox(origincombo_, getFirst(origindata));
198 void GGraphics::onSizingModeChange()
200 bool const scalingmode = setscalingradio_->get_active();
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);
210 void GGraphics::PopulateComboBox(Gtk::ComboBox * combo,
211 vector<string> const & strings)
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;
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);
228 void GGraphics::apply()
230 // Create the parameters structure and fill the data from the dialog.
231 InsetGraphicsParams & igp = controller().params();
234 igp.filename.set(fileentry_->get_text(),
235 kernel().bufferFilepath());
238 static_cast<int>(displayscalespin_->get_adjustment()->get_value());
239 if (igp.lyxscale == 0) {
243 switch (displaycombo_->get_active_row_number()) {
245 igp.display = graphics::NoDisplay;
248 igp.display = graphics::ColorDisplay;
251 igp.display = graphics::GrayscaleDisplay;
254 igp.display = graphics::MonochromeDisplay;
257 igp.display = graphics::DefaultDisplay;
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();
267 igp.scale = string();
268 igp.width = widthlengthentry_->get_length();
271 igp.height = heightlengthentry_->get_length();
273 igp.keepAspectRatio = aspectcheck_->get_active();
274 igp.draft = draftcheck_->get_active();
275 igp.noUnzip = !unzipcheck_->get_active();
279 if (!controller().bbChanged) {
280 // don't write anything
283 Glib::ustring const bbunit = (*bbunitscombo_->get_active())[stringcol_];
286 if (leftbottomxspin_->get_text().empty())
289 bb = leftbottomxspin_->get_text() + bbunit;
293 if (leftbottomyspin_->get_text().empty())
296 bb += leftbottomyspin_->get_text() + bbunit;
300 if (righttopxspin_->get_text().empty())
303 bb += righttopxspin_->get_text() + bbunit;
307 if (righttopyspin_->get_text().empty())
310 bb += righttopyspin_->get_text() + bbunit;
312 /// The bounding box with "xLB yLB yRT yRT ", divided by a space!
315 igp.clip = clipcheck_->get_active();
318 igp.rotateAngle = convert<string>(anglespin_->get_adjustment()->get_value());
320 int const origin_pos = origincombo_->get_active_row_number();
321 igp.rotateOrigin = origins_[origin_pos];
323 igp.subcaption = subfigcheck_->get_active();
324 igp.subcaptionText = subfigentry_->get_text();
326 igp.special = latexoptsentry_->get_text();
330 void GGraphics::update() {
331 // set the right default unit
332 defaultUnit = getDefaultUnit();
334 // Update dialog with details from inset
335 InsetGraphicsParams & igp = controller().params();
339 igp.filename.outputFilename(kernel().bufferFilepath());
340 fileentry_->set_text(name);
341 displayscalespin_->get_adjustment()->set_value(igp.lyxscale);
344 switch (igp.display) {
345 case graphics::NoDisplay:
346 displaycombo_->set_active(4);
348 case graphics::ColorDisplay:
349 displaycombo_->set_active(3);
351 case graphics::GrayscaleDisplay:
352 displaycombo_->set_active(2);
354 case graphics::MonochromeDisplay:
355 displaycombo_->set_active(1);
357 case graphics::DefaultDisplay:
358 displaycombo_->set_active(0);
361 outputscalespin_->get_adjustment()->set_value(convert<double>(igp.scale));
363 widthlengthentry_->set_length(igp.width);
364 heightlengthentry_->set_length(igp.height);
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);
373 outputscalespin_->get_adjustment()->set_value(100.0);
374 setscalingradio_->set_active(true);
376 onSizingModeChange();
378 aspectcheck_->set_active(igp.keepAspectRatio);
379 draftcheck_->set_active(igp.draft);
380 unzipcheck_->set_active(!igp.noUnzip);
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);
389 anglespin_->get_adjustment()->set_value(convert<double>(igp.rotateAngle));
392 if (igp.rotateOrigin.empty()) {
395 origin_pos = findPos(origins_, igp.rotateOrigin);
397 origincombo_->set_active(origin_pos);
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);
405 // open dialog in the file-tab, whenever filename is empty
406 if (igp.filename.empty()) {
407 notebook_->set_current_page(0);
411 bc().input(ButtonPolicy::SMI_INVALID);
415 void GGraphics::updateBB(string const & filename, string const & bb_inset)
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
421 if (bb_inset.empty()) {
422 lyxerr[Debug::GRAPHICS]
423 << "GGraphics::updateBB() [no BoundingBox]\n";
424 string const bb = controller().readBB(filename);
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));
434 leftbottomxspin_->set_text("");
435 leftbottomyspin_->set_text("");
436 righttopxspin_->set_text("");
437 righttopyspin_->set_text("");
439 unitsComboFromLength(bbunitscombo_, stringcol_,
440 LyXLength("bp"), defaultUnit);
442 // get the values from the inset
443 lyxerr[Debug::GRAPHICS]
444 << "FormGraphics::updateBB(): igp has BoundingBox"
445 << " ["<< bb_inset << "]\n";
448 anyLength = LyXLength(token(bb_inset, ' ', 0));
450 unitsComboFromLength(bbunitscombo_, stringcol_, anyLength, defaultUnit);
452 leftbottomxspin_->get_adjustment()->set_value(anyLength.value());
454 anyLength = LyXLength(token(bb_inset, ' ', 1));
455 leftbottomyspin_->get_adjustment()->set_value(anyLength.value());
457 anyLength = LyXLength(token(bb_inset, ' ', 2));
458 righttopxspin_->get_adjustment()->set_value(anyLength.value());
460 anyLength = LyXLength(token(bb_inset, ' ', 3));
461 righttopyspin_->get_adjustment()->set_value(anyLength.value());
463 controller().bbChanged = false;
467 void GGraphics::onBrowseClicked()
469 // Get the filename from the dialog
470 string const in_name = fileentry_->get_text();
471 string const out_name = lyx::to_utf8(controller().browse(lyx::from_utf8(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);
477 if (controller().isFilenameValid(out_name) &&
478 !controller().bbChanged) {
479 updateBB(out_name, string());
482 bc().input(ButtonPolicy::SMI_VALID);
486 void GGraphics::onBBChange()
488 controller().bbChanged = true;
489 bc().input(ButtonPolicy::SMI_VALID);
493 void GGraphics::onBBFromFileClicked()
495 string const filename = fileentry_->get_text();
496 if (!filename.empty()) {
497 string bb = controller().readBB(filename);
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);
506 controller().bbChanged = false;
508 leftbottomxspin_->set_text("");
509 leftbottomyspin_->set_text("");
510 righttopxspin_->set_text("");
511 righttopyspin_->set_text("");
512 unitsComboFromLength(bbunitscombo_, stringcol_,
513 LyXLength("bp"), defaultUnit);
515 bc().input(ButtonPolicy::SMI_VALID);
519 void GGraphics::onSubFigCheckToggled()
521 subfigentry_->set_sensitive(subfigcheck_->get_active());
522 bc().input(ButtonPolicy::SMI_VALID);
526 void GGraphics::onEditClicked()
528 controller().editGraphics();
532 void GGraphics::onInput()
534 bc().input(ButtonPolicy::SMI_VALID);
537 } // namespace frontend