missing NULL terminator in set_config_x
[geda-gaf.git] / gschem / src / gschem_preview.c
blob7cdc77632ededd0299a510f509303455edbb84af
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
20 /*!
21 * \file gschem_preview.c
23 * \brief A widget for viewing a symbol or schematic
26 #include <config.h>
28 #include <stdio.h>
29 #ifdef HAVE_STDLIB_H
30 #include <stdlib.h>
31 #endif
32 #ifdef HAVE_STRING_H
33 #include <string.h>
34 #endif
35 #ifdef HAVE_UNISTD_H
36 #include <unistd.h>
37 #endif
39 #include "gschem.h"
41 #define OVER_ZOOM_FACTOR 0.1
44 enum {
45 PROP_FILENAME=1,
46 PROP_BUFFER,
47 PROP_ACTIVE
50 static GObjectClass *preview_parent_class = NULL;
53 static void preview_zoom (GschemPreview *preview);
55 static void preview_class_init (GschemPreviewClass *class);
56 static void preview_init (GschemPreview *preview);
57 static void preview_set_property (GObject *object,
58 guint property_id,
59 const GValue *value,
60 GParamSpec *pspec);
61 static void preview_get_property (GObject *object,
62 guint property_id,
63 GValue *value,
64 GParamSpec *pspec);
65 static void preview_dispose (GObject *self);
68 /*! \brief create a new preview widget
70 GtkWidget*
71 gschem_preview_new ()
73 return GTK_WIDGET (g_object_new (GSCHEM_TYPE_PREVIEW, NULL));
77 /*! \brief get the filename for the current page
79 static char*
80 preview_get_filename (GschemPreview *preview)
82 PAGE *page = gschem_page_view_get_page (GSCHEM_PAGE_VIEW (preview));
84 g_return_val_if_fail (page != NULL, "");
86 return page->page_filename;
90 /*! \brief Completes initialitation of the widget after realization.
91 * \par Function Description
92 * This function terminates the initialization of the preview widget
93 * after it has been realized.
95 * \param [in] widget The preview widget.
96 * \param [in] user_data Unused user data.
98 static void
99 preview_callback_realize (GtkWidget *widget, gpointer user_data)
101 g_return_if_fail (widget != NULL);
103 gtk_widget_grab_focus (widget);
104 gschem_page_view_zoom_extents (GSCHEM_PAGE_VIEW (widget), NULL);
108 /*! \brief Trigger deferred zoom and redraw preview widget.
110 static gboolean
111 preview_callback_expose_event (GtkWidget *widget,
112 GdkEvent *event,
113 gpointer user_data)
115 GschemPreview *preview = GSCHEM_PREVIEW (widget);
117 if (preview->needs_zoom) {
118 preview_zoom (preview);
119 preview->needs_zoom = FALSE;
122 return x_event_expose (GSCHEM_PAGE_VIEW (widget), &event->expose, user_data);
126 /*! \brief Handles the press on a mouse button.
127 * \par Function Description
128 * It handles the user inputs.
130 * Three action are available: zoom in, pan and zoom out on preview display.
132 * \param [in] widget The preview widget.
133 * \param [in] event The event structure.
134 * \param [in] user_data Unused user data.
135 * \returns FALSE to propagate the event further.
137 static gboolean
138 preview_callback_button_press (GtkWidget *widget,
139 GdkEventButton *event,
140 gpointer user_data)
142 GschemPreview *preview = GSCHEM_PREVIEW (widget);
143 GschemToplevel *preview_w_current = preview->preview_w_current;
144 gint wx, wy;
146 if (!preview->active) {
147 return TRUE;
150 switch (event->button) {
151 case 1: /* left mouse button: zoom in */
152 a_zoom (preview_w_current,
153 GSCHEM_PAGE_VIEW (preview),
154 ZOOM_IN,
155 HOTKEY);
156 gschem_page_view_invalidate_all (GSCHEM_PAGE_VIEW (widget));
157 break;
158 case 2: /* middle mouse button: pan */
159 if (!x_event_get_pointer_position(preview_w_current, FALSE, &wx, &wy))
160 return FALSE;
161 gschem_page_view_pan (GSCHEM_PAGE_VIEW (preview), wx, wy);
162 break;
163 case 3: /* right mouse button: zoom out */
164 a_zoom (preview_w_current,
165 GSCHEM_PAGE_VIEW (preview),
166 ZOOM_OUT,
167 HOTKEY);
168 gschem_page_view_invalidate_all (GSCHEM_PAGE_VIEW (widget));
169 break;
172 return FALSE;
176 /*! \brief Updates the preview widget.
177 * \par Function Description
178 * This function updates the preview: if the preview is active and a
179 * filename has been given, it opens the file and displays
180 * it. Otherwise it displays a blank page.
182 * \param [in] preview The preview widget.
184 static void
185 preview_update (GschemPreview *preview)
187 GError * err = NULL;
189 GschemPageView *preview_view = GSCHEM_PAGE_VIEW (preview);
191 g_return_if_fail (preview_view != NULL);
192 PAGE *preview_page = gschem_page_view_get_page (preview_view);
194 if (preview_page == NULL) {
195 return;
198 TOPLEVEL *preview_toplevel = preview_page->toplevel;
200 /* delete old preview */
201 s_page_delete_objects (preview_toplevel, preview_page);
203 if (preview->active) {
204 g_assert ((preview->filename == NULL) || (preview->buffer == NULL));
205 if (preview->filename != NULL) {
206 /* open up file in current page */
207 f_open_flags (preview_toplevel, preview_page,
208 preview->filename,
209 F_OPEN_RC | F_OPEN_RESTORE_CWD, NULL);
210 /* test value returned by f_open... - Fix me */
211 /* we should display something if there an error occured - Fix me */
213 if (preview->buffer != NULL) {
214 /* Load the data buffer */
215 GList * objects = o_read_buffer (preview_toplevel,
216 NULL, preview->buffer, -1,
217 _("Preview Buffer"), &err);
219 if (err == NULL) {
220 s_page_append_list (preview_toplevel, preview_page,
221 objects);
223 else {
224 s_page_append (preview_toplevel, preview_page,
225 o_text_new(preview_toplevel, 2, 100, 100, LOWER_MIDDLE, 0,
226 err->message, 10, VISIBLE, SHOW_NAME_VALUE));
227 g_error_free(err);
232 if (gtk_widget_get_window (GTK_WIDGET (preview)) != NULL) {
233 preview_zoom (preview);
234 preview->needs_zoom = FALSE;
235 } else
236 preview->needs_zoom = TRUE;
239 static void
240 preview_zoom (GschemPreview *preview)
242 GschemPageView *preview_view = GSCHEM_PAGE_VIEW (preview);
243 PAGE *preview_page = gschem_page_view_get_page (preview_view);
244 if (preview_page == NULL)
245 return;
247 int left, top, right, bottom;
248 int width, height;
250 if (world_get_object_glist_bounds (preview_page->toplevel,
251 s_page_objects (preview_page),
252 &left, &top,
253 &right, &bottom)) {
254 /* Clamp the canvas size to the extents of the page being previewed */
255 width = right - left;
256 height = bottom - top;
258 GschemPageGeometry *geometry = gschem_page_view_get_page_geometry (preview_view);
259 geometry->world_left = left - ((double)width * OVER_ZOOM_FACTOR);
260 geometry->world_right = right + ((double)width * OVER_ZOOM_FACTOR);
261 geometry->world_top = top - ((double)height * OVER_ZOOM_FACTOR);
262 geometry->world_bottom = bottom + ((double)height * OVER_ZOOM_FACTOR);
265 /* display current page (possibly empty) */
266 gschem_page_view_zoom_extents (preview_view, NULL);
269 GType
270 gschem_preview_get_type ()
272 static GType preview_type = 0;
274 if (!preview_type) {
275 static const GTypeInfo preview_info = {
276 sizeof(GschemPreviewClass),
277 NULL, /* base_init */
278 NULL, /* base_finalize */
279 (GClassInitFunc) preview_class_init,
280 NULL, /* class_finalize */
281 NULL, /* class_data */
282 sizeof(GschemPreview),
283 0, /* n_preallocs */
284 (GInstanceInitFunc) preview_init,
287 preview_type = g_type_register_static (GSCHEM_TYPE_PAGE_VIEW,
288 "GschemPreview",
289 &preview_info, 0);
292 return preview_type;
295 static void
296 preview_class_init (GschemPreviewClass *klass)
298 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
300 preview_parent_class = g_type_class_peek_parent (klass);
302 gobject_class->set_property = preview_set_property;
303 gobject_class->get_property = preview_get_property;
304 gobject_class->dispose = preview_dispose;
306 g_object_class_install_property (
307 gobject_class, PROP_FILENAME,
308 g_param_spec_string ("filename",
311 NULL,
312 G_PARAM_READWRITE));
313 g_object_class_install_property (
314 gobject_class, PROP_BUFFER,
315 g_param_spec_string ("buffer",
318 NULL,
319 G_PARAM_WRITABLE));
320 g_object_class_install_property(
321 gobject_class, PROP_ACTIVE,
322 g_param_spec_boolean ("active",
325 FALSE,
326 G_PARAM_READWRITE));
332 static gboolean
333 preview_event_scroll (GtkWidget *widget,
334 GdkEventScroll *event,
335 GschemToplevel *w_current)
337 if (!GSCHEM_PREVIEW (widget)->active) {
338 return TRUE;
340 return x_event_scroll (widget, event, GSCHEM_PREVIEW (widget)->preview_w_current);
343 static void
344 preview_init (GschemPreview *preview)
346 struct event_reg_t {
347 gchar *detailed_signal;
348 GCallback c_handler;
349 } drawing_area_events[] = {
350 { "realize", G_CALLBACK (preview_callback_realize) },
351 { "expose_event", G_CALLBACK (preview_callback_expose_event) },
352 { "button_press_event", G_CALLBACK (preview_callback_button_press) },
353 { "configure_event", G_CALLBACK (x_event_configure) },
354 { "scroll_event", G_CALLBACK (preview_event_scroll) },
355 { NULL, NULL }
356 }, *tmp;
358 GschemToplevel *preview_w_current;
359 preview_w_current = gschem_toplevel_new ();
360 gschem_toplevel_set_toplevel (preview_w_current, s_toplevel_new ());
362 preview_w_current->toplevel->load_newer_backup_func =
363 x_fileselect_load_backup;
364 preview_w_current->toplevel->load_newer_backup_data =
365 preview_w_current;
366 o_text_set_rendered_bounds_func (preview_w_current->toplevel,
367 o_text_get_rendered_bounds,
368 preview_w_current);
370 i_vars_set (preview_w_current);
372 /* be sure to turn off scrollbars */
373 preview_w_current->scrollbars_flag = FALSE;
375 /* be sure to turn off the grid */
376 gschem_options_set_grid_mode (preview_w_current->options, GRID_MODE_NONE);
378 /* preview_w_current windows don't have toolbars */
379 preview_w_current->handleboxes = FALSE;
380 preview_w_current->toolbars = FALSE;
382 preview_w_current->drawing_area = GTK_WIDGET (preview);
383 preview->preview_w_current = preview_w_current;
385 preview->active = FALSE;
386 preview->needs_zoom = FALSE;
387 preview->filename = NULL;
388 preview->buffer = NULL;
389 gschem_page_view_set_page (GSCHEM_PAGE_VIEW (preview),
390 s_page_new (preview->preview_w_current->toplevel,
391 "preview"));
393 gtk_widget_set_events (GTK_WIDGET (preview),
394 GDK_EXPOSURE_MASK |
395 GDK_POINTER_MOTION_MASK |
396 GDK_BUTTON_PRESS_MASK);
397 for (tmp = drawing_area_events; tmp->detailed_signal != NULL; tmp++) {
398 g_signal_connect (GTK_WIDGET (preview),
399 tmp->detailed_signal,
400 tmp->c_handler,
401 preview_w_current);
406 static void
407 preview_set_property (GObject *object,
408 guint property_id,
409 const GValue *value,
410 GParamSpec *pspec)
412 GschemPreview *preview = GSCHEM_PREVIEW (object);
413 GschemToplevel *preview_w_current = preview->preview_w_current;
415 g_assert (preview_w_current != NULL);
417 switch(property_id) {
418 case PROP_FILENAME:
419 if (preview->buffer != NULL) {
420 g_free (preview->buffer);
421 preview->buffer = NULL;
422 g_object_notify (object, "buffer");
424 g_free (preview->filename);
425 preview->filename = g_strdup (g_value_get_string (value));
426 break;
428 case PROP_BUFFER:
429 if (preview->filename != NULL) {
430 g_free (preview->filename);
431 preview->filename = NULL;
432 g_object_notify (object, "filename");
434 g_free (preview->buffer);
435 preview->buffer = g_strdup (g_value_get_string (value));
436 break;
438 case PROP_ACTIVE:
439 preview->active = g_value_get_boolean (value);
440 preview_update (preview);
441 break;
442 default:
443 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
448 static void
449 preview_get_property (GObject *object,
450 guint property_id,
451 GValue *value,
452 GParamSpec *pspec)
454 GschemPreview *preview = GSCHEM_PREVIEW (object);
456 switch(property_id) {
457 case PROP_FILENAME:
458 g_value_set_string (value, preview_get_filename (preview));
459 break;
461 case PROP_ACTIVE:
462 g_value_set_boolean (value, preview->active);
463 break;
465 default:
466 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
470 static void
471 preview_dispose (GObject *self)
473 GschemPreview *preview = GSCHEM_PREVIEW (self);
474 GschemToplevel *preview_w_current = preview->preview_w_current;
476 if (preview_w_current != NULL) {
477 preview_w_current->drawing_area = NULL;
479 gschem_toplevel_free (preview_w_current);
481 preview->preview_w_current = NULL;
484 G_OBJECT_CLASS (preview_parent_class)->dispose (self);