iup-stack/iup/srccd/iup_draw_cd.c

533 lines
14 KiB
C
Executable File

/** \file
* \brief IupDraw driver
*
* See Copyright Notice in cd.h
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <cd.h>
#include <cd_private.h>
#include "iup.h"
#include "iupdraw_cd.h"
#include "iup_drvdraw.h"
#include "iup_drvfont.h"
struct _cdCtxCanvas
{
cdCanvas* canvas;
Ihandle* ih;
IdrawCanvas* dc;
};
static void cdkillcanvas(cdCtxCanvas *ctxcanvas)
{
if (ctxcanvas->dc)
iupdrvDrawKillCanvas(ctxcanvas->dc);
memset(ctxcanvas, 0, sizeof(cdCtxCanvas));
free(ctxcanvas);
}
static int cdactivate(cdCtxCanvas *ctxcanvas)
{
int w, h;
if (ctxcanvas->dc)
iupdrvDrawKillCanvas(ctxcanvas->dc);
ctxcanvas->dc = iupdrvDrawCreateCanvas(ctxcanvas->ih);
iupdrvDrawGetSize(ctxcanvas->dc, &w, &h);
ctxcanvas->canvas->bpp = IupGetInt(NULL, "SCREENDEPTH");
ctxcanvas->canvas->xres = IupGetDouble(NULL, "SCREENDPI") / 25.4;
ctxcanvas->canvas->yres = ctxcanvas->canvas->xres;
ctxcanvas->canvas->w = w;
ctxcanvas->canvas->h = h;
ctxcanvas->canvas->w_mm = ((double)w) / ctxcanvas->canvas->xres;
ctxcanvas->canvas->h_mm = ((double)h) / ctxcanvas->canvas->yres;
ctxcanvas->canvas->invert_yaxis = 1;
return CD_OK;
}
static void cdflush(cdCtxCanvas *ctxcanvas)
{
if (ctxcanvas->dc)
iupdrvDrawFlush(ctxcanvas->dc);
}
static void cdclear(cdCtxCanvas* ctxcanvas)
{
if (ctxcanvas->dc)
iupdrvDrawRectangle(ctxcanvas->dc, 0, 0, ctxcanvas->canvas->w - 1, ctxcanvas->canvas->h - 1, cdCanvasBackground(ctxcanvas->canvas, CD_QUERY), CD_FILL, 1);
}
static int cdfont(cdCtxCanvas *ctxcanvas, const char *type_face, int style, int size)
{
int is_italic = 0, is_bold = 0; /* default is CD_PLAIN */
int is_strikeout = 0, is_underline = 0;
char font[1024];
if (style & CD_BOLD)
is_bold = 1;
if (style & CD_ITALIC)
is_italic = 1;
if (style & CD_UNDERLINE)
is_underline = 1;
if (style & CD_STRIKEOUT)
is_strikeout = 1;
sprintf(font, "%s, %s%s%s%s%d", type_face, is_bold ? "Bold " : "", is_italic ? "Italic " : "", is_underline ? "Underline " : "", is_strikeout ? "Strikeout " : "", size);
/* store in native font and manually save font parameters */
strcpy(ctxcanvas->canvas->native_font, font);
strcpy(ctxcanvas->canvas->font_type_face, type_face);
ctxcanvas->canvas->font_style = style;
ctxcanvas->canvas->font_size = size;
return 0;
}
static void cdgetfontdim(cdCtxCanvas* ctxcanvas, int *max_width, int *line_height, int *ascent, int *descent)
{
iupdrvFontGetFontDim(ctxcanvas->canvas->native_font, max_width, line_height, ascent, descent);
}
static void cdgettextsize(cdCtxCanvas* ctxcanvas, const char *s, int len, int *width, int *height)
{
iupdrvFontGetTextSize(ctxcanvas->canvas->native_font, s, len, width, height);
}
static void cdcliparea(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax)
{
if (ctxcanvas->canvas->clip_mode == CD_CLIPAREA)
iupdrvDrawSetClipRect(ctxcanvas->dc, xmin, ymin, xmax, ymax);
}
static int cdclip(cdCtxCanvas *ctxcanvas, int mode)
{
if (mode == CD_CLIPAREA)
iupdrvDrawSetClipRect(ctxcanvas->dc, ctxcanvas->canvas->clip_rect.xmin, ctxcanvas->canvas->clip_rect.ymin, ctxcanvas->canvas->clip_rect.xmax, ctxcanvas->canvas->clip_rect.ymax);
else if (mode == CD_CLIPOFF)
iupdrvDrawResetClip(ctxcanvas->dc);
else if (mode == CD_CLIPPOLYGON || mode == CD_CLIPREGION)
return ctxcanvas->canvas->clip_mode;
return mode;
}
/******************************************************/
/* primitives */
/******************************************************/
static int cd2iup_linestyle(cdCtxCanvas *ctxcanvas)
{
if (ctxcanvas->canvas->line_style == CD_DASHED)
return IUP_DRAW_STROKE_DASH;
else if (ctxcanvas->canvas->line_style == CD_DOTTED)
return IUP_DRAW_STROKE_DOT;
else if (ctxcanvas->canvas->line_style == CD_DASH_DOT)
return IUP_DRAW_STROKE_DASH_DOT;
else if (ctxcanvas->canvas->line_style == CD_DASH_DOT_DOT)
return IUP_DRAW_STROKE_DASH_DOT_DOT;
else
return IUP_DRAW_STROKE;
}
static void cdline(cdCtxCanvas *ctxcanvas, int px1, int py1, int px2, int py2)
{
if (ctxcanvas->dc)
iupdrvDrawLine(ctxcanvas->dc, px1, py1, px2, py2, ctxcanvas->canvas->foreground, cd2iup_linestyle(ctxcanvas), ctxcanvas->canvas->line_width);
}
static void cdrect(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax)
{
if (ctxcanvas->dc)
iupdrvDrawRectangle(ctxcanvas->dc, xmin, ymin, xmax, ymax, ctxcanvas->canvas->foreground, cd2iup_linestyle(ctxcanvas), ctxcanvas->canvas->line_width);
}
static void cdbox(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax)
{
if (ctxcanvas->dc)
iupdrvDrawRectangle(ctxcanvas->dc, xmin, ymin, xmax, ymax, ctxcanvas->canvas->foreground, IUP_DRAW_FILL, ctxcanvas->canvas->line_width);
}
static void cdarc(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2)
{
int rx = w / 2;
int ry = h / 2;
int x1 = xc - rx;
int y1 = yc - ry;
int x2 = xc + rx;
int y2 = yc + ry;
if (ctxcanvas->dc)
iupdrvDrawArc(ctxcanvas->dc, x1, y1, x2, y2, a1, a2, ctxcanvas->canvas->foreground, cd2iup_linestyle(ctxcanvas), ctxcanvas->canvas->line_width);
}
static void cdsector(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2)
{
int rx = w / 2;
int ry = h / 2;
int x1 = xc - rx;
int y1 = yc - ry;
int x2 = xc + rx;
int y2 = yc + ry;
if (ctxcanvas->dc)
iupdrvDrawArc(ctxcanvas->dc, x1, y1, x2, y2, a1, a2, ctxcanvas->canvas->foreground, IUP_DRAW_FILL, ctxcanvas->canvas->line_width);
}
/* TODO: not exported in CD dll yet */
static void x_cdRotatePoint(cdCanvas* canvas, int x, int y, int cx, int cy, int *rx, int *ry, double sin_theta, double cos_theta)
{
double t;
/* translate to (cx,cy) */
x = x - cx;
y = y - cy;
/* rotate */
if (canvas->invert_yaxis)
{
t = (x * cos_theta) + (y * sin_theta); *rx = _cdRound(t);
t = -(x * sin_theta) + (y * cos_theta); *ry = _cdRound(t);
}
else
{
t = (x * cos_theta) - (y * sin_theta); *rx = _cdRound(t);
t = (x * sin_theta) + (y * cos_theta); *ry = _cdRound(t);
}
/* translate back */
*rx = *rx + cx;
*ry = *ry + cy;
}
static void cdtext(cdCtxCanvas *ctxcanvas, int x, int y, const char *s, int len)
{
int w, h, desc;
int ox = x, oy = y;
/* cxText method is called for single lines only */
iupdrvFontGetFontDim(ctxcanvas->canvas->native_font, NULL, NULL, NULL, &desc);
iupdrvFontGetTextSize(ctxcanvas->canvas->native_font, s, len, &w, &h);
/* move to top-left corner of the text */
switch (ctxcanvas->canvas->text_alignment)
{
case CD_BASE_RIGHT:
case CD_NORTH_EAST:
case CD_EAST:
case CD_SOUTH_EAST:
x = x - w;
break;
case CD_BASE_CENTER:
case CD_CENTER:
case CD_NORTH:
case CD_SOUTH:
x = x - w / 2;
break;
case CD_BASE_LEFT:
case CD_NORTH_WEST:
case CD_WEST:
case CD_SOUTH_WEST:
x = x;
break;
}
switch (ctxcanvas->canvas->text_alignment)
{
case CD_BASE_LEFT:
case CD_BASE_CENTER:
case CD_BASE_RIGHT:
y = y - h + desc;
break;
case CD_SOUTH_EAST:
case CD_SOUTH_WEST:
case CD_SOUTH:
y = y - h;
break;
case CD_NORTH_EAST:
case CD_NORTH:
case CD_NORTH_WEST:
y = y;
break;
case CD_CENTER:
case CD_EAST:
case CD_WEST:
y = y - h / 2;
break;
}
if (ctxcanvas->canvas->text_orientation)
{
double cos_angle = cos(ctxcanvas->canvas->text_orientation*CD_DEG2RAD);
double sin_angle = sin(ctxcanvas->canvas->text_orientation*CD_DEG2RAD);
x_cdRotatePoint(ctxcanvas->canvas, x, y, ox, oy, &x, &y, sin_angle, cos_angle);
}
if (ctxcanvas->dc)
iupdrvDrawText(ctxcanvas->dc, s, len, x, y, w, h, ctxcanvas->canvas->foreground, ctxcanvas->canvas->native_font, IUP_DRAW_LEFT, ctxcanvas->canvas->text_orientation); /* left alignment - unused, multiline alignment is done by CD, layout is NOT centered */
}
static void cdpoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n)
{
int style;
if (mode == CD_BEZIER)
{
/* cdSimPolyBezier(ctxcanvas->canvas, poly, n); TODO: not exported in CD dll yet */
return;
}
if (mode == CD_PATH)
{
cdSimPolyPath(ctxcanvas->canvas, poly, n);
return;
}
if (mode == CD_CLIP || mode == CD_REGION)
return;
if (mode == CD_CLOSED_LINES || mode == CD_FILL)
{
poly[n].x = poly[0].x;
poly[n].y = poly[0].y;
n++;
}
if (mode == CD_FILL && ctxcanvas->canvas->interior_style == CD_HOLLOW)
mode = CD_CLOSED_LINES;
if (mode == CD_FILL)
style = IUP_DRAW_STROKE;
else
style = cd2iup_linestyle(ctxcanvas);
if (ctxcanvas->dc)
iupdrvDrawPolygon(ctxcanvas->dc, (int*)poly, n, ctxcanvas->canvas->foreground, style, ctxcanvas->canvas->line_width);
}
/******************************************************/
/* client images */
/******************************************************/
static void sFixImageY(int *y, int h)
{
*y -= (h - 1); /* move Y to top-left corner, since it was at the bottom of the image */
}
static void cdputimagerectrgba(cdCtxCanvas* ctxcanvas, int width, int height, const unsigned char *red,
const unsigned char *green, const unsigned char *blue, const unsigned char *alpha, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax)
{
int i, j, count;
Ihandle *image;
int pos;
unsigned char *rgba;
int dy = y;
int nw, nh;
sFixImageY(&dy, height);
nw = xmax - xmin + 1;
nh = ymax - ymin + 1;
image = IupImageRGBA(nw, nh, NULL);
IupSetHandle("_IUPDRAW_CD_IMAGE", image);
rgba = (unsigned char*)IupGetAttribute(image, "WID");
count = 0;
for (i = ymin; i <= ymax; i++)
{
for (j = xmin; j <= xmax; j++)
{
pos = (ymax + ymin - i)*width + j;
rgba[count++] = red[pos];
rgba[count++] = green[pos];
rgba[count++] = blue[pos];
rgba[count++] = alpha[pos];
}
}
if (ctxcanvas->dc)
iupdrvDrawImage(ctxcanvas->dc, "_IUPDRAW_CD_IMAGE", 0, NULL, x, dy, w, h);
IupDestroy(image);
IupSetHandle("_IUPDRAW_CD_IMAGE", NULL);
}
static void cdputimagerectrgb(cdCtxCanvas* ctxcanvas, int width, int height, const unsigned char *red,
const unsigned char *green, const unsigned char *blue, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax)
{
int i, j, count;
Ihandle *image;
int pos;
unsigned char *rgb;
int dy = y;
int nw, nh;
sFixImageY(&dy, height);
nw = xmax - xmin + 1;
nh = ymax - ymin + 1;
image = IupImageRGB(nw, nh, NULL);
IupSetHandle("_IUPDRAW_CD_IMAGE", image);
rgb = (unsigned char*)IupGetAttribute(image, "WID");
count = 0;
for (i = ymin; i <= ymax; i++)
{
for (j = xmin; j <= xmax; j++)
{
pos = (ymax + ymin - i)*width + j;
rgb[count++] = red[pos];
rgb[count++] = green[pos];
rgb[count++] = blue[pos];
}
}
if (ctxcanvas->dc)
iupdrvDrawImage(ctxcanvas->dc, "_IUPDRAW_CD_IMAGE", 0, NULL, x, dy, w, h);
IupDestroy(image);
IupSetHandle("_IUPDRAW_CD_IMAGE", NULL);
}
static void cdputimagerectmap(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *index, const long *colors,
int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax)
{
int i, j, count;
int pos;
Ihandle *image;
unsigned char *map;
int dy = y;
char name[60];
int nh, nw;
sFixImageY(&dy, ih);
nw = xmax - xmin + 1;
nh = ymax - ymin + 1;
image = IupImage(nw, nh, NULL);
IupSetHandle("_IUPDRAW_CD_IMAGE", image);
map = (unsigned char*)IupGetAttribute(image, "WID");
for (i = 0; i < 256; i++)
{
sprintf(name, "%d", i);
IupSetRGB(image, name, cdRed(colors[i]), cdGreen(colors[i]), cdBlue(colors[i]));
}
count = 0;
for (i = ymin; i <= ymax; i++)
{
for (j = xmin; j <= xmax; j++)
{
pos = (ymax + ymin - i)*iw + j;
map[count++] = index[pos];
}
}
if (ctxcanvas->dc)
iupdrvDrawImage(ctxcanvas->dc, "_IUPDRAW_CD_IMAGE", 0, NULL, x, dy, w, h);
IupDestroy(image);
IupSetHandle("_IUPDRAW_CD_IMAGE", NULL);
}
/******************************************************/
/* server images */
/******************************************************/
static void cdpixel(cdCtxCanvas *ctxcanvas, int x, int y, long color)
{
if (ctxcanvas->dc)
iupdrvDrawArc(ctxcanvas->dc, x, y, x, y, 0.0, 360.0, color, CD_FILL, 1);
}
static void cdcreatecanvas(cdCanvas* canvas, Ihandle *ih)
{
cdCtxCanvas *ctxcanvas;
ctxcanvas = (cdCtxCanvas *)malloc(sizeof(cdCtxCanvas));
memset(ctxcanvas, 0, sizeof(cdCtxCanvas));
ctxcanvas->canvas = canvas;
ctxcanvas->ih = ih;
canvas->ctxcanvas = ctxcanvas;
ctxcanvas->canvas->bpp = IupGetInt(NULL, "SCREENDEPTH");
ctxcanvas->canvas->xres = IupGetDouble(NULL, "SCREENDPI") / 25.4;
ctxcanvas->canvas->yres = ctxcanvas->canvas->xres;
IupSetAttribute(ih, "_CD_CANVAS", (char*)canvas);
}
static void cdinittable(cdCanvas* canvas)
{
/* initialize function table*/
canvas->cxFlush = cdflush;
canvas->cxClear = cdclear;
canvas->cxPixel = cdpixel;
canvas->cxLine = cdline;
canvas->cxPoly = cdpoly;
canvas->cxRect = cdrect;
canvas->cxBox = cdbox;
canvas->cxArc = cdarc;
canvas->cxSector = cdsector;
canvas->cxChord = cdSimChord;
canvas->cxText = cdtext;
canvas->cxPutImageRectRGBA = cdputimagerectrgba;
canvas->cxPutImageRectRGB = cdputimagerectrgb;
canvas->cxPutImageRectMap = cdputimagerectmap;
canvas->cxClip = cdclip;
canvas->cxClipArea = cdcliparea;
canvas->cxFont = cdfont;
canvas->cxGetFontDim = cdgetfontdim;
canvas->cxGetTextSize = cdgettextsize;
canvas->cxKillCanvas = cdkillcanvas;
canvas->cxActivate = cdactivate;
}
/******************************************************/
static cdContext cdIupDrawContext =
{
CD_CAP_ALL & ~(CD_CAP_PLAY | CD_CAP_YAXIS | CD_CAP_FPRIMTIVES | CD_CAP_GETIMAGERGB |
CD_CAP_IMAGESRV | CD_CAP_BACKOPACITY | CD_CAP_WRITEMODE | CD_CAP_HATCH | CD_CAP_STIPPLE | CD_CAP_PATTERN |
CD_CAP_LINECAP | CD_CAP_LINEJOIN | CD_CAP_PATH | CD_CAP_BEZIER |
CD_CAP_PALETTE | CD_CAP_CLIPPOLY | CD_CAP_REGION | CD_CAP_CHORD),
CD_CTX_WINDOW,
cdcreatecanvas,
cdinittable,
NULL,
NULL,
};
cdContext* cdContextIupDraw(void)
{
return &cdIupDrawContext;
}