/* * GDI graphics operations * * Copyright 1993 Alexandre Julliard */ static char Copyright[] = "Copyright Alexandre Julliard, 1993"; #include #include #include #include #include #ifndef PI #define PI M_PI #endif #include "gdi.h" #include "syscolor.h" extern int COLOR_ToPhysical( DC *dc, COLORREF color ); /*********************************************************************** * LineTo (GDI.19) */ BOOL LineTo( HDC hdc, short x, short y ) { DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ); if (!dc) return FALSE; if (DC_SetupGCForPen( dc )) XDrawLine(XT_display, dc->u.x.drawable, dc->u.x.gc, dc->w.DCOrgX + XLPTODP( dc, dc->w.CursPosX ), dc->w.DCOrgY + YLPTODP( dc, dc->w.CursPosY ), dc->w.DCOrgX + XLPTODP( dc, x ), dc->w.DCOrgY + YLPTODP( dc, y ) ); dc->w.CursPosX = x; dc->w.CursPosY = y; return TRUE; } /*********************************************************************** * MoveTo (GDI.20) */ DWORD MoveTo( HDC hdc, short x, short y ) { POINT pt; if (MoveToEx( hdc, x, y, &pt )) return pt.x | (pt.y << 16); else return 0; } /*********************************************************************** * MoveToEx (GDI.483) */ BOOL MoveToEx( HDC hdc, short x, short y, LPPOINT pt ) { DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ); if (!dc) return FALSE; if (pt) { pt->x = dc->w.CursPosX; pt->y = dc->w.CursPosY; } dc->w.CursPosX = x; dc->w.CursPosY = y; return TRUE; } /*********************************************************************** * GRAPH_DrawArc * * Helper functions for Arc(), Chord() and Pie(). * 'lines' is the number of lines to draw: 0 for Arc, 1 for Chord, 2 for Pie. */ BOOL GRAPH_DrawArc( HDC hdc, int left, int top, int right, int bottom, int xstart, int ystart, int xend, int yend, int lines ) { int xcenter, ycenter; double start_angle, end_angle, diff_angle; XPoint points[3]; DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ); if (!dc) return FALSE; left = XLPTODP( dc, left ); top = YLPTODP( dc, top ); right = XLPTODP( dc, right ); bottom = YLPTODP( dc, bottom ); xstart = XLPTODP( dc, xstart ); ystart = YLPTODP( dc, ystart ); xend = XLPTODP( dc, xend ); yend = YLPTODP( dc, yend ); if ((left == right) || (top == bottom)) return FALSE; if (!DC_SetupGCForPen( dc )) return TRUE; xcenter = (right + left) / 2; ycenter = (bottom + top) / 2; start_angle = atan2( (double)(ycenter-ystart)*(right-left), (double)(xstart-xcenter)*(bottom-top) ); end_angle = atan2( (double)(ycenter-yend)*(right-left), (double)(xend-xcenter)*(bottom-top) ); diff_angle = end_angle - start_angle; if (diff_angle < 0.0) diff_angle += 2*PI; XDrawArc( XT_display, dc->u.x.drawable, dc->u.x.gc, dc->w.DCOrgX + left, dc->w.DCOrgY + top, right-left-1, bottom-top-1, (int)(start_angle * 180 * 64 / PI), (int)(diff_angle * 180 * 64 / PI) ); if (!lines) return TRUE; points[0].x = dc->w.DCOrgX + xcenter + (int)(cos(start_angle) * (right-left) / 2); points[0].y = dc->w.DCOrgY + ycenter - (int)(sin(start_angle) * (bottom-top) / 2); points[1].x = dc->w.DCOrgX + xcenter + (int)(cos(end_angle) * (right-left) / 2); points[1].y = dc->w.DCOrgY + ycenter - (int)(sin(end_angle) * (bottom-top) / 2); if (lines == 2) { points[2] = points[1]; points[1].x = dc->w.DCOrgX + xcenter; points[1].y = dc->w.DCOrgY + ycenter; } XDrawLines( XT_display, dc->u.x.drawable, dc->u.x.gc, points, lines+1, CoordModeOrigin ); return TRUE; } /*********************************************************************** * Arc (GDI.23) */ BOOL Arc( HDC hdc, int left, int top, int right, int bottom, int xstart, int ystart, int xend, int yend ) { return GRAPH_DrawArc( hdc, left, top, right, bottom, xstart, ystart, xend, yend, 0 ); } /*********************************************************************** * Pie (GDI.26) */ BOOL Pie( HDC hdc, int left, int top, int right, int bottom, int xstart, int ystart, int xend, int yend ) { return GRAPH_DrawArc( hdc, left, top, right, bottom, xstart, ystart, xend, yend, 2 ); } /*********************************************************************** * Chord (GDI.348) */ BOOL Chord( HDC hdc, int left, int top, int right, int bottom, int xstart, int ystart, int xend, int yend ) { return GRAPH_DrawArc( hdc, left, top, right, bottom, xstart, ystart, xend, yend, 1 ); } /*********************************************************************** * Ellipse (GDI.24) */ BOOL Ellipse( HDC hdc, int left, int top, int right, int bottom ) { DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ); if (!dc) return FALSE; left = XLPTODP( dc, left ); top = YLPTODP( dc, top ); right = XLPTODP( dc, right ); bottom = YLPTODP( dc, bottom ); if ((left == right) || (top == bottom)) return FALSE; if (DC_SetupGCForBrush( dc )) XFillArc( XT_display, dc->u.x.drawable, dc->u.x.gc, dc->w.DCOrgX + left, dc->w.DCOrgY + top, right-left-1, bottom-top-1, 0, 360*64 ); if (DC_SetupGCForPen( dc )) XDrawArc( XT_display, dc->u.x.drawable, dc->u.x.gc, dc->w.DCOrgX + left, dc->w.DCOrgY + top, right-left-1, bottom-top-1, 0, 360*64 ); return TRUE; } /*********************************************************************** * Rectangle (GDI.27) */ BOOL Rectangle( HDC hdc, int left, int top, int right, int bottom ) { DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ); if (!dc) return FALSE; left = XLPTODP( dc, left ); top = YLPTODP( dc, top ); right = XLPTODP( dc, right ); bottom = YLPTODP( dc, bottom ); if (DC_SetupGCForBrush( dc )) XFillRectangle( XT_display, dc->u.x.drawable, dc->u.x.gc, dc->w.DCOrgX + left, dc->w.DCOrgY + top, right-left-1, bottom-top-1 ); if (DC_SetupGCForPen( dc )) XDrawRectangle( XT_display, dc->u.x.drawable, dc->u.x.gc, dc->w.DCOrgX + left, dc->w.DCOrgY + top, right-left-1, bottom-top-1 ); return TRUE; } /*********************************************************************** * RoundRect (GDI.28) */ BOOL RoundRect( HDC hDC, short left, short top, short right, short bottom, short ell_width, short ell_height) { int x1, y1, x2, y2; DC * dc = (DC *) GDI_GetObjPtr(hDC, DC_MAGIC); if (!dc) return FALSE; /* printf("RoundRect(%d %d %d %d %d %d\n", left, top, right, bottom, ell_width, ell_height); */ x1 = XLPTODP(dc, left); y1 = YLPTODP(dc, top); x2 = XLPTODP(dc, right - ell_width); y2 = YLPTODP(dc, bottom - ell_height); if (DC_SetupGCForBrush(dc)) { XFillArc(XT_display, dc->u.x.drawable, dc->u.x.gc, dc->w.DCOrgX + x1, dc->w.DCOrgY + y1, ell_width, ell_height, 90 * 64, 90 * 64); XFillArc(XT_display, dc->u.x.drawable, dc->u.x.gc, dc->w.DCOrgX + x1, dc->w.DCOrgY + y2, ell_width, ell_height, 180 * 64, 90 * 64); XFillArc(XT_display, dc->u.x.drawable, dc->u.x.gc, dc->w.DCOrgX + x2, dc->w.DCOrgY + y2, ell_width, ell_height, 270 * 64, 90 * 64); XFillArc(XT_display, dc->u.x.drawable, dc->u.x.gc, dc->w.DCOrgX + x2, dc->w.DCOrgY + y1, ell_width, ell_height, 0, 90 * 64); ell_width /= 2; ell_height /= 2; XFillRectangle(XT_display, dc->u.x.drawable, dc->u.x.gc, dc->w.DCOrgX + left + ell_width, dc->w.DCOrgY + top, right - left - 2 * ell_width, bottom - top); XFillRectangle(XT_display, dc->u.x.drawable, dc->u.x.gc, dc->w.DCOrgX + left, dc->w.DCOrgY + top + ell_height, ell_width, bottom - top - 2 * ell_height); XFillRectangle(XT_display, dc->u.x.drawable, dc->u.x.gc, dc->w.DCOrgX + right - ell_width, dc->w.DCOrgY + top + ell_height, ell_width, bottom - top - 2 * ell_height); ell_width *= 2; ell_height *= 2; } if (DC_SetupGCForPen(dc)) { XDrawArc(XT_display, dc->u.x.drawable, dc->u.x.gc, dc->w.DCOrgX + x1, dc->w.DCOrgY + y1, ell_width, ell_height, 90 * 64, 90 * 64); XDrawArc(XT_display, dc->u.x.drawable, dc->u.x.gc, dc->w.DCOrgX + x1, dc->w.DCOrgY + y2, ell_width, ell_height, 180 * 64, 90 * 64); XDrawArc(XT_display, dc->u.x.drawable, dc->u.x.gc, dc->w.DCOrgX + x2, dc->w.DCOrgY + y2, ell_width, ell_height, 270 * 64, 90 * 64); XDrawArc(XT_display, dc->u.x.drawable, dc->u.x.gc, dc->w.DCOrgX + x2, dc->w.DCOrgY + y1, ell_width, ell_height, 0, 90 * 64); } ell_width /= 2; ell_height /= 2; MoveTo(hDC, left, top + ell_height); LineTo(hDC, left, bottom - ell_height); MoveTo(hDC, left + ell_width, bottom); LineTo(hDC, right - ell_width, bottom); MoveTo(hDC, right, bottom - ell_height); LineTo(hDC, right, top + ell_height); MoveTo(hDC, right - ell_width, top); LineTo(hDC, left + ell_width, top); return TRUE; } /*********************************************************************** * FillRect (USER.81) */ int FillRect( HDC hdc, LPRECT rect, HBRUSH hbrush ) { HBRUSH prevBrush; if ((rect->right <= rect->left) || (rect->bottom <= rect->top)) return 0; if (!(prevBrush = SelectObject( hdc, hbrush ))) return 0; PatBlt( hdc, rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top, PATCOPY ); SelectObject( hdc, prevBrush ); return 1; } /*********************************************************************** * InvertRect (USER.82) */ void InvertRect( HDC hdc, LPRECT rect ) { if ((rect->right <= rect->left) || (rect->bottom <= rect->top)) return; PatBlt( hdc, rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top, DSTINVERT ); } /*********************************************************************** * FrameRect (USER.83) */ int FrameRect( HDC hdc, LPRECT rect, HBRUSH hbrush ) { HBRUSH prevBrush; int left, top, right, bottom; DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ); if (!dc) return FALSE; if ((rect->right <= rect->left) || (rect->bottom <= rect->top)) return 0; if (!(prevBrush = SelectObject( hdc, hbrush ))) return 0; left = XLPTODP( dc, rect->left ); top = YLPTODP( dc, rect->top ); right = XLPTODP( dc, rect->right ); bottom = YLPTODP( dc, rect->bottom ); if (DC_SetupGCForBrush( dc )) { PatBlt( hdc, rect->left, rect->top, 1, rect->bottom - rect->top, PATCOPY ); PatBlt( hdc, rect->right - 1, rect->top, 1, rect->bottom - rect->top, PATCOPY ); PatBlt( hdc, rect->left, rect->top, rect->right - rect->left, 1, PATCOPY ); PatBlt( hdc, rect->left, rect->bottom - 1, rect->right - rect->left, 1, PATCOPY ); } SelectObject( hdc, prevBrush ); return 1; } /*********************************************************************** * SetPixel (GDI.31) */ COLORREF SetPixel( HDC hdc, short x, short y, COLORREF color ) { int pixel; PALETTEENTRY entry; DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ); if (!dc) return 0; x = dc->w.DCOrgX + XLPTODP( dc, x ); y = dc->w.DCOrgY + YLPTODP( dc, y ); pixel = COLOR_ToPhysical( dc, color ); GetPaletteEntries( dc->w.hPalette, pixel, 1, &entry ); XSetForeground( XT_display, dc->u.x.gc, pixel ); XSetFunction( XT_display, dc->u.x.gc, GXcopy ); XDrawPoint( XT_display, dc->u.x.drawable, dc->u.x.gc, x, y ); return RGB( entry.peRed, entry.peGreen, entry.peBlue ); } /*********************************************************************** * GetPixel (GDI.83) */ COLORREF GetPixel( HDC hdc, short x, short y ) { PALETTEENTRY entry; XImage * image; DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ); if (!dc) return 0; x = dc->w.DCOrgX + XLPTODP( dc, x ); y = dc->w.DCOrgY + YLPTODP( dc, y ); if ((x < 0) || (y < 0)) return 0; if (!(dc->w.flags & DC_MEMORY)) { XWindowAttributes win_attr; if (!XGetWindowAttributes( XT_display, dc->u.x.drawable, &win_attr )) return 0; if (win_attr.map_state != IsViewable) return 0; if ((x >= win_attr.width) || (y >= win_attr.height)) return 0; } image = XGetImage( XT_display, dc->u.x.drawable, x, y, 1, 1, AllPlanes, ZPixmap ); GetPaletteEntries( dc->w.hPalette, XGetPixel( image, 0, 0 ), 1, &entry ); XDestroyImage( image ); return RGB( entry.peRed, entry.peGreen, entry.peBlue ); } /*********************************************************************** * PaintRgn (GDI.43) */ BOOL PaintRgn( HDC hdc, HRGN hrgn ) { RECT box; HRGN tmpVisRgn, prevVisRgn; DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ); if (!dc) return FALSE; /* Modify visible region */ prevVisRgn = SaveVisRgn( hdc ); if (prevVisRgn) { if (!(tmpVisRgn = CreateRectRgn( 0, 0, 0, 0 ))) { RestoreVisRgn( hdc ); return FALSE; } CombineRgn( tmpVisRgn, prevVisRgn, hrgn, RGN_AND ); SelectVisRgn( hdc, tmpVisRgn ); DeleteObject( tmpVisRgn ); } else SelectVisRgn( hdc, hrgn ); /* Fill the region */ GetClipBox( hdc, &box ); if (DC_SetupGCForBrush( dc )) XFillRectangle( XT_display, dc->u.x.drawable, dc->u.x.gc, dc->w.DCOrgX + box.left, dc->w.DCOrgY + box.top, box.right-box.left, box.bottom-box.top ); /* Restore the visible region */ if (prevVisRgn) RestoreVisRgn( hdc ); else SelectVisRgn( hdc, 0 ); return TRUE; } /*********************************************************************** * FillRgn (GDI.40) */ BOOL FillRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush ) { BOOL retval; HBRUSH prevBrush = SelectObject( hdc, hbrush ); if (!prevBrush) return FALSE; retval = PaintRgn( hdc, hrgn ); SelectObject( hdc, prevBrush ); return retval; } /*********************************************************************** * DrawFocusRect (USER.466) */ void DrawFocusRect( HDC hdc, LPRECT rc ) { HPEN hOldPen; int oldDrawMode, oldBkMode; int left, top, right, bottom; DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ); if (!dc) return; left = XLPTODP( dc, rc->left ); top = YLPTODP( dc, rc->top ); right = XLPTODP( dc, rc->right ); bottom = YLPTODP( dc, rc->bottom ); hOldPen = (HPEN)SelectObject(hdc, sysColorObjects.hpenWindowText ); oldDrawMode = SetROP2(hdc, R2_XORPEN); oldBkMode = SetBkMode(hdc, TRANSPARENT); if (DC_SetupGCForPen( dc )) XDrawRectangle( XT_display, dc->u.x.drawable, dc->u.x.gc, dc->w.DCOrgX + left, dc->w.DCOrgY + top, right-left-1, bottom-top-1 ); SetBkMode(hdc, oldBkMode); SetROP2(hdc, oldDrawMode); SelectObject(hdc, (HANDLE)hOldPen); } /********************************************************************** * DrawReliefRect (Not a MSWin Call) */ void DrawReliefRect( HDC hdc, RECT rect, int thickness, BOOL pressed ) { HBRUSH hbrushOld; int i; hbrushOld = SelectObject( hdc, pressed ? sysColorObjects.hbrushBtnShadow : sysColorObjects.hbrushBtnHighlight ); for (i = 0; i < thickness; i++) { PatBlt( hdc, rect.left + i, rect.top, 1, rect.bottom - rect.top - i, PATCOPY ); PatBlt( hdc, rect.left, rect.top + i, rect.right - rect.left - i, 1, PATCOPY ); } SelectObject( hdc, pressed ? sysColorObjects.hbrushBtnHighlight : sysColorObjects.hbrushBtnShadow ); for (i = 0; i < thickness; i++) { PatBlt( hdc, rect.right - i - 1, rect.top + i, 1, rect.bottom - rect.top - i, PATCOPY ); PatBlt( hdc, rect.left + i, rect.bottom - i - 1, rect.right - rect.left - i, 1, PATCOPY ); } SelectObject( hdc, hbrushOld ); } /********************************************************************** * Polyline (GDI.37) */ BOOL Polyline (HDC hdc, LPPOINT pt, int count) { register int i; DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ); if (DC_SetupGCForPen( dc )) { for (i = 0; i < count-1; i ++) XDrawLine (XT_display, dc->u.x.drawable, dc->u.x.gc, dc->w.DCOrgX + XLPTODP(dc, pt [i].x), dc->w.DCOrgY + YLPTODP(dc, pt [i].y), dc->w.DCOrgX + XLPTODP(dc, pt [i+1].x), dc->w.DCOrgY + YLPTODP(dc, pt [i+1].y)); XDrawLine (XT_display, dc->u.x.drawable, dc->u.x.gc, dc->w.DCOrgX + XLPTODP(dc, pt [count-1].x), dc->w.DCOrgY + YLPTODP(dc, pt [count-1].y), dc->w.DCOrgX + XLPTODP(dc, pt [0].x), dc->w.DCOrgY + YLPTODP(dc, pt [0].y)); } return (TRUE); } /********************************************************************** * Polygon (GDI.36) */ BOOL Polygon (HDC hdc, LPPOINT pt, int count) { register int i; DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ); XPoint *points = (XPoint *) malloc (sizeof (XPoint) * count+1); if (DC_SetupGCForBrush( dc )) { for (i = 0; i < count; i++) { points [i].x = dc->w.DCOrgX + XLPTODP(dc, pt [i].x); points [i].y = dc->w.DCOrgY + YLPTODP(dc, pt [i].y); } points [count] = points [0]; XFillPolygon( XT_display, dc->u.x.drawable, dc->u.x.gc, points, count, Complex, CoordModeOrigin); if (DC_SetupGCForPen ( dc )) { XDrawLines( XT_display, dc->u.x.drawable, dc->u.x.gc, points, count, CoordModeOrigin ); } } free ((void *) points); return (TRUE); } /********************************************************************** * FloodFill_rec -- FloodFill helper function * * Just does a recursive flood fill: * this is /not/ efficent -- a better way would be to draw * an entire line at a time, but this will do for now. */ static BOOL FloodFill_rec(XImage *image, int x, int y, int orgx, int orgy, int endx, int endy, Pixel borderp, Pixel fillp) { Pixel testp; if (x > endx || x < orgx || y > endy || y < orgy) return FALSE; XPutPixel(image, x, y, fillp); testp = XGetPixel(image, x+1, y+1); if (testp != borderp && testp != fillp) FloodFill_rec(image, x+1, y+1, orgx, orgy, endx, endy, borderp, fillp); testp = XGetPixel(image, x+1, y-1); if (testp != borderp && testp != fillp) FloodFill_rec(image, x+1, y-1, orgx, orgy, endx, endy, borderp, fillp); testp = XGetPixel(image, x-1, y+1); if (testp != borderp && testp != fillp) FloodFill_rec(image, x-1, y+1, orgx, orgy, endx, endy, borderp, fillp); testp = XGetPixel(image, x-1, y-1); if (testp != borderp && testp != fillp) FloodFill_rec(image, x-1, y-1, orgx, orgy, endx, endy, borderp, fillp); return TRUE; } /********************************************************************** * FloodFill (GDI.25) */ BOOL FloodFill(HDC hdc, short x, short y, DWORD crColor) { Pixel boundrypixel; int imagex, imagey; XImage *image; DC *dc; #ifdef DEBUG_GRAPHICS printf("FloodFill %x %d,%d %x\n", hdc, x, y, crColor); #endif dc = (DC *) GDI_GetObjPtr(hdc, DC_MAGIC); if (!dc) return 0; x = dc->w.DCOrgX + XLPTODP(dc, x); y = dc->w.DCOrgY + YLPTODP(dc, y); if (x < dc->w.DCOrgX || x > dc->w.DCOrgX + dc->w.DCSizeX || y < dc->w.DCOrgY || y > dc->w.DCOrgY + dc->w.DCSizeY) return 0; if (!DC_SetupGCForBrush(dc)) return FALSE; boundrypixel = GetNearestPaletteIndex( dc->w.hPalette, crColor ); image = XGetImage(display, dc->u.x.drawable, dc->w.DCOrgX, dc->w.DCOrgY, dc->w.DCSizeX, dc->w.DCSizeY, AllPlanes, ZPixmap); if (XGetPixel(image, x, y) == boundrypixel) return FALSE; if (!FloodFill_rec(image, x, y, 0,0, dc->w.DCOrgX + dc->w.DCSizeX, dc->w.DCOrgY + dc->w.DCSizeY, boundrypixel, dc->u.x.brush.pixel)) { XDestroyImage(image); return 0; } XPutImage(display, dc->u.x.drawable, dc->u.x.gc, image, 0, 0, dc->w.DCOrgX, dc->w.DCOrgY, dc->w.DCSizeX, dc->w.DCSizeY); XDestroyImage(image); return TRUE; }