Set up a custom NSScrollView clone to see if that's more or less feasible than hijacking NSScrollView itself. Doesn't do scrolling yet.
This commit is contained in:
parent
568e9f65e8
commit
51e60359ab
|
@ -0,0 +1,12 @@
|
||||||
|
// 8 september 2015
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#import <stdint.h>
|
||||||
|
#import "ui.h"
|
||||||
|
|
||||||
|
extern uiArea *newArea(uiAreaHandler *ah);
|
||||||
|
|
||||||
|
extern uiDrawContext *newContext(CGContextRef);
|
||||||
|
|
||||||
|
extern NSView *areaGetView(uiArea *);
|
||||||
|
|
||||||
|
extern void areaUpdateScroll(uiArea *);
|
|
@ -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];
|
||||||
|
*/
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,171 @@
|
||||||
|
// 4 september 2015
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include "area.h"
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
// #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<NSApplicationDelegate, NSTextFieldDelegate>
|
||||||
|
@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;
|
||||||
|
}
|
|
@ -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
|
Loading…
Reference in New Issue