1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2020 gEDA Contributors (see ChangeLog for details)
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 * \file gschem_page_view.c
23 * \brief A widget for viewing a schematic page
39 #include <gdk/gdkkeysyms.h>
41 #include "gtk/gtkmarshal.h"
45 #define INVALIDATE_MARGIN 1
59 typedef void (*NotifyFunction
) (void*,void*);
62 dispose (GObject
*object
);
65 finalize (GObject
*object
);
68 get_property (GObject
*object
, guint param_id
, GValue
*value
, GParamSpec
*pspec
);
71 gschem_page_view_class_init (GschemPageViewClass
*klass
);
74 gschem_page_view_init (GschemPageView
*view
);
77 gschem_page_view_update_hadjustment (GschemPageView
*view
);
80 gschem_page_view_update_vadjustment (GschemPageView
*view
);
83 hadjustment_value_changed (GtkAdjustment
*vadjustment
, GschemPageView
*view
);
86 remove_page_weak_reference (PAGE
*page
, gpointer geometry
, GschemPageView
*view
);
89 page_deleted (PAGE
*page
, GschemPageView
*view
);
92 set_property (GObject
*object
, guint param_id
, const GValue
*value
, GParamSpec
*pspec
);
95 set_scroll_adjustments (GschemPageView
*view
, GtkAdjustment
*hadjustment
, GtkAdjustment
*vadjustment
);
98 vadjustment_value_changed (GtkAdjustment
*vadjustment
, GschemPageView
*view
);
102 static GObjectClass
*gschem_page_view_parent_class
= NULL
;
106 * In later versions of GTK+, the GtkScrolledWindow uses an interface, instead
107 * of signals, to set the scrollbar adjustments. When Gschem uses on of these
108 * more recent version of GTK+, this function will no longer be needed.
111 cclosure_marshal_VOID__OBJECT_OBJECT (GClosure
*closure
,
112 GValue
*return_value G_GNUC_UNUSED
,
113 guint n_param_values
,
114 const GValue
*param_values
,
115 gpointer invocation_hint G_GNUC_UNUSED
,
116 gpointer marshal_data
)
118 typedef void (*GMarshalFunc_VOID__OBJECT_OBJECT
) (gpointer data1
,
123 register GMarshalFunc_VOID__OBJECT_OBJECT callback
;
124 register GCClosure
*cc
= (GCClosure
*) closure
;
125 register gpointer data1
, data2
;
127 g_return_if_fail (n_param_values
== 3);
129 if (G_CCLOSURE_SWAP_DATA (closure
)) {
130 data1
= closure
->data
;
131 data2
= g_value_peek_pointer (param_values
+ 0);
134 data1
= g_value_peek_pointer (param_values
+ 0);
135 data2
= closure
->data
;
138 callback
= (GMarshalFunc_VOID__OBJECT_OBJECT
) (marshal_data
? marshal_data
: cc
->callback
);
141 g_value_get_object (param_values
+ 1),
142 g_value_get_object (param_values
+ 2),
148 /*! \brief Dispose of the object
151 dispose (GObject
*object
)
153 GschemPageView
*view
;
155 g_return_if_fail (object
!= NULL
);
156 view
= GSCHEM_PAGE_VIEW (object
);
157 g_return_if_fail (view
!= NULL
);
159 gschem_page_view_set_hadjustment (view
, NULL
);
160 gschem_page_view_set_vadjustment (view
, NULL
);
162 g_hash_table_foreach (view
->geometry_table
, (GHFunc
)remove_page_weak_reference
, view
);
163 g_hash_table_remove_all (view
->geometry_table
);
165 /* We aren't bothering about invoking
166 * gschem_page_view_set_page (view, NULL)
167 * directly here since the current page itself must use its weak
168 * reference to call cleanup closure (page_deleted) for this
171 /* lastly, chain up to the parent dispose */
173 g_return_if_fail (gschem_page_view_parent_class
!= NULL
);
174 gschem_page_view_parent_class
->dispose (object
);
179 /*! \brief Event handler for window realized
182 event_realize(GtkWidget
*widget
, gpointer unused
)
184 GschemPageView
*view
= GSCHEM_PAGE_VIEW(widget
);
185 GdkWindow
*window
= gtk_widget_get_window (widget
);
187 g_return_if_fail (view
!= NULL
);
188 g_return_if_fail (window
!= NULL
);
190 gtk_widget_get_allocation (widget
, &(view
->previous_allocation
));
195 /*! \brief Event handler for window unrealized
198 event_unrealize(GtkWidget
*widget
, gpointer unused
)
200 GschemPageView
*view
= GSCHEM_PAGE_VIEW(widget
);
202 g_return_if_fail (view
!= NULL
);
207 /*! \brief Finalize object
210 finalize (GObject
*object
)
212 GschemPageView
*view
= GSCHEM_PAGE_VIEW (object
);
214 g_return_if_fail (view
!= NULL
);
215 g_return_if_fail (view
->geometry_table
!= NULL
);
217 g_hash_table_destroy (view
->geometry_table
);
219 /* lastly, chain up to the parent finalize */
221 g_return_if_fail (gschem_page_view_parent_class
!= NULL
);
222 gschem_page_view_parent_class
->finalize (object
);
227 /*! \brief Get a property
230 * \param [in] param_id
231 * \param [in,out] value
235 get_property (GObject
*object
, guint param_id
, GValue
*value
, GParamSpec
*pspec
)
237 GschemPageView
*view
= GSCHEM_PAGE_VIEW (object
);
240 case PROP_HADJUSTMENT
:
241 g_value_set_object (value
, gschem_page_view_get_hadjustment (view
));
245 g_value_set_pointer (value
, gschem_page_view_get_page (view
));
248 case PROP_PAGE_GEOMETRY
:
249 g_value_set_boxed (value
, gschem_page_view_get_page_geometry (view
));
252 case PROP_VADJUSTMENT
:
253 g_value_set_object (value
, gschem_page_view_get_vadjustment (view
));
257 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, param_id
, pspec
);
263 /*! \brief Initialize GschemPageView class
265 * \param [in] klass The class for the GschemPageView
268 gschem_page_view_class_init (GschemPageViewClass
*klass
)
270 gschem_page_view_parent_class
= G_OBJECT_CLASS (g_type_class_peek_parent (klass
));
272 G_OBJECT_CLASS (klass
)->dispose
= dispose
;
273 G_OBJECT_CLASS (klass
)->finalize
= finalize
;
275 G_OBJECT_CLASS (klass
)->get_property
= get_property
;
276 G_OBJECT_CLASS (klass
)->set_property
= set_property
;
278 g_object_class_install_property (G_OBJECT_CLASS (klass
),
280 g_param_spec_object ("hadjustment",
281 "Horizontal adjustment",
282 "Horizontal adjustment",
284 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT
));
286 g_object_class_install_property (G_OBJECT_CLASS (klass
),
288 g_param_spec_pointer ("page",
291 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
));
293 g_object_class_install_property (G_OBJECT_CLASS (klass
),
295 g_param_spec_boxed ("page-geometry",
298 GSCHEM_TYPE_PAGE_GEOMETRY
,
299 G_PARAM_READABLE
| G_PARAM_STATIC_STRINGS
));
301 g_object_class_install_property (G_OBJECT_CLASS (klass
),
303 g_param_spec_object ("vadjustment",
304 "Vertical adjustment",
305 "Vertical adjustment",
307 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT
));
309 GTK_WIDGET_CLASS (klass
)->set_scroll_adjustments_signal
= g_signal_new (
310 "set-scroll-adjustments",
311 G_OBJECT_CLASS_TYPE (klass
),
312 G_SIGNAL_RUN_LAST
| G_SIGNAL_ACTION
,
316 cclosure_marshal_VOID__OBJECT_OBJECT
,
320 GTK_TYPE_ADJUSTMENT
);
324 G_OBJECT_CLASS_TYPE (klass
),
325 G_SIGNAL_RUN_LAST
| G_SIGNAL_ACTION
,
329 g_cclosure_marshal_VOID__VOID
,
336 /*! \brief Get the horizontal adjustment for this view
338 * \param [in] view The view
339 * \return The horizontal adjustment for this view
342 gschem_page_view_get_hadjustment (GschemPageView
*view
)
344 g_return_val_if_fail (view
!= NULL
, NULL
);
346 return view
->hadjustment
;
351 /*! \brief Get page for this view
353 * \param [in] view The view
354 * \return The page for the view
357 gschem_page_view_get_page (GschemPageView
*view
)
359 g_return_val_if_fail (view
!= NULL
, NULL
);
366 /*! \brief Get page geometry for this view
368 * \param [in] view The view
369 * \return The page geometry for the view
372 gschem_page_view_get_page_geometry (GschemPageView
*view
)
375 GschemPageGeometry
*geometry
= NULL
;
376 GdkWindow
*window
= NULL
;
380 g_return_val_if_fail (view
!= NULL
, NULL
);
382 page
= gschem_page_view_get_page (view
);
387 geometry
= g_hash_table_lookup (view
->geometry_table
, page
);
389 window
= gtk_widget_get_window (GTK_WIDGET (view
));
390 g_return_val_if_fail (window
!= NULL
, NULL
);
391 screen_width
= gdk_window_get_width (window
);
392 screen_height
= gdk_window_get_height (window
);
394 if (geometry
== NULL
) {
395 geometry
= gschem_page_geometry_new_with_values (screen_width
,
397 view
->page
->toplevel
->init_left
,
398 view
->page
->toplevel
->init_top
,
399 view
->page
->toplevel
->init_right
,
400 view
->page
->toplevel
->init_bottom
,
401 view
->page
->toplevel
->init_left
,
402 view
->page
->toplevel
->init_top
,
403 view
->page
->toplevel
->init_right
,
404 view
->page
->toplevel
->init_bottom
);
406 g_hash_table_insert (view
->geometry_table
, page
, geometry
);
408 gschem_page_geometry_zoom_extents (geometry
,
409 view
->page
->toplevel
,
410 s_page_objects (page
));
413 gschem_page_geometry_set_values (geometry
,
414 max (fabs ((double)(gschem_page_geometry_get_viewport_right (geometry
) - gschem_page_geometry_get_viewport_left (geometry
)) / screen_width
), (fabs ((double)(gschem_page_geometry_get_viewport_top (geometry
) - gschem_page_geometry_get_viewport_bottom (geometry
)) / screen_height
))),
417 gschem_page_geometry_get_viewport_left (geometry
),
418 gschem_page_geometry_get_viewport_top (geometry
),
419 gschem_page_geometry_get_viewport_right (geometry
),
420 gschem_page_geometry_get_viewport_bottom (geometry
));
428 /*! \brief Get/register GschemPageView type.
431 gschem_page_view_get_type ()
433 static GType type
= 0;
436 static const GTypeInfo info
= {
437 sizeof(GschemPageViewClass
),
438 NULL
, /* base_init */
439 NULL
, /* base_finalize */
440 (GClassInitFunc
) gschem_page_view_class_init
,
441 NULL
, /* class_finalize */
442 NULL
, /* class_data */
443 sizeof(GschemPageView
),
445 (GInstanceInitFunc
) gschem_page_view_init
,
448 type
= g_type_register_static (GTK_TYPE_DRAWING_AREA
, "GschemPageView", &info
, 0);
456 /*! \brief Get the vertical adjustment for this view
458 * \param [in] view The view
459 * \return The vertical adjustment for this view
462 gschem_page_view_get_vadjustment (GschemPageView
*view
)
464 g_return_val_if_fail (view
!= NULL
, NULL
);
466 return view
->vadjustment
;
471 /*! \brief Schedule redraw for the entire window
473 * \param [in,out] view The Gschem page view to redraw
476 gschem_page_view_invalidate_all (GschemPageView
*view
)
480 /* this function can be called early during initialization */
485 window
= gtk_widget_get_window (GTK_WIDGET (view
));
487 if (window
== NULL
) {
491 gdk_window_invalidate_rect (window
, NULL
, FALSE
);
496 /*! \brief Schedule redraw of the given object
498 * \param [in,out] view The Gschem page view to redraw
499 * \param [in] object The object to redraw
502 gschem_page_view_invalidate_object (GschemPageView
*view
, OBJECT
*object
)
504 g_return_if_fail (object
!= NULL
);
505 g_return_if_fail (view
!= NULL
);
507 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (view
))) {
511 PAGE
*page
= gschem_page_view_get_page (view
);
520 success
= world_get_single_object_bounds (page
->toplevel
,
528 gschem_page_view_invalidate_world_rect (view
,
539 /*! \brief Schedule redraw of the given rectange
541 * \param [in,out] view The Gschem page view to redraw
548 gschem_page_view_invalidate_screen_rect (GschemPageView
*view
, int left
, int top
, int right
, int bottom
)
556 g_return_if_fail (view
!= NULL
);
558 window
= gtk_widget_get_window (GTK_WIDGET (view
));
560 if (window
== NULL
) {
564 grip_half_size
= GRIP_SIZE
/ 2;
565 cue_half_size
= gschem_page_view_SCREENabs (view
, CUE_BOX_SIZE
);
566 bloat
= MAX (grip_half_size
, cue_half_size
) + INVALIDATE_MARGIN
;
568 rect
.x
= MIN(left
, right
) - bloat
;
569 rect
.y
= MIN(top
, bottom
) - bloat
;
570 rect
.width
= 1 + abs( left
- right
) + 2 * bloat
;
571 rect
.height
= 1 + abs( top
- bottom
) + 2 * bloat
;
573 gdk_window_invalidate_rect (window
, &rect
, FALSE
);
578 /*! \brief Schedule redraw of the given rectange
580 * \param [in,out] view The Gschem page view to redraw
587 gschem_page_view_invalidate_world_rect (GschemPageView
*view
, int left
, int top
, int right
, int bottom
)
594 g_return_if_fail (view
!= NULL
);
596 gschem_page_view_WORLDtoSCREEN (view
, left
, top
, &screen_left
, &screen_top
);
597 gschem_page_view_WORLDtoSCREEN (view
, right
, bottom
, &screen_right
, &screen_bottom
);
599 gschem_page_view_invalidate_screen_rect (view
,
608 /*! \brief Initialize GschemPageView instance
610 * \param [in,out] view the gschem page view
613 gschem_page_view_init (GschemPageView
*view
)
615 g_return_if_fail (view
!= NULL
);
617 view
->hadjustment
= NULL
;
618 view
->vadjustment
= NULL
;
620 view
->geometry_table
= g_hash_table_new_full (g_direct_hash
,
623 (GDestroyNotify
) gschem_page_geometry_free
);
626 view
->configured
= FALSE
;
628 view
->doing_pan
= FALSE
;
633 g_signal_connect (view
,
634 "set-scroll-adjustments",
635 G_CALLBACK (set_scroll_adjustments
),
638 g_signal_connect(view
,
640 G_CALLBACK (event_realize
),
643 g_signal_connect(view
,
645 G_CALLBACK (event_unrealize
),
651 /*! \brief Create a new instance of the GschemPageView
652 * \par Function Description
653 * This function creates a new instance of the GschemPageView
654 * structure. The resulting view becomes a "viewport" for the
655 * given \a page. If the page is not NULL, a weak reference
656 * callback is added for \a page so that it can do necessary
657 * clean-up for the view when the page is deleted (e.g. due to
658 * using close-page! Scheme function).
660 * \param [in] page The page to refer to.
662 * \return A new instance of the GschemPageView
665 gschem_page_view_new_with_page (PAGE
*page
)
667 GschemPageView
*view
= GSCHEM_PAGE_VIEW (g_object_new (GSCHEM_TYPE_PAGE_VIEW
,
671 s_page_weak_ref (page
, (NotifyFunction
) page_deleted
, view
);
679 /*! \brief Pan the view on the given world coordinate using given zoom factor
681 * \param [in,out] page_view This GschemPageView
682 * \param [in] w_x The world x coordinate of the new center
683 * \param [in] w_y The world y coordinate of the new center
684 * \param [in] relativ_zoom_factor The zoom factor
687 gschem_page_view_pan_general (GschemPageView
*view
, int w_x
, int w_y
, double relativ_zoom_factor
)
689 GschemPageGeometry
*geometry
= NULL
;
691 g_return_if_fail (view
!= NULL
);
693 geometry
= gschem_page_view_get_page_geometry (view
);
694 g_return_if_fail (geometry
!= NULL
);
696 /* make mouse to the new world-center;
697 attention: there are information looses because of type cast in mil_x */
699 gschem_page_geometry_pan_general (geometry
, w_x
, w_y
, relativ_zoom_factor
);
701 g_signal_emit_by_name (view
, "update-grid-info");
702 gschem_page_view_update_scroll_adjustments (view
);
703 gschem_page_view_invalidate_all (view
);
707 /*! \brief Center the view on the given world coordinate
709 * \param [in,out] page_view This GschemPageView
710 * \param [in] w_x The world x coordinate of the new center
711 * \param [in] w_y The world y coordinate of the new center
714 gschem_page_view_pan (GschemPageView
*view
, int w_x
, int w_y
)
716 gschem_page_view_pan_general (view
, w_x
, w_y
, 1);
717 /* Trigger a motion event to update the objects being drawn */
718 /* This works e.g. if the view is centered at the mouse pointer position */
719 x_event_faked_motion (view
, NULL
);
721 gschem_page_view_update_scroll_adjustments (view
);
722 gschem_page_view_invalidate_all (view
);
727 /*! \brief Pan the view by the given screen coordinate displacement
729 * \param [in,out] view This GschemPageView
730 * \param [in] diff_x The screen x coordinate displacement
731 * \param [in] diff_y The screen y coordinate displacement
734 gschem_page_view_pan_mouse (GschemPageView
*view
, int diff_x
, int diff_y
)
736 GschemPageGeometry
*geometry
= NULL
;
737 double world_cx
, world_cy
;
738 double page_cx
, page_cy
;
740 g_return_if_fail (view
!= NULL
);
742 geometry
= gschem_page_view_get_page_geometry (view
);
743 g_return_if_fail (geometry
!= NULL
);
746 printf("gschem_page_view_pan_mouse(): diff_x=%d, diff_y=%d\n", diff_x
, diff_y
);
749 page_cx
= (gschem_page_geometry_get_viewport_left (geometry
) + gschem_page_geometry_get_viewport_right (geometry
)) / 2.0;
750 page_cy
= (gschem_page_geometry_get_viewport_top (geometry
) + gschem_page_geometry_get_viewport_bottom (geometry
)) / 2.0;
752 world_cx
= page_cx
- gschem_page_view_WORLDabs (view
, diff_x
);
753 world_cy
= page_cy
+ gschem_page_view_WORLDabs (view
, diff_y
);
756 printf(" world_cx=%f, world_cy=%f\n", world_cx
, world_cy
);
759 gschem_page_view_pan_general (view
, world_cx
, world_cy
, 1);
761 /* Trigger a motion event to update the objects being drawn */
762 /* Don't emit such an event if diffs are zero to avoid recursion */
763 if (diff_x
== 0 && diff_y
== 0) {
764 x_event_faked_motion (view
, NULL
);
770 /*! \brief Start mouse panning in the view
771 * \par Function Description
772 * This function saves current coordinates of the mouse pointer
773 * to pan_x and pan_y and toggles the view into pan mode.
775 * \param [in,out] view This GschemPageView
776 * \param [in] x The screen x coordinate
777 * \param [in] y The screen y coordinate
779 void gschem_page_view_pan_start (GschemPageView
*view
, int x
, int y
)
781 view
->doing_pan
= TRUE
;
789 /*! \brief Continue mouse panning in the view
790 * \par Function Description
791 * In the view pan mode, this function calculates displacement of
792 * the mouse pointer relative to its previous position and repans
793 * the view taking into account the given mouse pan gain setting.
794 * Then it replaces pan_x and pan_y with the new coordinates.
796 * \param [in,out] view This GschemPageView
797 * \param [in] mousepan_gain Mouse pan gain
798 * \param [in] x The new screen x coordinate
799 * \param [in] y The new screen y coordinate
802 gschem_page_view_pan_motion (GschemPageView
*view
, int mousepan_gain
, int x
, int y
)
804 int pdiff_x
, pdiff_y
;
806 if (view
->doing_pan
) {
807 pdiff_x
= x
- view
->pan_x
;
808 pdiff_y
= y
- view
->pan_y
;
810 if (!(view
->throttle
% 5)) {
811 gschem_page_view_pan_mouse(view
,
812 pdiff_x
* mousepan_gain
,
813 pdiff_y
* mousepan_gain
);
822 /*! \brief End mouse panning in the view
823 * \par Function Description
824 * This function resets the view pan mode and invalidates the
825 * view after panning.
827 * \param [in,out] view This GschemPageView
828 * \returns TRUE if panning has been finished, or FALSE if there was no panning
831 gschem_page_view_pan_end (GschemPageView
*view
)
833 if (view
->doing_pan
) {
834 gschem_page_view_invalidate_all (view
);
835 view
->doing_pan
= FALSE
;
844 /*! \brief Transform SCREEN coordinates to WORLD coordinates
845 * \par Function Description
846 * This function takes in SCREEN x/y coordinates and
847 * transforms them to WORLD x/y coordinates.
849 * \param [in] view The GschemPageView object.
850 * \param [in] mx The x coordinate in SCREEN units.
851 * \param [in] my The y coordinate in SCREEN units.
852 * \param [out] x The x coordinate in WORLD units.
853 * \param [out] y The y coordinate in WORLD units.
854 * \note Question: why are we returning in x and y
855 * if this is SCREEN to WORLD shouldn't WORLD
856 * coordinates be returned in mx and my?
859 gschem_page_view_SCREENtoWORLD (GschemPageView
*view
, int mx
, int my
, int *x
, int *y
)
861 GschemPageGeometry
*geometry
= gschem_page_view_get_page_geometry (view
);
863 g_return_if_fail (geometry
!= NULL
);
865 *x
= gschem_page_geometry_mil_x (geometry
, mx
);
866 *y
= gschem_page_geometry_mil_y (geometry
, my
);
871 /*! \brief Set the horizontal scroll adjustment for this view
873 * \param [in,out] view The view
874 * \param [in] hadjustment The horizontal scroll adjustment
877 gschem_page_view_set_hadjustment (GschemPageView
*view
, GtkAdjustment
*hadjustment
)
879 g_return_if_fail (view
!= NULL
);
881 if (view
->hadjustment
!= NULL
) {
882 g_signal_handlers_disconnect_by_func (G_OBJECT (view
->hadjustment
),
883 G_CALLBACK (hadjustment_value_changed
),
886 g_object_unref (view
->hadjustment
);
889 view
->hadjustment
= hadjustment
;
891 if (view
->hadjustment
!= NULL
) {
892 g_object_ref (view
->hadjustment
);
894 g_signal_connect (G_OBJECT (view
->hadjustment
),
896 G_CALLBACK (hadjustment_value_changed
),
900 g_object_notify (G_OBJECT (view
), "hadjustment");
905 /*! \brief Set the page for this view
907 * The toplevel property must be set and the page must belong to that
910 * \param [in,out] view The view
911 * \param [in] page The page
914 gschem_page_view_set_page (GschemPageView
*view
, PAGE
*page
)
916 g_return_if_fail (view
!= NULL
);
917 g_return_if_fail (view
->geometry_table
!= NULL
);
919 if (page
!= view
->page
) {
924 s_page_weak_ref (page
, (NotifyFunction
) page_deleted
, view
);
926 g_return_if_fail (page
->toplevel
!= NULL
);
927 s_page_goto (page
->toplevel
, page
);
928 /* gschem_toplevel_page_changed is called by the notify::page handler */
930 /* redraw the current page and update UI */
931 gschem_page_view_invalidate_all (view
);
932 if (gtk_widget_get_window (GTK_WIDGET (view
)) != NULL
)
933 gschem_page_view_update_scroll_adjustments (view
);
935 g_object_notify (G_OBJECT (view
), "page");
936 g_object_notify (G_OBJECT (view
), "page-geometry");
937 g_signal_emit_by_name (view
, "update-grid-info");
940 if (view
->hadjustment
!= NULL
) {
941 gtk_adjustment_set_page_size (view
->hadjustment
,
942 gtk_adjustment_get_upper (view
->hadjustment
));
944 if (view
->vadjustment
!= NULL
) {
945 gtk_adjustment_set_page_size (view
->vadjustment
,
946 gtk_adjustment_get_upper (view
->vadjustment
));
953 /*! \brief Set the vertical scroll adjustment for this view
955 * \param [in,out] view The view
956 * \param [in] vadjustment The vertical scroll adjustment
959 gschem_page_view_set_vadjustment (GschemPageView
*view
, GtkAdjustment
*vadjustment
)
961 g_return_if_fail (view
!= NULL
);
963 if (view
->vadjustment
!= NULL
) {
964 g_signal_handlers_disconnect_by_func (G_OBJECT (view
->vadjustment
),
965 G_CALLBACK (vadjustment_value_changed
),
968 g_object_unref (view
->vadjustment
);
971 view
->vadjustment
= vadjustment
;
973 if (view
->vadjustment
!= NULL
) {
974 g_object_ref (view
->vadjustment
);
976 g_signal_connect (G_OBJECT (view
->vadjustment
),
978 G_CALLBACK (vadjustment_value_changed
),
982 g_object_notify (G_OBJECT (view
), "vadjustment");
987 /*! \brief Signal handler for a horizontal scroll adjustment change
990 hadjustment_value_changed (GtkAdjustment
*hadjustment
, GschemPageView
*view
)
992 g_return_if_fail (hadjustment
!= NULL
);
993 g_return_if_fail (view
!= NULL
);
995 GschemPageGeometry
*geometry
= gschem_page_view_get_page_geometry (view
);
997 if (view
->hadjustment
!= NULL
&& geometry
!= NULL
) {
1001 g_return_if_fail (view
->hadjustment
== hadjustment
);
1003 current_left
= gschem_page_geometry_get_viewport_left (geometry
),
1004 new_left
= (int) hadjustment
->value
;
1006 geometry
->viewport_left
= new_left
;
1007 geometry
->viewport_right
= geometry
->viewport_right
- (current_left
- new_left
);
1009 gschem_page_view_invalidate_all (view
);
1015 /*! \brief Set a gobject property
1018 set_property (GObject
*object
, guint param_id
, const GValue
*value
, GParamSpec
*pspec
)
1020 GschemPageView
*view
= GSCHEM_PAGE_VIEW (object
);
1023 case PROP_HADJUSTMENT
:
1024 gschem_page_view_set_hadjustment (view
, g_value_get_object (value
));
1028 gschem_page_view_set_page (view
, g_value_get_pointer (value
));
1031 case PROP_VADJUSTMENT
:
1032 gschem_page_view_set_vadjustment (view
, g_value_get_object (value
));
1036 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, param_id
, pspec
);
1042 /*! \brief Get absolute SCREEN value
1044 * \par Function Description
1045 * Converts WORLD value \a val to absolute SCREEN value.
1047 * \param [in] view This GschemPageView
1048 * \param [in] val The value to convert
1049 * \return The converted value in SCREEN pixels
1052 gschem_page_view_SCREENabs(GschemPageView
*view
, int val
)
1057 GschemPageGeometry
*geometry
= gschem_page_view_get_page_geometry (view
);
1059 g_return_val_if_fail (view
!= NULL
, 0);
1061 if (geometry
== NULL
) return 0;
1063 f0
= gschem_page_geometry_get_viewport_left (geometry
);
1064 f1
= gschem_page_geometry_get_viewport_right (geometry
);
1065 i
= (double)(geometry
->screen_width
) * (double)(val
) / (f1
- f0
);
1078 /*! \brief Update the horizontal scroll adjustment
1081 gschem_page_view_update_hadjustment (GschemPageView
*view
)
1083 g_return_if_fail (view
!= NULL
);
1085 GschemPageGeometry
*geometry
= gschem_page_view_get_page_geometry (view
);
1087 if (view
->hadjustment
!= NULL
&& geometry
!= NULL
) {
1089 gtk_adjustment_set_page_increment (view
->hadjustment
,
1090 abs (geometry
->viewport_right
- geometry
->viewport_left
) - 100.0);
1092 gtk_adjustment_set_page_size (view
->hadjustment
,
1093 abs (geometry
->viewport_right
- geometry
->viewport_left
));
1095 gtk_adjustment_set_value (view
->hadjustment
,
1096 geometry
->viewport_left
);
1099 printf("H %f %f\n", view
->hadjustment
->lower
, view
->hadjustment
->upper
);
1100 printf("Hp %f\n", view
->hadjustment
->page_size
);
1103 gtk_adjustment_changed(view
->hadjustment
);
1104 gtk_adjustment_value_changed (view
->hadjustment
);
1110 /*! \brief Update the scroll adjustments
1113 gschem_page_view_update_scroll_adjustments (GschemPageView
*view
)
1115 g_return_if_fail (view
!= NULL
);
1117 gschem_page_view_update_hadjustment (view
);
1118 gschem_page_view_update_vadjustment (view
);
1123 /*! \brief Update the vertical scroll adjustment
1126 gschem_page_view_update_vadjustment (GschemPageView
*view
)
1128 g_return_if_fail (view
!= NULL
);
1130 GschemPageGeometry
*geometry
= gschem_page_view_get_page_geometry (view
);
1132 if (view
->vadjustment
!= NULL
&& geometry
!= NULL
) {
1134 gtk_adjustment_set_page_increment(view
->vadjustment
,
1135 abs (geometry
->viewport_bottom
- geometry
->viewport_top
) - 100.0);
1137 gtk_adjustment_set_page_size (view
->vadjustment
,
1138 abs (geometry
->viewport_bottom
- geometry
->viewport_top
));
1140 gtk_adjustment_set_value(view
->vadjustment
,
1141 geometry
->world_bottom
- geometry
->viewport_bottom
);
1144 printf("V %f %f\n", view
->vadjustment
->lower
, view
->vadjustment
->upper
);
1145 printf("Vp %f\n", view
->vadjustment
->page_size
);
1148 gtk_adjustment_changed(view
->vadjustment
);
1149 gtk_adjustment_value_changed (view
->vadjustment
);
1154 /*! \brief Get absolute WORLD coordinate.
1155 * \par Function Description
1156 * Get absolute WORLD coordinate.
1158 * \param [in,out] view The view
1159 * \param [in] val The coordinate to convert.
1160 * \return The converted WORLD coordinate.
1163 gschem_page_view_WORLDabs(GschemPageView
*page_view
, int val
)
1165 GtkAllocation allocation
;
1166 double fw0
,fw1
,fw
,fval
;
1170 GschemPageGeometry
*geometry
= gschem_page_view_get_page_geometry (page_view
);
1172 gtk_widget_get_allocation (GTK_WIDGET(page_view
), &allocation
);
1174 fw1
= geometry
->viewport_right
;
1175 fw0
= geometry
->viewport_left
;
1176 fw
= allocation
.width
;
1178 i
= fval
* (fw1
- fw0
) / fw
;
1195 remove_page_weak_reference (PAGE
*page
, gpointer geometry
, GschemPageView
*view
)
1197 typedef void (*NotifyFunction
) (void*,void*);
1199 g_return_if_fail (page
!= NULL
);
1200 g_return_if_fail (view
!= NULL
);
1202 s_page_weak_unref (page
, (NotifyFunction
) page_deleted
, view
);
1211 page_deleted (PAGE
*page
, GschemPageView
*view
)
1213 g_return_if_fail (page
!= NULL
);
1214 g_return_if_fail (view
!= NULL
);
1215 g_return_if_fail (view
->geometry_table
!= NULL
);
1217 g_hash_table_remove (view
->geometry_table
, page
);
1218 if (view
->page
== page
)
1219 gschem_page_view_set_page (view
, NULL
);
1224 /*! \brief Signal handler for setting the scroll adjustments
1226 * Sent from the GtkScrolledWindow to set the adjustments for the
1227 * corresponding scroll bars.
1230 set_scroll_adjustments (GschemPageView
*view
, GtkAdjustment
*hadjustment
, GtkAdjustment
*vadjustment
)
1232 gschem_page_view_set_hadjustment (view
, hadjustment
);
1233 gschem_page_view_set_vadjustment (view
, vadjustment
);
1238 /*! \brief Signal handler for a vertical scroll adjustment change
1241 vadjustment_value_changed (GtkAdjustment
*vadjustment
, GschemPageView
*view
)
1243 g_return_if_fail (vadjustment
!= NULL
);
1244 g_return_if_fail (view
!= NULL
);
1246 GschemPageGeometry
*geometry
= gschem_page_view_get_page_geometry (view
);
1248 if (view
->vadjustment
!= NULL
&& geometry
!= NULL
) {
1252 g_return_if_fail (view
->vadjustment
== vadjustment
);
1254 current_bottom
= geometry
->viewport_bottom
;
1255 new_bottom
= geometry
->world_bottom
- (int) vadjustment
->value
;
1257 geometry
->viewport_bottom
= new_bottom
;
1258 geometry
->viewport_top
= geometry
->viewport_top
- (current_bottom
- new_bottom
);
1260 gschem_page_view_invalidate_all (view
);
1266 /*! \brief Transform WORLD coordinates to SCREEN coordinates
1269 gschem_page_view_WORLDtoSCREEN (GschemPageView
*view
, int x
, int y
, int *px
, int *py
)
1271 GschemPageGeometry
*geometry
= gschem_page_view_get_page_geometry (view
);
1275 g_return_if_fail (geometry
!= NULL
);
1277 *px
= gschem_page_geometry_pix_x (geometry
, x
);
1278 *py
= gschem_page_geometry_pix_y (geometry
, y
);
1283 /*! \brief Zoom the view to the extents of a set of objects
1285 * By providing a NULL for the objects parameter, this function will zoom to
1286 * the extents of all objects in the drawing.
1288 * \param [in,out] view This GschemPageView
1289 * \param [in] objects The list of objects to compute extents, or NULL
1292 gschem_page_view_zoom_extents (GschemPageView
*view
, const GList
*objects
)
1294 GschemPageGeometry
*geometry
= NULL
;
1296 const GList
*temp
= objects
;
1298 g_return_if_fail (view
!= NULL
);
1300 page
= gschem_page_view_get_page (view
);
1301 g_return_if_fail (page
!= NULL
);
1303 geometry
= gschem_page_view_get_page_geometry (view
);
1304 g_return_if_fail (geometry
!= NULL
);
1307 temp
= s_page_objects (gschem_page_view_get_page (view
));
1310 gschem_page_geometry_zoom_extents (geometry
, page
->toplevel
, temp
);
1312 /* Trigger a motion event to update the objects being drawn */
1313 x_event_faked_motion (view
, NULL
);
1315 g_signal_emit_by_name (view
, "update-grid-info");
1316 gschem_page_view_update_scroll_adjustments (view
);
1317 gschem_page_view_invalidate_all (view
);
1320 /*! \brief utility function to find the first parent that has a ->page
1322 * \param [in] object The object
1323 * \return the parent object that had a non-NULL ->page
1325 OBJECT
*gschem_page_get_page_object(OBJECT
*object
)
1327 OBJECT
*page_obj
= object
;
1328 while((page_obj
!= NULL
) && (page_obj
->page
== NULL
))
1329 page_obj
= page_obj
->parent
;
1333 /*! \brief Zoom in on a single text object
1335 * \param [in] view This GschemPageView
1336 * \param [in] object The text object
1339 gschem_page_view_zoom_text (GschemPageView
*view
, OBJECT
*object
, gboolean zoom_hidden
)
1345 int viewport_center_x
, viewport_center_y
, viewport_width
, viewport_height
;
1347 int old_show_hidden
;
1349 g_return_if_fail (view
!= NULL
);
1350 GschemPageGeometry
*geometry
= gschem_page_view_get_page_geometry (view
);
1351 g_return_if_fail (geometry
!= NULL
);
1353 g_return_if_fail (object
!= NULL
);
1355 page_obj
= gschem_page_get_page_object(object
);
1357 g_return_if_fail (page_obj
->page
!= NULL
);
1358 g_return_if_fail (page_obj
->page
->toplevel
!= NULL
);
1359 g_return_if_fail (object
->text
!= NULL
);
1362 old_show_hidden
= page_obj
->page
->toplevel
->show_hidden_text
;
1363 page_obj
->page
->toplevel
->show_hidden_text
= 1;
1366 success
= world_get_single_object_bounds (page_obj
->page
->toplevel
,
1373 page_obj
->page
->toplevel
->show_hidden_text
= old_show_hidden
;
1377 /* Here we are trying to make the text screen height to be about */
1378 /* 50 pixels high, perhaps a future enhancement will be to make */
1379 /* this number configurable */
1380 viewport_center_x
= (x
[1] + x
[0]) / 2;
1381 viewport_center_y
= (y
[1] + y
[0]) / 2;
1382 k
= ((y
[1] - y
[0]) / 50);
1383 viewport_height
= geometry
->screen_height
* k
;
1384 viewport_width
= geometry
->screen_width
* k
;
1386 gschem_page_geometry_set_values (geometry
,
1388 geometry
->screen_width
,
1389 geometry
->screen_height
,
1390 viewport_center_x
- viewport_width
/ 2,
1391 viewport_center_y
- viewport_height
/ 2,
1392 viewport_center_x
+ viewport_width
/ 2,
1393 viewport_center_y
+ viewport_height
/ 2);
1395 gschem_page_view_invalidate_all (view
);
1400 /*! \brief Redraw page on the view
1402 * \param [in] view The GschemPageView object which page to redraw
1405 gschem_page_view_redraw (GschemPageView
*view
, GdkEventExpose
*event
, GschemToplevel
*w_current
)
1407 GschemPageGeometry
*geometry
;
1414 g_return_if_fail (view
!= NULL
);
1415 g_return_if_fail (w_current
!= NULL
);
1417 page
= gschem_page_view_get_page (view
);
1420 geometry
= gschem_page_view_get_page_geometry (view
);
1422 g_return_if_fail (view
!= NULL
);
1424 o_redraw_rect (w_current
,
1425 gtk_widget_get_window (GTK_WIDGET(view
)),