pcb 4.1.1
An interactive printed circuit board layout editor.
|
00001 /* 00002 * COPYRIGHT 00003 * 00004 * PCB, interactive printed circuit board design 00005 * Copyright (C) 2009 PCB Contributors (See ChangeLog for details) 00006 * 00007 * This program is free software; you can redistribute it and/or modify 00008 * it under the terms of the GNU General Public License as published by 00009 * the Free Software Foundation; either version 2 of the License, or 00010 * (at your option) any later version. 00011 * 00012 * This program is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 * GNU General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU General Public License along 00018 * with this program; if not, write to the Free Software Foundation, Inc., 00019 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 00020 * 00021 * Contact addresses for paper mail and Email: 00022 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany 00023 * Thomas.Nau@rz.uni-ulm.de 00024 * 00025 */ 00026 00027 #ifdef HAVE_CONFIG_H 00028 #include "config.h" 00029 #endif 00030 00031 #include "global.h" 00032 00033 #include "gui.h" 00034 00035 #include "copy.h" 00036 #include "data.h" 00037 #include "draw.h" 00038 #include "mymem.h" 00039 #include "move.h" 00040 #include "rotate.h" 00041 #include "hid/common/trackball.h" 00042 #include "gui-trackball.h" 00043 00044 #ifdef HAVE_LIBDMALLOC 00045 #include <dmalloc.h> 00046 #endif 00047 00048 enum { 00049 ROTATION_CHANGED, 00050 VIEW_2D_CHANGED, 00051 LAST_SIGNAL 00052 }; 00053 00054 00055 static guint ghid_trackball_signals[ LAST_SIGNAL ] = { 0 }; 00056 static GObjectClass *ghid_trackball_parent_class = NULL; 00057 00058 00059 static gboolean 00060 button_press_cb (GtkWidget *widget, GdkEventButton *ev, gpointer userdata) 00061 { 00062 GhidTrackball *ball = GHID_TRACKBALL (userdata); 00063 float axis[3]; 00064 00065 /* Only respond to left mouse button for now */ 00066 if (ev->button != 1) 00067 return TRUE; 00068 00069 switch (ev->type) { 00070 00071 case GDK_BUTTON_PRESS: 00072 ball->x1 = 2. * ev->x / widget->allocation.width - 1.; 00073 ball->y1 = 2. * ev->y / widget->allocation.height - 1.; 00074 ball->dragging = TRUE; 00075 break; 00076 00077 case GDK_2BUTTON_PRESS: 00078 /* Reset the rotation of the trackball */ 00079 /* TODO: Would be nice to animate this! */ 00080 axis[0] = 1.; axis[1] = 0.; axis[2] = 0.; 00081 axis_to_quat (axis, 0, ball->quart1); 00082 axis_to_quat (axis, 0, ball->quart2); 00083 g_signal_emit (ball, ghid_trackball_signals[ROTATION_CHANGED], 0, 00084 ball->quart2); 00085 break; 00086 00087 default: 00088 break; 00089 } 00090 00091 return TRUE; 00092 } 00093 00094 00095 static gboolean 00096 button_release_cb (GtkWidget *widget, GdkEventButton *ev, gpointer userdata) 00097 { 00098 GhidTrackball *ball = GHID_TRACKBALL (userdata); 00099 00100 /* Only respond to left mouse button for now */ 00101 if (ev->button != 1) 00102 return TRUE; 00103 00104 ball->quart1[0] = ball->quart2[0]; 00105 ball->quart1[1] = ball->quart2[1]; 00106 ball->quart1[2] = ball->quart2[2]; 00107 ball->quart1[3] = ball->quart2[3]; 00108 00109 ball->dragging = FALSE; 00110 00111 return TRUE; 00112 } 00113 00114 00115 static gboolean 00116 motion_notify_cb (GtkWidget *widget, GdkEventMotion *ev, gpointer userdata) 00117 { 00118 GhidTrackball *ball = GHID_TRACKBALL (userdata); 00119 double x1, y1; 00120 double x2, y2; 00121 float q[4]; 00122 00123 if (!ball->dragging) { 00124 gdk_event_request_motions (ev); 00125 return TRUE; 00126 } 00127 00128 x1 = ball->x1; 00129 y1 = ball->y1; 00130 00131 x2 = 2. * ev->x / widget->allocation.width - 1.; 00132 y2 = 2. * ev->y / widget->allocation.height - 1.; 00133 00134 /* Trackball computation */ 00135 trackball (q, x1, y1, x2, y2); 00136 add_quats (q, ball->quart1, ball->quart2); 00137 00138 g_signal_emit (ball, ghid_trackball_signals[ROTATION_CHANGED], 0, 00139 ball->quart2); 00140 00141 gdk_event_request_motions (ev); 00142 return TRUE; 00143 } 00144 00145 static gboolean 00146 ghid_trackball_expose (GtkWidget * widget, GdkEventExpose * ev) 00147 { 00148 cairo_t *cr; 00149 cairo_pattern_t *pattern; 00150 GtkAllocation allocation; 00151 GdkColor color; 00152 double radius; 00153 00154 cr = gdk_cairo_create (gtk_widget_get_window (widget)); 00155 00156 /* set a clip region for the expose event */ 00157 cairo_rectangle (cr, 00158 ev->area.x, ev->area.y, 00159 ev->area.width, ev->area.height); 00160 cairo_clip (cr); 00161 00162 gtk_widget_get_allocation (widget, &allocation); 00163 00164 radius = (MIN (allocation.width, allocation.height) - 5) / 2.; 00165 pattern = cairo_pattern_create_radial (2 * radius * 0.8, 00166 2 * radius * 0.3, 00167 0., 00168 2 * radius * 0.50, 00169 2 * radius * 0.50, 00170 2 * radius * 0.71); 00171 00172 color = widget->style->fg[gtk_widget_get_state (widget)]; 00173 00174 cairo_pattern_add_color_stop_rgb (pattern, 0.0, 00175 (color.red / 65535. * 0.5 + 4.5) / 5., 00176 (color.green / 65535. * 0.5 + 4.5) / 5., 00177 (color.blue / 65535. * 0.5 + 4.5) / 5.); 00178 cairo_pattern_add_color_stop_rgb (pattern, 0.2, 00179 (color.red / 65535. * 1.5 + 3.7) / 5., 00180 (color.green / 65535. * 1.5 + 3.7) / 5., 00181 (color.blue / 65535. * 1.5 + 3.7) / 5.); 00182 cairo_pattern_add_color_stop_rgb (pattern, 1.0, 00183 (color.red / 65535. * 5. + 0.) / 5., 00184 (color.green / 65535. * 5. + 0.) / 5., 00185 (color.blue / 65535. * 5. + 0.) / 5.); 00186 cairo_set_source (cr, pattern); 00187 cairo_pattern_destroy (pattern); 00188 00189 cairo_save (cr); 00190 cairo_translate (cr, allocation.width / 2., allocation.height / 2.); 00191 cairo_scale (cr, radius, radius); 00192 cairo_arc (cr, 0., 0., 1., 0., 2 * M_PI); 00193 cairo_restore (cr); 00194 00195 cairo_fill_preserve (cr); 00196 00197 gdk_cairo_set_source_color (cr, &widget->style->bg[gtk_widget_get_state (widget)]); 00198 cairo_set_line_width (cr, 0.4); 00199 cairo_stroke (cr); 00200 00201 cairo_destroy (cr); 00202 00203 return FALSE; 00204 } 00205 00206 static gboolean 00207 view_2d_toggled_cb (GtkToggleButton *toggle, gpointer userdata) 00208 { 00209 GhidTrackball *ball = GHID_TRACKBALL (userdata); 00210 float axis[3]; 00211 float quart[4]; 00212 gboolean view_2d; 00213 00214 view_2d = gtk_toggle_button_get_active (toggle); 00215 if (view_2d) 00216 { 00217 axis[0] = 1.; axis[1] = 0.; axis[2] = 0.; 00218 axis_to_quat (axis, 0, quart); 00219 00220 g_signal_emit (ball, ghid_trackball_signals[ROTATION_CHANGED], 0, quart); 00221 gtk_widget_set_sensitive (ball->drawing_area, FALSE); 00222 } 00223 else 00224 { 00225 g_signal_emit (ball, ghid_trackball_signals[ROTATION_CHANGED], 0, ball->quart1); 00226 gtk_widget_set_sensitive (ball->drawing_area, TRUE); 00227 } 00228 00229 g_signal_emit (ball, ghid_trackball_signals[VIEW_2D_CHANGED], 0, view_2d); 00230 00231 return TRUE; 00232 } 00245 static GObject * 00246 ghid_trackball_constructor (GType type, 00247 guint n_construct_properties, 00248 GObjectConstructParam *construct_properties) 00249 { 00250 GhidTrackball *ball; 00251 float axis[3]; 00252 00253 /* chain up to constructor of parent class */ 00254 ball = GHID_TRACKBALL (G_OBJECT_CLASS (ghid_trackball_parent_class)-> 00255 constructor (type, n_construct_properties, construct_properties)); 00256 00257 gtk_widget_set_size_request (GTK_WIDGET (ball), 140, 140); 00258 00259 ball->view_2d = gtk_toggle_button_new_with_label (_("2D View")); 00260 gtk_box_pack_start (GTK_BOX (ball), ball->view_2d, FALSE, FALSE, 0); 00261 gtk_widget_show (ball->view_2d); 00262 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ball->view_2d), TRUE); 00263 00264 ball->drawing_area = gtk_drawing_area_new (); 00265 gtk_box_pack_start (GTK_BOX (ball), ball->drawing_area, TRUE, TRUE, 0); 00266 gtk_widget_set_sensitive (ball->drawing_area, FALSE); 00267 gtk_widget_show (ball->drawing_area); 00268 00269 axis[0] = 1.; axis[1] = 0.; axis[2] = 0.; 00270 axis_to_quat (axis, 0, ball->quart1); 00271 axis_to_quat (axis, 0, ball->quart2); 00272 00273 g_signal_connect (ball->view_2d, "toggled", 00274 G_CALLBACK (view_2d_toggled_cb), ball); 00275 00276 g_signal_connect (ball->drawing_area, "expose-event", 00277 G_CALLBACK (ghid_trackball_expose), ball); 00278 g_signal_connect (ball->drawing_area, "button-press-event", 00279 G_CALLBACK (button_press_cb), ball); 00280 g_signal_connect (ball->drawing_area, "button-release-event", 00281 G_CALLBACK (button_release_cb), ball); 00282 g_signal_connect (ball->drawing_area, "motion-notify-event", 00283 G_CALLBACK (motion_notify_cb), ball); 00284 00285 gtk_widget_add_events (ball->drawing_area, GDK_BUTTON_PRESS_MASK | 00286 GDK_BUTTON_RELEASE_MASK | 00287 GDK_POINTER_MOTION_MASK | 00288 GDK_POINTER_MOTION_HINT_MASK); 00289 00290 return G_OBJECT (ball); 00291 } 00292 00293 00294 00303 static void 00304 ghid_trackball_finalize (GObject * object) 00305 { 00306 G_OBJECT_CLASS (ghid_trackball_parent_class)->finalize (object); 00307 } 00308 00309 00322 static void 00323 ghid_trackball_set_property (GObject * object, guint property_id, 00324 const GValue * value, GParamSpec * pspec) 00325 { 00326 switch (property_id) 00327 { 00328 default: 00329 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); 00330 } 00331 } 00332 00333 00346 static void 00347 ghid_trackball_get_property (GObject * object, guint property_id, 00348 GValue * value, GParamSpec * pspec) 00349 { 00350 switch (property_id) 00351 { 00352 default: 00353 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); 00354 } 00355 00356 } 00357 00358 00367 static void 00368 ghid_trackball_class_init (GhidTrackballClass * klass) 00369 { 00370 GObjectClass *gobject_class = G_OBJECT_CLASS (klass); 00371 00372 gobject_class->constructor = ghid_trackball_constructor; 00373 gobject_class->finalize = ghid_trackball_finalize; 00374 gobject_class->set_property = ghid_trackball_set_property; 00375 gobject_class->get_property = ghid_trackball_get_property; 00376 00377 ghid_trackball_parent_class = g_type_class_peek_parent (klass); 00378 00379 ghid_trackball_signals[ROTATION_CHANGED] = 00380 g_signal_new ("rotation-changed", 00381 G_OBJECT_CLASS_TYPE( gobject_class ), 00382 G_SIGNAL_RUN_FIRST, /*signal_flags */ 00383 G_STRUCT_OFFSET( GhidTrackballClass, rotation_changed ), 00384 NULL, /* accumulator */ 00385 NULL, /* accu_data */ 00386 g_cclosure_marshal_VOID__POINTER, 00387 G_TYPE_NONE, 00388 1, /* n_params */ 00389 G_TYPE_POINTER 00390 ); 00391 00392 ghid_trackball_signals[VIEW_2D_CHANGED] = 00393 g_signal_new ("view-2d-changed", 00394 G_OBJECT_CLASS_TYPE( gobject_class ), 00395 G_SIGNAL_RUN_FIRST, /*signal_flags */ 00396 G_STRUCT_OFFSET( GhidTrackballClass, view_2d_changed ), 00397 NULL, /* accumulator */ 00398 NULL, /* accu_data */ 00399 g_cclosure_marshal_VOID__BOOLEAN, 00400 G_TYPE_NONE, 00401 1, /* n_params */ 00402 G_TYPE_BOOLEAN 00403 ); 00404 } 00405 00406 00416 GType 00417 ghid_trackball_get_type () 00418 { 00419 static GType ghid_trackball_type = 0; 00420 00421 if (!ghid_trackball_type) 00422 { 00423 static const GTypeInfo ghid_trackball_info = { 00424 sizeof (GhidTrackballClass), 00425 NULL, /* base_init */ 00426 NULL, /* base_finalize */ 00427 (GClassInitFunc) ghid_trackball_class_init, 00428 NULL, /* class_finalize */ 00429 NULL, /* class_data */ 00430 sizeof (GhidTrackball), 00431 0, /* n_preallocs */ 00432 NULL, /* instance_init */ 00433 }; 00434 00435 ghid_trackball_type = 00436 g_type_register_static (GTK_TYPE_VBOX, "GhidTrackball", 00437 &ghid_trackball_info, 0); 00438 } 00439 00440 return ghid_trackball_type; 00441 } 00442 00443 00451 GtkWidget * 00452 ghid_trackball_new (void) 00453 { 00454 GhidTrackball *ball; 00455 00456 ball = g_object_new (GHID_TYPE_TRACKBALL, NULL); 00457 00458 return GTK_WIDGET (ball); 00459 }