diff --git a/gtkarea/draw.c b/gtkarea/draw.c index bf3448f3..00f32a4a 100644 --- a/gtkarea/draw.c +++ b/gtkarea/draw.c @@ -48,6 +48,20 @@ void uiDrawRectangle(uiDrawContext *c, intmax_t x, intmax_t y, intmax_t width, i cairo_rectangle(c->cr, (double) x + 0.5, (double) y + 0.5, width, height); } +void uiDrawArc(uiDrawContext *c, intmax_t xCenter, intmax_t yCenter, intmax_t radius, double startAngle, double endAngle, int lineFromCurrentPointToStart) +{ + if (!lineFromCurrentPointToStart) + cairo_new_sub_path(c->cr); + // the Windows AngleArc() function only goes counterclockwise, so our uiDrawArc() function does too + // simulate it in cairo by drawing a negative arc from end to start + cairo_arc_negative(c->cr, + ((double) xCenter) + 0.5, + ((double) yCenter) + 0.5, + radius, + endAngle, + startAngle); +} + void uiDrawCloseFigure(uiDrawContext *c) { cairo_close_path(c->cr); diff --git a/gtkarea/draw_windows.c b/gtkarea/draw_windows.c new file mode 100644 index 00000000..956f0512 --- /dev/null +++ b/gtkarea/draw_windows.c @@ -0,0 +1,120 @@ +// 7 september 2015 +#include "area.h" + +struct uiDrawContext { + HDC mainDC; + + // when drawing in RGBA mode, we need to use this + HDC alphaDC; + HBITMAP alphaBitmap; + + // and this is the DC we actually draw to, either mainDC or alphaDC + HDC currentDC; + + // source color + BOOL useRGB; + BOOL useAlpha; + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; +}; + +uiDrawContext *newContext(HDC dc) +{ + uiDrawContext *c; + + c = (uiDrawContext *) g_malloc0(sizeof (uiDrawContext)); + c->mainDC = dc; + return c; +} + +void uiDrawBeginPathRGB(uiDrawContext *c, uint8_t r, uint8_t g, uint8_t b) +{ + c->useRGB = TRUE; + c->useAlpha = FALSE; + c->r = r; + c->g = g; + c->b = b; + c->currentDC = c->mainDC; + if (BeginPath(c->currentDC) == 0) + logLastError("error beginning new path in uiDrawBeginPathRGB()"); +} + +void uiDrawBeginPathRGBA(uiDrawContext *c, uint8_t r, uint8_t g, uint8_t b, uint8_t a) +{ + // TODO +} + +void uiDrawMoveTo(uiDrawContext *c, intmax_t x, intmax_t y) +{ + if (MoveToEx(c->currentDC, x, y, NULL) == 0) + logLastError("error moving to point in uiDrawMoveTo()"); +} + +void uiDrawLineTo(uiDrawContext *c, intmax_t x, intmax_t y) +{ + if (LineTo(c->currentDC, x, y) == 0) + logLastError("error drawing line in uiDrawLineTo()"); +} + +void uiDrawRectangle(uiDrawContext *c, intmax_t x, intmax_t y, intmax_t width, intmax_t height) +{ + if (Rectangle(c->currentDC, x, y, x + width, y + height) == 0) + logLastError("error drawing rectangle in uiDrawRectangle()"); +} + +void uiDrawArc(uiDrawContext *c, intmax_t xCenter, intmax_t yCenter, intmax_t radius, double startAngle, double endAngle, int lineFromCurrentPointToStart) +{ + if (!lineFromCurrentPointToStart) { + // TODO + } + // TODO convert radians to degrees + if (AngleArc(c->currentDC, + xCenter, yCenter + radius, + startAngle, + // the "sweep angle" is relative to the start angle, not to 0 + endAngle - startAngle) == 0) + logLastError("error drawing arc in uiDrawArc()"); +} + +void uiDrawCloseFigure(uiDrawContext *c) +{ + if (CloseFigure(c->currentDC) == 0) + logLastError("error closing figure in uiDrawCloseFigure()"); +} + +void uiDrawStroke(uiDrawContext *c, uiDrawStrokeParams *p) +{ + // TODO + + switch (p->Cap) { + case uiDrawLineCapFlat: + break; + case uiDrawLineCapRound: + break; + case uiDrawLineCapSquare: + break; + } + switch (p->Join) { + case uiDrawLineJoinMiter: + break; + case uiDrawLineJoinRound: + break; + case uiDrawLineJoinBevel: + break; + } +} + +void uiDrawFill(uiDrawContext *c, uiDrawFillMode mode) +{ + // TODO + + switch (mode) { + case uiDrawFillModeWinding: + break; + case uiDrawFillModeAlternate: + break; + } +} diff --git a/gtkarea/main.c b/gtkarea/main.c index 052ffab7..a5e39bc2 100644 --- a/gtkarea/main.c +++ b/gtkarea/main.c @@ -1,4 +1,6 @@ // 4 september 2015 +#define _GNU_SOURCE +#include #include "area.h" // #qo pkg-config: gtk+-3.0 @@ -48,6 +50,31 @@ static void handlerDraw(uiAreaHandler *a, uiArea *area, uiAreaDrawParams *p) sp.Thickness = 1; sp.MiterLimit = uiDrawDefaultMiterLimit; uiDrawStroke(p->Context, &sp); + + uiDrawBeginPathRGB(p->Context, 0x80, 0xC0, 0x00); + uiDrawMoveTo(p->Context, 400, 100); + uiDrawArc(p->Context, + 400, 100, + 50, + 30. * (M_PI / 180.), + // note the end angle here + // in GDI, the second angle to AngleArc() is relative to the start, not to 0 + 330. * (M_PI / 180.), + 1); + // TODO add a checkbox for this + uiDrawLineTo(p->Context, 400, 100); + uiDrawArc(p->Context, + 510, 100, + 50, + 30. * (M_PI / 180.), + 330. * (M_PI / 180.), + 0); + uiDrawCloseFigure(p->Context); + sp.Cap = uiDrawLineCapFlat; + sp.Join = uiDrawLineJoinMiter; + sp.Thickness = 1; + sp.MiterLimit = uiDrawDefaultMiterLimit; + uiDrawStroke(p->Context, &sp); } static uintmax_t handlerHScrollMax(uiAreaHandler *a, uiArea *area) diff --git a/gtkarea/ui.h b/gtkarea/ui.h index a9d785e8..5ad72609 100644 --- a/gtkarea/ui.h +++ b/gtkarea/ui.h @@ -78,6 +78,8 @@ void uiDrawBeginPathRGBA(uiDrawContext *, uint8_t, uint8_t, uint8_t, uint8_t); void uiDrawMoveTo(uiDrawContext *, intmax_t, intmax_t); void uiDrawLineTo(uiDrawContext *, intmax_t, intmax_t); void uiDrawRectangle(uiDrawContext *, intmax_t, intmax_t, intmax_t, intmax_t); +// notes: angles are both relative to 0 and go counterclockwise +void uiDrawArc(uiDrawContext *, intmax_t, intmax_t, intmax_t, double, double, int); void uiDrawCloseFigure(uiDrawContext *); void uiDrawStroke(uiDrawContext *, uiDrawStrokeParams *); @@ -87,8 +89,8 @@ void uiDrawFill(uiDrawContext *, uiDrawFillMode); // cairo gdi core graphics // move_to MoveToEx MoveToPoint // line_to LineTo AddLineToPoint -// arc Arc/ArcTo/AngleArc/Ellipse AddArc/AddArcToPoint/AddEllipseInRect -// arc_negative Pie AddArc/AddArcToPoint +// arc Arc/ArcTo/AngleArc/Pie AddArc/AddArcToPoint/AddEllipseInRect +// arc_negative Arc/ArcTo/AngleArc/Pie AddArc/AddArcToPoint // curve_to PolyBezier/PolyBezierTo AddCurveToPoint // rectangle Rectangle AddRect // [arc functions?] Chord [arc functions?] @@ -112,3 +114,26 @@ void uiDrawFill(uiDrawContext *, uiDrawFillMode); // - arbitrary patterns // - solid colors, arbitrary spaces // - shadows + +// arcs +// cairo_arc/arc_negative +// - parameters: center, radius, angle1 radians, angle2 radins +// - if angle2 < angle1, TODO +// - if angle2 > angle1, TODO +// - line segment from current point to beginning of arc +// - arc: clockwise, arc_negative: counterclockwise +// - circular +// GDI Arc/Pie +// - parameters: bounding box, start point, end point +// - current position not used/changed +// - either clockwise or counterclockwise +// - elliptical +// GDI ArcTo +// - same as Arc except line segment from current point to beginning of arc +// - there does not appear to be a PieTo +// GDI AngleArc +// - parameters: center, radius, angle1 degrees, angle2 degrees +// - line segment from current position to beginning of arc +// - counterclockwise +// - circular +// - can be used to draw pies too; MSDN example demonstrates