From 51e60359ab28e7086767ab6eb3084e438213d4d4 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Thu, 10 Sep 2015 14:27:45 -0400 Subject: [PATCH] Set up a custom NSScrollView clone to see if that's more or less feasible than hijacking NSScrollView itself. Doesn't do scrolling yet. --- macarea/alt/area.h | 12 +++ macarea/alt/area.m | 242 +++++++++++++++++++++++++++++++++++++++++++++ macarea/alt/draw.m | 148 +++++++++++++++++++++++++++ macarea/alt/main.m | 171 ++++++++++++++++++++++++++++++++ macarea/alt/ui.h | 138 ++++++++++++++++++++++++++ 5 files changed, 711 insertions(+) create mode 100644 macarea/alt/area.h create mode 100644 macarea/alt/area.m create mode 100644 macarea/alt/draw.m create mode 100644 macarea/alt/main.m create mode 100644 macarea/alt/ui.h diff --git a/macarea/alt/area.h b/macarea/alt/area.h new file mode 100644 index 00000000..4575d5f0 --- /dev/null +++ b/macarea/alt/area.h @@ -0,0 +1,12 @@ +// 8 september 2015 +#import +#import +#import "ui.h" + +extern uiArea *newArea(uiAreaHandler *ah); + +extern uiDrawContext *newContext(CGContextRef); + +extern NSView *areaGetView(uiArea *); + +extern void areaUpdateScroll(uiArea *); diff --git a/macarea/alt/area.m b/macarea/alt/area.m new file mode 100644 index 00000000..b99543cd --- /dev/null +++ b/macarea/alt/area.m @@ -0,0 +1,242 @@ +// 9 september 2015 +#include "area.h" + +// TODO remove this +void addConstraint(NSView *view, NSString *constraint, NSDictionary *metrics, NSDictionary *views) +{ + NSArray *constraints; + + constraints = [NSLayoutConstraint constraintsWithVisualFormat:constraint + options:0 + metrics:metrics + views:views]; + [view addConstraints:constraints]; +} + +// NSScrollers have no intrinsic size; here we give it one +@interface areaScroller : NSScroller { + BOOL libui_vertical; +} +- (id)initWithFrame:(NSRect)r vertical:(BOOL)v; +@end + +@implementation areaScroller + +- (id)initWithFrame:(NSRect)r vertical:(BOOL)v +{ + self = [super initWithFrame:r]; + if (self) + self->libui_vertical = v; + return self; +} + +- (NSSize)intrinsicContentSize +{ + NSSize s; + CGFloat scrollerWidth; + + s = [super intrinsicContentSize]; + scrollerWidth = [NSScroller scrollerWidthForControlSize:[self controlSize] + scrollerStyle:[self scrollerStyle]]; + if (self->libui_vertical) + s.width = scrollerWidth; + else + s.height = scrollerWidth; + return s; +} + +- (void)setControlSize:(NSControlSize)size +{ + [super setControlSize:size]; + [self invalidateIntrinsicContentSize]; +} + +- (void)setScrollerStyle:(NSScrollerStyle)style +{ + [super setScrollerStyle:style]; + [self invalidateIntrinsicContentSize]; +} + +@end + +@interface areaDrawingView : NSView { + uiArea *libui_a; +} +- (id)initWithFrame:(NSRect)r area:(uiArea *)a; +@end + +@interface areaView : NSView { + uiArea *libui_a; + areaDrawingView *drawingView; + areaScroller *hscrollbar; + areaScroller *vscrollbar; +} +- (id)initWithFrame:(NSRect)r area:(uiArea *)a; +@end + +struct uiArea { +// uiDarwinControl c; + areaView *view; + uiAreaHandler *ah; +}; + +@implementation areaDrawingView + +- (id)initWithFrame:(NSRect)r area:(uiArea *)a +{ + self = [super initWithFrame:r]; + if (self) + self->libui_a = a; + return self; +} + +- (void)drawRect:(NSRect)r +{ + CGContextRef c; + uiAreaDrawParams dp; + + c = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort]; + dp.Context = newContext(c); + + dp.ClientWidth = [self frame].size.width; + dp.ClientHeight = [self frame].size.height; + + dp.ClipX = r.origin.x; + dp.ClipY = r.origin.y; + dp.ClipWidth = r.size.width; + dp.ClipHeight = r.size.height; + + // TODO DPI + + // TODO scroll position + + (*(self->libui_a->ah->Draw))(self->libui_a->ah, self->libui_a, &dp); +} + +- (BOOL)isFlipped +{ + return YES; +} + +@end + +@implementation areaView + +- (id)initWithFrame:(NSRect)r area:(uiArea *)a +{ + NSScrollerStyle style; + CGFloat swidth; + NSMutableDictionary *views; + NSLayoutConstraint *constraint; + + self = [super initWithFrame:r]; + if (self) { + self->libui_a = a; + + self->drawingView = [[areaDrawingView alloc] initWithFrame:NSZeroRect area:self->libui_a]; + [self->drawingView setTranslatesAutoresizingMaskIntoConstraints:NO]; + + style = [NSScroller preferredScrollerStyle]; + swidth = [NSScroller scrollerWidthForControlSize:NSRegularControlSize + scrollerStyle:style]; + + self->hscrollbar = [[areaScroller alloc] + initWithFrame:NSMakeRect(0, 0, swidth * 5, swidth) + vertical:NO]; + [self->hscrollbar setScrollerStyle:style]; + [self->hscrollbar setKnobStyle:NSScrollerKnobStyleDefault]; + [self->hscrollbar setControlTint:NSDefaultControlTint]; + [self->hscrollbar setControlSize:NSRegularControlSize]; +//TODO [self->hscrollbar setArrowsPosition:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]; + [self->hscrollbar setTranslatesAutoresizingMaskIntoConstraints:NO]; + + self->vscrollbar = [[areaScroller alloc] + initWithFrame:NSMakeRect(0, 0, swidth, swidth * 5) + vertical:YES]; + [self->vscrollbar setScrollerStyle:style]; + [self->vscrollbar setKnobStyle:NSScrollerKnobStyleDefault]; + [self->vscrollbar setControlTint:NSDefaultControlTint]; + [self->vscrollbar setControlSize:NSRegularControlSize]; +//TODO [self->vscrollbar setArrowsPosition:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]; + [self->vscrollbar setTranslatesAutoresizingMaskIntoConstraints:NO]; + + [self addSubview:self->drawingView]; + [self addSubview:self->hscrollbar]; + [self addSubview:self->vscrollbar]; + + // use visual constraints to arrange: + // - the drawing view and vertical scrollbar horizontally + // - the drawing view and horizontal scrollbar vertically + // - the horizontal scrollbar flush left + // - the vertical scrollbar flush top + views = [NSMutableDictionary new]; + [views setObject:self->drawingView forKey:@"drawingView"]; + [views setObject:self->hscrollbar forKey:@"hscrollbar"]; + [views setObject:self->vscrollbar forKey:@"vscrollbar"]; + addConstraint(self, @"H:|[drawingView][vscrollbar]|", nil, views); + addConstraint(self, @"V:|[drawingView][hscrollbar]|", nil, views); + addConstraint(self, @"H:|[hscrollbar]", nil, views); + addConstraint(self, @"V:|[vscrollbar]", nil, views); + [views release]; + + // use explicit layout constraints to line up + // - the bottom edge of the drawing view with the bottom edge of the vertical scrollbar + // - the right edge of the drawing view with the right edge of the horizontal scrollbar + constraint = [NSLayoutConstraint constraintWithItem:self->drawingView + attribute:NSLayoutAttributeBottom + relatedBy:NSLayoutRelationEqual + toItem:self->vscrollbar + attribute:NSLayoutAttributeBottom + multiplier:1 + constant:0]; + [self addConstraint:constraint]; + [constraint release]; + constraint = [NSLayoutConstraint constraintWithItem:self->drawingView + attribute:NSLayoutAttributeRight + relatedBy:NSLayoutRelationEqual + toItem:self->hscrollbar + attribute:NSLayoutAttributeRight + multiplier:1 + constant:0]; + [self addConstraint:constraint]; + [constraint release]; + } + return self; +} + +@end + +uiArea *newArea(uiAreaHandler *ah) +{ + uiArea *a; + + // TODO + a = (uiArea *) malloc(sizeof (uiArea)); + + a->ah = ah; + + a->view = [[areaView alloc] initWithFrame:NSZeroRect area:a]; + + // set initial state + // TODO do this on other platforms? + areaUpdateScroll(a); + + return a; +} + +NSView *areaGetView(uiArea *a) +{ + return a->view; +} + +void areaUpdateScroll(uiArea *a) +{ +/* TODO + NSRect frame; + + frame.origin = NSMakePoint(0, 0); + frame.size.width = (*(a->ah->HScrollMax))(a->ah, a); + frame.size.height = (*(a->ah->VScrollMax))(a->ah, a); + [a->documentView setFrame:frame]; +*/ +} diff --git a/macarea/alt/draw.m b/macarea/alt/draw.m new file mode 100644 index 00000000..753ecfc1 --- /dev/null +++ b/macarea/alt/draw.m @@ -0,0 +1,148 @@ +// 6 september 2015 +#include "area.h" + +// TODO some pixel thick lines aren't actually pixel thick + +struct uiDrawContext { + CGContextRef c; + + BOOL useRGBA; + CGFloat r; + CGFloat g; + CGFloat b; + CGFloat a; +}; + +uiDrawContext *newContext(CGContextRef ctxt) +{ + uiDrawContext *c; + + // TODO use uiNew + c = (uiDrawContext *) malloc(sizeof (uiDrawContext)); + c->c = ctxt; + return c; +} + +void uiDrawBeginPathRGB(uiDrawContext *c, uint8_t r, uint8_t g, uint8_t b) +{ + c->useRGBA = YES; + c->r = ((CGFloat) r) / 255; + c->g = ((CGFloat) g) / 255; + c->b = ((CGFloat) b) / 255; + c->a = 1.0; + CGContextBeginPath(c->c); +} + +void uiDrawBeginPathRGBA(uiDrawContext *c, uint8_t r, uint8_t g, uint8_t b, uint8_t a) +{ + c->useRGBA = YES; + c->r = ((CGFloat) r) / 255; + c->g = ((CGFloat) g) / 255; + c->b = ((CGFloat) b) / 255; + c->a = ((CGFloat) a) / 255; + CGContextBeginPath(c->c); +} + +// TODO 0.25 for retina? some say yes, some say no +// TODO same adjustment for cairo +#define topoint(x) (((CGFloat) x) + 0.5) + +void uiDrawMoveTo(uiDrawContext *c, intmax_t x, intmax_t y) +{ + CGContextMoveToPoint(c->c, topoint(x), topoint(y)); +} + +void uiDrawLineTo(uiDrawContext *c, intmax_t x, intmax_t y) +{ + CGContextAddLineToPoint(c->c, topoint(x), topoint(y)); +} + +// TODO width-1/height-1? (also for cairo) +void uiDrawRectangle(uiDrawContext *c, intmax_t x, intmax_t y, intmax_t width, intmax_t height) +{ + CGContextAddRect(c->c, CGRectMake(topoint(x), topoint(y), width, height)); +} + +void uiDrawArcTo(uiDrawContext *c, intmax_t xCenter, intmax_t yCenter, intmax_t radius, double startAngle, double endAngle, int lineFromCurrentPointToStart) +{ + if (!lineFromCurrentPointToStart) { + // see http://stackoverflow.com/questions/31489157/extra-line-when-drawing-an-arc-in-swift + // TODO verify correctness + CGFloat x, y; + + x = topoint(xCenter); + y = topoint(yCenter); + x += radius * cos(startAngle); + y -= radius * sin(startAngle); + CGContextMoveToPoint(c->c, x, y); + } + CGContextAddArc(c->c, + topoint(xCenter), topoint(yCenter), + radius, + startAngle, endAngle, + 0); +} + +void uiDrawBezierTo(uiDrawContext *c, intmax_t c1x, intmax_t c1y, intmax_t c2x, intmax_t c2y, intmax_t endX, intmax_t endY) +{ + CGContextAddCurveToPoint(c->c, + topoint(c1x), topoint(c1y), + topoint(c2x), topoint(c2y), + topoint(endX), topoint(endY)); +} + +void uiDrawCloseFigure(uiDrawContext *c) +{ + CGContextClosePath(c->c); +} + +void uiDrawStroke(uiDrawContext *c, uiDrawStrokeParams *p) +{ + switch (p->Cap) { + case uiDrawLineCapFlat: + CGContextSetLineCap(c->c, kCGLineCapButt); + break; + case uiDrawLineCapRound: + CGContextSetLineCap(c->c, kCGLineCapRound); + break; + case uiDrawLineCapSquare: + CGContextSetLineCap(c->c, kCGLineCapSquare); + break; + } + switch (p->Join) { + case uiDrawLineJoinMiter: + CGContextSetLineJoin(c->c, kCGLineJoinMiter); + CGContextSetMiterLimit(c->c, p->MiterLimit); + break; + case uiDrawLineJoinRound: + CGContextSetLineJoin(c->c, kCGLineJoinRound); + break; + case uiDrawLineJoinBevel: + CGContextSetLineJoin(c->c, kCGLineJoinBevel); + break; + } + CGContextSetLineWidth(c->c, p->Thickness); + if (c->useRGBA) + CGContextSetRGBStrokeColor(c->c, c->r, c->g, c->b, c->a); + else { + // TODO + } + CGContextStrokePath(c->c); +} + +void uiDrawFill(uiDrawContext *c, uiDrawFillMode mode) +{ + if (c->useRGBA) + CGContextSetRGBFillColor(c->c, c->r, c->g, c->b, c->a); + else { + // TODO + } + switch (mode) { + case uiDrawFillModeWinding: + CGContextFillPath(c->c); + break; + case uiDrawFillModeAlternate: + CGContextEOFillPath(c->c); + break; + } +} diff --git a/macarea/alt/main.m b/macarea/alt/main.m new file mode 100644 index 00000000..4d532ef8 --- /dev/null +++ b/macarea/alt/main.m @@ -0,0 +1,171 @@ +// 4 september 2015 +#define _GNU_SOURCE +#include "area.h" +#include + +// #qo LDFLAGS: -framework Foundation -framework AppKit -framework CoreGraphics + +struct handler { + uiAreaHandler ah; +}; + +static uiArea *area; +static struct handler h; +//static NSTextField *nhspinb; +//static NSTextField *nvspinb; + +static void handlerDraw(uiAreaHandler *a, uiArea *area, uiAreaDrawParams *p) +{ + uiDrawStrokeParams sp; + + uiDrawBeginPathRGB(p->Context, 0xFF, 0x00, 0x00); + uiDrawMoveTo(p->Context, p->ClipX + 5, p->ClipY + 5); + uiDrawLineTo(p->Context, (p->ClipX + p->ClipWidth) - 5, (p->ClipY + p->ClipHeight) - 5); + sp.Cap = uiDrawLineCapFlat; + sp.Join = uiDrawLineJoinMiter; + sp.Thickness = 1; + sp.MiterLimit = uiDrawDefaultMiterLimit; + uiDrawStroke(p->Context, &sp); + + uiDrawBeginPathRGB(p->Context, 0x00, 0x00, 0xC0); + uiDrawMoveTo(p->Context, p->ClipX, p->ClipY); + uiDrawLineTo(p->Context, p->ClipX + p->ClipWidth, p->ClipY); + uiDrawLineTo(p->Context, 50, 150); + uiDrawLineTo(p->Context, 50, 50); + uiDrawCloseFigure(p->Context); + sp.Cap = uiDrawLineCapFlat; + sp.Join = uiDrawLineJoinRound; + sp.Thickness = 5; + uiDrawStroke(p->Context, &sp); + + uiDrawBeginPathRGBA(p->Context, 0x00, 0xC0, 0x00, 0x80); + uiDrawRectangle(p->Context, 120, 80, 50, 50); + uiDrawFill(p->Context, uiDrawFillModeWinding); + + uiDrawBeginPathRGB(p->Context, 0x00, 0x80, 0x00); + uiDrawMoveTo(p->Context, 5, 10); + uiDrawLineTo(p->Context, 5, 50); + sp.Cap = uiDrawLineCapFlat; + sp.Join = uiDrawLineJoinMiter; + sp.Thickness = 1; + sp.MiterLimit = uiDrawDefaultMiterLimit; + uiDrawStroke(p->Context, &sp); + + uiDrawBeginPathRGB(p->Context, 0x80, 0xC0, 0x00); + uiDrawMoveTo(p->Context, 400, 100); + uiDrawArcTo(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); + uiDrawArcTo(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); + + uiDrawBeginPathRGB(p->Context, 0x00, 0x80, 0xC0); + uiDrawMoveTo(p->Context, 300, 300); + uiDrawBezierTo(p->Context, + 350, 320, + 310, 390, + 435, 372); + sp.Cap = uiDrawLineCapFlat; + sp.Join = uiDrawLineJoinMiter; + sp.Thickness = 1; + sp.MiterLimit = uiDrawDefaultMiterLimit; + uiDrawStroke(p->Context, &sp); +} + +static uintmax_t handlerHScrollMax(uiAreaHandler *a, uiArea *area) +{/* TODO + WCHAR c[50]; + + GetWindowTextW(nhspinb, c, 50); + return _wtoi(c); +*/} + +static uintmax_t handlerVScrollMax(uiAreaHandler *a, uiArea *area) +{/* TODO + WCHAR c[50]; + + GetWindowTextW(nvspinb, c, 50); + return _wtoi(c); +*/} + +// areaUpdateScroll(area); + +@interface appDelegate : NSObject +@end + +@implementation appDelegate + +- (void)controlTextDidChange:(NSNotification *)note +{ + areaUpdateScroll(area); +} + +- (void)applicationDidFinishLaunching:(NSApplication *)app +{ + NSWindow *mainwin; + NSView *contentView; + NSView *areav; + NSArray *constraints; + NSDictionary *views; + + mainwin = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 500, 500) + styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask) + backing:NSBackingStoreBuffered + defer:YES]; + contentView = [mainwin contentView]; + + area = newArea((uiAreaHandler *) (&h)); + areav = areaGetView(area); + [areav setTranslatesAutoresizingMaskIntoConstraints:NO]; + [contentView addSubview:areav]; + + views = @{ + @"areav": areav, + }; + constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[areav]-|" + options:0 + metrics:nil + views:views]; + [contentView addConstraints:constraints]; + constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[areav]-|" + options:0 + metrics:nil + views:views]; + [contentView addConstraints:constraints]; + + [mainwin makeKeyAndOrderFront:nil]; +} + +@end + +int main(void) +{ + NSApplication *app; + + h.ah.Draw = handlerDraw; + h.ah.HScrollMax = handlerHScrollMax; + h.ah.VScrollMax = handlerVScrollMax; + + app = [NSApplication sharedApplication]; + [app setActivationPolicy:NSApplicationActivationPolicyRegular]; + [app setDelegate:[appDelegate new]]; + [app run]; + return 0; +} diff --git a/macarea/alt/ui.h b/macarea/alt/ui.h new file mode 100644 index 00000000..4cc6097d --- /dev/null +++ b/macarea/alt/ui.h @@ -0,0 +1,138 @@ +// 4 september 2015 + +typedef struct uiArea uiArea; +typedef struct uiAreaHandler uiAreaHandler; +typedef struct uiAreaDrawParams uiAreaDrawParams; + +typedef struct uiDrawContext uiDrawContext; + +struct uiAreaHandler { + void (*Draw)(uiAreaHandler *, uiArea *, uiAreaDrawParams *); + uintmax_t (*HScrollMax)(uiAreaHandler *, uiArea *); + uintmax_t (*VScrollMax)(uiAreaHandler *, uiArea *); +}; + +struct uiAreaDrawParams { + uiDrawContext *Context; + + intmax_t ClientWidth; + intmax_t ClientHeight; + + intmax_t ClipX; + intmax_t ClipY; + intmax_t ClipWidth; + intmax_t ClipHeight; + + int DPIX; + int DPIY; + + intmax_t HScrollPos; + intmax_t VScrollPos; +}; + +// TODO proper sources +// TODO dotting/dashing + +typedef struct uiDrawStrokeParams uiDrawStrokeParams; +typedef enum uiDrawLineCap uiDrawLineCap; +typedef enum uiDrawLineJoin uiDrawLineJoin; +typedef enum uiDrawFillMode uiDrawFillMode; + +enum uiDrawLineCap { + uiDrawLineCapFlat, + uiDrawLineCapRound, + uiDrawLineCapSquare, +}; + +enum uiDrawLineJoin { + uiDrawLineJoinMiter, + uiDrawLineJoinRound, + uiDrawLineJoinBevel, +}; + +// this is the default for botoh cairo and GDI +// Core Graphics doesn't explicitly specify a default, but NSBezierPath allows you to choose one, and this is the initial value +// so we're good to use it too! +#define uiDrawDefaultMiterLimit 10.0 + +enum uiDrawFillMode { + uiDrawFillModeWinding, + // TODO rename to EvenOdd? + uiDrawFillModeAlternate, +}; + +struct uiDrawStrokeParams { + uiDrawLineCap Cap; + uiDrawLineJoin Join; + intmax_t Thickness; + double MiterLimit; +}; + +void uiDrawBeginPathRGB(uiDrawContext *, uint8_t, uint8_t, uint8_t); +// TODO verify these aren't alpha premultiplied anywhere +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 uiDrawArcTo(uiDrawContext *, intmax_t, intmax_t, intmax_t, double, double, int); +// TODO behavior when there is no initial point on Windows and OS X +void uiDrawBezierTo(uiDrawContext *, intmax_t, intmax_t, intmax_t, intmax_t, intmax_t, intmax_t); +void uiDrawCloseFigure(uiDrawContext *); + +void uiDrawStroke(uiDrawContext *, uiDrawStrokeParams *); +void uiDrawFill(uiDrawContext *, uiDrawFillMode); + +// path functions +// cairo gdi core graphics +// move_to MoveToEx MoveToPoint +// line_to LineTo AddLineToPoint +// 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?] +// [combination] RoundRect [same way as cairo?] +// [TODO pango] TextOut/ExtTextOut [TODO core text] +// [TODO] [TODO] AddQuadCurveToPoint + +// on sources: +// cairo: +// - RGB +// - RGBA +// - images +// - linear gradients, RGB or RGBA +// - rounded gradients, RGB or RGBA +// gdi: +// - RGB +// - hatches +// - images +// we can create a linear gradient image, but RGB only, and of finite size +// core graphics: +// - 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