diff options
| author | Liam P. White <inkscapebronyat-signgmaildotcom> | 2014-03-28 01:36:41 +0000 |
|---|---|---|
| committer | Liam P. White <inkscapebronyat-signgmaildotcom> | 2014-03-28 01:36:41 +0000 |
| commit | c1ecda53e4ce811681e6545f6158eb48c4a983a0 (patch) | |
| tree | 064de4eb4815f49ed736bc9c52c3b3d78251a61a /src/ui | |
| parent | Update to trunk (diff) | |
| parent | Fix make check (diff) | |
| download | inkscape-c1ecda53e4ce811681e6545f6158eb48c4a983a0.tar.gz inkscape-c1ecda53e4ce811681e6545f6158eb48c4a983a0.zip | |
Update to trunk
(bzr r13090.1.35)
Diffstat (limited to 'src/ui')
| -rw-r--r-- | src/ui/CMakeLists.txt | 7 | ||||
| -rw-r--r-- | src/ui/dialog/Makefile_insert | 5 | ||||
| -rw-r--r-- | src/ui/dialog/arrange-tab.h | 54 | ||||
| -rw-r--r-- | src/ui/dialog/dialog-manager.cpp | 4 | ||||
| -rw-r--r-- | src/ui/dialog/grid-arrange-tab.cpp | 809 | ||||
| -rw-r--r-- | src/ui/dialog/grid-arrange-tab.h | 154 | ||||
| -rw-r--r-- | src/ui/dialog/polar-arrange-tab.cpp | 414 | ||||
| -rw-r--r-- | src/ui/dialog/polar-arrange-tab.h | 100 | ||||
| -rw-r--r-- | src/ui/dialog/tile.cpp | 878 | ||||
| -rw-r--r-- | src/ui/dialog/tile.h | 135 | ||||
| -rw-r--r-- | src/ui/tools/connector-tool.cpp | 53 | ||||
| -rw-r--r-- | src/ui/widget/Makefile_insert | 2 | ||||
| -rw-r--r-- | src/ui/widget/anchor-selector.cpp | 97 | ||||
| -rw-r--r-- | src/ui/widget/anchor-selector.h | 59 |
14 files changed, 1779 insertions, 992 deletions
diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index c3e406e3f..7d80f1e36 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -69,6 +69,7 @@ set(ui_SRC dialog/floating-behavior.cpp dialog/font-substitution.cpp dialog/glyphs.cpp + dialog/grid-arrange-tab.cpp dialog/guides.cpp dialog/icon-preview.cpp dialog/inkscape-preferences.cpp @@ -83,6 +84,7 @@ set(ui_SRC dialog/object-attributes.cpp dialog/object-properties.cpp dialog/ocaldialogs.cpp + dialog/polar-arrange-tab.cpp dialog/print-colors-preview-dialog.cpp dialog/print.cpp dialog/symbols.cpp @@ -103,6 +105,7 @@ set(ui_SRC # dialog/whiteboard-sharewithchat.cpp # dialog/whiteboard-sharewithuser.cpp + widget/anchor-selector.cpp widget/button.cpp widget/color-picker.cpp widget/color-preview.cpp @@ -162,6 +165,7 @@ set(ui_SRC dialog/aboutbox.h dialog/align-and-distribute.h + dialog/arrange-tab.h dialog/behavior.h dialog/calligraphic-profile-rename.h dialog/color-item.h @@ -186,6 +190,7 @@ set(ui_SRC dialog/font-substitution.h dialog/glyphs.h dialog/guides.h + dialog/grid-arrange-tab.h dialog/icon-preview.h dialog/inkscape-preferences.h dialog/input.h @@ -200,6 +205,7 @@ set(ui_SRC dialog/object-properties.h dialog/ocaldialogs.h dialog/panel-dialog.h + dialog/polar-arrange-tab.h dialog/pixelartdialog.h dialog/print-colors-preview-dialog.h dialog/print.h @@ -259,6 +265,7 @@ set(ui_SRC tools/tweak-tool.h tools/zoom-tool.h + widget/anchor-selector.h widget/attr-widget.h widget/button.h widget/color-picker.h diff --git a/src/ui/dialog/Makefile_insert b/src/ui/dialog/Makefile_insert index 1cf667f2a..8a7a4a5dd 100644 --- a/src/ui/dialog/Makefile_insert +++ b/src/ui/dialog/Makefile_insert @@ -5,6 +5,7 @@ ink_common_sources += \ ui/dialog/aboutbox.h \ ui/dialog/align-and-distribute.cpp \ ui/dialog/align-and-distribute.h \ + ui/dialog/arrange-tab.h \ ui/dialog/behavior.h \ ui/dialog/calligraphic-profile-rename.h \ ui/dialog/calligraphic-profile-rename.cpp \ @@ -50,6 +51,8 @@ ink_common_sources += \ ui/dialog/floating-behavior.h \ ui/dialog/glyphs.cpp \ ui/dialog/glyphs.h \ + ui/dialog/grid-arrange-tab.h \ + ui/dialog/grid-arrange-tab.cpp \ ui/dialog/guides.cpp \ ui/dialog/guides.h \ ui/dialog/icon-preview.cpp \ @@ -79,6 +82,8 @@ ink_common_sources += \ ui/dialog/object-properties.cpp \ ui/dialog/object-properties.h \ ui/dialog/panel-dialog.h \ + ui/dialog/polar-arrange-tab.cpp \ + ui/dialog/polar-arrange-tab.h \ ui/dialog/print.cpp \ ui/dialog/print.h \ ui/dialog/print-colors-preview-dialog.cpp \ diff --git a/src/ui/dialog/arrange-tab.h b/src/ui/dialog/arrange-tab.h new file mode 100644 index 000000000..3ffe1ef4c --- /dev/null +++ b/src/ui/dialog/arrange-tab.h @@ -0,0 +1,54 @@ +/** + * @brief Arrange tools base class + */ +/* Authors: + * * Declara Denis + * Copyright (C) 2012 Authors + * + * Released under GNU GPL. Read the file 'COPYING' for more information. + */ + +#ifndef INKSCAPE_UI_DIALOG_ARRANGE_TAB_H +#define INKSCAPE_UI_DIALOG_ARRANGE_TAB_H + +#include <gtkmm/box.h> + +namespace Inkscape { +namespace UI { +namespace Dialog { + +/** + * This interface should be implemented by each arrange mode. + * The class is a Gtk::VBox and will be displayed as a tab in + * the dialog + */ +class ArrangeTab : public Gtk::VBox +{ +public: + ArrangeTab() {}; + virtual ~ArrangeTab() {}; + + /** + * Do the actual work! This method is invoked to actually arrange the + * selection + */ + virtual void arrange() = 0; +}; + +} //namespace Dialog +} //namespace UI +} //namespace Inkscape + + +#endif /* INKSCAPE_UI_DIALOG_ARRANGE_TAB_H */ + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/dialog-manager.cpp b/src/ui/dialog/dialog-manager.cpp index ddf41e0c8..ee11601f3 100644 --- a/src/ui/dialog/dialog-manager.cpp +++ b/src/ui/dialog/dialog-manager.cpp @@ -120,8 +120,8 @@ DialogManager::DialogManager() { // registerFactory("PrintColorsPreviewDialog", &create<PrintColorsPreviewDialog, FloatingBehavior>); registerFactory("SvgFontsDialog", &create<SvgFontsDialog, FloatingBehavior>); registerFactory("Swatches", &create<SwatchesPanel, FloatingBehavior>); + registerFactory("TileDialog", &create<ArrangeDialog, FloatingBehavior>); registerFactory("Symbols", &create<SymbolsDialog, FloatingBehavior>); - registerFactory("TileDialog", &create<TileDialog, FloatingBehavior>); registerFactory("Trace", &create<TraceDialog, FloatingBehavior>); registerFactory("PixelArt", &create<PixelArtDialog, FloatingBehavior>); registerFactory("Transformation", &create<Transformation, FloatingBehavior>); @@ -156,8 +156,8 @@ DialogManager::DialogManager() { // registerFactory("PrintColorsPreviewDialog", &create<PrintColorsPreviewDialog, DockBehavior>); registerFactory("SvgFontsDialog", &create<SvgFontsDialog, DockBehavior>); registerFactory("Swatches", &create<SwatchesPanel, DockBehavior>); + registerFactory("TileDialog", &create<ArrangeDialog, DockBehavior>); registerFactory("Symbols", &create<SymbolsDialog, DockBehavior>); - registerFactory("TileDialog", &create<TileDialog, DockBehavior>); registerFactory("Trace", &create<TraceDialog, DockBehavior>); registerFactory("PixelArt", &create<PixelArtDialog, DockBehavior>); registerFactory("Transformation", &create<Transformation, DockBehavior>); diff --git a/src/ui/dialog/grid-arrange-tab.cpp b/src/ui/dialog/grid-arrange-tab.cpp new file mode 100644 index 000000000..8c0a4dc66 --- /dev/null +++ b/src/ui/dialog/grid-arrange-tab.cpp @@ -0,0 +1,809 @@ +/* + * A simple dialog for creating grid type arrangements of selected objects + * + * Authors: + * Bob Jamison ( based off trace dialog) + * John Cliff + * Other dudes from The Inkscape Organization + * Abhishek Sharma + * Declara Denis + * + * Copyright (C) 2004 Bob Jamison + * Copyright (C) 2004 John Cliff + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ +//#define DEBUG_GRID_ARRANGE 1 + +#include "ui/dialog/grid-arrange-tab.h" +#include <gtk/gtk.h> //for GTK_RESPONSE* types +#include <glibmm/i18n.h> +#include <gtkmm/stock.h> + +#if WITH_GTKMM_3_0 +# include <gtkmm/grid.h> +#else +# include <gtkmm/table.h> +#endif + +#include <2geom/transforms.h> + +#include "verbs.h" +#include "preferences.h" +#include "inkscape.h" +#include "desktop-handles.h" +#include "selection.h" +#include "document.h" +#include "document-undo.h" +#include "sp-item.h" +#include "widgets/icon.h" +#include "desktop.h" +//#include "sp-item-transform.h" FIXME +#include "ui/dialog/tile.h" // for Inkscape::UI::Dialog::ArrangeDialog + +/* + * Sort items by their x co-ordinates, taking account of y (keeps rows intact) + * + * <0 *elem1 goes before *elem2 + * 0 *elem1 == *elem2 + * >0 *elem1 goes after *elem2 + */ +static int sp_compare_x_position(SPItem *first, SPItem *second) +{ + using Geom::X; + using Geom::Y; + + Geom::OptRect a = first->documentVisualBounds(); + Geom::OptRect b = second->documentVisualBounds(); + + if ( !a || !b ) { + // FIXME? + return 0; + } + + double const a_height = a->dimensions()[Y]; + double const b_height = b->dimensions()[Y]; + + bool a_in_b_vert = false; + if ((a->min()[Y] < b->min()[Y] + 0.1) && (a->min()[Y] > b->min()[Y] - b_height)) { + a_in_b_vert = true; + } else if ((b->min()[Y] < a->min()[Y] + 0.1) && (b->min()[Y] > a->min()[Y] - a_height)) { + a_in_b_vert = true; + } else if (b->min()[Y] == a->min()[Y]) { + a_in_b_vert = true; + } else { + a_in_b_vert = false; + } + + if (!a_in_b_vert) { + return -1; + } + if (a_in_b_vert && a->min()[X] > b->min()[X]) { + return 1; + } + if (a_in_b_vert && a->min()[X] < b->min()[X]) { + return -1; + } + return 0; +} + +/* + * Sort items by their y co-ordinates. + */ +static int sp_compare_y_position(SPItem *first, SPItem *second) +{ + Geom::OptRect a = first->documentVisualBounds(); + Geom::OptRect b = second->documentVisualBounds(); + + if ( !a || !b ) { + // FIXME? + return 0; + } + + if (a->min()[Geom::Y] > b->min()[Geom::Y]) { + return 1; + } + if (a->min()[Geom::Y] < b->min()[Geom::Y]) { + return -1; + } + + return 0; +} + +namespace Inkscape { +namespace UI { +namespace Dialog { + + +//######################################################################### +//## E V E N T S +//######################################################################### + +/* + * + * This arranges the selection in a grid pattern. + * + */ + +void GridArrangeTab::arrange() +{ + + int cnt,row_cnt,col_cnt,a,row,col; + double grid_left,grid_top,col_width,row_height,paddingx,paddingy,width, height, new_x, new_y; + double total_col_width,total_row_height; + col_width = 0; + row_height = 0; + total_col_width=0; + total_row_height=0; + + // check for correct numbers in the row- and col-spinners + on_col_spinbutton_changed(); + on_row_spinbutton_changed(); + + // set padding to manual values + paddingx = XPadding.getValue("px"); + paddingy = YPadding.getValue("px"); + + std::vector<double> row_heights; + std::vector<double> col_widths; + std::vector<double> row_ys; + std::vector<double> col_xs; + + int NoOfCols = NoOfColsSpinner.get_value_as_int(); + int NoOfRows = NoOfRowsSpinner.get_value_as_int(); + + width = 0; + for (a=0;a<NoOfCols; a++){ + col_widths.push_back(width); + } + + height = 0; + for (a=0;a<NoOfRows; a++){ + row_heights.push_back(height); + } + grid_left = 99999; + grid_top = 99999; + + SPDesktop *desktop = Parent->getDesktop(); + sp_desktop_document(desktop)->ensureUpToDate(); + + Inkscape::Selection *selection = sp_desktop_selection (desktop); + const GSList *items = selection ? selection->itemList() : 0; + cnt=0; + for (; items != NULL; items = items->next) { + SPItem *item = SP_ITEM(items->data); + Geom::OptRect b = item->documentVisualBounds(); + if (!b) { + continue; + } + + width = b->dimensions()[Geom::X]; + height = b->dimensions()[Geom::Y]; + + if (b->min()[Geom::X] < grid_left) { + grid_left = b->min()[Geom::X]; + } + if (b->min()[Geom::Y] < grid_top) { + grid_top = b->min()[Geom::Y]; + } + if (width > col_width) { + col_width = width; + } + if (height > row_height) { + row_height = height; + } + } + + + // require the sorting done before we can calculate row heights etc. + + g_return_if_fail(selection); + const GSList *items2 = selection->itemList(); + GSList *rev = g_slist_copy(const_cast<GSList *>(items2)); + GSList *sorted = NULL; + rev = g_slist_sort(rev, (GCompareFunc) sp_compare_y_position); + sorted = g_slist_sort(rev, (GCompareFunc) sp_compare_x_position); + + + // Calculate individual Row and Column sizes if necessary + + + cnt=0; + const GSList *sizes = sorted; + for (; sizes != NULL; sizes = sizes->next) { + SPItem *item = SP_ITEM(sizes->data); + Geom::OptRect b = item->documentVisualBounds(); + if (b) { + width = b->dimensions()[Geom::X]; + height = b->dimensions()[Geom::Y]; + if (width > col_widths[(cnt % NoOfCols)]) { + col_widths[(cnt % NoOfCols)] = width; + } + if (height > row_heights[(cnt / NoOfCols)]) { + row_heights[(cnt / NoOfCols)] = height; + } + } + + cnt++; + } + + + /// Make sure the top and left of the grid dont move by compensating for align values. + if (RowHeightButton.get_active()){ + grid_top = grid_top - (((row_height - row_heights[0]) / 2)*(VertAlign)); + } + if (ColumnWidthButton.get_active()){ + grid_left = grid_left - (((col_width - col_widths[0]) /2)*(HorizAlign)); + } + + #ifdef DEBUG_GRID_ARRANGE + g_print("\n cx = %f cy= %f gridleft=%f",cx,cy,grid_left); + #endif + + // Calculate total widths and heights, allowing for columns and rows non uniformly sized. + + if (ColumnWidthButton.get_active()){ + total_col_width = col_width * NoOfCols; + col_widths.clear(); + for (a=0;a<NoOfCols; a++){ + col_widths.push_back(col_width); + } + } else { + for (a = 0; a < (int)col_widths.size(); a++) + { + total_col_width += col_widths[a] ; + } + } + + if (RowHeightButton.get_active()){ + total_row_height = row_height * NoOfRows; + row_heights.clear(); + for (a=0;a<NoOfRows; a++){ + row_heights.push_back(row_height); + } + } else { + for (a = 0; a < (int)row_heights.size(); a++) + { + total_row_height += row_heights[a] ; + } + } + + + Geom::OptRect sel_bbox = selection->visualBounds(); + // Fit to bbox, calculate padding between rows accordingly. + if ( sel_bbox && !SpaceManualRadioButton.get_active() ){ +#ifdef DEBUG_GRID_ARRANGE +g_print("\n row = %f col = %f selection x= %f selection y = %f", total_row_height,total_col_width, b.extent(Geom::X), b.extent(Geom::Y)); +#endif + paddingx = (sel_bbox->width() - total_col_width) / (NoOfCols -1); + paddingy = (sel_bbox->height() - total_row_height) / (NoOfRows -1); + } + +/* + Horizontal align - Left = 0 + Centre = 1 + Right = 2 + + Vertical align - Top = 0 + Middle = 1 + Bottom = 2 + + X position is calculated by taking the grids left co-ord, adding the distance to the column, + then adding 1/2 the spacing multiplied by the align variable above, + Y position likewise, takes the top of the grid, adds the y to the current row then adds the padding in to align it. + +*/ + + // Calculate row and column x and y coords required to allow for columns and rows which are non uniformly sized. + + for (a=0;a<NoOfCols; a++){ + if (a<1) col_xs.push_back(0); + else col_xs.push_back(col_widths[a-1]+paddingx+col_xs[a-1]); + } + + + for (a=0;a<NoOfRows; a++){ + if (a<1) row_ys.push_back(0); + else row_ys.push_back(row_heights[a-1]+paddingy+row_ys[a-1]); + } + + cnt=0; + for (row_cnt=0; ((sorted != NULL) && (row_cnt<NoOfRows)); row_cnt++) { + + GSList *current_row = NULL; + for (col_cnt = 0; ((sorted != NULL) && (col_cnt<NoOfCols)); col_cnt++) { + current_row = g_slist_append (current_row, sorted->data); + sorted = sorted->next; + } + + for (; current_row != NULL; current_row = current_row->next) { + SPItem *item=SP_ITEM(current_row->data); + Inkscape::XML::Node *repr = item->getRepr(); + Geom::OptRect b = item->documentVisualBounds(); + Geom::Point min; + if (b) { + width = b->dimensions()[Geom::X]; + height = b->dimensions()[Geom::Y]; + min = b->min(); + } else { + width = height = 0; + min = Geom::Point(0, 0); + } + + row = cnt / NoOfCols; + col = cnt % NoOfCols; + + new_x = grid_left + (((col_widths[col] - width)/2)*HorizAlign) + col_xs[col]; + new_y = grid_top + (((row_heights[row] - height)/2)*VertAlign) + row_ys[row]; + + // signs are inverted between x and y due to y inversion + Geom::Point move = Geom::Point(new_x - min[Geom::X], min[Geom::Y] - new_y); + Geom::Affine const affine = Geom::Affine(Geom::Translate(move)); + item->set_i2d_affine(item->i2dt_affine() * affine); + item->doWriteTransform(repr, item->transform, NULL); + SP_OBJECT (current_row->data)->updateRepr(); + cnt +=1; + } + g_slist_free (current_row); + } + + DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_SELECTION_ARRANGE, + _("Arrange in a grid")); + +} + + +//######################################################################### +//## E V E N T S +//######################################################################### + +/** + * changed value in # of columns spinbox. + */ +void GridArrangeTab::on_row_spinbutton_changed() +{ + // quit if run by the attr_changed listener + if (updating) { + return; + } + + // in turn, prevent listener from responding + updating = true; + SPDesktop *desktop = Parent->getDesktop(); + + Inkscape::Selection *selection = desktop ? desktop->selection : 0; + g_return_if_fail( selection ); + + GSList const *items = selection->itemList(); + int selcount = g_slist_length((GSList *)items); + + double PerCol = ceil(selcount / NoOfColsSpinner.get_value()); + NoOfRowsSpinner.set_value(PerCol); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble("/dialogs/gridtiler/NoOfCols", NoOfColsSpinner.get_value()); + updating=false; +} + +/** + * changed value in # of rows spinbox. + */ +void GridArrangeTab::on_col_spinbutton_changed() +{ + // quit if run by the attr_changed listener + if (updating) { + return; + } + + // in turn, prevent listener from responding + updating = true; + SPDesktop *desktop = Parent->getDesktop(); + Inkscape::Selection *selection = desktop ? desktop->selection : 0; + g_return_if_fail(selection); + + GSList const *items = selection->itemList(); + int selcount = g_slist_length((GSList *)items); + + double PerRow = ceil(selcount / NoOfRowsSpinner.get_value()); + NoOfColsSpinner.set_value(PerRow); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble("/dialogs/gridtiler/NoOfCols", PerRow); + + updating=false; +} + +/** + * changed value in x padding spinbox. + */ +void GridArrangeTab::on_xpad_spinbutton_changed() +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble("/dialogs/gridtiler/XPad", XPadding.getValue("px")); + +} + +/** + * changed value in y padding spinbox. + */ +void GridArrangeTab::on_ypad_spinbutton_changed() +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble("/dialogs/gridtiler/YPad", YPadding.getValue("px")); +} + + +/** + * checked/unchecked autosize Rows button. + */ +void GridArrangeTab::on_RowSize_checkbutton_changed() +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + if (RowHeightButton.get_active()) { + prefs->setDouble("/dialogs/gridtiler/AutoRowSize", 20); + } else { + prefs->setDouble("/dialogs/gridtiler/AutoRowSize", -20); + } + RowHeightBox.set_sensitive ( !RowHeightButton.get_active()); +} + +/** + * checked/unchecked autosize Rows button. + */ +void GridArrangeTab::on_ColSize_checkbutton_changed() +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + if (ColumnWidthButton.get_active()) { + prefs->setDouble("/dialogs/gridtiler/AutoColSize", 20); + } else { + prefs->setDouble("/dialogs/gridtiler/AutoColSize", -20); + } + ColumnWidthBox.set_sensitive ( !ColumnWidthButton.get_active()); +} + +/** + * changed value in columns spinbox. + */ +void GridArrangeTab::on_rowSize_spinbutton_changed() +{ + // quit if run by the attr_changed listener + if (updating) { + return; + } + + // in turn, prevent listener from responding + updating = true; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble("/dialogs/gridtiler/RowHeight", RowHeightSpinner.get_value()); + updating=false; + +} + +/** + * changed value in rows spinbox. + */ +void GridArrangeTab::on_colSize_spinbutton_changed() +{ + // quit if run by the attr_changed listener + if (updating) { + return; + } + + // in turn, prevent listener from responding + updating = true; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble("/dialogs/gridtiler/ColWidth", ColumnWidthSpinner.get_value()); + updating=false; + +} + +/** + * changed Radio button in Spacing group. + */ +void GridArrangeTab::Spacing_button_changed() +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + if (SpaceManualRadioButton.get_active()) { + prefs->setDouble("/dialogs/gridtiler/SpacingType", 20); + } else { + prefs->setDouble("/dialogs/gridtiler/SpacingType", -20); + } + + XPadding.set_sensitive ( SpaceManualRadioButton.get_active()); + YPadding.set_sensitive ( SpaceManualRadioButton.get_active()); +} + +/** + * changed Anchor selection widget. + */ +void GridArrangeTab::Align_changed() +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + VertAlign = AlignmentSelector.getVerticalAlignment(); + prefs->setInt("/dialogs/gridtiler/VertAlign", VertAlign); + HorizAlign = AlignmentSelector.getHorizontalAlignment(); + prefs->setInt("/dialogs/gridtiler/HorizAlign", HorizAlign); +} + +/** + * Desktop selection changed + */ +void GridArrangeTab::updateSelection() +{ + // quit if run by the attr_changed listener + if (updating) { + return; + } + + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + // in turn, prevent listener from responding + updating = true; + SPDesktop *desktop = Parent->getDesktop(); + Inkscape::Selection *selection = desktop ? desktop->selection : 0; + GSList const *items = selection ? selection->itemList() : 0; + + if (items) { + int selcount = g_slist_length((GSList *)items); + + if (NoOfColsSpinner.get_value() > 1 && NoOfRowsSpinner.get_value() > 1){ + // Update the number of rows assuming number of columns wanted remains same. + double NoOfRows = ceil(selcount / NoOfColsSpinner.get_value()); + NoOfRowsSpinner.set_value(NoOfRows); + + // if the selection has less than the number set for one row, reduce it appropriately + if (selcount < NoOfColsSpinner.get_value()) { + double NoOfCols = ceil(selcount / NoOfRowsSpinner.get_value()); + NoOfColsSpinner.set_value(NoOfCols); + prefs->setInt("/dialogs/gridtiler/NoOfCols", NoOfCols); + } + } else { + double PerRow = ceil(sqrt(selcount)); + double PerCol = ceil(sqrt(selcount)); + NoOfRowsSpinner.set_value(PerRow); + NoOfColsSpinner.set_value(PerCol); + prefs->setInt("/dialogs/gridtiler/NoOfCols", static_cast<int>(PerCol)); + } + } + + updating = false; +} + + + +/*########################## +## Experimental +##########################*/ + +static void updateSelectionCallback(Inkscape::Application */*inkscape*/, Inkscape::Selection */*selection*/, GridArrangeTab *dlg) +{ + dlg->updateSelection(); +} + + +//######################################################################### +//## C O N S T R U C T O R / D E S T R U C T O R +//######################################################################### +/** + * Constructor + */ +GridArrangeTab::GridArrangeTab(ArrangeDialog *parent) + : Parent(parent), + XPadding(_("X:"), _("Horizontal spacing between columns."), UNIT_TYPE_LINEAR, "", "object-columns", &PaddingUnitMenu), + YPadding(_("Y:"), _("Vertical spacing between rows."), XPadding, "", "object-rows", &PaddingUnitMenu), +#if WITH_GTKMM_3_0 + PaddingTable(Gtk::manage(new Gtk::Grid())) +#else + PaddingTable(Gtk::manage(new Gtk::Table(2, 2, false))) +#endif +{ + // bool used by spin button callbacks to stop loops where they change each other. + updating = false; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + + // could not do this in gtkmm - there's no Gtk::SizeGroup public constructor (!) + GtkSizeGroup *_col1 = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); + GtkSizeGroup *_col2 = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); + GtkSizeGroup *_col3 = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); + + { + // Selection Change signal + g_signal_connect ( G_OBJECT (INKSCAPE), "change_selection", G_CALLBACK (updateSelectionCallback), this); + } + + Gtk::Box *contents = this; + +#define MARGIN 2 + + //##Set up the panel + + SPDesktop *desktop = Parent->getDesktop(); + + Inkscape::Selection *selection = desktop ? desktop->selection : 0; + g_return_if_fail( selection ); + int selcount = 1; + if (!selection->isEmpty()) { + GSList const *items = selection->itemList(); + selcount = g_slist_length((GSList *)items); + } + + + /*#### Number of Rows ####*/ + + double PerRow = ceil(sqrt(selcount)); + double PerCol = ceil(sqrt(selcount)); + + #ifdef DEBUG_GRID_ARRANGE + g_print("/n PerRox = %f PerCol = %f selcount = %d",PerRow,PerCol,selcount); + #endif + + NoOfRowsLabel.set_text_with_mnemonic(_("_Rows:")); + NoOfRowsLabel.set_mnemonic_widget(NoOfRowsSpinner); + NoOfRowsBox.pack_start(NoOfRowsLabel, false, false, MARGIN); + + NoOfRowsSpinner.set_digits(0); + NoOfRowsSpinner.set_increments(1, 0); + NoOfRowsSpinner.set_range(1.0, 10000.0); + NoOfRowsSpinner.set_value(PerCol); + NoOfRowsSpinner.signal_changed().connect(sigc::mem_fun(*this, &GridArrangeTab::on_col_spinbutton_changed)); + NoOfRowsSpinner.set_tooltip_text(_("Number of rows")); + NoOfRowsBox.pack_start(NoOfRowsSpinner, false, false, MARGIN); + gtk_size_group_add_widget(_col1, (GtkWidget *) NoOfRowsBox.gobj()); + + RowHeightButton.set_label(_("Equal _height")); + RowHeightButton.set_use_underline(true); + double AutoRow = prefs->getDouble("/dialogs/gridtiler/AutoRowSize", 15); + if (AutoRow>0) + AutoRowSize=true; + else + AutoRowSize=false; + RowHeightButton.set_active(AutoRowSize); + + NoOfRowsBox.pack_start(RowHeightButton, false, false, MARGIN); + + RowHeightButton.set_tooltip_text(_("If not set, each row has the height of the tallest object in it")); + RowHeightButton.signal_toggled().connect(sigc::mem_fun(*this, &GridArrangeTab::on_RowSize_checkbutton_changed)); + + SpinsHBox.pack_start(NoOfRowsBox, false, false, MARGIN); + + + /*#### Label for X ####*/ + padXByYLabel.set_label(" "); + XByYLabelVBox.pack_start(padXByYLabel, false, false, MARGIN); + XByYLabel.set_markup(" × "); + XByYLabelVBox.pack_start(XByYLabel, false, false, MARGIN); + SpinsHBox.pack_start(XByYLabelVBox, false, false, MARGIN); + gtk_size_group_add_widget(_col2, GTK_WIDGET(XByYLabelVBox.gobj())); + + /*#### Number of columns ####*/ + + NoOfColsLabel.set_text_with_mnemonic(_("_Columns:")); + NoOfColsLabel.set_mnemonic_widget(NoOfColsSpinner); + NoOfColsBox.pack_start(NoOfColsLabel, false, false, MARGIN); + + NoOfColsSpinner.set_digits(0); + NoOfColsSpinner.set_increments(1, 0); + NoOfColsSpinner.set_range(1.0, 10000.0); + NoOfColsSpinner.set_value(PerRow); + NoOfColsSpinner.signal_changed().connect(sigc::mem_fun(*this, &GridArrangeTab::on_row_spinbutton_changed)); + NoOfColsSpinner.set_tooltip_text(_("Number of columns")); + NoOfColsBox.pack_start(NoOfColsSpinner, false, false, MARGIN); + gtk_size_group_add_widget(_col3, GTK_WIDGET(NoOfColsBox.gobj())); + + ColumnWidthButton.set_label(_("Equal _width")); + ColumnWidthButton.set_use_underline(true); + double AutoCol = prefs->getDouble("/dialogs/gridtiler/AutoColSize", 15); + if (AutoCol>0) + AutoColSize=true; + else + AutoColSize=false; + ColumnWidthButton.set_active(AutoColSize); + NoOfColsBox.pack_start(ColumnWidthButton, false, false, MARGIN); + + ColumnWidthButton.set_tooltip_text(_("If not set, each column has the width of the widest object in it")); + ColumnWidthButton.signal_toggled().connect(sigc::mem_fun(*this, &GridArrangeTab::on_ColSize_checkbutton_changed)); + + SpinsHBox.pack_start(NoOfColsBox, false, false, MARGIN); + + TileBox.pack_start(SpinsHBox, false, false, MARGIN); + + VertAlign = prefs->getInt("/dialogs/gridtiler/VertAlign", 1); + HorizAlign = prefs->getInt("/dialogs/gridtiler/HorizAlign", 1); + + // Anchor selection widget + AlignLabel.set_label("Alignment:"); + AlignLabel.set_alignment(Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + AlignmentSelector.setAlignment(HorizAlign, VertAlign); + AlignmentSelector.on_selectionChanged().connect(sigc::mem_fun(*this, &GridArrangeTab::Align_changed)); + TileBox.pack_start(AlignLabel, false, false, MARGIN); + TileBox.pack_start(AlignmentSelector, true, false, MARGIN); + + { + /*#### Radio buttons to control spacing manually or to fit selection bbox ####*/ + SpaceByBBoxRadioButton.set_label(_("_Fit into selection box")); + SpaceByBBoxRadioButton.set_use_underline (true); + SpaceByBBoxRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &GridArrangeTab::Spacing_button_changed)); + SpacingGroup = SpaceByBBoxRadioButton.get_group(); + + SpacingVBox.pack_start(SpaceByBBoxRadioButton, false, false, MARGIN); + + SpaceManualRadioButton.set_label(_("_Set spacing:")); + SpaceManualRadioButton.set_use_underline (true); + SpaceManualRadioButton.set_group(SpacingGroup); + SpaceManualRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &GridArrangeTab::Spacing_button_changed)); + SpacingVBox.pack_start(SpaceManualRadioButton, false, false, MARGIN); + + TileBox.pack_start(SpacingVBox, false, false, MARGIN); + } + + { + /*#### Padding ####*/ + PaddingUnitMenu.setUnitType(UNIT_TYPE_LINEAR); + PaddingUnitMenu.setUnit("px"); + + YPadding.setDigits(5); + YPadding.setIncrements(0.2, 0); + YPadding.setRange(-10000, 10000); + double yPad = prefs->getDouble("/dialogs/gridtiler/YPad", 15); + YPadding.setValue(yPad, "px"); + YPadding.signal_value_changed().connect(sigc::mem_fun(*this, &GridArrangeTab::on_ypad_spinbutton_changed)); + + XPadding.setDigits(5); + XPadding.setIncrements(0.2, 0); + XPadding.setRange(-10000, 10000); + double xPad = prefs->getDouble("/dialogs/gridtiler/XPad", 15); + XPadding.setValue(xPad, "px"); + + XPadding.signal_value_changed().connect(sigc::mem_fun(*this, &GridArrangeTab::on_xpad_spinbutton_changed)); + } + + PaddingTable->set_border_width(MARGIN); + +#if WITH_GTKMM_3_0 + PaddingTable->set_row_spacing(MARGIN); + PaddingTable->set_column_spacing(MARGIN); + PaddingTable->attach(XPadding, 0, 0, 1, 1); + PaddingTable->attach(PaddingUnitMenu, 1, 0, 1, 1); + PaddingTable->attach(YPadding, 0, 1, 1, 1); +#else + PaddingTable->set_row_spacings(MARGIN); + PaddingTable->set_col_spacings(MARGIN); + PaddingTable->attach(XPadding, 0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK); + PaddingTable->attach(PaddingUnitMenu, 1, 2, 0, 1, Gtk::SHRINK, Gtk::SHRINK); + PaddingTable->attach(YPadding, 0, 1, 1, 2, Gtk::SHRINK, Gtk::SHRINK); +#endif + + TileBox.pack_start(*PaddingTable, false, false, MARGIN); + + contents->pack_start(TileBox); + + double SpacingType = prefs->getDouble("/dialogs/gridtiler/SpacingType", 15); + if (SpacingType>0) { + ManualSpacing=true; + } else { + ManualSpacing=false; + } + SpaceManualRadioButton.set_active(ManualSpacing); + SpaceByBBoxRadioButton.set_active(!ManualSpacing); + XPadding.set_sensitive (ManualSpacing); + YPadding.set_sensitive (ManualSpacing); + + //## The OK button FIXME + /*TileOkButton = addResponseButton(C_("Rows and columns dialog","_Arrange"), GTK_RESPONSE_APPLY); + TileOkButton->set_use_underline(true); + TileOkButton->set_tooltip_text(_("Arrange selected objects"));*/ + + show_all_children(); +} + +} //namespace Dialog +} //namespace UI +} //namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/grid-arrange-tab.h b/src/ui/dialog/grid-arrange-tab.h new file mode 100644 index 000000000..9d6700b39 --- /dev/null +++ b/src/ui/dialog/grid-arrange-tab.h @@ -0,0 +1,154 @@ +/** + * @brief Arranges Objects into a Grid + */ +/* Authors: + * Bob Jamison ( based off trace dialog) + * John Cliff + * Other dudes from The Inkscape Organization + * Abhishek Sharma + * Declara Denis + * + * Copyright (C) 2004 Bob Jamison + * Copyright (C) 2004 John Cliff + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef INKSCAPE_UI_DIALOG_GRID_ARRANGE_TAB_H +#define INKSCAPE_UI_DIALOG_GRID_ARRANGE_TAB_H + +#include <gtkmm.h> + +#include "ui/dialog/arrange-tab.h" + +#include "ui/widget/anchor-selector.h" +#include "ui/widget/scalar-unit.h" +#include "ui/widget/spinbutton.h" + +namespace Inkscape { +namespace UI { +namespace Dialog { + +class ArrangeDialog; + +/** + * Dialog for tiling an object + */ +class GridArrangeTab : public ArrangeTab { +public: + GridArrangeTab(ArrangeDialog *parent); + virtual ~GridArrangeTab() {}; + + /** + * Do the actual work + */ + virtual void arrange(); + + /** + * Respond to selection change + */ + void updateSelection(); + + // Callbacks from spinbuttons + void on_row_spinbutton_changed(); + void on_col_spinbutton_changed(); + void on_xpad_spinbutton_changed(); + void on_ypad_spinbutton_changed(); + void on_RowSize_checkbutton_changed(); + void on_ColSize_checkbutton_changed(); + void on_rowSize_spinbutton_changed(); + void on_colSize_spinbutton_changed(); + void Spacing_button_changed(); + void Align_changed(); + + +private: + GridArrangeTab(GridArrangeTab const &d); // no copy + void operator=(GridArrangeTab const &d); // no assign + + ArrangeDialog *Parent; + + bool userHidden; + bool updating; + + Gtk::VBox TileBox; + Gtk::Button *TileOkButton; + Gtk::Button *TileCancelButton; + + // Number selected label + Gtk::Label SelectionContentsLabel; + + + Gtk::HBox AlignHBox; + Gtk::HBox SpinsHBox; + + // Number per Row + Gtk::VBox NoOfColsBox; + Gtk::Label NoOfColsLabel; + Inkscape::UI::Widget::SpinButton NoOfColsSpinner; + bool AutoRowSize; + Gtk::CheckButton RowHeightButton; + + Gtk::VBox XByYLabelVBox; + Gtk::Label padXByYLabel; + Gtk::Label XByYLabel; + + // Number per Column + Gtk::VBox NoOfRowsBox; + Gtk::Label NoOfRowsLabel; + Inkscape::UI::Widget::SpinButton NoOfRowsSpinner; + bool AutoColSize; + Gtk::CheckButton ColumnWidthButton; + + // Alignment + Gtk::Label AlignLabel; + Inkscape::UI::Widget::AnchorSelector AlignmentSelector; + double VertAlign; + double HorizAlign; + + Inkscape::UI::Widget::UnitMenu PaddingUnitMenu; + Inkscape::UI::Widget::ScalarUnit XPadding; + Inkscape::UI::Widget::ScalarUnit YPadding; + +#if WITH_GTKMM_3_0 + Gtk::Grid *PaddingTable; +#else + Gtk::Table *PaddingTable; +#endif + + // BBox or manual spacing + Gtk::VBox SpacingVBox; + Gtk::RadioButtonGroup SpacingGroup; + Gtk::RadioButton SpaceByBBoxRadioButton; + Gtk::RadioButton SpaceManualRadioButton; + bool ManualSpacing; + + // Row height + Gtk::VBox RowHeightVBox; + Gtk::HBox RowHeightBox; + Gtk::Label RowHeightLabel; + Inkscape::UI::Widget::SpinButton RowHeightSpinner; + + // Column width + Gtk::VBox ColumnWidthVBox; + Gtk::HBox ColumnWidthBox; + Gtk::Label ColumnWidthLabel; + Inkscape::UI::Widget::SpinButton ColumnWidthSpinner; +}; + +} //namespace Dialog +} //namespace UI +} //namespace Inkscape + +#endif /* INKSCAPE_UI_DIALOG_GRID_ARRANGE_TAB_H */ + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/polar-arrange-tab.cpp b/src/ui/dialog/polar-arrange-tab.cpp new file mode 100644 index 000000000..a00b8fc02 --- /dev/null +++ b/src/ui/dialog/polar-arrange-tab.cpp @@ -0,0 +1,414 @@ +/** + * @brief Arranges Objects into a Circle/Ellipse + */ +/* Authors: + * Declara Denis + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "ui/dialog/polar-arrange-tab.h" +#include "ui/dialog/tile.h" + +#include <2geom/transforms.h> +#include <glibmm/i18n.h> + +#include "verbs.h" +#include "preferences.h" +#include "inkscape.h" +#include "desktop-handles.h" +#include "selection.h" +#include "document.h" +#include "document-undo.h" +#include "sp-item.h" +#include "widgets/icon.h" +#include "desktop.h" +#include "sp-ellipse.h" +#include "sp-item-transform.h" + +namespace Inkscape { +namespace UI { +namespace Dialog { + +PolarArrangeTab::PolarArrangeTab(ArrangeDialog *parent_) + : parent(parent_), + parametersTable(3, 3, false), + centerY("", "Y coordinate of the center", UNIT_TYPE_LINEAR), + centerX("", "X coordinate of the center", centerY), + radiusY("", "Y coordinate of the radius", UNIT_TYPE_LINEAR), + radiusX("", "X coordinate of the radius", radiusY), + angleY("", "Starting angle", UNIT_TYPE_RADIAL), + angleX("", "End angle", angleY) +{ + anchorPointLabel.set_text(C_("Polar arrange tab", "Anchor point:")); + anchorPointLabel.set_alignment(Gtk::ALIGN_START); + pack_start(anchorPointLabel, false, false); + + anchorBoundingBoxRadio.set_label(C_("Polar arrange tab", "Object's bounding box:")); + anchorRadioGroup = anchorBoundingBoxRadio.get_group(); + anchorBoundingBoxRadio.signal_toggled().connect(sigc::mem_fun(*this, &PolarArrangeTab::on_anchor_radio_changed)); + pack_start(anchorBoundingBoxRadio, false, false); + + pack_start(anchorSelector, false, false); + + anchorObjectPivotRadio.set_label(C_("Polar arrange tab", "Object's rotational center")); + anchorObjectPivotRadio.set_group(anchorRadioGroup); + anchorObjectPivotRadio.signal_toggled().connect(sigc::mem_fun(*this, &PolarArrangeTab::on_anchor_radio_changed)); + pack_start(anchorObjectPivotRadio, false, false); + + arrangeOnLabel.set_text(C_("Polar arrange tab", "Arrange on:")); + arrangeOnLabel.set_alignment(Gtk::ALIGN_START); + pack_start(arrangeOnLabel, false, false); + + arrangeOnFirstCircleRadio.set_label(C_("Polar arrange tab", "First selected circle/ellipse/arc")); + arrangeRadioGroup = arrangeOnFirstCircleRadio.get_group(); + arrangeOnFirstCircleRadio.signal_toggled().connect(sigc::mem_fun(*this, &PolarArrangeTab::on_arrange_radio_changed)); + pack_start(arrangeOnFirstCircleRadio, false, false); + + arrangeOnLastCircleRadio.set_label(C_("Polar arrange tab", "Last selected circle/ellipse/arc")); + arrangeOnLastCircleRadio.set_group(arrangeRadioGroup); + arrangeOnLastCircleRadio.signal_toggled().connect(sigc::mem_fun(*this, &PolarArrangeTab::on_arrange_radio_changed)); + pack_start(arrangeOnLastCircleRadio, false, false); + + arrangeOnParametersRadio.set_label(C_("Polar arrange tab", "Parameterized:")); + arrangeOnParametersRadio.set_group(arrangeRadioGroup); + arrangeOnParametersRadio.signal_toggled().connect(sigc::mem_fun(*this, &PolarArrangeTab::on_arrange_radio_changed)); + pack_start(arrangeOnParametersRadio, false, false); + + centerLabel.set_text(_("Center X/Y:")); + parametersTable.attach(centerLabel, 0, 1, 0, 1, Gtk::FILL); + centerX.setDigits(2); + centerX.setIncrements(0.2, 0); + centerX.setRange(-10000, 10000); + centerX.setValue(0, "px"); + centerY.setDigits(2); + centerY.setIncrements(0.2, 0); + centerY.setRange(-10000, 10000); + centerY.setValue(0, "px"); + parametersTable.attach(centerX, 1, 2, 0, 1, Gtk::FILL); + parametersTable.attach(centerY, 2, 3, 0, 1, Gtk::FILL); + + radiusLabel.set_text(_("Radius X/Y:")); + parametersTable.attach(radiusLabel, 0, 1, 1, 2, Gtk::FILL); + radiusX.setDigits(2); + radiusX.setIncrements(0.2, 0); + radiusX.setRange(0.001, 10000); + radiusX.setValue(100, "px"); + radiusY.setDigits(2); + radiusY.setIncrements(0.2, 0); + radiusY.setRange(0.001, 10000); + radiusY.setValue(100, "px"); + parametersTable.attach(radiusX, 1, 2, 1, 2, Gtk::FILL); + parametersTable.attach(radiusY, 2, 3, 1, 2, Gtk::FILL); + + angleLabel.set_text(_("Angle X/Y:")); + parametersTable.attach(angleLabel, 0, 1, 2, 3, Gtk::FILL); + angleX.setDigits(2); + angleX.setIncrements(0.2, 0); + angleX.setRange(-10000, 10000); + angleX.setValue(0, "°"); + angleY.setDigits(2); + angleY.setIncrements(0.2, 0); + angleY.setRange(-10000, 10000); + angleY.setValue(180, "°"); + parametersTable.attach(angleX, 1, 2, 2, 3, Gtk::FILL); + parametersTable.attach(angleY, 2, 3, 2, 3, Gtk::FILL); + pack_start(parametersTable, false, false); + + rotateObjectsCheckBox.set_label(_("Rotate objects")); + rotateObjectsCheckBox.set_active(true); + pack_start(rotateObjectsCheckBox, false, false); + + centerX.set_sensitive(false); + centerY.set_sensitive(false); + angleX.set_sensitive(false); + angleY.set_sensitive(false); + radiusX.set_sensitive(false); + radiusY.set_sensitive(false); +} + +/** + * This function rotates an item around a given point by a given amount + * @param item item to rotate + * @param center center of the rotation to perform + * @param rotation amount to rotate the object by + */ +static void rotateAround(SPItem *item, Geom::Point center, Geom::Rotate const &rotation) +{ + Geom::Translate const s(center); + Geom::Affine affine = Geom::Affine(s).inverse() * Geom::Affine(rotation) * Geom::Affine(s); + + // Save old center + center = item->getCenter(); + + item->set_i2d_affine(item->i2dt_affine() * affine); + item->doWriteTransform(item->getRepr(), item->transform); + + if(item->isCenterSet()) + { + item->setCenter(center * affine); + item->updateRepr(); + } +} + +/** + * Calculates the angle at which to put an object given the total amount + * of objects, the index of the objects as well as the arc start and end + * points + * @param arcBegin angle at which the arc begins + * @param arcEnd angle at which the arc ends + * @param count number of objects in the selection + * @param n index of the object in the selection + */ +static float calcAngle(float arcBegin, float arcEnd, int count, int n) +{ + float arcLength = arcEnd - arcBegin; + float delta = std::abs(std::abs(arcLength) - 2*M_PI); + if(delta > 0.01) count--; // If not a complete circle, put an object also at the extremes of the arc; + + float angle = n / (float)count; + // Normalize for arcLength: + angle = angle * arcLength; + angle += arcBegin; + + return angle; +} + +/** + * Calculates the point at which an object needs to be, given the center of the ellipse, + * it's radius (x and y), as well as the angle + */ +static Geom::Point calcPoint(float cx, float cy, float rx, float ry, float angle) +{ + return Geom::Point(cx + cos(angle) * rx, cy + sin(angle) * ry); +} + +/** + * Returns the selected anchor point in document coordinates. If anchor + * is 0 to 8, then a bounding box point has been choosen. If it is 9 however + * the rotational center is chosen. + * @todo still using a hack to get the real coordinate space (subtracting document height + * and inverting axes) + */ +static Geom::Point getAnchorPoint(int anchor, SPItem *item) +{ + Geom::Point source; + + Geom::OptRect bbox = item->documentVisualBounds(); + + switch(anchor) + { + case 0: // Top - Left + case 3: // Middle - Left + case 6: // Bottom - Left + source[0] = bbox->min()[Geom::X]; + break; + case 1: // Top - Middle + case 4: // Middle - Middle + case 7: // Bottom - Middle + source[0] = (bbox->min()[Geom::X] + bbox->max()[Geom::X]) / 2.0f; + break; + case 2: // Top - Right + case 5: // Middle - Right + case 8: // Bottom - Right + source[0] = bbox->max()[Geom::X]; + break; + }; + + switch(anchor) + { + case 0: // Top - Left + case 1: // Top - Middle + case 2: // Top - Right + source[1] = bbox->min()[Geom::Y]; + break; + case 3: // Middle - Left + case 4: // Middle - Middle + case 5: // Middle - Right + source[1] = (bbox->min()[Geom::Y] + bbox->max()[Geom::Y]) / 2.0f; + break; + case 6: // Bottom - Left + case 7: // Bottom - Middle + case 8: // Bottom - Right + source[1] = bbox->max()[Geom::Y]; + break; + }; + + // If using center + if(anchor == 9) + source = item->getCenter(); + else + { + // FIXME: + source[1] -= item->document->getHeight().value("px"); + source[1] *= -1; + } + + return source; +} + +/** + * Moves an SPItem to a given location, the location is based on the given anchor point. + * @param anchor 0 to 8 are the various bounding box points like follows: + * 0 1 2 + * 3 4 5 + * 6 7 8 + * Anchor mode 9 is the rotational center of the object + * @param item Item to move + * @param p point at which to move the object + */ +static void moveToPoint(int anchor, SPItem *item, Geom::Point p) +{ + sp_item_move_rel(item, Geom::Translate(p - getAnchorPoint(anchor, item))); +} + +void PolarArrangeTab::arrange() +{ + Inkscape::Selection *selection = sp_desktop_selection(parent->getDesktop()); + const GSList *items, *tmp; + tmp = items = selection->itemList(); + SPGenericEllipse *referenceEllipse = NULL; // Last ellipse in selection + + bool arrangeOnEllipse = !arrangeOnParametersRadio.get_active(); + bool arrangeOnFirstEllipse = arrangeOnEllipse && arrangeOnFirstCircleRadio.get_active(); + + int count = 0; + while(tmp) + { + if(arrangeOnEllipse) + { + SPItem *item = SP_ITEM(tmp->data); + + if(arrangeOnFirstEllipse) + { + // The first selected ellipse is actually the last one in the list + if(SP_IS_GENERICELLIPSE(item)) + referenceEllipse = SP_GENERICELLIPSE(item); + } else { + // The last selected ellipse is actually the first in list + if(SP_IS_GENERICELLIPSE(item) && referenceEllipse == NULL) + referenceEllipse = SP_GENERICELLIPSE(item); + } + } + tmp = tmp->next; + ++count; + } + + float cx, cy; // Center of the ellipse + float rx, ry; // Radiuses of the ellipse in x and y direction + float arcBeg, arcEnd; // begin and end angles for arcs + Geom::Affine transformation; // Any additional transformation to apply to the objects + + if(arrangeOnEllipse) + { + if(referenceEllipse == NULL) + { + Gtk::MessageDialog dialog(_("Couldn't find an ellipse in selection"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true); + dialog.run(); + return; + } else { + cx = referenceEllipse->cx.value; + cy = referenceEllipse->cy.value; + rx = referenceEllipse->rx.value; + ry = referenceEllipse->ry.value; + arcBeg = referenceEllipse->start; + arcEnd = referenceEllipse->end; + + transformation = referenceEllipse->i2dt_affine(); + + // We decrement the count by 1 as we are not going to lay + // out the reference ellipse + --count; + } + + } else { + // Read options from UI + cx = centerX.getValue("px"); + cy = centerY.getValue("px"); + rx = radiusX.getValue("px"); + ry = radiusY.getValue("px"); + arcBeg = angleX.getValue("rad"); + arcEnd = angleY.getValue("rad"); + transformation.setIdentity(); + referenceEllipse = NULL; + } + + int anchor = 9; + if(anchorBoundingBoxRadio.get_active()) + { + anchor = anchorSelector.getHorizontalAlignment() + + anchorSelector.getVerticalAlignment() * 3; + } + + Geom::Point realCenter = Geom::Point(cx, cy) * transformation; + + tmp = items; + int i = 0; + while(tmp) + { + SPItem *item = SP_ITEM(tmp->data); + + // Ignore the reference ellipse if any + if(item != referenceEllipse) + { + float angle = calcAngle(arcBeg, arcEnd, count, i); + Geom::Point newLocation = calcPoint(cx, cy, rx, ry, angle) * transformation; + + moveToPoint(anchor, item, newLocation); + + if(rotateObjectsCheckBox.get_active()) { + // Calculate the angle by which to rotate each object + angle = -atan2f(newLocation.x() - realCenter.x(), newLocation.y() - realCenter.y()); + rotateAround(item, newLocation, Geom::Rotate(angle)); + } + + ++i; + } + tmp = tmp->next; + } + + DocumentUndo::done(sp_desktop_document(parent->getDesktop()), SP_VERB_SELECTION_ARRANGE, + _("Arrange on ellipse")); +} + +void PolarArrangeTab::updateSelection() +{ +} + +void PolarArrangeTab::on_arrange_radio_changed() +{ + bool arrangeParametric = arrangeOnParametersRadio.get_active(); + + centerX.set_sensitive(arrangeParametric); + centerY.set_sensitive(arrangeParametric); + + angleX.set_sensitive(arrangeParametric); + angleY.set_sensitive(arrangeParametric); + + radiusX.set_sensitive(arrangeParametric); + radiusY.set_sensitive(arrangeParametric); + + parametersTable.set_visible(arrangeParametric); +} + +void PolarArrangeTab::on_anchor_radio_changed() +{ + bool anchorBoundingBox = anchorBoundingBoxRadio.get_active(); + + anchorSelector.set_sensitive(anchorBoundingBox); +} + +} //namespace Dialog +} //namespace UI +} //namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/polar-arrange-tab.h b/src/ui/dialog/polar-arrange-tab.h new file mode 100644 index 000000000..bfed40bbd --- /dev/null +++ b/src/ui/dialog/polar-arrange-tab.h @@ -0,0 +1,100 @@ +/** + * @brief Arranges Objects into a Circle/Ellipse + */ +/* Authors: + * Declara Denis + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef INKSCAPE_UI_DIALOG_POLAR_ARRANGE_TAB_H +#define INKSCAPE_UI_DIALOG_POLAR_ARRANGE_TAB_H + +#include "ui/dialog/arrange-tab.h" + +#include "ui/widget/anchor-selector.h" +#include "ui/widget/scalar-unit.h" + +namespace Inkscape { +namespace UI { +namespace Dialog { + +class ArrangeDialog; + +/** + * PolarArrangeTab is a Tab displayed in the Arrange dialog and contains + * enables the user to arrange objects on a circular or elliptical shape + */ +class PolarArrangeTab : public ArrangeTab { +public: + PolarArrangeTab(ArrangeDialog *parent_); + virtual ~PolarArrangeTab() {}; + + /** + * Do the actual arrangement + */ + virtual void arrange(); + + /** + * Respond to selection change + */ + void updateSelection(); + + void on_anchor_radio_changed(); + void on_arrange_radio_changed(); + +private: + PolarArrangeTab(PolarArrangeTab const &d); // no copy + void operator=(PolarArrangeTab const &d); // no assign + + ArrangeDialog *parent; + + Gtk::Label anchorPointLabel; + + Gtk::RadioButtonGroup anchorRadioGroup; + Gtk::RadioButton anchorBoundingBoxRadio; + Gtk::RadioButton anchorObjectPivotRadio; + Inkscape::UI::Widget::AnchorSelector anchorSelector; + + Gtk::Label arrangeOnLabel; + + Gtk::RadioButtonGroup arrangeRadioGroup; + Gtk::RadioButton arrangeOnFirstCircleRadio; + Gtk::RadioButton arrangeOnLastCircleRadio; + Gtk::RadioButton arrangeOnParametersRadio; + + Gtk::Table parametersTable; + + Gtk::Label centerLabel; + Inkscape::UI::Widget::ScalarUnit centerY; + Inkscape::UI::Widget::ScalarUnit centerX; + + Gtk::Label radiusLabel; + Inkscape::UI::Widget::ScalarUnit radiusY; + Inkscape::UI::Widget::ScalarUnit radiusX; + + Gtk::Label angleLabel; + Inkscape::UI::Widget::ScalarUnit angleY; + Inkscape::UI::Widget::ScalarUnit angleX; + + Gtk::CheckButton rotateObjectsCheckBox; + + +}; + +} //namespace Dialog +} //namespace UI +} //namespace Inkscape + +#endif /* INKSCAPE_UI_DIALOG_POLAR_ARRANGE_TAB_H */ + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/tile.cpp b/src/ui/dialog/tile.cpp index c35d3b554..a3cffb3d4 100644 --- a/src/ui/dialog/tile.cpp +++ b/src/ui/dialog/tile.cpp @@ -6,878 +6,62 @@ * John Cliff * Other dudes from The Inkscape Organization * Abhishek Sharma + * Declara Denis * * Copyright (C) 2004 Bob Jamison * Copyright (C) 2004 John Cliff * * Released under GNU GPL, read the file 'COPYING' for more information */ -//#define DEBUG_GRID_ARRANGE 1 -#include "tile.h" -#include <gtk/gtk.h> //for GTK_RESPONSE* types -#include <glibmm/i18n.h> -#include <gtkmm/stock.h> +#include "ui/dialog/grid-arrange-tab.h" +#include "ui/dialog/polar-arrange-tab.h" -#if WITH_GTKMM_3_0 -# include <gtkmm/grid.h> -#else -# include <gtkmm/table.h> -#endif - -#include <2geom/transforms.h> +#include <glibmm/i18n.h> +#include "tile.h" #include "verbs.h" -#include "preferences.h" -#include "inkscape.h" -#include "desktop-handles.h" -#include "selection.h" -#include "document.h" -#include "document-undo.h" -#include "sp-item.h" -#include "widgets/icon.h" -#include "desktop.h" - -/* - * Sort items by their x co-ordinates, taking account of y (keeps rows intact) - * - * <0 *elem1 goes before *elem2 - * 0 *elem1 == *elem2 - * >0 *elem1 goes after *elem2 - */ -static int sp_compare_x_position(SPItem *first, SPItem *second) -{ - using Geom::X; - using Geom::Y; - - Geom::OptRect a = first->documentVisualBounds(); - Geom::OptRect b = second->documentVisualBounds(); - - if ( !a || !b ) { - // FIXME? - return 0; - } - - double const a_height = a->dimensions()[Y]; - double const b_height = b->dimensions()[Y]; - - bool a_in_b_vert = false; - if ((a->min()[Y] < b->min()[Y] + 0.1) && (a->min()[Y] > b->min()[Y] - b_height)) { - a_in_b_vert = true; - } else if ((b->min()[Y] < a->min()[Y] + 0.1) && (b->min()[Y] > a->min()[Y] - a_height)) { - a_in_b_vert = true; - } else if (b->min()[Y] == a->min()[Y]) { - a_in_b_vert = true; - } else { - a_in_b_vert = false; - } - - if (!a_in_b_vert) { - return -1; - } - if (a_in_b_vert && a->min()[X] > b->min()[X]) { - return 1; - } - if (a_in_b_vert && a->min()[X] < b->min()[X]) { - return -1; - } - return 0; -} - -/* - * Sort items by their y co-ordinates. - */ -static int -sp_compare_y_position(SPItem *first, SPItem *second) -{ - Geom::OptRect a = first->documentVisualBounds(); - Geom::OptRect b = second->documentVisualBounds(); - - if ( !a || !b ) { - // FIXME? - return 0; - } - - if (a->min()[Geom::Y] > b->min()[Geom::Y]) { - return 1; - } - if (a->min()[Geom::Y] < b->min()[Geom::Y]) { - return -1; - } - - return 0; -} namespace Inkscape { namespace UI { namespace Dialog { - -//######################################################################### -//## E V E N T S -//######################################################################### - -/* - * - * This arranges the selection in a grid pattern. - * - */ - -void TileDialog::Grid_Arrange () +ArrangeDialog::ArrangeDialog() + : UI::Widget::Panel("", "/dialogs/gridtiler", SP_VERB_SELECTION_ARRANGE), + _gridArrangeTab(new GridArrangeTab(this)), + _polarArrangeTab(new PolarArrangeTab(this)) { + Gtk::Box *contents = this->_getContents(); - int cnt,row_cnt,col_cnt,a,row,col; - double grid_left,grid_top,col_width,row_height,paddingx,paddingy,width, height, new_x, new_y; - double total_col_width,total_row_height; - col_width = 0; - row_height = 0; - total_col_width=0; - total_row_height=0; - - // check for correct numbers in the row- and col-spinners - on_col_spinbutton_changed(); - on_row_spinbutton_changed(); - - // set padding to manual values - paddingx = XPadding.getValue("px"); - paddingy = YPadding.getValue("px"); - - std::vector<double> row_heights; - std::vector<double> col_widths; - std::vector<double> row_ys; - std::vector<double> col_xs; - - int NoOfCols = NoOfColsSpinner.get_value_as_int(); - int NoOfRows = NoOfRowsSpinner.get_value_as_int(); - - width = 0; - for (a=0;a<NoOfCols; a++){ - col_widths.push_back(width); - } - - height = 0; - for (a=0;a<NoOfRows; a++){ - row_heights.push_back(height); - } - grid_left = 99999; - grid_top = 99999; - - SPDesktop *desktop = getDesktop(); - sp_desktop_document(desktop)->ensureUpToDate(); - - Inkscape::Selection *selection = sp_desktop_selection (desktop); - const GSList *items = selection ? selection->itemList() : 0; - cnt=0; - for (; items != NULL; items = items->next) { - SPItem *item = SP_ITEM(items->data); - Geom::OptRect b = item->documentVisualBounds(); - if (!b) { - continue; - } - - width = b->dimensions()[Geom::X]; - height = b->dimensions()[Geom::Y]; - - if (b->min()[Geom::X] < grid_left) { - grid_left = b->min()[Geom::X]; - } - if (b->min()[Geom::Y] < grid_top) { - grid_top = b->min()[Geom::Y]; - } - if (width > col_width) { - col_width = width; - } - if (height > row_height) { - row_height = height; - } - } - - - // require the sorting done before we can calculate row heights etc. - - g_return_if_fail(selection); - const GSList *items2 = selection->itemList(); - GSList *rev = g_slist_copy(const_cast<GSList *>(items2)); - GSList *sorted = NULL; - rev = g_slist_sort(rev, (GCompareFunc) sp_compare_y_position); - sorted = g_slist_sort(rev, (GCompareFunc) sp_compare_x_position); - - - // Calculate individual Row and Column sizes if necessary - - - cnt=0; - const GSList *sizes = sorted; - for (; sizes != NULL; sizes = sizes->next) { - SPItem *item = SP_ITEM(sizes->data); - Geom::OptRect b = item->documentVisualBounds(); - if (b) { - width = b->dimensions()[Geom::X]; - height = b->dimensions()[Geom::Y]; - if (width > col_widths[(cnt % NoOfCols)]) { - col_widths[(cnt % NoOfCols)] = width; - } - if (height > row_heights[(cnt / NoOfCols)]) { - row_heights[(cnt / NoOfCols)] = height; - } - } - - cnt++; - } - - - /// Make sure the top and left of the grid dont move by compensating for align values. - if (RowHeightButton.get_active()){ - grid_top = grid_top - (((row_height - row_heights[0]) / 2)*(VertAlign)); - } - if (ColumnWidthButton.get_active()){ - grid_left = grid_left - (((col_width - col_widths[0]) /2)*(HorizAlign)); - } - - #ifdef DEBUG_GRID_ARRANGE - g_print("\n cx = %f cy= %f gridleft=%f",cx,cy,grid_left); - #endif - - // Calculate total widths and heights, allowing for columns and rows non uniformly sized. + _notebook.append_page(*_gridArrangeTab, C_("Arrange dialog", "Rectangular grid")); + _notebook.append_page(*_polarArrangeTab, C_("Arrange dialog", "Polar Coordinates")); + _arrangeBox.pack_start(_notebook); - if (ColumnWidthButton.get_active()){ - total_col_width = col_width * NoOfCols; - col_widths.clear(); - for (a=0;a<NoOfCols; a++){ - col_widths.push_back(col_width); - } - } else { - for (a = 0; a < (int)col_widths.size(); a++) - { - total_col_width += col_widths[a] ; - } - } - - if (RowHeightButton.get_active()){ - total_row_height = row_height * NoOfRows; - row_heights.clear(); - for (a=0;a<NoOfRows; a++){ - row_heights.push_back(row_height); - } - } else { - for (a = 0; a < (int)row_heights.size(); a++) - { - total_row_height += row_heights[a] ; - } - } - - - Geom::OptRect sel_bbox = selection->visualBounds(); - // Fit to bbox, calculate padding between rows accordingly. - if ( sel_bbox && !SpaceManualRadioButton.get_active() ){ -#ifdef DEBUG_GRID_ARRANGE -g_print("\n row = %f col = %f selection x= %f selection y = %f", total_row_height,total_col_width, b.extent(Geom::X), b.extent(Geom::Y)); -#endif - paddingx = (sel_bbox->width() - total_col_width) / (NoOfCols -1); - paddingy = (sel_bbox->height() - total_row_height) / (NoOfRows -1); - } - -/* - Horizontal align - Left = 0 - Centre = 1 - Right = 2 - - Vertical align - Top = 0 - Middle = 1 - Bottom = 2 - - X position is calculated by taking the grids left co-ord, adding the distance to the column, - then adding 1/2 the spacing multiplied by the align variable above, - Y position likewise, takes the top of the grid, adds the y to the current row then adds the padding in to align it. - -*/ - - // Calculate row and column x and y coords required to allow for columns and rows which are non uniformly sized. - - for (a=0;a<NoOfCols; a++){ - if (a<1) col_xs.push_back(0); - else col_xs.push_back(col_widths[a-1]+paddingx+col_xs[a-1]); - } - - - for (a=0;a<NoOfRows; a++){ - if (a<1) row_ys.push_back(0); - else row_ys.push_back(row_heights[a-1]+paddingy+row_ys[a-1]); - } - - cnt=0; - for (row_cnt=0; ((sorted != NULL) && (row_cnt<NoOfRows)); row_cnt++) { - - GSList *current_row = NULL; - for (col_cnt = 0; ((sorted != NULL) && (col_cnt<NoOfCols)); col_cnt++) { - current_row = g_slist_append (current_row, sorted->data); - sorted = sorted->next; - } - - for (; current_row != NULL; current_row = current_row->next) { - SPItem *item=SP_ITEM(current_row->data); - Inkscape::XML::Node *repr = item->getRepr(); - Geom::OptRect b = item->documentVisualBounds(); - Geom::Point min; - if (b) { - width = b->dimensions()[Geom::X]; - height = b->dimensions()[Geom::Y]; - min = b->min(); - } else { - width = height = 0; - min = Geom::Point(0, 0); - } - - row = cnt / NoOfCols; - col = cnt % NoOfCols; - - new_x = grid_left + (((col_widths[col] - width)/2)*HorizAlign) + col_xs[col]; - new_y = grid_top + (((row_heights[row] - height)/2)*VertAlign) + row_ys[row]; - - // signs are inverted between x and y due to y inversion - Geom::Point move = Geom::Point(new_x - min[Geom::X], min[Geom::Y] - new_y); - Geom::Affine const affine = Geom::Affine(Geom::Translate(move)); - item->set_i2d_affine(item->i2dt_affine() * affine); - item->doWriteTransform(repr, item->transform, NULL); - SP_OBJECT (current_row->data)->updateRepr(); - cnt +=1; - } - g_slist_free (current_row); - } - - DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_SELECTION_GRIDTILE, - _("Arrange in a grid")); - -} - - -//######################################################################### -//## E V E N T S -//######################################################################### - - -void TileDialog::_apply() -{ - Grid_Arrange(); -} - - -/** - * changed value in # of columns spinbox. - */ -void TileDialog::on_row_spinbutton_changed() -{ - // quit if run by the attr_changed listener - if (updating) { - return; - } - - // in turn, prevent listener from responding - updating = true; - SPDesktop *desktop = getDesktop(); - - Inkscape::Selection *selection = desktop ? desktop->selection : 0; - g_return_if_fail( selection ); - - GSList const *items = selection->itemList(); - int selcount = g_slist_length((GSList *)items); - - double PerCol = ceil(selcount / NoOfColsSpinner.get_value()); - NoOfRowsSpinner.set_value(PerCol); - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setDouble("/dialogs/gridtiler/NoOfCols", NoOfColsSpinner.get_value()); - updating=false; -} - -/** - * changed value in # of rows spinbox. - */ -void TileDialog::on_col_spinbutton_changed() -{ - // quit if run by the attr_changed listener - if (updating) { - return; - } - - // in turn, prevent listener from responding - updating = true; - SPDesktop *desktop = getDesktop(); - Inkscape::Selection *selection = desktop ? desktop->selection : 0; - g_return_if_fail(selection); - - GSList const *items = selection->itemList(); - int selcount = g_slist_length((GSList *)items); - - double PerRow = ceil(selcount / NoOfRowsSpinner.get_value()); - NoOfColsSpinner.set_value(PerRow); - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setDouble("/dialogs/gridtiler/NoOfCols", PerRow); - - updating=false; + _arrangeButton = this->addResponseButton(C_("Arrange dialog","_Arrange"), GTK_RESPONSE_APPLY); + _arrangeButton->set_use_underline(true); + _arrangeButton->set_tooltip_text(_("Arrange selected objects")); + contents->pack_start(_arrangeBox); + //show_all_children(); } -/** - * changed value in x padding spinbox. - */ -void TileDialog::on_xpad_spinbutton_changed() -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setDouble("/dialogs/gridtiler/XPad", XPadding.getValue("px")); -} - -/** - * changed value in y padding spinbox. - */ -void TileDialog::on_ypad_spinbutton_changed() +void ArrangeDialog::on_show() { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setDouble("/dialogs/gridtiler/YPad", YPadding.getValue("px")); + UI::Widget::Panel::on_show(); + _polarArrangeTab->on_arrange_radio_changed(); } - -/** - * checked/unchecked autosize Rows button. - */ -void TileDialog::on_RowSize_checkbutton_changed() +void ArrangeDialog::_apply() { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - if (RowHeightButton.get_active()) { - prefs->setDouble("/dialogs/gridtiler/AutoRowSize", 20); - } else { - prefs->setDouble("/dialogs/gridtiler/AutoRowSize", -20); - } - RowHeightBox.set_sensitive ( !RowHeightButton.get_active()); -} - -/** - * checked/unchecked autosize Rows button. - */ -void TileDialog::on_ColSize_checkbutton_changed() -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - if (ColumnWidthButton.get_active()) { - prefs->setDouble("/dialogs/gridtiler/AutoColSize", 20); - } else { - prefs->setDouble("/dialogs/gridtiler/AutoColSize", -20); - } - ColumnWidthBox.set_sensitive ( !ColumnWidthButton.get_active()); -} - -/** - * changed value in columns spinbox. - */ -void TileDialog::on_rowSize_spinbutton_changed() -{ - // quit if run by the attr_changed listener - if (updating) { - return; - } - - // in turn, prevent listener from responding - updating = true; - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setDouble("/dialogs/gridtiler/RowHeight", RowHeightSpinner.get_value()); - updating=false; - -} - -/** - * changed value in rows spinbox. - */ -void TileDialog::on_colSize_spinbutton_changed() -{ - // quit if run by the attr_changed listener - if (updating) { - return; - } - - // in turn, prevent listener from responding - updating = true; - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setDouble("/dialogs/gridtiler/ColWidth", ColumnWidthSpinner.get_value()); - updating=false; - -} - -/** - * changed Radio button in Spacing group. - */ -void TileDialog::Spacing_button_changed() -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - if (SpaceManualRadioButton.get_active()) { - prefs->setDouble("/dialogs/gridtiler/SpacingType", 20); - } else { - prefs->setDouble("/dialogs/gridtiler/SpacingType", -20); - } - - XPadding.set_sensitive ( SpaceManualRadioButton.get_active()); - YPadding.set_sensitive ( SpaceManualRadioButton.get_active()); -} - -/** - * changed Radio button in Vertical Align group. - */ -void TileDialog::VertAlign_changed() -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - if (VertTopRadioButton.get_active()) { - VertAlign = 0; - prefs->setInt("/dialogs/gridtiler/VertAlign", 0); - } else if (VertCentreRadioButton.get_active()){ - VertAlign = 1; - prefs->setInt("/dialogs/gridtiler/VertAlign", 1); - } else if (VertBotRadioButton.get_active()){ - VertAlign = 2; - prefs->setInt("/dialogs/gridtiler/VertAlign", 2); - } -} - -/** - * changed Radio button in Vertical Align group. - */ -void TileDialog::HorizAlign_changed() -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - if (HorizLeftRadioButton.get_active()) { - HorizAlign = 0; - prefs->setInt("/dialogs/gridtiler/HorizAlign", 0); - } else if (HorizCentreRadioButton.get_active()){ - HorizAlign = 1; - prefs->setInt("/dialogs/gridtiler/HorizAlign", 1); - } else if (HorizRightRadioButton.get_active()){ - HorizAlign = 2; - prefs->setInt("/dialogs/gridtiler/HorizAlign", 2); - } -} - -/** - * Desktop selection changed - */ -void TileDialog::updateSelection() -{ - // quit if run by the attr_changed listener - if (updating) { - return; - } - - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - // in turn, prevent listener from responding - updating = true; - SPDesktop *desktop = getDesktop(); - Inkscape::Selection *selection = desktop ? desktop->selection : 0; - GSList const *items = selection ? selection->itemList() : 0; - - if (items) { - int selcount = g_slist_length((GSList *)items); - - if (NoOfColsSpinner.get_value() > 1 && NoOfRowsSpinner.get_value() > 1){ - // Update the number of rows assuming number of columns wanted remains same. - double NoOfRows = ceil(selcount / NoOfColsSpinner.get_value()); - NoOfRowsSpinner.set_value(NoOfRows); - - // if the selection has less than the number set for one row, reduce it appropriately - if (selcount < NoOfColsSpinner.get_value()) { - double NoOfCols = ceil(selcount / NoOfRowsSpinner.get_value()); - NoOfColsSpinner.set_value(NoOfCols); - prefs->setInt("/dialogs/gridtiler/NoOfCols", NoOfCols); - } - } else { - double PerRow = ceil(sqrt(selcount)); - double PerCol = ceil(sqrt(selcount)); - NoOfRowsSpinner.set_value(PerRow); - NoOfColsSpinner.set_value(PerCol); - prefs->setInt("/dialogs/gridtiler/NoOfCols", static_cast<int>(PerCol)); - } - } - - updating = false; -} - - - -/*########################## -## Experimental -##########################*/ - -static void updateSelectionCallback(Inkscape::Application */*inkscape*/, Inkscape::Selection */*selection*/, TileDialog *dlg) -{ - dlg->updateSelection(); -} - - -//######################################################################### -//## C O N S T R U C T O R / D E S T R U C T O R -//######################################################################### -/** - * Constructor - */ -TileDialog::TileDialog() - : UI::Widget::Panel("", "/dialogs/gridtiler", SP_VERB_SELECTION_GRIDTILE), - XPadding(_("X:"), _("Horizontal spacing between columns."), UNIT_TYPE_LINEAR, "", "object-columns", &PaddingUnitMenu), - YPadding(_("Y:"), _("Vertical spacing between rows."), UNIT_TYPE_LINEAR, "", "object-rows", &PaddingUnitMenu), -#if WITH_GTKMM_3_0 - PaddingTable(Gtk::manage(new Gtk::Grid())) -#else - PaddingTable(Gtk::manage(new Gtk::Table(2, 2, false))) -#endif -{ - // bool used by spin button callbacks to stop loops where they change each other. - updating = false; - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - - // could not do this in gtkmm - there's no Gtk::SizeGroup public constructor (!) - GtkSizeGroup *_col1 = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); - GtkSizeGroup *_col2 = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); - GtkSizeGroup *_col3 = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); - - { - // Selection Change signal - g_signal_connect ( G_OBJECT (INKSCAPE), "change_selection", G_CALLBACK (updateSelectionCallback), this); - } - - Gtk::Box *contents = _getContents(); - -#define MARGIN 2 - - //##Set up the panel - - SPDesktop *desktop = getDesktop(); - - Inkscape::Selection *selection = desktop ? desktop->selection : 0; - g_return_if_fail( selection ); - int selcount = 1; - if (!selection->isEmpty()) { - GSList const *items = selection->itemList(); - selcount = g_slist_length((GSList *)items); - } - - - /*#### Number of Rows ####*/ - - double PerRow = ceil(sqrt(selcount)); - double PerCol = ceil(sqrt(selcount)); - - #ifdef DEBUG_GRID_ARRANGE - g_print("/n PerRox = %f PerCol = %f selcount = %d",PerRow,PerCol,selcount); - #endif - - NoOfRowsLabel.set_text_with_mnemonic(_("_Rows:")); - NoOfRowsLabel.set_mnemonic_widget(NoOfRowsSpinner); - NoOfRowsBox.pack_start(NoOfRowsLabel, false, false, MARGIN); - - NoOfRowsSpinner.set_digits(0); - NoOfRowsSpinner.set_increments(1, 0); - NoOfRowsSpinner.set_range(1.0, 10000.0); - NoOfRowsSpinner.set_value(PerCol); - NoOfRowsSpinner.signal_changed().connect(sigc::mem_fun(*this, &TileDialog::on_col_spinbutton_changed)); - NoOfRowsSpinner.set_tooltip_text(_("Number of rows")); - NoOfRowsBox.pack_start(NoOfRowsSpinner, false, false, MARGIN); - gtk_size_group_add_widget(_col1, GTK_WIDGET(NoOfRowsBox.gobj())); - - RowHeightButton.set_label(_("Equal _height")); - RowHeightButton.set_use_underline(true); - double AutoRow = prefs->getDouble("/dialogs/gridtiler/AutoRowSize", 15); - if (AutoRow>0) - AutoRowSize=true; - else - AutoRowSize=false; - RowHeightButton.set_active(AutoRowSize); - - NoOfRowsBox.pack_start(RowHeightButton, false, false, MARGIN); - - RowHeightButton.set_tooltip_text(_("If not set, each row has the height of the tallest object in it")); - RowHeightButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::on_RowSize_checkbutton_changed)); - - { - /*#### Radio buttons to control vertical alignment ####*/ - - VertAlignLabel.set_label(_("Align:")); - VertAlignHBox.pack_start(VertAlignLabel, false, false, MARGIN); - - VertTopRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::VertAlign_changed)); - VertAlignGroup = VertTopRadioButton.get_group(); - VertAlignVBox.pack_start(VertTopRadioButton, false, false, 0); - - VertCentreRadioButton.set_group(VertAlignGroup); - VertCentreRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::VertAlign_changed)); - VertAlignVBox.pack_start(VertCentreRadioButton, false, false, 0); - - VertBotRadioButton.set_group(VertAlignGroup); - VertBotRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::VertAlign_changed)); - VertAlignVBox.pack_start(VertBotRadioButton, false, false, 0); - - VertAlign = prefs->getInt("/dialogs/gridtiler/VertAlign", 1); - if (VertAlign == 0) { - VertTopRadioButton.set_active(TRUE); - } - else if (VertAlign == 1) { - VertCentreRadioButton.set_active(TRUE); - } - else if (VertAlign == 2){ - VertBotRadioButton.set_active(TRUE); - } - VertAlignHBox.pack_start(VertAlignVBox, false, false, MARGIN); - NoOfRowsBox.pack_start(VertAlignHBox, false, false, MARGIN); - } - - SpinsHBox.pack_start(NoOfRowsBox, false, false, MARGIN); - - - /*#### Label for X ####*/ - padXByYLabel.set_label(" "); - XByYLabelVBox.pack_start(padXByYLabel, false, false, MARGIN); - XByYLabel.set_markup(" × "); - XByYLabelVBox.pack_start(XByYLabel, false, false, MARGIN); - SpinsHBox.pack_start(XByYLabelVBox, false, false, MARGIN); - gtk_size_group_add_widget(_col2, GTK_WIDGET(XByYLabelVBox.gobj())); - - /*#### Number of columns ####*/ - - NoOfColsLabel.set_text_with_mnemonic(_("_Columns:")); - NoOfColsLabel.set_mnemonic_widget(NoOfColsSpinner); - NoOfColsBox.pack_start(NoOfColsLabel, false, false, MARGIN); - - NoOfColsSpinner.set_digits(0); - NoOfColsSpinner.set_increments(1, 0); - NoOfColsSpinner.set_range(1.0, 10000.0); - NoOfColsSpinner.set_value(PerRow); - NoOfColsSpinner.signal_changed().connect(sigc::mem_fun(*this, &TileDialog::on_row_spinbutton_changed)); - NoOfColsSpinner.set_tooltip_text(_("Number of columns")); - NoOfColsBox.pack_start(NoOfColsSpinner, false, false, MARGIN); - gtk_size_group_add_widget(_col3, GTK_WIDGET(NoOfColsBox.gobj())); - - ColumnWidthButton.set_label(_("Equal _width")); - ColumnWidthButton.set_use_underline(true); - double AutoCol = prefs->getDouble("/dialogs/gridtiler/AutoColSize", 15); - if (AutoCol>0) - AutoColSize=true; - else - AutoColSize=false; - ColumnWidthButton.set_active(AutoColSize); - NoOfColsBox.pack_start(ColumnWidthButton, false, false, MARGIN); - - ColumnWidthButton.set_tooltip_text(_("If not set, each column has the width of the widest object in it")); - ColumnWidthButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::on_ColSize_checkbutton_changed)); - - - { - /*#### Radio buttons to control horizontal alignment ####*/ - - HorizAlignLabel.set_label(_("Align:")); - HorizAlignVBox.pack_start(HorizAlignLabel, false, false, MARGIN); - - HorizAlignHBox.pack_start(*(new Gtk::HBox()), true, true, 0); // centering strut - - HorizLeftRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::HorizAlign_changed)); - HorizAlignGroup = HorizLeftRadioButton.get_group(); - HorizAlignHBox.pack_start(HorizLeftRadioButton, false, false, 0); - - HorizCentreRadioButton.set_group(HorizAlignGroup); - HorizCentreRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::HorizAlign_changed)); - HorizAlignHBox.pack_start(HorizCentreRadioButton, false, false, 0); - - HorizRightRadioButton.set_group(HorizAlignGroup); - HorizRightRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::HorizAlign_changed)); - HorizAlignHBox.pack_start(HorizRightRadioButton, false, false, 0); - - HorizAlignHBox.pack_start(*(new Gtk::HBox()), true, true, 0); // centering strut - - HorizAlign = prefs->getInt("/dialogs/gridtiler/HorizAlign", 1); - if (HorizAlign == 0) { - HorizLeftRadioButton.set_active(TRUE); - } - else if (HorizAlign == 1) { - HorizCentreRadioButton.set_active(TRUE); - } - else if (HorizAlign == 2) { - HorizRightRadioButton.set_active(TRUE); - } - HorizAlignVBox.pack_start(HorizAlignHBox, false, false, MARGIN); - NoOfColsBox.pack_start(HorizAlignVBox, false, false, MARGIN); - } - - SpinsHBox.pack_start(NoOfColsBox, false, false, MARGIN); - - TileBox.pack_start(SpinsHBox, false, false, MARGIN); - - { - /*#### Radio buttons to control spacing manually or to fit selection bbox ####*/ - SpaceByBBoxRadioButton.set_label(_("_Fit into selection box")); - SpaceByBBoxRadioButton.set_use_underline (true); - SpaceByBBoxRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::Spacing_button_changed)); - SpacingGroup = SpaceByBBoxRadioButton.get_group(); - - SpacingVBox.pack_start(SpaceByBBoxRadioButton, false, false, MARGIN); - - SpaceManualRadioButton.set_label(_("_Set spacing:")); - SpaceManualRadioButton.set_use_underline (true); - SpaceManualRadioButton.set_group(SpacingGroup); - SpaceManualRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::Spacing_button_changed)); - SpacingVBox.pack_start(SpaceManualRadioButton, false, false, MARGIN); - - TileBox.pack_start(SpacingVBox, false, false, MARGIN); - } - - { - /*#### Padding ####*/ - PaddingUnitMenu.setUnitType(UNIT_TYPE_LINEAR); - PaddingUnitMenu.setUnit("px"); - - YPadding.setDigits(5); - YPadding.setIncrements(0.2, 0); - YPadding.setRange(-10000, 10000); - double yPad = prefs->getDouble("/dialogs/gridtiler/YPad", 15); - YPadding.setValue(yPad, "px"); - YPadding.signal_value_changed().connect(sigc::mem_fun(*this, &TileDialog::on_ypad_spinbutton_changed)); - - XPadding.setDigits(5); - XPadding.setIncrements(0.2, 0); - XPadding.setRange(-10000, 10000); - double xPad = prefs->getDouble("/dialogs/gridtiler/XPad", 15); - XPadding.setValue(xPad, "px"); - - XPadding.signal_value_changed().connect(sigc::mem_fun(*this, &TileDialog::on_xpad_spinbutton_changed)); - } - - PaddingTable->set_border_width(MARGIN); - -#if WITH_GTKMM_3_0 - PaddingTable->set_row_spacing(MARGIN); - PaddingTable->set_column_spacing(MARGIN); - PaddingTable->attach(XPadding, 0, 0, 1, 1); - PaddingTable->attach(PaddingUnitMenu, 1, 0, 1, 1); - PaddingTable->attach(YPadding, 0, 1, 1, 1); -#else - PaddingTable->set_row_spacings(MARGIN); - PaddingTable->set_col_spacings(MARGIN); - PaddingTable->attach(XPadding, 0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK); - PaddingTable->attach(PaddingUnitMenu, 1, 2, 0, 1, Gtk::SHRINK, Gtk::SHRINK); - PaddingTable->attach(YPadding, 0, 1, 1, 2, Gtk::SHRINK, Gtk::SHRINK); -#endif - - TileBox.pack_start(*PaddingTable, false, false, MARGIN); - - contents->pack_start(TileBox); - - double SpacingType = prefs->getDouble("/dialogs/gridtiler/SpacingType", 15); - if (SpacingType>0) { - ManualSpacing=true; - } else { - ManualSpacing=false; - } - SpaceManualRadioButton.set_active(ManualSpacing); - SpaceByBBoxRadioButton.set_active(!ManualSpacing); - XPadding.set_sensitive (ManualSpacing); - YPadding.set_sensitive (ManualSpacing); - - //## The OK button - TileOkButton = addResponseButton(C_("Rows and columns dialog","_Arrange"), GTK_RESPONSE_APPLY); - TileOkButton->set_use_underline(true); - TileOkButton->set_tooltip_text(_("Arrange selected objects")); - - show_all_children(); + switch(_notebook.get_current_page()) + { + case 0: + _gridArrangeTab->arrange(); + break; + case 1: + _polarArrangeTab->arrange(); + break; + } } } //namespace Dialog diff --git a/src/ui/dialog/tile.h b/src/ui/dialog/tile.h index 6e41723fd..2f75a8922 100644 --- a/src/ui/dialog/tile.h +++ b/src/ui/dialog/tile.h @@ -5,6 +5,7 @@ * Bob Jamison ( based off trace dialog) * John Cliff * Other dudes from The Inkscape Organization + * Declara Denis * * Copyright (C) 2004 Bob Jamison * Copyright (C) 2004 John Cliff @@ -29,8 +30,6 @@ #include <gtkmm/radiobutton.h> #include "ui/widget/panel.h" -#include "ui/widget/spinbutton.h" -#include "ui/widget/scalar-unit.h" namespace Gtk { class Button; @@ -46,134 +45,34 @@ namespace Inkscape { namespace UI { namespace Dialog { +class ArrangeTab; +class GridArrangeTab; +class PolarArrangeTab; -/** - * Dialog for tiling an object - */ -class TileDialog : public UI::Widget::Panel { -public: - TileDialog() ; - virtual ~TileDialog() {}; +class ArrangeDialog : public UI::Widget::Panel { +private: + Gtk::VBox _arrangeBox; + Gtk::Notebook _notebook; - /** - * Do the actual work - */ - void Grid_Arrange(); + GridArrangeTab *_gridArrangeTab; + PolarArrangeTab *_polarArrangeTab; - /** - * Respond to selection change - */ - void updateSelection(); + Gtk::Button *_arrangeButton; + +public: + ArrangeDialog(); + virtual ~ArrangeDialog() {}; /** * Callback from Apply */ virtual void _apply(); - // Callbacks from spinbuttons - void on_row_spinbutton_changed(); - void on_col_spinbutton_changed(); - void on_xpad_spinbutton_changed(); - void on_ypad_spinbutton_changed(); - void on_RowSize_checkbutton_changed(); - void on_ColSize_checkbutton_changed(); - void on_rowSize_spinbutton_changed(); - void on_colSize_spinbutton_changed(); - void Spacing_button_changed(); - void VertAlign_changed(); - void HorizAlign_changed(); - - static TileDialog& getInstance() { return *new TileDialog(); } - -private: - TileDialog(TileDialog const &d); // no copy - void operator=(TileDialog const &d); // no assign - - bool userHidden; - bool updating; - - Gtk::Notebook notebook; - - Gtk::VBox TileBox; - Gtk::Button *TileOkButton; - Gtk::Button *TileCancelButton; - - // Number selected label - Gtk::Label SelectionContentsLabel; - - - Gtk::HBox AlignHBox; - Gtk::HBox SpinsHBox; - - // Number per Row - Gtk::VBox NoOfColsBox; - Gtk::Label NoOfColsLabel; - Inkscape::UI::Widget::SpinButton NoOfColsSpinner; - bool AutoRowSize; - Gtk::CheckButton RowHeightButton; - - Gtk::VBox XByYLabelVBox; - Gtk::Label padXByYLabel; - Gtk::Label XByYLabel; - - // Number per Column - Gtk::VBox NoOfRowsBox; - Gtk::Label NoOfRowsLabel; - Inkscape::UI::Widget::SpinButton NoOfRowsSpinner; - bool AutoColSize; - Gtk::CheckButton ColumnWidthButton; - - // Vertical align - Gtk::Label VertAlignLabel; - Gtk::HBox VertAlignHBox; - Gtk::VBox VertAlignVBox; - Gtk::RadioButtonGroup VertAlignGroup; - Gtk::RadioButton VertCentreRadioButton; - Gtk::RadioButton VertTopRadioButton; - Gtk::RadioButton VertBotRadioButton; - double VertAlign; - - // Horizontal align - Gtk::Label HorizAlignLabel; - Gtk::VBox HorizAlignVBox; - Gtk::HBox HorizAlignHBox; - Gtk::RadioButtonGroup HorizAlignGroup; - Gtk::RadioButton HorizCentreRadioButton; - Gtk::RadioButton HorizLeftRadioButton; - Gtk::RadioButton HorizRightRadioButton; - double HorizAlign; - - Inkscape::UI::Widget::UnitMenu PaddingUnitMenu; - Inkscape::UI::Widget::ScalarUnit XPadding; - Inkscape::UI::Widget::ScalarUnit YPadding; - -#if WITH_GTKMM_3_0 - Gtk::Grid *PaddingTable; -#else - Gtk::Table *PaddingTable; -#endif + virtual void on_show(); - // BBox or manual spacing - Gtk::VBox SpacingVBox; - Gtk::RadioButtonGroup SpacingGroup; - Gtk::RadioButton SpaceByBBoxRadioButton; - Gtk::RadioButton SpaceManualRadioButton; - bool ManualSpacing; - - // Row height - Gtk::VBox RowHeightVBox; - Gtk::HBox RowHeightBox; - Gtk::Label RowHeightLabel; - Inkscape::UI::Widget::SpinButton RowHeightSpinner; - - // Column width - Gtk::VBox ColumnWidthVBox; - Gtk::HBox ColumnWidthBox; - Gtk::Label ColumnWidthLabel; - Inkscape::UI::Widget::SpinButton ColumnWidthSpinner; + static ArrangeDialog& getInstance() { return *new ArrangeDialog(); } }; - } //namespace Dialog } //namespace UI } //namespace Inkscape diff --git a/src/ui/tools/connector-tool.cpp b/src/ui/tools/connector-tool.cpp index e19f35832..4f918b483 100644 --- a/src/ui/tools/connector-tool.cpp +++ b/src/ui/tools/connector-tool.cpp @@ -201,7 +201,8 @@ ConnectorTool::~ConnectorTool() { for (int i = 0; i < 2; ++i) { if (this->endpt_handle[1]) { - g_object_unref(this->endpt_handle[i]); + //g_object_unref(this->endpt_handle[i]); + knot_unref(this->endpt_handle[i]); this->endpt_handle[i] = NULL; } } @@ -319,7 +320,7 @@ cc_clear_active_knots(SPKnotList k) // Hide the connection points if they exist. if (k.size()) { for (SPKnotList::iterator it = k.begin(); it != k.end(); ++it) { - sp_knot_hide(it->first); + it->first->hide(); } } } @@ -341,7 +342,7 @@ void ConnectorTool::cc_clear_active_conn() { // Hide the endpoint handles. for (int i = 0; i < 2; ++i) { if (this->endpt_handle[i]) { - sp_knot_hide(this->endpt_handle[i]); + this->endpt_handle[i]->hide(); } } } @@ -365,7 +366,7 @@ cc_select_handle(SPKnot* knot) knot->setSize(10); knot->setAnchor(SP_ANCHOR_CENTER); knot->setFill(0x0000ffff, 0x0000ffff, 0x0000ffff); - sp_knot_update_ctrl(knot); + knot->update_ctrl(); } static void @@ -375,7 +376,7 @@ cc_deselect_handle(SPKnot* knot) knot->setSize(8); knot->setAnchor(SP_ANCHOR_CENTER); knot->setFill(0xffffff00, 0xff0000ff, 0xff0000ff); - sp_knot_update_ctrl(knot); + knot->update_ctrl(); } bool ConnectorTool::item_handler(SPItem* item, GdkEvent* event) { @@ -969,7 +970,8 @@ cc_generic_knot_handler(SPCanvasItem *, GdkEvent *event, SPKnot *knot) { g_assert (knot != NULL); - g_object_ref(knot); + //g_object_ref(knot); + knot_ref(knot); ConnectorTool *cc = SP_CONNECTOR_CONTEXT( knot->desktop->event_context); @@ -979,7 +981,7 @@ cc_generic_knot_handler(SPCanvasItem *, GdkEvent *event, SPKnot *knot) gchar const *knot_tip = "Click to join at this point"; switch (event->type) { case GDK_ENTER_NOTIFY: - sp_knot_set_flag(knot, SP_KNOT_MOUSEOVER, TRUE); + knot->set_flag(SP_KNOT_MOUSEOVER, TRUE); cc->active_handle = knot; if (knot_tip) @@ -991,7 +993,7 @@ cc_generic_knot_handler(SPCanvasItem *, GdkEvent *event, SPKnot *knot) consumed = TRUE; break; case GDK_LEAVE_NOTIFY: - sp_knot_set_flag(knot, SP_KNOT_MOUSEOVER, FALSE); + knot->set_flag(SP_KNOT_MOUSEOVER, FALSE); /* FIXME: the following test is a workaround for LP Bug #1273510. * It seems that a signal is not correctly disconnected, maybe @@ -1010,7 +1012,8 @@ cc_generic_knot_handler(SPCanvasItem *, GdkEvent *event, SPKnot *knot) break; } - g_object_unref(knot); + //g_object_unref(knot); + knot_unref(knot); return consumed; } @@ -1066,14 +1069,14 @@ endpt_handler(SPKnot */*knot*/, GdkEvent *event, ConnectorTool *cc) } void ConnectorTool::_activeShapeAddKnot(SPItem* item) { - SPKnot *knot = sp_knot_new(desktop, 0); + SPKnot *knot = new SPKnot(desktop, 0); knot->owner = item; knot->setShape(SP_KNOT_SHAPE_SQUARE); knot->setSize(8); knot->setAnchor(SP_ANCHOR_CENTER); knot->setFill(0xffffff00, 0xff0000ff, 0xff0000ff); - sp_knot_update_ctrl(knot); + knot->update_ctrl(); // We don't want to use the standard knot handler. g_signal_handler_disconnect(G_OBJECT(knot->item), @@ -1084,8 +1087,8 @@ void ConnectorTool::_activeShapeAddKnot(SPItem* item) { g_signal_connect(G_OBJECT(knot->item), "event", G_CALLBACK(cc_generic_knot_handler), knot); - sp_knot_set_position(knot, item->avoidRef->getConnectionPointPos() * desktop->doc2dt(), 0); - sp_knot_show(knot); + knot->set_position(item->avoidRef->getConnectionPointPos() * desktop->doc2dt(), 0); + knot->show(); this->knots[knot] = 1; } @@ -1149,17 +1152,17 @@ void ConnectorTool::cc_set_active_conn(SPItem *item) { { // Connector is invisible because it is clipped to the boundary of // two overlpapping shapes. - sp_knot_hide(this->endpt_handle[0]); - sp_knot_hide(this->endpt_handle[1]); + this->endpt_handle[0]->hide(); + this->endpt_handle[1]->hide(); } else { // Just adjust handle positions. Geom::Point startpt = *(curve->first_point()) * i2dt; - sp_knot_set_position(this->endpt_handle[0], startpt, 0); + this->endpt_handle[0]->set_position(startpt, 0); Geom::Point endpt = *(curve->last_point()) * i2dt; - sp_knot_set_position(this->endpt_handle[1], endpt, 0); + this->endpt_handle[1]->set_position(endpt, 0); } return; @@ -1184,7 +1187,7 @@ void ConnectorTool::cc_set_active_conn(SPItem *item) { for (int i = 0; i < 2; ++i) { // Create the handle if it doesn't exist if ( this->endpt_handle[i] == NULL ) { - SPKnot *knot = sp_knot_new(this->desktop, + SPKnot *knot = new SPKnot(this->desktop, _("<b>Connector endpoint</b>: drag to reroute or connect to new shapes")); knot->setShape(SP_KNOT_SHAPE_SQUARE); @@ -1192,7 +1195,7 @@ void ConnectorTool::cc_set_active_conn(SPItem *item) { knot->setAnchor(SP_ANCHOR_CENTER); knot->setFill(0xffffff00, 0xff0000ff, 0xff0000ff); knot->setStroke(0x000000ff, 0x000000ff, 0x000000ff); - sp_knot_update_ctrl(knot); + knot->update_ctrl(); // We don't want to use the standard knot handler, // since we don't want this knot to be draggable. @@ -1232,13 +1235,13 @@ void ConnectorTool::cc_set_active_conn(SPItem *item) { } Geom::Point startpt = *(curve->first_point()) * i2dt; - sp_knot_set_position(this->endpt_handle[0], startpt, 0); + this->endpt_handle[0]->set_position(startpt, 0); Geom::Point endpt = *(curve->last_point()) * i2dt; - sp_knot_set_position(this->endpt_handle[1], endpt, 0); + this->endpt_handle[1]->set_position(endpt, 0); - sp_knot_show(this->endpt_handle[0]); - sp_knot_show(this->endpt_handle[1]); + this->endpt_handle[0]->show(); + this->endpt_handle[1]->show(); } void cc_create_connection_point(ConnectorTool* cc) @@ -1250,7 +1253,7 @@ void cc_create_connection_point(ConnectorTool* cc) cc_deselect_handle( cc->selected_handle ); } - SPKnot *knot = sp_knot_new(cc->desktop, 0); + SPKnot *knot = new SPKnot(cc->desktop, 0); // We do not process events on this knot. g_signal_handler_disconnect(G_OBJECT(knot->item), @@ -1260,7 +1263,7 @@ void cc_create_connection_point(ConnectorTool* cc) cc_select_handle( knot ); cc->selected_handle = knot; - sp_knot_show(cc->selected_handle); + cc->selected_handle->show(); cc->state = SP_CONNECTOR_CONTEXT_NEWCONNPOINT; } } diff --git a/src/ui/widget/Makefile_insert b/src/ui/widget/Makefile_insert index 196004df1..e18b790bd 100644 --- a/src/ui/widget/Makefile_insert +++ b/src/ui/widget/Makefile_insert @@ -1,6 +1,8 @@ ## Makefile.am fragment sourced by src/Makefile.am. ink_common_sources += \ + ui/widget/anchor-selector.h \ + ui/widget/anchor-selector.cpp \ ui/widget/attr-widget.h \ ui/widget/button.h \ ui/widget/button.cpp \ diff --git a/src/ui/widget/anchor-selector.cpp b/src/ui/widget/anchor-selector.cpp new file mode 100644 index 000000000..82e27ee89 --- /dev/null +++ b/src/ui/widget/anchor-selector.cpp @@ -0,0 +1,97 @@ +/* + * anchor-selector.cpp + * + * Created on: Mar 22, 2012 + * Author: denis + * + * Released under GNU GPL. Read the file 'COPYING' for more information. + */ + +#include "ui/widget/anchor-selector.h" +#include <iostream> +#include "widgets/icon.h" +#include "ui/icon-names.h" + +namespace Inkscape { +namespace UI { +namespace Widget { + +void AnchorSelector::setupButton(const Glib::ustring& icon, Gtk::ToggleButton& button) { + Gtk::Widget* buttonIcon = Gtk::manage(sp_icon_get_icon(icon, Inkscape::ICON_SIZE_SMALL_TOOLBAR)); + buttonIcon->show(); + + button.set_relief(Gtk::RELIEF_NONE); + button.show(); + button.add(*buttonIcon); + button.set_can_focus(false); +} + +AnchorSelector::AnchorSelector() + : Gtk::Alignment(0.5, 0, 0, 0), + _container(3, 3, true) +{ + setupButton(INKSCAPE_ICON("boundingbox_top_left"), _buttons[0]); + setupButton(INKSCAPE_ICON("boundingbox_top"), _buttons[1]); + setupButton(INKSCAPE_ICON("boundingbox_top_right"), _buttons[2]); + setupButton(INKSCAPE_ICON("boundingbox_left"), _buttons[3]); + setupButton(INKSCAPE_ICON("boundingbox_center"), _buttons[4]); + setupButton(INKSCAPE_ICON("boundingbox_right"), _buttons[5]); + setupButton(INKSCAPE_ICON("boundingbox_bottom_left"), _buttons[6]); + setupButton(INKSCAPE_ICON("boundingbox_bottom"), _buttons[7]); + setupButton(INKSCAPE_ICON("boundingbox_bottom_right"), _buttons[8]); + + for(int i = 0; i < 9; ++i) { + _buttons[i].signal_clicked().connect( + sigc::bind(sigc::mem_fun(*this, &AnchorSelector::btn_activated), i)); + _container.attach(_buttons[i], i % 3, i % 3+1, i / 3, i / 3+1, Gtk::FILL, Gtk::FILL); + } + _selection = 4; + _buttons[4].set_active(); + + this->add(_container); +} + +AnchorSelector::~AnchorSelector() +{ + // TODO Auto-generated destructor stub +} + +void AnchorSelector::btn_activated(int index) +{ + + if(_selection == index && _buttons[index].get_active() == false) + { + _buttons[index].set_active(true); + } + else if(_selection != index && _buttons[index].get_active()) + { + int old_selection = _selection; + _selection = index; + _buttons[old_selection].set_active(false); + _selectionChanged.emit(); + } +} + +void AnchorSelector::setAlignment(int horizontal, int vertical) +{ + int index = 3 * vertical + horizontal; + if(index >= 0 && index < 9) + { + _buttons[index].set_active(!_buttons[index].get_active()); + } +} + +} // namespace Widget +} // namespace UI +} // namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/ui/widget/anchor-selector.h b/src/ui/widget/anchor-selector.h new file mode 100644 index 000000000..2263438e3 --- /dev/null +++ b/src/ui/widget/anchor-selector.h @@ -0,0 +1,59 @@ +/* + * anchor-selector.h + * + * Created on: Mar 22, 2012 + * Author: denis + * + * Released under GNU GPL. Read the file 'COPYING' for more information. + */ + +#ifndef ANCHOR_SELECTOR_H_ +#define ANCHOR_SELECTOR_H_ + +#include <gtkmm.h> + +namespace Inkscape { +namespace UI { +namespace Widget { + +class AnchorSelector : public Gtk::Alignment +{ +private: + Gtk::ToggleButton _buttons[9]; + int _selection; + Gtk::Table _container; + + sigc::signal<void> _selectionChanged; + + void setupButton(const Glib::ustring &icon, Gtk::ToggleButton &button); + void btn_activated(int index); + +public: + + int getHorizontalAlignment() { return _selection % 3; } + int getVerticalAlignment() { return _selection / 3; } + + sigc::signal<void> &on_selectionChanged() { return _selectionChanged; } + + void setAlignment(int horizontal, int vertical); + + AnchorSelector(); + virtual ~AnchorSelector(); +}; + +} // namespace Widget +} // namespace UI +} // namespace Inkscape + +#endif /* ANCHOR_SELECTOR_H_ */ + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : |
