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/lyxlib.h" // for float_equal
30 #include "support/lstrings.h"
31 #include "support/convert.h"
40 using support::float_equal;
41 using support::strToDbl;
47 string defaultUnit("cm");
50 GGraphics::GGraphics(Dialog & parent)
51 : GViewCB<ControlGraphics, GViewGladeB>(parent, _("Graphics"), false)
55 void GGraphics::doBuild()
57 string const gladeName = findGladeFile("graphics");
58 xml_ = Gnome::Glade::Xml::create(gladeName);
61 xml_->get_widget("Close", button);
63 xml_->get_widget("Ok", button);
65 xml_->get_widget("Apply", button);
67 xml_->get_widget("Restore", button);
70 xml_->get_widget("Notebook", notebook_);
73 xml_->get_widget("File", fileentry_);
74 xml_->get_widget("DisplayScale", displayscalespin_);
75 xml_->get_widget("OutputScale", outputscalespin_);
76 xml_->get_widget("Browse", browsebutton_);
77 xml_->get_widget("Edit", editbutton_);
78 xml_->get_widget("Display", displaycombo_);
79 xml_->get_widget("Width", widthspin_);
80 xml_->get_widget("Height", heightspin_);
81 xml_->get_widget("MaintainAspectRatio", aspectcheck_);
82 xml_->get_widget("WidthUnits", widthunitscombo_);
83 xml_->get_widget("HeightUnits", heightunitscombo_);
84 xml_->get_widget("SetScaling", setscalingradio_);
85 xml_->get_widget("SetSize", setsizeradio_);
88 xml_->get_widget("ClipToBoundingBox", clipcheck_);
89 xml_->get_widget("RightTopX", righttopxspin_);
90 xml_->get_widget("RightTopY", righttopyspin_);
91 xml_->get_widget("LeftBottomX", leftbottomxspin_);
92 xml_->get_widget("LeftBottomY", leftbottomyspin_);
93 xml_->get_widget("BoundingUnits", bbunitscombo_);
94 xml_->get_widget("GetFromFile", bbfromfilebutton_);
97 xml_->get_widget("Angle", anglespin_);
98 xml_->get_widget("Origin", origincombo_);
99 xml_->get_widget("UseSubfigure", subfigcheck_);
100 xml_->get_widget("SubfigureCaption", subfigentry_);
101 xml_->get_widget("LatexOptions", latexoptsentry_);
102 xml_->get_widget("DraftMode", draftcheck_);
103 xml_->get_widget("UnzipOnExport", unzipcheck_);
105 // Setup the columnrecord we use for combos
106 cols_.add(stringcol_);
110 // Disable for read-only documents.
111 bcview().addReadOnly(browsebutton_);
112 bcview().addReadOnly(aspectcheck_);
114 fileentry_->signal_changed().connect(
115 sigc::mem_fun(*this, &GGraphics::onInput));
116 displayscalespin_->signal_changed().connect(
117 sigc::mem_fun(*this, &GGraphics::onInput));
118 displaycombo_->signal_changed().connect(
119 sigc::mem_fun(*this, &GGraphics::onInput));
120 outputscalespin_->signal_changed().connect(
121 sigc::mem_fun(*this, &GGraphics::onInput));
122 heightspin_->signal_changed().connect(
123 sigc::mem_fun(*this, &GGraphics::onInput));
124 heightunitscombo_->signal_changed().connect(
125 sigc::mem_fun(*this, &GGraphics::onInput));
126 widthspin_->signal_changed().connect(
127 sigc::mem_fun(*this, &GGraphics::onInput));
128 widthunitscombo_->signal_changed().connect(
129 sigc::mem_fun(*this, &GGraphics::onInput));
130 aspectcheck_->signal_toggled().connect(
131 sigc::mem_fun(*this, &GGraphics::onInput));
133 setscalingradio_->signal_toggled().connect(
134 sigc::mem_fun(*this, &GGraphics::onSizingModeChange));
135 setsizeradio_->signal_toggled().connect(
136 sigc::mem_fun(*this, &GGraphics::onSizingModeChange));
138 browsebutton_->signal_clicked().connect(
139 sigc::mem_fun(*this, &GGraphics::onBrowseClicked));
141 editbutton_->signal_clicked().connect(
142 sigc::mem_fun(*this, &GGraphics::onEditClicked));
144 vector<string> const unit_list = buildLengthUnitList();
145 PopulateComboBox(heightunitscombo_, unit_list);
146 PopulateComboBox(widthunitscombo_, unit_list);
148 // the bounding box page
149 leftbottomxspin_->signal_changed().connect(
150 sigc::mem_fun(*this, &GGraphics::onBBChange));
151 leftbottomyspin_->signal_changed().connect(
152 sigc::mem_fun(*this, &GGraphics::onBBChange));
153 righttopxspin_->signal_changed().connect(
154 sigc::mem_fun(*this, &GGraphics::onBBChange));
155 righttopyspin_->signal_changed().connect(
156 sigc::mem_fun(*this, &GGraphics::onBBChange));
157 bbunitscombo_->signal_changed().connect(
158 sigc::mem_fun(*this, &GGraphics::onBBChange));
159 clipcheck_->signal_toggled().connect(
160 sigc::mem_fun(*this, &GGraphics::onBBChange));
162 bbfromfilebutton_->signal_clicked().connect(
163 sigc::mem_fun(*this, &GGraphics::onBBFromFileClicked));
165 // disable for read-only documents
166 bcview().addReadOnly(bbfromfilebutton_);
167 bcview().addReadOnly(clipcheck_);
168 PopulateComboBox(bbunitscombo_, getBBUnits());
173 // disable for read-only documents
174 bcview().addReadOnly(anglespin_);
175 bcview().addReadOnly(origincombo_);
176 bcview().addReadOnly(subfigcheck_);
177 bcview().addReadOnly(latexoptsentry_);
178 bcview().addReadOnly(draftcheck_);
179 bcview().addReadOnly(unzipcheck_);
181 anglespin_->signal_changed().connect(
182 sigc::mem_fun(*this, &GGraphics::onInput));
183 origincombo_->signal_changed().connect(
184 sigc::mem_fun(*this, &GGraphics::onInput));
185 subfigentry_->signal_changed().connect(
186 sigc::mem_fun(*this, &GGraphics::onInput));
187 latexoptsentry_->signal_changed().connect(
188 sigc::mem_fun(*this, &GGraphics::onInput));
189 draftcheck_->signal_toggled().connect(
190 sigc::mem_fun(*this, &GGraphics::onInput));
191 unzipcheck_->signal_toggled().connect(
192 sigc::mem_fun(*this, &GGraphics::onInput));
194 subfigcheck_->signal_toggled().connect(
195 sigc::mem_fun(*this, &GGraphics::onSubFigCheckToggled));
197 vector<RotationOriginPair> origindata = getRotationOriginData();
199 // Store the identifiers for later
200 origins_ = getSecond(origindata);
201 PopulateComboBox(origincombo_, getFirst(origindata));
205 void GGraphics::onSizingModeChange()
207 bool const scalingmode = setscalingradio_->get_active();
209 outputscalespin_->set_sensitive(scalingmode);
210 widthspin_->set_sensitive(!scalingmode);
211 heightspin_->set_sensitive(!scalingmode);
212 widthunitscombo_->set_sensitive(!scalingmode);
213 heightunitscombo_->set_sensitive(!scalingmode);
214 aspectcheck_->set_sensitive(!scalingmode);
215 bc().input(ButtonPolicy::SMI_VALID);
219 void GGraphics::PopulateComboBox(Gtk::ComboBox * combo,
220 vector<string> const & strings)
222 Glib::RefPtr<Gtk::ListStore> model = Gtk::ListStore::create(cols_);
223 vector<string>::const_iterator it = strings.begin();
224 vector<string>::const_iterator end = strings.end();
225 for (int rowindex = 0; it != end; ++it, ++rowindex) {
226 Gtk::TreeModel::iterator row = model->append();
227 (*row)[stringcol_] = *it;
230 combo->set_model(model);
231 Gtk::CellRendererText * cell = Gtk::manage(new Gtk::CellRendererText);
232 combo->pack_start(*cell, true);
233 combo->add_attribute(*cell, "text", 0);
237 void GGraphics::apply()
239 // Create the parameters structure and fill the data from the dialog.
240 InsetGraphicsParams & igp = controller().params();
243 igp.filename.set(fileentry_->get_text(),
244 kernel().bufferFilepath());
247 static_cast<int>(displayscalespin_->get_adjustment()->get_value());
248 if (igp.lyxscale == 0) {
252 switch (displaycombo_->get_active_row_number()) {
254 igp.display = graphics::NoDisplay;
257 igp.display = graphics::ColorDisplay;
260 igp.display = graphics::GrayscaleDisplay;
263 igp.display = graphics::MonochromeDisplay;
266 igp.display = graphics::DefaultDisplay;
269 if (setscalingradio_->get_active()) {
270 float scaleValue = outputscalespin_->get_adjustment()->get_value();
271 igp.scale = convert<string>(scaleValue);
272 if (float_equal(scaleValue, 0.0, 0.05))
273 igp.scale = string();
274 igp.width = LyXLength();
276 igp.scale = string();
277 Glib::ustring const widthunit =
278 (*widthunitscombo_->get_active())[stringcol_];
279 igp.width = LyXLength(widthspin_->get_text() + widthunit);
283 Glib::ustring const heightunit =
284 (*heightunitscombo_->get_active())[stringcol_];
285 igp.height = LyXLength(heightspin_->get_text() + heightunit);
287 igp.keepAspectRatio = aspectcheck_->get_active();
288 igp.draft = draftcheck_->get_active();
289 igp.noUnzip = !unzipcheck_->get_active();
293 if (!controller().bbChanged) {
294 // don't write anything
297 Glib::ustring const bbunit = (*bbunitscombo_->get_active())[stringcol_];
300 if (leftbottomxspin_->get_text().empty())
303 bb = leftbottomxspin_->get_text() + bbunit;
307 if (leftbottomyspin_->get_text().empty())
310 bb += leftbottomyspin_->get_text() + bbunit;
314 if (righttopxspin_->get_text().empty())
317 bb += righttopxspin_->get_text() + bbunit;
321 if (righttopyspin_->get_text().empty())
324 bb += righttopyspin_->get_text() + bbunit;
326 /// The bounding box with "xLB yLB yRT yRT ", divided by a space!
329 igp.clip = clipcheck_->get_active();
332 igp.rotateAngle = convert<string>(anglespin_->get_adjustment()->get_value());
334 int const origin_pos = origincombo_->get_active_row_number();
335 igp.rotateOrigin = origins_[origin_pos];
337 igp.subcaption = subfigcheck_->get_active();
338 igp.subcaptionText = subfigentry_->get_text();
340 igp.special = latexoptsentry_->get_text();
344 void GGraphics::update() {
345 // set the right default unit
346 defaultUnit = getDefaultUnit();
348 // Update dialog with details from inset
349 InsetGraphicsParams & igp = controller().params();
353 igp.filename.outputFilename(kernel().bufferFilepath());
354 fileentry_->set_text(name);
355 displayscalespin_->get_adjustment()->set_value(igp.lyxscale);
358 switch (igp.display) {
359 case graphics::NoDisplay:
360 displaycombo_->set_active(4);
362 case graphics::ColorDisplay:
363 displaycombo_->set_active(3);
365 case graphics::GrayscaleDisplay:
366 displaycombo_->set_active(2);
368 case graphics::MonochromeDisplay:
369 displaycombo_->set_active(1);
371 case graphics::DefaultDisplay:
372 displaycombo_->set_active(0);
375 outputscalespin_->get_adjustment()->set_value(strToDbl(igp.scale));
376 widthspin_->get_adjustment()->set_value(igp.width.value());
377 unitsComboFromLength(widthunitscombo_, stringcol_,
378 igp.width, defaultUnit);
379 heightspin_->get_adjustment()->set_value(igp.height.value());
380 unitsComboFromLength(heightunitscombo_, stringcol_,
381 igp.height, defaultUnit);
383 if (!igp.scale.empty()
384 && !float_equal(strToDbl(igp.scale), 0.0, 0.05)) {
385 // scaling sizing mode
386 setscalingradio_->set_active(true);
388 setsizeradio_->set_active(true);
390 onSizingModeChange();
392 aspectcheck_->set_active(igp.keepAspectRatio);
393 draftcheck_->set_active(igp.draft);
394 unzipcheck_->set_active(!igp.noUnzip);
397 // set the bounding box values, if exists. First we need the whole
398 // path, because the controller knows nothing about the doc-dir
399 updateBB(igp.filename.absFilename(), igp.bb);
400 clipcheck_->set_active(igp.clip);
403 anglespin_->get_adjustment()->set_value(strToDbl(igp.rotateAngle));
406 if (igp.rotateOrigin.empty()) {
409 origin_pos = findPos(origins_, igp.rotateOrigin);
411 origincombo_->set_active(origin_pos);
414 subfigcheck_->set_active(igp.subcaption);
415 subfigentry_->set_text(igp.subcaptionText);
416 subfigentry_->set_sensitive(subfigcheck_->get_active());
417 latexoptsentry_->set_text(igp.special);
419 // open dialog in the file-tab, whenever filename is empty
420 if (igp.filename.empty()) {
421 notebook_->set_current_page(0);
425 bc().input(ButtonPolicy::SMI_INVALID);
429 void GGraphics::updateBB(string const & filename, string const & bb_inset)
431 // Update dialog with details from inset
432 // set the bounding box values, if exists. First we need the whole
433 // path, because the controller knows nothing about the doc-dir
435 if (bb_inset.empty()) {
436 lyxerr[Debug::GRAPHICS]
437 << "GGraphics::updateBB() [no BoundingBox]\n";
438 string const bb = controller().readBB(filename);
440 // get the values from the file
441 // in this case we always have the point-unit
442 leftbottomxspin_->set_text(token(bb, ' ', 0));
443 leftbottomyspin_->set_text(token(bb, ' ', 1));
444 righttopxspin_->set_text(token(bb, ' ', 2));
445 righttopyspin_->set_text(token(bb, ' ', 3));
448 leftbottomxspin_->set_text("");
449 leftbottomyspin_->set_text("");
450 righttopxspin_->set_text("");
451 righttopyspin_->set_text("");
453 unitsComboFromLength(bbunitscombo_, stringcol_,
454 LyXLength("bp"), defaultUnit);
456 // get the values from the inset
457 lyxerr[Debug::GRAPHICS]
458 << "FormGraphics::updateBB(): igp has BoundingBox"
459 << " ["<< bb_inset << "]\n";
462 anyLength = LyXLength(token(bb_inset, ' ', 0));
464 unitsComboFromLength(bbunitscombo_, stringcol_, anyLength, defaultUnit);
466 leftbottomxspin_->get_adjustment()->set_value(anyLength.value());
468 anyLength = LyXLength(token(bb_inset, ' ', 1));
469 leftbottomyspin_->get_adjustment()->set_value(anyLength.value());
471 anyLength = LyXLength(token(bb_inset, ' ', 2));
472 righttopxspin_->get_adjustment()->set_value(anyLength.value());
474 anyLength = LyXLength(token(bb_inset, ' ', 3));
475 righttopyspin_->get_adjustment()->set_value(anyLength.value());
477 controller().bbChanged = false;
481 void GGraphics::onBrowseClicked()
483 // Get the filename from the dialog
484 string const in_name = fileentry_->get_text();
485 string const out_name = controller().browse(in_name);
486 lyxerr[Debug::GRAPHICS]
487 << "[FormGraphics]out_name: " << out_name << "\n";
488 if (out_name != in_name && !out_name.empty()) {
489 fileentry_->set_text(out_name);
491 if (controller().isFilenameValid(out_name) &&
492 !controller().bbChanged) {
493 updateBB(out_name, string());
496 bc().input(ButtonPolicy::SMI_VALID);
500 void GGraphics::onBBChange()
502 controller().bbChanged = true;
503 bc().input(ButtonPolicy::SMI_VALID);
507 void GGraphics::onBBFromFileClicked()
509 string const filename = fileentry_->get_text();
510 if (!filename.empty()) {
511 string bb = controller().readBB(filename);
513 leftbottomxspin_->set_text(token(bb, ' ', 0));
514 leftbottomyspin_->set_text(token(bb, ' ', 1));
515 righttopxspin_->set_text(token(bb, ' ', 2));
516 righttopyspin_->set_text(token(bb, ' ', 3));
517 unitsComboFromLength(bbunitscombo_, stringcol_,
518 LyXLength("bp"), defaultUnit);
520 controller().bbChanged = false;
522 leftbottomxspin_->set_text("");
523 leftbottomyspin_->set_text("");
524 righttopxspin_->set_text("");
525 righttopyspin_->set_text("");
526 unitsComboFromLength(bbunitscombo_, stringcol_,
527 LyXLength("bp"), defaultUnit);
529 bc().input(ButtonPolicy::SMI_VALID);
533 void GGraphics::onSubFigCheckToggled()
535 subfigentry_->set_sensitive(subfigcheck_->get_active());
536 bc().input(ButtonPolicy::SMI_VALID);
540 void GGraphics::onEditClicked()
542 controller().editGraphics();
546 void GGraphics::onInput()
548 bc().input(ButtonPolicy::SMI_VALID);
551 } // namespace frontend