gtk2/gdk/gdkpango.c
Havoc Pennington ef4356b567 adapt to handle PangoColor
2001-01-26  Havoc Pennington  <hp@redhat.com>

	* gtk/gtktextlayout.c (convert_color): adapt to handle PangoColor

	* gtk/gtktreeview.c (gtk_tree_view_widget_to_tree_coords): fix to
	not offset by TREE_VIEW_HEADER_HEIGHT
	(gtk_tree_view_tree_to_widget_coords): fix to not offset by
	TREE_VIEW_HEADER_HEIGHT

	* configure.in (included_loaders): for me, --with-included-loaders
	generates the error "the specified loader yes does not exist",
	i.e. the arg defaults to "yes", so change test for value ""
	to test for value "yes", and include all loaders in that case.

	* gtk/gtkrbtree.c (_gtk_rbtree_get_depth): new function

	* gtk/gtktreeview.c (gtk_tree_view_get_cell_rect): fix to properly
	handle TREE_VIEW_VERTICAL_SEPARATOR
	(gtk_tree_view_bin_expose): fix to consider the row offset as
	pointing halfway into vertical separator.
	(gtk_tree_view_draw_node_focus_rect): ditto

	* gtk/gtkdebug.h, gtk/gtkmain.c (gtk_init_check): Add
	--gtk-debug=updates, which causes gdk_window_set_debug_updates
	(TRUE) to be called.

	* gdk/gdkwindow.c (gdk_window_set_debug_updates): Allow enabling a
	debug mode where the invalid region is colored in on invalidate,
	so you can see the flicker and know whether your redraw code is
	doing a good job.

	* gtk/gtktreeview.c (gtk_tree_view_queue_draw_node): Work in
	tree window coordinates (clip rect is in tree window coords)

	* gtk/Makefile.am: add gtktreednd.[hc]

	* gtk/gtkliststore.c: implement gtktreednd interfaces.

	* gtk/gtktreednd.c, gtk/gtktreednd.h: New interface to support
	drag-and-drop data operations on a model (so we can set up tree
	drag-and-drop automatically)

	* gtk/testgtk.c: Add a window to change sensitivity in the
	GtkLabel test; add a way to change the entry frame in GtkEntry
	test

	* gtk/gtkentry.c (gtk_entry_set_has_frame):
	(gtk_entry_get_has_frame): new functions to remove the frame
	around an entry
	(gtk_entry_size_request): shrink requisition if no frame
	(gtk_entry_draw_focus): don't draw frame if no frame

	* gtk/gtkstyle.c (gtk_default_draw_check): draw custom look for
	checks inside a cell renderer
	(gtk_default_draw_option): ditto for options

	* gtk/gtktreeviewcolumn.c (update_button_contents): add/remove
	children from the alignment, not the button
	(gtk_tree_view_column_init): ref/sink the column, to emulate
	GObject refcounting.

	* gtk/gtkcellrenderer.c (gtk_cell_renderer_init): ref/sink

	* gtk/gtkcellrenderertoggle.c (gtk_cell_renderer_toggle_render):
	Use theme functions to draw the toggles

	* gdk/gdkpango.c (gdk_pango_get_gc): use GdkRGB to alloc colors

	* gdk/gdkpango.h, gdk/gdkpango.c: Add GdkPangoAttrStipple and
	GdkPangoAttrEmbossed to use in rendering insensitive text

	* gdk/gdkpango.c (gdk_draw_layout_line): render new properties

	* gtk/gtkstyle.c (gtk_default_draw_layout): handle sensitivity
	using new GDK features
2001-01-26 21:12:05 +00:00

554 lines
14 KiB
C

