blob: 2594c917b769252394fba702b810a16eb4277394 [file] [log] [blame]
/*
* GDI graphics operations
*
* Copyright 1993 Alexandre Julliard
*/
static char Copyright[] = "Copyright Alexandre Julliard, 1993";
#include <math.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Intrinsic.h>
#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;
}