[dia] guides: Salvage patch from Martin van Zijl
- From: Zander <zbrown src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [dia] guides: Salvage patch from Martin van Zijl
- Date: Sun, 6 Oct 2019 18:05:53 +0000 (UTC)
commit 354cdb199553ec17440907095086cdfa9e096e28
Author: Zander Brown <zbrown gnome org>
Date: Fri Oct 4 16:08:22 2019 +0100
guides: Salvage patch from Martin van Zijl
Minimal tweaks for compatability with current master
Fix https://gitlab.gnome.org/GNOME/dia/issues/79
app/commands.c | 68 +++++++++++
app/commands.h | 24 ++--
app/dia-props.c | 9 ++
app/dia.gresource.xml | 5 +
app/diagram.c | 171 ++++++++++++++++++++++++++-
app/diagram.h | 46 +++++++-
app/display.c | 56 ++++++++-
app/display.h | 12 +-
app/grid.c | 115 ++++++++++++++++++
app/grid.h | 1 +
app/guide_tool.c | 221 +++++++++++++++++++++++++++++++++++
app/guide_tool.h | 54 +++++++++
app/icons/dia-guides-snap-off.png | Bin 0 -> 361 bytes
app/icons/dia-guides-snap-off.svg | 90 ++++++++++++++
app/icons/dia-guides-snap-on.png | Bin 0 -> 373 bytes
app/icons/dia-guides-snap-on.svg | 90 ++++++++++++++
app/interface.c | 178 ++++++++++++++++++++++++++++
app/load_save.c | 105 ++++++++++++-----
app/menus.c | 54 +++++++++
app/menus.h | 1 +
app/meson.build | 5 +
app/modify_tool.c | 28 +++++
app/new_guide_dialog.c | 149 ++++++++++++++++++++++++
app/new_guide_dialog.h | 26 +++++
app/preferences.c | 10 ++
app/preferences.h | 5 +
app/ruler.c | 2 +-
app/tool.c | 29 +++--
app/tool.h | 7 +-
app/undo.c | 226 ++++++++++++++++++++++++++++++++++++
app/undo.h | 25 ++++
data/ui/display-ui.xml | 7 ++
data/ui/integrated-ui.xml | 7 ++
data/ui/popup-ui.xml | 9 +-
data/ui/properties-dialog.ui | 29 ++++-
lib/diagramdata.h | 2 +-
lib/guide.c | 1 +
lib/guide.h | 31 +++++
lib/meson.build | 2 +
plug-ins/python/pydia-diagramdata.c | 30 ++---
40 files changed, 1834 insertions(+), 96 deletions(-)
---
diff --git a/app/commands.c b/app/commands.c
index ca0c237b..95d2c6a3 100644
--- a/app/commands.c
+++ b/app/commands.c
@@ -90,6 +90,8 @@ ShellExecuteA (long hwnd,
#include "dia-props.h"
#include "authors.h" /* master contributors data */
#include "object.h"
+#include "new_guide_dialog.h"
+
void
file_quit_callback (GtkAction *action)
@@ -1426,6 +1428,72 @@ view_layers_callback (GtkAction *action)
integrated_ui_layer_view_show (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)));
}
+
+void
+view_new_guide_callback (GtkAction *action)
+{
+ DDisplay *ddisp;
+
+ ddisp = ddisplay_active ();
+ if (!ddisp) {
+ return;
+ }
+
+ dialog_new_guide_show ();
+}
+
+
+void
+view_visible_guides_callback (GtkToggleAction *action)
+{
+ DDisplay *ddisp;
+ gboolean old_val;
+
+ ddisp = ddisplay_active ();
+ if (!ddisp) {
+ return;
+ }
+
+ old_val = ddisp->guides_visible;
+ ddisp->guides_visible = gtk_toggle_action_get_active (action);
+
+ if (old_val != ddisp->guides_visible) {
+ ddisplay_add_update_all (ddisp);
+ ddisplay_flush (ddisp);
+ }
+}
+
+
+void
+view_snap_to_guides_callback (GtkToggleAction *action)
+{
+ DDisplay *ddisp;
+
+ ddisp = ddisplay_active ();
+ if (!ddisp) {
+ return;
+ }
+
+ ddisplay_set_snap_to_guides (ddisp, gtk_toggle_action_get_active (action));
+}
+
+
+void
+view_remove_all_guides_callback (GtkAction *action)
+{
+ Diagram *dia;
+
+ dia = ddisplay_active_diagram ();
+ if (!dia) {
+ return;
+ }
+
+ diagram_remove_all_guides (dia);
+ diagram_add_update_all (dia);
+ diagram_flush (dia);
+}
+
+
void
layers_add_layer_callback (GtkAction *action)
{
diff --git a/app/commands.h b/app/commands.h
index 077f8344..4137b7cb 100644
--- a/app/commands.h
+++ b/app/commands.h
@@ -45,16 +45,20 @@ void edit_cut_text_callback (GtkAction *action);
void edit_paste_image_callback (GtkAction *action);
-void view_zoom_in_callback (GtkAction *action);
-void view_zoom_out_callback (GtkAction *action);
-void view_zoom_set_callback (GtkAction *action);
-void view_unfullscreen (void);
-void view_fullscreen_callback (GtkToggleAction *action);
-void view_aa_callback (GtkToggleAction *action);
-void view_visible_grid_callback (GtkToggleAction *action);
-void view_snap_to_grid_callback (GtkToggleAction *action);
-void view_snap_to_objects_callback (GtkToggleAction *action);
-void view_toggle_rulers_callback (GtkToggleAction *action);
+void view_zoom_in_callback (GtkAction *action);
+void view_zoom_out_callback (GtkAction *action);
+void view_zoom_set_callback (GtkAction *action);
+void view_unfullscreen (void);
+void view_fullscreen_callback (GtkToggleAction *action);
+void view_aa_callback (GtkToggleAction *action);
+void view_visible_grid_callback (GtkToggleAction *action);
+void view_snap_to_grid_callback (GtkToggleAction *action);
+void view_new_guide_callback (GtkAction *action);
+void view_visible_guides_callback (GtkToggleAction *action);
+void view_snap_to_guides_callback (GtkToggleAction *action);
+void view_remove_all_guides_callback (GtkAction *action);
+void view_snap_to_objects_callback (GtkToggleAction *action);
+void view_toggle_rulers_callback (GtkToggleAction *action);
void view_toggle_scrollbars_callback (GtkToggleAction *action);
void view_show_cx_pts_callback (GtkToggleAction *action);
diff --git a/app/dia-props.c b/app/dia-props.c
index d363417e..a214cea6 100644
--- a/app/dia-props.c
+++ b/app/dia-props.c
@@ -54,6 +54,7 @@ struct _DiaDiagramPropertiesDialogPrivate {
GtkWidget *background;
GtkWidget *grid_lines;
GtkWidget *page_lines;
+ GtkWidget *guide_lines;
};
G_DEFINE_TYPE_WITH_PRIVATE (DiaDiagramPropertiesDialog, dia_diagram_properties_dialog, GTK_TYPE_DIALOG)
@@ -164,6 +165,9 @@ dia_diagram_properties_dialog_response (GtkDialog *dialog,
dia_mem_swap_change_new (priv->diagram,
&priv->diagram->pagebreak_color,
sizeof(priv->diagram->pagebreak_color));
+ dia_mem_swap_change_new (priv->diagram,
+ &priv->diagram->guide_color,
+ sizeof(priv->diagram->guide_color));
undo_set_transactionpoint (priv->diagram->undo);
priv->diagram->grid.dynamic =
@@ -181,6 +185,8 @@ dia_diagram_properties_dialog_response (GtkDialog *dialog,
&priv->diagram->grid.colour);
dia_color_selector_get_color (priv->page_lines,
&priv->diagram->pagebreak_color);
+ dia_color_selector_get_color (priv->guide_lines,
+ &priv->diagram->guide_color);
diagram_add_update_all (priv->diagram);
diagram_flush (priv->diagram);
diagram_set_modified (priv->diagram, TRUE);
@@ -318,6 +324,7 @@ dia_diagram_properties_dialog_init (DiaDiagramPropertiesDialog *self)
priv->background = GTK_WIDGET (gtk_builder_get_object (builder, "background"));
priv->grid_lines = GTK_WIDGET (gtk_builder_get_object (builder, "grid_lines"));
priv->page_lines = GTK_WIDGET (gtk_builder_get_object (builder, "page_lines"));
+ priv->guide_lines = GTK_WIDGET (gtk_builder_get_object (builder, "guide_lines"));
g_clear_object (&builder);
}
@@ -385,6 +392,8 @@ dia_diagram_properties_dialog_set_diagram (DiaDiagramPropertiesDialog *self,
&diagram->grid.colour);
dia_color_selector_set_color (priv->page_lines,
&diagram->pagebreak_color);
+ dia_color_selector_set_color (priv->guide_lines,
+ &diagram->guide_color);
update_sensitivity (GTK_TOGGLE_BUTTON (priv->dynamic), self);
diff --git a/app/dia.gresource.xml b/app/dia.gresource.xml
index a09e1561..262a3952 100644
--- a/app/dia.gresource.xml
+++ b/app/dia.gresource.xml
@@ -23,6 +23,11 @@
<file>icons/dia-layer-rename.png</file>
<file>icons/dia-layer-move-above.png</file>
<file>icons/dia-layer-move-below.png</file>
+ <!-- GTK3: Use SVG directly instead of PNG -->
+ <file>icons/dia-guides-snap-off.svg</file>
+ <file>icons/dia-guides-snap-on.svg</file>
+ <file>icons/dia-guides-snap-off.png</file>
+ <file>icons/dia-guides-snap-on.png</file>
<file>dia-splash.png</file>
</gresource>
</gresources>
diff --git a/app/diagram.c b/app/diagram.c
index 44f3ccac..8e034980 100644
--- a/app/diagram.c
+++ b/app/diagram.c
@@ -234,6 +234,7 @@ dia_diagram_init (Diagram *self)
/* Sure, but it's also silly ZB */
self->pagebreak_color = prefs.new_diagram.pagebreak_color;
+ self->guide_color = prefs.new_diagram.guide_color;
get_paper_info (&self->data->paper, -1, &prefs.new_diagram);
@@ -247,10 +248,7 @@ dia_diagram_init (Diagram *self)
self->grid.dynamic = prefs.grid.dynamic;
self->grid.major_lines = prefs.grid.major_lines;
- self->guides.nhguides = 0;
- self->guides.hguides = NULL;
- self->guides.nvguides = 0;
- self->guides.vguides = NULL;
+ self->guides = NULL;
self->filename = NULL;
@@ -1610,3 +1608,168 @@ dia_diagram_get_file (Diagram *self)
return priv->file;
}
+
+
+Guide *
+diagram_add_guide (Diagram *dia, real position, GtkOrientation orientation, gboolean push_undo)
+{
+ Guide *guide = g_new0 (Guide, 1);
+ guide->position = position;
+ guide->orientation = orientation;
+ dia->guides = g_list_append (dia->guides, guide);
+
+ if(push_undo) {
+ dia_add_guide_change_new (dia, guide, TRUE); /* Update undo stack. */
+ undo_set_transactionpoint (dia->undo);
+ }
+
+ diagram_add_update_all (dia);
+ diagram_modified (dia);
+ diagram_flush (dia);
+
+ return guide;
+}
+
+Guide *
+diagram_pick_guide (Diagram *dia,
+ gdouble x,
+ gdouble y,
+ gdouble epsilon_x,
+ gdouble epsilon_y)
+{
+ GList *list;
+ Guide *ret = NULL;
+ gdouble mindist = G_MAXDOUBLE;
+
+ g_return_val_if_fail (epsilon_x > 0 && epsilon_y > 0, NULL);
+
+ for (list = dia->guides;
+ list;
+ list = g_list_next (list)) {
+ Guide *guide = list->data;
+ real position = guide->position;
+ gdouble dist;
+
+ switch (guide->orientation) {
+ case GTK_ORIENTATION_HORIZONTAL:
+ dist = ABS (position - y);
+ if (dist < MIN (epsilon_y, mindist)) {
+ mindist = dist;
+ ret = guide;
+ }
+ break;
+
+ case GTK_ORIENTATION_VERTICAL:
+ dist = ABS (position - x);
+ if (dist < MIN (epsilon_x, mindist / epsilon_y * epsilon_x)) {
+ mindist = dist * epsilon_y / epsilon_x;
+ ret = guide;
+ }
+ break;
+
+ default:
+ continue;
+ }
+ }
+
+ return ret;
+}
+
+Guide *
+diagram_pick_guide_h (Diagram *dia,
+ gdouble x,
+ gdouble y,
+ gdouble epsilon_x,
+ gdouble epsilon_y)
+{
+ GList *list;
+ Guide *ret = NULL;
+ gdouble mindist = G_MAXDOUBLE;
+
+ g_return_val_if_fail (epsilon_x > 0 && epsilon_y > 0, NULL);
+
+ for (list = dia->guides;
+ list;
+ list = g_list_next (list)) {
+ Guide *guide = list->data;
+ real position = guide->position;
+ gdouble dist;
+
+ switch (guide->orientation) {
+ case GTK_ORIENTATION_HORIZONTAL:
+ dist = ABS (position - y);
+ if (dist < MIN (epsilon_y, mindist)) {
+ mindist = dist;
+ ret = guide;
+ }
+ break;
+
+ default:
+ continue;
+ }
+ }
+
+ return ret;
+}
+
+
+Guide *
+diagram_pick_guide_v (Diagram *dia,
+ gdouble x,
+ gdouble y,
+ gdouble epsilon_x,
+ gdouble epsilon_y)
+{
+ GList *list;
+ Guide *ret = NULL;
+ gdouble mindist = G_MAXDOUBLE;
+
+ g_return_val_if_fail (epsilon_x > 0 && epsilon_y > 0, NULL);
+
+ for (list = dia->guides;
+ list;
+ list = g_list_next (list)) {
+ Guide *guide = list->data;
+ real position = guide->position;
+ gdouble dist;
+
+ switch (guide->orientation) {
+ case GTK_ORIENTATION_VERTICAL:
+ dist = ABS (position - x);
+ if (dist < MIN (epsilon_x, mindist / epsilon_y * epsilon_x)) {
+ mindist = dist * epsilon_y / epsilon_x;
+ ret = guide;
+ }
+ break;
+
+ default:
+ continue;
+ }
+ }
+
+ return ret;
+}
+
+
+void
+diagram_remove_guide (Diagram *dia, Guide *guide, gboolean push_undo)
+{
+ if (push_undo) {
+ dia_delete_guide_change_new (dia, guide, TRUE); /* Update undo stack. */
+ }
+
+ dia->guides = g_list_remove (dia->guides, guide);
+}
+
+
+void
+diagram_remove_all_guides (Diagram *dia)
+{
+ GList *list;
+
+ for(list = g_list_copy (dia->guides); list; list = g_list_next(list)) {
+ diagram_remove_guide (dia, list->data, TRUE);
+ }
+
+ undo_set_transactionpoint (dia->undo);
+}
diff --git a/app/diagram.h b/app/diagram.h
index e2546f3b..735205cb 100644
--- a/app/diagram.h
+++ b/app/diagram.h
@@ -26,6 +26,7 @@ typedef struct _Diagram Diagram;
#include "diagramdata.h"
#include "undo.h"
#include "diagrid.h"
+#include "guide.h"
G_BEGIN_DECLS
@@ -51,12 +52,8 @@ struct _Diagram {
Color pagebreak_color; /*!< just to show page breaks */
DiaGrid grid; /*!< the display grid */
- /*! almost completely unused guides (load and save code is there) */
- struct {
- /* sorted arrays of the guides for the diagram */
- real *hguides, *vguides;
- guint nhguides, nvguides;
- } guides;
+ GList *guides; /*!< list of guides */
+ Color guide_color; /*!< color for guides */
DiagramData *data; /*! just for compatibility, now that the Diagram _is_ and not _has_ DiagramData */
@@ -141,6 +138,43 @@ void dia_diagram_set_file (Diagram *self,
GFile *file);
GFile *dia_diagram_get_file (Diagram *self);
+/** Add a guide to the diagram at the given position and orientation.
+ * Update the undo stack if "push_undo" is true. */
+Guide *diagram_add_guide (Diagram *dia, real position, GtkOrientation orientation, gboolean push_undo);
+
+/** Pick a guide within (epsilon_x, epsilon_y) distance of (x, y).
+ * Return NULL if no such guide exists. */
+Guide *diagram_pick_guide (Diagram *dia,
+ gdouble x,
+ gdouble y,
+ gdouble epsilon_x,
+ gdouble epsilon_y);
+
+
+/** Pick a *horizontal* guide within (epsilon_x, epsilon_y) distance of (x, y).
+ * Return NULL if no such guide exists. */
+Guide *diagram_pick_guide_h (Diagram *dia,
+ gdouble x,
+ gdouble y,
+ gdouble epsilon_x,
+ gdouble epsilon_y);
+
+/** Pick a *vertical* guide within (epsilon_x, epsilon_y) distance of (x, y).
+ * Return NULL if no such guide exists. */
+Guide *diagram_pick_guide_v (Diagram *dia,
+ gdouble x,
+ gdouble y,
+ gdouble epsilon_x,
+ gdouble epsilon_y);
+
+/** Remove the given guide from the diagram.
+ * Update the undo stack if "push_undo" is true. */
+void diagram_remove_guide (Diagram *dia, Guide *guide, gboolean push_undo);
+
+/** Remove all guides from the diagram. Updates undo stack. */
+void diagram_remove_all_guides (Diagram *dia);
+
+
G_END_DECLS
#endif /* DIAGRAM_H */
diff --git a/app/display.c b/app/display.c
index 081382c3..6fa5df61 100644
--- a/app/display.c
+++ b/app/display.c
@@ -228,6 +228,17 @@ new_display(Diagram *dia)
if (preset != 0)
ddisp->grid.snap = (preset > 0 ? TRUE : FALSE);
+ ddisp->guides_visible = prefs.guides_visible;
+ preset = GPOINTER_TO_INT (g_object_get_data (G_OBJECT(dia), "show-guides"));
+ if (preset != 0) {
+ ddisp->guides_visible = (preset > 0 ? TRUE : FALSE);
+ }
+ ddisp->guides_snap = prefs.guides_snap;
+ preset = GPOINTER_TO_INT (g_object_get_data (G_OBJECT(dia), "snap-to-guides"));
+ if (preset != 0) {
+ ddisp->guides_snap = (preset > 0 ? TRUE : FALSE);
+ }
+
ddisp->show_cx_pts = prefs.show_cx_pts;
preset = GPOINTER_TO_INT (g_object_get_data (G_OBJECT(dia), "show-connection-points"));
if (preset != 0)
@@ -267,6 +278,10 @@ new_display(Diagram *dia)
ddisp->visible = visible;
+ ddisp->is_dragging_new_guideline = FALSE;
+ ddisp->dragged_new_guideline_position = 0;
+ ddisp->dragged_new_guideline_orientation = GTK_ORIENTATION_HORIZONTAL;
+
initialize_display_widgets(ddisp);
return ddisp; /* set the user data */
}
@@ -507,6 +522,7 @@ ddisplay_render_pixmap (DDisplay *ddisp,
/* Draw grid */
grid_draw (ddisp, update);
pagebreak_draw (ddisp, update);
+ guidelines_draw (ddisp, update);
#ifdef TRACES
timer = g_timer_new();
@@ -1153,15 +1169,19 @@ display_update_menu_state(DDisplay *ddisp)
GtkToggleAction *rulers;
GtkToggleAction *visible_grid;
GtkToggleAction *snap_to_grid;
+ GtkToggleAction *visible_guides;
+ GtkToggleAction *snap_to_guides;
GtkToggleAction *show_cx_pts;
GtkToggleAction *antialiased;
gboolean scrollbars_shown;
- rulers = GTK_TOGGLE_ACTION (menus_get_action ("ViewShowrulers"));
- visible_grid = GTK_TOGGLE_ACTION (menus_get_action ("ViewShowgrid"));
- snap_to_grid = GTK_TOGGLE_ACTION (menus_get_action ("ViewSnaptogrid"));
- show_cx_pts = GTK_TOGGLE_ACTION (menus_get_action ("ViewShowconnectionpoints"));
- antialiased = GTK_TOGGLE_ACTION (menus_get_action ("ViewAntialiased"));
+ rulers = GTK_TOGGLE_ACTION (menus_get_action ("ViewShowrulers"));
+ visible_grid = GTK_TOGGLE_ACTION (menus_get_action ("ViewShowgrid"));
+ snap_to_grid = GTK_TOGGLE_ACTION (menus_get_action ("ViewSnaptogrid"));
+ visible_guides = GTK_TOGGLE_ACTION (menus_get_action ("ViewShowguides"));
+ snap_to_guides = GTK_TOGGLE_ACTION (menus_get_action ("ViewSnaptoguides"));
+ show_cx_pts = GTK_TOGGLE_ACTION (menus_get_action ("ViewShowconnectionpoints"));
+ antialiased = GTK_TOGGLE_ACTION (menus_get_action ("ViewAntialiased"));
gtk_action_set_sensitive (menus_get_action ("ViewAntialiased"),
g_type_from_name ("DiaCairoInteractiveRenderer") != 0);
@@ -1178,6 +1198,10 @@ display_update_menu_state(DDisplay *ddisp)
ddisp->grid.visible);
gtk_toggle_action_set_active (snap_to_grid,
ddisp->grid.snap);
+ gtk_toggle_action_set_active (visible_guides,
+ ddisp->guides_visible);
+ gtk_toggle_action_set_active (snap_to_guides,
+ ddisp->guides_snap);
gtk_toggle_action_set_active (show_cx_pts,
ddisp->show_cx_pts);
@@ -1426,6 +1450,9 @@ display_set_active(DDisplay *ddisp)
/* Object snapping */
ddisplay_set_snap_to_objects (ddisp, ddisp->mainpoint_magnetism);
+ /* Snap to guides */
+ ddisplay_set_snap_to_guides (ddisp, ddisp->guides_snap);
+
display_update_menu_state (ddisp);
gtk_window_present (GTK_WINDOW(ddisp->shell));
@@ -1540,3 +1567,22 @@ ddisplay_show_all (DDisplay *ddisp)
ddisplay_add_update_all(ddisp);
ddisplay_flush(ddisp);
}
+
+
+/** Set the display's snap-to-guides setting, updating menu and button
+ * in the process */
+void
+ddisplay_set_snap_to_guides (DDisplay *ddisp, gboolean snap)
+{
+ GtkToggleAction *snap_to_guides;
+ ddisp->guides_snap = snap;
+
+ snap_to_guides = GTK_TOGGLE_ACTION (menus_get_action ("ViewSnaptoguides"));
+
+ if (is_integrated_ui ())
+ integrated_ui_toolbar_guides_snap_synchronize_to_display (ddisp);
+
+ /* Currently, this can cause double emit, but that's a small problem. */
+ gtk_toggle_action_set_active (snap_to_guides, ddisp->guides_snap);
+ ddisplay_update_statusbar (ddisp);
+}
diff --git a/app/display.h b/app/display.h
index 5ca96415..07539aab 100644
--- a/app/display.h
+++ b/app/display.h
@@ -62,6 +62,7 @@ struct _DDisplay {
GtkWidget *zoom_status;
GtkWidget *grid_status;
GtkWidget *mainpoint_status;
+ GtkWidget *guide_snap_status;
GtkWidget *modified_status;
GtkAccelGroup *accel_group;
@@ -75,7 +76,10 @@ struct _DDisplay {
Grid grid; /* the grid in this display */
- gboolean show_cx_pts; /* Connection points toggle boolean */
+ gboolean guides_visible; /* Whether guides are visible. */
+ gboolean guides_snap; /* Whether to snap to guides. */
+
+ gboolean show_cx_pts; /* Connection points toggle boolean */
gboolean autoscroll;
gboolean mainpoint_magnetism; /* Mainpoints snapped from entire obj*/
@@ -108,6 +112,11 @@ struct _DDisplay {
/* Rember the last clicked point per display, but in diagram coordinates */
Point clicked_position;
+
+ /* For dragging a new guideline. */
+ gboolean is_dragging_new_guideline;
+ gdouble dragged_new_guideline_position;
+ GtkOrientation dragged_new_guideline_orientation;
};
extern GdkCursor *default_cursor;
@@ -143,6 +152,7 @@ void ddisplay_zoom_middle(DDisplay *ddisp, real magnify);
void ddisplay_zoom_centered(DDisplay *ddisp, Point *point, real magnify);
void ddisplay_set_snap_to_grid(DDisplay *ddisp, gboolean snap);
+void ddisplay_set_snap_to_guides(DDisplay *ddisp, gboolean snap);
void ddisplay_set_snap_to_objects(DDisplay *ddisp, gboolean magnetic);
void ddisplay_set_renderer(DDisplay *ddisp, int aa_renderer);
void ddisplay_resize_canvas(DDisplay *ddisp,
diff --git a/app/grid.c b/app/grid.c
index 49648347..516667b7 100644
--- a/app/grid.c
+++ b/app/grid.c
@@ -377,9 +377,124 @@ pagebreak_draw (DDisplay *ddisp, DiaRectangle *update)
}
}
+
+void
+guidelines_draw (DDisplay *ddisp, DiaRectangle *update)
+{
+ Diagram *dia = ddisp->diagram;
+ DiaRenderer *renderer = ddisp->renderer;
+ GList *list;
+ real line_width;
+
+ int width = dia_interactive_renderer_get_width_pixels (DIA_INTERACTIVE_RENDERER (ddisp->renderer));
+ int height = dia_interactive_renderer_get_height_pixels (DIA_INTERACTIVE_RENDERER (ddisp->renderer));
+
+ Color guideline_color = dia->guide_color;
+
+ if (!dia) {
+ return;
+ }
+
+ /* Make the line width a little bigger than hairline. */
+ line_width = ddisplay_untransform_length (ddisp, 2);
+
+ dia_renderer_set_linewidth (renderer, line_width);
+ dia_renderer_set_linestyle (renderer, LINESTYLE_SOLID, 0.0);
+
+ if (ddisp->guides_visible) {
+ list = dia->guides;
+ while (list) {
+ int x;
+ int y;
+ Guide *guide = list->data;
+
+ switch (guide->orientation) {
+ case GTK_ORIENTATION_HORIZONTAL:
+ ddisplay_transform_coords (ddisp, 0, guide->position, &x, &y);
+ dia_interactive_renderer_draw_pixel_line (DIA_INTERACTIVE_RENDERER (renderer),
+ 0, y, width, y, &guideline_color);
+ break;
+
+ case GTK_ORIENTATION_VERTICAL:
+ ddisplay_transform_coords (ddisp, guide->position, 0, &x, &y);
+ dia_interactive_renderer_draw_pixel_line (DIA_INTERACTIVE_RENDERER (renderer),
+ x, 0, x, height, &guideline_color);
+ break;
+
+ default:
+ g_print ("Should not have reached this.\n");
+ break;
+ }
+
+ list = g_list_next (list);
+ }
+ }
+
+ /* NOTE: We can still drag new guides even if guide visibility
+ * is set to off (like in GIMP). */
+ if (ddisp->is_dragging_new_guideline) {
+ int x;
+ int y;
+
+ switch (ddisp->dragged_new_guideline_orientation) {
+ case GTK_ORIENTATION_HORIZONTAL:
+ ddisplay_transform_coords (ddisp, 0, ddisp->dragged_new_guideline_position, &x, &y);
+ dia_interactive_renderer_draw_pixel_line (DIA_INTERACTIVE_RENDERER (renderer),
+ 0, y, width, y, &guideline_color);
+ break;
+
+ case GTK_ORIENTATION_VERTICAL:
+ ddisplay_transform_coords (ddisp, ddisp->dragged_new_guideline_position, 0, &x, &y);
+ dia_interactive_renderer_draw_pixel_line (DIA_INTERACTIVE_RENDERER (renderer),
+ x, 0, x, height, &guideline_color);
+ break;
+
+ default:
+ g_print ("Should not have reached this.\n");
+ break;
+ }
+ }
+}
+
+
+/* For guides. */
+#define FUNSCALEX(s,x) ((x) / (s)->zoom_factor)
+#define FUNSCALEY(s,y) ((y) / (s)->zoom_factor)
+
+
void
snap_to_grid (DDisplay *ddisp, coord *x, coord *y)
{
+ /* First snap to guides - only if they are visible and the setting is
+ * turned on. */
+ if (ddisp->guides_snap && ddisp->guides_visible) {
+ Guide *guide_h;
+ Guide *guide_v;
+ const gint snap_distance = prefs.snap_distance;
+
+ guide_h = diagram_pick_guide_h (ddisp->diagram, *x, *y,
+ FUNSCALEX (ddisp, snap_distance),
+ FUNSCALEY (ddisp, snap_distance));
+
+ guide_v = diagram_pick_guide_v (ddisp->diagram, *x, *y,
+ FUNSCALEX (ddisp, snap_distance),
+ FUNSCALEY (ddisp, snap_distance));
+
+ if (guide_h) {
+ *y = guide_h->position;
+ }
+
+ if (guide_v) {
+ *x = guide_v->position;
+ }
+
+ /* Assume this takes priority over grid. */
+ if (guide_h || guide_v) {
+ return;
+ }
+ }
+
+ /* Snap to grid. */
if (ddisp->grid.snap) {
if (ddisp->diagram->grid.hex) {
real width_x = ddisp->diagram->grid.hex_size;
diff --git a/app/grid.h b/app/grid.h
index df835aae..910d88b7 100644
--- a/app/grid.h
+++ b/app/grid.h
@@ -32,6 +32,7 @@ struct _Grid {
void grid_draw(DDisplay *ddisp, DiaRectangle *update);
void pagebreak_draw(DDisplay *ddisp, DiaRectangle *update);
+void guidelines_draw(DDisplay *ddisp, DiaRectangle *update);
void snap_to_grid(DDisplay *ddisp, coord *x, coord *y);
gboolean grid_step (DDisplay *ddisp, GtkOrientation orientation,
diff --git a/app/guide_tool.c b/app/guide_tool.c
new file mode 100644
index 00000000..4abadce8
--- /dev/null
+++ b/app/guide_tool.c
@@ -0,0 +1,221 @@
+/* Dia -- an diagram creation/manipulation program
+ * Copyright (C) 1998 Alexander Larsson
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#include <config.h>
+
+#include <gdk/gdk.h>
+
+#include "cursor.h"
+#include "guide_tool.h"
+#include "undo.h"
+#include "diainteractiverenderer.h"
+
+#define GUIDE_POSITION_UNDEFINED G_MINDOUBLE
+
+/* The original position of the current guide
+ * before we started dragging it. Need to keep track of it for
+ * undo moving/deleting guides. */
+static real guide_original_pos = 0;
+
+struct _GuideTool {
+ Tool tool;
+
+ Guide *guide;
+ real position;
+ GtkOrientation orientation;
+ int ruler_height;
+};
+
+
+
+static void
+guide_button_release(GuideTool *tool, GdkEventButton *event, DDisplay *ddisp);
+
+static void
+guide_motion(GuideTool *tool, GdkEventMotion *event, DDisplay *ddisp);
+
+
+
+void _guide_tool_start_new (DDisplay *display,
+ GtkOrientation orientation)
+{
+ _guide_tool_start (display, orientation, NULL);
+}
+
+void _guide_tool_start (DDisplay *display,
+ GtkOrientation orientation,
+ Guide *guide)
+{
+ tool_select(GUIDE_TOOL, guide, GINT_TO_POINTER(orientation), NULL, 0);
+ display->dragged_new_guideline_orientation = orientation;
+}
+
+Tool *create_guide_tool(void)
+{
+ GuideTool *tool;
+
+ tool = g_new0(GuideTool, 1);
+ tool->tool.type = GUIDE_TOOL;
+
+ tool->tool.button_release_func = (ButtonReleaseFunc) &guide_button_release;
+ tool->tool.motion_func = (MotionFunc) &guide_motion;
+
+ tool->guide = NULL;
+ tool->position = GUIDE_POSITION_UNDEFINED;
+ tool->orientation = GTK_ORIENTATION_HORIZONTAL; /* Default. */
+
+ return (Tool *)tool;
+}
+
+void free_guide_tool(Tool *tool)
+{
+ GuideTool *gtool = (GuideTool *)tool;
+ g_free(gtool);
+}
+
+static void
+guide_button_release(GuideTool *tool, GdkEventButton *event,
+ DDisplay *ddisp)
+{
+ /* Reset. */
+ ddisp->is_dragging_new_guideline = FALSE;
+
+ if (tool->position == GUIDE_POSITION_UNDEFINED)
+ {
+ /* Dragged out of bounds, so remove the guide. */
+ if (tool->guide) {
+ tool->guide->position = guide_original_pos; /* So that when we undo, it goes back to original
position. */
+ diagram_remove_guide (ddisp->diagram, tool->guide, TRUE);
+ tool->guide = NULL;
+ }
+ }
+ else
+ {
+ if (!tool->guide) {
+ /* Add a new guide. */
+ diagram_add_guide (ddisp->diagram, tool->position, tool->orientation, TRUE);
+ }
+ else
+ {
+ /* Moved an existing guide, so update the undo stack. */
+ dia_move_guide_change_new (ddisp->diagram, tool->guide, guide_original_pos, tool->position);
+ undo_set_transactionpoint (ddisp->diagram->undo);
+ }
+ }
+
+ diagram_add_update_all(ddisp->diagram);
+ diagram_modified(ddisp->diagram);
+ diagram_flush(ddisp->diagram);
+
+ tool_reset();
+}
+
+static void
+guide_motion(GuideTool *tool, GdkEventMotion *event, DDisplay *ddisp)
+{
+ gint tx, ty;
+ Point to;
+ gint disp_width;
+ gint disp_height;
+
+ disp_width = dia_interactive_renderer_get_width_pixels (DIA_INTERACTIVE_RENDERER (ddisp->renderer));
+ disp_height = dia_interactive_renderer_get_height_pixels (DIA_INTERACTIVE_RENDERER (ddisp->renderer));
+
+ /* Event coordinates. */
+ tx = event->x;
+ ty = event->y;
+
+ /* Minus ruler height. */
+ if (tool->orientation == GTK_ORIENTATION_HORIZONTAL)
+ ty -= tool->ruler_height;
+ else
+ tx -= tool->ruler_height;
+
+ /* Diagram coordinates. */
+ ddisplay_untransform_coords(ddisp, tx, ty, &to.x, &to.y);
+
+ if (tx < 0 || tx >= disp_width ||
+ ty < 0 || ty >= disp_height)
+ {
+ /* Out of bounds. */
+ tool->position = GUIDE_POSITION_UNDEFINED;
+
+ /* Cancel dragging a new guide. */
+ ddisp->is_dragging_new_guideline = FALSE;
+ ddisp->dragged_new_guideline_position = 0;
+
+ if(tool->guide)
+ {
+ /* Deleting an existing guide. Hide it for now. */
+ tool->guide->position = G_MAXDOUBLE;
+ }
+ }
+ else
+ {
+ /* In bounds - add or move a guide. */
+ if (tool->orientation == GTK_ORIENTATION_HORIZONTAL)
+ tool->position = to.y;
+ else
+ tool->position = to.x;
+
+ if(tool->guide)
+ {
+ /* Move existing guide. */
+ tool->guide->position = tool->position;
+ }
+ else
+ {
+ /* Add new guide. */
+ ddisp->is_dragging_new_guideline = TRUE;
+ ddisp->dragged_new_guideline_position = tool->position;
+ }
+ }
+
+ diagram_add_update_all(ddisp->diagram);
+ diagram_modified(ddisp->diagram);
+ ddisplay_flush(ddisp);
+}
+
+void guide_tool_set_ruler_height(Tool *tool, int height)
+{
+ GuideTool *gtool = (GuideTool *)tool;
+ gtool->ruler_height = height;
+}
+
+void guide_tool_start_edit (DDisplay *display,
+ Guide *guide)
+{
+ _guide_tool_start (display, guide->orientation, guide);
+
+ if(guide)
+ {
+ /* Store original position for undo stack. */
+ guide_original_pos = guide->position;
+ }
+}
+
+void guide_tool_set_guide(Tool *tool, Guide *guide)
+{
+ GuideTool *gtool = (GuideTool *)tool;
+ gtool->guide = guide;
+}
+
+void guide_tool_set_orientation(Tool *tool, GtkOrientation orientation)
+{
+ GuideTool *gtool = (GuideTool *)tool;
+ gtool->orientation = orientation;
+}
diff --git a/app/guide_tool.h b/app/guide_tool.h
new file mode 100644
index 00000000..1e003514
--- /dev/null
+++ b/app/guide_tool.h
@@ -0,0 +1,54 @@
+/* Dia -- an diagram creation/manipulation program
+ * Copyright (C) 1998 Alexander Larsson
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#ifndef GUIDE_TOOL_H
+#define GUIDE_TOOL_H
+
+#include "guide.h"
+#include "tool.h"
+
+typedef struct _GuideTool GuideTool;
+
+Tool *create_guide_tool(void);
+void free_guide_tool(Tool *tool);
+
+/** Start dragging a new guide. */
+void _guide_tool_start_new (DDisplay *display,
+ GtkOrientation orientation);
+
+/** Start editing (i.e. moving) an existing guide. */
+void guide_tool_start_edit (DDisplay *display,
+ Guide *guide);
+
+/** Start using the guide tool.
+ * If guide is not NULL, then start editing that guide.
+ * If guide is NULL, then start adding a new guide. */
+void _guide_tool_start (DDisplay *display,
+ GtkOrientation orientation,
+ Guide *guide);
+
+/** Inform the tool of the ruler height. Required to calculate
+ * the position of the guide on the page. */
+void guide_tool_set_ruler_height(Tool *tool, int height);
+
+/** Set the guide to edit. */
+void guide_tool_set_guide(Tool *tool, Guide *guide);
+
+/** Set the orientation of the tool. */
+void guide_tool_set_orientation(Tool *tool, GtkOrientation orientation);
+
+#endif /* GUIDE_TOOL_H */
diff --git a/app/icons/dia-guides-snap-off.png b/app/icons/dia-guides-snap-off.png
new file mode 100644
index 00000000..13ad1430
Binary files /dev/null and b/app/icons/dia-guides-snap-off.png differ
diff --git a/app/icons/dia-guides-snap-off.svg b/app/icons/dia-guides-snap-off.svg
new file mode 100644
index 00000000..ab1c3e2a
--- /dev/null
+++ b/app/icons/dia-guides-snap-off.svg
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="24"
+ height="24"
+ viewBox="0 0 6.3499999 6.3500002"
+ version="1.1"
+ id="svg8"
+ inkscape:version="0.92.4 5da689c313, 2019-01-14"
+ sodipodi:docname="dia-guides-snap-off.svg">
+ <defs
+ id="defs2" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="22.84"
+ inkscape:cx="13.354502"
+ inkscape:cy="10.620889"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ units="px"
+ showguides="false"
+ inkscape:window-width="1366"
+ inkscape:window-height="704"
+ inkscape:window-x="0"
+ inkscape:window-y="27"
+ inkscape:window-maximized="1">
+ <inkscape:grid
+ type="xygrid"
+ id="grid817" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata5">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(0,-290.64998)">
+ <rect
+
style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#241f31;stroke-width:0.26061457;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke
fill markers"
+ id="rect815"
+ width="5.5602164"
+ height="5.560216"
+ x="0.39489198"
+ y="291.04486" />
+ <rect
+
style="opacity:1;fill:#26a269;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.3266578;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke
fill markers"
+ id="rect846"
+ width="5.2916665"
+ height="1.0583333"
+ x="0.52916664"
+ y="294.35413" />
+ <rect
+
style="opacity:1;fill:#26a269;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.32665783;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke
fill markers"
+ id="rect846-3"
+ width="1.0583333"
+ height="5.2916665"
+ x="3.7041667"
+ y="291.17914" />
+ <circle
+
style="opacity:1;fill:#a51d2d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.38133451;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke
fill markers"
+ id="path863"
+ cx="2.1166668"
+ cy="292.76663"
+ r="1.0583334" />
+ </g>
+</svg>
diff --git a/app/icons/dia-guides-snap-on.png b/app/icons/dia-guides-snap-on.png
new file mode 100644
index 00000000..0a1cb054
Binary files /dev/null and b/app/icons/dia-guides-snap-on.png differ
diff --git a/app/icons/dia-guides-snap-on.svg b/app/icons/dia-guides-snap-on.svg
new file mode 100644
index 00000000..3ea4a124
--- /dev/null
+++ b/app/icons/dia-guides-snap-on.svg
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="24"
+ height="24"
+ viewBox="0 0 6.3499999 6.3500002"
+ version="1.1"
+ id="svg8"
+ inkscape:version="0.92.4 5da689c313, 2019-01-14"
+ sodipodi:docname="dia-guides-snap-on.svg">
+ <defs
+ id="defs2" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="39.76"
+ inkscape:cx="13.354502"
+ inkscape:cy="7.1182622"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ units="px"
+ showguides="false"
+ inkscape:window-width="1366"
+ inkscape:window-height="704"
+ inkscape:window-x="0"
+ inkscape:window-y="27"
+ inkscape:window-maximized="1">
+ <inkscape:grid
+ type="xygrid"
+ id="grid817" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata5">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(0,-290.64998)">
+ <rect
+
style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#241f31;stroke-width:0.26061457;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke
fill markers"
+ id="rect815"
+ width="5.5602164"
+ height="5.560216"
+ x="0.39489198"
+ y="291.04486" />
+ <rect
+
style="opacity:1;fill:#26a269;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.3266578;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke
fill markers"
+ id="rect846"
+ width="5.2916665"
+ height="1.0583333"
+ x="0.52916664"
+ y="294.35413" />
+ <rect
+
style="opacity:1;fill:#26a269;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.32665783;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke
fill markers"
+ id="rect846-3"
+ width="1.0583333"
+ height="5.2916665"
+ x="3.7041667"
+ y="291.17914" />
+ <circle
+
style="opacity:1;fill:#a51d2d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.38133451;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke
fill markers"
+ id="path863"
+ cx="4.2333336"
+ cy="294.8833"
+ r="1.0583334" />
+ </g>
+</svg>
diff --git a/app/interface.c b/app/interface.c
index 377efb68..a1918b06 100644
--- a/app/interface.c
+++ b/app/interface.c
@@ -50,6 +50,35 @@
#include <gdk-pixbuf/gdk-pixbuf.h>
+#include "guide_tool.h"
+
+#include <glib/gprintf.h>
+
+static gboolean _ddisplay_hruler_button_press (GtkWidget *widget,
+ GdkEventButton *bevent,
+ DDisplay *ddisp);
+
+static gboolean _ddisplay_vruler_button_press (GtkWidget *widget,
+ GdkEventButton *bevent,
+ DDisplay *ddisp);
+
+static gboolean _ddisplay_ruler_button_press (GtkWidget *widget,
+ GdkEventButton *event,
+ DDisplay *ddisp,
+ GtkOrientation orientation);
+
+static gboolean _ddisplay_ruler_button_release (GtkWidget *widget,
+ GdkEventButton *bevent,
+ DDisplay *ddisp);
+
+static gboolean _ddisplay_hruler_motion_notify (GtkWidget *widget,
+ GdkEventMotion *event,
+ DDisplay *ddisp);
+
+static gboolean _ddisplay_vruler_motion_notify (GtkWidget *widget,
+ GdkEventMotion *event,
+ DDisplay *ddisp);
+
static void
dia_dnd_file_drag_data_received (GtkWidget *widget,
GdkDragContext *context,
@@ -154,6 +183,18 @@ interface_toggle_mainpoint_magnetism(GtkWidget *widget, gpointer data)
ddisplay_flush(ddisp);
}
+
+static void
+interface_toggle_snap_to_guides (GtkWidget *widget, gpointer data)
+{
+ DDisplay *ddisp = (DDisplay *) data;
+ ddisplay_set_snap_to_guides (ddisp,
+ gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)));
+ ddisplay_add_update_all (ddisp);
+ ddisplay_flush (ddisp);
+}
+
+
static gint
origin_button_press(GtkWidget *widget, GdkEventButton *event, gpointer data)
{
@@ -489,6 +530,32 @@ _ddisplay_setup_rulers (DDisplay *ddisp, GtkWidget *shell, GtkWidget *table)
ddisp->hrule = dia_ruler_new (GTK_ORIENTATION_HORIZONTAL, shell, ddisp);
ddisp->vrule = dia_ruler_new (GTK_ORIENTATION_VERTICAL, shell, ddisp);
+ /* Callbacks for adding guides - horizontal ruler. */
+ g_signal_connect (ddisp->hrule, "button-press-event",
+ G_CALLBACK (_ddisplay_hruler_button_press),
+ ddisp);
+
+ g_signal_connect (ddisp->hrule, "button_release_event",
+ G_CALLBACK (_ddisplay_ruler_button_release),
+ ddisp);
+
+ g_signal_connect (ddisp->hrule, "motion_notify_event",
+ G_CALLBACK (_ddisplay_hruler_motion_notify),
+ ddisp);
+
+ /* Callbacks for adding guides - vertical ruler. */
+ g_signal_connect (ddisp->vrule, "button-press-event",
+ G_CALLBACK (_ddisplay_vruler_button_press),
+ ddisp);
+
+ g_signal_connect (ddisp->vrule, "button_release_event",
+ G_CALLBACK (_ddisplay_ruler_button_release),
+ ddisp);
+
+ g_signal_connect (ddisp->vrule, "motion_notify_event",
+ G_CALLBACK (_ddisplay_vruler_motion_notify),
+ ddisp);
+
/* harder to change position in the table, but we did not do it for years ;) */
gtk_table_attach (GTK_TABLE (table), ddisp->hrule, 1, 2, 0, 1,
GTK_EXPAND | GTK_SHRINK | GTK_FILL, GTK_FILL, 0, 0);
@@ -681,6 +748,7 @@ use_integrated_ui_for_display_shell(DDisplay *ddisp, char *title)
integrated_ui_toolbar_grid_snap_synchronize_to_display (ddisp);
integrated_ui_toolbar_object_snap_synchronize_to_display (ddisp);
+ integrated_ui_toolbar_guides_snap_synchronize_to_display (ddisp);
/* set the focus to the canvas area */
gtk_widget_grab_focus (ddisp->canvas);
@@ -830,6 +898,16 @@ create_display_shell(DDisplay *ddisp,
gtk_box_pack_start (GTK_BOX (status_hbox), ddisp->mainpoint_status,
FALSE, FALSE, 0);
+ ddisp->guide_snap_status = dia_toggle_button_new_with_icon_names ("dia-guides-snap-on",
+ "dia-guides-snap-off");
+
+ g_signal_connect(G_OBJECT(ddisp->guide_snap_status), "toggled",
+ G_CALLBACK (interface_toggle_snap_to_guides), ddisp);
+ gtk_widget_set_tooltip_text(ddisp->guide_snap_status,
+ _("Toggles snap-to-guides for this window."));
+ gtk_box_pack_start (GTK_BOX (status_hbox), ddisp->guide_snap_status,
+ FALSE, FALSE, 0);
+
/* Statusbar */
ddisp->modified_status = gtk_statusbar_new ();
@@ -846,6 +924,7 @@ create_display_shell(DDisplay *ddisp,
gtk_widget_show (zoom_label);
gtk_widget_show (ddisp->grid_status);
gtk_widget_show (ddisp->mainpoint_status);
+ gtk_widget_show (ddisp->guide_snap_status);
gtk_widget_show (ddisp->modified_status);
gtk_widget_show (status_hbox);
gtk_widget_show (table);
@@ -1236,3 +1315,102 @@ integrated_ui_statusbar_show (gboolean show)
gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), show);
}
}
+
+
+static gboolean
+_ddisplay_hruler_button_press (GtkWidget *widget,
+ GdkEventButton *event,
+ DDisplay *ddisp)
+{
+ return _ddisplay_ruler_button_press (widget, event, ddisp,
+ GTK_ORIENTATION_HORIZONTAL);
+}
+
+
+static gboolean
+_ddisplay_vruler_button_press (GtkWidget *widget,
+ GdkEventButton *event,
+ DDisplay *ddisp)
+{
+ return _ddisplay_ruler_button_press (widget, event, ddisp,
+ GTK_ORIENTATION_VERTICAL);
+}
+
+
+static gboolean
+_ddisplay_ruler_button_press (GtkWidget *widget,
+ GdkEventButton *event,
+ DDisplay *ddisp,
+ GtkOrientation orientation)
+{
+ /* Start adding a new guide if the left button was pressed. */
+ if (event->type == GDK_BUTTON_PRESS && event->button == 1) {
+ _guide_tool_start_new (ddisp, orientation);
+ }
+
+ return FALSE;
+}
+
+
+static gboolean
+_ddisplay_ruler_button_release (GtkWidget *widget,
+ GdkEventButton *event,
+ DDisplay *ddisp)
+{
+ /* Hack to get this triggered. */
+ if(active_tool->type == GUIDE_TOOL)
+ {
+ if (active_tool->button_release_func)
+ {
+ (*active_tool->button_release_func) (active_tool, event, ddisp);
+ }
+ }
+
+ return FALSE;
+}
+
+
+static gboolean
+_ddisplay_hruler_motion_notify (GtkWidget *widget,
+ GdkEventMotion *event,
+ DDisplay *ddisp)
+{
+ /* Hack to get this triggered. */
+ if(active_tool->type == GUIDE_TOOL) {
+ if (active_tool->motion_func) {
+
+ /* Minus ruler height. */
+ GtkRequisition ruler_requisition;
+ gtk_widget_size_request (widget, &ruler_requisition);
+ guide_tool_set_ruler_height(active_tool, ruler_requisition.height);
+
+ /* Do the move. */
+ (*active_tool->motion_func) (active_tool, event, ddisp);
+ }
+ }
+
+ return FALSE;
+}
+
+
+static gboolean
+_ddisplay_vruler_motion_notify (GtkWidget *widget,
+ GdkEventMotion *event,
+ DDisplay *ddisp)
+{
+ /* Hack to get this triggered. */
+ if(active_tool->type == GUIDE_TOOL) {
+ if (active_tool->motion_func) {
+
+ /* Minus ruler width. */
+ GtkRequisition ruler_requisition;
+ gtk_widget_size_request (widget, &ruler_requisition);
+ guide_tool_set_ruler_height(active_tool, ruler_requisition.width);
+
+ /* Do the move. */
+ (*active_tool->motion_func) (active_tool, event, ddisp);
+ }
+ }
+
+ return FALSE;
+}
diff --git a/app/load_save.c b/app/load_save.c
index e5315b34..79fd40d2 100644
--- a/app/load_save.c
+++ b/app/load_save.c
@@ -377,7 +377,7 @@ diagram_data_load(const gchar *filename, DiagramData *data, DiaContext *ctx, voi
xmlDocPtr doc;
xmlNodePtr root;
xmlNodePtr diagramdata;
- xmlNodePtr paperinfo, gridinfo, guideinfo;
+ xmlNodePtr paperinfo, gridinfo;
xmlNodePtr layer_node;
AttributeNode attr;
DiaLayer *layer;
@@ -564,39 +564,50 @@ diagram_data_load(const gchar *filename, DiagramData *data, DiaContext *ctx, voi
data_color(attribute_first_data(attr), &diagram->grid.colour, ctx);
}
}
+
if (diagram) {
- attr = composite_find_attribute(diagramdata, "guides");
+ attr = composite_find_attribute (diagramdata, "guides");
if (attr != NULL) {
- guint i;
- DataNode guide;
+ DataNode guides_data;
- guideinfo = attribute_first_data(attr);
+ /* Clear old guides. */
+ g_list_free (diagram->guides);
+ diagram->guides = NULL;
- attr = composite_find_attribute(guideinfo, "hguides");
- if (attr != NULL) {
- diagram->guides.nhguides = attribute_num_data(attr);
- g_free(diagram->guides.hguides);
- diagram->guides.hguides = g_new(real, diagram->guides.nhguides);
+ /* Load new guides. */
+ guides_data = attribute_first_data (attr);
+ while (guides_data) {
+ real position = 0;
+ GtkOrientation orientation = GTK_ORIENTATION_HORIZONTAL;
- guide = attribute_first_data(attr);
- for (i = 0; i < diagram->guides.nhguides; i++, guide = data_next(guide))
- diagram->guides.hguides[i] = data_real(guide, ctx);
- }
- attr = composite_find_attribute(guideinfo, "vguides");
- if (attr != NULL) {
- diagram->guides.nvguides = attribute_num_data(attr);
- g_free(diagram->guides.vguides);
- diagram->guides.vguides = g_new(real, diagram->guides.nvguides);
+ attr = composite_find_attribute (guides_data, "position");
+ if(attr != NULL) {
+ position = data_real (attribute_first_data (attr), ctx);
+ }
+
+ attr = composite_find_attribute (guides_data, "orientation");
+ if (attr != NULL) {
+ orientation = data_int (attribute_first_data (attr), ctx);
+ }
- guide = attribute_first_data(attr);
- for (i = 0; i < diagram->guides.nvguides; i++, guide = data_next(guide))
- diagram->guides.vguides[i] = data_real(guide, ctx);
+ diagram_add_guide (diagram, position, orientation, FALSE);
+
+ guides_data = data_next (guides_data);
}
}
+
+ /* Guide color. */
+ diagram->guide_color = prefs.new_diagram.guide_color;
+ attr = composite_find_attribute (diagramdata, "guide_color");
+ if (attr != NULL) {
+ data_color (attribute_first_data (attr), &diagram->guide_color, ctx);
+ }
}
+
/* parse some display settings */
if (diagram) {
- attr = composite_find_attribute(diagramdata, "display");
+ attr = composite_find_attribute (diagramdata, "display");
+
if (attr != NULL) {
DataNode dispinfo;
@@ -614,6 +625,13 @@ diagram_data_load(const gchar *filename, DiagramData *data, DiaContext *ctx, voi
g_object_set_data(G_OBJECT(diagram),
"snap-to-grid", GINT_TO_POINTER (data_boolean(attribute_first_data(attr), ctx) ? 1 : -1));
+ attr = composite_find_attribute(dispinfo, "snap-to-guides");
+ if (attr != NULL) {
+ g_object_set_data (G_OBJECT (diagram),
+ "snap-to-guides",
+ GINT_TO_POINTER (data_boolean (attribute_first_data (attr), ctx) ? 1 : -1));
+ }
+
attr = composite_find_attribute(dispinfo, "snap-to-object");
if (attr != NULL)
g_object_set_data(G_OBJECT(diagram),
@@ -624,6 +642,14 @@ diagram_data_load(const gchar *filename, DiagramData *data, DiaContext *ctx, voi
g_object_set_data(G_OBJECT(diagram),
"show-grid", GINT_TO_POINTER (data_boolean(attribute_first_data(attr), ctx) ? 1 : -1));
+
+ attr = composite_find_attribute(dispinfo, "show-guides");
+ if (attr != NULL) {
+ g_object_set_data (G_OBJECT (diagram),
+ "show-guides",
+ GINT_TO_POINTER (data_boolean (attribute_first_data (attr), ctx) ? 1 : -1));
+ }
+
attr = composite_find_attribute(dispinfo, "show-connection-points");
if (attr != NULL)
g_object_set_data(G_OBJECT(diagram),
@@ -929,6 +955,7 @@ diagram_data_write_doc(DiagramData *data, const char *filename, DiaContext *ctx)
}
if (diagram) {
+ GList *list;
attr = new_attribute((ObjectNode)tree, "grid");
gridinfo = data_add_composite(attr, "grid", ctx);
data_add_boolean(composite_add_attribute(gridinfo, "dynamic"),
@@ -945,16 +972,26 @@ diagram_data_write_doc(DiagramData *data, const char *filename, DiaContext *ctx)
data_add_composite(gridinfo, "color", ctx);
data_add_color(attr, &diagram->grid.colour, ctx);
- attr = new_attribute((ObjectNode)tree, "guides");
- guideinfo = data_add_composite(attr, "guides", ctx);
- attr = composite_add_attribute(guideinfo, "hguides");
- for (i = 0; i < diagram->guides.nhguides; i++)
- data_add_real(attr, diagram->guides.hguides[i], ctx);
- attr = composite_add_attribute(guideinfo, "vguides");
- for (i = 0; i < diagram->guides.nvguides; i++)
- data_add_real(attr, diagram->guides.vguides[i], ctx);
+ /* Guides. */
+ attr = new_attribute ((ObjectNode) tree, "guides");
+ list = diagram->guides;
+ while (list) {
+ Guide *guide = list->data;
+
+ guideinfo = data_add_composite (attr, "guide", ctx);
+
+ data_add_real (composite_add_attribute (guideinfo, "position"), guide->position, ctx);
+ data_add_int (composite_add_attribute (guideinfo, "orientation"), guide->orientation, ctx);
+
+ list = g_list_next (list);
+ }
+
+ if (diagram) {
+ attr = new_attribute ((ObjectNode) tree, "guide_color");
+ data_add_color (attr, &diagram->guide_color, ctx);
+ }
- if (g_slist_length(diagram->displays) == 1) {
+ if (g_slist_length (diagram->displays) == 1) {
xmlNodePtr dispinfo;
/* store some display attributes */
DDisplay *ddisp = diagram->displays->data;
@@ -965,10 +1002,14 @@ diagram_data_write_doc(DiagramData *data, const char *filename, DiaContext *ctx)
ddisp->aa_renderer, ctx);
data_add_boolean(composite_add_attribute(dispinfo, "snap-to-grid"),
ddisp->grid.snap, ctx);
+ data_add_boolean(composite_add_attribute(dispinfo, "snap-to-guides"),
+ ddisp->guides_snap, ctx);
data_add_boolean(composite_add_attribute(dispinfo, "snap-to-object"),
ddisp->mainpoint_magnetism, ctx);
data_add_boolean(composite_add_attribute(dispinfo, "show-grid"),
ddisp->grid.visible, ctx);
+ data_add_boolean (composite_add_attribute (dispinfo, "show-guides"),
+ ddisp->guides_visible, ctx);
data_add_boolean(composite_add_attribute(dispinfo, "show-connection-points"),
ddisp->show_cx_pts, ctx);
}
diff --git a/app/menus.c b/app/menus.c
index bfe82028..2107d4e3 100644
--- a/app/menus.c
+++ b/app/menus.c
@@ -57,6 +57,7 @@
#define DIA_INTEGRATED_TOOLBAR_ZOOM_COMBO "dia-integrated-toolbar-zoom-combo_entry"
#define DIA_INTEGRATED_TOOLBAR_SNAP_GRID "dia-integrated-toolbar-snap-grid"
#define DIA_INTEGRATED_TOOLBAR_OBJECT_SNAP "dia-integrated-toolbar-object-snap"
+#define DIA_INTEGRATED_TOOLBAR_GUIDES_SNAP "dia-integrated-toolbar-guides-snap"
#define ZOOM_FIT _("Fit")
@@ -172,6 +173,9 @@ static const GtkActionEntry display_entries[] =
{ "ViewCloneview", NULL, N_("C_lone View"), NULL, NULL, G_CALLBACK (view_clone_view_callback) },
{ "ViewRedraw", GTK_STOCK_REFRESH, NULL, NULL, NULL, G_CALLBACK (view_redraw_callback) },
+ { "ViewGuides", NULL, N_("Guides"), NULL, NULL, NULL },
+ { "ViewNewguide", NULL, N_("New Guide..."), NULL, NULL, G_CALLBACK (view_new_guide_callback) },
+
{ "Objects", NULL, N_("_Objects"), NULL, NULL },
{ "ObjectsSendtoback", GTK_STOCK_GOTO_BOTTOM, N_("Send to _Back"), FIRST_MODIFIER "<shift>B", N_("Move
selection to the bottom"), G_CALLBACK (objects_place_under_callback) },
{ "ObjectsBringtofront", GTK_STOCK_GOTO_TOP, N_("Bring to _Front"), FIRST_MODIFIER "<shift>F", N_("Move
selection to the top"), G_CALLBACK (objects_place_over_callback) },
@@ -255,6 +259,9 @@ static const GtkToggleActionEntry display_toggle_entries[] =
{ "ViewAntialiased", NULL, N_("_Antialiased"), NULL, NULL, G_CALLBACK (view_aa_callback) },
{ "ViewShowgrid", NULL, N_("Show _Grid"), NULL, NULL, G_CALLBACK (view_visible_grid_callback) },
{ "ViewSnaptogrid", NULL, N_("_Snap to Grid"), NULL, NULL, G_CALLBACK (view_snap_to_grid_callback) },
+ { "ViewShowguides", NULL, N_("Show Guides"), NULL, NULL, G_CALLBACK (view_visible_guides_callback) },
+ { "ViewSnaptoguides", NULL, N_("Snap to Guides"), NULL, NULL, G_CALLBACK (view_snap_to_guides_callback)
},
+ { "ViewRemoveallguides", NULL, N_("Remove all Guides"), NULL, NULL, G_CALLBACK
(view_remove_all_guides_callback) },
{ "ViewSnaptoobjects", NULL, N_("Snap to _Objects"), NULL, NULL, G_CALLBACK
(view_snap_to_objects_callback) },
{ "ViewShowrulers", NULL, N_("Show _Rulers"), NULL, NULL, G_CALLBACK (view_toggle_rulers_callback) },
{ "ViewShowscrollbars", NULL, N_("Show Scrollbars"), NULL, N_("Show or hide the toolbar"), G_CALLBACK
(view_toggle_scrollbars_callback) },
@@ -355,6 +362,24 @@ integrated_ui_toolbar_object_snap_synchronize_to_display (gpointer param)
}
}
+
+/**
+ * Synchronized the snap-to-guide property button with the display.
+ * @param param Display to synchronize to.
+ */
+void
+integrated_ui_toolbar_guides_snap_synchronize_to_display (gpointer param)
+{
+ DDisplay *ddisp = param;
+ if (ddisp && ddisp->common_toolbar) {
+ GtkToggleButton *b = g_object_get_data (G_OBJECT (ddisp->common_toolbar),
+ DIA_INTEGRATED_TOOLBAR_GUIDES_SNAP);
+ gboolean active = ddisp->guides_snap? TRUE : FALSE;
+ gtk_toggle_button_set_active (b, active);
+ }
+}
+
+
/**
* Sets the Object-snap property for the active display.
* @param b Object snap toggle button.
@@ -370,6 +395,22 @@ integrated_ui_toolbar_object_snap_toggle (GtkToggleButton *b,
}
}
+
+/**
+ * Sets the Guide-snap property for the active display.
+ * @param b Guide snap toggle button.
+ * @param not_used
+ */
+static void
+integrated_ui_toolbar_guide_snap_toggle(GtkToggleButton *b, gpointer *not_used)
+{
+ DDisplay *ddisp = ddisplay_active ();
+ if (ddisp) {
+ ddisplay_set_snap_to_guides (ddisp, gtk_toggle_button_get_active (b));
+ }
+}
+
+
/**
* Synchronizes the Snap-to-grid property button with the display.
* @param param Display to synchronize to.
@@ -607,6 +648,19 @@ create_integrated_ui_toolbar (void)
w);
integrated_ui_toolbar_add_custom_item (toolbar, w);
+ /* Guide Snapping */
+ w = dia_toggle_button_new_with_icon_names ("dia-guides-snap-on",
+ "dia-guides-snap-off");
+ g_signal_connect (G_OBJECT (w),
+ "toggled",
+ G_CALLBACK (integrated_ui_toolbar_guide_snap_toggle),
+ toolbar);
+ gtk_widget_set_tooltip_text (w, _("Toggles guide snapping."));
+ g_object_set_data (G_OBJECT (toolbar),
+ DIA_INTEGRATED_TOOLBAR_GUIDES_SNAP,
+ w);
+ integrated_ui_toolbar_add_custom_item (toolbar, w);
+
sep = gtk_separator_tool_item_new ();
gtk_toolbar_insert (toolbar, sep, -1);
gtk_widget_show (GTK_WIDGET (sep));
diff --git a/app/menus.h b/app/menus.h
index b8856043..ccaea805 100644
--- a/app/menus.h
+++ b/app/menus.h
@@ -33,6 +33,7 @@ void integrated_ui_toolbar_set_zoom_text (GtkToo
const gchar *text);
void integrated_ui_toolbar_grid_snap_synchronize_to_display (gpointer ddisp);
void integrated_ui_toolbar_object_snap_synchronize_to_display (gpointer ddisp);
+void integrated_ui_toolbar_guides_snap_synchronize_to_display (gpointer ddisp);
/* TODO: rename: menus_get_integrated_ui_menubar() */
void menus_get_integrated_ui_menubar (GtkWidget **menubar,
diff --git a/app/meson.build b/app/meson.build
index 3dd80d71..308a440a 100644
--- a/app/meson.build
+++ b/app/meson.build
@@ -22,6 +22,11 @@ dia_sources = [
'layer-editor/layer_dialog.c',
'layer-editor/layer_dialog.h',
+ 'guide_tool.c',
+ 'guide_tool.h',
+ 'new_guide_dialog.c',
+ 'new_guide_dialog.h',
+
'commands.c',
'app_procs.c',
'connectionpoint_ops.c',
diff --git a/app/modify_tool.c b/app/modify_tool.c
index 0862bc31..1f218250 100644
--- a/app/modify_tool.c
+++ b/app/modify_tool.c
@@ -42,6 +42,7 @@
#include "prop_text.h"
#include "object.h"
+#include "guide_tool.h"
static DiaObject *click_select_object(DDisplay *ddisp, Point *clickedpoint,
GdkEventButton *event);
@@ -79,6 +80,9 @@ struct _ModifyTool {
modify_motion was called */
/* Undo info: */
Point *orig_pos;
+
+ /* Guide info: */
+ Guide *guide;
};
@@ -257,6 +261,11 @@ static int do_if_clicked_handle(DDisplay *ddisp, ModifyTool *tool,
return FALSE;
}
+
+#define FUNSCALEX(s,x) ((x) / (s)->zoom_factor)
+#define FUNSCALEY(s,y) ((y) / (s)->zoom_factor)
+
+
static void
modify_button_press(ModifyTool *tool, GdkEventButton *event,
DDisplay *ddisp)
@@ -264,11 +273,15 @@ modify_button_press(ModifyTool *tool, GdkEventButton *event,
Point clickedpoint;
DiaObject *clicked_obj;
gboolean some_selected;
+ Guide *guide;
+ const gint pick_guide_snap_distance = 20; /* Margin of error for selecting a guide. */
ddisplay_untransform_coords(ddisp,
(int)event->x, (int)event->y,
&clickedpoint.x, &clickedpoint.y);
+ tool->guide = NULL;
+
/* don't got to single handle movement if there is more than one object selected */
some_selected = g_list_length (ddisp->diagram->data->selected) > 1;
if (!some_selected && do_if_clicked_handle(ddisp, tool, &clickedpoint, event))
@@ -292,6 +305,21 @@ modify_button_press(ModifyTool *tool, GdkEventButton *event,
tool->start_time = time_micro();
ddisplay_set_all_cursor_name (NULL, "move");
} else {
+ /* If there is a guide nearby, then drag it.
+ * Note: We can only drag guides if they are visible (like in GIMP). */
+ if (ddisp->guides_visible) {
+ guide = diagram_pick_guide (ddisp->diagram, clickedpoint.x, clickedpoint.y,
+ FUNSCALEX (ddisp, pick_guide_snap_distance ),
+ FUNSCALEY (ddisp, pick_guide_snap_distance ));
+
+ if (guide) {
+ tool->guide = guide;
+ guide_tool_start_edit (ddisp, guide);
+ return;
+ }
+ }
+
+ /* Box select. */
tool->state = STATE_BOX_SELECT;
tool->start_box = clickedpoint;
tool->end_box = clickedpoint;
diff --git a/app/new_guide_dialog.c b/app/new_guide_dialog.c
new file mode 100644
index 00000000..d38e81cb
--- /dev/null
+++ b/app/new_guide_dialog.c
@@ -0,0 +1,149 @@
+/* Dia -- an diagram creation/manipulation program
+ * Copyright (C) 1998 Alexander Larsson
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <math.h>
+#include <string.h>
+
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+
+#include "intl.h"
+#include "new_guide_dialog.h"
+#include "object_ops.h"
+#include "object.h"
+#include "connectionpoint_ops.h"
+#include "undo.h"
+#include "message.h"
+#include "properties.h"
+#include "diaoptionmenu.h"
+
+static GtkWidget *dialog = NULL;
+static GtkWidget *position_entry, *orientation_menu;
+static Diagram *current_diagram = NULL;
+
+static void
+diagram_new_guide_respond(GtkWidget *widget,
+ gint response_id,
+ gpointer user_data)
+{
+ if (response_id == GTK_RESPONSE_OK) {
+ real position = gtk_spin_button_get_value( GTK_SPIN_BUTTON(position_entry) );
+ int orientation = dia_option_menu_get_active(orientation_menu);
+ diagram_add_guide(current_diagram, position, orientation, TRUE);
+ }
+
+ /* Hide the dialog if "OK" or "Cancel" were clicked. */
+ if (response_id != GTK_RESPONSE_APPLY)
+ gtk_widget_hide(dialog);
+}
+
+static void
+create_new_guide_dialog(Diagram *dia)
+{
+ GtkWidget *dialog_vbox;
+ GtkWidget *label;
+ GtkAdjustment *adj;
+ GtkWidget *table;
+ const gdouble UPPER_LIMIT = G_MAXDOUBLE;
+
+ current_diagram = dia;
+
+ dialog = gtk_dialog_new_with_buttons(
+ _("Add New Guide"),
+ GTK_WINDOW(ddisplay_active()->shell),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_STOCK_CLOSE, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_APPLY, GTK_RESPONSE_APPLY,
+ GTK_STOCK_OK, GTK_RESPONSE_OK,
+ NULL);
+
+ gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_RESPONSE_OK);
+
+ dialog_vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
+
+ gtk_window_set_role(GTK_WINDOW(dialog), "new_guide");
+
+ g_signal_connect(G_OBJECT(dialog), "response",
+ G_CALLBACK(diagram_new_guide_respond), NULL);
+
+ g_signal_connect(G_OBJECT(dialog), "delete_event",
+ G_CALLBACK(gtk_widget_hide), NULL);
+ g_signal_connect(G_OBJECT(dialog), "destroy",
+ G_CALLBACK(gtk_widget_destroyed), &dialog);
+
+ table = gtk_table_new(3,3,FALSE);
+ gtk_container_set_border_width(GTK_CONTAINER(table), 2);
+ gtk_table_set_row_spacings(GTK_TABLE(table), 1);
+ gtk_table_set_col_spacings(GTK_TABLE(table), 2);
+
+ label = gtk_label_new(_("Orientation: "));
+ gtk_table_attach(GTK_TABLE(table), label, 0,1, 0,1,
+ GTK_FILL, GTK_FILL, 0, 0);
+ gtk_widget_show(label);
+
+ orientation_menu = dia_option_menu_new();
+ gtk_table_attach(GTK_TABLE(table), orientation_menu, 1,2, 0,1,
+ GTK_FILL, GTK_FILL, 0, 0);
+ dia_option_menu_add_item (orientation_menu, "Horizontal", GTK_ORIENTATION_HORIZONTAL);
+ dia_option_menu_add_item (orientation_menu, "Vertical", GTK_ORIENTATION_VERTICAL);
+ dia_option_menu_set_active (orientation_menu, GTK_ORIENTATION_HORIZONTAL);
+ gtk_widget_show(orientation_menu);
+
+ label = gtk_label_new(_("Position: "));
+ gtk_table_attach(GTK_TABLE(table), label, 0,1, 1,2,
+ GTK_FILL, GTK_FILL, 0, 0);
+ gtk_widget_show(label);
+
+ adj = GTK_ADJUSTMENT(gtk_adjustment_new(1.0, 0.0, UPPER_LIMIT, 0.1, 10.0, 0));
+ position_entry = gtk_spin_button_new(adj, 1.0, 3);
+ gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(position_entry), TRUE);
+ gtk_table_attach(GTK_TABLE(table), position_entry, 1,2, 1,2,
+ GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
+ gtk_widget_show(position_entry);
+
+ gtk_widget_show(table);
+
+ gtk_box_pack_start(GTK_BOX(dialog_vbox), table, TRUE, TRUE, 0);
+ gtk_widget_show(dialog_vbox);
+}
+
+void
+dialog_new_guide_show(void)
+{
+ Diagram *dia;
+ dia = ddisplay_active_diagram();
+
+ if(!dia)
+ return;
+
+ if (dialog) {
+ /* This makes the dialog a child of the newer diagram */
+ gtk_widget_destroy(dialog);
+ dialog = NULL;
+ }
+
+ create_new_guide_dialog(dia);
+
+ gtk_window_set_transient_for(GTK_WINDOW(dialog),
+ GTK_WINDOW (ddisplay_active()->shell));
+ gtk_widget_show(dialog);
+}
diff --git a/app/new_guide_dialog.h b/app/new_guide_dialog.h
new file mode 100644
index 00000000..e8799b76
--- /dev/null
+++ b/app/new_guide_dialog.h
@@ -0,0 +1,26 @@
+/* Dia -- an diagram creation/manipulation program
+ * Copyright (C) 1998 Alexander Larsson
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#ifndef NEW_GUIDE_DIALOG_H
+#define NEW_GUIDE_DIALOG_H
+
+#include "diatypes.h"
+#include "diagram.h"
+
+void dialog_new_guide_show (void);
+
+#endif /* NEW_GUIDE_DIALOG_H */
diff --git a/app/preferences.c b/app/preferences.c
index 34183447..191edf97 100644
--- a/app/preferences.c
+++ b/app/preferences.c
@@ -93,9 +93,11 @@ static int default_undo_depth = 15;
static guint default_recent_documents = 5;
static Color default_colour = DEFAULT_GRID_COLOR;
static Color pbreak_colour = DEFAULT_PAGEBREAK_COLOR;
+static Color guide_colour = DEFAULT_GUIDE_COLOR;
static const gchar *default_paper_name = NULL;
static const gchar *default_length_unit = "Centimeter";
static const gchar *default_fontsize_unit = "Point";
+static guint default_snap_distance = 10;
static const char *default_favored_filter = N_("any");
@@ -184,6 +186,8 @@ DiaPrefData prefs_data[] =
{ "fontsize_unit", PREF_CHOICE, PREF_OFFSET(fontsize_unit),
&default_fontsize_unit, UI_TAB, N_("Font size unit:"), NULL, FALSE,
_get_units_name_list, update_internal_prefs },
+ { "snap_distance", PREF_UINT, PREF_OFFSET(snap_distance),
+ &default_snap_distance, 0, N_("Guide snapping distance:") },
{ NULL, PREF_NONE, 0, NULL, DIA_TAB, N_("New diagram:") },
{ "is_portrait", PREF_BOOLEAN, PREF_OFFSET(new_diagram.is_portrait), &default_true, DIA_TAB,
N_("Portrait") },
@@ -216,6 +220,12 @@ DiaPrefData prefs_data[] =
{ "view_antialiased", PREF_BOOLEAN, PREF_OFFSET(view_antialiased), &default_false, VIEW_TAB, N_("view
antialiased") },
{ NULL, PREF_END_GROUP, 0, NULL, VIEW_TAB, NULL },
+ { NULL, PREF_NONE, 0, NULL, VIEW_TAB, N_("Guides:") },
+ { "show_guides", PREF_BOOLEAN, PREF_OFFSET(guides_visible), &default_true, VIEW_TAB, N_("Visible") },
+ { "snap_to_guides", PREF_BOOLEAN, PREF_OFFSET(guides_snap), &default_true, VIEW_TAB, N_("Snap to guides")
},
+ { "guide_colour", PREF_COLOUR, PREF_OFFSET(new_diagram.guide_color), &guide_colour, VIEW_TAB, N_("Color:")
},
+ { NULL, PREF_END_GROUP, 0, NULL, VIEW_TAB, NULL },
+
/* Favored Filter */
{ NULL, PREF_NONE, 0, NULL, FAVOR_TAB, N_("Export") },
{ "favored_png_export", PREF_CHOICE, PREF_OFFSET(favored_filter.png), &default_favored_filter,
diff --git a/app/preferences.h b/app/preferences.h
index 663a208c..b6f32b7c 100644
--- a/app/preferences.h
+++ b/app/preferences.h
@@ -23,6 +23,7 @@
#define DEFAULT_GRID_COLOR { 0.85, .90, .90, 1.0 }
#define DEFAULT_PAGEBREAK_COLOR { 0.0, 0.0, 0.6, 1.0 }
+#define DEFAULT_GUIDE_COLOR { 0.0, 1.0, 0.0, 1.0 }
struct DiaPreferences {
struct {
@@ -79,6 +80,10 @@ struct DiaPreferences {
char *emf;
char *print;
} favored_filter;
+
+ int guides_visible; /** Whether guides are visible. */
+ int guides_snap; /** Whether to snap to guides. */
+ guint snap_distance; /** The snapping distance for guides. */
};
extern struct DiaPreferences prefs;
diff --git a/app/ruler.c b/app/ruler.c
index 66aaf46c..1a1cb7b5 100644
--- a/app/ruler.c
+++ b/app/ruler.c
@@ -253,7 +253,7 @@ dia_ruler_new (GtkOrientation orientation, GtkWidget *shell, DDisplay *ddisp)
DIA_RULER(rule)->orientation = orientation;
DIA_RULER(rule)->ddisp = ddisp;
- gtk_widget_set_events (rule, GDK_EXPOSURE_MASK);
+ gtk_widget_set_events (rule, GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
GDK_POINTER_MOTION_MASK);
g_signal_connect_swapped (G_OBJECT (shell), "motion_notify_event",
G_CALLBACK (dia_ruler_motion_notify),
diff --git a/app/tool.c b/app/tool.c
index 492af30c..8ec24d7f 100644
--- a/app/tool.c
+++ b/app/tool.c
@@ -26,14 +26,15 @@
#include "interface.h"
#include "defaults.h"
#include "object.h"
+#include "guide_tool.h"
Tool *active_tool = NULL;
Tool *transient_tool = NULL;
static GtkWidget *active_button = NULL;
static GtkWidget *former_button = NULL;
-void
-tool_select_former(void)
+void
+tool_select_former(void)
{
if (former_button) {
g_signal_emit_by_name(G_OBJECT(former_button), "clicked",
@@ -92,13 +93,16 @@ tool_free(Tool *tool)
case TEXTEDIT_TOOL :
free_textedit_tool(tool);
break;
+ case GUIDE_TOOL:
+ free_guide_tool(tool);
+ break;
default:
- g_assert(0);
+ g_assert(0);
}
}
-void
-tool_select(ToolType type, gpointer extra_data,
+void
+tool_select(ToolType type, gpointer extra_data,
gpointer user_data, GtkWidget *button,
int invert_persistence)
{
@@ -124,21 +128,26 @@ tool_select(ToolType type, gpointer extra_data,
case TEXTEDIT_TOOL :
active_tool = create_textedit_tool();
break;
+ case GUIDE_TOOL :
+ active_tool = create_guide_tool ();
+ guide_tool_set_guide (active_tool, extra_data);
+ guide_tool_set_orientation (active_tool, GPOINTER_TO_INT(user_data));
+ break;
default:
- g_assert(0);
+ g_assert(0);
}
if (button)
active_button = button;
}
void
-tool_options_dialog_show(ToolType type, gpointer extra_data,
+tool_options_dialog_show(ToolType type, gpointer extra_data,
gpointer user_data, GtkWidget *button,
- int invert_persistence)
+ int invert_persistence)
{
DiaObjectType *objtype;
- if (active_tool->type != type)
+ if (active_tool->type != type)
tool_select(type,extra_data,user_data,button,invert_persistence);
switch(type) {
@@ -154,5 +163,7 @@ tool_options_dialog_show(ToolType type, gpointer extra_data,
break;
case TEXTEDIT_TOOL :
break;
+ case GUIDE_TOOL :
+ break;
}
}
diff --git a/app/tool.h b/app/tool.h
index 174eda1a..e2a90104 100644
--- a/app/tool.h
+++ b/app/tool.h
@@ -38,12 +38,13 @@ enum _ToolType {
MAGNIFY_TOOL,
MODIFY_TOOL,
SCROLL_TOOL,
- TEXTEDIT_TOOL
+ TEXTEDIT_TOOL,
+ GUIDE_TOOL,
};
struct _Tool {
ToolType type;
-
+
/* Action functions */
ButtonPressFunc button_press_func;
ButtonHoldFunc button_hold_func;
@@ -69,7 +70,7 @@ void tool_select(ToolType type, gpointer extra_data, gpointer user_date,
GtkWidget *button, int invert_persistence);
void tool_select_former(void);
void tool_reset(void);
-void tool_options_dialog_show(ToolType type, gpointer extra_data,
+void tool_options_dialog_show(ToolType type, gpointer extra_data,
gpointer user_data,GtkWidget *button,
int invert_persistence);
diff --git a/app/undo.c b/app/undo.c
index 0e035025..c714541b 100644
--- a/app/undo.c
+++ b/app/undo.c
@@ -1642,3 +1642,229 @@ dia_mem_swap_change_new (Diagram *dia, gpointer dest, gsize size)
return DIA_CHANGE (change);
}
+
+
+
+struct _DiaMoveGuideChange {
+ DiaChange parent;
+
+ real orig_pos;
+ real dest_pos;
+ Guide *guide;
+};
+
+DIA_DEFINE_CHANGE (DiaMoveGuideChange, dia_move_guide_change)
+
+
+static void
+dia_move_guide_change_apply (DiaChange *self, Diagram *dia)
+{
+ DiaMoveGuideChange *change = DIA_MOVE_GUIDE_CHANGE (self);
+
+ change->guide->position = change->dest_pos;
+
+ /* Force redraw. */
+ diagram_add_update_all (dia);
+ diagram_modified (dia);
+ diagram_flush (dia);
+}
+
+
+static void
+dia_move_guide_change_revert (DiaChange *self, Diagram *dia)
+{
+ DiaMoveGuideChange *change = DIA_MOVE_GUIDE_CHANGE (self);
+
+ change->guide->position = change->orig_pos;
+
+ /* Force redraw. */
+ diagram_add_update_all (dia);
+ diagram_modified (dia);
+ diagram_flush (dia);
+}
+
+
+static void
+dia_move_guide_change_free (DiaChange *change)
+{
+ /* Nothing to free. */
+}
+
+
+DiaChange *
+dia_move_guide_change_new (Diagram *dia, Guide *guide, real orig_pos, real dest_pos)
+{
+ DiaMoveGuideChange *change = dia_change_new (DIA_TYPE_MOVE_GUIDE_CHANGE);
+
+ change->orig_pos = orig_pos;
+ change->dest_pos = dest_pos;
+ change->guide = guide;
+
+ undo_push_change (dia->undo, DIA_CHANGE (change));
+
+ return DIA_CHANGE (change);
+}
+
+
+
+struct _DiaAddGuideChange {
+ DiaChange parent;
+
+ Guide *guide;
+ int applied;
+};
+
+DIA_DEFINE_CHANGE (DiaAddGuideChange, dia_add_guide_change)
+
+
+static void
+dia_add_guide_change_apply (DiaChange *self, Diagram *dia)
+{
+ DiaAddGuideChange *change = DIA_ADD_GUIDE_CHANGE (self);
+ Guide *new_guide;
+
+ g_debug ("add_guide_apply()");
+
+ new_guide = diagram_add_guide (dia, change->guide->position, change->guide->orientation, FALSE);
+ g_free (change->guide);
+ change->guide = new_guide;
+
+ /* Force redraw. */
+ diagram_add_update_all (dia);
+ diagram_modified (dia);
+ diagram_flush (dia);
+
+ /* Set flag. */
+ change->applied = 1;
+}
+
+
+static void
+dia_add_guide_change_revert (DiaChange *self, Diagram *dia)
+{
+ DiaAddGuideChange *change = DIA_ADD_GUIDE_CHANGE (self);
+
+ g_debug ("add_guide_revert()");
+
+ diagram_remove_guide (dia, change->guide, FALSE);
+
+ /* Force redraw. */
+ diagram_add_update_all (dia);
+ diagram_modified (dia);
+ diagram_flush (dia);
+
+ /* Set flag. */
+ change->applied = 0;
+}
+
+
+static void
+dia_add_guide_change_free (DiaChange *self)
+{
+ DiaAddGuideChange *change = DIA_ADD_GUIDE_CHANGE (self);
+
+ g_debug ("add_guide_free()");
+
+ if (!change->applied) {
+ g_free (change->guide);
+ }
+}
+
+
+DiaChange *
+dia_add_guide_change_new (Diagram *dia, Guide *guide, int applied)
+{
+ DiaAddGuideChange *change = dia_change_new (DIA_TYPE_ADD_GUIDE_CHANGE);
+
+ change->guide = guide;
+ change->applied = applied;
+
+ undo_push_change (dia->undo, DIA_CHANGE (change));
+
+ return DIA_CHANGE (change);
+}
+
+
+
+struct _DiaDeleteGuideChange {
+ DiaChange parent;
+
+ Guide *guide;
+ int applied;
+};
+
+DIA_DEFINE_CHANGE (DiaDeleteGuideChange, dia_delete_guide_change)
+
+
+static void
+dia_delete_guide_change_apply (DiaChange *self, Diagram *dia)
+{
+ DiaDeleteGuideChange *change = DIA_DELETE_GUIDE_CHANGE (self);
+
+ g_debug ("delete_guide_apply()");
+
+ diagram_remove_guide (dia, change->guide, FALSE);
+
+ /* Force redraw. */
+ diagram_add_update_all (dia);
+ diagram_modified (dia);
+ diagram_flush (dia);
+
+ /* Set flag. */
+ change->applied = 1;
+}
+
+
+static void
+dia_delete_guide_change_revert (DiaChange *self, Diagram *dia)
+{
+ DiaDeleteGuideChange *change = DIA_DELETE_GUIDE_CHANGE (self);
+
+ /* Declare variable. */
+ Guide *new_guide;
+
+ /* Log message. */
+ g_debug ("delete_guide_revert()");
+
+ /* Add it again. */
+ new_guide = diagram_add_guide(dia, change->guide->position, change->guide->orientation, FALSE);
+
+ /* Reassign. */
+ g_free(change->guide);
+ change->guide = new_guide;
+
+ /* Force redraw. */
+ diagram_add_update_all(dia);
+ diagram_modified(dia);
+ diagram_flush(dia);
+
+ /* Set flag. */
+ change->applied = 0;
+}
+
+
+static void
+dia_delete_guide_change_free (DiaChange *self)
+{
+ DiaDeleteGuideChange *change = DIA_DELETE_GUIDE_CHANGE (self);
+
+ g_debug ("delete_guide_free()");
+
+ if (change->applied) {
+ g_free (change->guide);
+ }
+}
+
+
+DiaChange *
+dia_delete_guide_change_new (Diagram *dia, Guide *guide, int applied)
+{
+ DiaDeleteGuideChange *change = dia_change_new (DIA_TYPE_DELETE_GUIDE_CHANGE);
+
+ change->guide = guide;
+ change->applied = applied;
+
+ undo_push_change (dia->undo, DIA_CHANGE (change));
+
+ return DIA_CHANGE (change);
+}
diff --git a/app/undo.h b/app/undo.h
index cefcb00f..caad9ec1 100644
--- a/app/undo.h
+++ b/app/undo.h
@@ -22,6 +22,7 @@
typedef struct _UndoStack UndoStack;
#include "diagram.h"
+#include "guide.h"
#include "dia-change.h"
@@ -174,5 +175,29 @@ DiaChange *dia_mem_swap_change_new (Diagram *dia,
gsize size);
+#define DIA_TYPE_MOVE_GUIDE_CHANGE dia_move_guide_change_get_type ()
+G_DECLARE_FINAL_TYPE (DiaMoveGuideChange, dia_move_guide_change, DIA, MOVE_GUIDE_CHANGE, DiaChange)
+
+DiaChange *dia_move_guide_change_new (Diagram *dia,
+ Guide *guide,
+ real orig_pos,
+ real dest_pos);
+
+
+#define DIA_TYPE_ADD_GUIDE_CHANGE dia_add_guide_change_get_type ()
+G_DECLARE_FINAL_TYPE (DiaAddGuideChange, dia_add_guide_change, DIA, ADD_GUIDE_CHANGE, DiaChange)
+
+DiaChange *dia_add_guide_change_new (Diagram *dia,
+ Guide *guide,
+ int applied);
+
+
+#define DIA_TYPE_DELETE_GUIDE_CHANGE dia_delete_guide_change_get_type ()
+G_DECLARE_FINAL_TYPE (DiaDeleteGuideChange, dia_delete_guide_change, DIA, DELETE_GUIDE_CHANGE, DiaChange)
+
+DiaChange *dia_delete_guide_change_new (Diagram *dia,
+ Guide *guide,
+ int applied);
+
#endif /* UNDO_H */
diff --git a/data/ui/display-ui.xml b/data/ui/display-ui.xml
index 049de3be..37e251d9 100644
--- a/data/ui/display-ui.xml
+++ b/data/ui/display-ui.xml
@@ -69,6 +69,13 @@
<menuitem name="ViewCloneview" action="ViewCloneview" />
<menuitem name="ViewRedraw" action="ViewRedraw" />
<separator name="ViewSep3" />
+ <menu name="ViewGuides" action="ViewGuides">
+ <menuitem name="ViewNewguide" action="ViewNewguide" />
+ <menuitem name="ViewShowguides" action="ViewShowguides" />
+ <menuitem name="ViewSnaptoguides" action="ViewSnaptoguides" />
+ <menuitem name="ViewRemoveallguides" action="ViewRemoveallguides" />
+ </menu>
+ <separator name="ViewSep4" />
<separator name="ViewExtensionStart" />
</menu>
<menu name="Layers" action="Layers">
diff --git a/data/ui/integrated-ui.xml b/data/ui/integrated-ui.xml
index 25919ff5..0d0a1771 100644
--- a/data/ui/integrated-ui.xml
+++ b/data/ui/integrated-ui.xml
@@ -83,6 +83,13 @@
<menuitem name="ViewShowscrollbars" action="ViewShowscrollbars" />
<menuitem name="ViewShowconnectionpoints" action="ViewShowconnectionpoints" />
<separator name="ViewSep3" />
+ <menu name="ViewGuides" action="ViewGuides">
+ <menuitem name="ViewNewguide" action="ViewNewguide" />
+ <menuitem name="ViewShowguides" action="ViewShowguides" />
+ <menuitem name="ViewSnaptoguides" action="ViewSnaptoguides" />
+ <menuitem name="ViewRemoveallguides" action="ViewRemoveallguides" />
+ </menu>
+ <separator name="ViewSep4" />
<menuitem name="ViewNewview" action="ViewNewview" />
<menuitem name="ViewCloneview" action="ViewCloneview" />
<menuitem name="ViewRedraw" action="ViewRedraw" />
diff --git a/data/ui/popup-ui.xml b/data/ui/popup-ui.xml
index 4a4b297e..71a15f31 100644
--- a/data/ui/popup-ui.xml
+++ b/data/ui/popup-ui.xml
@@ -64,11 +64,18 @@
<menuitem name="ViewShowrulers" action="ViewShowrulers" />
<menuitem name="ViewShowconnectionpoints" action="ViewShowconnectionpoints" />
<separator name="ViewSep2" />
+ <menu name="ViewGuides" action="ViewGuides">
+ <menuitem name="ViewNewguide" action="ViewNewguide" />
+ <menuitem name="ViewShowguides" action="ViewShowguides" />
+ <menuitem name="ViewSnaptoguides" action="ViewSnaptoguides" />
+ <menuitem name="ViewRemoveallguides" action="ViewRemoveallguides" />
+ </menu>
+ <separator name="ViewSep3" />
<menuitem name="ViewNewview" action="ViewNewview" />
<menuitem name="ViewCloneview" action="ViewCloneview" />
<menuitem name="ViewShowall" action="ViewShowall" />
<menuitem name="ViewRedraw" action="ViewRedraw" />
- <separator name="ViewSep3" />
+ <separator name="ViewSep4" />
<separator name="ViewExtensionStart" />
</menu>
<menu name="Layers" action="Layers">
diff --git a/data/ui/properties-dialog.ui b/data/ui/properties-dialog.ui
index 2b31becd..16ddb820 100644
--- a/data/ui/properties-dialog.ui
+++ b/data/ui/properties-dialog.ui
@@ -320,7 +320,7 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="border_width">6</property>
- <property name="n_rows">3</property>
+ <property name="n_rows">4</property>
<property name="n_columns">2</property>
<property name="column_spacing">6</property>
<property name="row_spacing">6</property>
@@ -361,6 +361,19 @@
<property name="y_options"/>
</packing>
</child>
+ <child>
+ <object class="GtkLabel" id="label12">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Guides</property>
+ </object>
+ <packing>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="y_options"/>
+ </packing>
+ </child>
<child>
<object class="DiaColorSelector" id="background">
<property name="visible">True</property>
@@ -401,6 +414,20 @@
<property name="y_options"/>
</packing>
</child>
+ <child>
+ <object class="DiaColorSelector" id="guide_lines">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="y_options"/>
+ </packing>
+ </child>
</object>
<packing>
<property name="position">1</property>
diff --git a/lib/diagramdata.h b/lib/diagramdata.h
index ab35f054..0bd3fbaf 100644
--- a/lib/diagramdata.h
+++ b/lib/diagramdata.h
@@ -40,7 +40,7 @@ struct _NewDiagramData {
gfloat scaling;
gboolean fitto;
gint fitwidth, fitheight;
- Color bg_color, pagebreak_color, grid_color;
+ Color bg_color, pagebreak_color, grid_color, guide_color;
int compress_save;
gchar *unit, *font_unit;
};
diff --git a/lib/guide.c b/lib/guide.c
new file mode 100644
index 00000000..38609538
--- /dev/null
+++ b/lib/guide.c
@@ -0,0 +1 @@
+#include "guide.h"
diff --git a/lib/guide.h b/lib/guide.h
new file mode 100644
index 00000000..1be5669d
--- /dev/null
+++ b/lib/guide.h
@@ -0,0 +1,31 @@
+/* Dia -- an diagram creation/manipulation program
+ * Copyright (C) 1998 Alexander Larsson
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#ifndef GUIDE_H
+#define GUIDE_H
+
+#include "diatypes.h"
+#include <gtk/gtk.h>
+
+typedef struct _Guide Guide;
+
+struct _Guide {
+ real position;
+ GtkOrientation orientation;
+};
+
+#endif /* GUIDE_H */
diff --git a/lib/meson.build b/lib/meson.build
index 3b1eac81..19519980 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -136,6 +136,8 @@ libdia_sources = stdprop_sources + [
'dia_svg.c',
'autoroute.c',
'parent.c',
+ 'guide.c',
+ 'guide.h',
'diaarrowchooser.c',
'diaarrowselector.c',
'diacolorselector.c',
diff --git a/plug-ins/python/pydia-diagramdata.c b/plug-ins/python/pydia-diagramdata.c
index cbb25748..90915c37 100644
--- a/plug-ins/python/pydia-diagramdata.c
+++ b/plug-ins/python/pydia-diagramdata.c
@@ -400,28 +400,14 @@ PyDiaDiagramData_GetAttr(PyDiaDiagramData *self, gchar *attr)
} else {
/* In the interactive case diagramdata is_a diagram */
if (DIA_IS_DIAGRAM (self->data)) {
- Diagram *diagram = DIA_DIAGRAM(self->data);
- if (diagram) { /* paranoid and helping scan-build */
- if (!strcmp(attr, "grid_width"))
- return Py_BuildValue("(dd)", diagram->grid.width_x, diagram->grid.width_y);
- else if (!strcmp(attr, "grid_visible"))
- return Py_BuildValue("(ii)", diagram->grid.visible_x, diagram->grid.visible_y);
- else if (!strcmp(attr, "hguides")) {
- int len = diagram->guides.nhguides;
- PyObject *ret = PyTuple_New(len);
- int i;
- for (i = 0; i < len; i++)
- PyTuple_SetItem(ret, i, PyFloat_FromDouble(diagram->guides.hguides[i]));
- return ret;
- } else if (diagram && !strcmp(attr, "vguides")) {
- int len = diagram->guides.nvguides;
- PyObject *ret = PyTuple_New(len);
- int i;
- for (i = 0; i < len; i++)
- PyTuple_SetItem(ret, i, PyFloat_FromDouble(diagram->guides.vguides[i]));
- return ret;
- }
- }
+ Diagram *diagram = DIA_DIAGRAM (self->data);
+ if (diagram) { /* paranoid and helping scan-build */
+ if (!strcmp (attr, "grid_width")) {
+ return Py_BuildValue ("(dd)", diagram->grid.width_x, diagram->grid.width_y);
+ } else if (!strcmp (attr, "grid_visible")) {
+ return Py_BuildValue ("(ii)", diagram->grid.visible_x, diagram->grid.visible_y);
+ }
+ }
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]