/* GNOME GUI Library * Copyright (C) 1998 Cesar Miquel * Based in gnome-about, copyright (C) 1998 Horacio J. Peņa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Cambridge, MA 02139, USA. */ #include #include "gnome-about.h" #include "libgnome/gnome-util.h" #include "libgnome/gnome-i18nP.h" #include "gnome-stock.h" #include #include /* FONTS */ #define HELVETICA_20_BFONT "-adobe-helvetica-bold-r-normal-*-20-*-*-*-*-*-*-*" #define HELVETICA_14_BFONT "-adobe-helvetica-bold-r-normal-*-14-*-*-*-*-*-*-*" #define HELVETICA_12_BFONT "-adobe-helvetica-bold-r-normal-*-12-*-*-*-*-*-*-*" #define HELVETICA_12_FONT "-adobe-helvetica-medium-r-normal-*-12-*-*-*-*-*-*-*" #define HELVETICA_10_FONT "-adobe-helvetica-medium-r-normal-*-10-*-*-*-*-*-*-*" #define GNOME_ABOUT_DEFAULT_WIDTH 100 #define GNOME_ABOUT_MAX_WIDTH 600 #define BASE_LINE_SKIP 0 typedef struct { gchar *title; gchar *copyright; GList *names; gchar *comments; GdkPixmap *logo; GdkBitmap *mask; gint logo_w, logo_h; gint w, h; GdkColor light_green; GdkFont *font_title, *font_copyright, *font_author, *font_names, *font_comments; } GnomeAboutInfo; static void gnome_about_class_init (GnomeAboutClass *klass); static void gnome_about_init (GnomeAbout *about); static void gnome_about_repaint (GtkWidget *w, GdkEventExpose *, GnomeAboutInfo *data); static void gnome_about_display_comments (GdkWindow *win, GdkFont *font, GdkGC *gc, gint x, gint y, gint w, const gchar *comments); /** * gnome_about_get_type * * Returns the GtkType for the GnomeAbout widget. **/ guint gnome_about_get_type () { static guint about_type = 0; if (!about_type) { GtkTypeInfo about_info = { "GnomeAbout", sizeof (GnomeAbout), sizeof (GnomeAboutClass), (GtkClassInitFunc) gnome_about_class_init, (GtkObjectInitFunc) gnome_about_init, (GtkArgSetFunc) NULL, (GtkArgGetFunc) NULL, }; about_type = gtk_type_unique (gnome_dialog_get_type (), &about_info); } return about_type; } static void gnome_about_class_init (GnomeAboutClass *klass) { } static void gnome_about_init (GnomeAbout *about) { } static void gnome_about_repaint (GtkWidget *widget, GdkEventExpose *event, GnomeAboutInfo *gai) { GdkWindow *win = widget->window; GdkColor *black = &widget->style->black; GdkColor *white = &widget->style->white; GdkColor *light_green = &gai->light_green; GList *name; static GdkGC *gc = NULL; int h, y, x; if (gc == NULL) gc = gdk_gc_new (win); gdk_window_clear (win); /* Draw pixmap first */ y = 1; if (gai->logo) { y += 2; x = (gai->w - gai->logo_w) / 2; if (gai->mask) { gdk_gc_set_clip_mask (gc, gai->mask); gdk_gc_set_clip_origin (gc, x, y); } gdk_draw_pixmap (win, gc, gai->logo, 0, 0, x, y, gai->logo_w, gai->logo_h); if (gai->mask) { gdk_gc_set_clip_mask (gc, NULL); gdk_gc_set_clip_origin (gc, 0, 0); } y += 2 + gai->logo_h; } /* Draw title */ h = gai->font_title->descent + gai->font_title->ascent + 13; if (gai->title) { y += 2; gdk_gc_set_foreground (gc, black); gdk_gc_set_background (gc, black); gdk_draw_rectangle (win, gc, TRUE, 2, y, gai->w - 5, h); y += h - 7 - gai->font_title->descent; x = (gai->w - gdk_string_measure (gai->font_title, gai->title)) / 2; gdk_gc_set_foreground (gc, white); gdk_draw_string (win, gai->font_title, gc, x, y, gai->title); y += 7 + gai->font_title->descent + 2; } if (gai->copyright || gai->names || gai->comments) { gdk_gc_set_foreground (gc, light_green); gdk_gc_set_background (gc, light_green); gdk_draw_rectangle (win, gc, TRUE, 2, y, gai->w-5, gai->h - y - 3); } gdk_gc_set_foreground (gc, black); if (gai->copyright) { y += 4 + gai->font_copyright->ascent; gdk_draw_string (win, gai->font_copyright, gc, 5, y, gai->copyright); y += gai->font_copyright->descent + 4; } if (gai->names) { y += 2 + gai->font_author->ascent; if (g_list_length (gai->names) == 1) gdk_draw_string (win, gai->font_author, gc, 5, y, _("Author:") ); else gdk_draw_string (win, gai->font_author, gc, 5, y, _("Authors:") ); } x = 5 + gdk_string_measure (gai->font_author, _("Authors:")) + 10; name = g_list_first (gai->names); while (name) { h = gai->font_names->descent + gai->font_names->ascent; gdk_draw_string (win, gai->font_names, gc, x, y, (char *)name->data); name = name->next; if (name != NULL) y += h; } if (gai->comments) { y += 2 + 2 * gai->font_comments->ascent; gnome_about_display_comments (win, gai->font_comments, gc, 8, y, gai->w, gai->comments); } return; } static void gnome_about_display_comments (GdkWindow *win, GdkFont *font, GdkGC *gc, gint x, gint y, gint w, const gchar *comments) { char *tok, *p1, *p2, *p3, c; char *buffer; int ypos, width, done; GList *par, *tmp; char *tokp; width = w - 16; if (comments == NULL) return; /* we need a buffer because strtok will modify the string! */ /* strtok is a cool but dangerous function. */ buffer = g_strdup(comments); ypos = y; /* Make a list with each paragraph */ par = (GList *)NULL; for (tok = strtok_r (buffer, "\n", &tokp); tok; tok = strtok_r (NULL, "\n", &tokp)) { par = g_list_append (par, g_strdup(tok)); } /* Print each paragraph */ tmp = par; while (tmp != NULL) { done = FALSE; p1 = p2 = tmp->data; while (!done) { c = *p1; *p1 = 0; while ( gdk_string_measure (font, p2) < width && c != 0) { *p1 = c; p1++; c = *p1; *p1 = 0; } switch (c) { case ' ': p1++; gdk_draw_string (win, font, gc, x, ypos, p2); break; case '\0': done = TRUE; gdk_draw_string (win, font, gc, x, ypos, p2); break; default: p3 = p1; while (*p1 != ' ' && p1 > p2) p1--; if (p1 == p2) { gdk_draw_string (win, font, gc, x, ypos, p2); *p3 = c; p1 = p3; break; } else { *p3 = c; *p1 = 0; p1++; gdk_draw_string (win, font, gc, x, ypos, p2); } break; } ypos += font->descent + font->ascent; p2 = p1; } tmp = tmp->next; ypos += BASE_LINE_SKIP; /* Skip a bit */ } /* Free list memory */ g_list_foreach(par, (GFunc)g_free, NULL); g_list_free (par); g_free (buffer); return; } /* ---------------------------------------------------------------------- NAME: gnome_about_calc_size DESCRIPTION: Calculates size of window WITHOUT counting pixmap. ---------------------------------------------------------------------- */ static void gnome_about_calc_size (GnomeAboutInfo *gai) { GList *name; gint num_pars, i, h, w, len[4], tmpl; const gchar *p; gfloat maxlen; w = GNOME_ABOUT_DEFAULT_WIDTH; h = 1; if (gai->title) { len[0] = gdk_string_measure (gai->font_title, gai->title); h += 4 + gai->font_title->descent + gai->font_title->ascent + 14; } else len[0] = 0; if (gai->copyright) { h += gai->font_copyright->descent + gai->font_copyright->ascent + 8; len[1] = gdk_string_measure (gai->font_copyright, gai->copyright); } else len[1] = 0; len[2] = 0; if (gai->names) { name = g_list_first (gai->names); while (name) { tmpl = gdk_string_measure (gai->font_names, name->data); if (tmpl > len[2]) len[2] = tmpl; name = name->next; } tmpl = gdk_string_measure (gai->font_names, _("Authors: ")); len[2] += tmpl + 15; h += g_list_length (gai->names) * (gai->font_names->descent + gai->font_names->ascent + BASE_LINE_SKIP ) + 4; } maxlen = (gfloat) w; for (i=0; i<3; i++) if (len[i] > maxlen) maxlen = (gfloat) len[i]; w = (int) (maxlen * 1.2); if ( w > GNOME_ABOUT_MAX_WIDTH ) w = GNOME_ABOUT_MAX_WIDTH; if (gai->comments) { num_pars = 1; p = gai->comments; while (*p != '\0') { if (*p == '\n') num_pars++; p++; } i = gdk_string_measure (gai->font_comments, gai->comments); i /= w - 16; i += 1 + num_pars;; h += i * (gai->font_comments->descent + gai->font_comments->ascent); } gai->w = w+4; gai->h = h+3; return; } /* ---------------------------------------------------------------------- NAME: gnome_fill_info DESCRIPTION: ---------------------------------------------------------------------- */ static GnomeAboutInfo* gnome_fill_info (GtkWidget *widget, const gchar *title, const gchar *version, const gchar *copyright, const gchar **authors, const gchar *comments, const gchar *logo) { GnomeAboutInfo *gai; static GdkColor light_green = {0, 30208, 41216, 33792}; GtkStyle *style; /* alloc mem for struct */ gai = g_new (GnomeAboutInfo, 1); /* Create fonts */ /* FIXME: dirty hack, but it solves i18n problem without rewriting the drawing code.. */ style = gtk_style_ref (widget->style); gtk_widget_set_name (widget, "Title"); gai->font_title = gdk_font_ref (widget->style->font); gtk_widget_set_name (widget, "Copyright"); gai->font_copyright = gdk_font_ref (widget->style->font); gtk_widget_set_name (widget, "Author"); gai->font_author = gdk_font_ref (widget->style->font); gtk_widget_set_name (widget, "Names"); gai->font_names = gdk_font_ref (widget->style->font); gtk_widget_set_name (widget, "Comments"); gai->font_comments = gdk_font_ref (widget->style->font); gtk_widget_set_style (widget, style); gtk_style_unref (style); /* Add color */ memcpy (&gai->light_green, &light_green, sizeof (GdkColor)); /* gdk_color_alloc (gdk_colormap_get_system (), &gai->light_green); */ /* FIXME: this should use a GdkColorContext for allocation. * The cc structure should reside in the GnomeAboutClass so * that all about boxes share it. */ gdk_color_alloc (gtk_widget_get_default_colormap (), &gai->light_green); /* fill struct */ if(title) gai->title = g_strconcat (title, " ", version ? version : "", NULL); else gai->title = NULL; gai->copyright = g_strdup(copyright); gai->comments = g_strdup(comments); gai->names = NULL; if (authors && authors[0]) { while( *authors ) { gai->names = g_list_append (gai->names, g_strdup(*authors)); authors++; } } /* Calculate width of window */ gnome_about_calc_size (gai); /* Done */ return gai; } /* ---------------------------------------------------------------------- NAME: gnome_destroy_about DESCRIPTION: ---------------------------------------------------------------------- */ static void gnome_destroy_about (GtkWidget *widget, gpointer *data) { GnomeAboutInfo *gai; gai = (GnomeAboutInfo *)data; /* Free memory used for title, copyright and comments */ g_free (gai->title); g_free (gai->copyright); g_free (gai->comments); /* Free GUI's. */ gdk_font_unref (gai->font_title); gdk_font_unref (gai->font_copyright); gdk_font_unref (gai->font_author); gdk_font_unref (gai->font_names); gdk_font_unref (gai->font_comments); /* Free memory used for authors */ g_list_foreach(gai->names, (GFunc)g_free, NULL); g_list_free (gai->names); g_free (gai); } /** * gnome_about_new * @title: Name of app. * @version: version number * @copyright: copyright string * @authors: %NULL terminated list of authors * @comments: Other comments * @logo: a logo pixmap file. * * Creates a new GNOME About dialog. @title, @version, * @copyright, and @authors are displayed first, in that order. * @comments is typically the location for multiple lines of text, if * necessary. (Separate with "\n".) @logo is the filename of a * optional pixmap to be displayed in the dialog, typically a product or * company logo of some sort; set to %NULL if no logo file is available. * * Returns: * &GtkWidget pointer to new dialog **/ GtkWidget* gnome_about_new (const gchar *title, const gchar *version, const gchar *copyright, const gchar **authors, const gchar *comments, const gchar *logo) { GnomeAbout *about; if(!title) title = ""; if(!version) version = ""; if(!copyright) copyright = ""; g_return_val_if_fail (authors != NULL, NULL); if(!comments) comments = ""; about = gtk_type_new (gnome_about_get_type ()); gnome_about_construct(about, title, version, copyright, authors, comments, logo); return GTK_WIDGET (about); } /** * gnome_about_construct * @about: Pointer to new GNOME about object * @title: Name of app. * @version: version number * @copyright: copyright string * @authors: %NULL terminated list of authors * @comments: Other comments * @logo: a logo pixmap file. * * Constructs a new GNOME About dialog, given an object * @about newly created via the Gtk type system. @title, @version, * @copyright, and @authors are displayed first, in that order. * @comments is typically the location for multiple lines of text, if * necessary. (Separate with "\n".) @logo is the filename of a * optional pixmap to be displayed in the dialog, typically a product or * company logo of some sort; set to %NULL if no logo file is available. * * Note: * Only for use by bindings to languages other than C; don't use * in applications. * */ void gnome_about_construct (GnomeAbout *about, const gchar *title, const gchar *version, const gchar *copyright, const gchar **authors, const gchar *comments, const gchar *logo) { GnomeAboutInfo *ai; GtkWidget *frame; GtkWidget *drawing_area; GtkStyle *style; gint w,h; char *filename; gtk_window_set_title (GTK_WINDOW (about), _("About")); gtk_window_set_policy (GTK_WINDOW (about), FALSE, FALSE, TRUE); /* x = (gdk_screen_width () - w) / 2; */ /* y = (gdk_screen_height () - h) / 2; */ /* gtk_widget_set_uposition ( GTK_WIDGET (about), x, y); */ frame = gtk_frame_new (NULL); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN); gtk_container_set_border_width (GTK_CONTAINER (frame), 4); gtk_container_add (GTK_CONTAINER (GNOME_DIALOG(about)->vbox), GTK_WIDGET(frame)); gtk_widget_show (frame); drawing_area = gtk_drawing_area_new (); /* Make it have white bg color */ gtk_widget_set_name (drawing_area, "DrawingArea"); gtk_container_add (GTK_CONTAINER (frame), drawing_area); style = gtk_widget_get_style (drawing_area); ai = gnome_fill_info (drawing_area, title, version, copyright, authors, comments, logo); gtk_signal_connect(GTK_OBJECT(about),"destroy", GTK_SIGNAL_FUNC(gnome_destroy_about),ai); w = ai->w; h = ai->h; /* x = (gdk_screen_width () - w) / 2; */ /* y = (gdk_screen_height () - h) / 2; */ /* gtk_widget_set_uposition ( GTK_WIDGET (about), x, y); */ if (logo) { filename = gnome_pixmap_file (logo); if (filename && gdk_imlib_load_file_to_pixmap (filename, &ai->logo, &ai->mask)) { gdk_window_get_size ((GdkWindow *) ai->logo, &ai->logo_w, &ai->logo_h); h += 4 + ai->logo_h; ai->h = h; ai->w = MAX (w, (ai->logo_w + 6)); w = ai->w; } else ai->logo = NULL; g_free(filename); } else ai->logo = NULL; gtk_widget_set_usize ( GTK_WIDGET (drawing_area), w, h); gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK); gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event", (GtkSignalFunc) gnome_about_repaint, (gpointer) ai); gtk_widget_show (drawing_area); gnome_dialog_append_button ( GNOME_DIALOG(about), GNOME_STOCK_BUTTON_OK); gnome_dialog_set_close( GNOME_DIALOG(about), TRUE ); }