diff options
-rw-r--r-- | tdegtk/Makefile.am | 15 | ||||
-rw-r--r-- | tdegtk/tdegtk-draw.c | 1062 | ||||
-rw-r--r-- | tdegtk/tdegtk-draw.cpp | 1273 | ||||
-rw-r--r-- | tdegtk/tdegtk-hooks.cpp | 100 | ||||
-rw-r--r-- | tdegtk/tdegtk-hooks.h | 63 | ||||
-rw-r--r-- | tdegtk/tdegtk-signals.cpp | 89 | ||||
-rw-r--r-- | tdegtk/tdegtk-signals.h | 64 | ||||
-rw-r--r-- | tdegtk/tdegtk-theme.c | 51 | ||||
-rw-r--r-- | tdegtk/tdegtk-theme.cpp | 788 | ||||
-rw-r--r-- | tdegtk/tdegtk-types.h | 25 | ||||
-rw-r--r-- | tdegtk/tdegtk-utils.cpp | 1064 | ||||
-rw-r--r-- | tdegtk/tdegtk-utils.h | 428 | ||||
-rw-r--r-- | tdegtk/tdegtk-widgetlookup.cpp | 231 | ||||
-rw-r--r-- | tdegtk/tdegtk-widgetlookup.h | 92 | ||||
-rw-r--r-- | tdegtk/tqtcairopainter.cpp | 14 | ||||
-rw-r--r-- | tdegtk/tqtcairopainter.h | 4 | ||||
-rwxr-xr-x | tests/compare | 3 | ||||
-rw-r--r-- | tests/test-painter.cpp | 90 |
18 files changed, 4332 insertions, 1124 deletions
diff --git a/tdegtk/Makefile.am b/tdegtk/Makefile.am index 208c447..26f45dd 100644 --- a/tdegtk/Makefile.am +++ b/tdegtk/Makefile.am @@ -7,6 +7,10 @@ source_h = \ $(srcdir)/tdegtk-draw.h \ $(srcdir)/tdegtk-engine.h \ $(srcdir)/tdegtk-support.h \ + $(srcdir)/tdegtk-hooks.h \ + $(srcdir)/tdegtk-signals.h \ + $(srcdir)/tdegtk-widgetlookup.h \ + $(srcdir)/tdegtk-utils.h \ $(srcdir)/tdegtk-types.h source_c = \ @@ -14,10 +18,14 @@ source_c = \ $(srcdir)/gtkroundedbox.c \ $(srcdir)/raico-blur.c \ $(srcdir)/tdegtk-cairo-support.c \ - $(srcdir)/tdegtk-draw.c \ + $(srcdir)/tdegtk-draw.cpp \ $(srcdir)/tdegtk-engine.c \ $(srcdir)/tdegtk-support.c \ - $(srcdir)/tdegtk-theme.c + $(srcdir)/tdegtk-hooks.cpp \ + $(srcdir)/tdegtk-signals.cpp \ + $(srcdir)/tdegtk-widgetlookup.cpp \ + $(srcdir)/tdegtk-utils.cpp \ + $(srcdir)/tdegtk-theme.cpp enginedir = $(libdir)/gtk-3.0/$(GTK_VERSION)/theming-engines engine_LTLIBRARIES = libtdegtk.la @@ -25,8 +33,9 @@ engine_LTLIBRARIES = libtdegtk.la libtdegtk_la_SOURCES = $(source_h) $(source_c) libtdegtk_la_CFLAGS = $(TDEGTK_CFLAGS) +libtdegtk_la_CXXFLAGS = $(TDEGTK_CXXFLAGS) -I/usr/include/tqt -I/usr/include/tqt3 -I/opt/trinity/include $(TDEGTK_CFLAGS) -libtdegtk_la_LIBADD = $(TDEGTK_LIBADD) +libtdegtk_la_LIBADD = $(TDEGTK_LIBADD) libtqtcairo.la -ltqt -ltqt-mt -L/opt/trinity/lib -ltdecore libtdegtk_la_LDFLAGS = $(TDEGTK_LDFLAGS) diff --git a/tdegtk/tdegtk-draw.c b/tdegtk/tdegtk-draw.c deleted file mode 100644 index f1fa2df..0000000 --- a/tdegtk/tdegtk-draw.c +++ /dev/null @@ -1,1062 +0,0 @@ -/* The TdeGtk Theming Engine for Gtk+. - * Copyright (C) 2011 Canonical Ltd - * - * 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., 51 Franklin St, Fifth Floor, Boston, - * MA 02110-1301, USA. - * - * Authored by Andrea Cimitan <andrea.cimitan@canonical.com> - * - */ - -#include <cairo.h> -#include <gtk/gtk.h> -#include <math.h> - -#include "tdegtk-cairo-support.h" -#include "tdegtk-draw.h" -#include "tdegtk-support.h" -#include "tdegtk-types.h" - -/* draw a texture placed on the centroid */ -static gboolean -draw_centroid_texture (GtkThemingEngine *engine, - cairo_t *cr, - gdouble x, - gdouble y, - gdouble width, - gdouble height) -{ - GtkStateFlags state; - GValue value = { 0, }; - cairo_pattern_t *texture = NULL; - cairo_surface_t *surface = NULL; - gboolean retval = FALSE; - - state = gtk_theming_engine_get_state (engine); - - gtk_theming_engine_get_property (engine, "-tdegtk-centroid-texture", state, &value); - - if (!G_VALUE_HOLDS_BOXED (&value)) - return FALSE; - - texture = g_value_dup_boxed (&value); - g_value_unset (&value); - - if (texture != NULL) - cairo_pattern_get_surface (texture, &surface); - - if (surface != NULL) - { - cairo_save (cr); - - cairo_set_source_surface (cr, surface, (gint) (x + width / 2 - cairo_image_surface_get_width (surface) / 2), - (gint) (y + height / 2 - cairo_image_surface_get_height (surface) / 2)); - cairo_paint (cr); - - cairo_restore (cr); - - retval = TRUE; - } - - if (texture != NULL) - cairo_pattern_destroy (texture); - - return retval; -} - -static void -tdegtk_draw_activity (DRAW_ARGS) -{ - /* playground for effects */ - tdegtk_cairo_draw_background (engine, cr, - x, y, width, height, - 0, gtk_theming_engine_get_junction_sides (engine)); - tdegtk_cairo_draw_frame (engine, cr, - x, y, width, height, - 0, gtk_theming_engine_get_junction_sides (engine)); -} - -static void -tdegtk_draw_arrow (GtkThemingEngine *engine, - cairo_t *cr, - gdouble angle, - gdouble x, - gdouble y, - gdouble size) -{ - GtkStateFlags state; - GdkRGBA color; - gdouble size_reduction = 2; - - state = gtk_theming_engine_get_state (engine); - - gtk_theming_engine_get_color (engine, state, &color); - - cairo_save (cr); - - /* use floor function to adjust doubles */ - y = floor (y); - x = floor (x); - size = floor (size); - - size -= size_reduction; - - cairo_translate (cr, size_reduction / 2, size_reduction / 2); - cairo_translate (cr, x + (gint) (size / 2.0) + 0.5, y + (gint) (size / 2.0) + 0.5); - cairo_rotate (cr, angle - G_PI_2); - cairo_translate (cr, (gint) (size / 4.0), 0); - - /* FIXME this + 1/- 1 is done to fix blurred diagonal lines. - * I know it's not nice at all, but it fix a visual bug */ - cairo_move_to (cr, - (gint) (size / 2.0), - (gint) (size / 2.0)); - cairo_rel_line_to (cr, (gint) (size / 2.0) + 1, (gint) (size / 2.0)); - cairo_rel_line_to (cr, - (gint) (size / 2.0) - 1, (gint) (size / 2.0)); - cairo_close_path (cr); - - cairo_set_source_rgba (cr, color.red, color.green, color.blue, color.alpha * 0.75); - cairo_fill_preserve (cr); - - gdk_cairo_set_source_rgba (cr, &color); - cairo_stroke (cr); - - cairo_restore (cr); -} - -static void -tdegtk_draw_cell_background (DRAW_ARGS, - GtkRegionFlags flags) -{ - GtkJunctionSides junction; - guint hidden_side; - - junction = GTK_JUNCTION_RIGHT | GTK_JUNCTION_LEFT; - - hidden_side = SIDE_RIGHT | SIDE_LEFT; - - if ((flags & GTK_REGION_FIRST) != 0) - { - junction &= ~(GTK_JUNCTION_CORNER_TOPLEFT | GTK_JUNCTION_CORNER_BOTTOMLEFT); - hidden_side &= ~(SIDE_LEFT); - } - if ((flags & GTK_REGION_LAST) != 0) - { - junction &= ~(GTK_JUNCTION_CORNER_TOPRIGHT | GTK_JUNCTION_CORNER_BOTTOMRIGHT); - hidden_side &= ~(SIDE_RIGHT); - } - - tdegtk_cairo_draw_background (engine, cr, - x, y, width, height, - hidden_side, junction); -} - -static void -tdegtk_draw_cell_frame (DRAW_ARGS, - GtkRegionFlags flags) -{ - GtkJunctionSides junction; - guint hidden_side; - - junction = GTK_JUNCTION_RIGHT | GTK_JUNCTION_LEFT; - - hidden_side = SIDE_RIGHT | SIDE_LEFT; - - if ((flags & GTK_REGION_FIRST) != 0) - { - junction &= ~(GTK_JUNCTION_CORNER_TOPLEFT | GTK_JUNCTION_CORNER_BOTTOMLEFT); - hidden_side &= ~(SIDE_LEFT); - } - if ((flags & GTK_REGION_LAST) != 0) - { - junction &= ~(GTK_JUNCTION_CORNER_TOPRIGHT | GTK_JUNCTION_CORNER_BOTTOMRIGHT); - hidden_side &= ~(SIDE_RIGHT); - } - - tdegtk_cairo_draw_frame (engine, cr, - x, y, width, height, - hidden_side, junction); -} - -static void -tdegtk_draw_check (DRAW_ARGS) -{ - GtkStateFlags state; - gboolean in_menu; - gboolean draw_bullet, inconsistent; - - state = gtk_theming_engine_get_state (engine); - - in_menu = gtk_theming_engine_has_class (engine, GTK_STYLE_CLASS_MENUITEM); - inconsistent = (state & GTK_STATE_FLAG_INCONSISTENT) != 0; - draw_bullet = (state & GTK_STATE_FLAG_ACTIVE) != 0; - draw_bullet |= inconsistent; - - if (!in_menu) - { - tdegtk_cairo_draw_background (engine, cr, - x, y, width, height, - 0, gtk_theming_engine_get_junction_sides (engine)); - tdegtk_cairo_draw_frame (engine, cr, - x, y, width, height, - 0, gtk_theming_engine_get_junction_sides (engine)); - } - - if (draw_bullet) - { - GdkRGBA *bullet_color; - - gtk_theming_engine_get (engine, state, - "-tdegtk-bullet-color", &bullet_color, - NULL); - - if (inconsistent) - { - cairo_save (cr); - - cairo_set_line_width (cr, 2.0); - cairo_move_to (cr, 3, height / 2.0); - cairo_line_to (cr, width - 3, height / 2.0); - - cairo_restore (cr); - } - else - { - cairo_translate (cr, x, y); - - if (in_menu) - { - cairo_scale (cr, width / 18.0, height / 18.0); - cairo_translate (cr, 2.0, 3.0); - } - else - { - GdkRGBA *bullet_outline_color; - - gtk_theming_engine_get (engine, state, - "-tdegtk-bullet-outline-color", &bullet_outline_color, - NULL); - - cairo_scale (cr, width / 18.0, height / 18.0); - - /* thick's outline */ - cairo_move_to (cr, 5.0, 5.65); - cairo_line_to (cr, 8.95, 9.57); - cairo_line_to (cr, 16.0, 2.54); - cairo_line_to (cr, 16.0, 8.36); - cairo_line_to (cr, 10.6, 15.1); - cairo_line_to (cr, 7.6, 15.1); - cairo_line_to (cr, 2.95, 10.48); - cairo_line_to (cr, 2.95, 7.65); - cairo_close_path (cr); - - gdk_cairo_set_source_rgba (cr, bullet_outline_color); - cairo_fill (cr); - - cairo_translate (cr, 4.0, 2.0); - - gdk_rgba_free (bullet_outline_color); - } - - /* thick */ - cairo_move_to (cr, 0.0, 6.0); - cairo_line_to (cr, 0.0, 8.0); - cairo_line_to (cr, 4.0, 12.0); - cairo_line_to (cr, 6.0, 12.0); - cairo_line_to (cr, 15.0, 1.0); - cairo_line_to (cr, 15.0, 0.0); - cairo_line_to (cr, 14.0, 0.0); - cairo_line_to (cr, 5.0, 9.0); - cairo_line_to (cr, 1.0, 5.0); - cairo_close_path (cr); - } - - gdk_cairo_set_source_rgba (cr, bullet_color); - cairo_fill (cr); - - gdk_rgba_free (bullet_color); - } -} - -static void -tdegtk_draw_common (DRAW_ARGS) -{ - tdegtk_cairo_draw_background (engine, cr, - x, y, width, height, - 0, gtk_theming_engine_get_junction_sides (engine)); - tdegtk_cairo_draw_frame (engine, cr, - x, y, width, height, - 0, gtk_theming_engine_get_junction_sides (engine)); -} - -static void -tdegtk_draw_common_background (DRAW_ARGS) -{ - tdegtk_cairo_draw_background (engine, cr, - x, y, width, height, - 0, gtk_theming_engine_get_junction_sides (engine)); -} - -static void -tdegtk_draw_common_frame (DRAW_ARGS) -{ - tdegtk_cairo_draw_frame (engine, cr, - x, y, width, height, - 0, gtk_theming_engine_get_junction_sides (engine)); -} - -static void -tdegtk_draw_expander (DRAW_ARGS) -{ - GtkStateFlags state; - GdkRGBA color; - gint size; - gdouble angle = G_PI_2; - - state = gtk_theming_engine_get_state (engine); - - gtk_theming_engine_get_color (engine, state, &color); - - cairo_save (cr); - - /* use floor function to adjust doubles */ - size = floor (MIN (width, height)); - - x += (gint) (width / 2) - size / 2; - y += (gint) (height / 2) - size / 2; - - if ((state & GTK_STATE_FLAG_ACTIVE) == 0) - angle = 0; - - cairo_translate (cr, x + size / 2.0 + 0.5, y + size / 2.0 + 0.5); - cairo_rotate (cr, angle); - cairo_translate (cr, size / 4.0, 0); - - /* FIXME this + 1/- 1 is done to fix blurred diagonal lines. - * I know it's not nice at all, but it fix a visual bug */ - cairo_move_to (cr, - size / 2.0, - size / 2.0); - cairo_rel_line_to (cr, size / 2.0 + 1, size / 2.0); - cairo_rel_line_to (cr, - size / 2.0 - 1, size / 2.0); - cairo_close_path (cr); - - cairo_set_source_rgba (cr, color.red, color.green, color.blue, color.alpha * 0.75); - cairo_fill_preserve (cr); - - gdk_cairo_set_source_rgba (cr, &color); - cairo_stroke (cr); - - cairo_restore (cr); -} - -static void -tdegtk_draw_extension (DRAW_ARGS, - GtkPositionType gap_side) -{ - GtkBorder border; - GtkBorder *outer_border; - GtkJunctionSides junction = 0; - GtkStateFlags state; - gboolean has_outer_stroke = FALSE; - gdouble bg_offset = 0; - guint hidden_side = 0; - - state = gtk_theming_engine_get_state (engine); - - gtk_theming_engine_get (engine, state, - "-tdegtk-outer-stroke-width", &outer_border, - NULL); - gtk_theming_engine_get_border (engine, state, &border); - - if (!tdegtk_gtk_border_is_zero (outer_border)) - has_outer_stroke = TRUE; - - cairo_save (cr); - - /* FIXME doesn't work properly with not homogenuos border-width, - * especially between tab and notebook. - * I guess the issue comes from the fact draw_background - * is looking at border dimensions while we're not, - * or we're doing it wrong. - * draw_background is looking at SIDE_BOTTOM and - * sets border to 0 for this side */ - switch (gap_side) - { - case GTK_POS_TOP: - junction = GTK_JUNCTION_TOP; - hidden_side = SIDE_TOP; - - if (has_outer_stroke) - { - y -= outer_border->bottom; - height += outer_border->bottom; - } - - if ((state & GTK_STATE_FLAG_ACTIVE) != 0) - bg_offset = border.bottom; - - cairo_translate (cr, x + width, y + height); - cairo_rotate (cr, G_PI); - break; - default: - case GTK_POS_BOTTOM: - junction = GTK_JUNCTION_BOTTOM; - hidden_side = SIDE_BOTTOM; - - if (has_outer_stroke) - height += outer_border->top; - - if ((state & GTK_STATE_FLAG_ACTIVE) != 0) - bg_offset = border.top; - - cairo_translate (cr, x, y); - break; - case GTK_POS_LEFT: - junction = GTK_JUNCTION_LEFT; - hidden_side = SIDE_LEFT; - - if (has_outer_stroke) - { - x -= outer_border->right; - width += outer_border->right; - } - - if ((state & GTK_STATE_FLAG_ACTIVE) != 0) - bg_offset = border.right; - - cairo_translate (cr, x + width, y); - cairo_rotate (cr, G_PI / 2); - break; - case GTK_POS_RIGHT: - junction = GTK_JUNCTION_RIGHT; - hidden_side = SIDE_RIGHT; - - if (has_outer_stroke) - width += outer_border->left; - - if ((state & GTK_STATE_FLAG_ACTIVE) != 0) - bg_offset = border.left; - - cairo_translate (cr, x, y + height); - cairo_rotate (cr, - G_PI / 2); - break; - } - - if (gap_side == GTK_POS_TOP || - gap_side == GTK_POS_BOTTOM) - tdegtk_cairo_draw_background (engine, cr, 0, 0, width, height + bg_offset, SIDE_BOTTOM, GTK_JUNCTION_BOTTOM); - else - tdegtk_cairo_draw_background (engine, cr, 0, 0, height, width + bg_offset, SIDE_BOTTOM, GTK_JUNCTION_BOTTOM); - cairo_restore (cr); - - /* FIXME the frame on bottom bar has the wrong gradient, - * while should be reflected */ - tdegtk_cairo_draw_frame (engine, cr, x, y, width, height, hidden_side, junction); - - gtk_border_free (outer_border); -} - -static void -tdegtk_draw_focus (DRAW_ARGS) -{ - GdkRGBA *fill_color, *border_color, *outer_stroke_color; - GtkStateFlags state; - gint focus_pad, line_width; - gint radius; - - state = gtk_theming_engine_get_state (engine); - - gtk_theming_engine_get (engine, state, - "-tdegtk-focus-border-color", &border_color, - "-tdegtk-focus-border-radius", &radius, - "-tdegtk-focus-fill-color", &fill_color, - "-tdegtk-focus-outer-stroke-color", &outer_stroke_color, - NULL); - gtk_theming_engine_get_style (engine, - "focus-padding", &focus_pad, - "focus-line-width", &line_width, - NULL); - - x += focus_pad; - y += focus_pad; - width -= focus_pad * 2; - height -= focus_pad * 2; - - cairo_save (cr); - - cairo_set_line_width (cr, line_width); - - /* first layer, background */ - tdegtk_cairo_round_rect (cr, x, y, - width, height, - radius, SIDE_ALL, GTK_JUNCTION_NONE); - gdk_cairo_set_source_rgba (cr, fill_color); - cairo_fill (cr); - - /* second layer, outer stroke */ - tdegtk_cairo_round_rect_inner (cr, x - line_width, y - line_width, - width + line_width * 2, height + line_width * 2, - radius + 1, SIDE_ALL, GTK_JUNCTION_NONE); - gdk_cairo_set_source_rgba (cr, outer_stroke_color); - cairo_stroke (cr); - - /* third layer, border */ - tdegtk_cairo_round_rect_inner (cr, x, y, - width, height, - radius, SIDE_ALL, GTK_JUNCTION_NONE); - gdk_cairo_set_source_rgba (cr, border_color); - cairo_stroke (cr); - - cairo_restore (cr); - - gdk_rgba_free (border_color); - gdk_rgba_free (fill_color); - gdk_rgba_free (outer_stroke_color); -} - -static void -tdegtk_draw_frame_gap (DRAW_ARGS, - GtkPositionType gap_side, - gdouble xy0_gap, - gdouble xy1_gap) -{ - GtkBorder border; - GtkBorder *outer_border; - GtkCssBorderCornerRadius *top_left_radius, *top_right_radius; - GtkCssBorderCornerRadius *bottom_left_radius, *bottom_right_radius; - GtkCssBorderRadius border_radius = { { 0, }, }; - GtkJunctionSides junction; - GtkStateFlags state; - gboolean has_outer_stroke = FALSE; - gdouble x0, y0, x1, y1, xc, yc, wc, hc; - - xc = yc = wc = hc = 0; - - junction = gtk_theming_engine_get_junction_sides (engine); - - state = gtk_theming_engine_get_state (engine); - - gtk_theming_engine_get (engine, state, - /* Can't use border-radius as it's an int for - * backwards compat */ - "border-top-left-radius", &top_left_radius, - "border-top-right-radius", &top_right_radius, - "border-bottom-right-radius", &bottom_right_radius, - "border-bottom-left-radius", &bottom_left_radius, - "-tdegtk-outer-stroke-width", &outer_border, - NULL); - gtk_theming_engine_get_border (engine, state, &border); - - if (!tdegtk_gtk_border_is_zero (outer_border)) - has_outer_stroke = TRUE; - - if (top_left_radius) - border_radius.top_left = *top_left_radius; - g_free (top_left_radius); - if (top_right_radius) - border_radius.top_right = *top_right_radius; - g_free (top_right_radius); - if (bottom_right_radius) - border_radius.bottom_right = *bottom_right_radius; - g_free (bottom_right_radius); - if (bottom_left_radius) - border_radius.bottom_left = *bottom_left_radius; - g_free (bottom_left_radius); - - cairo_save (cr); - - switch (gap_side) - { - case GTK_POS_TOP: - xc = x + xy0_gap + border.left; - yc = y; - wc = MAX (xy1_gap - xy0_gap - (border.left + border.right), 0); - hc = border.top * 2; - - if (has_outer_stroke) - { - xc += outer_border->left; - wc = MAX (xy1_gap - xy0_gap - (outer_border->left + outer_border->right) - (border.left + border.right), 0); - hc += outer_border->top; - } - - if (xy0_gap < border_radius.top_left.horizontal) - junction |= GTK_JUNCTION_CORNER_TOPLEFT; - - if (xy1_gap > width - border_radius.top_right.horizontal) - junction |= GTK_JUNCTION_CORNER_TOPRIGHT; - break; - default: - case GTK_POS_BOTTOM: - xc = x + xy0_gap + border.left; - yc = y + height - border.bottom * 2; - wc = MAX (xy1_gap - xy0_gap - (border.left + border.right), 0); - hc = border.bottom * 2; - - if (has_outer_stroke) - { - xc += outer_border->left; - yc -= outer_border->bottom; - wc = MAX (xy1_gap - xy0_gap - (outer_border->left + outer_border->right) - (border.left + border.right), 0); - hc += outer_border->bottom; - } - - if (xy0_gap < border_radius.bottom_left.horizontal) - junction |= GTK_JUNCTION_CORNER_BOTTOMLEFT; - - if (xy1_gap > width - border_radius.bottom_right.horizontal) - junction |= GTK_JUNCTION_CORNER_BOTTOMRIGHT; - - break; - case GTK_POS_LEFT: - xc = x; - yc = y + xy0_gap + border.top; - wc = border.left * 2; - hc = MAX (xy1_gap - xy0_gap - (border.top + border.bottom), 0); - - if (has_outer_stroke) - { - yc += outer_border->top; - wc += outer_border->left; - hc = MAX (xy1_gap - xy0_gap - (outer_border->top + outer_border->bottom) - (border.top + border.bottom), 0); - } - - if (xy0_gap < border_radius.top_left.vertical) - junction |= GTK_JUNCTION_CORNER_TOPLEFT; - - if (xy1_gap > height - border_radius.bottom_left.vertical) - junction |= GTK_JUNCTION_CORNER_BOTTOMLEFT; - - break; - case GTK_POS_RIGHT: - xc = x + width - border.right * 2; - yc = y + xy0_gap + border.top; - wc = border.right * 2; - hc = MAX (xy1_gap - xy0_gap - (border.top + border.bottom), 0); - - if (has_outer_stroke) - { - xc -= outer_border->right; - yc += outer_border->top; - wc += outer_border->right; - hc = MAX (xy1_gap - xy0_gap - (outer_border->top + outer_border->bottom) - (border.top + border.bottom), 0); - } - - if (xy0_gap < border_radius.top_right.vertical) - junction |= GTK_JUNCTION_CORNER_TOPRIGHT; - - if (xy1_gap > height - border_radius.bottom_right.vertical) - junction |= GTK_JUNCTION_CORNER_BOTTOMRIGHT; - - break; - } - - /* clip the gap */ - cairo_clip_extents (cr, &x0, &y0, &x1, &y1); - cairo_rectangle (cr, x0, y0, x1 - x0, yc - y0); - cairo_rectangle (cr, x0, yc, xc - x0, hc); - cairo_rectangle (cr, xc + wc, yc, x1 - (xc + wc), hc); - cairo_rectangle (cr, x0, yc + hc, x1 - x0, y1 - (yc + hc)); - cairo_clip (cr); - - /* draw the frame, gap area will not be drawn */ - tdegtk_cairo_draw_frame (engine, cr, x, y, width, height, 0, junction); - - cairo_restore (cr); - - gtk_border_free (outer_border); -} - -static void -tdegtk_draw_grip (DRAW_ARGS) -{ - GdkRGBA border_color; - GdkRGBA *inner_stroke_color; - GtkStateFlags state; - gint lx, ly; - - state = gtk_theming_engine_get_state (engine); - - gtk_theming_engine_get (engine, state, - "-tdegtk-inner-stroke-color", &inner_stroke_color, - NULL); - gtk_theming_engine_get_border_color (engine, state, &border_color); - - for (ly = 0; ly < 4; ly++) - { - /* vertically, four rows of dots */ - for (lx = 0; lx <= ly; lx++) - { - /* horizontally */ - int ny = (3.5 - ly) * 3; - int nx = lx * 3; - - gdk_cairo_set_source_rgba (cr, inner_stroke_color); - cairo_rectangle (cr, x + width - nx - 1, y + height - ny - 1, 2, 2); - cairo_fill (cr); - - gdk_cairo_set_source_rgba (cr, &border_color); - cairo_rectangle (cr, x + width - nx - 1, y + height - ny - 1, 1, 1); - cairo_fill (cr); - } - } - - gdk_rgba_free (inner_stroke_color); -} - -static void -tdegtk_draw_handle (DRAW_ARGS) -{ - gdouble line_width; - gint i, bar_y, num_bars, bar_spacing, bar_width, bar_height; - - tdegtk_cairo_draw_background (engine, cr, - x, y, width, height, - 0, gtk_theming_engine_get_junction_sides (engine)); - - if (draw_centroid_texture (engine, cr, x, y, width, height)) - return; - - tdegtk_get_line_width (engine, &line_width); - - bar_y = 1; - num_bars = 3; - bar_spacing = 3; - bar_width = 3; - bar_height = num_bars * bar_spacing * line_width; - - cairo_save (cr); - - cairo_translate (cr, x + (gint) (width / 2), y + (gint) (height / 2)); - - if (height > width) - cairo_translate (cr, - bar_width / 2 - 0.5, - bar_height / 2 + 0.5); - else - { - cairo_translate (cr, - bar_height / 2 + 0.5, bar_width / 2 + 0.5); - cairo_rotate (cr, - G_PI / 2); - } - - for (i = 0; i < num_bars; i++) - { - /* draw bars */ - cairo_move_to (cr, 0, bar_y); - cairo_line_to (cr, bar_width, bar_y); - tdegtk_cairo_set_source_border (engine, cr, bar_width, 3); - cairo_stroke (cr); - - cairo_move_to (cr, 0, bar_y + line_width); - cairo_line_to (cr, bar_width, bar_y + line_width); - tdegtk_cairo_set_source_inner_stroke (engine, cr, bar_width, line_width); - cairo_stroke (cr); - - bar_y += bar_spacing; - } - - cairo_restore (cr); -} - -static void -tdegtk_draw_line (GtkThemingEngine *engine, - cairo_t *cr, - gdouble x0, - gdouble y0, - gdouble x1, - gdouble y1) -{ - /* line endings */ - if (y0 == y1) - { - y0 += 0.5; - y1 += 0.5; - x0 += 0.5; - x1 -= 0.5; - } - else if (x0 == x1) - { - x0 += 0.5; - x1 += 0.5; - y0 += 0.5; - y1 -= 0.5; - } - - cairo_move_to (cr, x0, y0); - cairo_line_to (cr, x1, y1); - tdegtk_cairo_set_source_border (engine, cr, MAX (x1 - x0, 1), MAX (y1 - y0, 1)); - cairo_stroke (cr); -} - -static void -tdegtk_draw_notebook (DRAW_ARGS, - GtkPositionType gap_side, - gdouble xy0_gap, - gdouble xy1_gap) -{ - tdegtk_cairo_draw_background (engine, cr, - x, y, width, height, - 0, gtk_theming_engine_get_junction_sides (engine)); - tdegtk_draw_frame_gap (engine, cr, - x, y, width, height, - gap_side, xy0_gap, xy1_gap); -} - -static void -tdegtk_draw_radio (DRAW_ARGS) -{ - GtkStateFlags state; - gboolean in_menu; - gboolean draw_bullet, inconsistent; - - state = gtk_theming_engine_get_state (engine); - - in_menu = gtk_theming_engine_has_class (engine, GTK_STYLE_CLASS_MENUITEM); - inconsistent = (state & GTK_STATE_FLAG_INCONSISTENT) != 0; - draw_bullet = (state & GTK_STATE_FLAG_ACTIVE) != 0; - draw_bullet |= inconsistent; - - if (!in_menu) - { - tdegtk_cairo_draw_background (engine, cr, - x, y, width, height, - 0, gtk_theming_engine_get_junction_sides (engine)); - tdegtk_cairo_draw_frame (engine, cr, - x, y, width, height, - 0, gtk_theming_engine_get_junction_sides (engine)); - } - - if (draw_bullet) - { - GdkRGBA *bullet_color; - - gtk_theming_engine_get (engine, state, - "-tdegtk-bullet-color", &bullet_color, - NULL); - - if (inconsistent) - { - cairo_save (cr); - - cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); - cairo_set_line_width (cr, 2.0); - - cairo_move_to(cr, 5, height / 2.0); - cairo_line_to(cr, width - 5, height / 2.0); - - gdk_cairo_set_source_rgba (cr, bullet_color); - cairo_stroke (cr); - - cairo_restore (cr); - } - else - { - if (in_menu) - cairo_arc (cr, x + width / 2.0, y + height / 2.0, - (width + height) / 4.0 - 4, 0, G_PI * 2); - else - { - GdkRGBA *bullet_outline_color; - - gtk_theming_engine_get (engine, state, - "-tdegtk-bullet-outline-color", &bullet_outline_color, - NULL); - - /* bullet's outline */ - cairo_arc (cr, x + width / 2.0, y + height / 2.0, - (width + height) / 4.0 - 4, 0, G_PI * 2); - gdk_cairo_set_source_rgba (cr, bullet_outline_color); - cairo_fill (cr); - - cairo_arc (cr, x + width / 2.0, y + height / 2.0, - (width + height) / 4.0 - 5, 0, G_PI * 2); - - gdk_rgba_free (bullet_outline_color); - } - - /* bullet */ - gdk_cairo_set_source_rgba (cr, bullet_color); - cairo_fill (cr); - } - - gdk_rgba_free (bullet_color); - } -} - -static void -tdegtk_draw_separator (DRAW_ARGS) -{ - gdouble line_width; - - tdegtk_get_line_width (engine, &line_width); - - if (line_width == 0) - return; - - /* FIXME right code should be - * if (gtk_theming_engine_has_class (engine, GTK_STYLE_CLASS_VERTICAL)) - * but doesn't work for separator tool item. */ - if (width > height) - { - cairo_move_to (cr, x, y + (gint) (height / 2) + line_width / 2); - cairo_line_to (cr, x + width, y + (gint) (height / 2) + line_width / 2); - tdegtk_cairo_set_source_inner_stroke (engine, cr, width, line_width); - cairo_stroke (cr); - - cairo_move_to (cr, x, y + (gint) (height / 2) - line_width / 2); - cairo_line_to (cr, x + width, y + (gint) (height / 2) - line_width / 2); - tdegtk_cairo_set_source_border (engine, cr, width, line_width); - cairo_stroke (cr); - } - else - { - cairo_move_to (cr, x + (gint) (width / 2) + line_width / 2, y); - cairo_line_to (cr, x + (gint) (width / 2) + line_width / 2, y + height); - tdegtk_cairo_set_source_inner_stroke (engine, cr, line_width, height); - cairo_stroke (cr); - - cairo_move_to (cr, x + (gint) (width / 2) - line_width / 2, y); - cairo_line_to (cr, x + (gint) (width / 2) - line_width / 2, y + height); - tdegtk_cairo_set_source_border (engine, cr, line_width, height); - cairo_stroke (cr); - } -} - -static void -tdegtk_draw_slider (DRAW_ARGS, - GtkOrientation orientation) -{ - /* use orientation, if needed */ - tdegtk_cairo_draw_background (engine, cr, - x, y, width, height, - 0, gtk_theming_engine_get_junction_sides (engine)); - - draw_centroid_texture (engine, cr, x, y, width, height); - - tdegtk_cairo_draw_frame (engine, cr, - x, y, width, height, - 0, gtk_theming_engine_get_junction_sides (engine)); -} - -static void -tdegtk_draw_spinbutton_background (DRAW_ARGS) -{ - GtkBorder border, *outer_border; - GtkJunctionSides junction; - GtkStateFlags state; - - junction = gtk_theming_engine_get_junction_sides (engine); - - state = gtk_theming_engine_get_state (engine); - - gtk_theming_engine_get (engine, state, - "-tdegtk-outer-stroke-width", &outer_border, - NULL); - gtk_theming_engine_get_border (engine, state, &border); - - cairo_save (cr); - - cairo_rectangle (cr, x, y, width, height); - cairo_clip (cr); - - if (!(junction & GTK_JUNCTION_CORNER_TOPRIGHT)) - { - y = ceil (y); - height = floor (height); - height += border.bottom + outer_border->bottom; - } - else - { - y = floor (y); - height = ceil (height); - y -= outer_border->top; - height += outer_border->bottom; - } - - tdegtk_cairo_draw_background (engine, cr, - x, y, width, height, - 0, junction); - - cairo_restore (cr); - - gtk_border_free (outer_border); -} - -static void -tdegtk_draw_spinbutton_frame (DRAW_ARGS) -{ - GtkBorder border, *outer_border; - GtkJunctionSides junction; - GtkStateFlags state; - - junction = gtk_theming_engine_get_junction_sides (engine); - - state = gtk_theming_engine_get_state (engine); - - gtk_theming_engine_get (engine, state, - "-tdegtk-outer-stroke-width", &outer_border, - NULL); - gtk_theming_engine_get_border (engine, state, &border); - - cairo_save (cr); - - cairo_rectangle (cr, x, y, width, height); - cairo_clip (cr); - - if (!(junction & GTK_JUNCTION_CORNER_TOPRIGHT)) - { - y = ceil (y); - height = floor (height); - height += border.bottom + outer_border->bottom; - } - else - { - y = floor (y); - height = ceil (height); - y -= outer_border->top; - height += outer_border->bottom; - } - - tdegtk_cairo_draw_frame (engine, cr, - x, y, width, height, - 0, junction); - - cairo_restore (cr); - - gtk_border_free (outer_border); -} - -void -tdegtk_register_style_default (TdeGtkStyleFunctions *functions) -{ - g_assert (functions); - - functions->draw_activity = tdegtk_draw_activity; - functions->draw_arrow = tdegtk_draw_arrow; - functions->draw_cell_background = tdegtk_draw_cell_background; - functions->draw_cell_frame = tdegtk_draw_cell_frame; - functions->draw_check = tdegtk_draw_check; - functions->draw_common = tdegtk_draw_common; - functions->draw_common_background = tdegtk_draw_common_background; - functions->draw_common_frame = tdegtk_draw_common_frame; - functions->draw_expander = tdegtk_draw_expander; - functions->draw_extension = tdegtk_draw_extension; - functions->draw_focus = tdegtk_draw_focus; - functions->draw_frame_gap = tdegtk_draw_frame_gap; - functions->draw_grip = tdegtk_draw_grip; - functions->draw_handle = tdegtk_draw_handle; - functions->draw_line = tdegtk_draw_line; - functions->draw_notebook = tdegtk_draw_notebook; - functions->draw_radio = tdegtk_draw_radio; - functions->draw_separator = tdegtk_draw_separator; - functions->draw_slider = tdegtk_draw_slider; - functions->draw_spinbutton_background = tdegtk_draw_spinbutton_background; - functions->draw_spinbutton_frame = tdegtk_draw_spinbutton_frame; -} diff --git a/tdegtk/tdegtk-draw.cpp b/tdegtk/tdegtk-draw.cpp new file mode 100644 index 0000000..77c0b7c --- /dev/null +++ b/tdegtk/tdegtk-draw.cpp @@ -0,0 +1,1273 @@ +/* The TdeGtk Theming Engine for Gtk+. + * Copyright (C) 2012 Timothy Pearson <kb9vqf@pearsoncomputing.net> + * + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#include <cairo.h> +#include <gtk/gtk.h> +#include <math.h> + +#include <tqapplication.h> +#include <tqpainter.h> +#include <tqstyle.h> + +#include "tdegtk-cairo-support.h" +#include "tdegtk-draw.h" +#include "tdegtk-support.h" +#include "tdegtk-types.h" +#include "tdegtk-widgetlookup.h" +#include "tdegtk-utils.h" + +#include "tqtcairopainter.h" + +#define DEBUG_FILL_BACKGROUND_WITH_COLOR(p,x,y,z) TQBrush brush2( TQColor(x,y,z), TQBrush::SolidPattern ); \ + p.setBrush( brush2 ); \ + p.setPen( TQt::NoPen ); \ + p.drawRect( 0,0, 5000,5000 ); + +#define DRAW_FILLED_RECTANGLE_OVER_ENTIRE_AREA(p,x) p.setBrush(x); \ + p.setPen(TQt::NoPen); \ + p.drawRect(0, 0, width, height); + +#define DRAW_FILLED_RECTANGLE_OVER_SPECIFIC_AREA(p,b,x,y,w,h) p.setBrush(b); \ + p.setPen(TQt::NoPen); \ + p.drawRect(x, y, w, h); + +WidgetLookup m_widgetLookup; + +// Keep this in sync with gtkToTQPaletteColorGroup() below +static TQColorGroup gtkToTQtColorGroup(GtkThemingEngine* engine, GtkStateFlags state) { +// GdkRGBA *background_color; +// GdkRGBA *foreground_color; +// gtk_theming_engine_get(engine, state, GTK_STYLE_PROPERTY_BACKGROUND_COLOR, &background_color, NULL); +// gtk_theming_engine_get(engine, state, GTK_STYLE_PROPERTY_COLOR, &foreground_color, NULL); + +// GTK_STATE_FLAG_ACTIVE +// GTK_STATE_FLAG_PRELIGHT +// GTK_STATE_FLAG_SELECTED +// GTK_STATE_FLAG_INSENSITIVE +// GTK_STATE_FLAG_INCONSISTENT +// GTK_STATE_FLAG_FOCUSED + + TQColorGroup cg; +// if (state & GTK_STATE_FLAG_INCONSISTENT) { +// cg = tqApp->palette().inactive(); +// } + /*else*/ if (state & GTK_STATE_FLAG_INSENSITIVE) { + cg = tqApp->palette().disabled(); + } + else { + cg = tqApp->palette().active(); + } +// cg.setColor(TQColorGroup::Background, TQColor((background_color->red*255.0),(background_color->green*255.0),(background_color->blue*255.0))); +// cg.setColor(TQColorGroup::Foreground, TQColor((foreground_color->red*255.0),(foreground_color->green*255.0),(foreground_color->blue*255.0))); + + return cg; +} + +// Keep this in sync with gtkToTQtColorGroup() above +static TQPalette::ColorGroup gtkToTQPaletteColorGroup(GtkThemingEngine* engine, GtkStateFlags state) { + TQPalette::ColorGroup cg = TQPalette::Active; + + if (state & GTK_STATE_FLAG_INSENSITIVE) { + cg = TQPalette::Disabled; + } + else { + cg = TQPalette::Active; + } + + return cg; +} + +static TQStyle::SFlags gtkToTQtStyleFlags(GtkThemingEngine* engine, GtkStateFlags state, TQt3WidgetType wt) { + TQStyle::SFlags sflags = TQStyle::Style_Default; + + gboolean active, inconsistent, mousedown, prelight, focused, disabled, in_menu; + in_menu = gtk_theming_engine_has_class (engine, GTK_STYLE_CLASS_MENUITEM); + prelight = (state & GTK_STATE_FLAG_PRELIGHT) != 0; + focused = (state & GTK_STATE_FLAG_FOCUSED) != 0; + disabled = (state & GTK_STATE_FLAG_INSENSITIVE) != 0; + inconsistent = (state & GTK_STATE_FLAG_INCONSISTENT) != 0; + mousedown = (state & GTK_STATE_FLAG_SELECTED) != 0; + active = (state & GTK_STATE_FLAG_ACTIVE) != 0; + + if ((wt == TQT3WT_TQRadioButton) || (wt == TQT3WT_TQCheckBox) || (wt == TQT3WT_TQPushButton)) { + if (!inconsistent) { + if (active) { + sflags |= TQStyle::Style_On; + } + else { + sflags |= TQStyle::Style_Off; + } + } + if (mousedown) { + sflags |= TQStyle::Style_Down; + } + if (prelight) { + sflags |= TQStyle::Style_MouseOver; + } + if (focused) { + sflags |= TQStyle::Style_HasFocus; + } + if (!disabled) { + sflags |= TQStyle::Style_Enabled; + } + } + else if (wt == TQT3WT_GTKTreeViewCell) { + if (!inconsistent) { + if (active) { + sflags |= TQStyle::Style_On; + } + else { + sflags |= TQStyle::Style_Off; + } + } + if (prelight) { + sflags |= TQStyle::Style_MouseOver; + } + if (focused) { + sflags |= TQStyle::Style_HasFocus; + } + if (!disabled) { + sflags |= TQStyle::Style_Enabled; + } + } + else { + if (active) { + sflags |= TQStyle::Style_Down; + } + if (prelight) { + sflags |= TQStyle::Style_MouseOver; + } + if (focused) { + sflags |= TQStyle::Style_HasFocus; + } + if (!disabled) { + sflags |= TQStyle::Style_Enabled; + } + } + + return sflags; +} + +static TQColorGroup::ColorRole backgroundModeToColorRole(TQt::BackgroundMode mode) { + TQColorGroup::ColorRole ret = TQColorGroup::Background; + + if (mode == TQt::PaletteForeground) { + ret = TQColorGroup::Foreground; + } + else if (mode == TQt::PaletteBackground) { + ret = TQColorGroup::Background; + } + else if (mode == TQt::PaletteButton) { + ret = TQColorGroup::Button; + } + else if (mode == TQt::PaletteLight) { + ret = TQColorGroup::Light; + } + else if (mode == TQt::PaletteMidlight) { + ret = TQColorGroup::Midlight; + } + else if (mode == TQt::PaletteDark) { + ret = TQColorGroup::Dark; + } + else if (mode == TQt::PaletteMid) { + ret = TQColorGroup::Mid; + } + else if (mode == TQt::PaletteText) { + ret = TQColorGroup::Text; + } + else if (mode == TQt::PaletteBrightText) { + ret = TQColorGroup::BrightText; + } + else if (mode == TQt::PaletteButtonText) { + ret = TQColorGroup::ButtonText; + } + else if (mode == TQt::PaletteBase) { + ret = TQColorGroup::Base; + } + else if (mode == TQt::PaletteShadow) { + ret = TQColorGroup::Shadow; + } + else if (mode == TQt::PaletteHighlight) { + ret = TQColorGroup::Highlight; + } + else if (mode == TQt::PaletteHighlightedText) { + ret = TQColorGroup::HighlightedText; + } + else if (mode == TQt::PaletteLink) { + ret = TQColorGroup::Link; + } + else if (mode == TQt::PaletteLinkVisited) { + ret = TQColorGroup::LinkVisited; + } + + return ret; +} + +/* draw a texture placed on the centroid */ +static gboolean +draw_centroid_texture (GtkThemingEngine *engine, + cairo_t *cr, + gdouble x, + gdouble y, + gdouble width, + gdouble height) +{ + GtkStateFlags state; + GValue value = { 0, }; + cairo_pattern_t *texture = NULL; + cairo_surface_t *surface = NULL; + gboolean retval = FALSE; + + state = gtk_theming_engine_get_state (engine); + + gtk_theming_engine_get_property (engine, "-tdegtk-centroid-texture", state, &value); + + if (!G_VALUE_HOLDS_BOXED (&value)) + return FALSE; + + texture = (cairo_pattern_t*)g_value_dup_boxed (&value); + g_value_unset (&value); + + if (texture != NULL) + cairo_pattern_get_surface (texture, &surface); + + if (surface != NULL) + { + cairo_save (cr); + + cairo_set_source_surface (cr, surface, (gint) (x + width / 2 - cairo_image_surface_get_width (surface) / 2), + (gint) (y + height / 2 - cairo_image_surface_get_height (surface) / 2)); + cairo_paint (cr); + + cairo_restore (cr); + + retval = TRUE; + } + + if (texture != NULL) + cairo_pattern_destroy (texture); + + return retval; +} + +static void +tdegtk_draw_activity (DRAW_ARGS) +{ + /* playground for effects */ + tdegtk_cairo_draw_background (engine, cr, + x, y, width, height, + 0, gtk_theming_engine_get_junction_sides (engine)); + tdegtk_cairo_draw_frame (engine, cr, + x, y, width, height, + 0, gtk_theming_engine_get_junction_sides (engine)); +} + +static void +tdegtk_draw_arrow (GtkThemingEngine *engine, + cairo_t *cr, + gdouble angle, + gdouble x, + gdouble y, + gdouble size) +{ + TQRect boundingRect(0, 0, size, size); + TQt3CairoPaintDevice pd(NULL, x, y, size, size, cr); + TQPainter p(&pd); + + DEBUG_FILL_BACKGROUND_WITH_COLOR(p,128,0,255); + + GtkStateFlags state; + state = gtk_theming_engine_get_state(engine); + + GtkArrowType arrow_direction; + + if ((angle <= ((G_PI/2)-(G_PI/4))) || (angle > ((3*(G_PI/2))+(G_PI/4)))) { + arrow_direction = GTK_ARROW_UP; + } + else if ((angle <= ((G_PI)-(G_PI/4))) && (angle > ((0)+(G_PI/4)))) { + arrow_direction = GTK_ARROW_RIGHT; + } + else if ((angle <= ((3*(G_PI/2))-(G_PI/4))) && (angle > ((G_PI/2)+(G_PI/4)))) { + arrow_direction = GTK_ARROW_DOWN; + } + else { + arrow_direction = GTK_ARROW_LEFT; + } + + if (gtk_theming_engine_has_class(engine, GTK_STYLE_CLASS_SCROLLBAR)) { + TQStringList objectTypes; + objectTypes.append(TQSCROLLBAR_OBJECT_NAME_STRING); + TQPalette objectPalette = tqApp->palette(objectTypes); + + TQStyleControlElementData ceData; + TQStyle::ControlElementFlags elementFlags; + ceData.widgetObjectTypes = objectTypes; + ceData.rect = boundingRect; + ceData.orientation = ((arrow_direction == GTK_ARROW_UP) || (arrow_direction == GTK_ARROW_DOWN))?TQt::Vertical:TQt::Horizontal; + + bool subline = ((arrow_direction == GTK_ARROW_DOWN) || (arrow_direction == GTK_ARROW_RIGHT))?false:true; + + // Draw slider arrow buttons + TQRect scrollpagerect = tqApp->style().querySubControlMetrics(TQStyle::CC_ScrollBar, ceData, elementFlags, (subline)?TQStyle::SC_ScrollBarSubLine:TQStyle::SC_ScrollBarAddLine, gtkToTQtStyleFlags(engine, state, TQT3WT_NONE)); + if (ceData.orientation == TQt::Vertical) { + scrollpagerect.setY(ceData.rect.y()); + scrollpagerect.setHeight(ceData.rect.height()); + } + else { + scrollpagerect.setX(ceData.rect.x()); + scrollpagerect.setWidth(ceData.rect.width()); + } + tqApp->style().drawPrimitive((subline)?TQStyle::PE_ScrollBarSubLine:TQStyle::PE_ScrollBarAddLine, &p, scrollpagerect, gtkToTQtColorGroup(engine, state), gtkToTQtStyleFlags(engine, state, TQT3WT_NONE) | ((ceData.orientation == TQt::Horizontal)?TQStyle::Style_Horizontal:TQStyle::Style_Default)); + } + + p.end(); + + return; + + GdkRGBA color; + gdouble size_reduction = 2; + + state = gtk_theming_engine_get_state (engine); + + gtk_theming_engine_get_color (engine, state, &color); + + cairo_save (cr); + + /* use floor function to adjust doubles */ + y = floor (y); + x = floor (x); + size = floor (size); + + size -= size_reduction; + + cairo_translate (cr, size_reduction / 2, size_reduction / 2); + cairo_translate (cr, x + (gint) (size / 2.0) + 0.5, y + (gint) (size / 2.0) + 0.5); + cairo_rotate (cr, angle - G_PI_2); + cairo_translate (cr, (gint) (size / 4.0), 0); + + /* FIXME this + 1/- 1 is done to fix blurred diagonal lines. + * I know it's not nice at all, but it fix a visual bug */ + cairo_move_to (cr, - (gint) (size / 2.0), - (gint) (size / 2.0)); + cairo_rel_line_to (cr, (gint) (size / 2.0) + 1, (gint) (size / 2.0)); + cairo_rel_line_to (cr, - (gint) (size / 2.0) - 1, (gint) (size / 2.0)); + cairo_close_path (cr); + + cairo_set_source_rgba (cr, color.red, color.green, color.blue, color.alpha * 0.75); + cairo_fill_preserve (cr); + + gdk_cairo_set_source_rgba (cr, &color); + cairo_stroke (cr); + + cairo_restore (cr); +} + +static void +tdegtk_draw_cell_background (DRAW_ARGS, + GtkRegionFlags flags) +{ + GtkJunctionSides junction; + guint hidden_side; + + junction = (GtkJunctionSides)(GTK_JUNCTION_RIGHT | GTK_JUNCTION_LEFT); + + hidden_side = SIDE_RIGHT | SIDE_LEFT; + + if ((flags & GTK_REGION_FIRST) != 0) + { + junction = (GtkJunctionSides)(junction & ~(GTK_JUNCTION_CORNER_TOPLEFT | GTK_JUNCTION_CORNER_BOTTOMLEFT)); + hidden_side &= ~(SIDE_LEFT); + } + if ((flags & GTK_REGION_LAST) != 0) + { + junction = (GtkJunctionSides)(junction & ~(GTK_JUNCTION_CORNER_TOPRIGHT | GTK_JUNCTION_CORNER_BOTTOMRIGHT)); + hidden_side &= ~(SIDE_RIGHT); + } + + tdegtk_cairo_draw_background (engine, cr, + x, y, width, height, + hidden_side, junction); +} + +static void +tdegtk_draw_cell_frame (DRAW_ARGS, + GtkRegionFlags flags) +{ + GtkJunctionSides junction; + guint hidden_side; + + junction = (GtkJunctionSides)(GTK_JUNCTION_RIGHT | GTK_JUNCTION_LEFT); + + hidden_side = SIDE_RIGHT | SIDE_LEFT; + + if ((flags & GTK_REGION_FIRST) != 0) + { + junction = (GtkJunctionSides)(junction & ~(GTK_JUNCTION_CORNER_TOPLEFT | GTK_JUNCTION_CORNER_BOTTOMLEFT)); + hidden_side &= ~(SIDE_LEFT); + } + if ((flags & GTK_REGION_LAST) != 0) + { + junction = (GtkJunctionSides)(junction & ~(GTK_JUNCTION_CORNER_TOPRIGHT | GTK_JUNCTION_CORNER_BOTTOMRIGHT)); + hidden_side &= ~(SIDE_RIGHT); + } + + tdegtk_cairo_draw_frame (engine, cr, + x, y, width, height, + hidden_side, junction); +} + +static void +tdegtk_draw_check (DRAW_ARGS) +{ + TQRect boundingRect(0, 0, width, height); + TQt3CairoPaintDevice pd(NULL, x, y, width, height, cr); + TQPainter p(&pd); + + DEBUG_FILL_BACKGROUND_WITH_COLOR(p,255,0,0); + + GtkStateFlags state; + state = gtk_theming_engine_get_state(engine); + const GtkWidgetPath* path(gtk_theming_engine_get_path(engine)); + + if (gtk_widget_path_is_type(path, GTK_TYPE_TREE_VIEW)) { + tqApp->style().drawPrimitive(TQStyle::PE_Indicator, &p, boundingRect, gtkToTQtColorGroup(engine, state), gtkToTQtStyleFlags(engine, state, TQT3WT_GTKTreeViewCell)); + } + else { + tqApp->style().drawPrimitive(TQStyle::PE_Indicator, &p, boundingRect, gtkToTQtColorGroup(engine, state), gtkToTQtStyleFlags(engine, state, TQT3WT_TQCheckBox)); + } + p.end(); +} + +static void +tdegtk_draw_common (DRAW_ARGS) +{ + TQRect boundingRect(0, 0, width, height); + TQt3CairoPaintDevice pd(NULL, x, y, width, height, cr); + TQPainter p(&pd); + + DEBUG_FILL_BACKGROUND_WITH_COLOR(p,0,255,255); + + GtkStateFlags state; + state = gtk_theming_engine_get_state(engine); + //tqApp->style().drawPrimitive(TQStyle::PE_Indicator, &p, boundingRect, gtkToTQtColorGroup(engine, state), gtkToTQtStyleFlags(engine, state, TQT3WT_NONE)); + + p.end(); +} + +static void +tdegtk_draw_common_background (DRAW_ARGS) +{ + TQRect boundingRect(0, 0, width, height); + TQt3CairoPaintDevice pd(NULL, x, y, width, height, cr); + TQPainter p(&pd); + + DEBUG_FILL_BACKGROUND_WITH_COLOR(p,0,0,255); + + GtkStateFlags state; + state = gtk_theming_engine_get_state(engine); + + if (gtk_theming_engine_has_class(engine, GTK_STYLE_CLASS_ENTRY)) { + TQStringList objectTypes; + objectTypes.append(TQLINEEDIT_OBJECT_NAME_STRING); + TQPalette objectPalette = tqApp->palette(objectTypes); + + // Draw background + TQBrush brush = objectPalette.brush(gtkToTQPaletteColorGroup(engine, state), TQColorGroup::Base); + DRAW_FILLED_RECTANGLE_OVER_ENTIRE_AREA(p, brush) + } + + if (gtk_theming_engine_has_class(engine, GTK_STYLE_CLASS_SCROLLBAR)) { + TQStringList objectTypes; + objectTypes.append(TQSCROLLBAR_OBJECT_NAME_STRING); + TQPalette objectPalette = tqApp->palette(objectTypes); + + TQStyleControlElementData ceData; + TQStyle::ControlElementFlags elementFlags; + ceData.widgetObjectTypes = objectTypes; + ceData.rect = boundingRect; + ceData.orientation = (gtk_theming_engine_has_class(engine, GTK_STYLE_CLASS_VERTICAL))?TQt::Vertical:TQt::Horizontal; + + // Draw frame + tqApp->style().drawPrimitive(TQStyle::PE_PanelLineEdit, &p, boundingRect, gtkToTQtColorGroup(engine, state), gtkToTQtStyleFlags(engine, state, TQT3WT_NONE)); + } + + if (gtk_theming_engine_has_class(engine, GTK_STYLE_CLASS_BUTTON)) { + TQStringList objectTypes; + objectTypes.append(TQBUTTON_OBJECT_NAME_STRING); + TQPalette objectPalette = tqApp->palette(objectTypes); + + // Draw background + TQBrush brush = objectPalette.brush(gtkToTQPaletteColorGroup(engine, state), TQColorGroup::Background); + DRAW_FILLED_RECTANGLE_OVER_ENTIRE_AREA(p, brush) + } + + if (gtk_theming_engine_has_class(engine, GTK_STYLE_CLASS_TOOLTIP)) { + TQStringList objectTypes; + objectTypes.append(TQTIPLABEL_OBJECT_NAME_STRING); + TQPalette objectPalette = tqApp->palette(objectTypes); + + // Draw background + TQBrush brush = objectPalette.brush(gtkToTQPaletteColorGroup(engine, state), TQColorGroup::Background); + DRAW_FILLED_RECTANGLE_OVER_ENTIRE_AREA(p, brush) + } + + if (gtk_theming_engine_has_class(engine, GTK_STYLE_CLASS_BACKGROUND)) { + TQStringList objectTypes; + objectTypes.append(TQWIDGET_OBJECT_NAME_STRING); + TQPalette objectPalette = tqApp->palette(objectTypes); + + // Draw background + TQBrush brush = objectPalette.brush(gtkToTQPaletteColorGroup(engine, state), TQColorGroup::Background); + DRAW_FILLED_RECTANGLE_OVER_ENTIRE_AREA(p, brush) + } + + p.end(); +} + +static void +tdegtk_draw_common_frame (DRAW_ARGS) +{ + TQRect boundingRect(0, 0, width, height); + TQt3CairoPaintDevice pd(NULL, x, y, width, height, cr); + TQPainter p(&pd); + + GtkStateFlags state; + state = gtk_theming_engine_get_state(engine); + + if (gtk_theming_engine_has_class(engine, GTK_STYLE_CLASS_SCROLLBAR)) { + if (gtk_theming_engine_has_class(engine, GTK_STYLE_CLASS_BUTTON)) { + // Scrollbar buttons are drawn in the arrow handler + } + else { + TQStringList objectTypes; + objectTypes.append(TQSCROLLBAR_OBJECT_NAME_STRING); + TQPalette objectPalette = tqApp->palette(objectTypes); + + TQStyleControlElementData ceData; + TQStyle::ControlElementFlags elementFlags; + ceData.widgetObjectTypes = objectTypes; + ceData.rect = boundingRect; + ceData.orientation = (gtk_theming_engine_has_class(engine, GTK_STYLE_CLASS_VERTICAL))?TQt::Vertical:TQt::Horizontal; + + // Draw background + // HACK + // PE_ScrollBarAddPage and PE_ScrollBarSubPage are separate in TQt3 + // Apparently there is no such distinction in GTK3! + TQRect scrollpagerect = tqApp->style().querySubControlMetrics(TQStyle::CC_ScrollBar, ceData, elementFlags, TQStyle::SC_ScrollBarAddPage, gtkToTQtStyleFlags(engine, state, TQT3WT_NONE)); + if (ceData.orientation == TQt::Vertical) { + scrollpagerect.setY(ceData.rect.y()); + scrollpagerect.setHeight(ceData.rect.height()); + } + else { + scrollpagerect.setX(ceData.rect.x()); + scrollpagerect.setWidth(ceData.rect.width()); + } + tqApp->style().drawPrimitive(TQStyle::PE_ScrollBarAddPage, &p, scrollpagerect, gtkToTQtColorGroup(engine, state), gtkToTQtStyleFlags(engine, state, TQT3WT_NONE)); + } + } + else { + if (gtk_theming_engine_has_class(engine, GTK_STYLE_CLASS_BUTTON)) { + // Draw frame + tqApp->style().drawPrimitive(TQStyle::PE_ButtonBevel, &p, boundingRect, gtkToTQtColorGroup(engine, state), gtkToTQtStyleFlags(engine, state, TQT3WT_TQPushButton)); + } + + if (gtk_theming_engine_has_class(engine, GTK_STYLE_CLASS_ENTRY)) { + TQStringList objectTypes; + objectTypes.append(TQLINEEDIT_OBJECT_NAME_STRING); + TQPalette objectPalette = tqApp->palette(objectTypes); + + // Draw frame + tqApp->style().drawPrimitive(TQStyle::PE_PanelLineEdit, &p, boundingRect, gtkToTQtColorGroup(engine, state), gtkToTQtStyleFlags(engine, state, TQT3WT_NONE)); + } + } + + p.end(); +} + +static void +tdegtk_draw_expander (DRAW_ARGS) +{ + GtkStateFlags state; + GdkRGBA color; + gint size; + gdouble angle = G_PI_2; + + state = gtk_theming_engine_get_state (engine); + + gtk_theming_engine_get_color (engine, state, &color); + + cairo_save (cr); + + /* use floor function to adjust doubles */ + size = floor (MIN (width, height)); + + x += (gint) (width / 2) - size / 2; + y += (gint) (height / 2) - size / 2; + + if ((state & GTK_STATE_FLAG_ACTIVE) == 0) + angle = 0; + + cairo_translate (cr, x + size / 2.0 + 0.5, y + size / 2.0 + 0.5); + cairo_rotate (cr, angle); + cairo_translate (cr, size / 4.0, 0); + + /* FIXME this + 1/- 1 is done to fix blurred diagonal lines. + * I know it's not nice at all, but it fix a visual bug */ + cairo_move_to (cr, - size / 2.0, - size / 2.0); + cairo_rel_line_to (cr, size / 2.0 + 1, size / 2.0); + cairo_rel_line_to (cr, - size / 2.0 - 1, size / 2.0); + cairo_close_path (cr); + + cairo_set_source_rgba (cr, color.red, color.green, color.blue, color.alpha * 0.75); + cairo_fill_preserve (cr); + + gdk_cairo_set_source_rgba (cr, &color); + cairo_stroke (cr); + + cairo_restore (cr); +} + +static void +tdegtk_draw_extension (DRAW_ARGS, + GtkPositionType gap_side) +{ + TQRect boundingRect(0, 0, width, height); + TQt3CairoPaintDevice pd(NULL, x, y, width, height, cr); + TQPainter p(&pd); + + DEBUG_FILL_BACKGROUND_WITH_COLOR(p,255,255,0); + + const GtkWidgetPath* path; + GtkStateFlags state; + GtkWidget* widget; + + path = gtk_theming_engine_get_path(engine); + state = gtk_theming_engine_get_state(engine); + widget = m_widgetLookup.find(cr, path); + + if (gtk_theming_engine_has_class(engine, GTK_STYLE_CLASS_NOTEBOOK)) { + // Check tab properties + const int tabIndex = Gtk::gtk_notebook_find_tab(widget, x+width/2, y+height/2); +// Style::instance().animations().tabWidgetEngine().updateTabRect(widget, tabIndex, x, y, width, height); +// bool prelight = (tabIndex == Style::instance().animations().tabWidgetEngine().hoveredTab(widget)); + bool prelight = false; + GtkNotebook* notebook = GTK_NOTEBOOK(widget); +// bool firstTab = (tabIndex == 0); +// bool lastTab = (tabIndex == gtk_notebook_get_n_pages(notebook)-1); + const int currentPage = gtk_notebook_get_current_page(notebook); + const int numPages = gtk_notebook_get_n_pages(notebook); + + TQStringList objectTypes; + objectTypes.append(TQTABBAR_OBJECT_NAME_STRING); + TQPalette objectPalette = tqApp->palette(objectTypes); + + TQStyleControlElementData ceData; + TQStyle::ControlElementFlags elementFlags; + ceData.widgetObjectTypes = objectTypes; + ceData.rect = boundingRect; + + TQTab tqt3Tab; + tqt3Tab.setIdentifier(tabIndex); + TQStyleOption tabOpt(&tqt3Tab, (prelight)?&tqt3Tab:(TQTab*)NULL); + + elementFlags = elementFlags | TQStyle::CEF_HasParentWidget; + ceData.parentWidgetData.widgetObjectTypes.append(TQTABBAR_OBJECT_NAME_STRING); + + int tab_overlap = tqApp->style().pixelMetric(TQStyle::PM_TabBarTabOverlap); + + boundingRect = TQRect(0, 0, width+(tab_overlap*2)-tab_overlap, height); + TQt3CairoPaintDevice pd2(NULL, x-tab_overlap, y, width+(tab_overlap*2), height, cr); + TQPainter p2(&pd2); + + switch (gap_side) { + default: + case GTK_POS_TOP: + ceData.tabBarData.shape = TQTabBar::RoundedBelow; + break; + case GTK_POS_LEFT: + // FIXME + // TQt3 does not know how to draw these + ceData.tabBarData.shape = TQTabBar::RoundedAbove; + break; + case GTK_POS_BOTTOM: + ceData.tabBarData.shape = TQTabBar::RoundedAbove; + break; + case GTK_POS_RIGHT: + // FIXME + // TQt3 does not know how to draw these + ceData.tabBarData.shape = TQTabBar::RoundedAbove; + break; + } + ceData.tabBarData.tabCount = numPages; + ceData.tabBarData.identIndexMap[tqt3Tab.identifier()] = tabIndex; + + cairo_save(cr); + cairo_reset_clip(cr); + + // Draw background + TQBrush brush = objectPalette.brush(gtkToTQPaletteColorGroup(engine, state), TQColorGroup::Background); + DRAW_FILLED_RECTANGLE_OVER_SPECIFIC_AREA(p2, brush, 0, 0, width, height) + + // Draw tab + tqApp->style().drawControl(TQStyle::CE_TabBarTab, &p2, ceData, elementFlags, boundingRect, gtkToTQtColorGroup(engine, state), gtkToTQtStyleFlags(engine, state, TQT3WT_NONE) | ((tabIndex==currentPage)?TQStyle::Style_Selected:TQStyle::Style_Default), tabOpt); + + cairo_restore(cr); + } + + p.end(); +} + +static void +tdegtk_draw_focus (DRAW_ARGS) +{ + GtkStateFlags state; + + state = gtk_theming_engine_get_state (engine); + + return; +} + +static void +tdegtk_draw_frame_gap (DRAW_ARGS, + GtkPositionType gap_side, + gdouble xy0_gap, + gdouble xy1_gap) +{ + TQRect boundingRect(0, 0, width, height); + TQt3CairoPaintDevice pd(NULL, x, y, width, height, cr); + TQPainter p(&pd); + + DEBUG_FILL_BACKGROUND_WITH_COLOR(p,255,128,0); + + p.end(); + + return; + + GtkBorder border; + GtkBorder *outer_border; + GtkCssBorderCornerRadius *top_left_radius, *top_right_radius; + GtkCssBorderCornerRadius *bottom_left_radius, *bottom_right_radius; + GtkCssBorderRadius border_radius = { { 0, }, }; + GtkJunctionSides junction; + GtkStateFlags state; + gboolean has_outer_stroke = FALSE; + gdouble x0, y0, x1, y1, xc, yc, wc, hc; + + xc = yc = wc = hc = 0; + + junction = gtk_theming_engine_get_junction_sides (engine); + + state = gtk_theming_engine_get_state (engine); + + gtk_theming_engine_get (engine, state, + /* Can't use border-radius as it's an int for + * backwards compat */ + "border-top-left-radius", &top_left_radius, + "border-top-right-radius", &top_right_radius, + "border-bottom-right-radius", &bottom_right_radius, + "border-bottom-left-radius", &bottom_left_radius, + "-tdegtk-outer-stroke-width", &outer_border, + NULL); + gtk_theming_engine_get_border (engine, state, &border); + + if (!tdegtk_gtk_border_is_zero (outer_border)) + has_outer_stroke = TRUE; + + if (top_left_radius) + border_radius.top_left = *top_left_radius; + g_free (top_left_radius); + if (top_right_radius) + border_radius.top_right = *top_right_radius; + g_free (top_right_radius); + if (bottom_right_radius) + border_radius.bottom_right = *bottom_right_radius; + g_free (bottom_right_radius); + if (bottom_left_radius) + border_radius.bottom_left = *bottom_left_radius; + g_free (bottom_left_radius); + + cairo_save (cr); + + switch (gap_side) + { + case GTK_POS_TOP: + xc = x + xy0_gap + border.left; + yc = y; + wc = MAX (xy1_gap - xy0_gap - (border.left + border.right), 0); + hc = border.top * 2; + + if (has_outer_stroke) + { + xc += outer_border->left; + wc = MAX (xy1_gap - xy0_gap - (outer_border->left + outer_border->right) - (border.left + border.right), 0); + hc += outer_border->top; + } + + if (xy0_gap < border_radius.top_left.horizontal) + junction = (GtkJunctionSides)(junction | GTK_JUNCTION_CORNER_TOPLEFT); + + if (xy1_gap > width - border_radius.top_right.horizontal) + junction = (GtkJunctionSides)(junction | GTK_JUNCTION_CORNER_TOPRIGHT); + break; + default: + case GTK_POS_BOTTOM: + xc = x + xy0_gap + border.left; + yc = y + height - border.bottom * 2; + wc = MAX (xy1_gap - xy0_gap - (border.left + border.right), 0); + hc = border.bottom * 2; + + if (has_outer_stroke) + { + xc += outer_border->left; + yc -= outer_border->bottom; + wc = MAX (xy1_gap - xy0_gap - (outer_border->left + outer_border->right) - (border.left + border.right), 0); + hc += outer_border->bottom; + } + + if (xy0_gap < border_radius.bottom_left.horizontal) + junction = (GtkJunctionSides)(junction | GTK_JUNCTION_CORNER_BOTTOMLEFT); + + if (xy1_gap > width - border_radius.bottom_right.horizontal) + junction = (GtkJunctionSides)(junction | GTK_JUNCTION_CORNER_BOTTOMRIGHT); + + break; + case GTK_POS_LEFT: + xc = x; + yc = y + xy0_gap + border.top; + wc = border.left * 2; + hc = MAX (xy1_gap - xy0_gap - (border.top + border.bottom), 0); + + if (has_outer_stroke) + { + yc += outer_border->top; + wc += outer_border->left; + hc = MAX (xy1_gap - xy0_gap - (outer_border->top + outer_border->bottom) - (border.top + border.bottom), 0); + } + + if (xy0_gap < border_radius.top_left.vertical) + junction = (GtkJunctionSides)(junction | GTK_JUNCTION_CORNER_TOPLEFT); + + if (xy1_gap > height - border_radius.bottom_left.vertical) + junction = (GtkJunctionSides)(junction | GTK_JUNCTION_CORNER_BOTTOMLEFT); + + break; + case GTK_POS_RIGHT: + xc = x + width - border.right * 2; + yc = y + xy0_gap + border.top; + wc = border.right * 2; + hc = MAX (xy1_gap - xy0_gap - (border.top + border.bottom), 0); + + if (has_outer_stroke) + { + xc -= outer_border->right; + yc += outer_border->top; + wc += outer_border->right; + hc = MAX (xy1_gap - xy0_gap - (outer_border->top + outer_border->bottom) - (border.top + border.bottom), 0); + } + + if (xy0_gap < border_radius.top_right.vertical) + junction = (GtkJunctionSides)(junction | GTK_JUNCTION_CORNER_TOPRIGHT); + + if (xy1_gap > height - border_radius.bottom_right.vertical) + junction = (GtkJunctionSides)(junction | GTK_JUNCTION_CORNER_BOTTOMRIGHT); + + break; + } + + /* clip the gap */ + cairo_clip_extents (cr, &x0, &y0, &x1, &y1); + cairo_rectangle (cr, x0, y0, x1 - x0, yc - y0); + cairo_rectangle (cr, x0, yc, xc - x0, hc); + cairo_rectangle (cr, xc + wc, yc, x1 - (xc + wc), hc); + cairo_rectangle (cr, x0, yc + hc, x1 - x0, y1 - (yc + hc)); + cairo_clip (cr); + + /* draw the frame, gap area will not be drawn */ + tdegtk_cairo_draw_frame (engine, cr, x, y, width, height, 0, junction); + + cairo_restore (cr); + + gtk_border_free (outer_border); +} + +static void +tdegtk_draw_grip (DRAW_ARGS) +{ + GdkRGBA border_color; + GdkRGBA *inner_stroke_color; + GtkStateFlags state; + gint lx, ly; + + state = gtk_theming_engine_get_state (engine); + + gtk_theming_engine_get (engine, state, + "-tdegtk-inner-stroke-color", &inner_stroke_color, + NULL); + gtk_theming_engine_get_border_color (engine, state, &border_color); + + for (ly = 0; ly < 4; ly++) + { + /* vertically, four rows of dots */ + for (lx = 0; lx <= ly; lx++) + { + /* horizontally */ + int ny = (3.5 - ly) * 3; + int nx = lx * 3; + + gdk_cairo_set_source_rgba (cr, inner_stroke_color); + cairo_rectangle (cr, x + width - nx - 1, y + height - ny - 1, 2, 2); + cairo_fill (cr); + + gdk_cairo_set_source_rgba (cr, &border_color); + cairo_rectangle (cr, x + width - nx - 1, y + height - ny - 1, 1, 1); + cairo_fill (cr); + } + } + + gdk_rgba_free (inner_stroke_color); +} + +static void +tdegtk_draw_handle (DRAW_ARGS) +{ + TQRect boundingRect(0, 0, width, height); + TQt3CairoPaintDevice pd(NULL, x, y, width, height, cr); + TQPainter p(&pd); + + DEBUG_FILL_BACKGROUND_WITH_COLOR(p,0,128,255); + + p.end(); + + return; + + gdouble line_width; + gint i, bar_y, num_bars, bar_spacing, bar_width, bar_height; + + tdegtk_cairo_draw_background (engine, cr, + x, y, width, height, + 0, gtk_theming_engine_get_junction_sides (engine)); + + if (draw_centroid_texture (engine, cr, x, y, width, height)) + return; + + tdegtk_get_line_width (engine, &line_width); + + bar_y = 1; + num_bars = 3; + bar_spacing = 3; + bar_width = 3; + bar_height = num_bars * bar_spacing * line_width; + + cairo_save (cr); + + cairo_translate (cr, x + (gint) (width / 2), y + (gint) (height / 2)); + + if (height > width) + cairo_translate (cr, - bar_width / 2 - 0.5, - bar_height / 2 + 0.5); + else + { + cairo_translate (cr, - bar_height / 2 + 0.5, bar_width / 2 + 0.5); + cairo_rotate (cr, - G_PI / 2); + } + + for (i = 0; i < num_bars; i++) + { + /* draw bars */ + cairo_move_to (cr, 0, bar_y); + cairo_line_to (cr, bar_width, bar_y); + tdegtk_cairo_set_source_border (engine, cr, bar_width, 3); + cairo_stroke (cr); + + cairo_move_to (cr, 0, bar_y + line_width); + cairo_line_to (cr, bar_width, bar_y + line_width); + tdegtk_cairo_set_source_inner_stroke (engine, cr, bar_width, line_width); + cairo_stroke (cr); + + bar_y += bar_spacing; + } + + cairo_restore (cr); +} + +static void +tdegtk_draw_line (GtkThemingEngine *engine, + cairo_t *cr, + gdouble x0, + gdouble y0, + gdouble x1, + gdouble y1) +{ + /* line endings */ + if (y0 == y1) + { + y0 += 0.5; + y1 += 0.5; + x0 += 0.5; + x1 -= 0.5; + } + else if (x0 == x1) + { + x0 += 0.5; + x1 += 0.5; + y0 += 0.5; + y1 -= 0.5; + } + + cairo_move_to (cr, x0, y0); + cairo_line_to (cr, x1, y1); + tdegtk_cairo_set_source_border (engine, cr, MAX (x1 - x0, 1), MAX (y1 - y0, 1)); + cairo_stroke (cr); +} + +static void +tdegtk_draw_notebook (DRAW_ARGS, + GtkPositionType gap_side, + gdouble xy0_gap, + gdouble xy1_gap) +{ + TQRect boundingRect(0, 0, width, height); + TQt3CairoPaintDevice pd(NULL, x, y, width, height, cr); + TQPainter p(&pd); + + DEBUG_FILL_BACKGROUND_WITH_COLOR(p,0,255,0); + + GtkStateFlags state; + state = gtk_theming_engine_get_state(engine); + //tqApp->style().drawPrimitive(TQStyle::PE_ExclusiveIndicator, &p, boundingRect, gtkToTQtColorGroup(engine, state), gtkToTQtStyleFlags(engine, state, TQT3WT_NONE)); + + p.end(); +} + +static void +tdegtk_draw_radio (DRAW_ARGS) +{ + TQRect boundingRect(0, 0, width, height); + TQt3CairoPaintDevice pd(NULL, x, y, width, height, cr); + TQPainter p(&pd); + + DEBUG_FILL_BACKGROUND_WITH_COLOR(p,255,0,0); + + GtkStateFlags state; + state = gtk_theming_engine_get_state(engine); + const GtkWidgetPath* path(gtk_theming_engine_get_path(engine)); + + if (gtk_widget_path_is_type(path, GTK_TYPE_TREE_VIEW)) { + tqApp->style().drawPrimitive(TQStyle::PE_ExclusiveIndicator, &p, boundingRect, gtkToTQtColorGroup(engine, state), gtkToTQtStyleFlags(engine, state, TQT3WT_GTKTreeViewCell)); + } + else { + tqApp->style().drawPrimitive(TQStyle::PE_ExclusiveIndicator, &p, boundingRect, gtkToTQtColorGroup(engine, state), gtkToTQtStyleFlags(engine, state, TQT3WT_TQRadioButton)); + } + + p.end(); +} + +static void +tdegtk_draw_separator (DRAW_ARGS) +{ + gdouble line_width; + + tdegtk_get_line_width (engine, &line_width); + + if (line_width == 0) + return; + + /* FIXME right code should be + * if (gtk_theming_engine_has_class (engine, GTK_STYLE_CLASS_VERTICAL)) + * but doesn't work for separator tool item. */ + if (width > height) + { + cairo_move_to (cr, x, y + (gint) (height / 2) + line_width / 2); + cairo_line_to (cr, x + width, y + (gint) (height / 2) + line_width / 2); + tdegtk_cairo_set_source_inner_stroke (engine, cr, width, line_width); + cairo_stroke (cr); + + cairo_move_to (cr, x, y + (gint) (height / 2) - line_width / 2); + cairo_line_to (cr, x + width, y + (gint) (height / 2) - line_width / 2); + tdegtk_cairo_set_source_border (engine, cr, width, line_width); + cairo_stroke (cr); + } + else + { + cairo_move_to (cr, x + (gint) (width / 2) + line_width / 2, y); + cairo_line_to (cr, x + (gint) (width / 2) + line_width / 2, y + height); + tdegtk_cairo_set_source_inner_stroke (engine, cr, line_width, height); + cairo_stroke (cr); + + cairo_move_to (cr, x + (gint) (width / 2) - line_width / 2, y); + cairo_line_to (cr, x + (gint) (width / 2) - line_width / 2, y + height); + tdegtk_cairo_set_source_border (engine, cr, line_width, height); + cairo_stroke (cr); + } +} + +static void +tdegtk_draw_slider (DRAW_ARGS, + GtkOrientation orientation) +{ + TQRect boundingRect(0, 0, width, height); + TQt3CairoPaintDevice pd(NULL, x, y, width, height, cr); + TQPainter p(&pd); + + DEBUG_FILL_BACKGROUND_WITH_COLOR(p,255,0,255); + + GtkStateFlags state; + state = gtk_theming_engine_get_state(engine); + + if (gtk_theming_engine_has_class(engine, GTK_STYLE_CLASS_SCROLLBAR)) { + TQStringList objectTypes; + objectTypes.append(TQSCROLLBAR_OBJECT_NAME_STRING); + TQPalette objectPalette = tqApp->palette(objectTypes); + + TQStyleControlElementData ceData; + TQStyle::ControlElementFlags elementFlags; + ceData.widgetObjectTypes = objectTypes; + ceData.rect = boundingRect; + ceData.orientation = (gtk_theming_engine_has_class(engine, GTK_STYLE_CLASS_VERTICAL))?TQt::Vertical:TQt::Horizontal; + + // Draw slider + TQRect scrollpagerect = tqApp->style().querySubControlMetrics(TQStyle::CC_ScrollBar, ceData, elementFlags, TQStyle::SC_ScrollBarSlider, gtkToTQtStyleFlags(engine, state, TQT3WT_NONE)); + if (ceData.orientation == TQt::Vertical) { + scrollpagerect.setY(ceData.rect.y()); + scrollpagerect.setHeight(ceData.rect.height()); + } + else { + scrollpagerect.setX(ceData.rect.x()); + scrollpagerect.setWidth(ceData.rect.width()); + } + tqApp->style().drawPrimitive(TQStyle::PE_ScrollBarSlider, &p, scrollpagerect, gtkToTQtColorGroup(engine, state), gtkToTQtStyleFlags(engine, state, TQT3WT_NONE)); + } + + p.end(); +} + +static void +tdegtk_draw_spinbutton_background (DRAW_ARGS) +{ + GtkBorder border, *outer_border; + GtkJunctionSides junction; + GtkStateFlags state; + + junction = gtk_theming_engine_get_junction_sides (engine); + + state = gtk_theming_engine_get_state (engine); + + gtk_theming_engine_get (engine, state, + "-tdegtk-outer-stroke-width", &outer_border, + NULL); + gtk_theming_engine_get_border (engine, state, &border); + + cairo_save (cr); + + cairo_rectangle (cr, x, y, width, height); + cairo_clip (cr); + + if (!(junction & GTK_JUNCTION_CORNER_TOPRIGHT)) + { + y = ceil (y); + height = floor (height); + height += border.bottom + outer_border->bottom; + } + else + { + y = floor (y); + height = ceil (height); + y -= outer_border->top; + height += outer_border->bottom; + } + + tdegtk_cairo_draw_background (engine, cr, + x, y, width, height, + 0, junction); + + cairo_restore (cr); + + gtk_border_free (outer_border); +} + +static void +tdegtk_draw_spinbutton_frame (DRAW_ARGS) +{ + GtkBorder border, *outer_border; + GtkJunctionSides junction; + GtkStateFlags state; + + junction = gtk_theming_engine_get_junction_sides (engine); + + state = gtk_theming_engine_get_state (engine); + + gtk_theming_engine_get (engine, state, + "-tdegtk-outer-stroke-width", &outer_border, + NULL); + gtk_theming_engine_get_border (engine, state, &border); + + cairo_save (cr); + + cairo_rectangle (cr, x, y, width, height); + cairo_clip (cr); + + if (!(junction & GTK_JUNCTION_CORNER_TOPRIGHT)) + { + y = ceil (y); + height = floor (height); + height += border.bottom + outer_border->bottom; + } + else + { + y = floor (y); + height = ceil (height); + y -= outer_border->top; + height += outer_border->bottom; + } + + tdegtk_cairo_draw_frame (engine, cr, + x, y, width, height, + 0, junction); + + cairo_restore (cr); + + gtk_border_free (outer_border); +} + +void +tdegtk_register_style_default (TdeGtkStyleFunctions *functions) +{ + g_assert (functions); + + functions->draw_activity = tdegtk_draw_activity; + functions->draw_arrow = tdegtk_draw_arrow; + functions->draw_cell_background = tdegtk_draw_cell_background; + functions->draw_cell_frame = tdegtk_draw_cell_frame; + functions->draw_check = tdegtk_draw_check; + functions->draw_common = tdegtk_draw_common; + functions->draw_common_background = tdegtk_draw_common_background; + functions->draw_common_frame = tdegtk_draw_common_frame; + functions->draw_expander = tdegtk_draw_expander; + functions->draw_extension = tdegtk_draw_extension; + functions->draw_focus = tdegtk_draw_focus; + functions->draw_frame_gap = tdegtk_draw_frame_gap; + functions->draw_grip = tdegtk_draw_grip; + functions->draw_handle = tdegtk_draw_handle; + functions->draw_line = tdegtk_draw_line; + functions->draw_notebook = tdegtk_draw_notebook; + functions->draw_radio = tdegtk_draw_radio; + functions->draw_separator = tdegtk_draw_separator; + functions->draw_slider = tdegtk_draw_slider; + functions->draw_spinbutton_background = tdegtk_draw_spinbutton_background; + functions->draw_spinbutton_frame = tdegtk_draw_spinbutton_frame; +} diff --git a/tdegtk/tdegtk-hooks.cpp b/tdegtk/tdegtk-hooks.cpp new file mode 100644 index 0000000..dbb291f --- /dev/null +++ b/tdegtk/tdegtk-hooks.cpp @@ -0,0 +1,100 @@ +/* +* this file was largely taken from the oxygen gtk engine +* Copyright (c) 2010 Hugo Pereira Da Costa <hugo@oxygen-icons.org> +* Copyright (c) 2010 Ruslan Kabatsayev <b7.10110111@gmail.com> +* +* 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., 51 Franklin St, Fifth Floor, Boston, +* MA 02110-1301, USA. +*/ + +#include "tdegtk-hooks.h" +#include "../config.h" + +#include <cassert> +#include <iostream> + + #if TDEGTK_DEBUG + static int counter( 0 ); + #endif + + //__________________________________________________________________ + bool Hook::connect( const std::string& signal, GType typeId, GSignalEmissionHook hookFunction, gpointer data ) + { + // make sure that signal is not already connected + assert( _signalId == 0 && _hookId == 0 ); + + // check type id + if( !g_type_class_peek( typeId ) ) + { + + #if TDEGTK_DEBUG + std::cerr << "Oxygen::Hook::connect - typeId " << g_type_name(typeId) << " not yet installed" << std::endl; + #endif + + g_type_class_ref( typeId ); + + } + + // store signal id + _signalId = g_signal_lookup( signal.c_str(), typeId ); + if( !_signalId ) + { + + #if TDEGTK_DEBUG + std::cerr << "Oxygen::Hook::connect - signal " << signal << " not installed." << std::endl; + #endif + + return false; + + } + + // store attributes and create connection + _hookId = g_signal_add_emission_hook( + _signalId, + (GQuark)0L, + hookFunction, + data, 0L); + + #if TDEGTK_DEBUG + ++counter; + std::cerr << "Oxygen::Hook::connect - hook: " << _hookId << " counter: " << counter << std::endl; + #endif + + return true; + + } + + //____________________________________________________________________ + void Hook::disconnect( void ) + { + + // disconnect signal + if( _signalId > 0 && _hookId > 0 ) + { + + #if TDEGTK_DEBUG + --counter; + std::cerr << "Oxygen::Hook::disconnect - hook: " << _hookId << " counter: " << counter << std::endl; + #endif + + g_signal_remove_emission_hook( _signalId, _hookId ); + + } + + _signalId = 0; + _hookId = 0; + + } + diff --git a/tdegtk/tdegtk-hooks.h b/tdegtk/tdegtk-hooks.h new file mode 100644 index 0000000..a12244d --- /dev/null +++ b/tdegtk/tdegtk-hooks.h @@ -0,0 +1,63 @@ +#ifndef tdegtk_hooks_h +#define tdegtk_hooks_h +/* +* this file was largely taken from the oxygen gtk engine +* Copyright (c) 2010 Hugo Pereira Da Costa <hugo@oxygen-icons.org> +* Copyright (c) 2010 Ruslan Kabatsayev <b7.10110111@gmail.com> +* +* 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., 51 Franklin St, Fifth Floor, Boston, +* MA 02110-1301, USA. +*/ + +#include <gtk/gtk.h> +#include <string> + + + //! handles gtk signal hooks + class Hook + { + public: + + //! constructor + Hook( void ): + _signalId(0), + _hookId(0) + {} + + //! destructor + virtual ~Hook( void ) + {} + + + + //! connect + bool connect( const std::string&, GType, GSignalEmissionHook, gpointer ); + + bool connect( const std::string& signal, GSignalEmissionHook hook, gpointer data ) + { return connect( signal, GTK_TYPE_WIDGET, hook, data ); } + + //! disconnect + void disconnect( void ); + + private: + + //! signal id + guint _signalId; + gulong _hookId; + + }; + +#endif + diff --git a/tdegtk/tdegtk-signals.cpp b/tdegtk/tdegtk-signals.cpp new file mode 100644 index 0000000..131de88 --- /dev/null +++ b/tdegtk/tdegtk-signals.cpp @@ -0,0 +1,89 @@ + +/* +* this file was largely taken from the oxygen gtk engine +* Copyright (c) 2010 Hugo Pereira Da Costa <hugo@oxygen-icons.org> +* +* 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., 51 Franklin St, Fifth Floor, Boston, +* MA 02110-1301, USA. +*/ + +#include "tdegtk-signals.h" +#include "../config.h" + +#include <iostream> + + + #if OXYGEN_DEBUG + static int counter( 0 ); + #endif + + //____________________________________________________________________ + bool Signal::connect( GObject* object, const std::string& signal, GCallback callback, gpointer data, bool after ) + { + // make sure that signal is not already connected + assert( _object == 0L && _id == 0 ); + + // check object + if( !object ) return false; + + // first try lookup signal + if( !g_signal_lookup( signal.c_str(), G_OBJECT_TYPE(object) ) ) + { + + #if OXYGEN_DEBUG + std::cerr << "Oxygen::Signal::connect - signal " << signal << " not installed on widget " << object << std::endl; + #endif + + return false; + + } + + // store attributes and create connection + _object = object; + if(after) _id = g_signal_connect_after( object, signal.c_str(), callback, data ); + else _id = g_signal_connect( object, signal.c_str(), callback, data ); + + #if OXYGEN_DEBUG + ++counter; + std::cerr << "Oxygen::Signal::connect - _id: " << _id << " counter: " << counter << std::endl; + #endif + + return true; + + } + + //____________________________________________________________________ + void Signal::disconnect( void ) + { + + // disconnect signal + if( _object && _id > 0 ) + { + + #if OXYGEN_DEBUG + --counter; + std::cerr << "Oxygen::Signal::disconnect - _id: " << _id << " counter: " << counter << std::endl; + #endif + + g_signal_handler_disconnect( _object, _id ); + + } + + // reset members + _object = 0L; + _id = 0; + + } + diff --git a/tdegtk/tdegtk-signals.h b/tdegtk/tdegtk-signals.h new file mode 100644 index 0000000..1d0310c --- /dev/null +++ b/tdegtk/tdegtk-signals.h @@ -0,0 +1,64 @@ +#ifndef tdegtk_signal_h +#define tdegtk_signal_h + +/* +* this file was largely taken from the oxygen gtk engine +* Copyright (c) 2010 Hugo Pereira Da Costa <hugo@oxygen-icons.org> +* +* 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., 51 Franklin St, Fifth Floor, Boston, +* MA 02110-1301, USA. +*/ + +#include <gtk/gtk.h> +#include <cassert> +#include <string> + + //! handles gtk signal connections + class Signal + { + public: + + //! constructor + Signal( void ): + _id(0), + _object(0L) + {} + + //! destructor + virtual ~Signal( void ) + {} + + //! true if connected + bool isConnected( void ) const + { return _id > 0 && _object; } + + //! connect + bool connect( GObject*, const std::string&, GCallback, gpointer, bool after=false ); + + //! disconnect + void disconnect( void ); + + private: + + //! signal id + guint _id; + + //! connected object + GObject* _object; + + }; + +#endif + diff --git a/tdegtk/tdegtk-theme.c b/tdegtk/tdegtk-theme.c deleted file mode 100644 index 564a0fd..0000000 --- a/tdegtk/tdegtk-theme.c +++ /dev/null @@ -1,51 +0,0 @@ -/* The TdeGtk Theming Engine for Gtk+. - * Copyright (C) 2011 Canonical Ltd - * - * 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., 51 Franklin St, Fifth Floor, Boston, - * MA 02110-1301, USA. - * - * Authored by Andrea Cimitan <andrea.cimitan@canonical.com> - * - */ - -#include <gmodule.h> -#include <gtk/gtk.h> - -#include "tdegtk-engine.h" - -G_MODULE_EXPORT void theme_init (GTypeModule *module); - -G_MODULE_EXPORT void theme_exit (void); - -G_MODULE_EXPORT GtkThemingEngine* create_engine (void); - -G_MODULE_EXPORT void -theme_init (GTypeModule *module) -{ - tdegtk_engine_register_types (module); -} - -G_MODULE_EXPORT void -theme_exit (void) -{ -} - -G_MODULE_EXPORT GtkThemingEngine* -create_engine (void) -{ - return GTK_THEMING_ENGINE (g_object_new (TDEGTK_TYPE_ENGINE, - "name", "tdegtk", - NULL)); -} diff --git a/tdegtk/tdegtk-theme.cpp b/tdegtk/tdegtk-theme.cpp new file mode 100644 index 0000000..28ff8e9 --- /dev/null +++ b/tdegtk/tdegtk-theme.cpp @@ -0,0 +1,788 @@ +/* The TdeGtk Theming Engine for Gtk+. + * Copyright (C) 2012 Timothy Pearson <kb9vqf@pearsoncomputing.net> + * + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#define TDEGTK_THEME_THEME_DIRECTORY_NAME "tdegtk" +#define TDEGTK_THEME_CONTROL_FILE_NAME "gtk.css" +#define RC_CACHE_VERSION TQString("1") +#define DEBUG_PRINT(x) if (gtk3TQtDebug) printf(x"\n\r"); +#define DEBUG_PRINT_ARGS(x,y) if (gtk3TQtDebug) printf(x"\n\r",y); + +bool gtk3TQtEnable = false; +int gtk3TQtDebug = false; +bool tde_showIconsOnPushButtons = false; + +void initTDESettings(); +void writeGtkThemeControlFile(int forceRecreate); + +extern "C" { + #include <gmodule.h> + #include <gtk/gtk.h> + + #include "tdegtk-engine.h" + + G_MODULE_EXPORT void theme_init(GTypeModule *module); + + G_MODULE_EXPORT void theme_exit(void); + + G_MODULE_EXPORT GtkThemingEngine* create_engine(void); + + G_MODULE_EXPORT void theme_init(GTypeModule *module) { + tdegtk_engine_register_types(module); + } + + G_MODULE_EXPORT void theme_exit(void) { + // + } +} + +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <utility> +#include <vector> +#include <fstream> +#include <sstream> + +#include <tqpainter.h> +#include <tqapplication.h> +#include <tqdir.h> +#include <tqfile.h> +#include <tqstyle.h> +#include <tqslider.h> +#include <tqscrollbar.h> +#include <tqregexp.h> +#include <tqfont.h> + +#include <kapplication.h> +#include <kcmdlineargs.h> +#include <kaboutdata.h> +#include <klocale.h> +#include <kconfig.h> +#include <kglobal.h> +#include <kglobalsettings.h> + +#include <gdk/gdkx.h> + +#include "tdegtk-widgetlookup.h" + +extern WidgetLookup m_widgetLookup; + +typedef std::pair<std::string, unsigned int> SizePair; +typedef std::vector<SizePair> SizeMap; +SizeMap icon_sizes; + +G_MODULE_EXPORT GtkThemingEngine* create_engine(void) { + gtk3TQtEnable = true; + + gtk3TQtDebug = (getenv("GTK3_TQT_ENGINE_DEBUG") != NULL) ? 1 : 0; + DEBUG_PRINT("Creating KApplication") + + int argc = 1; + char** argv; + // Supply it with fake data to keep KApplication happy + argv = (char**) malloc(sizeof(char*)); + argv[0] = (char*) malloc(sizeof(char) * 21); + strncpy(argv[0], "gtk3-tqt-application", 21); + + KAboutData aboutData("gtk3-tqt-engine", I18N_NOOP("gtk3-tqt-engine"), "v0.1", + "GTK3 TQt theme engine", KAboutData::License_GPL, + "(c) 2012, Timothy Pearson", + "", 0 /* TODO: Website */, "kb9vqf@pearsoncomputing.net"); + KCmdLineArgs::init(argc, const_cast<char**>(argv), &aboutData); + + KApplication::disableAutoDcopRegistration(); + new KApplication(gdk_x11_get_default_xdisplay(), true, 0, 0, true); + + initTDESettings(); + + // initialize icon sizes + icon_sizes.push_back(std::make_pair("panel-menu", 16)); + icon_sizes.push_back(std::make_pair("panel", 32)); + icon_sizes.push_back(std::make_pair("gtk-small-toolbar", 22)); + icon_sizes.push_back(std::make_pair("gtk-large-toolbar", 22)); + icon_sizes.push_back(std::make_pair("gtk-dnd", 48)); + icon_sizes.push_back(std::make_pair("gtk-button", 16)); + icon_sizes.push_back(std::make_pair("gtk-menu", 16)); + icon_sizes.push_back(std::make_pair("gtk-dialog", 32)); + icon_sizes.push_back(std::make_pair("", 16)); + + writeGtkThemeControlFile(false); + + // Initialize hooks + m_widgetLookup.initializeHooks(); + + return GTK_THEMING_ENGINE (g_object_new (TDEGTK_TYPE_ENGINE, "name", "tdegtk", NULL)); +} + +// ========================================================================================================= +// +// TQt3/GTK Theme Control Functions +// +// ========================================================================================================= + +TQStringList tdeSearchPaths; +TQString iconTheme; +TQStringList iconThemeDirs; +TQColor alternateBackgroundColour; +int showIconsOnButtons; +int toolbarStyle; + +TQString tdeConfigValue(const TQString& section, const TQString& name, const TQString& def) { + KConfig currentConfig; + currentConfig.setGroup(section); + return currentConfig.readEntry(name, def); +} + +bool tdeBoolConfigValue(const TQString& section, const TQString& name, bool def) { + KConfig currentConfig; + currentConfig.setGroup(section); + return currentConfig.readBoolEntry(name, def); +} + +TQString tdeFindDir(const TQString& suffix, const TQString& file1, const TQString& file2) { + for ( TQStringList::Iterator it = tdeSearchPaths.begin(); it != tdeSearchPaths.end(); ++it ) + { + if ((TQFile::exists((*it) + suffix + file1)) || (TQFile::exists((*it) + suffix + file2))) + return (*it) + suffix; + } + return TQString(); +} + +TQString runCommand(const TQString& command) { + FILE* p = popen(command.latin1(), "r"); + if ((p == NULL) || (p < 0)) + return TQString(); + + TQString ret; + while (!feof(p)) + { + char buffer[256]; + int n = fread(buffer, 1, 255, p); + buffer[n] = '\0'; + ret += buffer; + } + pclose(p); + + return ret.stripWhiteSpace(); +} + +void initTDESettings() { + tdeSearchPaths.clear(); + + TQString tdeHome = getenv("TDEHOME"); + TQString tdeDirs = getenv("TDEDIRS"); + TQString tdeDir = getenv("TDEDIR"); + + if (!tdeHome.isEmpty()) { + tdeSearchPaths.append(tdeHome); + } + tdeSearchPaths.append(runCommand("tde-config --localprefix")); + + if (!tdeDirs.isEmpty()) { + tdeSearchPaths += TQStringList::split(':', tdeDirs); + } + if (!tdeDir.isEmpty()) { + tdeSearchPaths.append(tdeDir); + } + tdeSearchPaths.append(runCommand("tde-config --prefix")); + + iconTheme = tdeConfigValue("Icons", "Theme", "crystalsvg"); + tde_showIconsOnPushButtons = tdeBoolConfigValue("KDE", "ShowIconsOnPushButtons", false); + + TQStringList back = TQStringList::split(',', tdeConfigValue("General", "alternateBackground", "238,246,255")); + alternateBackgroundColour.setRgb(back[0].toInt(), back[1].toInt(), back[2].toInt()); + + showIconsOnButtons = (tdeConfigValue("KDE", "ShowIconsOnPushButtons", "true").lower() == "true"); + + TQString tmp = tdeConfigValue("Toolbar style", "IconText", "true").lower(); + if (tmp == "icononly") { + toolbarStyle = 0; + } + else if (tmp == "icontextright") { + toolbarStyle = 3; + } + else if (tmp == "textonly") { + toolbarStyle = 1; + } + else if (tmp == "icontextbottom") { + toolbarStyle = 2; + } + else { + // Should never happen, but just in case we fallback to TDE's default "icononly" + toolbarStyle = 0; + } +} + +void gtk3_tqt_load_resource_string(const char* css_string) { + GtkCssProvider *provider; + + provider = gtk_css_provider_new(); + gtk_css_provider_load_from_data(provider, css_string, -1, NULL); + GdkDisplay *display = gdk_display_get_default(); + GdkScreen *screen = gdk_display_get_default_screen(display); + gtk_style_context_add_provider_for_screen(screen, GTK_STYLE_PROVIDER(provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + g_object_unref(provider); + + DEBUG_PRINT_ARGS("gtk3_tqt_load_resource_string(%s)", css_string) +} + +void gtk3_tqt_reload_theme_definition_file(const char* filename) { + GtkCssProvider *provider; + GError *error; + + provider = gtk_css_provider_new(); + GdkDisplay *display = gdk_display_get_default(); + GdkScreen *screen = gdk_display_get_default_screen(display); + gtk_style_context_add_provider_for_screen(screen, GTK_STYLE_PROVIDER(provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + g_object_unref(provider); + if (!gtk_css_provider_load_from_path(provider, filename, &error)) { + g_printerr("%s: error parsing %s: %s\n", G_STRFUNC, filename, error->message); + g_clear_error(&error); + } +} + +TQString tdeFontToGTKFontString(TQFont font) { + TQString fontDescriptor = "font: "; + fontDescriptor.append(font.family()); + if (font.bold()) { + fontDescriptor.append(" bold"); + } + if (font.italic()) { + fontDescriptor.append(" italic"); + } + if (font.pointSizeFloat() != -1) { + fontDescriptor.append(TQString(" %1").arg(font.pointSizeFloat())); + } + else { + fontDescriptor.append(TQString(" %1px").arg(font.pixelSize())); + } + + return fontDescriptor; +} + +// Thanks Martin Dvorak of metatheme +TQString parse_rc_string(const TQString& defs, const TQString& pattern, bool widgetClass = true) { + static int dynamic_counter = 0; + ++dynamic_counter; + + return pattern + " {\n\t" + defs + ";\n}\n\n"; +} + +GtkIconSet* generateIconSet(const std::string& gtkIconName, const std::string& tdeIconName, TQStringList pathList) { + if (tdeIconName == "NONE") { + return 0L; + } + + bool empty = true; + + // create iconSet + GtkIconSet* iconSet = gtk_icon_set_new(); + + // loop over iconSizes + for (SizeMap::const_iterator sizeIter = icon_sizes.begin(); sizeIter != icon_sizes.end(); ++sizeIter) { + // generate full icon name + std::ostringstream iconFileStream; + iconFileStream << sizeIter->second << "x" << sizeIter->second << "/" << tdeIconName; + + // loop over provided path to see if at least one icon is found + for (TQStringList::const_iterator pathIter = pathList.begin(); pathIter != pathList.end(); ++pathIter) { + std::string filename((*pathIter + '/' + iconFileStream.str()).latin1()); + if (!std::ifstream(filename.c_str())) { + continue; + } + + empty = false; + GtkIconSource* iconSource(gtk_icon_source_new()); + + // set name + gtk_icon_source_set_filename(iconSource, filename.c_str()); + + // set direction and state wildcarded + gtk_icon_source_set_direction_wildcarded(iconSource, TRUE); + gtk_icon_source_set_state_wildcarded(iconSource, TRUE); + + // set size + if (sizeIter->first.empty()) { + gtk_icon_source_set_size_wildcarded(iconSource, TRUE); + } + else { + GtkIconSize size = gtk_icon_size_from_name(sizeIter->first.c_str()); + if (size != GTK_ICON_SIZE_INVALID) { + gtk_icon_source_set_size_wildcarded(iconSource, FALSE); + gtk_icon_source_set_size(iconSource, size); + } + } + + // add source to iconSet + gtk_icon_set_add_source(iconSet, iconSource); + break; + } + } + + // if nothing found, return; + if (empty) { + gtk_icon_set_unref(iconSet); + return 0L; + } + else { + return iconSet; + } + +} + +void doIconMapping(const char* gtkName, const char * tdeName, GtkIconFactory* factory, TQStringList tdeIconThemeDirs) { + GtkIconSet* iconSet = generateIconSet(gtkName, tdeName, tdeIconThemeDirs); + if (iconSet) { + gtk_icon_factory_add(factory, gtkName, iconSet); + gtk_icon_set_unref(iconSet); + } +} + +TQString colorString(TQColor color) { + TQString ret = "rgb("; + ret += TQString::number(color.red()) + ", "; + ret += TQString::number(color.green()) + ", "; + ret += TQString::number(color.blue()) + ")"; + + return ret; +} + +void setColour(TQString name, TQString state, TQColor color) { + state = ":" + state; + if (state == ":normal") { + state = ""; + } + gtk3_tqt_load_resource_string(parse_rc_string(name + ": " + colorString(color), "*" + state).latin1()); +} + +static TQStringList iconInheritsDirs(const TQString& icondir) { + TQFile index; + index.setName(icondir + "index.theme"); + if( !index.open( IO_ReadOnly )) { + index.setName(icondir + "index.desktop"); + if( !index.open( IO_ReadOnly )) + return TQStringList(); + } + char buf[1024]; + TQRegExp reg( "^\\s*Inherits=([^\\n]*)" ); + for(;;) { + if( index.readLine(buf, 1023) <= 0 ) { + break; + } + if( reg.search(buf, 0) >= 0 ) { + return TQStringList::split(",", reg.cap(1)); + } + } + return TQStringList(); +} + +void addIconThemeDir(const TQString& theme) { + // Try to find this theme's directory + TQString icondir = tdeFindDir("/share/icons/" + theme + "/", "index.theme", "index.desktop"); + if(icondir.isEmpty()) { + return; + } + if (iconThemeDirs.contains(icondir)) { + return; + } + + // Add this theme to the list + iconThemeDirs.append(icondir); + + // Do it again for any parent themes + TQStringList parents = iconInheritsDirs(icondir); + for ( TQStringList::Iterator it=parents.begin() ; it!=parents.end(); ++it) { + addIconThemeDir((*it).stripWhiteSpace()); + } +} + +void writeGtkThemeControlFile(int forceRecreate) { + if (!gtk3TQtEnable) { + return; + } + + DEBUG_PRINT("writeGtkThemeControlFile()") + + // Set colors + // Normal + setColour("color", "normal", tqApp->palette().active().text()); + setColour("background-color", "normal", tqApp->palette().active().background()); +// setColour("text", "normal", tqApp->palette().active().text()); +// setColour("base", "normal", tqApp->palette().active().base()); + + // Active (on) + setColour("color", "active", tqApp->palette().active().text()); + setColour("background-color", "active", tqApp->palette().active().background()); +// setColour("text", "active", tqApp->palette().active().text()); +// setColour("base", "active", tqApp->palette().active().base()); + + // Mouseover + setColour("color", "prelight", tqApp->palette().active().text()); // menu items - change? + setColour("background-color", "prelight", tqApp->palette().active().highlight()); +// setColour("text", "prelight", tqApp->palette().active().text()); +// setColour("base", "prelight", tqApp->palette().active().base()); + + // Selected + setColour("color", "selected", tqApp->palette().active().highlightedText()); + setColour("background-color", "selected", tqApp->palette().active().highlight()); +// setColour("text", "selected", tqApp->palette().active().highlightedText()); +// setColour("base", "selected", tqApp->palette().active().highlight()); + + // Disabled + setColour("color", "insensitive", tqApp->palette().disabled().text()); + setColour("background-color", "insensitive", tqApp->palette().disabled().background()); +// setColour("text", "insensitive", tqApp->palette().disabled().text()); +// setColour("base", "insensitive", tqApp->palette().disabled().background()); + + // Set up global application settings + GtkSettings* gtksettings = gtk_settings_get_default(); + GtkSettingsValue svalue; + if (gtksettings) { + g_object_set(gtksettings, "gtk-alternative-button-order", TRUE, NULL); + g_object_set(gtksettings, "gtk-button-images", tde_showIconsOnPushButtons, NULL); + g_object_set(gtksettings, "gtk-menu-popup-delay", tqApp->style().styleHint(TQStyle::SH_PopupMenu_SubMenuPopupDelay), NULL); + // Handle toolbar text display + if (toolbarStyle == 3) { + // This is broken by GTK bug #68700 + g_object_set(gtksettings, "gtk-toolbar-style", GTK_TOOLBAR_BOTH_HORIZ, NULL); + } + else if (toolbarStyle == 2) { + g_object_set(gtksettings, "gtk-toolbar-style", GTK_TOOLBAR_BOTH, NULL); + } + else if (toolbarStyle == 1) { + g_object_set(gtksettings, "gtk-toolbar-style", GTK_TOOLBAR_TEXT, NULL); + } + else { + g_object_set(gtksettings, "gtk-toolbar-style", GTK_TOOLBAR_ICONS, NULL); + } + } + + // This function takes quite a long time to execute, and is run at the start of every app. + // In order to speed it up, we can store the results in a file, along with the name of icon + // theme and style. This file can then be regenerated when the icon theme or style change. + + TQDir curDir; + TQString themeFilePath = TQDir::homeDirPath(); + curDir.setPath(themeFilePath); + if (!curDir.exists()) { + curDir.mkdir(themeFilePath); + } + themeFilePath = themeFilePath + "/.themes/"; + curDir.setPath(themeFilePath); + if (!curDir.exists()) { + curDir.mkdir(themeFilePath); + } + themeFilePath = themeFilePath + TQString(TDEGTK_THEME_THEME_DIRECTORY_NAME) + "/"; + curDir.setPath(themeFilePath); + if (!curDir.exists()) { + curDir.mkdir(themeFilePath); + } + themeFilePath = themeFilePath + "gtk-3.0/"; + curDir.setPath(themeFilePath); + if (!curDir.exists()) { + curDir.mkdir(themeFilePath); + } + + themeFilePath = themeFilePath + TDEGTK_THEME_CONTROL_FILE_NAME; + TQFile themeFile(themeFilePath); + TQTextStream stream; + + if (!forceRecreate && themeFile.exists()) + { + themeFile.open(IO_ReadOnly); + stream.setDevice(TQT_TQIODEVICE(&themeFile)); + + if (stream.readLine() == "/* " + iconTheme + ", " + tqApp->style().name() + ", " + RC_CACHE_VERSION + " */") + { + // This cache matches the current icon theme and style + gtk3_tqt_reload_theme_definition_file(themeFilePath.latin1()); + return; + } + + stream.unsetDevice(); + themeFile.close(); + } + + themeFile.open(IO_WriteOnly | IO_Truncate); + stream.setDevice(TQT_TQIODEVICE(&themeFile)); + + stream << "/* " << iconTheme << ", " << tqApp->style().name() << ", " << RC_CACHE_VERSION << " */\n\n"; + stream << "/* This file was generated by the Gtk TQt Theme Engine */\n"; + stream << "/* It will be recreated when you change your TDE icon theme or widget style */\n\n"; + + stream << "\n"; + stream << "* {\n\tengine:tdegtk;\n}\n"; + stream << "\n"; + + TQScrollBar sbar(NULL); + sbar.setOrientation(TQt::Horizontal); + sbar.setValue(1); + sbar.resize(200,25); + + // The following code determines how many buttons are on a scrollbar + // It works by looking at each pixel of the scrollbar's area not taken up by the groove, + // and asking the style which subcontrol is at that location. + TQRect rect = tqApp->style().querySubControlMetrics(TQStyle::CC_ScrollBar, &sbar, TQStyle::SC_ScrollBarGroove); + + bool back1 = false; + bool forward1 = false; + bool back2 = false; + bool forward2 = false; + + TQStyle::SubControl sc = TQStyle::SC_None; + for (TQPoint pos(0,7) ; pos.x()<rect.x() ; pos.setX(pos.x()+1)) + { + TQStyle::SubControl sc2 = tqApp->style().querySubControl(TQStyle::CC_ScrollBar, &sbar, pos); + if (sc != sc2) + { + if (sc2 == TQStyle::SC_ScrollBarAddLine) forward1 = true; + if (sc2 == TQStyle::SC_ScrollBarSubLine) back1 = true; + sc = sc2; + } + } + sc = TQStyle::SC_None; + for (TQPoint pos(rect.x()+rect.width(),7) ; pos.x()<200 ; pos.setX(pos.x()+1)) + { + TQStyle::SubControl sc2 = tqApp->style().querySubControl(TQStyle::CC_ScrollBar, &sbar, pos); + if (sc != sc2) + { + if (sc2 == TQStyle::SC_ScrollBarAddLine) forward2 = true; + if (sc2 == TQStyle::SC_ScrollBarSubLine) back2 = true; + sc = sc2; + } + } + + bool combobox_appears_as_list = (!(tqApp->style().styleHint(TQStyle::SH_ComboBox_Popup) || tqApp->style().styleHint(TQStyle::SH_GUIStyle) == TQt::MotifStyle)); + stream << parse_rc_string(TQString("-GtkComboBox-appears-as-list: %1px").arg(combobox_appears_as_list), "*"); + + stream << parse_rc_string(TQString("-GtkScrollbar-has-backward-stepper: ") + (back1 ? "1" : "0"), "*"); + stream << parse_rc_string(TQString("-GtkScrollbar-has-forward-stepper: ") + (forward2 ? "1" : "0"), "*"); + stream << parse_rc_string(TQString("-GtkScrollbar-has-secondary-forward-stepper: ") + (forward1 ? "1" : "0"), "*"); + stream << parse_rc_string(TQString("-GtkScrollbar-has-secondary-backward-stepper: ") + (back2 ? "1" : "0"), "*"); + + stream << parse_rc_string("-GtkScrollbar-stepper-size: " + TQString::number(tqApp->style().querySubControlMetrics(TQStyle::CC_ScrollBar, &sbar, TQStyle::SC_ScrollBarSubLine).width() - 1), "*"); + + stream << parse_rc_string("-GtkScrollbar-min-slider-length: " + TQString::number(tqApp->style().pixelMetric(TQStyle::PM_ScrollBarSliderMin)), "*"); + stream << parse_rc_string("-GtkScrollbar-slider-width: " + TQString::number(tqApp->style().pixelMetric(TQStyle::PM_ScrollBarExtent)-2), "*"); + + stream << parse_rc_string("-GtkButton-child-displacement-x: " + TQString::number(tqApp->style().pixelMetric(TQStyle::PM_ButtonShiftHorizontal)), "*"); + stream << parse_rc_string("-GtkButton-child-displacement-y: " + TQString::number(tqApp->style().pixelMetric(TQStyle::PM_ButtonShiftVertical)), "*"); + stream << parse_rc_string("-GtkButton-default-border: 0 0 0 0", "*"); + stream << parse_rc_string("-GtkButton-default-outside-border: 0 0 0 0", "*"); +#ifdef USE_NATIVE_GTK_BUTTON_DRAWING + stream << parse_rc_string("-GtkButton-inner-border: 2 2 2 2", "*"); +#else + if (tde_showIconsOnPushButtons) { + stream << parse_rc_string("-GtkButton-inner-border: 10 10 2 2", "*"); // Allow space for the icon on either side of the text + } + else { + stream << parse_rc_string("-GtkButton-inner-border: 2 2 2 2", "*"); + } +#endif + + stream << parse_rc_string("-GtkButtonBox-child_min_height: 0", "*"); + stream << parse_rc_string("-GtkButtonBox-child_internal_pad_x: 0", "*"); + stream << parse_rc_string("-GtkButtonBox-child_internal_pad_y: 0", "*"); + + TQSlider slider(NULL); // To keep BlueCurve happy + stream << parse_rc_string("-GtkScale-slider-length: " + TQString::number(tqApp->style().pixelMetric(TQStyle::PM_SliderLength, &slider)), "*"); + + stream << parse_rc_string("-GtkRange-arrow-scaling: 1.0", "GtkScrollbar"); + + stream << parse_rc_string("-xthickness: " + TQString::number(tqApp->style().pixelMetric(TQStyle::PM_DefaultFrameWidth)), "*.GtkMenu"); + stream << parse_rc_string("-ythickness: " + TQString::number(tqApp->style().pixelMetric(TQStyle::PM_DefaultFrameWidth)), "*.GtkMenu"); + stream << parse_rc_string("-xthickness: 5", "*.GtkMenu.Gtk*MenuItem"); + stream << parse_rc_string("-xthickness: 3", "*.GtkNotebook"); + stream << parse_rc_string("-ythickness: 3", "*.GtkNotebook"); + stream << parse_rc_string("-ythickness: 1", "*.GtkButton"); + stream << parse_rc_string("-color: " + colorString(TQColor(0,0,0)), "gtk-tooltips.GtkLabel", false); + + stream << parse_rc_string("-xthickness: 1", "*.GtkButton.*"); + stream << parse_rc_string("-ythickness: 1", "*.GtkButton.*"); + +// stream << parse_rc_string("GtkTreeView::allow-rules = 0", "*"); +// stream << parse_rc_string("GtkTreeView::tree-line-width = 1", "*"); +// stream << parse_rc_string("GtkTreeView::vertical-separator = 30", "*"); +// //stream << parse_rc_string("GtkTreeView::odd-row-color = { 0.0, 0.0, 0.0 }", "*"); + + stream << parse_rc_string("-GtkButton-inner-border: 0 0 0 0", "*GtkToolbar*GtkButton*"); + stream << parse_rc_string("-GtkButton-inner-border: 0 0 0 0", "*GtkToolbar*GtkToggleButton*"); + stream << parse_rc_string("-GtkButton-inner-border: 0 0 0 0", "*GtkNotebook*GtkButton*"); + stream << parse_rc_string("-GtkButton-inner-border: 0 0 0 0", "*GtkNotebook*GtkToggleButton*"); + + // TQt calls them tab boxes, GTK calls them notebooks (!??!?) Either way they are a pain... + //stream << parse_rc_string("-GtkNotebook-tab-overlap: " + TQString::number(tqApp->style().pixelMetric(TQStyle::PM_TabBarTabOverlap)), "*"); + stream << parse_rc_string("-GtkNotebook-tab-overlap: 0", "*"); // Overlap is handled in the style engine itself + stream << parse_rc_string("-GtkNotebook-tab-curvature: 0", "*"); + + // This sets both the radio button and check box sizes + stream << parse_rc_string("-GtkCheckButton-indicator-size: " + TQString::number(tqApp->style().pixelMetric(TQStyle::PM_IndicatorHeight)), "*"); + + // FIXME + // GtkCellRendererToggle indicator-size must be set as follows, however GTK3 does not provide any means to change the default size! + // See upstream GTK bug #687076 + //stream << parse_rc_string("-GtkCellRendererToggle-indicator-size: " + TQString::number(tqApp->style().pixelMetric(TQStyle::PM_IndicatorHeight)), "*"); + + // FIXME + // There must be a way to set the selected tab offset (shift) + // If not, it may be neccessary to override the GTK text drawing routines for notebooks to insert the proper shift + //stream << parse_rc_string("-????: " + TQString::number(tqApp->style().pixelMetric(TQStyle::PM_TabBarTabShiftHorizontal)), "*"); + + stream << parse_rc_string("-GtkButton-child-displacement-x: " + TQString::number(tqApp->style().pixelMetric(TQStyle::PM_ButtonShiftHorizontal)), "*"); + stream << parse_rc_string("-GtkButton-child-displacement-y: " + TQString::number(tqApp->style().pixelMetric(TQStyle::PM_ButtonShiftVertical)), "*"); + + // Set up fonts + TQFont generalFont = KGlobalSettings::generalFont(); + TQFont toolBarFont = KGlobalSettings::toolBarFont(); + TQFont menuFont = KGlobalSettings::menuFont(); + // TQFont windowTitleFont = KGlobalSettings::windowTitleFont(); + // TQFont taskbarFont = KGlobalSettings::taskbarFont(); + + stream << parse_rc_string(tdeFontToGTKFontString(generalFont), "*"); + stream << parse_rc_string(tdeFontToGTKFontString(toolBarFont), "*GtkToolbar*GtkButton*"); + stream << parse_rc_string(tdeFontToGTKFontString(menuFont), "*.GtkMenu"); + + // Set up icons + // Build the list of icon theme directories. + // This function is recursive - it gets the directories of all the inherited themes as well + addIconThemeDir(iconTheme); + + if (iconThemeDirs.isEmpty()) { + themeFile.close(); + if (!forceRecreate) { + gtk3_tqt_reload_theme_definition_file(themeFilePath.latin1()); + } + return; + } + + GtkIconFactory* factory; + factory = gtk_icon_factory_new(); + + doIconMapping("gtk-about", "actions/about_kde.png", factory, iconThemeDirs); + doIconMapping("gtk-add", "actions/add.png", factory, iconThemeDirs); + doIconMapping("gtk-apply", "actions/apply.png", factory, iconThemeDirs); + doIconMapping("gtk-bold", "actions/text_bold.png", factory, iconThemeDirs); + doIconMapping("gtk-cancel", "actions/button_cancel.png", factory, iconThemeDirs); + doIconMapping("gtk-cdrom", "devices/cdrom_unmount.png", factory, iconThemeDirs); + doIconMapping("gtk-clear", "actions/editclear.png", factory, iconThemeDirs); + doIconMapping("gtk-close", "actions/fileclose.png", factory, iconThemeDirs); + doIconMapping("gtk-color-picker", "actions/colorpicker.png", factory, iconThemeDirs); + doIconMapping("gtk-copy", "actions/editcopy.png", factory, iconThemeDirs); + doIconMapping("gtk-convert", "actions/gtk-convert.png", factory, iconThemeDirs); + doIconMapping("gtk-connect", "actions/connect_creating.png", factory, iconThemeDirs); + doIconMapping("gtk-cut", "actions/editcut.png", factory, iconThemeDirs); + doIconMapping("gtk-delete", "actions/editdelete.png", factory, iconThemeDirs); + doIconMapping("gtk-dialog-authentication", "status/gtk-dialog-authentication", factory, iconThemeDirs); + doIconMapping("gtk-dialog-error", "actions/messagebox_critical.png", factory, iconThemeDirs); + doIconMapping("gtk-dialog-info", "actions/messagebox_info.png", factory, iconThemeDirs); + doIconMapping("gtk-dialog-question", "actions/help.png", factory, iconThemeDirs); + doIconMapping("gtk-dialog-warning", "actions/messagebox_warning.png", factory, iconThemeDirs); + doIconMapping("gtk-directory", "filesystems/folder.png", factory, iconThemeDirs); + doIconMapping("gtk-disconnect", "actions/connect_no.png", factory, iconThemeDirs); + doIconMapping("gtk-dnd", "mimetypes/empty.png", factory, iconThemeDirs); + doIconMapping("gtk-dnd-multiple", "mimetypes/kmultiple.png", factory, iconThemeDirs); + doIconMapping("gtk-edit", "actions/edit.png", factory, iconThemeDirs); //2.6 + doIconMapping("gtk-execute", "actions/exec.png", factory, iconThemeDirs); + doIconMapping("gtk-file", "mimetypes/empty.png", factory, iconThemeDirs); + doIconMapping("gtk-find", "actions/find.png", factory, iconThemeDirs); + doIconMapping("gtk-find-and-replace", "actions/find.png", factory, iconThemeDirs); // Is there a TDE "find and replace" icon? FIXME + doIconMapping("gtk-floppy", "devices/3floppy_unmount.png", factory, iconThemeDirs); + doIconMapping("gtk-fullscreen", "actions/window-fullscreen.png", factory, iconThemeDirs); + doIconMapping("gtk-goto-bottom", "actions/bottom.png", factory, iconThemeDirs); + doIconMapping("gtk-goto-first", "actions/start.png", factory, iconThemeDirs); + doIconMapping("gtk-goto-last", "actions/finish.png", factory, iconThemeDirs); + doIconMapping("gtk-goto-top", "actions/top.png", factory, iconThemeDirs); + doIconMapping("gtk-go-back", "actions/back.png", factory, iconThemeDirs); + doIconMapping("gtk-go-down", "actions/down.png", factory, iconThemeDirs); + doIconMapping("gtk-go-forward", "actions/forward.png", factory, iconThemeDirs); + doIconMapping("gtk-go-up", "actions/up.png", factory, iconThemeDirs); + doIconMapping("gtk-harddisk", "devices/hdd_unmount.png", factory, iconThemeDirs); + doIconMapping("gtk-help", "apps/khelpcenter.png", factory, iconThemeDirs); + doIconMapping("gtk-home", "filesystems/folder_home.png", factory, iconThemeDirs); + doIconMapping("gtk-indent", "actions/indent.png", factory, iconThemeDirs); + doIconMapping("gtk-index", "actions/contents.png", factory, iconThemeDirs); + doIconMapping("gtk-info", "actions/messagebox_info.png", factory, iconThemeDirs); + doIconMapping("gtk-italic", "actions/text_italic.png", factory, iconThemeDirs); + doIconMapping("gtk-jump-to", "actions/goto.png", factory, iconThemeDirs); + doIconMapping("gtk-justify-center", "actions/text_center.png", factory, iconThemeDirs); + doIconMapping("gtk-justify-fill", "actions/text_block.png", factory, iconThemeDirs); + doIconMapping("gtk-justify-left", "actions/text_left.png", factory, iconThemeDirs); + doIconMapping("gtk-justify-right", "actions/text_right.png", factory, iconThemeDirs); + doIconMapping("gtk-leave-fullscreen", "actions/window-nofullscreen.png", factory, iconThemeDirs); + doIconMapping("gtk-media-forward", "player-fwd.png", factory, iconThemeDirs); + doIconMapping("gtk-media-next", "actions/player-end.png", factory, iconThemeDirs); + doIconMapping("gtk-media-pause", "actions/player-pause.png", factory, iconThemeDirs); + doIconMapping("gtk-media-previous", "actions/player-start.png", factory, iconThemeDirs); + doIconMapping("gtk-media-record", "actions/gtk-media-record.png", factory, iconThemeDirs); // FIXME + doIconMapping("gtk-media-rewind", "actions/player-rew.png", factory, iconThemeDirs); + doIconMapping("gtk-media-stop", "actions/player-stop.png", factory, iconThemeDirs); + doIconMapping("gtk-missing-image", "mimetypes/unknown.png", factory, iconThemeDirs); + doIconMapping("gtk-network", "filesystems/network.png", factory, iconThemeDirs); + doIconMapping("gtk-new", "actions/filenew.png", factory, iconThemeDirs); + doIconMapping("gtk-no", "actions/gtk-no.png", factory, iconThemeDirs); + doIconMapping("gtk-ok", "actions/button_ok.png", factory, iconThemeDirs); + doIconMapping("gtk-open", "actions/fileopen.png", factory, iconThemeDirs); + //doIconMapping("gtk-orientation-landscape", factory, iconThemeDirs); // FIXME + //doIconMapping("gtk-orientation-portrait", factory, iconThemeDirs); // FIXME + //doIconMapping("gtk-orientation-reverse-landscape", factory, iconThemeDirs); // FIXME + //doIconMapping("gtk-orientation-reverse-portrait"", factory, iconThemeDirs); // FIXME + doIconMapping("gtk-paste", "actions/editpaste.png", factory, iconThemeDirs); + doIconMapping("gtk-preferences", "actions/configure.png", factory, iconThemeDirs); + doIconMapping("gtk-print", "actions/fileprint.png", factory, iconThemeDirs); + doIconMapping("gtk-print-preview", "actions/filequickprint.png", factory, iconThemeDirs); + doIconMapping("gtk-properties", "actions/configure.png", factory, iconThemeDirs); + doIconMapping("gtk-quit", "actions/exit.png", factory, iconThemeDirs); + doIconMapping("gtk-redo", "actions/redo.png", factory, iconThemeDirs); + doIconMapping("gtk-refresh", "actions/reload.png", factory, iconThemeDirs); + doIconMapping("gtk-remove", "actions/remove.png", factory, iconThemeDirs); + doIconMapping("gtk-revert-to-saved", "actions/revert.png", factory, iconThemeDirs); + doIconMapping("gtk-save", "actions/filesave.png", factory, iconThemeDirs); + doIconMapping("gtk-save-as", "actions/filesaveas.png", factory, iconThemeDirs); + doIconMapping("gtk-select-all", "actions/gtk-select-all.png", factory, iconThemeDirs); // FIXME + doIconMapping("gtk-select-color", "actions/colorize.png", factory, iconThemeDirs); + doIconMapping("gtk-select-font", "mimetypes/font.png", factory, iconThemeDirs); + //doIconMapping("gtk-sort-ascending", "??", factory, iconThemeDirs); // FIXME + //doIconMapping("gtk-sort-descending", "??", factory, iconThemeDirs); // FIXME + doIconMapping("gtk-spell-check", "actions/spellcheck.png", factory, iconThemeDirs); + doIconMapping("gtk-stop", "actions/stop.png", factory, iconThemeDirs); + doIconMapping("gtk-strikethrough", "actions/text_strike.png", factory, iconThemeDirs); + doIconMapping("gtk-undelete", "actions/gtk-undelete.png", factory, iconThemeDirs); // FIXME + doIconMapping("gtk-underline", "actions/text_under.png", factory, iconThemeDirs); + doIconMapping("gtk-undo", "actions/undo.png", factory, iconThemeDirs); + doIconMapping("gtk-unindent", "actions/unindent.png", factory, iconThemeDirs); + doIconMapping("gtk-yes", "actions/button_ok.png", factory, iconThemeDirs); // Verify mapping here + doIconMapping("gtk-zoom-100", "actions/viewmag1.png", factory, iconThemeDirs); + doIconMapping("gtk-zoom-fit", "actions/viewmagfit.png", factory, iconThemeDirs); + doIconMapping("gtk-zoom-in", "actions/viewmag+.png", factory, iconThemeDirs); + doIconMapping("gtk-zoom-out", "actions/viewmag-.png", factory, iconThemeDirs); + + // Other icons that really should have Trinity equivalents in tdelibs + doIconMapping("list-add", "actions/add.png", factory, iconThemeDirs); + doIconMapping("list-remove", "actions/remove.png", factory, iconThemeDirs); + + gtk_icon_factory_add_default(factory); + + themeFile.close(); + + if (!forceRecreate) { + gtk3_tqt_reload_theme_definition_file(themeFilePath.latin1()); + } +} +// =========================================================================================================
\ No newline at end of file diff --git a/tdegtk/tdegtk-types.h b/tdegtk/tdegtk-types.h index ba280d2..ad94d5f 100644 --- a/tdegtk/tdegtk-types.h +++ b/tdegtk/tdegtk-types.h @@ -1,5 +1,5 @@ /* The TdeGtk Theming Engine for Gtk+. - * Copyright (C) 2011 Canonical Ltd + * Copyright (C) 2012 Timothy Pearson <kb9vqf@pearsoncomputing.net> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -16,7 +16,8 @@ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301, USA. * - * Authored by Andrea Cimitan <andrea.cimitan@canonical.com> + * Portions of this file written by + * Andrea Cimitan <andrea.cimitan@canonical.com> * */ @@ -61,6 +62,26 @@ typedef enum TDEGTK_NUM_STYLES = 1 } TdeGtkStyles; +enum TQt3WidgetType { + TQT3WT_NONE, + TQT3WT_TQProgressBar, + TQT3WT_TQTabBar, + TQT3WT_TQRadioButton, + TQT3WT_TQCheckBox, + TQT3WT_TQPushButton, + TQT3WT_TQPopupMenu, + TQT3WT_TQComboBox, + TQT3WT_TQSlider, + TQT3WT_TQScrollBar, + TQT3WT_TQSpinBox, + TQT3WT_TQSpinWidget, + TQT3WT_TQTitleBar, + TQT3WT_TQMenuBar, + TQT3WT_TQToolBox, + TQT3WT_TQToolButton, + TQT3WT_GTKTreeViewCell, +}; + typedef struct _TdeGtkStyleFunctions TdeGtkStyleFunctions; struct _TdeGtkStyleFunctions diff --git a/tdegtk/tdegtk-utils.cpp b/tdegtk/tdegtk-utils.cpp new file mode 100644 index 0000000..ad93793 --- /dev/null +++ b/tdegtk/tdegtk-utils.cpp @@ -0,0 +1,1064 @@ +/* +* this file was largely taken from the oxygen gtk engine +* Copyright (c) 2010 Hugo Pereira Da Costa <hugo@oxygen-icons.org> +* Copyright (c) 2010 Ruslan Kabatsayev <b7.10110111@gmail.com> +* +* GdkPixbuf modification code from Walmis +* <http://gnome-look.org/content/show.php?content=77783&forumpage=3> +* +* 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., 51 Franklin St, Fifth Floor, Boston, +* MA 02110-1301, USA. +*/ + +#include "tdegtk-utils.h" +//#include "oxygengtktypenames.h" +#include "config.h" + +#include <cmath> +#include <cstring> +#include <gtk/gtk.h> +#include <iostream> +#include <set> + + //_____________________________________________________________________________ + std::ostream& operator << ( std::ostream& out, const GtkWidgetPath* path ) + { + if( !path ) + { + + out << " (null)"; + + } else { + + for( gint pos=0; pos<gtk_widget_path_length( path ); ++pos ) + { + const char* name( g_type_name( gtk_widget_path_iter_get_object_type( path, pos ) ) ); + if(!name) break; + out << "/" << name; + } + + } + + return out; + + } + + + + //____________________________________________________________ + void Gtk::gtk_container_adjust_buttons_state(GtkContainer* container,gpointer data) + { + if(GTK_IS_BUTTON(container)) + { + + int x(0),y(0); + GtkWidget* button=GTK_WIDGET(container); + GtkAllocation allocation( gtk_widget_get_allocation( button ) ); + + GdkDeviceManager* manager( gdk_display_get_device_manager( gtk_widget_get_display( button ) ) ); + GdkDevice* pointer( gdk_device_manager_get_client_pointer( manager ) ); + gdk_window_get_device_position( gtk_widget_get_window( button ), pointer, &x, &y, 0L); + + if( !(x>0 && y>0 && + x < allocation.width && + y < allocation.height) && gtk_widget_get_state(button)==GTK_STATE_ACTIVE ) + { gtk_widget_set_state(button,GTK_STATE_NORMAL); } + + gtk_button_set_relief(GTK_BUTTON(button),GTK_RELIEF_NORMAL); + gtk_widget_set_size_request(button,16,16); + + return; + + } + + if(GTK_IS_CONTAINER(container)) + { gtk_container_foreach(container,(GtkCallback)gtk_container_adjust_buttons_state,0L); } + + } + + //____________________________________________________________ + bool Gtk::gtk_widget_path_has_type( const GtkWidgetPath* path, GType type ) + { + + if( !path ) return false; + for( gint pos=0; pos<gtk_widget_path_length( path ); ++pos ) + { + const GType local( gtk_widget_path_iter_get_object_type( path, pos ) ); + if( local == type || g_type_is_a( local, type ) ) + { return true; } + } + + return false; + + } + + //____________________________________________________________ + bool Gtk::gtk_widget_is_applet( GtkWidget* widget ) + { + if( !widget ) return false; + + #if OXYGEN_DEBUG + std::cerr << "Gtk::gtk_widget_is_applet(): " << Gtk::gtk_widget_path(widget) << std::endl; + #endif + + static const char* names[] = + { + "Panel", + "PanelWidget", + "PanelApplet", + "XfcePanelWindow", + 0 + }; + + // check widget name + std::string name( G_OBJECT_TYPE_NAME( widget ) ); + for( unsigned int i = 0; names[i]; ++i ) + { if( g_object_is_a( G_OBJECT( widget ), names[i] ) || name.find( names[i] ) == 0 ) return true; } + + // also check parent + if( GtkWidget* parent = gtk_widget_get_parent( widget ) ) + { + name = G_OBJECT_TYPE_NAME( parent ); + for( unsigned int i = 0; names[i]; ++i ) + { if( g_object_is_a( G_OBJECT( parent ), names[i] ) || name.find( names[i] ) == 0 ) return true; } + + } + + // also check first widget path element (needed for xfce panel) + std::string widgetPath=Gtk::gtk_widget_path(widget); + { + for( unsigned int i = 0; names[i]; ++i ) + { + if( widgetPath.find(names[i]) != std::string::npos ) + return true; + } + } + + return false; + + } + + //____________________________________________________________ + void Gtk::gtk_widget_print_tree( GtkWidget* widget ) + { + + if( !widget ) return; + std::cerr << "Oxygen::Gtk::gtk_widget_print_tree - widget: " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" << std::endl; + while( ( widget = gtk_widget_get_parent( widget ) ) ) + { std::cerr << " parent: " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" << std::endl; } + + } + + //________________________________________________________ + bool Gtk::gdk_default_screen_is_composited( void ) + { + GdkScreen* screen( gdk_screen_get_default() ); + return (screen && gdk_screen_is_composited( screen ) ); + } + + //________________________________________________________ + bool Gtk::gtk_widget_has_rgba( GtkWidget* widget ) + { + + if( !widget ) return false; + if( !gdk_default_screen_is_composited() ) return false; + return gdk_visual_has_rgba( gtk_widget_get_visual (widget) ); + + } + + //________________________________________________________ + bool Gtk::gdk_window_is_base( GdkWindow* window ) + { + + if( !GDK_IS_WINDOW( window ) ) return false; + + GdkWindowTypeHint hint = gdk_window_get_type_hint( window ); + + #if OXYGEN_DEBUG + std::cerr << "Gtk::gdk_window_is_base - " << TypeNames::windowTypeHint( hint ) << std::endl; + #endif + + return( + hint == GDK_WINDOW_TYPE_HINT_NORMAL || + hint == GDK_WINDOW_TYPE_HINT_DIALOG || + hint == GDK_WINDOW_TYPE_HINT_UTILITY ); + } + + //________________________________________________________ + bool Gtk::gdk_window_nobackground( GdkWindow* window ) + { + if( !GDK_IS_WINDOW( window ) ) return false; + + GdkWindowTypeHint hint = gdk_window_get_type_hint( window ); + return( hint == GDK_WINDOW_TYPE_HINT_COMBO || hint == GDK_WINDOW_TYPE_HINT_TOOLTIP ); + + } + + //________________________________________________________ + bool Gtk::gdk_window_has_rgba( GdkWindow* window ) + { + + if( !window ) return false; + + if( !gdk_default_screen_is_composited() ) return false; + return gdk_visual_has_rgba( gdk_window_get_visual( window ) ); + + } + + //________________________________________________________ + bool Gtk::gdk_visual_has_rgba( GdkVisual* visual ) + { + // check depth + if( gdk_visual_get_depth( visual ) != 32 ) return false; + + // check red pixel + guint32 redMask; + gdk_visual_get_red_pixel_details( visual, &redMask, 0L, 0L ); + if( redMask != 0xff0000 ) return false; + + // check green pixel + guint32 greenMask; + gdk_visual_get_green_pixel_details( visual, &greenMask, 0L, 0L ); + if( greenMask != 0x00ff00 ) return false; + + // check blue pixel + guint32 blueMask; + gdk_visual_get_blue_pixel_details( visual, &blueMask, 0L, 0L ); + if( blueMask != 0x0000ff ) return false; + + return true; + + } + + //________________________________________________________ + bool Gtk::g_object_is_a( const GObject* object, const std::string& typeName ) + { + + if( object ) + { + const GType tmp( g_type_from_name( typeName.c_str() ) ); + if( tmp ) + { return g_type_check_instance_is_a( (GTypeInstance*) object, tmp ); } + } + + return false; + } + + //________________________________________________________ + std::string Gtk::gtk_widget_path( GtkWidget* widget ) + { + + if(GTK_IS_WIDGET(widget)) + { + gchar* widgetPath; + gtk_widget_path( widget, 0L, &widgetPath, 0L); + const std::string out( widgetPath ); + g_free( widgetPath ); + return out; + } + return std::string("not-widget"); + + } + + //________________________________________________________ + GtkWidget* Gtk::gtk_widget_find_parent( GtkWidget* widget, GType type ) + { + + for( GtkWidget* parent = widget; parent; parent = gtk_widget_get_parent( parent ) ) + { if( G_TYPE_CHECK_INSTANCE_TYPE( parent, type ) ) return parent; } + + return 0L; + } + + //________________________________________________________ + GtkWidget* Gtk::gtk_parent_groupbox( GtkWidget* widget ) + { + + for( GtkWidget* parent = widget; parent; parent = gtk_widget_get_parent( parent ) ) + { if( gtk_widget_is_groupbox( parent ) ) return parent; } + + return 0L; + } + + //________________________________________________________ + bool Gtk::gtk_widget_is_parent( GtkWidget* widget, GtkWidget* potentialParent ) + { + + for( GtkWidget* parent = gtk_widget_get_parent( widget ); parent; parent = gtk_widget_get_parent( parent ) ) + { if( potentialParent==parent ) return true; } + + return false; + } + + //________________________________________________________ + bool Gtk::gtk_parent_is_shadow_in( GtkWidget* widget ) + { + for( GtkWidget* parent = gtk_widget_get_parent( widget ); parent; parent = gtk_widget_get_parent( parent ) ) + { + if( GTK_IS_FRAME( parent ) && gtk_frame_get_shadow_type( GTK_FRAME( parent ) ) == GTK_SHADOW_IN ) return true; + if( GTK_IS_SCROLLED_WINDOW( parent ) && gtk_scrolled_window_get_shadow_type( GTK_SCROLLED_WINDOW( parent ) ) == GTK_SHADOW_IN ) return true; + } + + return false; + } + + //________________________________________________________ + bool Gtk::gtk_button_is_flat( GtkWidget* widget ) + { + if( !GTK_IS_BUTTON( widget ) ) return false; + return ( gtk_button_get_relief( GTK_BUTTON( widget ) ) == GTK_RELIEF_NONE ); + } + + //________________________________________________________ + bool Gtk::gtk_button_is_header( GtkWidget* widget ) + { return GTK_IS_BUTTON( widget ) && gtk_parent_tree_view( widget ); } + + //________________________________________________________ + bool Gtk::gtk_button_is_in_path_bar( GtkWidget* widget ) + { + if( !( GTK_IS_BUTTON( widget ) && gtk_widget_get_parent( widget ) ) ) return false; + + std::string name(G_OBJECT_TYPE_NAME( gtk_widget_get_parent( widget ) ) ); + return name == "GtkPathBar" || name == "NautilusPathBar"; + } + + //________________________________________________________ + bool Gtk::gtk_path_bar_button_is_last( GtkWidget* widget ) + { + + GtkWidget* parent( gtk_widget_get_parent( widget ) ); + + // get parent and check type + if( !( parent && GTK_IS_CONTAINER( parent ) ) ) return false; + + // get children + GList* children( gtk_container_get_children( GTK_CONTAINER( parent ) ) ); + + /* + for some reason, pathbar buttons are ordered in the container in reverse order. + meaning that the last button (in the pathbar) is stored first in the list. + */ + bool result = (widget == g_list_first( children )->data ); + if( children ) g_list_free( children ); + return result; + + } + + //________________________________________________________ + GtkWidget* Gtk::gtk_button_find_image(GtkWidget* button) + { + + // check widget type + if(!GTK_IS_CONTAINER(button)) return 0L; + + GtkWidget* result( 0L ); + GList* children( gtk_container_get_children( GTK_CONTAINER( button ) ) ); + for( GList *child = g_list_first( children ); child; child = g_list_next( child ) ) + { + if( GTK_IS_IMAGE( child->data ) ) + { + result = GTK_WIDGET( child->data ); + break; + + } else if( GTK_IS_CONTAINER( child->data ) ) { + + result = gtk_button_find_image( GTK_WIDGET(child->data ) ); + break; + + } + + } + + if( children ) g_list_free( children ); + return result; + + } + + //________________________________________________________ + GtkWidget* Gtk::gtk_button_find_label(GtkWidget* button) + { + + // check widget type + if( !GTK_IS_CONTAINER(button) ) return 0L; + + GtkWidget* result( 0L ); + GList* children( gtk_container_get_children( GTK_CONTAINER( button ) ) ); + for( GList *child = g_list_first( children ); child; child = g_list_next( child ) ) + { + + if( GTK_IS_LABEL( child->data) ) + { + result = GTK_WIDGET( child->data ); + break; + + } else if( GTK_IS_CONTAINER( child->data ) ) { + + result = gtk_button_find_image(GTK_WIDGET(child->data)); + break; + + } + + } + + if( children ) g_list_free( children ); + return result; + + } + + //________________________________________________________ + bool Gtk::gtk_combobox_has_frame( GtkWidget* widget ) + { + + GValue val = { 0, }; + g_value_init(&val, G_TYPE_BOOLEAN); + g_object_get_property( G_OBJECT( widget ), "has-frame", &val ); + return (bool) g_value_get_boolean( &val ); + + } + + //________________________________________________________ + bool Gtk::gtk_combobox_is_tree_view( GtkWidget* widget ) + { + // check types and path + if( !widget && GTK_IS_TREE_VIEW( widget ) && GTK_IS_SCROLLED_WINDOW( gtk_widget_get_parent( widget ) ) ) return false; + return Gtk::gtk_widget_path( widget ) == "gtk-combobox-popup-window.GtkScrolledWindow.GtkTreeView"; + } + + //________________________________________________________ + bool Gtk::gtk_combobox_is_scrolled_window( GtkWidget* widget ) + { + // check types and path + if( !GTK_IS_SCROLLED_WINDOW(widget) ) return false; + return Gtk::gtk_widget_path( widget ) == "gtk-combobox-popup-window.GtkScrolledWindow"; + } + + //________________________________________________________ + bool Gtk::gtk_combobox_is_viewport( GtkWidget* widget ) + { + if( !GTK_IS_VIEWPORT(widget) ) return false; + static const std::string match( "gtk-combo-popup-window" ); + return Gtk::gtk_widget_path( widget ).substr( 0, match.size() ) == match; + } + + //________________________________________________________ + bool Gtk::gtk_combobox_is_frame( GtkWidget* widget ) + { + if( !GTK_IS_FRAME(widget) ) return false; + static const std::string match( "gtk-combo-popup-window" ); + return Gtk::gtk_widget_path( widget ).substr( 0, match.size() ) == match; + } + + //________________________________________________________ + bool Gtk::gtk_combobox_appears_as_list( GtkWidget* widget ) + { + gboolean appearsAsList; + gtk_widget_style_get( widget, "appears-as-list", &appearsAsList, NULL ); + return (bool) appearsAsList; + } + + //________________________________________________________ + bool Gtk::gtk_notebook_tab_contains( GtkWidget* widget, int tab, int x, int y ) + { + + if( !( tab >= 0 && GTK_IS_NOTEBOOK( widget ) ) ) return false; + + // cast to notebook and check against number of pages + GtkNotebook* notebook( GTK_NOTEBOOK( widget ) ); + if( tab >= gtk_notebook_get_n_pages( notebook ) ) return false; + + // retrieve page and tab label + GtkWidget* page( gtk_notebook_get_nth_page( notebook, tab ) ); + GtkWidget* tabLabel( gtk_notebook_get_tab_label( notebook, page ) ); + + // get allocted size and compare to position + const GtkAllocation allocation( gtk_widget_get_allocation( tabLabel ) ); + return Gtk::gdk_rectangle_contains( &allocation, x, y ); + + } + + //________________________________________________________ + int Gtk::gtk_notebook_find_tab( GtkWidget* widget, int x, int y ) + { + + if( !GTK_IS_NOTEBOOK( widget ) ) return -1; + + // cast to notebook and check against number of pages + GtkNotebook* notebook( GTK_NOTEBOOK( widget ) ); + int tab(-1); + int minDistance( -1 ); + for( int i = gtk_notebook_find_first_tab( widget ); i < gtk_notebook_get_n_pages( notebook ); ++i ) + { + + // retrieve page and tab label + GtkWidget* page( gtk_notebook_get_nth_page( notebook, i ) ); + if( !page ) continue; + + // get label + GtkWidget* tabLabel( gtk_notebook_get_tab_label( notebook, page ) ); + if(!tabLabel) continue; + + // get allocted size and compare to position + const GtkAllocation allocation( gtk_widget_get_allocation( tabLabel ) ); + + // get manhattan length + const int distance = int( + std::abs( double( allocation.x + allocation.width/2 - x ) ) + + std::abs( double( allocation.y + allocation.height/2 - y ) ) ); + if( minDistance < 0 || distance < minDistance ) + { + tab = i; + minDistance = distance; + } + } + + return tab; + + } + + //________________________________________________________ + int Gtk::gtk_notebook_find_first_tab( GtkWidget* widget ) + { + + // TODO: reimplement with gtk+3.0 + return 0; + +// if( !GTK_IS_NOTEBOOK( widget ) ) return 0; +// +// // cast to notebook +// GtkNotebook* notebook( GTK_NOTEBOOK( widget ) ); +// return g_list_position( notebook->children, notebook->first_tab ); + + } + + //____________________________________________________________ + bool Gtk::gtk_notebook_is_tab_label(GtkNotebook* notebook, GtkWidget* widget ) + { + + for( int i = 0; i < gtk_notebook_get_n_pages( notebook ); ++i ) + { + // retrieve page and tab label + GtkWidget* page( gtk_notebook_get_nth_page( notebook, i ) ); + if( !page ) continue; + + GtkWidget* tabLabel( gtk_notebook_get_tab_label( notebook, page ) ); + if( widget == tabLabel ) return true; + } + + return false; + + } + + + //____________________________________________________________ + void Gtk::gtk_notebook_get_tabbar_rect( GtkNotebook* notebook, GdkRectangle* rect ) + { + // check notebook and rect + if( !( notebook && rect ) ) return; + + // check tab visibility + GList* children( gtk_container_get_children( GTK_CONTAINER( notebook ) ) ); + if( !( gtk_notebook_get_show_tabs( notebook ) && children ) ) + { + if( children ) g_list_free( children ); + *rect = gdk_rectangle(); + return; + } + + // free children + if( children ) g_list_free( children ); + + // get full rect + gtk_widget_get_allocation( GTK_WIDGET( notebook ), rect ); + + // adjust to account for borderwidth + guint borderWidth( gtk_container_get_border_width( GTK_CONTAINER( notebook ) ) ); + rect->x += borderWidth; + rect->y += borderWidth; + rect->height -= 2*borderWidth; + rect->width -= 2*borderWidth; + + // get current page + int pageIndex( gtk_notebook_get_current_page( notebook ) ); + if( !( pageIndex >= 0 && pageIndex < gtk_notebook_get_n_pages( notebook ) ) ) + { + *rect = gdk_rectangle(); + return; + } + + GtkWidget* page( gtk_notebook_get_nth_page( notebook, pageIndex ) ); + if( !page ) + { + *rect = gdk_rectangle(); + return; + } + + // removes page allocated size from rect, based on tabwidget orientation + const GtkAllocation pageAllocation( gtk_widget_get_allocation( page ) ); + switch( gtk_notebook_get_tab_pos( notebook ) ) + { + case GTK_POS_BOTTOM: + rect->y += pageAllocation.height; + rect->height -= pageAllocation.height; + break; + + case GTK_POS_TOP: + rect->height -= pageAllocation.height; + break; + + case GTK_POS_RIGHT: + rect->x += pageAllocation.width; + rect->width -= pageAllocation.width; + break; + + case GTK_POS_LEFT: + rect->width -= pageAllocation.width; + break; + } + + return; + + } + + //____________________________________________________________ + bool Gtk::gtk_notebook_has_visible_arrows( GtkNotebook* notebook ) + { + + if( !gtk_notebook_get_show_tabs( notebook ) ) return false; + + // loop over pages + for( int i = 0; i < gtk_notebook_get_n_pages( notebook ); ++i ) + { + + // retrieve page and tab label + GtkWidget* page( gtk_notebook_get_nth_page( notebook, i ) ); + if( !page ) continue; + + GtkWidget* label( gtk_notebook_get_tab_label( notebook, page ) ); + if( label && !gtk_widget_get_mapped( label ) ) return true; + } + + return false; + + } + + //____________________________________________________________ + bool Gtk::gtk_notebook_update_close_buttons(GtkNotebook* notebook) + { + int numPages=gtk_notebook_get_n_pages( notebook ); + for( int i = 0; i < numPages; ++i ) + { + + // retrieve page + GtkWidget* page( gtk_notebook_get_nth_page( notebook, i ) ); + if( !page ) continue; + + // retrieve tab label + GtkWidget* tabLabel( gtk_notebook_get_tab_label( notebook, page ) ); + if( tabLabel && GTK_IS_CONTAINER( tabLabel ) ) + { gtk_container_adjust_buttons_state( GTK_CONTAINER( tabLabel ) ); } + + } + return FALSE; + } + + //________________________________________________________ + bool Gtk::gtk_notebook_is_close_button(GtkWidget* widget) + { + if( GtkNotebook* nb=GTK_NOTEBOOK(gtk_parent_notebook(widget) ) ) + { + // check if the button resides on tab label, not anywhere on the tab + bool tabLabelIsParent=false; + for( int i=0; i < gtk_notebook_get_n_pages(nb); ++i ) + { + GtkWidget* tabLabel( gtk_notebook_get_tab_label(nb,gtk_notebook_get_nth_page( nb, i ) ) ); + if( gtk_widget_is_parent( widget, GTK_WIDGET(tabLabel) ) ) + { tabLabelIsParent=true; } + } + + if( !tabLabelIsParent ) return false; + + // make sure button has no text and some image (for now, just hope it's a close icon) + if( gtk_button_find_image(widget) && !gtk_button_get_label( GTK_BUTTON(widget) ) ) + { return true; } + + // check for pidgin 'x' close button + if( GtkWidget* label = gtk_button_find_label(widget) ) + { + + const gchar* labelText=gtk_label_get_text( GTK_LABEL(label) ); + if(!strcmp(labelText,"×")) // It's not letter 'x' - it's a special symbol + { + gtk_widget_hide( label ); + return true; + } else return false; + + } else return false; + + } else return false; + + } + + //________________________________________________________ + bool Gtk::gtk_scrolled_window_force_sunken( GtkWidget* widget) + { + + // FMIconView (from nautilus) always get sunken + if( g_object_is_a( G_OBJECT( widget ), "FMIconView" ) ) return true; + + // other checks require widget to be of type GtkBin + if( !GTK_IS_BIN( widget ) ) return false; + + // retrieve child + GtkWidget* child( gtk_bin_get_child( GTK_BIN( widget ) ) ); + if( GTK_IS_TREE_VIEW( child ) || GTK_IS_ICON_VIEW( child ) ) return true; + else return false; + + } + + //________________________________________________________ + bool Gtk::gdk_window_map_to_toplevel( GdkWindow* window, gint* x, gint* y, gint* w, gint* h, bool frame ) + { + + // always initialize arguments (to invalid values) + if( x ) *x=0; + if( y ) *y=0; + if( w ) *w = -1; + if( h ) *h = -1; + + if( !( window && GDK_IS_WINDOW( window ) ) ) return false; + if( gdk_window_get_window_type( window ) == GDK_WINDOW_OFFSCREEN ) return false; + + // get window size and height + if( frame ) gdk_toplevel_get_frame_size( window, w, h ); + else gdk_toplevel_get_size( window, w, h ); + Gtk::gdk_window_get_toplevel_origin( window, x, y ); + return ((!w) || *w > 0) && ((!h) || *h>0); + + } + + //________________________________________________________ + bool Gtk::gtk_widget_map_to_toplevel( GtkWidget* widget, gint* x, gint* y, gint* w, gint* h, bool frame ) + { + + // always initialize arguments (to invalid values) + if( x ) *x=0; + if( y ) *y=0; + if( w ) *w = -1; + if( h ) *h = -1; + + if( !widget ) return false; + + // get window + GdkWindow* window( gtk_widget_get_parent_window( widget ) ); + if( !( window && GDK_IS_WINDOW( window ) ) ) return false; + if( gdk_window_get_window_type( window ) == GDK_WINDOW_OFFSCREEN ) return false; + + if( frame ) gdk_toplevel_get_frame_size( window, w, h ); + else gdk_toplevel_get_size( window, w, h ); + int xlocal, ylocal; + const bool success( gtk_widget_translate_coordinates( widget, gtk_widget_get_toplevel( widget ), 0, 0, &xlocal, &ylocal ) ); + if( success ) + { + + if( x ) *x=xlocal; + if( y ) *y=ylocal; + + } + + return success && ((!w) || *w > 0) && ((!h) || *h>0); + + } + + //________________________________________________________ + bool Gtk::gtk_widget_map_to_parent( GtkWidget* widget, GtkWidget* parent, gint* x, gint* y, gint* w, gint* h ) + { + + // always initialize arguments (to invalid values) + if( x ) *x=0; + if( y ) *y=0; + if( w ) *w = -1; + if( h ) *h = -1; + + if( !( widget && parent ) ) return false; + + const GtkAllocation allocation( gtk_widget_get_allocation( parent ) ); + if( w ) *w = allocation.width; + if( h ) *h = allocation.height; + + int xlocal, ylocal; + const bool success( gtk_widget_translate_coordinates( widget, parent, 0, 0, &xlocal, &ylocal ) ); + if( success ) + { + + if( x ) *x=xlocal; + if( y ) *y=ylocal; + + } + + return success && ((!w) || *w > 0) && ((!h) || *h>0); + + } + + //________________________________________________________ + bool Gtk::gdk_window_translate_origin( GdkWindow* parent, GdkWindow* child, gint* x, gint* y ) + { + if( x ) *x = 0; + if( y ) *y = 0; + if( !( parent && child ) ) return false; + while( child && GDK_IS_WINDOW( child ) && + child != parent && + gdk_window_get_window_type( child ) == GDK_WINDOW_CHILD ) + { + gint xloc; + gint yloc; + gdk_window_get_position( child, &xloc, &yloc ); + if( x ) *x += xloc; + if( y ) *y += yloc; + child = gdk_window_get_parent( child ); + } + + return( child == parent ); + + } + + //________________________________________________________ + void Gtk::gdk_toplevel_get_size( GdkWindow* window, gint* w, gint* h ) + { + + if( !( window && GDK_IS_WINDOW( window ) ) ) + { + if( w ) *w = -1; + if( h ) *h = -1; + return; + } + + if( GdkWindow* topLevel = gdk_window_get_toplevel( window ) ) + { + + if( w ) *w = gdk_window_get_width( topLevel ); + if( h ) *h = gdk_window_get_height( topLevel ); + + } else { + + if( w ) *w = gdk_window_get_width( window ); + if( h ) *h = gdk_window_get_height( window ); + + } + + return; + + } + + //________________________________________________________ + void Gtk::gdk_toplevel_get_frame_size( GdkWindow* window, gint* w, gint* h ) + { + + if( !( window && GDK_IS_WINDOW( window ) ) ) + { + if( w ) *w = -1; + if( h ) *h = -1; + return; + } + + GdkWindow* topLevel = gdk_window_get_toplevel( window ); + if( topLevel && GDK_IS_WINDOW( topLevel ) ) + { + if( gdk_window_get_window_type( topLevel ) == GDK_WINDOW_OFFSCREEN ) + { + + if( w ) *w = gdk_window_get_width(topLevel); + if( h ) *h = gdk_window_get_height(topLevel); + + } else { + + GdkRectangle rect = {0, 0, -1, -1}; + gdk_window_get_frame_extents( topLevel, &rect ); + + if( w ) *w = rect.width; + if( h ) *h = rect.height; + + } + } + + return; + + } + + //________________________________________________________ + void Gtk::gdk_window_get_toplevel_origin( GdkWindow* window, gint* x, gint* y ) + { + if( x ) *x = 0; + if( y ) *y = 0; + if( !window ) return; + while( window && GDK_IS_WINDOW( window ) && gdk_window_get_window_type( window ) == GDK_WINDOW_CHILD ) + { + gint xloc; + gint yloc; + gdk_window_get_position( window, &xloc, &yloc ); + if( x ) *x += xloc; + if( y ) *y += yloc; + window = gdk_window_get_parent( window ); + } + + return; + } + + //___________________________________________________________ + GdkPixbuf* Gtk::gdk_pixbuf_set_alpha( const GdkPixbuf *pixbuf, double alpha ) + { + + g_return_val_if_fail( pixbuf != 0L, 0L); + g_return_val_if_fail( GDK_IS_PIXBUF( pixbuf ), 0L ); + + /* Returns a copy of pixbuf with it's non-completely-transparent pixels to + have an alpha level "alpha" of their original value. */ + GdkPixbuf* target( gdk_pixbuf_add_alpha( pixbuf, false, 0, 0, 0 ) ); + if( alpha >= 1.0 ) return target; + if( alpha < 0 ) alpha = 0; + + const int width( gdk_pixbuf_get_width( target ) ); + const int height( gdk_pixbuf_get_height( target ) ); + const int rowstride( gdk_pixbuf_get_rowstride( target ) ); + unsigned char* data = gdk_pixbuf_get_pixels( target ); + + for( int y = 0; y < height; ++y ) + { + + for( int x = 0; x < width; ++x ) + { + /* The "4" is the number of chars per pixel, in this case, RGBA, + the 3 means "skip to the alpha" */ + unsigned char* current = data + ( y*rowstride ) + ( x*4 ) + 3; + *(current) = (unsigned char) ( *( current )*alpha ); + } + } + + return target; + } + + //_________________________________________________________ + bool Gtk::gdk_pixbuf_to_gamma(GdkPixbuf* pixbuf, double value) + { + if(gdk_pixbuf_get_colorspace(pixbuf)==GDK_COLORSPACE_RGB && + gdk_pixbuf_get_bits_per_sample(pixbuf)==8 && + gdk_pixbuf_get_has_alpha(pixbuf) && + gdk_pixbuf_get_n_channels(pixbuf)==4) + { + double gamma=1./(2.*value+0.5); + unsigned char* data=gdk_pixbuf_get_pixels(pixbuf); + const int height=gdk_pixbuf_get_height(pixbuf); + const int width=gdk_pixbuf_get_width(pixbuf); + const int rowstride=gdk_pixbuf_get_rowstride(pixbuf); + for(int x=0;x<width;++x) + { + for(int y=0; y<height; y++) + { + unsigned char* p=data + y*rowstride + x*4; + *p=(char)(pow((*p/255.),gamma)*255); ++p; + *p=(char)(pow((*p/255.),gamma)*255); ++p; + *p=(char)(pow((*p/255.),gamma)*255); + } + + } + + return true; + + } else return false; + + } + + //___________________________________________________________ + GdkPixbuf* Gtk::gdk_pixbuf_resize( GdkPixbuf* src, int width, int height ) + { + if( width == gdk_pixbuf_get_width( src ) && height == gdk_pixbuf_get_height( src ) ) + { + + return static_cast<GdkPixbuf*>(g_object_ref (src)); + + } else { + + return gdk_pixbuf_scale_simple( src, width, height, GDK_INTERP_BILINEAR ); + + } + + } + + //___________________________________________________________ + void Gtk::gtk_viewport_get_position( GtkViewport* viewport, gint* x, gint* y ) + { + + // initialize + if( x ) *x = 0; + if( y ) *y = 0; + + // get windows and derive offsets + gint xBin(0), yBin(0); + gdk_window_get_geometry( gtk_viewport_get_bin_window( viewport ), &xBin, &yBin, 0, 0 ); + + gint xView(0), yView(0); + gdk_window_get_geometry( gtk_viewport_get_view_window( viewport ), &xView, &yView, 0, 0 ); + + // calculate offsets + if( x ) *x = xView - xBin; + if( y ) *y = yView - yBin; + + // also correct from widget thickness + GtkStyle* style( gtk_widget_get_style( GTK_WIDGET( viewport ) ) ); + if( style ) + { + if( x ) *x -= style->xthickness; + if( y ) *y -= style->ythickness; + } + + return; + + } + + //___________________________________________________________ + GtkWidget* Gtk::gtk_dialog_find_button(GtkDialog* dialog,gint response_id) + { + + // get children of dialog's action area + GList* children( gtk_container_get_children( GTK_CONTAINER( gtk_dialog_get_action_area( dialog ) ) ) ); + + #if OXYGEN_DEBUG + std::cerr << "Oxygen::Gtk::gtk_dialog_find_button - buttons: "; + #endif + + for( GList *child = g_list_first( children ); child; child = g_list_next( child ) ) + { + + // check data + if( !GTK_IS_WIDGET( child->data ) ) continue; + GtkWidget* childWidget( GTK_WIDGET( child->data ) ); + + const gint id( gtk_dialog_get_response_for_widget(dialog, childWidget ) ); + + #if OXYGEN_DEBUG + std::cerr << Gtk::TypeNames::response( (GtkResponseType) id ) << ", "; + #endif + if( id == response_id ) return childWidget; + + } + + #if OXYGEN_DEBUG + std::cerr << std::endl; + #endif + + if( children ) g_list_free( children ); + return 0L; + + } + diff --git a/tdegtk/tdegtk-utils.h b/tdegtk/tdegtk-utils.h new file mode 100644 index 0000000..0b97689 --- /dev/null +++ b/tdegtk/tdegtk-utils.h @@ -0,0 +1,428 @@ +#ifndef tdegtk_utils_h +#define tdegtk_utils_h +/* +* this file was largely taken from the oxygen gtk engine +* Copyright (c) 2010 Hugo Pereira Da Costa <hugo@oxygen-icons.org> +* Copyright (c) 2010 Ruslan Kabatsayev <b7.10110111@gmail.com> +* +* GdkPixbuf modification code from Walmis +* <http://gnome-look.org/content/show.php?content=77783&forumpage=3> +* +* 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., 51 Franklin St, Fifth Floor, Boston, +* MA 02110-1301, USA. +*/ + +// #include "oxygenrgba.h" + +#include <gdk/gdk.h> +#include <gtk/gtk.h> + +#include <cmath> +#include <string> + +#if 0 + //! GdkRectangle streamer + inline std::ostream& operator << (std::ostream& out, const GdkRectangle& rect ) + { + out << "( " << rect.x << "," << rect.y << "," << rect.width << "," << rect.height << ")"; + return out; + } + + //! GtkBorder streamer + inline std::ostream& operator << (std::ostream& out, const GtkBorder& border ) + { + out << "( " << border.left << "," << border.right << "," << border.top << "," << border.bottom << ")"; + return out; + } + + //! streamer for GtkWidgetPath + std::ostream& operator << ( std::ostream& out, const GtkWidgetPath* path ); + + //! GtkContainer streamer + inline std::ostream& operator << (std::ostream& out, GtkContainer* container) + { + GList* children=gtk_container_get_children(container); + for(GList* child=g_list_first(children); child; child=g_list_next(child)) + { + out << G_OBJECT_TYPE_NAME(child->data) << " "; + } + g_list_free(children); + return out; + } +#endif + + namespace Gtk + { + + //! mouse button enumeration + enum MouseButton + { + NoButton = 0, + LeftButton = 1, + RightButton = 2, + MidButton = 3 + }; + + //@!name gdk utilities + //@{ + +#if 0 + //! returns OxygenRgba color from GdkColor + /*! TODO: remove as obsolete */ + inline ColorUtils::Rgba gdk_get_color( const GdkColor& color ) + { + return ColorUtils::Rgba( + double(color.red)/0xffff, + double(color.green)/0xffff, + double(color.blue)/0xffff ); + } + + //! returns OxygenRgba color from GdkColor + inline ColorUtils::Rgba gdk_get_color( const GdkRGBA& color ) + { return ColorUtils::Rgba( color.red, color.green, color.blue, color.alpha ); } +#endif + + //! map widget origin to top level + /*! + x and y correspond to (0,0) maped to toplevel window; + w and h correspond to toplevel window frame size + */ + bool gdk_window_map_to_toplevel( GdkWindow*, gint*, gint*, gint*, gint*, bool frame = false ); + + //! map widget origin to top level + /*! + x and y correspond to (0,0) maped to toplevel window; + w and h correspond to toplevel window frame size + */ + bool gtk_widget_map_to_toplevel( GtkWidget*, gint*, gint*, gint*, gint*, bool frame = false ); + + //! map widget onto another (parent) widget + /*! second argument can be any parent in widget's ancestry tree */ + bool gtk_widget_map_to_parent( GtkWidget*, GtkWidget*, gint*, gint*, gint*, gint* ); + + //! map window/widget origin to top level + inline bool gdk_map_to_toplevel( GdkWindow* window, GtkWidget* widget, gint* x, gint* y, gint* w, gint* h, bool frame = false ) + { + if( window && GDK_IS_WINDOW( window ) ) return gdk_window_map_to_toplevel( window, x, y, w, h, frame ); + else return gtk_widget_map_to_toplevel( widget, x, y, w, h, frame ); + } + + //! map window origin to top level + inline bool gdk_map_to_toplevel( GdkWindow* window, gint* x, gint* y, gint* w, gint* h, bool frame = false ) + { return gdk_window_map_to_toplevel( window, x, y, w, h, frame ); } + + //! translate origin of child window into parent + /*! returns true on success */ + bool gdk_window_translate_origin( GdkWindow*, GdkWindow*, gint*, gint* ); + + //! get top level windows dimension + void gdk_toplevel_get_size( GdkWindow*, gint*, gint* ); + + //! get top level windows dimension + void gdk_toplevel_get_frame_size( GdkWindow*, gint*, gint* ); + + //! get position relatve to toplevel + void gdk_window_get_toplevel_origin( GdkWindow*, gint*, gint* ); + + //! add alpha channel to pixbuf + GdkPixbuf* gdk_pixbuf_set_alpha( const GdkPixbuf*, double ); + + //! changes the gamma value of an image + bool gdk_pixbuf_to_gamma( GdkPixbuf* pixbuf, double value ); + + //! resize pixbuf + GdkPixbuf* gdk_pixbuf_resize( GdkPixbuf* src, int width, int height ); + + //! returns initialized GdkRectangle + inline GdkRectangle gdk_rectangle( int x = 0, int y = 0, int w = -1, int h = -1 ) + { + GdkRectangle out = {x, y, w, h}; + return out; + } + + //! returns true if rectangle is valid + inline bool gdk_rectangle_is_valid( const GdkRectangle* rect ) + { return rect && rect->width > 0 && rect->height > 0; } + + //! performs union of two rectangle, properly accounting for their validity + inline void gdk_rectangle_union( const GdkRectangle* first, const GdkRectangle* second, GdkRectangle* out ) + { + if( !out ) return; + const bool firstIsValid( Gtk::gdk_rectangle_is_valid( first ) ); + const bool secondIsValid( Gtk::gdk_rectangle_is_valid( second ) ); + if( firstIsValid && secondIsValid ) ::gdk_rectangle_union( first, second, out ); + else if( secondIsValid ) *out = *second; + else *out = *first; + } + + //! returns true if given rectangle contains point + inline bool gdk_rectangle_contains( const GdkRectangle* rect, int x, int y ) + { + return + rect && + ( rect->x <= x && (rect->x + rect->width) > x ) && + ( rect->y <= y && (rect->y + rect->height) > y ); + } + + //@} + + //! get arrow orientation from angle + inline GtkArrowType gtk_arrow_get_type( const double& angle ) + { + static const double delta( 0.001 ); + if( std::abs( angle ) < delta ) return GTK_ARROW_UP; + else if( std::abs( angle - M_PI/2 ) < delta ) return GTK_ARROW_RIGHT; + else if( std::abs( angle - M_PI ) < delta ) return GTK_ARROW_DOWN; + else return GTK_ARROW_LEFT; + } + + //! returns true if widget's layout is reversed + inline bool gtk_widget_layout_is_reversed( GtkWidget* widget ) + { return widget ? gtk_widget_get_direction( widget ) == GTK_TEXT_DIR_RTL : false; } + + //! returns true if widget's layout is reversed + inline bool gtk_theming_engine_layout_is_reversed( GtkThemingEngine* engine ) + { return engine ? gtk_theming_engine_get_direction( engine ) == GTK_TEXT_DIR_RTL : false; } + + //! set all buttons in the container to state NORMAL + void gtk_container_adjust_buttons_state( GtkContainer*, gpointer=0L ); + + //! returns widget allocation + inline GtkAllocation gtk_widget_get_allocation( GtkWidget* widget ) + { + GtkAllocation allocation = { 0, 0, -1, -1 }; + ::gtk_widget_get_allocation( widget, &allocation ); + return allocation; + } + + //! returns true if given path as given type + bool gtk_widget_path_has_type( const GtkWidgetPath*, GType ); + + //! returns true if widget is a groupbox (a la Qt) + inline bool gtk_widget_is_groupbox( GtkWidget* widget ) + { + return + GTK_IS_FRAME( widget ) && + gtk_frame_get_label_widget( GTK_FRAME( widget ) ) && + gtk_frame_get_shadow_type( GTK_FRAME( widget ) ) == GTK_SHADOW_OUT; + } + + //! returns true if widget (or one of its parent) has a custom background + bool gtk_widget_has_custom_background( GtkWidget*, GtkStateType = GTK_STATE_NORMAL ); + + //! returns true if is an Gnome applet + bool gtk_widget_is_applet( GtkWidget* ); + + //! print some widget information + void gtk_widget_print_tree( GtkWidget* ); + + //! returns true if widget supports rgba + bool gtk_widget_has_rgba( GtkWidget* ); + + //! returns true if default screen is composited + bool gdk_default_screen_is_composited( void ); + + //! returns true if window supports rgba + bool gdk_window_has_rgba( GdkWindow* ); + + //! true if visual supports rgba + bool gdk_visual_has_rgba( GdkVisual* ); + + //! returns true if window is a base window + bool gdk_window_is_base( GdkWindow* ); + + //! returns true if window is a base window that do not need painting + bool gdk_window_nobackground( GdkWindow* ); + + //! true if object match a given type + bool g_object_is_a( const GObject*, const std::string& ); + + //! trigger area update using GdkRectangle + inline void gtk_widget_queue_draw( GtkWidget* widget, const GdkRectangle* rect = 0L ) + { + if( !gdk_rectangle_is_valid( rect ) ) ::gtk_widget_queue_draw( widget ); + else ::gtk_widget_queue_draw_area( widget, rect->x, rect->y, rect->width, rect->height ); + } + + //!@name check parent type + //@{ + + //! returns widget path as a string + std::string gtk_widget_path( GtkWidget* ); + + //! return parent of given type if any + GtkWidget* gtk_widget_find_parent( GtkWidget*, GType ); + + //! return parent of given type + inline GtkWidget* gtk_widget_find_parent( GtkWidget* widget, const std::string& typeName ) + { + const GType tmp( g_type_from_name( typeName.c_str() ) ); + return tmp ? gtk_widget_find_parent( widget, tmp ): 0L; + } + + //! return parent "group box" if any. + GtkWidget* gtk_parent_groupbox( GtkWidget* widget ); + + //! return parent button if any. + inline GtkWidget* gtk_parent_button( GtkWidget* widget ) + { return gtk_widget_find_parent( widget, GTK_TYPE_BUTTON ); } + + //! return parent menu if any + inline GtkWidget* gtk_parent_menubar( GtkWidget* widget ) + { return gtk_widget_find_parent( widget, GTK_TYPE_MENU_BAR ); } + + //! return parent menu if any + inline GtkWidget* gtk_parent_menu( GtkWidget* widget ) + { return gtk_widget_find_parent( widget, GTK_TYPE_MENU ); } + + //! return parent treeview if any. + inline GtkWidget* gtk_parent_tree_view( GtkWidget* widget ) + { return gtk_widget_find_parent( widget, GTK_TYPE_TREE_VIEW ); } + + //! return parent combobox if any. + inline GtkWidget* gtk_parent_combobox( GtkWidget* widget ) + { return gtk_widget_find_parent( widget, GTK_TYPE_COMBO_BOX ); } + + //! return parent combobox if any. + inline GtkWidget* gtk_parent_combobox_entry( GtkWidget* widget ) + { + GtkWidget* parent( gtk_parent_combobox( widget ) ); + return ( parent && gtk_combo_box_get_has_entry( GTK_COMBO_BOX( parent ) ) ) ? parent:0L; + } + + //! return parent scrolled window if any. + inline GtkWidget* gtk_parent_scrolled_window( GtkWidget* widget ) + { return gtk_widget_find_parent( widget, GTK_TYPE_SCROLLED_WINDOW ); } + + //! return parent statusbar if any. + inline GtkWidget* gtk_parent_statusbar( GtkWidget* widget ) + { return gtk_widget_find_parent( widget, GTK_TYPE_STATUSBAR ); } + + //! return parent combobox if any. + inline GtkWidget* gtk_parent_notebook( GtkWidget* widget ) + { return gtk_widget_find_parent( widget, GTK_TYPE_NOTEBOOK ); } + + //! returns true if potentialParent is (maybe indirect) parent of widget + bool gtk_widget_is_parent( GtkWidget*, GtkWidget* potentialParent ); + + //! returns true if one of the parent widgets has a sunken shadow + bool gtk_parent_is_shadow_in( GtkWidget* ); + + //@} + + //! true if a widget (orientable) is horizontal + inline bool gtk_widget_is_horizontal( GtkWidget* widget ) + { + if( !GTK_IS_ORIENTABLE( widget ) ) return true; + return gtk_orientable_get_orientation( GTK_ORIENTABLE( widget ) ) == GTK_ORIENTATION_HORIZONTAL; + } + + + //! true if a widget (orientable) is vertical + inline bool gtk_widget_is_vertical( GtkWidget* widget ) + { + if( !GTK_IS_ORIENTABLE( widget ) ) return false; + return gtk_orientable_get_orientation( GTK_ORIENTABLE( widget ) ) == GTK_ORIENTATION_VERTICAL; + } + + //! true if scrolled window must be forced to have a sunken frame + bool gtk_scrolled_window_force_sunken( GtkWidget* ); + + //!@name button utilities + //@{ + + //! true for 'flat' buttons (e.g. toolbuttons) + bool gtk_button_is_flat( GtkWidget* ); + + //! true for treeview headers and affiliated + bool gtk_button_is_header( GtkWidget* ); + + //! true for buttons in path bars + bool gtk_button_is_in_path_bar( GtkWidget* widget ); + + //! true if widget is last in path bar + bool gtk_path_bar_button_is_last( GtkWidget* widget ); + + //! returns an image on button-container + GtkWidget* gtk_button_find_image( GtkWidget* ); + + //! returns an image on button-container + GtkWidget* gtk_button_find_label( GtkWidget* ); + + //@} + + //!@name combobox utilities + //@{ + + //! returns true if combobox has frame + bool gtk_combobox_has_frame( GtkWidget* ); + + //! true if widget is the treeview of a combobox + bool gtk_combobox_is_tree_view( GtkWidget* ); + + //! true if widget is the treeview of a combobox + bool gtk_combobox_is_scrolled_window( GtkWidget* ); + + //! true if widget is the treeview of a combobox + bool gtk_combobox_is_viewport( GtkWidget* ); + + //! true if widget is the treeview of a combobox + bool gtk_combobox_is_frame( GtkWidget* ); + + //! true if combobox must appear as list + bool gtk_combobox_appears_as_list( GtkWidget* ); + + //@} + + //!@name notebook utilities + //@{ + + //! returns true if position is in hovered tab + //* this should move to OxygenTabWidgetData + bool gtk_notebook_tab_contains( GtkWidget*, int tab, int x, int y ); + + //! returns tab matching position or -1 if none + int gtk_notebook_find_tab( GtkWidget*, int x, int y ); + + //! returns index of first visible tab + int gtk_notebook_find_first_tab( GtkWidget* ); + + //! returns true if widget is one of the notebook's tab labels + bool gtk_notebook_is_tab_label( GtkNotebook*, GtkWidget* ); + + //! returns tabbar rect in notebook + void gtk_notebook_get_tabbar_rect( GtkNotebook*, GdkRectangle* ); + + //! returns true if notebook has visible scrollbar arrows + /*! arrows are dimmed visible if at least one of the child tab_labels is unmapped */ + bool gtk_notebook_has_visible_arrows( GtkNotebook* ); + + // make all the buttons on the tabs normal + bool gtk_notebook_update_close_buttons( GtkNotebook*); + + //! returns true if widget is a notebook close button + bool gtk_notebook_is_close_button( GtkWidget* ); + + //@} + + //! calculates viewport offsets (between view window and bin window + void gtk_viewport_get_position( GtkViewport*, gint*, gint* ); + + //! returns a widget which has response_id as response id for dialog + GtkWidget* gtk_dialog_find_button( GtkDialog*, gint ); + + } + +#endif diff --git a/tdegtk/tdegtk-widgetlookup.cpp b/tdegtk/tdegtk-widgetlookup.cpp new file mode 100644 index 0000000..79ed0e9 --- /dev/null +++ b/tdegtk/tdegtk-widgetlookup.cpp @@ -0,0 +1,231 @@ +/* +* this file was largely taken from the oxygen gtk engine +* Copyright (c) 2010 Hugo Pereira Da Costa <hugo@oxygen-icons.org> +* Copyright (c) 2010 Ruslan Kabatsayev <b7.10110111@gmail.com> +* +* Hook-setup code provided by Ruslan +* +* 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., 51 Franklin St, Fifth Floor, Boston, +* MA 02110-1301, USA. +*/ + +#include "tdegtk-widgetlookup.h" +#include "config.h" + +#include <iostream> +#include <cairo/cairo-gobject.h> + +// #define TDEGTK_DEBUG 1 + + //__________________________________________________________________ + WidgetLookup::WidgetLookup( void ): + _hooksInitialized( false ), + _context( 0L ) + {} + + + //_____________________________________________________ + WidgetLookup::~WidgetLookup( void ) + { + + // disconnect hooks + _drawHook.disconnect(); + + } + + //_____________________________________________________ + void WidgetLookup::initializeHooks( void ) + { + + #if TDEGTK_DEBUG + std::cerr << "Oxygen::WidgetLookup::initializeHooks" << std::endl; + #endif + + if( _hooksInitialized ) return; + + // install hook and test + if( !_drawHook.connect( "draw", (GSignalEmissionHook)drawHook, this ) ) return; + + // set initialization flag + _hooksInitialized = true; + + return; + + } + + //_____________________________________________________ + GtkWidget* WidgetLookup::find( cairo_t* context, const GtkWidgetPath* path ) const + { + + // check path + if( !path ) return 0L; + + // get length and check + const gint length( gtk_widget_path_length( path ) ); + if( length < 1 ) return 0L; + + // lookup last type + return find( context, gtk_widget_path_iter_get_object_type( path, length-1 ) ); + + } + + //_____________________________________________________ + GtkWidget* WidgetLookup::find( cairo_t* context, GType type ) const + { + // check context + if( context != _context ) + { + #if TDEGTK_DEBUG + std::cerr << "Oxygen::WidgetLookup::find - invalid context: " << context << std::endl; + #endif + return 0L; + } + + #if TDEGTK_DEBUG + std::cerr + << "Oxygen::WidgetLookup::find -" + << " context: " << context + << " type: " << g_type_name( type ) + << std::endl; + #endif + + // look for type in stored widgets + /* we loop backward, since last added widgets are more likely to be looked up */ + for( WidgetList::const_reverse_iterator iter = _widgets.rbegin(); iter != _widgets.rend(); ++iter ) + { + // compare types and return if matched + if( G_OBJECT_TYPE( *iter ) == type ) + { + #if TDEGTK_DEBUG + std::cerr + << "Oxygen::WidgetLookup::find -" + << " context: " << context + << " type: " << g_type_name( type ) + << " found: " << *iter + << std::endl; + #endif + return *iter; + } + } + + #if TDEGTK_DEBUG + std::cerr + << "Oxygen::WidgetLookup::find -" + << " context: " << context + << " type: " << g_type_name( type ) + << " - no match found" + << std::endl; + #endif + + return 0L; + + } + + //_____________________________________________________ + void WidgetLookup::bind( GtkWidget* widget, cairo_t* context ) + { + // check if context has changed and clear widgets if yes + if( context != _context ) + { + + #if TDEGTK_DEBUG + std::cerr + << "Oxygen::WidgetLookup::bind -" + << " context: " << _context + << " widgets: " << _widgets.size() + << std::endl; + #endif + + _context = context; + _widgets.clear(); + } + + _widgets.push_back( widget ); + + // add to all widgets map + if( _allWidgets.find( widget ) == _allWidgets.end() ) + { + Signal destroyId; + destroyId.connect( G_OBJECT( widget ), "destroy", G_CALLBACK( destroyNotifyEvent ), this ); + _allWidgets.insert( std::make_pair( widget, destroyId ) ); + } + + } + + //____________________________________________________________________________________________ + void WidgetLookup::unregisterWidget( GtkWidget* widget ) + { + + #if TDEGTK_DEBUG + std::cerr << "Oxygen::WidgetLookup::unregisterWidget - " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" << std::endl; + #endif + + // find in map + WidgetMap::iterator iter( _allWidgets.find( widget ) ); + assert( iter != _allWidgets.end() ); + + // disconnect signal + iter->second.disconnect(); + + // erase from lists + _allWidgets.erase( widget ); + _widgets.remove( widget ); + + } + + //_____________________________________________________ + gboolean WidgetLookup::drawHook( GSignalInvocationHint*, guint numParams, const GValue* params, gpointer data ) + { + + // check number of parameters + if( numParams < 2 ) return FALSE; + + // get widget from params + GtkWidget* widget( GTK_WIDGET( g_value_get_object( params ) ) ); + + // check type + if( !GTK_IS_WIDGET( widget ) ) return FALSE; + + // check second parameter type. + if( !G_VALUE_HOLDS( params+1, CAIRO_GOBJECT_TYPE_CONTEXT ) ) + { return FALSE; } + + // retrieve context and cast + cairo_t* context( static_cast<cairo_t*>( g_value_get_boxed(params+1) ) ); + + #if TDEGTK_DEBUG + std::cerr + << "Oxygen::WidgetLookup::drawHook -" + << " widget: " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")" + << " context: " << context + << std::endl; + #endif + + // bind widget and context + static_cast<WidgetLookup*>( data )->bind( widget, context ); + + return TRUE; + + } + + + //____________________________________________________________________________________________ + gboolean WidgetLookup::destroyNotifyEvent( GtkWidget* widget, gpointer data ) + { + static_cast<WidgetLookup*>(data)->unregisterWidget( widget ); + return FALSE; + } + + diff --git a/tdegtk/tdegtk-widgetlookup.h b/tdegtk/tdegtk-widgetlookup.h new file mode 100644 index 0000000..98a7b96 --- /dev/null +++ b/tdegtk/tdegtk-widgetlookup.h @@ -0,0 +1,92 @@ +#ifndef tdegtk_widgetlookup_h +#define tdegtk_widgetlookup_h +/* +* this file was largely taken from the oxygen gtk engine +* Copyright (c) 2010 Hugo Pereira Da Costa <hugo@oxygen-icons.org> +* Copyright (c) 2010 Ruslan Kabatsayev <b7.10110111@gmail.com> +* +* 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., 51 Franklin St, Fifth Floor, Boston, +* MA 02110-1301, USA. +*/ + +#include "tdegtk-hooks.h" +#include "tdegtk-signals.h" + +#include <cairo/cairo.h> +#include <gtk/gtk.h> + +#include <list> +#include <map> + + + //! uses the widget's "draw" signal to bind GtkWidget and cairo context + /*! this allows us to retrieve painted widgets from ThemingEngine rendering primitives */ + class WidgetLookup + { + + public: + + //! constructor + explicit WidgetLookup( void ); + + //! destructor + virtual ~WidgetLookup( void ); + + //! initialize hooks + void initializeHooks( void ); + + //! find widget matching given context and type + GtkWidget* find( cairo_t*, const GtkWidgetPath* ) const; + + //! find widget matching given context and type + GtkWidget* find( cairo_t*, GType ) const; + + protected: + + //! bind widget to context + void bind( GtkWidget*, cairo_t* ); + + //! unregister widget + void unregisterWidget( GtkWidget* ); + + //! hook connected to widget's "draw" signal + static gboolean drawHook( GSignalInvocationHint*, guint, const GValue*, gpointer ); + + //! destruction callback + static gboolean destroyNotifyEvent( GtkWidget*, gpointer ); + + private: + + //! true if hooks are initialized + bool _hooksInitialized; + + //! hook connected to widget's "draw" signal + Hook _drawHook; + + //! store current context + cairo_t* _context; + + //! store list of associated widgets, to keep track of destruction + typedef std::list<GtkWidget*> WidgetList; + WidgetList _widgets; + + //! keep track of all registered widgets, and associated destroy callback + typedef std::map< GtkWidget*, Signal > WidgetMap; + WidgetMap _allWidgets; + + }; + +#endif + diff --git a/tdegtk/tqtcairopainter.cpp b/tdegtk/tqtcairopainter.cpp index c19a736..6d3b2cf 100644 --- a/tdegtk/tqtcairopainter.cpp +++ b/tdegtk/tqtcairopainter.cpp @@ -327,16 +327,16 @@ void TQt3CairoPaintDevice::transferIntermediateSurface() { if (!m_clipRegionEnabled) { // Clipping disabled - cairo_set_source_surface(m_devicePainter, m_intermediateSurface, 0, 0); + cairo_set_source_surface(m_devicePainter, m_intermediateSurface, m_offsetX, m_offsetY); cairo_set_operator(m_devicePainter, overlayMerge?CAIRO_OPERATOR_OVER:CAIRO_OPERATOR_SOURCE); cairo_paint(m_devicePainter); } else { // Clipping enabled cairo_surface_t* maskSurface = TQImageToCairoSurface(m_clipRegion); - cairo_set_source_surface(m_devicePainter, m_intermediateSurface, 0, 0); + cairo_set_source_surface(m_devicePainter, m_intermediateSurface, m_offsetX, m_offsetY); cairo_set_operator(m_devicePainter, overlayMerge?CAIRO_OPERATOR_OVER:CAIRO_OPERATOR_SOURCE); - cairo_mask_surface(m_devicePainter, maskSurface, 0, 0); + cairo_mask_surface(m_devicePainter, maskSurface, m_offsetX, m_offsetY); cairo_surface_destroy(maskSurface); } @@ -1083,16 +1083,18 @@ void TQt3CairoPaintDevice::setCairoTransformations() { Constructs TQt3CairoPaintDevice on an existing QPainter */ -TQt3CairoPaintDevice::TQt3CairoPaintDevice( cairo_surface_t *cairosurface, int width, int height, cairo_t *overridepainter ) +TQt3CairoPaintDevice::TQt3CairoPaintDevice( cairo_surface_t *cairosurface, int x, int y, int width, int height, cairo_t *overridepainter ) : TQPaintDevice( TQInternal::Picture | TQInternal::ExternalDevice ) { init(); + m_offsetX = x; + m_offsetY = y; if (width >= 0) { m_width = width; } if (height >= 0) { - m_height = width; + m_height = height; } if (overridepainter) { m_overridePainter = overridepainter; @@ -1138,6 +1140,8 @@ TQt3CairoPaintDevice::~TQt3CairoPaintDevice() void TQt3CairoPaintDevice::init() { m_width = -1; m_height = -1; + m_offsetX = 0; + m_offsetY = 0; m_intermediateSurface = NULL; m_painter = NULL; diff --git a/tdegtk/tqtcairopainter.h b/tdegtk/tqtcairopainter.h index 20a03d3..67ccd79 100644 --- a/tdegtk/tqtcairopainter.h +++ b/tdegtk/tqtcairopainter.h @@ -40,7 +40,7 @@ typedef TQPtrStack<TQWMatrix> TQWMatrixStack; class Q_EXPORT TQt3CairoPaintDevice : public TQPaintDevice // picture class { public: - TQt3CairoPaintDevice( cairo_surface_t *, int width = -1, int height = -1, cairo_t *overridepainter = NULL ); + TQt3CairoPaintDevice( cairo_surface_t *, int x = 0, int y = 0, int width = -1, int height = -1, cairo_t *overridepainter = NULL ); ~TQt3CairoPaintDevice(); protected: @@ -75,6 +75,8 @@ class Q_EXPORT TQt3CairoPaintDevice : public TQPaintDevice // picture class private: mutable int m_width; mutable int m_height; + mutable int m_offsetX; + mutable int m_offsetY; cairo_surface_t *m_surface; cairo_surface_t *m_intermediateSurface; diff --git a/tests/compare b/tests/compare new file mode 100755 index 0000000..83726c5 --- /dev/null +++ b/tests/compare @@ -0,0 +1,3 @@ +#!/bin/bash + +composite -compose subtract tqt3.png stroke.png diff.png diff --git a/tests/test-painter.cpp b/tests/test-painter.cpp index 3c21432..f912009 100644 --- a/tests/test-painter.cpp +++ b/tests/test-painter.cpp @@ -257,6 +257,96 @@ void runTests(TQPaintDevice* pd) { cg.setColor(TQColorGroup::Foreground, TQColor(0,0,0)); tqApp->style().drawPrimitive(TQStyle::PE_ExclusiveIndicator, &p, TQRect(400, 400, 16, 16), cg, TQStyle::Style_Down); + // Tab bar tab tests + { + int currentPage; + int numPages=3; + int tabIndex=2; + + int x = 0; + int y = 300; + int width = 50; + int height = 20; + + for (currentPage=0;currentPage<numPages;currentPage++) { + TQRect boundingRect(0, 0, width, height); + + TQStringList objectTypes; + objectTypes.append(TQTABBAR_OBJECT_NAME_STRING); + TQPalette objectPalette = tqApp->palette(objectTypes); + + TQStyleControlElementData ceData; + TQStyle::ControlElementFlags elementFlags; + ceData.widgetObjectTypes = objectTypes; + ceData.rect = boundingRect; + + TQTab tqt3Tab; + tqt3Tab.setIdentifier(currentPage); + TQStyleOption tabOpt(&tqt3Tab, (TQTab*)NULL); + + elementFlags = elementFlags | TQStyle::CEF_HasParentWidget; + ceData.parentWidgetData.widgetObjectTypes.append(TQTABBAR_OBJECT_NAME_STRING); + + int tab_overlap = tqApp->style().pixelMetric(TQStyle::PM_TabBarTabOverlap); + x = x + width + tab_overlap; + + boundingRect = TQRect(x, y, width+(tab_overlap*2), height); + + ceData.tabBarData.shape = TQTabBar::RoundedAbove; + ceData.tabBarData.tabCount = numPages; + ceData.tabBarData.identIndexMap[tqt3Tab.identifier()] = currentPage; + + TQColorGroup cg = tqApp->palette().active(); + + // Draw tab + tqApp->style().drawControl(TQStyle::CE_TabBarTab, &p, ceData, elementFlags, boundingRect, cg, ((tabIndex==currentPage)?TQStyle::Style_Selected:TQStyle::Style_Default), tabOpt); + } + } + { + int currentPage; + int numPages=3; + int tabIndex=2; + + int x = (50*4); + int y = 325; + int width = 50; + int height = 20; + + for (currentPage=(numPages-1);currentPage>=0;currentPage--) { + TQRect boundingRect(0, 0, width, height); + + TQStringList objectTypes; + objectTypes.append(TQTABBAR_OBJECT_NAME_STRING); + TQPalette objectPalette = tqApp->palette(objectTypes); + + TQStyleControlElementData ceData; + TQStyle::ControlElementFlags elementFlags; + ceData.widgetObjectTypes = objectTypes; + ceData.rect = boundingRect; + + TQTab tqt3Tab; + tqt3Tab.setIdentifier(currentPage); + TQStyleOption tabOpt(&tqt3Tab, (TQTab*)NULL); + + elementFlags = elementFlags | TQStyle::CEF_HasParentWidget; + ceData.parentWidgetData.widgetObjectTypes.append(TQTABBAR_OBJECT_NAME_STRING); + + int tab_overlap = tqApp->style().pixelMetric(TQStyle::PM_TabBarTabOverlap); + x = x - width - tab_overlap; + + boundingRect = TQRect(x, y, width+(tab_overlap*2), height); + + ceData.tabBarData.shape = TQTabBar::RoundedAbove; + ceData.tabBarData.tabCount = numPages; + ceData.tabBarData.identIndexMap[tqt3Tab.identifier()] = currentPage; + + TQColorGroup cg = tqApp->palette().active(); + + // Draw tab + tqApp->style().drawControl(TQStyle::CE_TabBarTab, &p, ceData, elementFlags, boundingRect, cg, ((tabIndex==currentPage)?TQStyle::Style_Selected:TQStyle::Style_Default), tabOpt); + } + } + p.end(); } |