gschem

x_preview.c

Go to the documentation of this file.
00001 /* gEDA - GPL Electronic Design Automation
00002  * gschem - gEDA Schematic Capture
00003  * Copyright (C) 1998-2010 Ales Hvezda
00004  * Copyright (C) 1998-2010 gEDA Contributors (see ChangeLog for details)
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00019  */
00020 #include <config.h>
00021 
00022 #include <stdio.h>
00023 #ifdef HAVE_STDLIB_H
00024 #include <stdlib.h>
00025 #endif
00026 #ifdef HAVE_STRING_H
00027 #include <string.h>
00028 #endif
00029 #ifdef HAVE_UNISTD_H
00030 #include <unistd.h>
00031 #endif
00032 
00033 #include "gschem.h"
00034 
00035 #ifdef HAVE_LIBDMALLOC
00036 #include <dmalloc.h>
00037 #endif
00038 
00039 #define OVER_ZOOM_FACTOR 0.1
00040 
00041 
00042 enum {
00043   PROP_FILENAME=1,
00044   PROP_BUFFER,
00045   PROP_ACTIVE
00046 };
00047 
00048 static GObjectClass *preview_parent_class = NULL;
00049 
00050 
00051 static void preview_class_init (PreviewClass *class);
00052 static void preview_init       (Preview *preview);
00053 static void preview_set_property (GObject *object,
00054                                   guint property_id,
00055                                   const GValue *value,
00056                                   GParamSpec *pspec);
00057 static void preview_get_property (GObject *object,
00058                                   guint property_id,
00059                                   GValue *value,
00060                                   GParamSpec *pspec);
00061 static void preview_dispose (GObject *self);
00062 
00073 static void
00074 preview_callback_realize (GtkWidget *widget,
00075                           gpointer user_data)
00076 {
00077   Preview *preview = PREVIEW (widget);
00078   GSCHEM_TOPLEVEL *preview_w_current = preview->preview_w_current;
00079   TOPLEVEL *preview_toplevel = preview_w_current->toplevel;
00080   PAGE *preview_page;
00081 
00082   preview_w_current->window = preview_w_current->drawing_area->window;
00083   gtk_widget_grab_focus (preview_w_current->drawing_area);
00084 
00085   preview_toplevel->width  = preview_w_current->drawing_area->allocation.width;
00086   preview_toplevel->height = preview_w_current->drawing_area->allocation.height;
00087   preview_w_current->win_width  = preview_toplevel->width;
00088   preview_w_current->win_height = preview_toplevel->height;
00089 
00090   preview_w_current->drawable = preview_w_current->window;
00091 
00092   x_window_setup_gc (preview_w_current);
00093 
00094   preview_page = s_page_new (preview_toplevel, "unknown");
00095   s_page_goto (preview_toplevel, preview_page);
00096 
00097   a_zoom_extents(preview_w_current,
00098                  s_page_objects (preview_page),
00099                  A_PAN_DONT_REDRAW);
00100 
00101   o_invalidate_all (preview_w_current);
00102 
00103 }
00104 
00114 static gboolean
00115 preview_callback_expose (GtkWidget *widget,
00116                          GdkEventExpose *event,
00117                          gpointer user_data)
00118 {
00119   Preview *preview = PREVIEW (widget);
00120   GSCHEM_TOPLEVEL *preview_w_current = preview->preview_w_current;
00121   GdkRectangle *rectangles;
00122   int n_rectangles;
00123   cairo_t *save_cr;
00124   PangoLayout *save_pl;
00125 
00126   save_cr = preview_w_current->cr;
00127   save_pl = preview_w_current->pl;
00128 
00129   preview_w_current->cr = gdk_cairo_create (widget->window);
00130   preview_w_current->pl = pango_cairo_create_layout (preview_w_current->cr);
00131 
00132   gdk_region_get_rectangles (event->region, &rectangles, &n_rectangles);
00133   o_redraw_rects (preview_w_current, rectangles, n_rectangles);
00134   g_free (rectangles);
00135 
00136   g_object_unref (preview_w_current->pl);
00137   cairo_destroy (preview_w_current->cr);
00138 
00139   preview_w_current->cr = save_cr;
00140   preview_w_current->pl = save_pl;
00141 
00142   return FALSE;
00143 }
00144 
00156 static gboolean
00157 preview_callback_button_press (GtkWidget *widget,
00158                                GdkEventButton *event,
00159                                gpointer user_data)
00160 {
00161   Preview *preview = PREVIEW (widget);
00162   GSCHEM_TOPLEVEL *preview_w_current = preview->preview_w_current;
00163   gint wx, wy; 
00164 
00165   if (!preview->active) {
00166     return TRUE;
00167   }
00168 
00169   switch (event->button) {
00170       case 1: /* left mouse button: zoom in */
00171         a_zoom (preview_w_current, ZOOM_IN, HOTKEY,
00172                 A_PAN_DONT_REDRAW);
00173         o_invalidate_all (preview_w_current);
00174         break;
00175       case 2: /* middle mouse button: pan */
00176     if (!x_event_get_pointer_position(preview_w_current, FALSE, &wx, &wy))
00177       return FALSE;
00178         a_pan (preview_w_current, wx, wy);
00179         break;
00180       case 3: /* right mouse button: zoom out */
00181         a_zoom (preview_w_current, ZOOM_OUT, HOTKEY,
00182                 A_PAN_DONT_REDRAW);
00183         o_invalidate_all (preview_w_current);
00184         break;
00185   }
00186   
00187   return FALSE;
00188 }
00189 
00190 
00199 static void
00200 preview_update (Preview *preview)
00201 {
00202   GSCHEM_TOPLEVEL *preview_w_current = preview->preview_w_current;
00203   TOPLEVEL *preview_toplevel = preview_w_current->toplevel;
00204   int left, top, right, bottom;
00205   int width, height;
00206   GError * err = NULL;
00207 
00208   if (preview_toplevel->page_current == NULL) {
00209     return;
00210   }
00211   
00212   /* delete old preview, create new page */
00213   /* it would be better to just resets current page - Fix me */
00214   s_page_delete (preview_toplevel, preview_toplevel->page_current);
00215   s_page_goto (preview_toplevel, s_page_new (preview_toplevel, "preview"));
00216   
00217   if (preview->active) {
00218     g_assert ((preview->filename == NULL) || (preview->buffer == NULL));
00219     if (preview->filename != NULL) {
00220       /* open up file in current page */
00221       f_open_flags (preview_toplevel, preview_toplevel->page_current,
00222                     preview->filename,
00223                     F_OPEN_RC | F_OPEN_RESTORE_CWD, NULL);
00224       /* test value returned by f_open... - Fix me */
00225       /* we should display something if there an error occured - Fix me */
00226     }
00227     if (preview->buffer != NULL) {
00228       /* Load the data buffer */
00229       GList * objects = o_read_buffer (preview_toplevel,
00230                                        NULL, preview->buffer, -1,
00231                                        _("Preview Buffer"), &err);
00232 
00233       if (err == NULL) {
00234         s_page_append_list (preview_toplevel, preview_toplevel->page_current,
00235                             objects);
00236       }
00237       else {
00238         s_page_append (preview_toplevel, preview_toplevel->page_current,
00239                        o_text_new(preview_toplevel, OBJ_TEXT, 2, 100, 100, LOWER_MIDDLE, 0,
00240                                   err->message, 10, VISIBLE, SHOW_NAME_VALUE));
00241         g_error_free(err);
00242       }
00243     }
00244   }
00245 
00246   if (world_get_object_glist_bounds (preview_toplevel,
00247                                      s_page_objects (preview_toplevel->page_current),
00248                                      &left, &top,
00249                                      &right, &bottom)) {
00250     /* Clamp the canvas size to the extents of the page being previewed */
00251     width = right - left;
00252     height = bottom - top;
00253     preview_toplevel->init_left   = left  - ((double)width * OVER_ZOOM_FACTOR);
00254     preview_toplevel->init_right  = right + ((double)width * OVER_ZOOM_FACTOR);
00255     preview_toplevel->init_top    = top    - ((double)height * OVER_ZOOM_FACTOR);
00256     preview_toplevel->init_bottom = bottom + ((double)height * OVER_ZOOM_FACTOR);
00257   }
00258 
00259   /* display current page (possibly empty) */
00260   a_zoom_extents (preview_w_current,
00261                   s_page_objects (preview_toplevel->page_current),
00262                   A_PAN_DONT_REDRAW);
00263   o_invalidate_all (preview_w_current);
00264   
00265 }
00266 
00267 GType
00268 preview_get_type ()
00269 {
00270   static GType preview_type = 0;
00271   
00272   if (!preview_type) {
00273     static const GTypeInfo preview_info = {
00274       sizeof(PreviewClass),
00275       NULL, /* base_init */
00276       NULL, /* base_finalize */
00277       (GClassInitFunc) preview_class_init,
00278       NULL, /* class_finalize */
00279       NULL, /* class_data */
00280       sizeof(Preview),
00281       0,    /* n_preallocs */
00282       (GInstanceInitFunc) preview_init,
00283     };
00284                 
00285     preview_type = g_type_register_static (GTK_TYPE_DRAWING_AREA,
00286                                            "Preview",
00287                                            &preview_info, 0);
00288   }
00289   
00290   return preview_type;
00291 }
00292 
00293 static void
00294 preview_class_init (PreviewClass *klass)
00295 {
00296   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
00297 
00298   preview_parent_class = g_type_class_peek_parent (klass);
00299   
00300   gobject_class->set_property = preview_set_property;
00301   gobject_class->get_property = preview_get_property;
00302   gobject_class->dispose      = preview_dispose;
00303 
00304   g_object_class_install_property (
00305     gobject_class, PROP_FILENAME,
00306     g_param_spec_string ("filename",
00307                          "",
00308                          "",
00309                          NULL,
00310                          G_PARAM_READWRITE));
00311   g_object_class_install_property (
00312     gobject_class, PROP_BUFFER,
00313     g_param_spec_string ("buffer",
00314                          "",
00315                          "",
00316                          NULL,
00317                          G_PARAM_WRITABLE));
00318   g_object_class_install_property(
00319     gobject_class, PROP_ACTIVE,
00320     g_param_spec_boolean ("active",
00321                           "",
00322                           "",
00323                           FALSE,
00324                           G_PARAM_READWRITE));
00325 
00326         
00327 }
00328 
00329 static gboolean
00330 preview_event_configure (GtkWidget         *widget,
00331                          GdkEventConfigure *event,
00332                          gpointer           user_data)
00333 {
00334   gboolean retval;
00335   GSCHEM_TOPLEVEL *preview_w_current = PREVIEW (widget)->preview_w_current;
00336   PAGE     *preview_page = preview_w_current->toplevel->page_current;
00337 
00338   retval = x_event_configure (widget, event, preview_w_current);
00339   if (preview_page != NULL) {
00340     a_zoom_extents(preview_w_current, s_page_objects (preview_page), 0);
00341   }
00342   return retval;
00343 }
00344 
00345 
00346 static gboolean
00347 preview_event_scroll (GtkWidget *widget,
00348                       GdkEventScroll *event,
00349                       GSCHEM_TOPLEVEL *w_current)
00350 {
00351   if (!PREVIEW (widget)->active) {
00352     return TRUE;
00353   }
00354   return x_event_scroll (widget, event, PREVIEW (widget)->preview_w_current);
00355 }
00356 
00357 static void
00358 preview_init (Preview *preview)
00359 {
00360   struct event_reg_t {
00361     gchar *detailed_signal;
00362     GCallback c_handler;
00363   } drawing_area_events[] = {
00364     { "realize",              G_CALLBACK (preview_callback_realize)       },
00365     { "expose_event",         G_CALLBACK (preview_callback_expose)        },
00366     { "button_press_event",   G_CALLBACK (preview_callback_button_press)  },
00367     { "configure_event",      G_CALLBACK (preview_event_configure)        },
00368     { "scroll_event",         G_CALLBACK (preview_event_scroll)           },
00369     { NULL,                   NULL                                        }
00370   }, *tmp;
00371   GSCHEM_TOPLEVEL *preview_w_current;
00372   preview_w_current = gschem_toplevel_new ();
00373   preview_w_current->toplevel = s_toplevel_new ();
00374 
00375   preview_w_current->toplevel->load_newer_backup_func =
00376     x_fileselect_load_backup;
00377   preview_w_current->toplevel->load_newer_backup_data =
00378     preview_w_current;
00379   o_text_set_rendered_bounds_func (preview_w_current->toplevel,
00380                                    o_text_get_rendered_bounds,
00381                                    preview_w_current);
00382 
00383   o_add_change_notify (preview_w_current->toplevel,
00384                        (ChangeNotifyFunc) o_invalidate,
00385                        (ChangeNotifyFunc) o_invalidate,
00386                        preview_w_current);
00387 
00388   i_vars_set (preview_w_current);
00389 
00390   /* be sure to turn off scrollbars */
00391   preview_w_current->scrollbars_flag = FALSE;
00392 
00393   /* be sure to turn off the grid */
00394   preview_w_current->grid = FALSE;
00395 
00396   /* preview_w_current windows don't have toolbars */
00397   preview_w_current->handleboxes = FALSE;
00398   preview_w_current->toolbars    = FALSE;
00399 
00400   preview_w_current->toplevel->width  = 160;
00401   preview_w_current->toplevel->height = 120;
00402   preview_w_current->win_width  = preview_w_current->toplevel->width;
00403   preview_w_current->win_height = preview_w_current->toplevel->height;
00404 
00405   preview_w_current->drawing_area = GTK_WIDGET (preview);
00406   preview->preview_w_current = preview_w_current;
00407 
00408   g_object_set (GTK_WIDGET (preview),
00409                 "width-request",  preview_w_current->toplevel->width,
00410                 "height-request", preview_w_current->toplevel->height,
00411                 NULL);
00412 
00413   preview->active   = FALSE;
00414   preview->filename = NULL;
00415   preview->buffer   = NULL;
00416   
00417   gtk_widget_set_events (GTK_WIDGET (preview), 
00418                          GDK_EXPOSURE_MASK | 
00419                          GDK_POINTER_MOTION_MASK |
00420                          GDK_BUTTON_PRESS_MASK);
00421   for (tmp = drawing_area_events; tmp->detailed_signal != NULL; tmp++) {
00422     g_signal_connect (preview,
00423                       tmp->detailed_signal,
00424                       tmp->c_handler,
00425                       NULL);
00426   }
00427   
00428 }
00429 
00430 static void
00431 preview_set_property (GObject *object,
00432                       guint property_id,
00433                       const GValue *value,
00434                       GParamSpec *pspec)
00435 {
00436   Preview *preview = PREVIEW (object);
00437   GSCHEM_TOPLEVEL *preview_w_current = preview->preview_w_current;
00438 
00439   g_assert (preview_w_current != NULL);
00440   
00441   switch(property_id) {
00442       case PROP_FILENAME:
00443         if (preview->buffer != NULL) {
00444           g_free (preview->buffer);
00445           preview->buffer = NULL;
00446           g_object_notify (object, "buffer");
00447         }
00448         g_free (preview->filename);
00449         preview->filename = g_strdup (g_value_get_string (value));
00450         preview_update (preview);
00451         break;
00452 
00453       case PROP_BUFFER:
00454         if (preview->filename != NULL) {
00455           g_free (preview->filename);
00456           preview->filename = NULL;
00457           g_object_notify (object, "filename");
00458         }
00459         g_free (preview->buffer);
00460         preview->buffer = g_strdup (g_value_get_string (value));
00461         preview_update (preview);
00462         break;
00463 
00464       case PROP_ACTIVE:
00465         preview->active = g_value_get_boolean (value);
00466         preview_update (preview);
00467         break;
00468       default:
00469         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
00470   }
00471 
00472 }
00473 
00474 static void
00475 preview_get_property (GObject *object,
00476                       guint property_id,
00477                       GValue *value,
00478                       GParamSpec *pspec)
00479 {
00480   Preview *preview = PREVIEW (object);
00481   GSCHEM_TOPLEVEL *preview_w_current = preview->preview_w_current;
00482 
00483   switch(property_id) {
00484       case PROP_FILENAME:
00485         g_assert (preview_w_current != NULL);
00486         /* return the filename of the current page in toplevel */
00487         g_value_set_string (value,
00488                             preview_w_current->toplevel->page_current->page_filename);
00489         break;
00490       case PROP_ACTIVE:
00491         g_value_set_boolean (value, preview->active);
00492         break;
00493       default:
00494         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
00495   }
00496 
00497 }
00498 
00499 static void
00500 preview_dispose (GObject *self)
00501 {
00502   Preview *preview = PREVIEW (self);
00503   GSCHEM_TOPLEVEL *preview_w_current = preview->preview_w_current;
00504 
00505   if (preview_w_current != NULL) {
00506     preview_w_current->drawing_area = NULL;
00507 
00508     x_window_free_gc (preview_w_current);
00509     
00510     s_toplevel_delete (preview_w_current->toplevel);
00511     g_free (preview_w_current);
00512 
00513     preview->preview_w_current = NULL;
00514   }
00515     
00516   G_OBJECT_CLASS (preview_parent_class)->dispose (self);
00517   
00518 }
00519 
00520 
00521 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines