#import "uipriv_darwin.h"
#define NSEventModifierFlags NSUInteger
@interface areaView : NSView {
uiArea *libui_a;
NSTrackingArea *libui_ta;
NSSize libui_ss;
BOOL libui_enabled;
}
- (id)initWithFrame:(NSRect)r area:(uiArea *)a;
- (uiModifiers)parseModifiers:(NSEvent *)e;
- (void)doMouseEvent:(NSEvent *)e;
- (int)sendKeyEvent:(uiAreaKeyEvent *)ke;
- (int)doKeyDownUp:(NSEvent *)e up:(int)up;
- (int)doKeyDown:(NSEvent *)e;
- (int)doKeyUp:(NSEvent *)e;
- (int)doFlagsChanged:(NSEvent *)e;
- (void)setupNewTrackingArea;
- (void)setScrollingSize:(NSSize)s;
- (BOOL)isEnabled;
- (void)setEnabled:(BOOL)e;
@end
struct uiArea {
uiDarwinControl c;
NSView *view; NSScrollView *sv;
areaView *area;
uiprivScrollViewData *d;
uiAreaHandler *ah;
BOOL scrolling;
NSEvent *dragevent;
};
@implementation areaView
- (id)initWithFrame:(NSRect)r area:(uiArea *)a
{
self = [super initWithFrame:r];
if (self) {
self->libui_a = a;
[self setupNewTrackingArea];
self->libui_ss = r.size;
self->libui_enabled = YES;
}
return self;
}
- (void)drawRect:(NSRect)r
{
uiArea *a = self->libui_a;
CGContextRef c;
uiAreaDrawParams dp;
c = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort];
dp.Context = uiprivDrawNewContext(c, [self bounds].size.height);
dp.AreaWidth = 0;
dp.AreaHeight = 0;
if (!a->scrolling) {
dp.AreaWidth = [self frame].size.width;
dp.AreaHeight = [self frame].size.height;
}
dp.ClipX = r.origin.x;
dp.ClipY = r.origin.y;
dp.ClipWidth = r.size.width;
dp.ClipHeight = r.size.height;
(*(a->ah->Draw))(a->ah, a, &dp);
uiprivDrawFreeContext(dp.Context);
}
- (BOOL)isFlipped
{
return YES;
}
- (BOOL)acceptsFirstResponder
{
return YES;
}
- (uiModifiers)parseModifiers:(NSEvent *)e
{
NSEventModifierFlags mods;
uiModifiers m;
m = 0;
mods = [e modifierFlags];
if ((mods & NSControlKeyMask) != 0)
m |= uiModifierCtrl;
if ((mods & NSAlternateKeyMask) != 0)
m |= uiModifierAlt;
if ((mods & NSShiftKeyMask) != 0)
m |= uiModifierShift;
if ((mods & NSCommandKeyMask) != 0)
m |= uiModifierSuper;
return m;
}
- (void)setupNewTrackingArea
{
self->libui_ta = [[NSTrackingArea alloc] initWithRect:[self bounds]
options:(NSTrackingMouseEnteredAndExited |
NSTrackingMouseMoved |
NSTrackingActiveAlways |
NSTrackingInVisibleRect |
NSTrackingEnabledDuringMouseDrag)
owner:self
userInfo:nil];
[self addTrackingArea:self->libui_ta];
}
- (void)updateTrackingAreas
{
[self removeTrackingArea:self->libui_ta];
[self->libui_ta release];
[self setupNewTrackingArea];
}
- (void)doMouseEvent:(NSEvent *)e
{
uiArea *a = self->libui_a;
uiAreaMouseEvent me;
NSPoint point;
unsigned int buttonNumber;
NSUInteger pmb;
unsigned int i, max;
point = [self convertPoint:[e locationInWindow] fromView:nil];
me.X = point.x;
me.Y = point.y;
me.AreaWidth = 0;
me.AreaHeight = 0;
if (!a->scrolling) {
me.AreaWidth = [self frame].size.width;
me.AreaHeight = [self frame].size.height;
}
buttonNumber = [e buttonNumber] + 1;
if (buttonNumber == 2)
buttonNumber = 3;
else if (buttonNumber == 3)
buttonNumber = 2;
me.Down = 0;
me.Up = 0;
me.Count = 0;
if (@available(macOS 10.12, *)) {
switch ([e type]) {
case NSEventTypeLeftMouseDown:
case NSEventTypeRightMouseDown:
case NSEventTypeOtherMouseDown:
me.Down = buttonNumber;
me.Count = [e clickCount];
break;
case NSEventTypeLeftMouseUp:
case NSEventTypeRightMouseUp:
case NSEventTypeOtherMouseUp:
me.Up = buttonNumber;
break;
case NSEventTypeLeftMouseDragged:
case NSEventTypeRightMouseDragged:
case NSEventTypeOtherMouseDragged:
buttonNumber = 0;
break;
}
} else {
NSEventType type = [e type];
if (type == NSLeftMouseDown || type == NSRightMouseDown || type == NSOtherMouseDown) {
me.Down = buttonNumber;
me.Count = [e clickCount];
}
else if (type == NSLeftMouseUp || type == NSRightMouseUp || type == NSOtherMouseUp) {
me.Up = buttonNumber;
}
else if (type == NSLeftMouseDragged || type == NSRightMouseDragged || type == NSOtherMouseDragged) {
buttonNumber = 0;
}
}
me.Modifiers = [self parseModifiers:e];
pmb = [NSEvent pressedMouseButtons];
me.Held1To64 = 0;
if (buttonNumber != 1 && (pmb & 1) != 0)
me.Held1To64 |= 1;
if (buttonNumber != 2 && (pmb & 4) != 0)
me.Held1To64 |= 2;
if (buttonNumber != 3 && (pmb & 2) != 0)
me.Held1To64 |= 4;
max = 32;
for (i = 4; i <= max; i++) {
uint64_t j;
if (buttonNumber == i)
continue;
j = 1 << (i - 1);
if ((pmb & j) != 0)
me.Held1To64 |= j;
}
if (self->libui_enabled) {
a->dragevent = e;
(*(a->ah->MouseEvent))(a->ah, a, &me);
a->dragevent = nil;
}
}
#define mouseEvent(name) \
- (void)name:(NSEvent *)e \
{ \
[self doMouseEvent:e]; \
}
mouseEvent(mouseMoved)
mouseEvent(mouseDragged)
mouseEvent(rightMouseDragged)
mouseEvent(otherMouseDragged)
mouseEvent(mouseDown)
mouseEvent(rightMouseDown)
mouseEvent(otherMouseDown)
mouseEvent(mouseUp)
mouseEvent(rightMouseUp)
mouseEvent(otherMouseUp)
- (void)mouseEntered:(NSEvent *)e
{
uiArea *a = self->libui_a;
if (self->libui_enabled)
(*(a->ah->MouseCrossed))(a->ah, a, 0);
}
- (void)mouseExited:(NSEvent *)e
{
uiArea *a = self->libui_a;
if (self->libui_enabled)
(*(a->ah->MouseCrossed))(a->ah, a, 1);
}
- (int)sendKeyEvent:(uiAreaKeyEvent *)ke
{
uiArea *a = self->libui_a;
return (*(a->ah->KeyEvent))(a->ah, a, ke);
}
- (int)doKeyDownUp:(NSEvent *)e up:(int)up
{
uiAreaKeyEvent ke;
ke.Key = 0;
ke.ExtKey = 0;
ke.Modifier = 0;
ke.Modifiers = [self parseModifiers:e];
ke.Up = up;
if (!uiprivFromKeycode([e keyCode], &ke))
return 0;
return [self sendKeyEvent:&ke];
}
- (int)doKeyDown:(NSEvent *)e
{
return [self doKeyDownUp:e up:0];
}
- (int)doKeyUp:(NSEvent *)e
{
return [self doKeyDownUp:e up:1];
}
- (int)doFlagsChanged:(NSEvent *)e
{
uiAreaKeyEvent ke;
uiModifiers whichmod;
ke.Key = 0;
ke.ExtKey = 0;
if (!uiprivKeycodeModifier([e keyCode], &whichmod))
return 0;
ke.Modifier = whichmod;
ke.Modifiers = [self parseModifiers:e];
ke.Up = (ke.Modifiers & ke.Modifier) == 0;
ke.Modifiers &= ~ke.Modifier;
return [self sendKeyEvent:&ke];
}
- (void)setFrameSize:(NSSize)size
{
uiArea *a = self->libui_a;
[super setFrameSize:size];
if (!a->scrolling)
[self setNeedsDisplay:YES];
}
- (void)setScrollingSize:(NSSize)s
{
self->libui_ss = s;
[self setFrameSize:s];
}
- (NSSize)intrinsicContentSize
{
if (!self->libui_a->scrolling)
return [super intrinsicContentSize];
return self->libui_ss;
}
- (BOOL)becomeFirstResponder
{
return [self isEnabled];
}
- (BOOL)isEnabled
{
return self->libui_enabled;
}
- (void)setEnabled:(BOOL)e
{
self->libui_enabled = e;
if (!self->libui_enabled && [self window] != nil)
if ([[self window] firstResponder] == self)
[[self window] makeFirstResponder:nil];
}
@end
uiDarwinControlAllDefaultsExceptDestroy(uiArea, view)
static void uiAreaDestroy(uiControl *c)
{
uiArea *a = uiArea(c);
if (a->scrolling)
uiprivScrollViewFreeData(a->sv, a->d);
[a->area release];
if (a->scrolling)
[a->sv release];
uiFreeControl(uiControl(a));
}
int uiprivSendAreaEvents(NSEvent *e)
{
NSEventType type;
id focused;
areaView *view;
type = [e type];
if (type != NSKeyDown && type != NSKeyUp && type != NSFlagsChanged)
return 0;
focused = [[e window] firstResponder];
if (focused == nil)
return 0;
if (![focused isKindOfClass:[areaView class]])
return 0;
view = (areaView *) focused;
if (@available(macOS 10.12, *)) {
switch (type) {
case NSEventTypeKeyDown: return [view doKeyDown:e];
case NSEventTypeKeyUp: return [view doKeyUp:e];
case NSEventTypeFlagsChanged: return [view doFlagsChanged:e];
}
} else {
if (type == NSKeyDown)
return [view doKeyDown:e];
if (type == NSKeyUp)
return [view doKeyUp:e];
if (type == NSFlagsChanged)
return [view doFlagsChanged:e];
}
return 0;
}
void uiAreaSetSize(uiArea *a, int width, int height)
{
if (!a->scrolling)
uiprivUserBug("You cannot call uiAreaSetSize() on a non-scrolling uiArea. (area: %p)", a);
[a->area setScrollingSize:NSMakeSize(width, height)];
}
void uiAreaQueueRedrawAll(uiArea *a)
{
[a->area setNeedsDisplay:YES];
}
void uiAreaScrollTo(uiArea *a, double x, double y, double width, double height)
{
if (!a->scrolling)
uiprivUserBug("You cannot call uiAreaScrollTo() on a non-scrolling uiArea. (area: %p)", a);
[a->area scrollRectToVisible:NSMakeRect(x, y, width, height)];
}
void uiAreaBeginUserWindowMove(uiArea *a)
{
uiprivNSWindow *w;
w = (uiprivNSWindow *) [a->area window];
if (w == nil)
return; if (a->dragevent == nil)
return; [w uiprivDoMove:a->dragevent];
}
void uiAreaBeginUserWindowResize(uiArea *a, uiWindowResizeEdge edge)
{
uiprivNSWindow *w;
w = (uiprivNSWindow *) [a->area window];
if (w == nil)
return; if (a->dragevent == nil)
return; [w uiprivDoResize:a->dragevent on:edge];
}
uiArea *uiNewArea(uiAreaHandler *ah)
{
uiArea *a;
uiDarwinNewControl(uiArea, a);
a->ah = ah;
a->scrolling = NO;
a->area = [[areaView alloc] initWithFrame:NSZeroRect area:a];
a->view = a->area;
return a;
}
uiArea *uiNewScrollingArea(uiAreaHandler *ah, int width, int height)
{
uiArea *a;
uiprivScrollViewCreateParams p;
uiDarwinNewControl(uiArea, a);
a->ah = ah;
a->scrolling = YES;
a->area = [[areaView alloc] initWithFrame:NSMakeRect(0, 0, width, height)
area:a];
memset(&p, 0, sizeof (uiprivScrollViewCreateParams));
p.DocumentView = a->area;
p.BackgroundColor = [NSColor controlColor];
p.DrawsBackground = 1;
p.Bordered = NO;
p.HScroll = YES;
p.VScroll = YES;
a->sv = uiprivMkScrollView(&p, &(a->d));
a->view = a->sv;
return a;
}