606 lines
19 KiB
D
606 lines
19 KiB
D
|
/* MinWin Paint module
|
||
|
*
|
||
|
* An GContext is a simple 2D drawing API similar to a Windows DC
|
||
|
* and an X11 Graphics Context. A GXContext is a more advanced
|
||
|
* painting API that is similar to GDI+ or Quartz.
|
||
|
*
|
||
|
* Written by Ben Hinkle and released to the public domain, as
|
||
|
* explained at http://creativecommons.org/licenses/publicdomain
|
||
|
* Report comments and bugs at dsource: http://www.dsource.org/projects/minwin
|
||
|
*/
|
||
|
|
||
|
module minwin.paint;
|
||
|
|
||
|
public {
|
||
|
import minwin.geometry;
|
||
|
import minwin.peer;
|
||
|
}
|
||
|
|
||
|
private {
|
||
|
import minwin.app;
|
||
|
import minwin.image;
|
||
|
import minwin.logging;
|
||
|
}
|
||
|
|
||
|
// TODO: gdi+
|
||
|
// maybe also add a template paint context with coordinates in non-int
|
||
|
|
||
|
GContext newGContext() {
|
||
|
GContext gc = GContext.freeList;
|
||
|
if (gc) {
|
||
|
GContext.freeList = GContext.freeList.next;
|
||
|
} else {
|
||
|
gc = new GContext;
|
||
|
}
|
||
|
return gc;
|
||
|
}
|
||
|
|
||
|
enum PenStyle {
|
||
|
Solid = 0,
|
||
|
Dash = 1, /* ------- */
|
||
|
Dot = 2, /* ....... */
|
||
|
DashDot = 3 /* _._._._ */
|
||
|
// todo: None?
|
||
|
}
|
||
|
|
||
|
enum LineJoin {
|
||
|
Round,
|
||
|
Bevel,
|
||
|
Miter
|
||
|
}
|
||
|
|
||
|
enum PaintMode {
|
||
|
Copy, Invert, And, Or, Xor
|
||
|
}
|
||
|
|
||
|
version (GTK)
|
||
|
version = SharedPenBrushImpl;
|
||
|
|
||
|
version (SharedPenBrushImpl) {
|
||
|
|
||
|
struct PenData {
|
||
|
uint width;
|
||
|
Color color;
|
||
|
PenStyle style;
|
||
|
LineJoin join;
|
||
|
|
||
|
}
|
||
|
|
||
|
class Pen {
|
||
|
PenData data;
|
||
|
this(PenData* data) {
|
||
|
this.data = *data;
|
||
|
}
|
||
|
this(Color color) {
|
||
|
data.color = color;
|
||
|
}
|
||
|
void dispose(){}
|
||
|
}
|
||
|
|
||
|
class Brush {
|
||
|
Color color;
|
||
|
this(Color color) {
|
||
|
this.color = color;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
version (MinWin32) {
|
||
|
private import minwin.mswindows;
|
||
|
|
||
|
public import minwin.font;
|
||
|
|
||
|
alias HDC GContextPeer;
|
||
|
|
||
|
class GXContext { } // GDI+
|
||
|
|
||
|
alias HPEN PenPeer;
|
||
|
alias HBRUSH BrushPeer;
|
||
|
|
||
|
private DWORD paintModeToNative(PaintMode mode) {
|
||
|
DWORD nmode;
|
||
|
switch (mode) {
|
||
|
case PaintMode.Copy: nmode = SRCCOPY; break;
|
||
|
case PaintMode.Invert: nmode = NOTSRCCOPY; break;
|
||
|
case PaintMode.And: nmode = SRCAND; break;
|
||
|
case PaintMode.Or: nmode = SRCPAINT; break;
|
||
|
case PaintMode.Xor: nmode = SRCINVERT; break;
|
||
|
default: assert(0);
|
||
|
}
|
||
|
return nmode;
|
||
|
}
|
||
|
|
||
|
struct PenData {
|
||
|
LOGPEN native;
|
||
|
void width(uint w) {
|
||
|
native.lopnWidth = XY(w,w).native;
|
||
|
}
|
||
|
void color(Color c) {
|
||
|
native.lopnColor = c.native;
|
||
|
}
|
||
|
void style(PenStyle s) {
|
||
|
native.lopnStyle = s;
|
||
|
}
|
||
|
void lineJoin(LineJoin j) {
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class Pen {
|
||
|
PenPeer peer;
|
||
|
|
||
|
mixin SimplePeerMixin!();
|
||
|
this(PenData* data) {
|
||
|
peer = CreatePenIndirect(&data.native);
|
||
|
sysAssert(peer !is null, "Failed to create pen");
|
||
|
hasPeer = OWNS_PEER;
|
||
|
}
|
||
|
this(Color color) {
|
||
|
PenData pd;
|
||
|
pd.color = color;
|
||
|
this(&pd);
|
||
|
}
|
||
|
this(PenPeer peer) {
|
||
|
this.peer = peer;
|
||
|
hasPeer = FOREIGN_PEER;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class Brush {
|
||
|
BrushPeer peer;
|
||
|
|
||
|
mixin SimplePeerMixin!();
|
||
|
this(Color color) {
|
||
|
peer = CreateSolidBrush(color.native);
|
||
|
sysAssert(peer !is null, "Failed to create brush");
|
||
|
hasPeer = OWNS_PEER;
|
||
|
}
|
||
|
this(BrushPeer peer) {
|
||
|
this.peer = peer;
|
||
|
hasPeer = FOREIGN_PEER;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class GContext {
|
||
|
GContextPeer peer;
|
||
|
GContext next; // free list link
|
||
|
static GContext freeList;
|
||
|
bool release;
|
||
|
HWND hwnd; // companion hwnd used if release is true
|
||
|
Font font;
|
||
|
FontPeer origFont; // stores font in used before setFont is called
|
||
|
Pen pen;
|
||
|
PenPeer origPen;
|
||
|
Brush brush;
|
||
|
BrushPeer origBrush;
|
||
|
Region cliprgn;
|
||
|
PAINTSTRUCT paintstruct;
|
||
|
|
||
|
~this() {
|
||
|
disposePeer();
|
||
|
}
|
||
|
int hasPeer;
|
||
|
void dispose() {
|
||
|
disposePeer();
|
||
|
next = freeList;
|
||
|
freeList = this;
|
||
|
}
|
||
|
void disposePeer() {
|
||
|
pen = null;
|
||
|
font = null;
|
||
|
origFont = origPen = origBrush = null;
|
||
|
brush = null;
|
||
|
cliprgn = null;
|
||
|
if (hasPeer == OWNS_PEER) {
|
||
|
if (release)
|
||
|
ReleaseDC(hwnd,peer);
|
||
|
else {
|
||
|
BOOL ok = DeleteDC(peer);
|
||
|
sysAssert(ok != false, "Failed to delete DC");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Rect updateRect() {
|
||
|
return toRect(paintstruct.rcPaint);
|
||
|
}
|
||
|
|
||
|
Font setFont(Font f) {
|
||
|
Font oldFont = font;
|
||
|
font = f;
|
||
|
if (f is null) {
|
||
|
SelectObject(peer, cast(HGDIOBJ) origFont);
|
||
|
} else if (oldFont is null) {
|
||
|
origFont = cast(FontPeer)SelectObject(peer, cast(HGDIOBJ) font.peer);
|
||
|
} else {
|
||
|
SelectObject(peer, cast(HGDIOBJ) font.peer);
|
||
|
}
|
||
|
return oldFont;
|
||
|
}
|
||
|
|
||
|
void getFontMetrics(inout FontMetrics f) {
|
||
|
BOOL ok = GetTextMetricsA(peer,&f.native);
|
||
|
sysAssert(ok != false, "Failed to get font metrics");
|
||
|
}
|
||
|
|
||
|
Pen setPen(Pen p) {
|
||
|
Pen oldPen = pen;
|
||
|
pen = p;
|
||
|
if (p is null) {
|
||
|
SelectObject(peer, cast(HGDIOBJ) origPen);
|
||
|
} else if (oldPen is null) {
|
||
|
origPen = cast(PenPeer)SelectObject(peer, cast(HGDIOBJ) pen.peer);
|
||
|
} else {
|
||
|
SelectObject(peer, cast(HGDIOBJ) pen.peer);
|
||
|
}
|
||
|
return oldPen;
|
||
|
}
|
||
|
|
||
|
Brush setBrush(Brush p) {
|
||
|
Brush oldBrush = brush;
|
||
|
brush = p;
|
||
|
if (p is null) {
|
||
|
SelectObject(peer, cast(HGDIOBJ) origBrush);
|
||
|
} else if (oldBrush is null) {
|
||
|
origBrush = cast(BrushPeer)SelectObject(peer, cast(HGDIOBJ) brush.peer);
|
||
|
} else {
|
||
|
SelectObject(peer, cast(HGDIOBJ) brush.peer);
|
||
|
}
|
||
|
return oldBrush;
|
||
|
}
|
||
|
|
||
|
void getClip(Region rgn) {
|
||
|
int res = GetClipRgn(peer,rgn.peer);
|
||
|
sysAssert(res != -1, "Failed to get clip region");
|
||
|
}
|
||
|
|
||
|
// in postscript could mean intersect with current clip region
|
||
|
void setClip(Region rgn) {
|
||
|
int res = SelectClipRgn(peer,rgn.peer);
|
||
|
sysAssert(res != 0, "Failed to set clip region");
|
||
|
}
|
||
|
|
||
|
// pen must be set
|
||
|
void drawRect(inout Rect r) {
|
||
|
// TODO: move in by pen width
|
||
|
BOOL ok = MoveToEx(peer,r.left,r.top,null);
|
||
|
sysAssert(ok != false, "Failed to draw rect");
|
||
|
LineTo(peer,r.left,r.bottom-1);
|
||
|
LineTo(peer,r.right-1,r.bottom-1);
|
||
|
LineTo(peer,r.right-1,r.top);
|
||
|
LineTo(peer,r.left,r.top);
|
||
|
}
|
||
|
|
||
|
// brush must be set
|
||
|
void fillRect(inout Rect r) {
|
||
|
sysAssert(brush !is null, "Brush must be set for fillRect");
|
||
|
int ok = FillRect(peer,&r.native,brush.peer);
|
||
|
sysAssert(ok != false, "Failed to fill rect");
|
||
|
}
|
||
|
|
||
|
void drawText(int x, int y, char[] str) {
|
||
|
BOOL ok;
|
||
|
if (useWfuncs) {
|
||
|
wchar[] buf = toUTF16(str);
|
||
|
ok = TextOutW(peer, x, y, buf.ptr, buf.length);
|
||
|
}
|
||
|
else {
|
||
|
auto buf = toMBSz(str);
|
||
|
ok = TextOutA(peer, x, y, buf, std.c.string.strlen(buf));
|
||
|
}
|
||
|
sysAssert(ok != false, "Failed to draw text");
|
||
|
}
|
||
|
void drawLine(int x1, int y1, int x2, int y2) {
|
||
|
BOOL ok = MoveToEx(peer,x1,y1,null);
|
||
|
sysAssert(ok != false, "Failed to draw line");
|
||
|
LineTo(peer,x2,y2);
|
||
|
}
|
||
|
void drawPolyline(Point[] pts) {
|
||
|
if (pts.length > 1) {
|
||
|
BOOL ok = MoveToEx(peer,pts[0].x,pts[0].y,null);
|
||
|
sysAssert(ok != false, "Failed to draw polyline");
|
||
|
for (int n=1; n < pts.length; ++n) {
|
||
|
LineTo(peer,pts[n].x,pts[n].y);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
void drawPolygon(Point[] pts) {
|
||
|
if (pts.length > 1) {
|
||
|
BOOL ok = MoveToEx(peer,pts[0].x,pts[0].y,null);
|
||
|
sysAssert(ok != false, "Failed to draw polygon");
|
||
|
for (int n=1; n < pts.length; ++n) {
|
||
|
LineTo(peer,pts[n].x,pts[n].y);
|
||
|
}
|
||
|
LineTo(peer,pts[0].x,pts[0].y);
|
||
|
}
|
||
|
}
|
||
|
void drawBezier(Point[] pts) {
|
||
|
// PolyBezier(peer,pts.ptr,pts.length);
|
||
|
}
|
||
|
void fillPolygon(Point[] pts) {
|
||
|
//?
|
||
|
}
|
||
|
void fillRegion(Region rgn) {
|
||
|
sysAssert(brush !is null, "Brush must be set for fillRect");
|
||
|
// FillRgn(peer,rgn,brush);
|
||
|
}
|
||
|
void drawRegion(Region rgn) {
|
||
|
BOOL ok = PaintRgn(peer,rgn.peer);
|
||
|
sysAssert(ok != false, "Failed to draw region");
|
||
|
}
|
||
|
|
||
|
void drawImage(Image im, int x, int y, PaintMode mode = PaintMode.Copy) {
|
||
|
HDC memDC = CreateCompatibleDC(peer);
|
||
|
sysAssert(memDC !is null, "Failed to create compatible DC in drawImage");
|
||
|
HANDLE res = SelectObject(memDC,im.peer);
|
||
|
sysAssert(res !is null, "Failed to select bitmap in drawImage");
|
||
|
version(LOG)log.writefln("drawing image %x %d %d",
|
||
|
im,im.width,im.height);
|
||
|
DWORD nmode = paintModeToNative(mode);
|
||
|
BOOL ok = BitBlt(peer,x,y,im.width,im.height,memDC,0,0,nmode);
|
||
|
sysAssert(ok != false, "Failed to BitBlt drawImage");
|
||
|
version(LOG)log.writefln(" result %d",cast(int)res);
|
||
|
ok = DeleteDC(memDC);
|
||
|
sysAssert(ok != false, "Failed to delete compatible DC in drawImage");
|
||
|
}
|
||
|
|
||
|
void stretchImage(Image im, int x, int y,
|
||
|
int w, int h, PaintMode mode = PaintMode.Copy) {
|
||
|
HDC memDC = CreateCompatibleDC(peer);
|
||
|
sysAssert(memDC !is null, "Failed to create compatible DC in stretchImage");
|
||
|
SelectObject(memDC,im.peer);
|
||
|
DWORD nmode = paintModeToNative(mode);
|
||
|
BOOL ok = StretchBlt(peer,x,y,w,h,memDC,0,0,im.width,im.height,nmode);
|
||
|
sysAssert(ok != false, "Failed to StretchBlt in stretchImage");
|
||
|
DeleteDC(memDC);
|
||
|
}
|
||
|
|
||
|
void drawSubImage(Image im, int x, int y,
|
||
|
int sx, int sy, int sw, int sh,
|
||
|
PaintMode mode = PaintMode.Copy) {
|
||
|
HDC memDC = CreateCompatibleDC(peer);
|
||
|
sysAssert(memDC !is null, "Failed to create compatible DC in drawSubImage");
|
||
|
SelectObject(memDC,im.peer);
|
||
|
DWORD nmode = paintModeToNative(mode);
|
||
|
BOOL ok = BitBlt(peer,x,y,sw,sh,memDC,sx,sx,nmode);
|
||
|
sysAssert(ok != false, "Failed to BitBlt in drawSubImage");
|
||
|
DeleteDC(memDC);
|
||
|
}
|
||
|
|
||
|
void stretchSubImage(Image im, int x, int y, int w, int h,
|
||
|
int sx, int sy, int sw, int sh,
|
||
|
PaintMode mode = PaintMode.Copy) {
|
||
|
HDC memDC = CreateCompatibleDC(peer);
|
||
|
sysAssert(memDC !is null, "Failed to create compatible DC in stretchSubImage");
|
||
|
SelectObject(memDC,im.peer);
|
||
|
DWORD nmode = paintModeToNative(mode);
|
||
|
BOOL ok = StretchBlt(peer,x,y,w,h,memDC,sx,sy,sw,sh,nmode);
|
||
|
sysAssert(ok != false, "Failed to StretchBlt in stretchSubImage");
|
||
|
DeleteDC(memDC);
|
||
|
}
|
||
|
|
||
|
void flush() {
|
||
|
GdiFlush();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} else version (GTK) {
|
||
|
|
||
|
private import minwin.gtk;
|
||
|
|
||
|
public import minwin.font;
|
||
|
|
||
|
private GdkFunction paintModeToNative(PaintMode mode) {
|
||
|
GdkFunction nmode;
|
||
|
switch (mode) {
|
||
|
case PaintMode.Copy: nmode = GdkFunction.GDK_COPY; break;
|
||
|
case PaintMode.Invert: nmode = GdkFunction.GDK_COPY_INVERT; break;
|
||
|
case PaintMode.And: nmode = GdkFunction.GDK_AND; break;
|
||
|
case PaintMode.Or: nmode = GdkFunction.GDK_OR; break;
|
||
|
case PaintMode.Xor: nmode = GdkFunction.GDK_XOR; break;
|
||
|
default: assert(0);
|
||
|
}
|
||
|
return nmode;
|
||
|
}
|
||
|
|
||
|
alias GdkGC* GContextPeer;
|
||
|
|
||
|
class GXContext { } // not impl in GDK
|
||
|
|
||
|
class GContext {
|
||
|
GContextPeer peer;
|
||
|
GContext next; // free list link
|
||
|
static GContext freeList;
|
||
|
GdkDrawable* drawable;
|
||
|
PangoLayout* layout;
|
||
|
Font font;
|
||
|
Pen pen;
|
||
|
Brush brush;
|
||
|
bool penActive;
|
||
|
GdkEventExpose* paintEvent;
|
||
|
|
||
|
~this() {
|
||
|
disposePeer();
|
||
|
}
|
||
|
int hasPeer;
|
||
|
void dispose() {
|
||
|
disposePeer();
|
||
|
next = freeList;
|
||
|
freeList = this;
|
||
|
}
|
||
|
void disposePeer() {
|
||
|
pen = null;
|
||
|
font = null;
|
||
|
brush = null;
|
||
|
penActive = false;
|
||
|
if (hasPeer == OWNS_PEER) {
|
||
|
g_object_unref(cast(GObject*)peer);
|
||
|
// g_object_unref(cast(GObject*)layout);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Rect updateRect() {
|
||
|
Rect r;
|
||
|
if (paintEvent)
|
||
|
r = toRect(paintEvent.area);
|
||
|
return r;
|
||
|
}
|
||
|
|
||
|
Font setFont(Font f) {
|
||
|
Font oldFont = font;
|
||
|
// if (oldFont is null)
|
||
|
// oldFont = DefaultFont;
|
||
|
font = f;
|
||
|
if (font)
|
||
|
pango_layout_set_font_description(layout,font.peer);
|
||
|
return oldFont;
|
||
|
}
|
||
|
|
||
|
void getFontMetrics(inout FontMetrics f) {
|
||
|
PangoContext* c = pango_layout_get_context(layout);
|
||
|
PangoFontMetrics* data = pango_context_get_metrics(c,font.peer,null);
|
||
|
f.ascent = pango_font_metrics_get_ascent(data);
|
||
|
f.descent = pango_font_metrics_get_descent(data);
|
||
|
// f.leading = f.descent;
|
||
|
f.leading = 0;
|
||
|
f.size = f.ascent+f.descent;
|
||
|
f.maxWidth = pango_font_metrics_get_approximate_char_width(data)/PANGO_SCALE;
|
||
|
f.size /= PANGO_SCALE;
|
||
|
f.ascent /= PANGO_SCALE;
|
||
|
f.descent /= PANGO_SCALE;
|
||
|
f.leading /= PANGO_SCALE;
|
||
|
pango_font_metrics_unref(data);
|
||
|
}
|
||
|
|
||
|
private void setForeground(Color rgb) {
|
||
|
GdkColor c;
|
||
|
c.red = Color.rescale(rgb.red,ubyte.max,ushort.max);
|
||
|
c.green = Color.rescale(rgb.green,ubyte.max,ushort.max);
|
||
|
c.blue = Color.rescale(rgb.blue,ubyte.max,ushort.max);
|
||
|
gdk_gc_set_rgb_fg_color(peer,&c);
|
||
|
}
|
||
|
|
||
|
Pen setPen(Pen p) {
|
||
|
Pen oldPen = pen;
|
||
|
pen = p;
|
||
|
if (p !is null) {
|
||
|
GdkLineStyle style = GdkLineStyle.GDK_LINE_SOLID;
|
||
|
if (p.data.style != PenStyle.Solid) {
|
||
|
style = GdkLineStyle.GDK_LINE_ON_OFF_DASH;
|
||
|
gdk_gc_set_dashes(peer,0,dashlist[style-1].ptr,
|
||
|
dashlist[style-1].length);
|
||
|
}
|
||
|
gdk_gc_set_line_attributes(peer,p.data.width,style,
|
||
|
GdkCapStyle.GDK_CAP_BUTT,
|
||
|
cast(GdkJoinStyle)p.data.join);
|
||
|
setForeground(p.data.color);
|
||
|
penActive = true;
|
||
|
}
|
||
|
return oldPen;
|
||
|
}
|
||
|
|
||
|
Brush setBrush(Brush p) {
|
||
|
Brush oldBrush = brush;
|
||
|
brush = p;
|
||
|
if (brush) {
|
||
|
setForeground(brush.color);
|
||
|
penActive = false;
|
||
|
}
|
||
|
return oldBrush;
|
||
|
}
|
||
|
|
||
|
void drawRect(inout Rect r) {
|
||
|
if (pen && !penActive) {
|
||
|
setForeground(pen.data.color);
|
||
|
penActive = true;
|
||
|
}
|
||
|
gdk_draw_rectangle(drawable,peer,false,
|
||
|
r.left,r.top,r.width-1,r.height-1);
|
||
|
}
|
||
|
|
||
|
// brush must be set
|
||
|
void fillRect(inout Rect r) {
|
||
|
if (brush && penActive) {
|
||
|
setForeground(brush.color);
|
||
|
penActive = false;
|
||
|
}
|
||
|
gdk_draw_rectangle(drawable,peer,true,
|
||
|
r.left,r.top,r.width,r.height);
|
||
|
}
|
||
|
|
||
|
private static {
|
||
|
byte[][3] dashlist;
|
||
|
byte[2] dashed = [6,6];
|
||
|
byte[2] dotted = [4,2];
|
||
|
byte[4] dashdotted = [4,6,4,2];
|
||
|
}
|
||
|
static this() {
|
||
|
dashlist[0] = dashed;
|
||
|
dashlist[1] = dotted;
|
||
|
dashlist[2] = dashdotted;
|
||
|
}
|
||
|
|
||
|
void drawLine(int x1, int y1, int x2, int y2) {
|
||
|
gdk_draw_line(drawable, peer, x1,y1,x2,y2);
|
||
|
}
|
||
|
|
||
|
void drawPolyline(Point[] pts) {
|
||
|
gdk_draw_lines(drawable, peer, cast(GdkPoint*)pts.ptr, pts.length);
|
||
|
}
|
||
|
|
||
|
void drawPolygon(Point[] pts) {
|
||
|
gdk_draw_polygon(drawable, peer, false, cast(GdkPoint*)pts.ptr, pts.length);
|
||
|
}
|
||
|
|
||
|
void fillPolygon(Point[] pts) {
|
||
|
gdk_draw_polygon(drawable, peer, true, cast(GdkPoint*)pts.ptr, pts.length);
|
||
|
}
|
||
|
|
||
|
void drawText(int x, int y, char[] str) {
|
||
|
pango_layout_set_text(layout,str.ptr,str.length);
|
||
|
gdk_draw_layout(drawable,peer,x,y,layout);
|
||
|
}
|
||
|
|
||
|
void drawImage(Image im, int x, int y, PaintMode mode = PaintMode.Copy) {
|
||
|
GdkGCValues vals;
|
||
|
gdk_gc_get_values(peer,&vals);
|
||
|
gdk_gc_set_function(peer,paintModeToNative(mode));
|
||
|
gdk_draw_drawable(drawable,peer,im.peer,0,0,x,y,-1,-1);
|
||
|
gdk_gc_set_function(peer,vals.Function);
|
||
|
}
|
||
|
|
||
|
void drawSubImage(Image im, int x, int y,
|
||
|
int sx, int sy, int sw, int sh,
|
||
|
PaintMode mode = PaintMode.Copy) {
|
||
|
GdkGCValues vals;
|
||
|
gdk_gc_get_values(peer,&vals);
|
||
|
gdk_gc_set_function(peer,paintModeToNative(mode));
|
||
|
gdk_draw_drawable(drawable,peer,im.peer,sx,sy,x,y,sw,sh);
|
||
|
gdk_gc_set_function(peer,vals.Function);
|
||
|
}
|
||
|
|
||
|
void stretchImage(Image im, int x, int y, int w, int h,
|
||
|
PaintMode mode = PaintMode.Copy) {
|
||
|
// TODO
|
||
|
GdkGCValues vals;
|
||
|
gdk_gc_get_values(peer,&vals);
|
||
|
gdk_gc_set_function(peer,paintModeToNative(mode));
|
||
|
gdk_draw_drawable(drawable,peer,im.peer,0,0,x,y,-1,-1);
|
||
|
gdk_gc_set_function(peer,vals.Function);
|
||
|
}
|
||
|
|
||
|
void stretchSubImage(Image im, int x, int y, int w, int h,
|
||
|
int sx, int sy, int sw, int sh,
|
||
|
PaintMode mode = PaintMode.Copy) {
|
||
|
// TODO
|
||
|
GdkGCValues vals;
|
||
|
gdk_gc_get_values(peer,&vals);
|
||
|
gdk_gc_set_function(peer,paintModeToNative(mode));
|
||
|
gdk_draw_drawable(drawable,peer,im.peer,sx,sy,x,y,sw,sh);
|
||
|
gdk_gc_set_function(peer,vals.Function);
|
||
|
}
|
||
|
|
||
|
void flush() { gdk_flush(); }
|
||
|
|
||
|
}
|
||
|
}
|