diff --git a/gnome/ChangeLog b/gnome/ChangeLog index 79a6dd290..f65c266e6 100644 --- a/gnome/ChangeLog +++ b/gnome/ChangeLog @@ -1,3 +1,10 @@ +1998-03-11 Federico Mena Quintero + + * gmc-chargrid.h: + * gmc-chargrid.c: New Character Grid widget for the file viewer. + This is a very lean and fast widget for displaying a grid of + monospaced characters. Just like a crippled-down terminal. + Tue Mar 10 23:46:29 1998 Miguel de Icaza * glayout.c diff --git a/gnome/Makefile.in b/gnome/Makefile.in index 1bbd4484b..eba2511bf 100644 --- a/gnome/Makefile.in +++ b/gnome/Makefile.in @@ -26,13 +26,15 @@ GNOMESRCS = \ gtools.c \ gdesktop.c \ gutil.c \ - gtrans.c + gtrans.c \ + gmc-chargrid.c GNOMEHDRS = \ gmain.h \ gscreen.h \ gwidget.h \ - gconf.h + gconf.h \ + gmc-chargrid.h # # These objects from ../src do not depend on HAVE_X / HAVE_GNOME?? @@ -52,7 +54,7 @@ OOBJS = main.o dlg.o screen.o widget.o wtools.o info.o boxes.o \ OBJS = $(LOBJS) $(OOBJS) \ gkey.o gmain.o gscreen.o gwidget.o gmenu.o ghelp.o ginfo.o \ - glayout.o gtools.o gdesktop.o gtrans.o gutil.o + glayout.o gtools.o gdesktop.o gtrans.o gutil.o gmc-chargrid.o # # Distribution variables diff --git a/gnome/gmc-chargrid.c b/gnome/gmc-chargrid.c new file mode 100644 index 000000000..000d36f3c --- /dev/null +++ b/gnome/gmc-chargrid.c @@ -0,0 +1,494 @@ +/* GmcCharGrid Widget - Simple character grid for the gmc viewer + * + * Copyright (C) 1997 The Free Software Foundation + * + * Author: Federico Mena + */ + +#include +#include "gmc-chargrid.h" + + +#define DEFAULT_WIDTH 80 +#define DEFAULT_HEIGHT 25 +#define DEFAULT_FONT "fixed" + + +#define CHARS(cgrid) ((char *) cgrid->chars) +#define COLORS(cgrid) ((gulong *) cgrid->colors) + + +enum { + SIZE_CHANGED, + LAST_SIGNAL +}; + +typedef void (* GmcCharGridSignal1) (GtkObject *object, + guint arg1, + guint arg2, + gpointer data); + +static void gmc_char_grid_marshal_signal_1 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); + + +static void gmc_char_grid_class_init (GmcCharGridClass *class); +static void gmc_char_grid_init (GmcCharGrid *cgrid); +static void gmc_char_grid_destroy (GtkObject *object); +static void gmc_char_grid_realize (GtkWidget *widget); +static void gmc_char_grid_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gmc_char_grid_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static gint gmc_char_grid_expose (GtkWidget *widget, + GdkEventExpose *event); +static void gmc_char_grid_real_size_changed (GmcCharGrid *cgrid, + guint width, + guint height); + + +static GtkWidgetClass *parent_class; + +static guint cgrid_signals[LAST_SIGNAL] = { 0 }; + + +guint +gmc_char_grid_get_type (void) +{ + static guint cgrid_type = 0; + + if (!cgrid_type) { + GtkTypeInfo cgrid_info = { + "GmcCharGrid", + sizeof (GmcCharGrid), + sizeof (GmcCharGridClass), + (GtkClassInitFunc) gmc_char_grid_class_init, + (GtkObjectInitFunc) gmc_char_grid_init, + (GtkArgSetFunc) NULL, + (GtkArgGetFunc) NULL + }; + + cgrid_type = gtk_type_unique (gtk_widget_get_type (), &cgrid_info); + } + + return cgrid_type; +} + +static void +gmc_char_grid_class_init (GmcCharGridClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = (GtkObjectClass *) class; + widget_class = (GtkWidgetClass *) class; + + parent_class = gtk_type_class (gtk_widget_get_type ()); + + cgrid_signals[SIZE_CHANGED] = + gtk_signal_new ("size_changed", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GmcCharGridClass, size_changed), + gmc_char_grid_marshal_signal_1, + GTK_TYPE_NONE, 2, + GTK_TYPE_UINT, + GTK_TYPE_UINT); + + gtk_object_class_add_signals (object_class, cgrid_signals, LAST_SIGNAL); + + object_class->destroy = gmc_char_grid_destroy; + + widget_class->realize = gmc_char_grid_realize; + widget_class->size_request = gmc_char_grid_size_request; + widget_class->size_allocate = gmc_char_grid_size_allocate; + widget_class->expose_event = gmc_char_grid_expose; + + class->size_changed = gmc_char_grid_real_size_changed; +} + +static void +gmc_char_grid_init (GmcCharGrid *cgrid) +{ + cgrid->width = 0; + cgrid->height = 0; + cgrid->chars = NULL; + cgrid->colors = NULL; + cgrid->frozen = 0; + cgrid->font = NULL; + cgrid->gc = NULL; + cgrid->char_width = 0; + cgrid->char_height = 0; + cgrid->char_y = 0; +} + +GtkWidget * +gmc_char_grid_new (void) +{ + GmcCharGrid *cgrid; + + cgrid = gtk_type_new (gmc_char_grid_get_type ()); + + gmc_char_grid_set_font (cgrid, DEFAULT_FONT); + gmc_char_grid_set_size (cgrid, DEFAULT_WIDTH, DEFAULT_HEIGHT); + + return GTK_WIDGET (cgrid); +} + +static void +gmc_char_grid_destroy (GtkObject *object) +{ + GmcCharGrid *cgrid; + + g_return_if_fail (object != NULL); + g_return_if_fail (GMC_IS_CHAR_GRID (object)); + + cgrid = GMC_CHAR_GRID (object); + + if (cgrid->chars) + g_free (cgrid->chars); + + if (cgrid->colors) + g_free (cgrid->colors); + + if (cgrid->font) + gdk_font_unref (cgrid->font); + + if (cgrid->gc) + gdk_gc_destroy (cgrid->gc); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gmc_char_grid_realize (GtkWidget *widget) +{ + GdkWindowAttr attributes; + gint attributes_mask; + GmcCharGrid *cgrid; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GMC_IS_CHAR_GRID (widget)); + + cgrid = GMC_CHAR_GRID (widget); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + attributes.x = widget->allocation.x + (widget->allocation.width - cgrid->char_width * cgrid->width) / 2; + attributes.y = widget->allocation.y + (widget->allocation.height - cgrid->char_height * cgrid->height) / 2; + attributes.width = cgrid->width * cgrid->char_width; + attributes.height = cgrid->height * cgrid->char_height; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = (gtk_widget_get_events (widget) + | GDK_EXPOSURE_MASK); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, widget); + + cgrid->gc = gdk_gc_new (cgrid->widget.window); + + widget->style = gtk_style_attach (widget->style, widget->window); + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); +} + +static void +gmc_char_grid_size_request (GtkWidget *widget, GtkRequisition *requisition) +{ + GmcCharGrid *cgrid; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GMC_IS_CHAR_GRID (widget)); + g_return_if_fail (requisition != NULL); + + cgrid = GMC_CHAR_GRID (widget); + + requisition->width = cgrid->width * cgrid->char_width; + requisition->height = cgrid->height * cgrid->char_height; +} + +static void +gmc_char_grid_size_allocate (GtkWidget *widget, GtkAllocation *allocation) +{ + GmcCharGrid *cgrid; + int w, h; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GMC_IS_CHAR_GRID (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + + cgrid = GMC_CHAR_GRID (widget); + + w = allocation->width / cgrid->char_width; + h = allocation->height / cgrid->char_height; + + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize (widget->window, + allocation->x + (allocation->width - cgrid->char_width * cgrid->width) / 2, + allocation->y + (allocation->height - cgrid->char_height * cgrid->height) / 2, + cgrid->width * cgrid->char_width, + cgrid->height * cgrid->char_height); + + if ((w != cgrid->width) || (h != cgrid->height)) + gmc_char_grid_set_size (cgrid, MAX (w, 1), MAX (h, 1)); +} + +static void +update_strip (GmcCharGrid *cgrid, int x, int y, int width) +{ + int i; + char *chars; + gulong *colors; + int first; + gulong color; + GdkColor gcolor; + + chars = CHARS (cgrid) + (cgrid->width * y + x); + colors = COLORS (cgrid) + (cgrid->width * y + x); + + i = 0; + + while (i < width) { + first = i; + color = colors[i]; + + do { + i++; + } while ((i < width) && (color == colors[i])); + + gcolor.pixel = color; + gdk_gc_set_foreground (cgrid->gc, &gcolor); + + gdk_draw_text (cgrid->widget.window, + cgrid->font, + cgrid->gc, + (first + x) * cgrid->char_width, + y * cgrid->char_height + cgrid->char_y, + &chars[first], + i - first); + } +} + +static void +update_region (GmcCharGrid *cgrid, int x, int y, int width, int height) +{ + int i; + + if ((width == 0) || (height == 0)) + return; + + gdk_window_clear_area (cgrid->widget.window, + x * cgrid->char_width, + y * cgrid->char_height, + width * cgrid->char_width, + height * cgrid->char_height); + + for (i = 0; i < height; i++) + update_strip (cgrid, x, y + i, width); +} + +static gint +gmc_char_grid_expose (GtkWidget *widget, GdkEventExpose *event) +{ + GmcCharGrid *cgrid; + int x1, y1, x2, y2; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GMC_IS_CHAR_GRID (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) { + cgrid = GMC_CHAR_GRID (widget); + + x1 = event->area.x / cgrid->char_width; + y1 = event->area.y / cgrid->char_height; + + x2 = (event->area.x + event->area.width) / cgrid->char_width; + y2 = (event->area.y + event->area.height) / cgrid->char_height; + + update_region (cgrid, x1, y1, (x2 - x1) + 1, (y2 - y1) + 1); + } + + return FALSE; +} + +void +gmc_char_grid_clear (GmcCharGrid *cgrid, int x, int y, int width, int height) +{ + int x1, y1, x2, y2; + int xx, yy; + char *ch; + + g_return_if_fail (cgrid != NULL); + g_return_if_fail (GMC_IS_CHAR_GRID (cgrid)); + + x1 = MAX (x, 0); + y1 = MAX (y, 0); + x2 = MIN (x + width, cgrid->width); + y2 = MIN (y + height, cgrid->height); + + ch = CHARS (cgrid) + (y1 * cgrid->width + x1); + + for (yy = y1; yy < y2; yy++) { + for (xx = x1; xx < x2; xx++) + ch[xx] = ' '; + + ch += cgrid->width; + } + + if (GTK_WIDGET_DRAWABLE (cgrid) && !cgrid->frozen) + update_region (cgrid, x, y, width, height); +} + +void +gmc_char_grid_put_char (GmcCharGrid *cgrid, int x, int y, gulong pixel, char ch) +{ + char *chars; + gulong *colors; + + g_return_if_fail (cgrid != NULL); + g_return_if_fail (GMC_IS_CHAR_GRID (cgrid)); + + if ((x < 0) || (x >= cgrid->width) + || (y < 0) || (y >= cgrid->height)) + return; + + chars = CHARS (cgrid); + colors = COLORS (cgrid); + + chars[y * cgrid->width + x] = ch; + colors[y * cgrid->width + x] = pixel; + + if (GTK_WIDGET_DRAWABLE (cgrid) && !cgrid->frozen) + update_region (cgrid, x, y, 1, 1); +} + +void +gmc_char_grid_put_string (GmcCharGrid *cgrid, int x, int y, gulong pixel, char *str) +{ + char *chars; + gulong *colors; + int i, pos; + + g_return_if_fail (cgrid != NULL); + g_return_if_fail (GMC_IS_CHAR_GRID (cgrid)); + + if ((x < 0) || (x >= cgrid->width) + || (y < 0) || (y >= cgrid->height)) + return; + + chars = CHARS (cgrid) + (cgrid->width * y + x); + colors = COLORS (cgrid) + (cgrid->width * y + x); + + for (i = 0, pos = x; (pos < cgrid->width) && *str; i++, pos++) { + *chars++ = *str++; + *colors++ = pixel; + } + + if (GTK_WIDGET_DRAWABLE (cgrid) && !cgrid->frozen) + update_region (cgrid, x, y, i, 1); +} + +void +gmc_char_grid_set_font (GmcCharGrid *cgrid, const char *font_name) +{ + g_return_if_fail (cgrid != NULL); + g_return_if_fail (GMC_IS_CHAR_GRID (cgrid)); + + if (cgrid->font) + gdk_font_unref (cgrid->font); + + cgrid->font = gdk_font_load (font_name); + + if (!cgrid->font) + cgrid->font = gdk_font_load (DEFAULT_FONT); + + cgrid->char_width = gdk_char_width (cgrid->font, ' '); /* assume monospaced font! */ + cgrid->char_height = cgrid->font->ascent + cgrid->font->descent; + cgrid->char_y = cgrid->font->ascent; + + gtk_widget_queue_resize (GTK_WIDGET (cgrid)); +} + +void +gmc_char_grid_set_size (GmcCharGrid *cgrid, guint width, guint height) +{ + gtk_signal_emit (GTK_OBJECT (cgrid), cgrid_signals[SIZE_CHANGED], width, height); +} + +void +gmc_char_grid_freeze (GmcCharGrid *cgrid) +{ + g_return_if_fail (cgrid != NULL); + g_return_if_fail (GMC_IS_CHAR_GRID (cgrid)); + + cgrid->frozen = TRUE; +} + +void +gmc_char_grid_thaw (GmcCharGrid *cgrid) +{ + g_return_if_fail (cgrid != NULL); + g_return_if_fail (GMC_IS_CHAR_GRID (cgrid)); + + cgrid->frozen = FALSE; + + if (GTK_WIDGET_DRAWABLE (cgrid)) + gtk_widget_queue_draw (GTK_WIDGET (cgrid)); +} + +static void +gmc_char_grid_marshal_signal_1 (GtkObject *object, GtkSignalFunc func, gpointer func_data, GtkArg *args) +{ + GmcCharGridSignal1 rfunc; + + rfunc = (GmcCharGridSignal1) func; + + (*rfunc) (object, GTK_VALUE_UINT (args[0]), GTK_VALUE_UINT (args[1]), func_data); +} + +static void +gmc_char_grid_real_size_changed (GmcCharGrid *cgrid, guint width, guint height) +{ + int i; + char *chars; + gulong *colors; + + g_return_if_fail (cgrid != NULL); + g_return_if_fail (GMC_IS_CHAR_GRID (cgrid)); + g_return_if_fail ((width > 0) && (height > 0)); + + if ((width == cgrid->width) && (height == cgrid->height)) + return; + + cgrid->width = width; + cgrid->height = height; + + if (cgrid->chars) + g_free (cgrid->chars); + + if (cgrid->colors) + g_free (cgrid->colors); + + chars = g_new (char, width * height); + cgrid->chars = chars; + + colors = g_new (gulong, width * height); + cgrid->colors = colors; + + for (i = 0; i < (width * height); i++) { + chars[i] = ' '; + colors[i] = 0; + } + + gtk_widget_queue_resize (GTK_WIDGET (cgrid)); +} diff --git a/gnome/gmc-chargrid.h b/gnome/gmc-chargrid.h new file mode 100644 index 000000000..b11e4b469 --- /dev/null +++ b/gnome/gmc-chargrid.h @@ -0,0 +1,69 @@ +/* GmcCharGrid Widget - Simple character grid for the gmc viewer + * + * Copyright (C) 1997 The Free Software Foundation + * + * Author: Federico Mena + */ + +#ifndef GMC_CHARGRID_H +#define GMC_CHARGRID_H + + +#include +#include + + +BEGIN_GNOME_DECLS + + +#define GMC_CHAR_GRID(obj) GTK_CHECK_CAST (obj, gmc_char_grid_get_type (), GmcCharGrid) +#define GMC_CHAR_GRID_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gmc_char_grid_get_type (), GmcCharGridClass) +#define GMC_IS_CHAR_GRID(obj) GTK_CHECK_TYPE (obj, gmc_char_grid_get_type ()) + + +typedef struct _GmcCharGrid GmcCharGrid; +typedef struct _GmcCharGridClass GmcCharGridClass; + +struct _GmcCharGrid { + GtkWidget widget; + + int width; + int height; + + void *chars; + void *colors; + + int frozen; + + GdkFont *font; + GdkGC *gc; + + int char_width; + int char_height; + int char_y; +}; + +struct _GmcCharGridClass { + GtkWidgetClass parent_class; + + void (* size_changed) (GmcCharGrid *cgrid, guint width, guint height); +}; + + +guint gmc_char_grid_get_type (void); +GtkWidget *gmc_char_grid_new (void); + +void gmc_char_grid_clear (GmcCharGrid *cgrid, int x, int y, int width, int height); +void gmc_char_grid_put_char (GmcCharGrid *cgrid, int x, int y, gulong pixel, char ch); +void gmc_char_grid_put_string (GmcCharGrid *cgrid, int x, int y, gulong pixel, char *str); + +void gmc_char_grid_set_font (GmcCharGrid *cgrid, const char *font_name); +void gmc_char_grid_set_size (GmcCharGrid *cgrid, guint width, guint height); + +void gmc_char_grid_freeze (GmcCharGrid *cgrid); +void gmc_char_grid_thaw (GmcCharGrid *cgrid); + + +END_GNOME_DECLS + +#endif