/* GDK - The GIMP Drawing Kit
* Copyright (C) 2000 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "gdkcolor.h"
#include "gdkgc.h"
#include "gdkpango.h"
#include "gdkprivate.h"
#define GDK_INFO_KEY "gdk-info"
typedef struct _GdkPangoContextInfo GdkPangoContextInfo;
struct _GdkPangoContextInfo
{
GdkColormap *colormap;
};
static PangoAttrType gdk_pango_attr_stipple_type;
static PangoAttrType gdk_pango_attr_embossed_type;
static void gdk_pango_get_item_properties (PangoItem *item,
PangoUnderline *uline,
gint *rise,
PangoColor *fg_color,
gboolean *fg_set,
PangoColor *bg_color,
gboolean *bg_set,
gboolean *embossed,
GdkBitmap **stipple,
gboolean *shape_set,
PangoRectangle *ink_rect,
PangoRectangle *logical_rect);
static void
gdk_pango_context_destroy (GdkPangoContextInfo *info)
{
gdk_colormap_unref (info->colormap);
g_free (info);
}
static GdkPangoContextInfo *
gdk_pango_context_get_info (PangoContext *context, gboolean create)
{
GdkPangoContextInfo *info =
g_object_get_qdata (G_OBJECT (context),
g_quark_try_string (GDK_INFO_KEY));
if (!info && create)
{
info = g_new (GdkPangoContextInfo, 1);
info->colormap = NULL;
g_object_set_qdata_full (G_OBJECT (context),
g_quark_from_static_string (GDK_INFO_KEY),
info, (GDestroyNotify)gdk_pango_context_destroy);
}
return info;
}
static GdkGC *
gdk_pango_get_gc (PangoContext *context,
PangoColor *fg_color,
GdkBitmap *stipple,
GdkGC *base_gc)
{
GdkColor color;
GdkGC *result;
GdkPangoContextInfo *info;
g_return_val_if_fail (context != NULL, NULL);
info = gdk_pango_context_get_info (context, FALSE);
if (info == NULL || info->colormap == NULL)
{
g_warning ("you must set the colormap on a PangoContext before using it to draw a layout");
return NULL;
}
color.red = fg_color->red;
color.green = fg_color->green;
color.blue = fg_color->blue;
result = gdk_gc_new (gdk_parent_root);
gdk_gc_copy (result, base_gc);
gdk_rgb_find_color (info->colormap, &color);
gdk_gc_set_foreground (result, &color);
if (stipple)
{
gdk_gc_set_fill (result, GDK_STIPPLED);
gdk_gc_set_stipple (result, stipple);
}
return result;
}
static void
gdk_pango_free_gc (PangoContext *context,
GdkGC *gc)
{
gdk_gc_unref (gc);
}
void
gdk_pango_context_set_colormap (PangoContext *context,
GdkColormap *colormap)
{
GdkPangoContextInfo *info;
g_return_if_fail (context != NULL);
info = gdk_pango_context_get_info (context, TRUE);
g_return_if_fail (info != NULL);
if (info->colormap != colormap)
{
if (info->colormap)
gdk_colormap_unref (info->colormap);
info->colormap = colormap;
if (info->colormap)
gdk_colormap_ref (info->colormap);
}
}
/**
* gdk_draw_layout_line:
* @drawable: the drawable on which to draw the line
* @gc: base graphics to use
* @x: the x position of start of string (in pixels)
* @y: the y position of baseline (in pixels)
* @line: a #PangoLayoutLine
*
* Render a #PangoLayoutLine onto an GDK drawable
*/
void
gdk_draw_layout_line (GdkDrawable *drawable,
GdkGC *gc,
gint x,
gint y,
PangoLayoutLine *line)
{
GSList *tmp_list = line->runs;
PangoRectangle overall_rect;
PangoRectangle logical_rect;
PangoRectangle ink_rect;
PangoContext *context;
gint x_off = 0;
gint rise = 0;
gboolean embossed;
GdkBitmap *stipple;
g_return_if_fail (drawable != NULL);
g_return_if_fail (gc != NULL);
g_return_if_fail (line != NULL);
context = pango_layout_get_context (line->layout);
pango_layout_line_get_extents (line,NULL, &overall_rect);
while (tmp_list)
{
PangoUnderline uline = PANGO_UNDERLINE_NONE;
PangoLayoutRun *run = tmp_list->data;
PangoColor fg_color, bg_color;
gboolean fg_set, bg_set, shape_set;
GdkGC *fg_gc;
gint risen_y;
tmp_list = tmp_list->next;
gdk_pango_get_item_properties (run->item, &uline,
&rise,
&fg_color, &fg_set,
&bg_color, &bg_set,
&embossed,
&stipple,
&shape_set,
&ink_rect,
&logical_rect);
/* we subtract the rise because X coordinates are upside down */
risen_y = y - rise / PANGO_SCALE;
if (!shape_set)
{
if (uline == PANGO_UNDERLINE_NONE)
pango_glyph_string_extents (run->glyphs, run->item->analysis.font,
NULL, &logical_rect);
else
pango_glyph_string_extents (run->glyphs, run->item->analysis.font,
&ink_rect, &logical_rect);
}
if (bg_set)
{
GdkGC *bg_gc = gdk_pango_get_gc (context, &bg_color, stipple, gc);
gdk_draw_rectangle (drawable, bg_gc, TRUE,
x + (x_off + logical_rect.x) / PANGO_SCALE,
risen_y + overall_rect.y / PANGO_SCALE,
logical_rect.width / PANGO_SCALE,
overall_rect.height / PANGO_SCALE);
if (stipple)
gdk_gc_set_fill (bg_gc, GDK_SOLID);
gdk_pango_free_gc (context, bg_gc);
}
if (fg_set || stipple)
fg_gc = gdk_pango_get_gc (context, &fg_color, stipple, gc);
else
fg_gc = gc;
if (!shape_set)
{
gint gx, gy;
gx = x + x_off / PANGO_SCALE;
gy = risen_y;
if (embossed)
{
PangoColor color = { 65535, 65535, 65535 };
GdkGC *white_gc = gdk_pango_get_gc (context, &color, stipple, fg_gc);
gdk_draw_glyphs (drawable, white_gc, run->item->analysis.font,
gx + 1,
gy + 1,
run->glyphs);
gdk_pango_free_gc (context, white_gc);
}
gdk_draw_glyphs (drawable, fg_gc, run->item->analysis.font,
gx, gy,
run->glyphs);
}
switch (uline)
{
case PANGO_UNDERLINE_NONE:
break;
case PANGO_UNDERLINE_DOUBLE:
gdk_draw_line (drawable, fg_gc,
x + (x_off + ink_rect.x) / PANGO_SCALE - 1,
risen_y + 3,
x + (x_off + ink_rect.x + ink_rect.width) / PANGO_SCALE,
risen_y + 3);
/* Fall through */
case PANGO_UNDERLINE_SINGLE:
gdk_draw_line (drawable, fg_gc,
x + (x_off + ink_rect.x) / PANGO_SCALE - 1,
risen_y + 1,
x + (x_off + ink_rect.x + ink_rect.width) / PANGO_SCALE,
risen_y + 1);
break;
case PANGO_UNDERLINE_LOW:
gdk_draw_line (drawable, fg_gc,
x + (x_off + ink_rect.x) / PANGO_SCALE - 1,
risen_y + (ink_rect.y + ink_rect.height) / PANGO_SCALE + 1,
x + (x_off + ink_rect.x + ink_rect.width) / PANGO_SCALE,
risen_y + (ink_rect.y + ink_rect.height) / PANGO_SCALE + 1);
break;
}
if (fg_gc != gc)
gdk_pango_free_gc (context, fg_gc);
x_off += logical_rect.width;
}
}
/**
* gdk_draw_layout:
* @drawable: the drawable on which to draw string
* @gc: base graphics context to use
* @x: the X position of the left of the layout (in pixels)
* @y: the Y position of the top of the layout (in pixels)
* @layout: a #PangoLayout
*
* Render a #PangoLayout onto a GDK drawable
*/
void
gdk_draw_layout (GdkDrawable *drawable,
GdkGC *gc,
int x,
int y,
PangoLayout *layout)
{
PangoLayoutIter *iter;
g_return_if_fail (drawable != NULL);
g_return_if_fail (gc != NULL);
g_return_if_fail (layout != NULL);
iter = pango_layout_get_iter (layout);
do
{
PangoRectangle logical_rect;
PangoLayoutLine *line;
int baseline;
line = pango_layout_iter_get_line (iter);
pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
baseline = pango_layout_iter_get_baseline (iter);
gdk_draw_layout_line (drawable, gc,
x + logical_rect.x / PANGO_SCALE,
y + baseline / PANGO_SCALE,
line);
}
while (pango_layout_iter_next_line (iter));
pango_layout_iter_free (iter);
}
static void
gdk_pango_get_item_properties (PangoItem *item,
PangoUnderline *uline,
gint *rise,
PangoColor *fg_color,
gboolean *fg_set,
PangoColor *bg_color,
gboolean *bg_set,
gboolean *embossed,
GdkBitmap **stipple,
gboolean *shape_set,
PangoRectangle *ink_rect,
PangoRectangle *logical_rect)
{
GSList *tmp_list = item->extra_attrs;
if (fg_set)
*fg_set = FALSE;
if (bg_set)
*bg_set = FALSE;
if (shape_set)
*shape_set = FALSE;
if (rise)
*rise = 0;
if (embossed)
*embossed = FALSE;
if (stipple)
*stipple = NULL;
while (tmp_list)
{
PangoAttribute *attr = tmp_list->data;
switch (attr->klass->type)
{
case PANGO_ATTR_UNDERLINE:
if (uline)
*uline = ((PangoAttrInt *)attr)->value;
break;
case PANGO_ATTR_FOREGROUND:
if (fg_color)
*fg_color = ((PangoAttrColor *)attr)->color;
if (fg_set)
*fg_set = TRUE;
break;
case PANGO_ATTR_BACKGROUND:
if (bg_color)
*bg_color = ((PangoAttrColor *)attr)->color;
if (bg_set)
*bg_set = TRUE;
break;
case PANGO_ATTR_SHAPE:
if (shape_set)
*shape_set = TRUE;
if (logical_rect)
*logical_rect = ((PangoAttrShape *)attr)->logical_rect;
if (ink_rect)
*ink_rect = ((PangoAttrShape *)attr)->ink_rect;
break;
case PANGO_ATTR_RISE:
if (rise)
*rise = ((PangoAttrInt *)attr)->value;
break;
default:
/* stipple_type and embossed_type aren't necessarily
* initialized, but they are 0, which is an
* invalid type so won't occur.
*/
if (stipple && attr->klass->type == gdk_pango_attr_stipple_type)
{
*stipple = ((GdkPangoAttrStipple*)attr)->stipple;
}
else if (embossed && attr->klass->type == gdk_pango_attr_embossed_type)
{
*embossed = ((GdkPangoAttrEmbossed*)attr);
}
break;
}
tmp_list = tmp_list->next;
}
}
static PangoAttribute *
gdk_pango_attr_stipple_copy (const PangoAttribute *attr)
{
const GdkPangoAttrStipple *src = (const GdkPangoAttrStipple*) attr;
return gdk_pango_attr_stipple_new (src->stipple);
}
static void
gdk_pango_attr_stipple_destroy (PangoAttribute *attr)
{
GdkPangoAttrStipple *st = (GdkPangoAttrStipple*) attr;
if (st->stipple)
g_object_unref (G_OBJECT (st->stipple));
g_free (attr);
}
static gboolean
gdk_pango_attr_stipple_compare (const PangoAttribute *attr1,
const PangoAttribute *attr2)
{
const GdkPangoAttrStipple *a = (const GdkPangoAttrStipple*) attr1;
const GdkPangoAttrStipple *b = (const GdkPangoAttrStipple*) attr2;
return a->stipple == b->stipple;
}
/**
* gdk_pango_attr_stipple_new:
* @stipple: a bitmap to be set as stipple
*
* Creates a new attribute containing a stipple bitmap to be used when
* rendering the text.
*
* Return value: new #PangoAttribute
**/
PangoAttribute *
gdk_pango_attr_stipple_new (GdkBitmap *stipple)
{
GdkPangoAttrStipple *result;
static PangoAttrClass klass = {
0,
gdk_pango_attr_stipple_copy,
gdk_pango_attr_stipple_destroy,
gdk_pango_attr_stipple_compare
};
if (!klass.type)
klass.type = gdk_pango_attr_stipple_type =
pango_attr_type_register ("GdkPangoAttrStipple");
result = g_new (GdkPangoAttrStipple, 1);
result->attr.klass = &klass;
if (stipple)
g_object_ref (stipple);
result->stipple = stipple;
return (PangoAttribute *)result;
}
static PangoAttribute *
gdk_pango_attr_embossed_copy (const PangoAttribute *attr)
{
const GdkPangoAttrEmbossed *e = (const GdkPangoAttrEmbossed*) attr;
return gdk_pango_attr_embossed_new (e->embossed);
}
static void
gdk_pango_attr_embossed_destroy (PangoAttribute *attr)
{
g_free (attr);
}
static gboolean
gdk_pango_attr_embossed_compare (const PangoAttribute *attr1,
const PangoAttribute *attr2)
{
const GdkPangoAttrEmbossed *e1 = (const GdkPangoAttrEmbossed*) attr1;
const GdkPangoAttrEmbossed *e2 = (const GdkPangoAttrEmbossed*) attr2;
return e1->embossed == e2->embossed;
}
/**
* gdk_pango_attr_embossed_new:
* @embossed: a bitmap to be set as embossed
*
* Creates a new attribute containing a embossed bitmap to be used when
* rendering the text.
*
* Return value: new #PangoAttribute
**/
PangoAttribute *
gdk_pango_attr_embossed_new (gboolean embossed)
{
GdkPangoAttrEmbossed *result;
static PangoAttrClass klass = {
0,
gdk_pango_attr_embossed_copy,
gdk_pango_attr_embossed_destroy,
gdk_pango_attr_embossed_compare
};
if (!klass.type)
klass.type = gdk_pango_attr_embossed_type =
pango_attr_type_register ("GdkPangoAttrEmbossed");
result = g_new (GdkPangoAttrEmbossed, 1);
result->attr.klass = &klass;
result->embossed = embossed;
return (PangoAttribute *)result;
}