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 _GLIBCPP_CONCEPT_CHECKS
15 #undef _GLIBCPP_CONCEPT_CHECKS
18 #include "GGraphics.h"
19 #include "ControlGraphics.h"
23 #include "controllers/helper_funcs.h"
25 #include "insets/insetgraphicsParams.h"
27 #include "lyxrc.h" // for lyxrc.default_papersize
29 #include "support/convert.h"
30 #include "support/lyxlib.h" // for float_equal
31 #include "support/lstrings.h"
40 using support::float_equal;
46 string defaultUnit("cm");
49 GGraphics::GGraphics(Dialog & parent)
50 : GViewCB<ControlGraphics, GViewGladeB>(parent, _("Graphics"), false)
54 void GGraphics::doBuild()
56 string const gladeName = findGladeFile("graphics");
57 xml_ = Gnome::Glade::Xml::create(gladeName);
60 xml_->get_widget("Close", button);
62 xml_->get_widget("Ok", button);
64 xml_->get_widget("Apply", button);
66 xml_->get_widget("Restore", button);
69 xml_->get_widget("Notebook", notebook_);
72 xml_->get_widget("File", fileentry_);
73 xml_->get_widget("DisplayScale", displayscalespin_);
74 xml_->get_widget("OutputScale", outputscalespin_);
75 xml_->get_widget("Browse", browsebutton_);
76 xml_->get_widget("Edit", editbutton_);
77 xml_->get_widget("Display", displaycombo_);
78 xml_->get_widget("Width", widthspin_);
79 xml_->get_widget("Height", heightspin_);
80 xml_->get_widget("MaintainAspectRatio", aspectcheck_);
81 xml_->get_widget("WidthUnits", widthunitscombo_);
82 xml_->get_widget("HeightUnits", heightunitscombo_);
83 xml_->get_widget("SetScaling", setscalingradio_);
84 xml_->get_widget("SetSize", setsizeradio_);
87 xml_->get_widget("ClipToBoundingBox", clipcheck_);
88 xml_->get_widget("RightTopX", righttopxspin_);
89 xml_->get_widget("RightTopY", righttopyspin_);
90 xml_->get_widget("LeftBottomX", leftbottomxspin_);
91 xml_->get_widget("LeftBottomY", leftbottomyspin_);
92 xml_->get_widget("BoundingUnits", bbunitscombo_);
93 xml_->get_widget("GetFromFile", bbfromfilebutton_);
96 xml_->get_widget("Angle", anglespin_);
97 xml_->get_widget("Origin", origincombo_);
98 xml_->get_widget("UseSubfigure", subfigcheck_);
99 xml_->get_widget("SubfigureCaption", subfigentry_);
100 xml_->get_widget("LatexOptions", latexoptsentry_);
101 xml_->get_widget("DraftMode", draftcheck_);
102 xml_->get_widget("UnzipOnExport", unzipcheck_);
104 // Setup the columnrecord we use for combos
105 cols_.add(stringcol_);
109 // Disable for read-only documents.
110 bcview().addReadOnly(browsebutton_);
111 bcview().addReadOnly(aspectcheck_);
113 fileentry_->signal_changed().connect(
114 sigc::mem_fun(*this, &GGraphics::onInput));
115 displayscalespin_->signal_changed().connect(
116 sigc::mem_fun(*this, &GGraphics::onInput));
117 displaycombo_->signal_changed().connect(
118 sigc::mem_fun(*this, &GGraphics::onInput));
119 outputscalespin_->signal_changed().connect(
120 sigc::mem_fun(*this, &GGraphics::onInput));
121 heightspin_->signal_changed().connect(
122 sigc::mem_fun(*this, &GGraphics::onInput));
123 heightunitscombo_->signal_changed().connect(
124 sigc::mem_fun(*this, &GGraphics::onInput));
125 widthspin_->signal_changed().connect(
126 sigc::mem_fun(*this, &GGraphics::onInput));
127 widthunitscombo_->signal_changed().connect(
128 sigc::mem_fun(*this, &GGraphics::onInput));
129 aspectcheck_->signal_toggled().connect(
130 sigc::mem_fun(*this, &GGraphics::onInput));
132 setscalingradio_->signal_toggled().connect(
133 sigc::mem_fun(*this, &GGraphics::onSizingModeChange));
134 setsizeradio_->signal_toggled().connect(
135 sigc::mem_fun(*this, &GGraphics::onSizingModeChange));
137 browsebutton_->signal_clicked().connect(
138 sigc::mem_fun(*this, &GGraphics::onBrowseClicked));
140 editbutton_->signal_clicked().connect(
141 sigc::mem_fun(*this, &GGraphics::onEditClicked));
143 vector<string> const unit_list = buildLengthUnitList();
144 PopulateComboBox(heightunitscombo_, unit_list);
145 PopulateComboBox(widthunitscombo_, unit_list);
147 // the bounding box page
148 leftbottomxspin_->signal_changed().connect(
149 sigc::mem_fun(*this, &GGraphics::onBBChange));
150 leftbottomyspin_->signal_changed().connect(
151 sigc::mem_fun(*this, &GGraphics::onBBChange));
152 righttopxspin_->signal_changed().connect(
153 sigc::mem_fun(*this, &GGraphics::onBBChange));
154 righttopyspin_->signal_changed().connect(
155 sigc::mem_fun(*this, &GGraphics::onBBChange));
156 bbunitscombo_->signal_changed().connect(
157 sigc::mem_fun(*this, &GGraphics::onBBChange));
158 clipcheck_->signal_toggled().connect(
159 sigc::mem_fun(*this, &GGraphics::onBBChange));
161 bbfromfilebutton_->signal_clicked().connect(
162 sigc::mem_fun(*this, &GGraphics::onBBFromFileClicked));
164 // disable for read-only documents
165 bcview().addReadOnly(bbfromfilebutton_);
166 bcview().addReadOnly(clipcheck_);
167 PopulateComboBox(bbunitscombo_, getBBUnits());
172 // disable for read-only documents
173 bcview().addReadOnly(anglespin_);
174 bcview().addReadOnly(origincombo_);
175 bcview().addReadOnly(subfigcheck_);
176 bcview().addReadOnly(latexoptsentry_);
177 bcview().addReadOnly(draftcheck_);
178 bcview().addReadOnly(unzipcheck_);
180 anglespin_->signal_changed().connect(
181 sigc::mem_fun(*this, &GGraphics::onInput));
182 origincombo_->signal_changed().connect(
183 sigc::mem_fun(*this, &GGraphics::onInput));
184 subfigentry_->signal_changed().connect(
185 sigc::mem_fun(*this, &GGraphics::onInput));
186 latexoptsentry_->signal_changed().connect(
187 sigc::mem_fun(*this, &GGraphics::onInput));
188 draftcheck_->signal_toggled().connect(
189 sigc::mem_fun(*this, &GGraphics::onInput));
190 unzipcheck_->signal_toggled().connect(
191 sigc::mem_fun(*this, &GGraphics::onInput));
193 subfigcheck_->signal_toggled().connect(
194 sigc::mem_fun(*this, &GGraphics::onSubFigCheckToggled));
196 vector<RotationOriginPair> origindata = getRotationOriginData();
198 // Store the identifiers for later
199 origins_ = getSecond(origindata);
200 PopulateComboBox(origincombo_, getFirst(origindata));
204 void GGraphics::onSizingModeChange()
206 bool const scalingmode = setscalingradio_->get_active();
208 outputscalespin_->set_sensitive(scalingmode);
209 widthspin_->set_sensitive(!scalingmode);
210 heightspin_->set_sensitive(!scalingmode);
211 widthunitscombo_->set_sensitive(!scalingmode);
212 heightunitscombo_->set_sensitive(!scalingmode);
213 aspectcheck_->set_sensitive(!scalingmode);
214 bc().input(ButtonPolicy::SMI_VALID);
218 void GGraphics::PopulateComboBox(Gtk::ComboBox * combo,
219 vector<string> const & strings)
221 Glib::RefPtr<Gtk::ListStore> model = Gtk::ListStore::create(cols_);
222 vector<string>::const_iterator it = strings.begin();
223 vector<string>::const_iterator end = strings.end();
224 for (int rowindex = 0; it != end; ++it, ++rowindex) {
225 Gtk::TreeModel::iterator row = model->append();
226 (*row)[stringcol_] = *it;
229 combo->set_model(model);
230 Gtk::CellRendererText * cell = Gtk::manage(new Gtk::CellRendererText);
231 combo->pack_start(*cell, true);
232 combo->add_attribute(*cell, "text", 0);
236 void GGraphics::apply()
238 // Create the parameters structure and fill the data from the dialog.
239 InsetGraphicsParams & igp = controller().params();
242 igp.filename.set(fileentry_->get_text(),
243 kernel().bufferFilepath());
246 static_cast<int>(displayscalespin_->get_adjustment()->get_value());
247 if (igp.lyxscale == 0) {
251 switch (displaycombo_->get_active_row_number()) {
253 igp.display = graphics::NoDisplay;
256 igp.display = graphics::ColorDisplay;
259 igp.display = graphics::GrayscaleDisplay;
262 igp.display = graphics::MonochromeDisplay;
265 igp.display = graphics::DefaultDisplay;
268 if (setscalingradio_->get_active()) {
269 float scaleValue = outputscalespin_->get_adjustment()->get_value();
270 igp.scale = convert<string>(scaleValue);
271 if (float_equal(scaleValue, 0.0, 0.05))
272 igp.scale = string();
273 igp.width = LyXLength();
275 igp.scale = string();
276 Glib::ustring const widthunit =
277 (*widthunitscombo_->get_active())[stringcol_];
278 igp.width = LyXLength(widthspin_->get_text() + widthunit);
282 Glib::ustring const heightunit =
283 (*heightunitscombo_->get_active())[stringcol_];
284 igp.height = LyXLength(heightspin_->get_text() + heightunit);
286 igp.keepAspectRatio = aspectcheck_->get_active();
287 igp.draft = draftcheck_->get_active();
288 igp.noUnzip = !unzipcheck_->get_active();
292 if (!controller().bbChanged) {
293 // don't write anything
296 Glib::ustring const bbunit = (*bbunitscombo_->get_active())[stringcol_];
299 if (leftbottomxspin_->get_text().empty())
302 bb = leftbottomxspin_->get_text() + bbunit;
306 if (leftbottomyspin_->get_text().empty())
309 bb += leftbottomyspin_->get_text() + bbunit;
313 if (righttopxspin_->get_text().empty())
316 bb += righttopxspin_->get_text() + bbunit;
320 if (righttopyspin_->get_text().empty())
323 bb += righttopyspin_->get_text() + bbunit;
325 /// The bounding box with "xLB yLB yRT yRT ", divided by a space!
328 igp.clip = clipcheck_->get_active();
331 igp.rotateAngle = convert<string>(anglespin_->get_adjustment()->get_value());
333 int const origin_pos = origincombo_->get_active_row_number();
334 igp.rotateOrigin = origins_[origin_pos];
336 igp.subcaption = subfigcheck_->get_active();
337 igp.subcaptionText = subfigentry_->get_text();
339 igp.special = latexoptsentry_->get_text();
343 void GGraphics::update() {
344 // set the right default unit
345 defaultUnit = getDefaultUnit();
347 // Update dialog with details from inset
348 InsetGraphicsParams & igp = controller().params();
352 igp.filename.outputFilename(kernel().bufferFilepath());
353 fileentry_->set_text(name);
354 displayscalespin_->get_adjustment()->set_value(igp.lyxscale);
357 switch (igp.display) {
358 case graphics::NoDisplay:
359 displaycombo_->set_active(4);
361 case graphics::ColorDisplay:
362 displaycombo_->set_active(3);
364 case graphics::GrayscaleDisplay:
365 displaycombo_->set_active(2);
367 case graphics::MonochromeDisplay:
368 displaycombo_->set_active(1);
370 case graphics::DefaultDisplay:
371 displaycombo_->set_active(0);
374 outputscalespin_->get_adjustment()->set_value(convert<double>(igp.scale));
375 widthspin_->get_adjustment()->set_value(igp.width.value());
376 unitsComboFromLength(widthunitscombo_, stringcol_,
377 igp.width, defaultUnit);
378 heightspin_->get_adjustment()->set_value(igp.height.value());
379 unitsComboFromLength(heightunitscombo_, stringcol_,
380 igp.height, defaultUnit);
382 if (!igp.scale.empty()
383 && !float_equal(convert<double>(igp.scale), 0.0, 0.05)) {
384 // scaling sizing mode
385 setscalingradio_->set_active(true);
387 setsizeradio_->set_active(true);
389 onSizingModeChange();
391 aspectcheck_->set_active(igp.keepAspectRatio);
392 draftcheck_->set_active(igp.draft);
393 unzipcheck_->set_active(!igp.noUnzip);
396 // set the bounding box values, if exists. First we need the whole
397 // path, because the controller knows nothing about the doc-dir
398 updateBB(igp.filename.absFilename(), igp.bb);
399 clipcheck_->set_active(igp.clip);
402 anglespin_->get_adjustment()->set_value(convert<double>(igp.rotateAngle));
405 if (igp.rotateOrigin.empty()) {
408 origin_pos = findPos(origins_, igp.rotateOrigin);
410 origincombo_->set_active(origin_pos);
413 subfigcheck_->set_active(igp.subcaption);
414 subfigentry_->set_text(igp.subcaptionText);
415 subfigentry_->set_sensitive(subfigcheck_->get_active());
416 latexoptsentry_->set_text(igp.special);
418 // open dialog in the file-tab, whenever filename is empty
419 if (igp.filename.empty()) {
420 notebook_->set_current_page(0);
424 bc().input(ButtonPolicy::SMI_INVALID);
428 void GGraphics::updateBB(string const & filename, string const & bb_inset)
430 // Update dialog with details from inset
431 // set the bounding box values, if exists. First we need the whole
432 // path, because the controller knows nothing about the doc-dir
434 if (bb_inset.empty()) {
435 lyxerr[Debug::GRAPHICS]
436 << "GGraphics::updateBB() [no BoundingBox]\n";
437 string const bb = controller().readBB(filename);
439 // get the values from the file
440 // in this case we always have the point-unit
441 leftbottomxspin_->set_text(token(bb, ' ', 0));
442 leftbottomyspin_->set_text(token(bb, ' ', 1));
443 righttopxspin_->set_text(token(bb, ' ', 2));
444 righttopyspin_->set_text(token(bb, ' ', 3));
447 leftbottomxspin_->set_text("");
448 leftbottomyspin_->set_text("");
449 righttopxspin_->set_text("");
450 righttopyspin_->set_text("");
452 unitsComboFromLength(bbunitscombo_, stringcol_,
453 LyXLength("bp"), defaultUnit);
455 // get the values from the inset
456 lyxerr[Debug::GRAPHICS]
457 << "FormGraphics::updateBB(): igp has BoundingBox"
458 << " ["<< bb_inset << "]\n";
461 anyLength = LyXLength(token(bb_inset, ' ', 0));
463 unitsComboFromLength(bbunitscombo_, stringcol_, anyLength, defaultUnit);
465 leftbottomxspin_->get_adjustment()->set_value(anyLength.value());
467 anyLength = LyXLength(token(bb_inset, ' ', 1));
468 leftbottomyspin_->get_adjustment()->set_value(anyLength.value());
470 anyLength = LyXLength(token(bb_inset, ' ', 2));
471 righttopxspin_->get_adjustment()->set_value(anyLength.value());
473 anyLength = LyXLength(token(bb_inset, ' ', 3));
474 righttopyspin_->get_adjustment()->set_value(anyLength.value());
476 controller().bbChanged = false;
480 void GGraphics::onBrowseClicked()
482 // Get the filename from the dialog
483 string const in_name = fileentry_->get_text();
484 string const out_name = controller().browse(in_name);
485 lyxerr[Debug::GRAPHICS]
486 << "[FormGraphics]out_name: " << out_name << "\n";
487 if (out_name != in_name && !out_name.empty()) {
488 fileentry_->set_text(out_name);
490 if (controller().isFilenameValid(out_name) &&
491 !controller().bbChanged) {
492 updateBB(out_name, string());
495 bc().input(ButtonPolicy::SMI_VALID);
499 void GGraphics::onBBChange()
501 controller().bbChanged = true;
502 bc().input(ButtonPolicy::SMI_VALID);
506 void GGraphics::onBBFromFileClicked()
508 string const filename = fileentry_->get_text();
509 if (!filename.empty()) {
510 string bb = controller().readBB(filename);
512 leftbottomxspin_->set_text(token(bb, ' ', 0));
513 leftbottomyspin_->set_text(token(bb, ' ', 1));
514 righttopxspin_->set_text(token(bb, ' ', 2));
515 righttopyspin_->set_text(token(bb, ' ', 3));
516 unitsComboFromLength(bbunitscombo_, stringcol_,
517 LyXLength("bp"), defaultUnit);
519 controller().bbChanged = false;
521 leftbottomxspin_->set_text("");
522 leftbottomyspin_->set_text("");
523 righttopxspin_->set_text("");
524 righttopyspin_->set_text("");
525 unitsComboFromLength(bbunitscombo_, stringcol_,
526 LyXLength("bp"), defaultUnit);
528 bc().input(ButtonPolicy::SMI_VALID);
532 void GGraphics::onSubFigCheckToggled()
534 subfigentry_->set_sensitive(subfigcheck_->get_active());
535 bc().input(ButtonPolicy::SMI_VALID);
539 void GGraphics::onEditClicked()
541 controller().editGraphics();
545 void GGraphics::onInput()
547 bc().input(ButtonPolicy::SMI_VALID);
550 } // namespace frontend