page-sizer.cpp revision bc5ab6c60f7d73fd883b4208ea63119cd2fabfd6
0N/A/** \file
2362N/A *
0N/A * Paper-size widget and helper functions
0N/A *
0N/A * Authors:
0N/A * bulia byak <buliabyak@users.sf.net>
2362N/A * Lauris Kaplinski <lauris@kaplinski.com>
0N/A * Jon Phillips <jon@rejon.org>
2362N/A * Ralf Stephan <ralf@ark.in-berlin.de> (Gtkmm)
0N/A *
0N/A * Copyright (C) 2000 - 2005 Authors
0N/A *
0N/A * Released under GNU GPL. Read the file 'COPYING' for more information
0N/A */
0N/A
0N/A#ifdef HAVE_CONFIG_H
0N/A# include <config.h>
0N/A#endif
0N/A
0N/A#include <cmath>
2362N/A#include <gtkmm.h>
2362N/A#include <gtkmm/optionmenu.h>
2362N/A#include <gtkmm/frame.h>
0N/A#include <gtkmm/table.h>
0N/A#include "ui/widget/button.h"
0N/A
0N/A#include "ui/widget/scalar-unit.h"
0N/A
0N/A#include "helper/units.h"
0N/A#include "inkscape.h"
0N/A#include "verbs.h"
0N/A#include "desktop-handles.h"
0N/A#include "document.h"
0N/A#include "desktop.h"
0N/A#include "page-sizer.h"
0N/A#include "helper/action.h"
0N/A
0N/Ausing std::pair;
0N/A
0N/Anamespace Inkscape {
0N/Anamespace UI {
0N/Anamespace Widget {
0N/A
0N/Astruct PaperSize {
0N/A char const * const name;
0N/A double const smaller;
0N/A double const larger;
0N/A SPUnitId const unit;
0N/A};
0N/A
0N/A /** \note
0N/A * The ISO page sizes in the table below differ from ghostscript's idea of page sizes (by
0N/A * less than 1pt). Being off by <1pt should be OK for most purposes, but may cause fuzziness
0N/A * (antialiasing) problems when printing to 72dpi or 144dpi printers or bitmap files due to
0N/A * postscript's different coordinate system (y=0 meaning bottom of page in postscript and top
0N/A * of page in SVG). I haven't looked into whether this does in fact cause fuzziness, I merely
0N/A * note the possibility. Rounding done by extension/internal/ps.cpp (e.g. floor/ceil calls)
0N/A * will also affect whether fuzziness occurs.
0N/A *
0N/A * The remainder of this comment discusses the origin of the numbers used for ISO page sizes in
0N/A * this table and in ghostscript.
0N/A *
0N/A * The versions here, in mm, are the official sizes according to
0N/A * <a href="http://en.wikipedia.org/wiki/Paper_sizes">http://en.wikipedia.org/wiki/Paper_sizes</a>
0N/A * at 2005-01-25. (The ISO entries in the below table
0N/A * were produced mechanically from the table on that page.)
0N/A *
0N/A * (The rule seems to be that A0, B0, ..., D0. sizes are rounded to the nearest number of mm
0N/A * from the "theoretical size" (i.e. 1000 * sqrt(2) or pow(2.0, .25) or the like), whereas
0N/A * going from e.g. A0 to A1 always take the floor of halving -- which by chance coincides
0N/A * exactly with flooring the "theoretical size" for n != 0 instead of the rounding to nearest
0N/A * done for n==0.)
0N/A *
0N/A * Ghostscript paper sizes are given in gs_statd.ps according to gs(1). gs_statd.ps always
0N/A * uses an integer number of pt: sometimes gs_statd.ps rounds to nearest (e.g. a1), sometimes
0N/A * floors (e.g. a10), sometimes ceils (e.g. a8).
0N/A *
0N/A * I'm not sure how ghostscript's gs_statd.ps was calculated: it isn't just rounding the
0N/A * "theoretical size" of each page to pt (see a0), nor is it rounding the a0 size times an
0N/A * appropriate power of two (see a1). Possibly it was prepared manually, with a human applying
0N/A * inconsistent rounding rules when converting from mm to pt.
0N/A */
0N/A /** \todo
0N/A * Should we include the JIS B series (used in Japan)
0N/A * (JIS B0 is sometimes called JB0, and similarly for JB1 etc)?
0N/A * Should we exclude B7--B10 and A7--10 to make the list smaller ?
0N/A * Should we include any of the ISO C, D and E series (see below) ?
0N/A */
0N/A
0N/Astatic PaperSize const inkscape_papers[] = {
0N/A { "A4", 210, 297, SP_UNIT_MM },
0N/A { "US Letter", 8.5, 11, SP_UNIT_IN },
0N/A { "US Legal", 8.5, 14, SP_UNIT_IN },
0N/A { "US Executive", 7.25, 10.5, SP_UNIT_IN },
0N/A { "A0", 841, 1189, SP_UNIT_MM },
0N/A { "A1", 594, 841, SP_UNIT_MM },
0N/A { "A2", 420, 594, SP_UNIT_MM },
0N/A { "A3", 297, 420, SP_UNIT_MM },
0N/A { "A5", 148, 210, SP_UNIT_MM },
0N/A { "A6", 105, 148, SP_UNIT_MM },
0N/A { "A7", 74, 105, SP_UNIT_MM },
0N/A { "A8", 52, 74, SP_UNIT_MM },
0N/A { "A9", 37, 52, SP_UNIT_MM },
0N/A { "A10", 26, 37, SP_UNIT_MM },
0N/A { "B0", 1000, 1414, SP_UNIT_MM },
0N/A { "B1", 707, 1000, SP_UNIT_MM },
0N/A { "B2", 500, 707, SP_UNIT_MM },
0N/A { "B3", 353, 500, SP_UNIT_MM },
0N/A { "B4", 250, 353, SP_UNIT_MM },
0N/A { "B5", 176, 250, SP_UNIT_MM },
0N/A { "B6", 125, 176, SP_UNIT_MM },
0N/A { "B7", 88, 125, SP_UNIT_MM },
0N/A { "B8", 62, 88, SP_UNIT_MM },
0N/A { "B9", 44, 62, SP_UNIT_MM },
0N/A { "B10", 31, 44, SP_UNIT_MM },
0N/A
0N/A#if 0 /* Whether to include or exclude these depends on how big we mind our page size menu
0N/A becoming. C series is used for envelopes; don't know what D and E series are used for. */
0N/A { "C0", 917, 1297, SP_UNIT_MM },
0N/A { "C1", 648, 917, SP_UNIT_MM },
0N/A { "C2", 458, 648, SP_UNIT_MM },
0N/A { "C3", 324, 458, SP_UNIT_MM },
0N/A { "C4", 229, 324, SP_UNIT_MM },
0N/A { "C5", 162, 229, SP_UNIT_MM },
0N/A { "C6", 114, 162, SP_UNIT_MM },
0N/A { "C7", 81, 114, SP_UNIT_MM },
0N/A { "C8", 57, 81, SP_UNIT_MM },
0N/A { "C9", 40, 57, SP_UNIT_MM },
0N/A { "C10", 28, 40, SP_UNIT_MM },
0N/A { "D1", 545, 771, SP_UNIT_MM },
0N/A { "D2", 385, 545, SP_UNIT_MM },
0N/A { "D3", 272, 385, SP_UNIT_MM },
0N/A { "D4", 192, 272, SP_UNIT_MM },
0N/A { "D5", 136, 192, SP_UNIT_MM },
0N/A { "D6", 96, 136, SP_UNIT_MM },
0N/A { "D7", 68, 96, SP_UNIT_MM },
0N/A { "E3", 400, 560, SP_UNIT_MM },
0N/A { "E4", 280, 400, SP_UNIT_MM },
0N/A { "E5", 200, 280, SP_UNIT_MM },
0N/A { "E6", 140, 200, SP_UNIT_MM },
0N/A#endif
0N/A
0N/A { "CSE", 462, 649, SP_UNIT_PT },
0N/A { "US #10 Envelope", 4.125, 9.5, SP_UNIT_IN }, // TODO: Select landscape by default.
0N/A /* See http://www.hbp.com/content/PCR_envelopes.cfm for a much larger list of US envelope
0N/A sizes. */
0N/A { "DL Envelope", 110, 220, SP_UNIT_MM }, // TODO: Select landscape by default.
0N/A { "Ledger/Tabloid", 11, 17, SP_UNIT_IN },
0N/A /* Note that `Folio' (used in QPrinter/KPrinter) is deliberately absent from this list, as it
0N/A means different sizes to different people: different people may expect the width to be
0N/A either 8, 8.25 or 8.5 inches, and the height to be either 13 or 13.5 inches, even
0N/A restricting our interpretation to foolscap folio. If you wish to introduce a folio-like
0N/A page size to the list, then please consider using a name more specific than just `Folio' or
0N/A `Foolscap Folio'. */
0N/A { "Banner 468x60", 60, 468, SP_UNIT_PX }, // TODO: Select landscape by default.
0N/A { "Icon 16x16", 16, 16, SP_UNIT_PX },
0N/A { "Icon 32x32", 32, 32, SP_UNIT_PX },
0N/A { NULL, 0, 0, SP_UNIT_PX },
0N/A};
0N/A
0N/A//===================================================
0N/Astatic const SPUnit _px_unit = sp_unit_get_by_id (SP_UNIT_PX);
0N/A
0N/Aclass SizeMenuItem : public Gtk::MenuItem {
0N/Apublic:
0N/A SizeMenuItem (PaperSize const * paper, PageSizer * widget)
0N/A : Gtk::MenuItem (paper ? paper->name : _("Custom")),
0N/A _paper(paper), _parent(widget) {}
0N/Aprotected:
0N/A PaperSize const * _paper;
0N/A PageSizer *_parent;
0N/A void on_activate();
0N/A};
0N/A
0N/Avoid
0N/ASizeMenuItem::on_activate()
0N/A{
0N/A if (_parent == 0) // handle Custom entry
0N/A return;
0N/A
0N/A double w = _paper->smaller, h = _paper->larger;
0N/A SPUnit const &src_unit = sp_unit_get_by_id (_paper->unit);
0N/A sp_convert_distance (&w, &src_unit, &_px_unit);
0N/A sp_convert_distance (&h, &src_unit, &_px_unit);
0N/A if (_parent->_landscape)
0N/A _parent->setDim (h, w);
0N/A else
0N/A _parent->setDim (w, h);
0N/A}
0N/A
0N/A//---------------------------------------------------
0N/A
0N/APageSizer::PageSizer()
0N/A: Gtk::VBox(false,4)
0N/A{
0N/A Gtk::HBox *hbox_size = manage (new Gtk::HBox (false, 4));
0N/A pack_start (*hbox_size, false, false, 0);
0N/A Gtk::Label *label_size = manage (new Gtk::Label (_("P_age size:"), 1.0, 0.5));
0N/A label_size->set_use_underline();
0N/A hbox_size->pack_start (*label_size, false, false, 0);
0N/A _omenu_size = manage (new Gtk::OptionMenu);
0N/A label_size->set_mnemonic_widget (*_omenu_size);
0N/A hbox_size->pack_start (*_omenu_size, true, true, 0);
0N/A Gtk::Menu *menu_size = manage (new Gtk::Menu);
0N/A
0N/A for (PaperSize const *paper = inkscape_papers; paper->name; paper++) {
0N/A SizeMenuItem *item = manage (new SizeMenuItem (paper, this));
0N/A menu_size->append (*item);
0N/A }
0N/A SizeMenuItem *item = manage (new SizeMenuItem (0, 0));
0N/A menu_size->prepend (*item);
0N/A _omenu_size->set_menu (*menu_size);
0N/A}
0N/A
0N/APageSizer::~PageSizer()
0N/A{
0N/A _portrait_connection.disconnect();
0N/A _landscape_connection.disconnect();
0N/A _changedw_connection.disconnect();
0N/A _changedh_connection.disconnect();
0N/A}
0N/A
0N/Avoid
0N/APageSizer::init (Registry& reg)
0N/A{
0N/A Gtk::HBox *hbox_ori = manage (new Gtk::HBox);
0N/A pack_start (*hbox_ori, false, false, 0);
0N/A Gtk::Label *label_ori = manage (new Gtk::Label (_("Page orientation:"), 0.0, 0.5));
0N/A hbox_ori->pack_start (*label_ori, false, false, 0);
0N/A _rb_land = manage (new Gtk::RadioButton (_("_Landscape"), true));
0N/A Gtk::RadioButton::Group group = _rb_land->get_group();
0N/A hbox_ori->pack_end (*_rb_land, false, false, 5);
0N/A _rb_port = manage (new Gtk::RadioButton (_("_Portrait"), true));
0N/A hbox_ori->pack_end (*_rb_port, false, false, 5);
0N/A _rb_port->set_group (group);
0N/A _rb_port->set_active (true);
0N/A
0N/A /* Custom paper frame */
0N/A Gtk::Frame *frame = manage (new Gtk::Frame(_("Custom size")));
0N/A pack_start (*frame, false, false, 0);
0N/A Gtk::Table *table = manage (new Gtk::Table (5, 2, false));
0N/A table->set_border_width (4);
0N/A table->set_row_spacings (4);
0N/A table->set_col_spacings (4);
0N/A
0N/A Inkscape::UI::Widget::Button* fit_canv = manage(new Inkscape::UI::Widget::Button(_("_Fit page to selection"),
0N/A _("Resize the page to fit the current selection, or the entire drawing if there is no selection")));
0N/A // prevent fit_canv from expanding
0N/A Gtk::Alignment *fit_canv_cont = manage(new Gtk::Alignment(1.0,0.5,0.0,0.0));
0N/A fit_canv_cont->add(*fit_canv);
0N/A
0N/A frame->add (*table);
0N/A
0N/A _wr = &reg;
0N/A
0N/A _rum.init (_("U_nits:"), "units", *_wr);
0N/A _rusw.init (_("_Width:"), _("Width of paper"), "width", _rum, *_wr);
0N/A _rush.init (_("_Height:"), _("Height of paper"), "height", _rum, *_wr);
0N/A
0N/A table->attach (*_rum._label, 0,1,0,1, Gtk::FILL|Gtk::EXPAND, (Gtk::AttachOptions)0,0,0);
0N/A table->attach (*_rum._sel, 1,2,0,1, Gtk::FILL|Gtk::EXPAND, (Gtk::AttachOptions)0,0,0);
0N/A table->attach (*_rusw.getSU(), 0,2,1,2, Gtk::FILL|Gtk::EXPAND, (Gtk::AttachOptions)0,0,0);
0N/A table->attach (*_rush.getSU(), 0,2,2,3, Gtk::FILL|Gtk::EXPAND, (Gtk::AttachOptions)0,0,0);
0N/A table->attach (*fit_canv_cont, 0,2,3,4, Gtk::FILL|Gtk::EXPAND, (Gtk::AttachOptions)0,0,0);
0N/A
0N/A _landscape_connection = _rb_land->signal_toggled().connect (sigc::mem_fun (*this, &PageSizer::on_landscape));
0N/A _portrait_connection = _rb_port->signal_toggled().connect (sigc::mem_fun (*this, &PageSizer::on_portrait));
0N/A _changedw_connection = _rusw.getSU()->signal_value_changed().connect (sigc::mem_fun (*this, &PageSizer::on_value_changed));
0N/A _changedh_connection = _rush.getSU()->signal_value_changed().connect (sigc::mem_fun (*this, &PageSizer::on_value_changed));
0N/A fit_canv->signal_clicked().connect(sigc::mem_fun(*this, &PageSizer::fire_fit_canvas_to_selection_or_drawing));
0N/A
0N/A show_all_children();
0N/A}
0N/A
0N/A
0N/A/**
0N/A * Set document dimensions (if not called by Doc prop's update()) and
0N/A * set the PageSizer's widgets and text entries accordingly. This is
0N/A * somewhat slow, is there something done too often invisibly?
0N/A *
0N/A * \param w, h given in px
0N/A */
0N/Avoid
0N/APageSizer::setDim (double w, double h)
0N/A{
0N/A static bool _called = false;
0N/A if (_called) return;
0N/A
0N/A _called = true;
0N/A
0N/A _landscape_connection.block();
0N/A _portrait_connection.block();
0N/A _changedw_connection.block();
0N/A _changedh_connection.block();
0N/A
0N/A if (SP_ACTIVE_DESKTOP && !_wr->isUpdating()) {
0N/A SPDocument *doc = sp_desktop_document(SP_ACTIVE_DESKTOP);
0N/A sp_document_set_width (doc, w, &_px_unit);
2014N/A sp_document_set_height (doc, h, &_px_unit);
0N/A sp_document_done (doc);
0N/A }
0N/A
0N/A _landscape = w>h;
0N/A _rb_land->set_active (_landscape ? true : false);
0N/A _rb_port->set_active (_landscape ? false : true);
0N/A
0N/A _omenu_size->set_history (1 + find_paper_size (w, h));
0N/A
0N/A Unit const& unit = _rum._sel->getUnit();
0N/A _rusw.setValue (w / unit.factor);
0N/A _rush.setValue (h / unit.factor);
0N/A
0N/A _landscape_connection.unblock();
2014N/A _portrait_connection.unblock();
0N/A _changedw_connection.unblock();
0N/A _changedh_connection.unblock();
0N/A
0N/A _called = false;
0N/A}
0N/A
0N/A/**
0N/A * Returns an index into inkscape_papers of a paper of the specified
0N/A * size (specified in px), or -1 if there's no such paper.
0N/A */
0N/Aint
0N/APageSizer::find_paper_size (double w, double h) const
0N/A{
0N/A double given[2];
0N/A if ( w < h ) {
0N/A given[0] = w; given[1] = h;
0N/A } else {
0N/A given[0] = h; given[1] = w;
0N/A }
0N/A g_return_val_if_fail(given[0] <= given[1], -1);
0N/A for (unsigned i = 0; i < G_N_ELEMENTS(inkscape_papers) - 1; ++i) {
0N/A SPUnit const &i_unit = sp_unit_get_by_id(inkscape_papers[i].unit);
2014N/A double const i_sizes[2] = { sp_units_get_pixels(inkscape_papers[i].smaller, i_unit),
0N/A sp_units_get_pixels(inkscape_papers[i].larger, i_unit) };
0N/A g_return_val_if_fail(i_sizes[0] <= i_sizes[1], -1);
0N/A if ((std::abs(given[0] - i_sizes[0]) <= .1) &&
0N/A (std::abs(given[1] - i_sizes[1]) <= .1) )
0N/A {
0N/A return (int) i;
0N/A }
0N/A }
0N/A return -1;
0N/A}
0N/A
0N/Avoid
0N/APageSizer::fire_fit_canvas_to_selection_or_drawing() {
0N/A SPDesktop *dt = SP_ACTIVE_DESKTOP;
0N/A if (!dt) return;
0N/A Verb *verb = Verb::get( SP_VERB_FIT_CANVAS_TO_SELECTION_OR_DRAWING );
0N/A if (verb) {
0N/A SPAction *action = verb->get_action(dt);
0N/A if (action) {
0N/A sp_action_perform(action, NULL);
0N/A }
0N/A }
0N/A}
0N/A
0N/Avoid
0N/APageSizer::on_portrait()
0N/A{
0N/A if (!_rb_port->get_active())
0N/A return;
0N/A double w = _rusw.getSU()->getValue ("px");
0N/A double h = _rush.getSU()->getValue ("px");
0N/A if (h<w) setDim (h, w);
0N/A}
0N/A
0N/Avoid
0N/APageSizer::on_landscape()
0N/A{
0N/A if (!_rb_land->get_active())
0N/A return;
0N/A double w = _rusw.getSU()->getValue ("px");
0N/A double h = _rush.getSU()->getValue ("px");
0N/A if (w<h) setDim (h, w);
0N/A}
0N/A
0N/Avoid
0N/APageSizer::on_value_changed()
0N/A{
0N/A if (_wr->isUpdating()) return;
0N/A
0N/A setDim (_rusw.getSU()->getValue("px"), _rush.getSU()->getValue("px"));
0N/A}
0N/A
0N/A} // namespace Widget
0N/A} // namespace UI
0N/A} // namespace Inkscape
0N/A
0N/A/*
0N/A Local Variables:
0N/A mode:c++
4632N/A c-file-style:"stroustrup"
4632N/A c-file-offsets:((innamespace . 0)(inline-open . 0))
0N/A indent-tabs-mode:nil
0N/A fill-column:99
0N/A End:
0N/A*/
0N/A// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
0N/A