Benoît Minisini 71af715f2a [GB.GTK]
* BUG: Fix the Draw.Text() and Draw.RichText() functions when the alignment 
  argument is used.
* NEW: Paint.Text() and Paint.RichText() were implemented.
* NEW: Paint.LinearGradient() and Paint.RadialGradient() were implemented.

[GB.QT4]
* BUG: Paint.ArcTo() should take angles in radian now.


git-svn-id: svn://localhost/gambas/trunk@2540 867c0c6c-44f3-4631-809d-bfa615b0a4ec
2009-12-29 18:08:06 +00:00

1125 lines
23 KiB
C++

/***************************************************************************
gdraw.cpp
(c) 2004-2006 - Daniel Campos Fernández <dcamposf@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
***************************************************************************/
#ifdef OS_SOLARIS
/* Make math.h define M_PI and a few other things */
#define __EXTENSIONS__
/* Get definition for finite() */
#include <ieeefp.h>
#endif
#include <math.h>
#include "widgets.h"
#include "widgets_private.h"
#include "gdrawingarea.h"
#include "gdesktop.h"
#include "gdraw.h"
#ifdef GDK_WINDOWING_X11
#ifndef GAMBAS_DIRECTFB
#define GOT_X11_PLATFORM
#endif
#endif
static const gchar _back_diagonal_bits[]={'\x01','\x02','\x04','\x08','\x10','\x20','\x40','\x80'};
static const gchar _cross_bits[]={'\x08', '\x08', '\x08', '\xff', '\x08', '\x08', '\x08', '\x08' };
static const gchar _cross_diagonal_bits[]={'\x11','\x0a','\x04','\x0a','\x11','\xa0','\x40','\xa0'};
static const gchar _dense12_bits[]={'\x11', '\x00','\x44','\x00','\x11','\x00','\x44','\x00'};
static const gchar _dense37_bits[]={'\x54','\x8a','\x51','\xaa','\x44','\xaa','\x11','\xaa'};
static const gchar _dense50_bits[]={'\x55','\xaa','\x55','\xaa','\x55','\xaa','\x55','\xaa'};
static const gchar _dense63_bits[]={'\xdd','\xaa','\x77','\xaa','\xdd','\xaa','\x77','\xaa'};
static const gchar _dense88_bits[]={'\xee','\xff','\xbb','\xff','\xee','\xff','\xbb','\xff'};
static const gchar _dense6_bits[]={'\x22', '\x00', '\x00', '\x00', '\x22','\x00','\x00','\x00'};
static const gchar _dense94_bits[]={'\xdd','\xff','\xff','\xff','\xdd','\xff','\xff','\xff' };
static const gchar _diagonal_bits[]={'\x08', '\x04', '\x02', '\x01', '\x80', '\x40', '\x20', '\x10' };
static const gchar _horizontal_bits[]={'\x00','\x00','\x01','\x00','\x00','\x00' };
static const gchar _vertical_bits[]={'\x10'};
void gDraw::init()
{
_shadow = GTK_SHADOW_NONE;
_state = GTK_STATE_NORMAL;
stl = NULL;
dr = drm = NULL;
gc = gcm = NULL;
ft = NULL;
stipple = NULL;
tag = NULL;
_width = _height = _resolution = 0;
_gc_stack = NULL;
}
void gDraw::clear()
{
dArea = NULL;
gFont::assign(&ft);
if (dr) g_object_unref(G_OBJECT(dr));
if (drm) g_object_unref(G_OBJECT(drm));
if (gc) g_object_unref(G_OBJECT(gc));
if (gcm) g_object_unref(G_OBJECT(gcm));
if (stipple) g_object_unref(G_OBJECT(stipple));
dr = NULL;
drm = NULL;
gc = NULL;
gcm = NULL;
stipple=NULL;
if (_gc_stack)
{
uint i;
for (i = 0; i < _gc_stack->len; i++)
g_object_unref(G_OBJECT(g_array_index(_gc_stack, GdkGC *, i)));
g_array_free(_gc_stack, TRUE);
_gc_stack = NULL;
}
}
gDraw::gDraw()
{
init();
}
gDraw::~gDraw()
{
disconnect();
clear();
}
void gDraw::reset()
{
clear();
init();
_shadow=GTK_SHADOW_NONE;
_state=GTK_STATE_NORMAL;
line_style = LINE_SOLID;
clip_enabled = false;
clip.x = 0;
clip.y = 0;
clip.width = 0;
clip.height = 0;
stipple = NULL;
fillCol = 0;
fill = 0;
_transparent = false;
}
void gDraw::initGC()
{
if (dr)
{
g_object_ref(G_OBJECT(dr));
gc = gdk_gc_new(dr);
gdk_gc_set_fill(gc,GDK_SOLID);
#ifdef GOT_X11_PLATFORM
XSetArcMode(GDK_GC_XDISPLAY(gc), GDK_GC_XGC(gc), ArcPieSlice);
#endif
}
if (drm)
{
g_object_ref(G_OBJECT(drm));
gcm = gdk_gc_new(drm);
gdk_gc_set_fill(gcm,GDK_SOLID);
#ifdef GOT_X11_PLATFORM
XSetArcMode(GDK_GC_XDISPLAY(gcm), GDK_GC_XGC(gcm), ArcPieSlice);
#endif
}
setTransparent(true);
setBackground(COLOR_DEFAULT);
setForeground(COLOR_DEFAULT);
}
void gDraw::connect(gControl *wid)
{
GdkSubwindowMode mode = GDK_CLIP_BY_CHILDREN;
reset();
ft = wid->font()->copy(); //ft = new gFont(wid->widget);
_width = wid->width();
_height = wid->height();
_default_bg = wid->realBackground();
_default_fg = wid->realForeground();
if (_default_bg == COLOR_DEFAULT)
_default_bg = gDesktop::bgColor();
if (_default_fg == COLOR_DEFAULT)
_default_fg = gDesktop::fgColor();
stl = gtk_style_copy(wid->widget->style);
stl = gtk_style_attach(stl, wid->widget->window);
switch (wid->getClass())
{
case Type_gMainWindow:
dr = GTK_LAYOUT(wid->widget)->bin_window;
mode = GDK_INCLUDE_INFERIORS;
break;
case Type_gDrawingArea:
if ( ((gDrawingArea*)wid)->cached() )
{
dArea=(gDrawingArea*)wid;
dArea->resizeCache();
dr=dArea->buffer;
// gdk_window_freeze_updates (GTK_LAYOUT(wid->widget)->bin_window);
}
else
{
dr=GTK_LAYOUT(wid->widget)->bin_window;
}
break;
case Type_gFrame:
dr=GTK_LAYOUT(wid->widget)->bin_window;
break;
default:
dr=wid->widget->window;
break;
}
initGC();
if (mode != GDK_CLIP_BY_CHILDREN)
gdk_gc_set_subwindow(gc, mode);
}
void gDraw::connect(gPicture *wid)
{
reset();
ft = new gFont();
_width = wid->width();
_height = wid->height();
_default_bg = 0xFFFFFF;
_default_fg = 0;
dr = wid->getPixmap();
drm = wid->getMask();
stl = gtk_style_copy(gt_get_style("GtkButton", GTK_TYPE_BUTTON));
stl = gtk_style_attach(stl, (GdkWindow*)dr);
wid->invalidate();
initGC();
}
void gDraw::disconnect()
{
//GdkRectangle rect;
if (stl)
{
g_object_unref(G_OBJECT(stl));
stl=NULL;
}
if (dr) {
if (dArea && dArea->cached())
{
dArea->setCache();
//dArea->updateCache();
dArea=NULL;
}
g_object_unref(G_OBJECT(dr));
dr = NULL;
if (drm)
{
g_object_unref(G_OBJECT(drm));
drm = NULL;
}
}
}
/**************************************************************************
Save / restore GC state
***************************************************************************/
void gDraw::save()
{
GdkGC *copy;
if (!_gc_stack)
_gc_stack = g_array_new(FALSE, FALSE, sizeof(GdkGC *));
copy = gdk_gc_new(dr);
gdk_gc_copy(copy, gc);
g_array_append_val(_gc_stack, copy);
if (gcm)
{
copy = gdk_gc_new(drm);
gdk_gc_copy(copy, gcm);
g_array_append_val(_gc_stack, copy);
}
}
void gDraw::restore()
{
GdkGC *copy;
if (!_gc_stack || _gc_stack->len <= 0)
return;
copy = g_array_index(_gc_stack, GdkGC *, _gc_stack->len - 1);
gdk_gc_copy(gc, copy);
g_object_unref(G_OBJECT(copy));
g_array_remove_index(_gc_stack, _gc_stack->len - 1);
if (gcm && _gc_stack->len > 0)
{
copy = g_array_index(_gc_stack, GdkGC *, _gc_stack->len - 1);
gdk_gc_copy(gcm, copy);
g_object_unref(G_OBJECT(copy));
g_array_remove_index(_gc_stack, _gc_stack->len - 1);
}
}
/**************************************************************************
Information
***************************************************************************/
GtkStyle *gDraw::style()
{
return stl;
}
void gDraw::setState(int vl)
{
switch (vl)
{
case GTK_STATE_NORMAL:
case GTK_STATE_ACTIVE:
case GTK_STATE_PRELIGHT:
case GTK_STATE_SELECTED:
case GTK_STATE_INSENSITIVE: _state=vl;
}
}
void gDraw::setShadow(int vl)
{
switch (vl)
{
case GTK_SHADOW_NONE:
case GTK_SHADOW_IN:
case GTK_SHADOW_OUT:
case GTK_SHADOW_ETCHED_IN:
case GTK_SHADOW_ETCHED_OUT: _shadow=vl;
}
}
/**************************************************************************
Line properties
***************************************************************************/
int gDraw::lineWidth()
{
GdkGCValues val;
gdk_gc_get_values(gc,&val);
return val.line_width;
}
void gDraw::setLineWidth(int vl)
{
GdkGCValues val;
if (vl<1) vl=1;
gdk_gc_get_values(gc, &val);
gdk_gc_set_line_attributes(gc, vl, val.line_style, val.cap_style, val.join_style);
if (drm)
{
gdk_gc_get_values(gcm, &val);
gdk_gc_set_line_attributes(gcm, vl, val.line_style, val.cap_style, val.join_style);
}
}
int gDraw::lineStyle()
{
return line_style;
}
void gDraw::setLineStyle(int vl)
{
gint8 _dash[6],bucle;
GdkGCValues val;
GdkLineStyle style;
if ( (vl<0) || (vl>5) ) return;
line_style=vl;
gdk_gc_get_values(gc, &val);
style = _transparent ? GDK_LINE_ON_OFF_DASH : GDK_LINE_DOUBLE_DASH;
if (val.line_width>5)
_dash[0]=val.line_width*3;
else
_dash[0]=12;
for (bucle=1;bucle<6;bucle++)
{
if (val.line_width>5)
_dash[bucle]=val.line_width;
else
_dash[bucle]=3;
}
switch(vl)
{
case LINE_DASH:
gdk_gc_set_dashes(gc, 0, _dash, 2);
if (gcm) gdk_gc_set_dashes(gcm, 0, _dash, 2);
break;
case LINE_DASH_DOT:
gdk_gc_set_dashes(gc,0,_dash,4);
if (gcm) gdk_gc_set_dashes(gcm, 0, _dash, 4);
break;
case LINE_DASH_DOT_DOT:
gdk_gc_set_dashes(gc,0,_dash,6);
if (gcm) gdk_gc_set_dashes(gcm, 0, _dash, 6);
break;
case LINE_DOT:
if (val.line_width>5)
_dash[0]=val.line_width;
else
_dash[0]=3;
gdk_gc_set_dashes(gc,0,_dash,2);
if (gcm) gdk_gc_set_dashes(gcm,0,_dash,2);
break;
case LINE_SOLID:
style = GDK_LINE_SOLID;
break;
case LINE_NONE:
break;
}
gdk_gc_set_line_attributes(gc, val.line_width, style, val.cap_style, val.join_style);
if (gcm) gdk_gc_set_line_attributes(gcm, val.line_width, style, val.cap_style, val.join_style);
}
/**************************************************************************
Colors
***************************************************************************/
gColor gDraw::foreground()
{
GdkGCValues val;
gdk_gc_get_values(gc,&val);
return val.foreground.pixel & 0xFFFFFF;
}
gColor gDraw::background()
{
GdkGCValues val;
gdk_gc_get_values(gc,&val);
return val.background.pixel & 0xFFFFFF;
}
gColor gDraw::fillColor()
{
return fillCol;
}
bool gDraw::invert()
{
GdkGCValues val;
gdk_gc_get_values(gc,&val);
return val.function == GDK_XOR;
}
void gDraw::setForeground(gColor vl)
{
GdkColormap *cmap;
GdkColor gcol;
if (vl == COLOR_DEFAULT)
vl = _default_fg;
//if ( foreground()==vl) return;
cmap=gdk_drawable_get_colormap(dr);
fill_gdk_color(&gcol, vl, cmap);
gdk_gc_set_foreground(gc, &gcol);
if (gcm)
{
GdkGCValues val;
val.foreground.pixel = (vl & 0xFF000000) ? 0 : 1;
gdk_gc_set_values(gcm, &val, GDK_GC_FOREGROUND);
}
}
void gDraw::setBackground(gColor vl)
{
GdkColormap *cmap;
GdkColor gcol;
if (vl == COLOR_DEFAULT)
vl = _default_bg;
//if ( background()==vl) return;
cmap=gdk_drawable_get_colormap(dr);
fill_gdk_color(&gcol, vl, cmap);
gdk_gc_set_background(gc, &gcol);
if (gcm)
{
GdkGCValues val;
val.background.pixel = (vl & 0xFF000000) ? 0 : 1;
gdk_gc_set_values(gcm, &val, GDK_GC_BACKGROUND);
}
}
void gDraw::setFillColor(gColor vl)
{
fillCol = vl;
}
void gDraw::setInvert(bool vl)
{
gdk_gc_set_function(gc,vl ? GDK_XOR : GDK_COPY);
}
/**************************************************************************
Fill
***************************************************************************/
int gDraw::fillX()
{
GdkGCValues val;
gdk_gc_get_values(gc,&val);
return val.ts_x_origin;
}
void gDraw::setFillX(int vl)
{
GdkGCValues val;
gdk_gc_get_values(gc,&val);
gdk_gc_offset(gc,vl,val.ts_y_origin);
if (gcm) gdk_gc_offset(gcm, vl, val.ts_y_origin);
}
int gDraw::fillY()
{
GdkGCValues val;
gdk_gc_get_values(gc,&val);
return val.ts_y_origin;
}
void gDraw::setFillY(int vl)
{
GdkGCValues val;
gdk_gc_get_values(gc,&val);
gdk_gc_offset(gc,val.ts_x_origin,vl);
if (gcm) gdk_gc_offset(gcm, val.ts_x_origin, vl);
}
int gDraw::fillStyle()
{
return fill;
}
void gDraw::setFillStyle(int vl)
{
if ( (fill<0) || (fill>14) ) return;
fill=vl;
if (stipple) {
g_object_unref(G_OBJECT(stipple));
stipple=NULL;
}
if ( (fill==FILL_NONE) || (fill==FILL_SOLID) ) return;
switch (vl)
{
case FILL_DENSE_94:
stipple=gdk_bitmap_create_from_data(NULL,_dense94_bits,8,8); break;
case FILL_DENSE_88:
stipple=gdk_bitmap_create_from_data(NULL,_dense88_bits,8,8); break;
case FILL_DENSE_63:
stipple=gdk_bitmap_create_from_data(NULL,_dense63_bits,8,8); break;
case FILL_DENSE_50:
stipple=gdk_bitmap_create_from_data(NULL,_dense50_bits,8,8); break;
case FILL_DENSE_37:
stipple=gdk_bitmap_create_from_data(NULL,_dense37_bits,8,8); break;
case FILL_DENSE_12:
stipple=gdk_bitmap_create_from_data(NULL,_dense12_bits,8,8); break;
case FILL_DENSE_06:
stipple=gdk_bitmap_create_from_data(NULL,_dense6_bits,8,8); break;
case FILL_HORIZONTAL:
stipple=gdk_bitmap_create_from_data(NULL,_horizontal_bits,1,6); break;
case FILL_VERTICAL:
stipple=gdk_bitmap_create_from_data(NULL,_vertical_bits,6,1); break;
case FILL_CROSS:
stipple=gdk_bitmap_create_from_data(NULL,_cross_bits,8,8); break;
case FILL_BACK_DIAGONAL:
stipple=gdk_bitmap_create_from_data(NULL,_back_diagonal_bits,8,8); break;
case FILL_DIAGONAL:
stipple=gdk_bitmap_create_from_data(NULL,_diagonal_bits,8,8); break;
case FILL_CROSS_DIAGONAL:
stipple=gdk_bitmap_create_from_data(NULL,_cross_diagonal_bits,8,8); break;
}
if (stipple)
{
gdk_gc_set_stipple (gc,stipple);
if (gcm) gdk_gc_set_stipple (gcm,stipple);
}
}
/**************************************************************************
Clip Area
***************************************************************************/
int gDraw::clipX()
{
return clip.x;
}
int gDraw::clipY()
{
return clip.y;
}
int gDraw::clipWidth()
{
return clip.width;
}
int gDraw::clipHeight()
{
return clip.height;
}
bool gDraw::clipEnabled()
{
return clip_enabled;
}
void gDraw::setClipEnabled(bool vl)
{
if (vl)
{
gdk_gc_set_clip_rectangle(gc,&clip);
if (gcm) gdk_gc_set_clip_rectangle(gcm, &clip);
clip_enabled=true;
}
else
{
gdk_gc_set_clip_rectangle(gc,NULL);
if (gcm) gdk_gc_set_clip_rectangle(gcm, NULL);
clip_enabled=false;
}
}
void gDraw::setClip(int x,int y,int w,int h)
{
clip_enabled=true;
clip.x=x;
clip.y=y;
clip.width=w;
clip.height=h;
gdk_gc_set_clip_rectangle(gc,&clip);
if (gcm) gdk_gc_set_clip_rectangle(gcm, &clip);
}
/**************************************************************************
Primitives
***************************************************************************/
void gDraw::line(int x1,int y1,int x2,int y2)
{
if (!line_style) return;
gdk_draw_line(dr,gc,x1,y1,x2,y2);
if (drm) gdk_draw_line(drm,gcm,x1,y1,x2,y2);
}
void gDraw::point(int x,int y)
{
gdk_draw_point(dr,gc,x,y);
if (drm) gdk_draw_point(drm,gcm,x,y);
}
void gDraw::startFill()
{
if (fill > 1)
{
gdk_gc_set_fill(gc,_transparent ? GDK_STIPPLED : GDK_OPAQUE_STIPPLED);
if (gcm) gdk_gc_set_fill(gcm,_transparent ? GDK_STIPPLED : GDK_OPAQUE_STIPPLED);
}
_save_fg = foreground();
setForeground(fillCol);
}
void gDraw::endFill()
{
setForeground(_save_fg);
gdk_gc_set_fill(gc,GDK_SOLID);
if (gcm) gdk_gc_set_fill(gcm,GDK_SOLID);
}
void gDraw::rect(int x,int y,int width,int height)
{
if (width<0) { x+=width; width=-width; }
if (height<0) { y+=height; height=-height; }
if (fill)
{
startFill();
gdk_draw_rectangle (dr,gc,true,x,y,width,height);
if (drm) gdk_draw_rectangle (drm,gcm,true,x,y,width,height);
endFill();
}
gdk_gc_set_fill(gc,GDK_SOLID);
if (gcm) gdk_gc_set_fill(gcm,GDK_SOLID);
if (!line_style) return;
gdk_draw_rectangle(dr,gc,false,x,y,width-1,height-1);
if (drm) gdk_draw_rectangle(drm,gcm,false,x,y,width-1,height-1);
}
void gDraw::ellipse(int x, int y, int w, int h, double start, double end)
{
int as, ae;
if (start == end)
{
as = 0;
ae = 64 * 360;
}
else
{
as = (int)(start*180/M_PI*64);
ae = (int)(end*180/M_PI*64) - as;
}
if (fill)
{
startFill();
gdk_draw_arc(dr,gc,true,x,y,w-1,h-1, as, ae);
if (drm) gdk_draw_arc(drm,gcm,true,x,y,w-1,h-1, as, ae);
endFill();
}
if (!line_style) return;
gdk_draw_arc(dr,gc,false,x,y,w-1,h-1, as, ae);
if (drm) gdk_draw_arc(drm,gcm,false,x,y,w-1,h-1, as, ae);
}
void gDraw::polyline (int *vl, int nel)
{
GdkPoint *points;
if (!line_style) return;
if (nel <= 0) return;
// BM: This is actually the same data structure, so let's avoid the copy!
/*points=(GdkPoint*)g_malloc(sizeof(GdkPoint)*nel);
for (bucle=0;bucle<nvl;bucle+=2)
{
points[b2].x=(gint)vl[bucle];
points[b2].y=(gint)vl[bucle+1];
b2++;
}*/
points = (GdkPoint *)vl;
gdk_draw_lines(dr,gc,points,nel);
if (drm) gdk_draw_lines(drm,gcm,points,nel);
//g_free(points);
}
void gDraw::polygon (int *vl, int nel)
{
GdkPoint *points;
if (!GDK_IS_DRAWABLE (dr)) return;
if (nel <= 0) return;
// BM: This is actually the same data structure, so let's avoid the copy!
/*points=(GdkPoint*)g_malloc(sizeof(GdkPoint)*nel);
for (bucle=0;bucle<nvl;bucle+=2)
{
points[b2].x=(gint)vl[bucle];
points[b2].y=(gint)vl[bucle+1];
b2++;
}*/
points = (GdkPoint *)vl;
if (fill)
{
startFill();
gdk_draw_polygon(dr,gc,true,points,nel);
if (drm) gdk_draw_polygon(drm,gcm,true,points,nel);
endFill();
}
if (!line_style)
return;
gdk_draw_polygon(dr,gc,false,points,nel);
if (drm) gdk_draw_polygon(drm,gcm,false,points,nel);
//g_free(points);
}
/****************************************************************************************
Rendering
*****************************************************************************************/
void gDraw::picture(gPicture *pic, int x, int y, int w, int h, int sx, int sy, int sw, int sh)
{
GdkBitmap *mask = NULL;
bool del = false;
if (!pic || pic->isVoid()) return;
GT_NORMALIZE(x, y, w, h, sx, sy, sw, sh, pic->width(), pic->height());
if (clip_enabled)
{
GdkRectangle rect = { x, y, w, h };
GdkRectangle dst;
if (!gdk_rectangle_intersect(&rect, &clip, &dst))
return;
sx += dst.x - x;
sy += dst.y - y;
sw += dst.width - w;
sh += dst.height - h;
x = dst.x;
y = dst.y;
w = dst.width;
h = dst.height;
}
if (pic->type() == gPicture::SERVER && w == sw && h == sh)
{
if (pic->isTransparent())
mask = pic->getMask();
if (mask)
{
GdkGC *tmp_gc = gdk_gc_new(dr);
gdk_gc_set_clip_mask(tmp_gc, mask);
gdk_gc_set_clip_origin(tmp_gc, x, y);
gdk_draw_drawable(dr, tmp_gc, pic->getPixmap(), sx, sy, x, y, sw, sh);
gdk_gc_set_clip_mask(tmp_gc, NULL);
g_object_unref(tmp_gc);
}
else
gdk_draw_drawable(dr, gc, pic->getPixmap(), sx, sy, x, y, sw, sh);
}
else
{
if (w != sw || h != sh)
{
gPicture *pic2;
pic2 = pic->copy(sx, sy, sw, sh);
pic = pic2->stretch(w, h, true);
delete pic2;
del = true;
sx = 0; sy = 0; sw = w; sh = h;
}
gdk_draw_pixbuf(dr, gc, pic->getPixbuf(), sx, sy, x, y, sw, sh, GDK_RGB_DITHER_MAX, 0, 0);
}
if (drm)
{
//GdkGCValues val;
//val.foreground.pixel = 0xFFFFFF;
//gdk_gc_set_values(gcm, &val, GDK_GC_FOREGROUND);
if (pic->isTransparent())
mask = pic->getMask();
if (mask)
{
gdk_gc_set_function(gcm, GDK_OR);
gdk_draw_drawable(drm, gcm, mask, sx, sy, x, y, sw, sh);
gdk_gc_set_function(gcm, GDK_COPY);
}
else
{
gdk_draw_rectangle(drm, gcm, true, x, y, w, h);
}
//val.foreground.pixel = (foreground() & 0xFF) ? 0 : 0xFFFFFF;
//gdk_gc_set_values(gcm, &val, GDK_GC_FOREGROUND);
}
if (del)
delete pic;
}
void gDraw::tiledPicture(gPicture *pic, int x, int y, int w, int h)
{
GdkPixmap *pixmap;
int sx = -fillX();
int sy = -fillY();
int sw = pic->width();
int sh = pic->height();
if (!pic || pic->isVoid()) return;
if (!sw || !sh )
return;
if ( sx < 0 )
sx = sw - -sx % sw;
else
sx = sx % sw;
if ( sy < 0 )
sy = sh - -sy % sh;
else
sy = sy % sh;
pixmap = pic->getPixmap();
{
int yPos, xPos, drawH, drawW, yOff, xOff;
yPos = y;
yOff = sy;
while( yPos < y + h )
{
drawH = sh - yOff; // Cropping first row
if ( yPos + drawH > y + h ) // Cropping last row
drawH = y + h - yPos;
xPos = x;
xOff = sx;
while( xPos < x + w )
{
drawW = sw - xOff; // Cropping first column
if ( xPos + drawW > x + w ) // Cropping last column
drawW = x + w - xPos;
picture(pic, xPos, yPos, drawW, drawH, xOff, yOff, drawW, drawH);
xPos += drawW;
xOff = 0;
}
yPos += drawH;
yOff = 0;
}
}
}
/****************************************************************************************
Text
*****************************************************************************************/
gFont* gDraw::font()
{
return ft;
}
void gDraw::setFont(gFont *f)
{
//if (f != ft)
gFont::set(&ft, f->copy());
}
int gDraw::textWidth(char *txt, int len)
{
if (!txt) return 0;
if (!len) return 0;
return ft->width((const char*)txt, len);
}
int gDraw::textHeight(char *txt, int len)
{
if (!txt) return 0;
if (!len) return 0;
return ft->height((const char*)txt, len);
}
void gDraw::drawLayout(PangoLayout *ly, int x, int y, int w, int h, int align)
{
int offx = 0, offy = 0;
float foffx, foffy;
int tw, th;
float ftw, fth;
gt_add_layout_from_font(ly, font());
gt_layout_alignment(ly, (float)w, (float)h, &ftw, &fth, align, &foffx, &foffy);
tw = (int)ftw;
th = (int)fth;
offx = (int)foffx;
offy = (int)foffy;
if (!_transparent)
{
gColor buf = foreground();
setForeground(background());
gdk_draw_rectangle (dr, gc, true, x + offx, y + offy, tw, th);
if (drm) gdk_draw_rectangle (drm, gcm, true, x + offx, y + offy, tw, th);
setForeground(buf);
}
gdk_draw_layout(dr, gc, x + offx, y + offy, ly);
if (drm && _transparent)
{
GdkBitmap *mask;
mask = gt_make_text_mask(dr, tw, th, ly, 0, 0);
gdk_gc_set_function(gcm, GDK_OR);
gdk_draw_drawable(drm, gcm, mask, 0, 0, x + offx, y + offy, tw, th);
gdk_gc_set_function(gcm, GDK_COPY);
g_object_unref(mask);
}
g_object_unref(G_OBJECT(ly));
}
void gDraw::text(char *txt,int len,int x,int y,int w,int h,int align)
{
PangoLayout *ly;
if (!txt || !len) return;
ly = pango_layout_new(ft->ct);
pango_layout_set_text(ly, txt, len);
drawLayout(ly, x, y, w, h, align);
}
void gDraw::richText(char *txt,int len,int x,int y,int w,int h,int align)
{
PangoLayout *ly;
char *html;
if (!txt || !len) return;
ly = pango_layout_new(ft->ct);
if (w > 0)
pango_layout_set_width(ly, w * PANGO_SCALE);
html = gt_html_to_pango_string(txt, len, false);
pango_layout_set_markup(ly, html, -1);
drawLayout(ly, x, y, w, h, align);
g_free(html);
}
void gDraw::richTextSize(char *txt, int len, int sw, int *w, int *h)
{
PangoLayout *ly;
int tw = 0, th = 0;
char *html;
if (txt && len)
{
ly = pango_layout_new(ft->ct);
html = gt_html_to_pango_string(txt, len, false);
pango_layout_set_markup(ly, html, -1);
if (sw > 0)
pango_layout_set_width(ly, sw * PANGO_SCALE);
pango_layout_get_pixel_size(ly, &tw, &th);
g_free(html);
}
if (w) *w = tw;
if (h) *h = th;
}
int gDraw::resolution()
{
GdkScreen *screen;
gint h, hmm;
if (!GDK_IS_DRAWABLE(dr))
return 0;
screen = gdk_drawable_get_screen(dr);
h = gdk_screen_get_height(screen);
hmm = gdk_screen_get_height_mm(screen);
return (h * 254 + hmm * 5) / (hmm * 10);
}
bool gDraw::isTransparent()
{
return _transparent;
}
void gDraw::setTransparent(bool vl)
{
_transparent = vl;
if (lineStyle() > 1) setLineStyle(lineStyle());
}