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 #include "GGraphics.h"
14 #include "ControlGraphics.h"
18 #include "controllers/helper_funcs.h"
20 #include "insets/insetgraphicsParams.h"
22 #include "lyxrc.h" // for lyxrc.default_papersize
24 #include "support/lyxlib.h" // for float_equal
25 #include "support/lstrings.h"
34 using support::float_equal;
40 string defaultUnit("cm");
43 GGraphics::GGraphics(Dialog & parent)
44 : GViewCB<ControlGraphics, GViewGladeB>(parent, _("Graphics"), false)
48 void GGraphics::doBuild()
50 string const gladeName = findGladeFile("graphics");
51 xml_ = Gnome::Glade::Xml::create(gladeName);
54 xml_->get_widget("Close", button);
56 xml_->get_widget("Ok", button);
58 xml_->get_widget("Apply", button);
60 xml_->get_widget("Restore", button);
63 xml_->get_widget("Notebook", notebook_);
66 xml_->get_widget("File", fileentry_);
67 xml_->get_widget("DisplayScale", displayscalespin_);
68 xml_->get_widget("OutputScale", outputscalespin_);
69 xml_->get_widget("Browse", browsebutton_);
70 xml_->get_widget("Edit", editbutton_);
71 xml_->get_widget("Display", displaycombo_);
72 xml_->get_widget("Width", widthspin_);
73 xml_->get_widget("Height", heightspin_);
74 xml_->get_widget("MaintainAspectRatio", aspectcheck_);
75 xml_->get_widget("WidthUnits", widthunitscombo_);
76 xml_->get_widget("HeightUnits", heightunitscombo_);
77 xml_->get_widget("SetScaling", setscalingradio_);
78 xml_->get_widget("SetSize", setsizeradio_);
81 xml_->get_widget("ClipToBoundingBox", clipcheck_);
82 xml_->get_widget("RightTopX", righttopxspin_);
83 xml_->get_widget("RightTopY", righttopyspin_);
84 xml_->get_widget("LeftBottomX", leftbottomxspin_);
85 xml_->get_widget("LeftBottomY", leftbottomyspin_);
86 xml_->get_widget("BoundingUnits", bbunitscombo_);
87 xml_->get_widget("GetFromFile", bbfromfilebutton_);
90 xml_->get_widget("Angle", anglespin_);
91 xml_->get_widget("Origin", origincombo_);
92 xml_->get_widget("UseSubfigure", subfigcheck_);
93 xml_->get_widget("SubfigureCaption", subfigentry_);
94 xml_->get_widget("LatexOptions", latexoptsentry_);
95 xml_->get_widget("DraftMode", draftcheck_);
96 xml_->get_widget("UnzipOnExport", unzipcheck_);
98 // Setup the columnrecord we use for combos
99 cols_.add(stringcol_);
103 // Disable for read-only documents.
104 bcview().addReadOnly(browsebutton_);
105 bcview().addReadOnly(aspectcheck_);
107 fileentry_->signal_changed().connect(
108 sigc::mem_fun(*this, &GGraphics::onInput));
109 displayscalespin_->signal_changed().connect(
110 sigc::mem_fun(*this, &GGraphics::onInput));
111 displaycombo_->signal_changed().connect(
112 sigc::mem_fun(*this, &GGraphics::onInput));
113 outputscalespin_->signal_changed().connect(
114 sigc::mem_fun(*this, &GGraphics::onInput));
115 heightspin_->signal_changed().connect(
116 sigc::mem_fun(*this, &GGraphics::onInput));
117 heightunitscombo_->signal_changed().connect(
118 sigc::mem_fun(*this, &GGraphics::onInput));
119 widthspin_->signal_changed().connect(
120 sigc::mem_fun(*this, &GGraphics::onInput));
121 widthunitscombo_->signal_changed().connect(
122 sigc::mem_fun(*this, &GGraphics::onInput));
123 aspectcheck_->signal_toggled().connect(
124 sigc::mem_fun(*this, &GGraphics::onInput));
126 setscalingradio_->signal_toggled().connect(
127 sigc::mem_fun(*this, &GGraphics::onSizingModeChange));
128 setsizeradio_->signal_toggled().connect(
129 sigc::mem_fun(*this, &GGraphics::onSizingModeChange));
131 browsebutton_->signal_clicked().connect(
132 sigc::mem_fun(*this, &GGraphics::onBrowseClicked));
134 editbutton_->signal_clicked().connect(
135 sigc::mem_fun(*this, &GGraphics::onEditClicked));
137 vector<string> const unit_list = buildLengthUnitList();
138 PopulateComboBox(heightunitscombo_, unit_list);
139 PopulateComboBox(widthunitscombo_, unit_list);
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));
196 // set the right default unit
197 switch (lyxrc.default_papersize) {
198 case PAPER_DEFAULT: break;
200 case PAPER_LEGALPAPER:
201 case PAPER_EXECUTIVEPAPER: defaultUnit = "in"; break;
205 case PAPER_B5PAPER: defaultUnit = "cm"; break;
210 void GGraphics::onSizingModeChange()
212 bool const scalingmode = setscalingradio_->get_active();
214 outputscalespin_->set_sensitive(scalingmode);
215 widthspin_->set_sensitive(!scalingmode);
216 heightspin_->set_sensitive(!scalingmode);
217 widthunitscombo_->set_sensitive(!scalingmode);
218 heightunitscombo_->set_sensitive(!scalingmode);
219 aspectcheck_->set_sensitive(!scalingmode);
220 bc().input(ButtonPolicy::SMI_VALID);
224 void GGraphics::PopulateComboBox(Gtk::ComboBox * combo,
225 vector<string> const & strings)
227 Glib::RefPtr<Gtk::ListStore> model = Gtk::ListStore::create(cols_);
228 vector<string>::const_iterator it = strings.begin();
229 vector<string>::const_iterator end = strings.end();
230 for (int rowindex = 0; it != end; ++it, ++rowindex) {
231 Gtk::TreeModel::iterator row = model->append();
232 (*row)[stringcol_] = *it;
235 combo->set_model(model);
236 Gtk::CellRendererText * cell = Gtk::manage(new Gtk::CellRendererText);
237 combo->pack_start(*cell, true);
238 combo->add_attribute(*cell, "text", 0);
242 void GGraphics::updateComboFromLength(Gtk::ComboBox * combo,
243 LyXLength const & len)
245 string unit = stringFromUnit(len.unit());
249 Gtk::TreeModel::iterator it = combo->get_model()->children().begin();
250 Gtk::TreeModel::iterator end = combo->get_model()->children().end();
251 for (; it != end ; ++it) {
252 if ((*it)[stringcol_] == unit) {
253 combo->set_active(it);
257 // Fallen through, we didn't find the target length!
258 combo->set_active(0);
259 lyxerr << "GGraphics::updateComboFromLength: couldn't find "
260 "target unit '" << unit << "'\n";
264 void GGraphics::apply()
266 // Create the parameters structure and fill the data from the dialog.
267 InsetGraphicsParams & igp = controller().params();
270 igp.filename.set(fileentry_->get_text(),
271 kernel().bufferFilepath());
274 static_cast<int>(displayscalespin_->get_adjustment()->get_value());
275 if (igp.lyxscale == 0) {
279 switch (displaycombo_->get_active_row_number()) {
281 igp.display = graphics::NoDisplay;
284 igp.display = graphics::ColorDisplay;
287 igp.display = graphics::GrayscaleDisplay;
290 igp.display = graphics::MonochromeDisplay;
293 igp.display = graphics::DefaultDisplay;
296 if (setscalingradio_->get_active()) {
297 igp.scale = outputscalespin_->get_adjustment()->get_value();
298 if (float_equal(igp.scale, 0.0, 0.05))
300 igp.width = LyXLength();
303 Glib::ustring const widthunit =
304 (*widthunitscombo_->get_active())[stringcol_];
305 igp.width = LyXLength(widthspin_->get_text() + widthunit);
309 Glib::ustring const heightunit =
310 (*heightunitscombo_->get_active())[stringcol_];
311 igp.height = LyXLength(heightspin_->get_text() + heightunit);
313 igp.keepAspectRatio = aspectcheck_->get_active();
314 igp.draft = draftcheck_->get_active();
315 igp.noUnzip = !unzipcheck_->get_active();
319 if (!controller().bbChanged) {
320 // don't write anything
323 Glib::ustring const bbunit = (*bbunitscombo_->get_active())[stringcol_];
326 if (leftbottomxspin_->get_text().empty())
329 bb = leftbottomxspin_->get_text() + bbunit;
333 if (leftbottomyspin_->get_text().empty())
336 bb += leftbottomyspin_->get_text() + bbunit;
340 if (righttopxspin_->get_text().empty())
343 bb += righttopxspin_->get_text() + bbunit;
347 if (righttopyspin_->get_text().empty())
350 bb += righttopyspin_->get_text() + bbunit;
352 /// The bounding box with "xLB yLB yRT yRT ", divided by a space!
355 igp.clip = clipcheck_->get_active();
358 igp.rotateAngle = anglespin_->get_adjustment()->get_value();
360 int const origin_pos = origincombo_->get_active_row_number();
361 igp.rotateOrigin = origins_[origin_pos];
363 igp.subcaption = subfigcheck_->get_active();
364 igp.subcaptionText = subfigentry_->get_text();
366 igp.special = latexoptsentry_->get_text();
370 void GGraphics::update() {
371 // Update dialog with details from inset
372 InsetGraphicsParams & igp = controller().params();
376 igp.filename.outputFilename(kernel().bufferFilepath());
377 fileentry_->set_text(name);
378 displayscalespin_->get_adjustment()->set_value(igp.lyxscale);
381 switch (igp.display) {
382 case graphics::NoDisplay:
383 displaycombo_->set_active(4);
385 case graphics::ColorDisplay:
386 displaycombo_->set_active(3);
388 case graphics::GrayscaleDisplay:
389 displaycombo_->set_active(2);
391 case graphics::MonochromeDisplay:
392 displaycombo_->set_active(1);
394 case graphics::DefaultDisplay:
395 displaycombo_->set_active(0);
398 outputscalespin_->get_adjustment()->set_value(igp.scale);
399 widthspin_->get_adjustment()->set_value(igp.width.value());
400 updateComboFromLength(widthunitscombo_, igp.width);
401 heightspin_->get_adjustment()->set_value(igp.height.value());
402 updateComboFromLength(heightunitscombo_, igp.height);
404 if (!float_equal(igp.scale, 0.0, 0.05)) {
405 //scaling sizing mode
406 setscalingradio_->set_active(true);
408 setsizeradio_->set_active(true);
411 aspectcheck_->set_active(igp.keepAspectRatio);
412 draftcheck_->set_active(igp.draft);
413 unzipcheck_->set_active(!igp.noUnzip);
416 // set the bounding box values, if exists. First we need the whole
417 // path, because the controller knows nothing about the doc-dir
418 updateBB(igp.filename.absFilename(), igp.bb);
419 clipcheck_->set_active(igp.clip);
422 anglespin_->get_adjustment()->set_value(igp.rotateAngle);
425 if (igp.rotateOrigin.empty()) {
428 origin_pos = findPos(origins_, igp.rotateOrigin);
430 origincombo_->set_active(origin_pos);
433 subfigcheck_->set_active(igp.subcaption);
434 subfigentry_->set_text(igp.subcaptionText);
435 subfigentry_->set_sensitive(subfigcheck_->get_active());
436 latexoptsentry_->set_text(igp.special);
438 // open dialog in the file-tab, whenever filename is empty
439 if (igp.filename.empty()) {
440 notebook_->set_current_page(0);
443 bc().input(ButtonPolicy::SMI_INVALID);
447 void GGraphics::updateBB(string const & filename, string const & bb_inset)
449 // Update dialog with details from inset
450 // set the bounding box values, if exists. First we need the whole
451 // path, because the controller knows nothing about the doc-dir
453 if (bb_inset.empty()) {
454 lyxerr[Debug::GRAPHICS]
455 << "GGraphics::updateBB() [no BoundingBox]\n";
456 string const bb = controller().readBB(filename);
458 // get the values from the file
459 // in this case we always have the point-unit
460 leftbottomxspin_->set_text(token(bb, ' ', 0));
461 leftbottomyspin_->set_text(token(bb, ' ', 1));
462 righttopxspin_->set_text(token(bb, ' ', 2));
463 righttopyspin_->set_text(token(bb, ' ', 3));
466 leftbottomxspin_->set_text("");
467 leftbottomyspin_->set_text("");
468 righttopxspin_->set_text("");
469 righttopyspin_->set_text("");
471 updateComboFromLength(bbunitscombo_,LyXLength("bp"));
473 // get the values from the inset
474 lyxerr[Debug::GRAPHICS]
475 << "FormGraphics::updateBB(): igp has BoundingBox"
476 << " ["<< bb_inset << "]\n";
479 anyLength = LyXLength(token(bb_inset, ' ', 0));
481 updateComboFromLength(bbunitscombo_, anyLength);
483 leftbottomxspin_->get_adjustment()->set_value(anyLength.value());
485 anyLength = LyXLength(token(bb_inset, ' ', 1));
486 leftbottomyspin_->get_adjustment()->set_value(anyLength.value());
488 anyLength = LyXLength(token(bb_inset, ' ', 2));
489 righttopxspin_->get_adjustment()->set_value(anyLength.value());
491 anyLength = LyXLength(token(bb_inset, ' ', 3));
492 righttopyspin_->get_adjustment()->set_value(anyLength.value());
494 controller().bbChanged = false;
498 void GGraphics::onBrowseClicked()
500 // Get the filename from the dialog
501 string const in_name = fileentry_->get_text();
502 string const out_name = controller().browse(in_name);
503 lyxerr[Debug::GRAPHICS]
504 << "[FormGraphics]out_name: " << out_name << "\n";
505 if (out_name != in_name && !out_name.empty()) {
506 fileentry_->set_text(out_name);
508 if (controller().isFilenameValid(out_name) &&
509 !controller().bbChanged) {
510 updateBB(out_name, string());
513 bc().input(ButtonPolicy::SMI_VALID);
517 void GGraphics::onBBChange()
519 controller().bbChanged = true;
520 bc().input(ButtonPolicy::SMI_VALID);
524 void GGraphics::onBBFromFileClicked()
526 string const filename = fileentry_->get_text();
527 if (!filename.empty()) {
528 string bb = controller().readBB(filename);
530 leftbottomxspin_->set_text(token(bb, ' ', 0));
531 leftbottomyspin_->set_text(token(bb, ' ', 1));
532 righttopxspin_->set_text(token(bb, ' ', 2));
533 righttopyspin_->set_text(token(bb, ' ', 3));
534 updateComboFromLength(bbunitscombo_,LyXLength("bp"));
536 controller().bbChanged = false;
538 leftbottomxspin_->set_text("");
539 leftbottomyspin_->set_text("");
540 righttopxspin_->set_text("");
541 righttopyspin_->set_text("");
542 updateComboFromLength(bbunitscombo_,LyXLength("bp"));
544 bc().input(ButtonPolicy::SMI_VALID);
548 void GGraphics::onSubFigCheckToggled()
550 subfigentry_->set_sensitive(subfigcheck_->get_active());
551 bc().input(ButtonPolicy::SMI_VALID);
555 void GGraphics::onEditClicked()
557 controller().editGraphics();
561 void GGraphics::onInput()
563 bc().input(ButtonPolicy::SMI_VALID);
566 } // namespace frontend