diff options
Diffstat (limited to 'src/libui_sdl/libui/darwin')
40 files changed, 0 insertions, 8472 deletions
diff --git a/src/libui_sdl/libui/darwin/CMakeLists.txt b/src/libui_sdl/libui/darwin/CMakeLists.txt deleted file mode 100644 index dbef5d4..0000000 --- a/src/libui_sdl/libui/darwin/CMakeLists.txt +++ /dev/null @@ -1,79 +0,0 @@ -# 3 june 2016 - -list(APPEND _LIBUI_SOURCES - darwin/alloc.m - darwin/area.m - darwin/areaevents.m - darwin/autolayout.m - darwin/box.m - darwin/button.m - darwin/checkbox.m - darwin/colorbutton.m - darwin/combobox.m - darwin/control.m - darwin/datetimepicker.m - darwin/debug.m - darwin/draw.m - darwin/drawtext.m - darwin/editablecombo.m - darwin/entry.m - darwin/fontbutton.m - darwin/form.m - darwin/grid.m - darwin/group.m - darwin/image.m - darwin/label.m - darwin/main.m - darwin/map.m - darwin/menu.m - darwin/multilineentry.m - darwin/progressbar.m - darwin/radiobuttons.m - darwin/scrollview.m - darwin/separator.m - darwin/slider.m - darwin/spinbox.m - darwin/stddialogs.m - darwin/tab.m - darwin/text.m - darwin/util.m - darwin/window.m - darwin/winmoveresize.m -) -set(_LIBUI_SOURCES ${_LIBUI_SOURCES} PARENT_SCOPE) - -list(APPEND _LIBUI_INCLUDEDIRS - darwin -) -set(_LIBUI_INCLUDEDIRS _LIBUI_INCLUDEDIRS PARENT_SCOPE) - -set(_LIBUINAME libui PARENT_SCOPE) -if(NOT BUILD_SHARED_LIBS) - set(_LIBUINAME libui-temporary PARENT_SCOPE) -endif() -# thanks to Mr-Hide in irc.freenode.net/#cmake -macro(_handle_static) - set_target_properties(${_LIBUINAME} PROPERTIES - ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}") - set(_aname $<TARGET_FILE:${_LIBUINAME}>) - set(_lname libui-combined.list) - set(_oname libui-combined.o) - add_custom_command( - OUTPUT ${_oname} - COMMAND - nm -m ${_aname} | sed -E -n "'s/^[0-9a-f]* \\([A-Z_]+,[a-z_]+\\) external //p'" > ${_lname} - COMMAND - ld -exported_symbols_list ${_lname} -r -all_load ${_aname} -o ${_oname} - COMMENT "Removing hidden symbols") - add_library(libui STATIC ${_oname}) - # otherwise cmake won't know which linker to use - set_target_properties(libui PROPERTIES - LINKER_LANGUAGE C) - set(_aname) - set(_lname) - set(_oname) -endmacro() - -set(_LIBUI_LIBS - objc "-framework Foundation" "-framework AppKit" -PARENT_SCOPE) diff --git a/src/libui_sdl/libui/darwin/alloc.m b/src/libui_sdl/libui/darwin/alloc.m deleted file mode 100644 index e271b90..0000000 --- a/src/libui_sdl/libui/darwin/alloc.m +++ /dev/null @@ -1,89 +0,0 @@ -// 4 december 2014 -#import <stdlib.h> -#import "uipriv_darwin.h" - -static NSMutableArray *allocations; -NSMutableArray *delegates; - -void initAlloc(void) -{ - allocations = [NSMutableArray new]; - delegates = [NSMutableArray new]; -} - -#define UINT8(p) ((uint8_t *) (p)) -#define PVOID(p) ((void *) (p)) -#define EXTRA (sizeof (size_t) + sizeof (const char **)) -#define DATA(p) PVOID(UINT8(p) + EXTRA) -#define BASE(p) PVOID(UINT8(p) - EXTRA) -#define SIZE(p) ((size_t *) (p)) -#define CCHAR(p) ((const char **) (p)) -#define TYPE(p) CCHAR(UINT8(p) + sizeof (size_t)) - -void uninitAlloc(void) -{ - NSMutableString *str; - NSValue *v; - - [delegates release]; - if ([allocations count] == 0) { - [allocations release]; - return; - } - str = [NSMutableString new]; - for (v in allocations) { - void *ptr; - - ptr = [v pointerValue]; - [str appendString:[NSString stringWithFormat:@"%p %s\n", ptr, *TYPE(ptr)]]; - } - userbug("Some data was leaked; either you left a uiControl lying around or there's a bug in libui itself. Leaked data:\n%s", [str UTF8String]); - [str release]; -} - -void *uiAlloc(size_t size, const char *type) -{ - void *out; - - out = malloc(EXTRA + size); - if (out == NULL) { - fprintf(stderr, "memory exhausted in uiAlloc()\n"); - abort(); - } - memset(DATA(out), 0, size); - *SIZE(out) = size; - *TYPE(out) = type; - [allocations addObject:[NSValue valueWithPointer:out]]; - return DATA(out); -} - -void *uiRealloc(void *p, size_t new, const char *type) -{ - void *out; - size_t *s; - - if (p == NULL) - return uiAlloc(new, type); - p = BASE(p); - out = realloc(p, EXTRA + new); - if (out == NULL) { - fprintf(stderr, "memory exhausted in uiRealloc()\n"); - abort(); - } - s = SIZE(out); - if (new <= *s) - memset(((uint8_t *) DATA(out)) + *s, 0, new - *s); - *s = new; - [allocations removeObject:[NSValue valueWithPointer:p]]; - [allocations addObject:[NSValue valueWithPointer:out]]; - return DATA(out); -} - -void uiFree(void *p) -{ - if (p == NULL) - implbug("attempt to uiFree(NULL)"); - p = BASE(p); - free(p); - [allocations removeObject:[NSValue valueWithPointer:p]]; -} diff --git a/src/libui_sdl/libui/darwin/area.m b/src/libui_sdl/libui/darwin/area.m deleted file mode 100644 index 23162e6..0000000 --- a/src/libui_sdl/libui/darwin/area.m +++ /dev/null @@ -1,475 +0,0 @@ -// 9 september 2015 -#import "uipriv_darwin.h" - -// 10.8 fixups -#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; // either sv or area depending on whether it is scrolling - NSScrollView *sv; - areaView *area; - struct scrollViewData *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]; - // see draw.m under text for why we need the height - dp.Context = newContext(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; - - // no need to save or restore the graphics state to reset transformations; Cocoa creates a brand-new context each time - (*(a->ah->Draw))(a->ah, a, &dp); - - freeContext(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]; -} - -// capture on drag is done automatically on OS X -- (void)doMouseEvent:(NSEvent *)e -{ - uiArea *a = self->libui_a; - uiAreaMouseEvent me; - NSPoint point; - int buttonNumber; - NSUInteger pmb; - unsigned int i, max; - - // this will convert point to drawing space - // thanks swillits in irc.freenode.net/#macdev - 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; - // swap button numbers 2 and 3 (right and middle) - if (buttonNumber == 2) - buttonNumber = 3; - else if (buttonNumber == 3) - buttonNumber = 2; - - me.Down = 0; - me.Up = 0; - me.Count = 0; - switch ([e type]) { - case NSLeftMouseDown: - case NSRightMouseDown: - case NSOtherMouseDown: - me.Down = buttonNumber; - me.Count = [e clickCount]; - break; - case NSLeftMouseUp: - case NSRightMouseUp: - case NSOtherMouseUp: - me.Up = buttonNumber; - break; - case NSLeftMouseDragged: - case NSRightMouseDragged: - case NSOtherMouseDragged: - // we include the button that triggered the dragged event in the Held fields - buttonNumber = 0; - break; - } - - 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; - // buttons 4..32 - // https://developer.apple.com/library/mac/documentation/Carbon/Reference/QuartzEventServicesRef/index.html#//apple_ref/c/tdef/CGMouseButton says Quartz only supports up to 32 buttons - 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) { - // and allow dragging here - 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); -} - -// note: there is no equivalent to WM_CAPTURECHANGED on Mac OS X; there literally is no way to break a grab like that -// even if I invoke the task switcher and switch processes, the mouse grab will still be held until I let go of all buttons -// therefore, no DragBroken() - -- (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 (!fromKeycode([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; - - // Mac OS X sends this event on both key up and key down. - // Fortunately -[e keyCode] IS valid here, so we can simply map from key code to Modifiers, get the value of [e modifierFlags], and check if the respective bit is set or not — that will give us the up/down state - if (!keycodeModifier([e keyCode], &whichmod)) - return 0; - ke.Modifier = whichmod; - ke.Modifiers = [self parseModifiers:e]; - ke.Up = (ke.Modifiers & ke.Modifier) == 0; - // and then drop the current modifier from Modifiers - ke.Modifiers &= ~ke.Modifier; - return [self sendKeyEvent:&ke]; -} - -- (void)setFrameSize:(NSSize)size -{ - uiArea *a = self->libui_a; - - [super setFrameSize:size]; - if (!a->scrolling) - // we must redraw everything on resize because Windows requires it - [self setNeedsDisplay:YES]; -} - -// TODO does this update the frame? -- (void)setScrollingSize:(NSSize)s -{ - self->libui_ss = s; - [self invalidateIntrinsicContentSize]; -} - -- (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) - scrollViewFreeData(a->sv, a->d); - [a->area release]; - if (a->scrolling) - [a->sv release]; - uiFreeControl(uiControl(a)); -} - -// called by subclasses of -[NSApplication sendEvent:] -// by default, NSApplication eats some key events -// this prevents that from happening with uiArea -// see http://stackoverflow.com/questions/24099063/how-do-i-detect-keyup-in-my-nsview-with-the-command-key-held and http://lists.apple.com/archives/cocoa-dev/2003/Oct/msg00442.html -int sendAreaEvents(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; - switch (type) { - case NSKeyDown: - return [view doKeyDown:e]; - case NSKeyUp: - return [view doKeyUp:e]; - case NSFlagsChanged: - return [view doFlagsChanged:e]; - } - return 0; -} - -void uiAreaSetSize(uiArea *a, int width, int height) -{ - if (!a->scrolling) - userbug("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) - userbug("You cannot call uiAreaScrollTo() on a non-scrolling uiArea. (area: %p)", a); - [a->area scrollRectToVisible:NSMakeRect(x, y, width, height)]; - // don't worry about the return value; it just says whether scrolling was needed -} - -void uiAreaBeginUserWindowMove(uiArea *a) -{ - libuiNSWindow *w; - - w = (libuiNSWindow *) [a->area window]; - if (w == nil) - return; // TODO - if (a->dragevent == nil) - return; // TODO - [w libui_doMove:a->dragevent]; -} - -void uiAreaBeginUserWindowResize(uiArea *a, uiWindowResizeEdge edge) -{ - libuiNSWindow *w; - - w = (libuiNSWindow *) [a->area window]; - if (w == nil) - return; // TODO - if (a->dragevent == nil) - return; // TODO - [w libui_doResize: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; - struct scrollViewCreateParams 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 (struct scrollViewCreateParams)); - p.DocumentView = a->area; - p.BackgroundColor = [NSColor controlColor]; - p.DrawsBackground = 1; - p.Bordered = NO; - p.HScroll = YES; - p.VScroll = YES; - a->sv = mkScrollView(&p, &(a->d)); - - a->view = a->sv; - - return a; -} diff --git a/src/libui_sdl/libui/darwin/areaevents.m b/src/libui_sdl/libui/darwin/areaevents.m deleted file mode 100644 index d7ceaaa..0000000 --- a/src/libui_sdl/libui/darwin/areaevents.m +++ /dev/null @@ -1,159 +0,0 @@ -// 30 march 2014 -#import "uipriv_darwin.h" - -/* -Mac OS X uses its own set of hardware key codes that are different from PC keyboard scancodes, but are positional (like PC keyboard scancodes). These are defined in <HIToolbox/Events.h>, a Carbon header. As far as I can tell, there's no way to include this header without either using an absolute path or linking Carbon into the program, so the constant values are used here instead. - -The Cocoa docs do guarantee that -[NSEvent keyCode] results in key codes that are the same as those returned by Carbon; that is, these codes. -*/ - -// use uintptr_t to be safe -static const struct { - uintptr_t keycode; - char equiv; -} keycodeKeys[] = { - { 0x00, 'a' }, - { 0x01, 's' }, - { 0x02, 'd' }, - { 0x03, 'f' }, - { 0x04, 'h' }, - { 0x05, 'g' }, - { 0x06, 'z' }, - { 0x07, 'x' }, - { 0x08, 'c' }, - { 0x09, 'v' }, - { 0x0B, 'b' }, - { 0x0C, 'q' }, - { 0x0D, 'w' }, - { 0x0E, 'e' }, - { 0x0F, 'r' }, - { 0x10, 'y' }, - { 0x11, 't' }, - { 0x12, '1' }, - { 0x13, '2' }, - { 0x14, '3' }, - { 0x15, '4' }, - { 0x16, '6' }, - { 0x17, '5' }, - { 0x18, '=' }, - { 0x19, '9' }, - { 0x1A, '7' }, - { 0x1B, '-' }, - { 0x1C, '8' }, - { 0x1D, '0' }, - { 0x1E, ']' }, - { 0x1F, 'o' }, - { 0x20, 'u' }, - { 0x21, '[' }, - { 0x22, 'i' }, - { 0x23, 'p' }, - { 0x25, 'l' }, - { 0x26, 'j' }, - { 0x27, '\'' }, - { 0x28, 'k' }, - { 0x29, ';' }, - { 0x2A, '\\' }, - { 0x2B, ',' }, - { 0x2C, '/' }, - { 0x2D, 'n' }, - { 0x2E, 'm' }, - { 0x2F, '.' }, - { 0x32, '`' }, - { 0x24, '\n' }, - { 0x30, '\t' }, - { 0x31, ' ' }, - { 0x33, '\b' }, - { 0xFFFF, 0 }, -}; - -static const struct { - uintptr_t keycode; - uiExtKey equiv; -} keycodeExtKeys[] = { - { 0x41, uiExtKeyNDot }, - { 0x43, uiExtKeyNMultiply }, - { 0x45, uiExtKeyNAdd }, - { 0x4B, uiExtKeyNDivide }, - { 0x4C, uiExtKeyNEnter }, - { 0x4E, uiExtKeyNSubtract }, - { 0x52, uiExtKeyN0 }, - { 0x53, uiExtKeyN1 }, - { 0x54, uiExtKeyN2 }, - { 0x55, uiExtKeyN3 }, - { 0x56, uiExtKeyN4 }, - { 0x57, uiExtKeyN5 }, - { 0x58, uiExtKeyN6 }, - { 0x59, uiExtKeyN7 }, - { 0x5B, uiExtKeyN8 }, - { 0x5C, uiExtKeyN9 }, - { 0x35, uiExtKeyEscape }, - { 0x60, uiExtKeyF5 }, - { 0x61, uiExtKeyF6 }, - { 0x62, uiExtKeyF7 }, - { 0x63, uiExtKeyF3 }, - { 0x64, uiExtKeyF8 }, - { 0x65, uiExtKeyF9 }, - { 0x67, uiExtKeyF11 }, - { 0x6D, uiExtKeyF10 }, - { 0x6F, uiExtKeyF12 }, - { 0x72, uiExtKeyInsert }, // listed as the Help key but it's in the same position on an Apple keyboard as the Insert key on a Windows keyboard; thanks to SeanieB from irc.badnik.net and Psy in irc.freenode.net/#macdev for confirming they have the same code - { 0x73, uiExtKeyHome }, - { 0x74, uiExtKeyPageUp }, - { 0x75, uiExtKeyDelete }, - { 0x76, uiExtKeyF4 }, - { 0x77, uiExtKeyEnd }, - { 0x78, uiExtKeyF2 }, - { 0x79, uiExtKeyPageDown }, - { 0x7A, uiExtKeyF1 }, - { 0x7B, uiExtKeyLeft }, - { 0x7C, uiExtKeyRight }, - { 0x7D, uiExtKeyDown }, - { 0x7E, uiExtKeyUp }, - { 0xFFFF, 0 }, -}; - -static const struct { - uintptr_t keycode; - uiModifiers equiv; -} keycodeModifiers[] = { - { 0x37, uiModifierSuper }, // left command - { 0x38, uiModifierShift }, // left shift - { 0x3A, uiModifierAlt }, // left option - { 0x3B, uiModifierCtrl }, // left control - { 0x3C, uiModifierShift }, // right shift - { 0x3D, uiModifierAlt }, // right alt - { 0x3E, uiModifierCtrl }, // right control - // the following is not in Events.h for some reason - // thanks to Nicole and jedivulcan from irc.badnik.net - { 0x36, uiModifierSuper }, // right command - { 0xFFFF, 0 }, -}; - -BOOL fromKeycode(unsigned short keycode, uiAreaKeyEvent *ke) -{ - int i; - - for (i = 0; keycodeKeys[i].keycode != 0xFFFF; i++) - if (keycodeKeys[i].keycode == keycode) { - ke->Key = keycodeKeys[i].equiv; - return YES; - } - for (i = 0; keycodeExtKeys[i].keycode != 0xFFFF; i++) - if (keycodeExtKeys[i].keycode == keycode) { - ke->ExtKey = keycodeExtKeys[i].equiv; - return YES; - } - return NO; -} - -BOOL keycodeModifier(unsigned short keycode, uiModifiers *mod) -{ - int i; - - for (i = 0; keycodeModifiers[i].keycode != 0xFFFF; i++) - if (keycodeModifiers[i].keycode == keycode) { - *mod = keycodeModifiers[i].equiv; - return YES; - } - return NO; -} diff --git a/src/libui_sdl/libui/darwin/autolayout.m b/src/libui_sdl/libui/darwin/autolayout.m deleted file mode 100644 index 9964155..0000000 --- a/src/libui_sdl/libui/darwin/autolayout.m +++ /dev/null @@ -1,161 +0,0 @@ -// 15 august 2015 -#import "uipriv_darwin.h" - -NSLayoutConstraint *mkConstraint(id view1, NSLayoutAttribute attr1, NSLayoutRelation relation, id view2, NSLayoutAttribute attr2, CGFloat multiplier, CGFloat c, NSString *desc) -{ - NSLayoutConstraint *constraint; - - constraint = [NSLayoutConstraint constraintWithItem:view1 - attribute:attr1 - relatedBy:relation - toItem:view2 - attribute:attr2 - multiplier:multiplier - constant:c]; - // apparently only added in 10.9 - if ([constraint respondsToSelector:@selector(setIdentifier:)]) - [((id) constraint) setIdentifier:desc]; - return constraint; -} - -CGFloat uiDarwinMarginAmount(void *reserved) -{ - return 20.0; -} - -CGFloat uiDarwinPaddingAmount(void *reserved) -{ - return 8.0; -} - -// this is needed for NSSplitView to work properly; see http://stackoverflow.com/questions/34574478/how-can-i-set-the-position-of-a-nssplitview-nowadays-setpositionofdivideratind (stal in irc.freenode.net/#macdev came up with the exact combination) -// turns out it also works on NSTabView and NSBox too, possibly others! -// and for bonus points, it even seems to fix unsatisfiable-constraint-autoresizing-mask issues with NSTabView and NSBox too!!! this is nuts -void jiggleViewLayout(NSView *view) -{ - [view setNeedsLayout:YES]; - [view layoutSubtreeIfNeeded]; -} - -static CGFloat margins(int margined) -{ - if (!margined) - return 0.0; - return uiDarwinMarginAmount(NULL); -} - -void singleChildConstraintsEstablish(struct singleChildConstraints *c, NSView *contentView, NSView *childView, BOOL hugsTrailing, BOOL hugsBottom, int margined, NSString *desc) -{ - CGFloat margin; - - margin = margins(margined); - - c->leadingConstraint = mkConstraint(contentView, NSLayoutAttributeLeading, - NSLayoutRelationEqual, - childView, NSLayoutAttributeLeading, - 1, -margin, - [desc stringByAppendingString:@" leading constraint"]); - [contentView addConstraint:c->leadingConstraint]; - [c->leadingConstraint retain]; - - c->topConstraint = mkConstraint(contentView, NSLayoutAttributeTop, - NSLayoutRelationEqual, - childView, NSLayoutAttributeTop, - 1, -margin, - [desc stringByAppendingString:@" top constraint"]); - [contentView addConstraint:c->topConstraint]; - [c->topConstraint retain]; - - c->trailingConstraintGreater = mkConstraint(contentView, NSLayoutAttributeTrailing, - NSLayoutRelationGreaterThanOrEqual, - childView, NSLayoutAttributeTrailing, - 1, margin, - [desc stringByAppendingString:@" trailing >= constraint"]); - if (hugsTrailing) - [c->trailingConstraintGreater setPriority:NSLayoutPriorityDefaultLow]; - [contentView addConstraint:c->trailingConstraintGreater]; - [c->trailingConstraintGreater retain]; - - c->trailingConstraintEqual = mkConstraint(contentView, NSLayoutAttributeTrailing, - NSLayoutRelationEqual, - childView, NSLayoutAttributeTrailing, - 1, margin, - [desc stringByAppendingString:@" trailing == constraint"]); - if (!hugsTrailing) - [c->trailingConstraintEqual setPriority:NSLayoutPriorityDefaultLow]; - [contentView addConstraint:c->trailingConstraintEqual]; - [c->trailingConstraintEqual retain]; - - c->bottomConstraintGreater = mkConstraint(contentView, NSLayoutAttributeBottom, - NSLayoutRelationGreaterThanOrEqual, - childView, NSLayoutAttributeBottom, - 1, margin, - [desc stringByAppendingString:@" bottom >= constraint"]); - if (hugsBottom) - [c->bottomConstraintGreater setPriority:NSLayoutPriorityDefaultLow]; - [contentView addConstraint:c->bottomConstraintGreater]; - [c->bottomConstraintGreater retain]; - - c->bottomConstraintEqual = mkConstraint(contentView, NSLayoutAttributeBottom, - NSLayoutRelationEqual, - childView, NSLayoutAttributeBottom, - 1, margin, - [desc stringByAppendingString:@" bottom == constraint"]); - if (!hugsBottom) - [c->bottomConstraintEqual setPriority:NSLayoutPriorityDefaultLow]; - [contentView addConstraint:c->bottomConstraintEqual]; - [c->bottomConstraintEqual retain]; -} - -void singleChildConstraintsRemove(struct singleChildConstraints *c, NSView *cv) -{ - if (c->leadingConstraint != nil) { - [cv removeConstraint:c->leadingConstraint]; - [c->leadingConstraint release]; - c->leadingConstraint = nil; - } - if (c->topConstraint != nil) { - [cv removeConstraint:c->topConstraint]; - [c->topConstraint release]; - c->topConstraint = nil; - } - if (c->trailingConstraintGreater != nil) { - [cv removeConstraint:c->trailingConstraintGreater]; - [c->trailingConstraintGreater release]; - c->trailingConstraintGreater = nil; - } - if (c->trailingConstraintEqual != nil) { - [cv removeConstraint:c->trailingConstraintEqual]; - [c->trailingConstraintEqual release]; - c->trailingConstraintEqual = nil; - } - if (c->bottomConstraintGreater != nil) { - [cv removeConstraint:c->bottomConstraintGreater]; - [c->bottomConstraintGreater release]; - c->bottomConstraintGreater = nil; - } - if (c->bottomConstraintEqual != nil) { - [cv removeConstraint:c->bottomConstraintEqual]; - [c->bottomConstraintEqual release]; - c->bottomConstraintEqual = nil; - } -} - -void singleChildConstraintsSetMargined(struct singleChildConstraints *c, int margined) -{ - CGFloat margin; - - margin = margins(margined); - if (c->leadingConstraint != nil) - [c->leadingConstraint setConstant:-margin]; - if (c->topConstraint != nil) - [c->topConstraint setConstant:-margin]; - if (c->trailingConstraintGreater != nil) - [c->trailingConstraintGreater setConstant:margin]; - if (c->trailingConstraintEqual != nil) - [c->trailingConstraintEqual setConstant:margin]; - if (c->bottomConstraintGreater != nil) - [c->bottomConstraintGreater setConstant:margin]; - if (c->bottomConstraintEqual != nil) - [c->bottomConstraintEqual setConstant:margin]; -} diff --git a/src/libui_sdl/libui/darwin/box.m b/src/libui_sdl/libui/darwin/box.m deleted file mode 100644 index 18d536d..0000000 --- a/src/libui_sdl/libui/darwin/box.m +++ /dev/null @@ -1,469 +0,0 @@ -// 15 august 2015 -#import "uipriv_darwin.h" - -// TODO hiding all stretchy controls still hugs trailing edge - -@interface boxChild : NSObject -@property uiControl *c; -@property BOOL stretchy; -@property NSLayoutPriority oldPrimaryHuggingPri; -@property NSLayoutPriority oldSecondaryHuggingPri; -- (NSView *)view; -@end - -@interface boxView : NSView { - uiBox *b; - NSMutableArray *children; - BOOL vertical; - int padded; - - NSLayoutConstraint *first; - NSMutableArray *inBetweens; - NSLayoutConstraint *last; - NSMutableArray *otherConstraints; - - NSLayoutAttribute primaryStart; - NSLayoutAttribute primaryEnd; - NSLayoutAttribute secondaryStart; - NSLayoutAttribute secondaryEnd; - NSLayoutAttribute primarySize; - NSLayoutConstraintOrientation primaryOrientation; - NSLayoutConstraintOrientation secondaryOrientation; -} -- (id)initWithVertical:(BOOL)vert b:(uiBox *)bb; -- (void)onDestroy; -- (void)removeOurConstraints; -- (void)syncEnableStates:(int)enabled; -- (CGFloat)paddingAmount; -- (void)establishOurConstraints; -- (void)append:(uiControl *)c stretchy:(int)stretchy; -- (void)delete:(int)n; -- (int)isPadded; -- (void)setPadded:(int)p; -- (BOOL)hugsTrailing; -- (BOOL)hugsBottom; -- (int)nStretchy; -@end - -struct uiBox { - uiDarwinControl c; - boxView *view; -}; - -@implementation boxChild - -- (NSView *)view -{ - return (NSView *) uiControlHandle(self.c); -} - -@end - -@implementation boxView - -- (id)initWithVertical:(BOOL)vert b:(uiBox *)bb -{ - self = [super initWithFrame:NSZeroRect]; - if (self != nil) { - // the weird names vert and bb are to shut the compiler up about shadowing because implicit this/self is stupid - self->b = bb; - self->vertical = vert; - self->padded = 0; - self->children = [NSMutableArray new]; - - self->inBetweens = [NSMutableArray new]; - self->otherConstraints = [NSMutableArray new]; - - if (self->vertical) { - self->primaryStart = NSLayoutAttributeTop; - self->primaryEnd = NSLayoutAttributeBottom; - self->secondaryStart = NSLayoutAttributeLeading; - self->secondaryEnd = NSLayoutAttributeTrailing; - self->primarySize = NSLayoutAttributeHeight; - self->primaryOrientation = NSLayoutConstraintOrientationVertical; - self->secondaryOrientation = NSLayoutConstraintOrientationHorizontal; - } else { - self->primaryStart = NSLayoutAttributeLeading; - self->primaryEnd = NSLayoutAttributeTrailing; - self->secondaryStart = NSLayoutAttributeTop; - self->secondaryEnd = NSLayoutAttributeBottom; - self->primarySize = NSLayoutAttributeWidth; - self->primaryOrientation = NSLayoutConstraintOrientationHorizontal; - self->secondaryOrientation = NSLayoutConstraintOrientationVertical; - } - } - return self; -} - -- (void)onDestroy -{ - boxChild *bc; - - [self removeOurConstraints]; - [self->inBetweens release]; - [self->otherConstraints release]; - - for (bc in self->children) { - uiControlSetParent(bc.c, NULL); - uiDarwinControlSetSuperview(uiDarwinControl(bc.c), nil); - uiControlDestroy(bc.c); - } - [self->children release]; -} - -- (void)removeOurConstraints -{ - if (self->first != nil) { - [self removeConstraint:self->first]; - [self->first release]; - self->first = nil; - } - if ([self->inBetweens count] != 0) { - [self removeConstraints:self->inBetweens]; - [self->inBetweens removeAllObjects]; - } - if (self->last != nil) { - [self removeConstraint:self->last]; - [self->last release]; - self->last = nil; - } - if ([self->otherConstraints count] != 0) { - [self removeConstraints:self->otherConstraints]; - [self->otherConstraints removeAllObjects]; - } -} - -- (void)syncEnableStates:(int)enabled -{ - boxChild *bc; - - for (bc in self->children) - uiDarwinControlSyncEnableState(uiDarwinControl(bc.c), enabled); -} - -- (CGFloat)paddingAmount -{ - if (!self->padded) - return 0.0; - return uiDarwinPaddingAmount(NULL); -} - -- (void)establishOurConstraints -{ - boxChild *bc; - CGFloat padding; - NSView *prev; - NSLayoutConstraint *c; - BOOL (*hugsSecondary)(uiDarwinControl *); - - [self removeOurConstraints]; - if ([self->children count] == 0) - return; - padding = [self paddingAmount]; - - // first arrange in the primary direction - prev = nil; - for (bc in self->children) { - if (!uiControlVisible(bc.c)) - continue; - if (prev == nil) { // first view - self->first = mkConstraint(self, self->primaryStart, - NSLayoutRelationEqual, - [bc view], self->primaryStart, - 1, 0, - @"uiBox first primary constraint"); - [self addConstraint:self->first]; - [self->first retain]; - prev = [bc view]; - continue; - } - // not the first; link it - c = mkConstraint(prev, self->primaryEnd, - NSLayoutRelationEqual, - [bc view], self->primaryStart, - 1, -padding, - @"uiBox in-between primary constraint"); - [self addConstraint:c]; - [self->inBetweens addObject:c]; - prev = [bc view]; - } - if (prev == nil) // no control visible; act as if no controls - return; - self->last = mkConstraint(prev, self->primaryEnd, - NSLayoutRelationEqual, - self, self->primaryEnd, - 1, 0, - @"uiBox last primary constraint"); - [self addConstraint:self->last]; - [self->last retain]; - - // then arrange in the secondary direction - hugsSecondary = uiDarwinControlHugsTrailingEdge; - if (!self->vertical) - hugsSecondary = uiDarwinControlHugsBottom; - for (bc in self->children) { - if (!uiControlVisible(bc.c)) - continue; - c = mkConstraint(self, self->secondaryStart, - NSLayoutRelationEqual, - [bc view], self->secondaryStart, - 1, 0, - @"uiBox secondary start constraint"); - [self addConstraint:c]; - [self->otherConstraints addObject:c]; - c = mkConstraint([bc view], self->secondaryEnd, - NSLayoutRelationLessThanOrEqual, - self, self->secondaryEnd, - 1, 0, - @"uiBox secondary end <= constraint"); - if ((*hugsSecondary)(uiDarwinControl(bc.c))) - [c setPriority:NSLayoutPriorityDefaultLow]; - [self addConstraint:c]; - [self->otherConstraints addObject:c]; - c = mkConstraint([bc view], self->secondaryEnd, - NSLayoutRelationEqual, - self, self->secondaryEnd, - 1, 0, - @"uiBox secondary end == constraint"); - if (!(*hugsSecondary)(uiDarwinControl(bc.c))) - [c setPriority:NSLayoutPriorityDefaultLow]; - [self addConstraint:c]; - [self->otherConstraints addObject:c]; - } - - // and make all stretchy controls the same size - if ([self nStretchy] == 0) - return; - prev = nil; // first stretchy view - for (bc in self->children) { - if (!uiControlVisible(bc.c)) - continue; - if (!bc.stretchy) - continue; - if (prev == nil) { - prev = [bc view]; - continue; - } - c = mkConstraint(prev, self->primarySize, - NSLayoutRelationEqual, - [bc view], self->primarySize, - 1, 0, - @"uiBox stretchy size constraint"); - [self addConstraint:c]; - [self->otherConstraints addObject:c]; - } -} - -- (void)append:(uiControl *)c stretchy:(int)stretchy -{ - boxChild *bc; - NSLayoutPriority priority; - int oldnStretchy; - - bc = [boxChild new]; - bc.c = c; - bc.stretchy = stretchy; - bc.oldPrimaryHuggingPri = uiDarwinControlHuggingPriority(uiDarwinControl(bc.c), self->primaryOrientation); - bc.oldSecondaryHuggingPri = uiDarwinControlHuggingPriority(uiDarwinControl(bc.c), self->secondaryOrientation); - - uiControlSetParent(bc.c, uiControl(self->b)); - uiDarwinControlSetSuperview(uiDarwinControl(bc.c), self); - uiDarwinControlSyncEnableState(uiDarwinControl(bc.c), uiControlEnabledToUser(uiControl(self->b))); - - // if a control is stretchy, it should not hug in the primary direction - // otherwise, it should *forcibly* hug - if (bc.stretchy) - priority = NSLayoutPriorityDefaultLow; - else - // LONGTERM will default high work? - priority = NSLayoutPriorityRequired; - uiDarwinControlSetHuggingPriority(uiDarwinControl(bc.c), priority, self->primaryOrientation); - // make sure controls don't hug their secondary direction so they fill the width of the view - uiDarwinControlSetHuggingPriority(uiDarwinControl(bc.c), NSLayoutPriorityDefaultLow, self->secondaryOrientation); - - oldnStretchy = [self nStretchy]; - [self->children addObject:bc]; - - [self establishOurConstraints]; - if (bc.stretchy) - if (oldnStretchy == 0) - uiDarwinNotifyEdgeHuggingChanged(uiDarwinControl(self->b)); - - [bc release]; // we don't need the initial reference now -} - -- (void)delete:(int)n -{ - boxChild *bc; - int stretchy; - - bc = (boxChild *) [self->children objectAtIndex:n]; - stretchy = bc.stretchy; - - uiControlSetParent(bc.c, NULL); - uiDarwinControlSetSuperview(uiDarwinControl(bc.c), nil); - - uiDarwinControlSetHuggingPriority(uiDarwinControl(bc.c), bc.oldPrimaryHuggingPri, self->primaryOrientation); - uiDarwinControlSetHuggingPriority(uiDarwinControl(bc.c), bc.oldSecondaryHuggingPri, self->secondaryOrientation); - - [self->children removeObjectAtIndex:n]; - - [self establishOurConstraints]; - if (stretchy) - if ([self nStretchy] == 0) - uiDarwinNotifyEdgeHuggingChanged(uiDarwinControl(self->b)); -} - -- (int)isPadded -{ - return self->padded; -} - -- (void)setPadded:(int)p -{ - CGFloat padding; - NSLayoutConstraint *c; - - self->padded = p; - padding = [self paddingAmount]; - for (c in self->inBetweens) - [c setConstant:-padding]; -} - -- (BOOL)hugsTrailing -{ - if (self->vertical) // always hug if vertical - return YES; - return [self nStretchy] != 0; -} - -- (BOOL)hugsBottom -{ - if (!self->vertical) // always hug if horizontal - return YES; - return [self nStretchy] != 0; -} - -- (int)nStretchy -{ - boxChild *bc; - int n; - - n = 0; - for (bc in self->children) { - if (!uiControlVisible(bc.c)) - continue; - if (bc.stretchy) - n++; - } - return n; -} - -@end - -static void uiBoxDestroy(uiControl *c) -{ - uiBox *b = uiBox(c); - - [b->view onDestroy]; - [b->view release]; - uiFreeControl(uiControl(b)); -} - -uiDarwinControlDefaultHandle(uiBox, view) -uiDarwinControlDefaultParent(uiBox, view) -uiDarwinControlDefaultSetParent(uiBox, view) -uiDarwinControlDefaultToplevel(uiBox, view) -uiDarwinControlDefaultVisible(uiBox, view) -uiDarwinControlDefaultShow(uiBox, view) -uiDarwinControlDefaultHide(uiBox, view) -uiDarwinControlDefaultEnabled(uiBox, view) -uiDarwinControlDefaultEnable(uiBox, view) -uiDarwinControlDefaultDisable(uiBox, view) - -static void uiBoxSyncEnableState(uiDarwinControl *c, int enabled) -{ - uiBox *b = uiBox(c); - - if (uiDarwinShouldStopSyncEnableState(uiDarwinControl(b), enabled)) - return; - [b->view syncEnableStates:enabled]; -} - -uiDarwinControlDefaultSetSuperview(uiBox, view) - -static BOOL uiBoxHugsTrailingEdge(uiDarwinControl *c) -{ - uiBox *b = uiBox(c); - - return [b->view hugsTrailing]; -} - -static BOOL uiBoxHugsBottom(uiDarwinControl *c) -{ - uiBox *b = uiBox(c); - - return [b->view hugsBottom]; -} - -static void uiBoxChildEdgeHuggingChanged(uiDarwinControl *c) -{ - uiBox *b = uiBox(c); - - [b->view establishOurConstraints]; -} - -uiDarwinControlDefaultHuggingPriority(uiBox, view) -uiDarwinControlDefaultSetHuggingPriority(uiBox, view) - -static void uiBoxChildVisibilityChanged(uiDarwinControl *c) -{ - uiBox *b = uiBox(c); - - [b->view establishOurConstraints]; -} - -void uiBoxAppend(uiBox *b, uiControl *c, int stretchy) -{ - // LONGTERM on other platforms - // or at leat allow this and implicitly turn it into a spacer - if (c == NULL) - userbug("You cannot add NULL to a uiBox."); - [b->view append:c stretchy:stretchy]; -} - -void uiBoxDelete(uiBox *b, int n) -{ - [b->view delete:n]; -} - -int uiBoxPadded(uiBox *b) -{ - return [b->view isPadded]; -} - -void uiBoxSetPadded(uiBox *b, int padded) -{ - [b->view setPadded:padded]; -} - -static uiBox *finishNewBox(BOOL vertical) -{ - uiBox *b; - - uiDarwinNewControl(uiBox, b); - - b->view = [[boxView alloc] initWithVertical:vertical b:b]; - - return b; -} - -uiBox *uiNewHorizontalBox(void) -{ - return finishNewBox(NO); -} - -uiBox *uiNewVerticalBox(void) -{ - return finishNewBox(YES); -} diff --git a/src/libui_sdl/libui/darwin/button.m b/src/libui_sdl/libui/darwin/button.m deleted file mode 100644 index baccabb..0000000 --- a/src/libui_sdl/libui/darwin/button.m +++ /dev/null @@ -1,113 +0,0 @@ -// 13 august 2015 -#import "uipriv_darwin.h" - -struct uiButton { - uiDarwinControl c; - NSButton *button; - void (*onClicked)(uiButton *, void *); - void *onClickedData; -}; - -@interface buttonDelegateClass : NSObject { - struct mapTable *buttons; -} -- (IBAction)onClicked:(id)sender; -- (void)registerButton:(uiButton *)b; -- (void)unregisterButton:(uiButton *)b; -@end - -@implementation buttonDelegateClass - -- (id)init -{ - self = [super init]; - if (self) - self->buttons = newMap(); - return self; -} - -- (void)dealloc -{ - mapDestroy(self->buttons); - [super dealloc]; -} - -- (IBAction)onClicked:(id)sender -{ - uiButton *b; - - b = (uiButton *) mapGet(self->buttons, sender); - (*(b->onClicked))(b, b->onClickedData); -} - -- (void)registerButton:(uiButton *)b -{ - mapSet(self->buttons, b->button, b); - [b->button setTarget:self]; - [b->button setAction:@selector(onClicked:)]; -} - -- (void)unregisterButton:(uiButton *)b -{ - [b->button setTarget:nil]; - mapDelete(self->buttons, b->button); -} - -@end - -static buttonDelegateClass *buttonDelegate = nil; - -uiDarwinControlAllDefaultsExceptDestroy(uiButton, button) - -static void uiButtonDestroy(uiControl *c) -{ - uiButton *b = uiButton(c); - - [buttonDelegate unregisterButton:b]; - [b->button release]; - uiFreeControl(uiControl(b)); -} - -char *uiButtonText(uiButton *b) -{ - return uiDarwinNSStringToText([b->button title]); -} - -void uiButtonSetText(uiButton *b, const char *text) -{ - [b->button setTitle:toNSString(text)]; -} - -void uiButtonOnClicked(uiButton *b, void (*f)(uiButton *, void *), void *data) -{ - b->onClicked = f; - b->onClickedData = data; -} - -static void defaultOnClicked(uiButton *b, void *data) -{ - // do nothing -} - -uiButton *uiNewButton(const char *text) -{ - uiButton *b; - - uiDarwinNewControl(uiButton, b); - - b->button = [[NSButton alloc] initWithFrame:NSZeroRect]; - [b->button setTitle:toNSString(text)]; - [b->button setButtonType:NSMomentaryPushInButton]; - [b->button setBordered:YES]; - [b->button setBezelStyle:NSRoundedBezelStyle]; - uiDarwinSetControlFont(b->button, NSRegularControlSize); - - if (buttonDelegate == nil) { - buttonDelegate = [[buttonDelegateClass new] autorelease]; - [delegates addObject:buttonDelegate]; - } - [buttonDelegate registerButton:b]; - uiButtonOnClicked(b, defaultOnClicked, NULL); - - return b; -} diff --git a/src/libui_sdl/libui/darwin/checkbox.m b/src/libui_sdl/libui/darwin/checkbox.m deleted file mode 100644 index dd1ce09..0000000 --- a/src/libui_sdl/libui/darwin/checkbox.m +++ /dev/null @@ -1,129 +0,0 @@ -// 14 august 2015 -#import "uipriv_darwin.h" - -struct uiCheckbox { - uiDarwinControl c; - NSButton *button; - void (*onToggled)(uiCheckbox *, void *); - void *onToggledData; -}; - -@interface checkboxDelegateClass : NSObject { - struct mapTable *buttons; -} -- (IBAction)onToggled:(id)sender; -- (void)registerCheckbox:(uiCheckbox *)c; -- (void)unregisterCheckbox:(uiCheckbox *)c; -@end - -@implementation checkboxDelegateClass - -- (id)init -{ - self = [super init]; - if (self) - self->buttons = newMap(); - return self; -} - -- (void)dealloc -{ - mapDestroy(self->buttons); - [super dealloc]; -} - -- (IBAction)onToggled:(id)sender -{ - uiCheckbox *c; - - c = (uiCheckbox *) mapGet(self->buttons, sender); - (*(c->onToggled))(c, c->onToggledData); -} - -- (void)registerCheckbox:(uiCheckbox *)c -{ - mapSet(self->buttons, c->button, c); - [c->button setTarget:self]; - [c->button setAction:@selector(onToggled:)]; -} - -- (void)unregisterCheckbox:(uiCheckbox *)c -{ - [c->button setTarget:nil]; - mapDelete(self->buttons, c->button); -} - -@end - -static checkboxDelegateClass *checkboxDelegate = nil; - -uiDarwinControlAllDefaultsExceptDestroy(uiCheckbox, button) - -static void uiCheckboxDestroy(uiControl *cc) -{ - uiCheckbox *c = uiCheckbox(cc); - - [checkboxDelegate unregisterCheckbox:c]; - [c->button release]; - uiFreeControl(uiControl(c)); -} - -char *uiCheckboxText(uiCheckbox *c) -{ - return uiDarwinNSStringToText([c->button title]); -} - -void uiCheckboxSetText(uiCheckbox *c, const char *text) -{ - [c->button setTitle:toNSString(text)]; -} - -void uiCheckboxOnToggled(uiCheckbox *c, void (*f)(uiCheckbox *, void *), void *data) -{ - c->onToggled = f; - c->onToggledData = data; -} - -int uiCheckboxChecked(uiCheckbox *c) -{ - return [c->button state] == NSOnState; -} - -void uiCheckboxSetChecked(uiCheckbox *c, int checked) -{ - NSInteger state; - - state = NSOnState; - if (!checked) - state = NSOffState; - [c->button setState:state]; -} - -static void defaultOnToggled(uiCheckbox *c, void *data) -{ - // do nothing -} - -uiCheckbox *uiNewCheckbox(const char *text) -{ - uiCheckbox *c; - - uiDarwinNewControl(uiCheckbox, c); - - c->button = [[NSButton alloc] initWithFrame:NSZeroRect]; - [c->button setTitle:toNSString(text)]; - [c->button setButtonType:NSSwitchButton]; - // doesn't seem to have an associated bezel style - [c->button setBordered:NO]; - [c->button setTransparent:NO]; - uiDarwinSetControlFont(c->button, NSRegularControlSize); - - if (checkboxDelegate == nil) { - checkboxDelegate = [[checkboxDelegateClass new] autorelease]; - [delegates addObject:checkboxDelegate]; - } - [checkboxDelegate registerCheckbox:c]; - uiCheckboxOnToggled(c, defaultOnToggled, NULL); - - return c; -} diff --git a/src/libui_sdl/libui/darwin/colorbutton.m b/src/libui_sdl/libui/darwin/colorbutton.m deleted file mode 100644 index 83b6157..0000000 --- a/src/libui_sdl/libui/darwin/colorbutton.m +++ /dev/null @@ -1,159 +0,0 @@ -// 15 may 2016 -#import "uipriv_darwin.h" - -// TODO no intrinsic height? - -@interface colorButton : NSColorWell { - uiColorButton *libui_b; - BOOL libui_changing; - BOOL libui_setting; -} -- (id)initWithFrame:(NSRect)frame libuiColorButton:(uiColorButton *)b; -- (void)deactivateOnClose:(NSNotification *)note; -- (void)libuiColor:(double *)r g:(double *)g b:(double *)b a:(double *)a; -- (void)libuiSetColor:(double)r g:(double)g b:(double)b a:(double)a; -@end - -// only one may be active at one time -static colorButton *activeColorButton = nil; - -struct uiColorButton { - uiDarwinControl c; - colorButton *button; - void (*onChanged)(uiColorButton *, void *); - void *onChangedData; -}; - -@implementation colorButton - -- (id)initWithFrame:(NSRect)frame libuiColorButton:(uiColorButton *)b -{ - self = [super initWithFrame:frame]; - if (self) { - // the default color is white; set it to black first (see -setColor: below for why we do it first) - [self libuiSetColor:0.0 g:0.0 b:0.0 a:1.0]; - - self->libui_b = b; - self->libui_changing = NO; - } - return self; -} - -- (void)activate:(BOOL)exclusive -{ - if (activeColorButton != nil) - activeColorButton->libui_changing = YES; - [NSColorPanel setPickerMask:NSColorPanelAllModesMask]; - [[NSColorPanel sharedColorPanel] setShowsAlpha:YES]; - [super activate:YES]; - activeColorButton = self; - // see stddialogs.m for details - [[NSColorPanel sharedColorPanel] setWorksWhenModal:NO]; - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(deactivateOnClose:) - name:NSWindowWillCloseNotification - object:[NSColorPanel sharedColorPanel]]; -} - -- (void)deactivate -{ - [super deactivate]; - activeColorButton = nil; - if (!self->libui_changing) - [[NSColorPanel sharedColorPanel] orderOut:nil]; - [[NSNotificationCenter defaultCenter] removeObserver:self - name:NSWindowWillCloseNotification - object:[NSColorPanel sharedColorPanel]]; - self->libui_changing = NO; -} - -- (void)deactivateOnClose:(NSNotification *)note -{ - [self deactivate]; -} - -- (void)setColor:(NSColor *)color -{ - uiColorButton *b = self->libui_b; - - [super setColor:color]; - // this is called by NSColorWell's init, so we have to guard - // also don't signal during a programmatic change - if (b != nil && !self->libui_setting) - (*(b->onChanged))(b, b->onChangedData); -} - -- (void)libuiColor:(double *)r g:(double *)g b:(double *)b a:(double *)a -{ - NSColor *rgba; - CGFloat cr, cg, cb, ca; - - // the given color may not be an RGBA color, which will cause the -getRed:green:blue:alpha: call to throw an exception - rgba = [[self color] colorUsingColorSpace:[NSColorSpace sRGBColorSpace]]; - [rgba getRed:&cr green:&cg blue:&cb alpha:&ca]; - *r = cr; - *g = cg; - *b = cb; - *a = ca; - // rgba will be autoreleased since it isn't a new or init call -} - -- (void)libuiSetColor:(double)r g:(double)g b:(double)b a:(double)a -{ - self->libui_setting = YES; - [self setColor:[NSColor colorWithSRGBRed:r green:g blue:b alpha:a]]; - self->libui_setting = NO; -} - -// NSColorWell has no intrinsic size by default; give it the default Interface Builder size. -- (NSSize)intrinsicContentSize -{ - return NSMakeSize(44, 23); -} - -@end - -uiDarwinControlAllDefaults(uiColorButton, button) - -// we do not want color change events to be sent to any controls other than the color buttons -// see main.m for more details -BOOL colorButtonInhibitSendAction(SEL sel, id from, id to) -{ - if (sel != @selector(changeColor:)) - return NO; - return ![to isKindOfClass:[colorButton class]]; -} - -static void defaultOnChanged(uiColorButton *b, void *data) -{ - // do nothing -} - -void uiColorButtonColor(uiColorButton *b, double *r, double *g, double *bl, double *a) -{ - [b->button libuiColor:r g:g b:bl a:a]; -} - -void uiColorButtonSetColor(uiColorButton *b, double r, double g, double bl, double a) -{ - [b->button libuiSetColor:r g:g b:bl a:a]; -} - -void uiColorButtonOnChanged(uiColorButton *b, void (*f)(uiColorButton *, void *), void *data) -{ - b->onChanged = f; - b->onChangedData = data; -} - -uiColorButton *uiNewColorButton(void) -{ - uiColorButton *b; - - uiDarwinNewControl(uiColorButton, b); - - b->button = [[colorButton alloc] initWithFrame:NSZeroRect libuiColorButton:b]; - - uiColorButtonOnChanged(b, defaultOnChanged, NULL); - - return b; -} diff --git a/src/libui_sdl/libui/darwin/combobox.m b/src/libui_sdl/libui/darwin/combobox.m deleted file mode 100644 index 89a2e28..0000000 --- a/src/libui_sdl/libui/darwin/combobox.m +++ /dev/null @@ -1,145 +0,0 @@ -// 14 august 2015 -#import "uipriv_darwin.h" - -// NSComboBoxes have no intrinsic width; we'll use the default Interface Builder width for them. -// NSPopUpButton is fine. -#define comboboxWidth 96 - -struct uiCombobox { - uiDarwinControl c; - NSPopUpButton *pb; - NSArrayController *pbac; - void (*onSelected)(uiCombobox *, void *); - void *onSelectedData; -}; - -@interface comboboxDelegateClass : NSObject { - struct mapTable *comboboxes; -} -- (IBAction)onSelected:(id)sender; -- (void)registerCombobox:(uiCombobox *)c; -- (void)unregisterCombobox:(uiCombobox *)c; -@end - -@implementation comboboxDelegateClass - -- (id)init -{ - self = [super init]; - if (self) - self->comboboxes = newMap(); - return self; -} - -- (void)dealloc -{ - mapDestroy(self->comboboxes); - [super dealloc]; -} - -- (IBAction)onSelected:(id)sender -{ - uiCombobox *c; - - c = uiCombobox(mapGet(self->comboboxes, sender)); - (*(c->onSelected))(c, c->onSelectedData); -} - -- (void)registerCombobox:(uiCombobox *)c -{ - mapSet(self->comboboxes, c->pb, c); - [c->pb setTarget:self]; - [c->pb setAction:@selector(onSelected:)]; -} - -- (void)unregisterCombobox:(uiCombobox *)c -{ - [c->pb setTarget:nil]; - mapDelete(self->comboboxes, c->pb); -} - -@end - -static comboboxDelegateClass *comboboxDelegate = nil; - -uiDarwinControlAllDefaultsExceptDestroy(uiCombobox, pb) - -static void uiComboboxDestroy(uiControl *cc) -{ - uiCombobox *c = uiCombobox(cc); - - [comboboxDelegate unregisterCombobox:c]; - [c->pb unbind:@"contentObjects"]; - [c->pb unbind:@"selectedIndex"]; - [c->pbac release]; - [c->pb release]; - uiFreeControl(uiControl(c)); -} - -void uiComboboxAppend(uiCombobox *c, const char *text) -{ - [c->pbac addObject:toNSString(text)]; -} - -int uiComboboxSelected(uiCombobox *c) -{ - return [c->pb indexOfSelectedItem]; -} - -void uiComboboxSetSelected(uiCombobox *c, int n) -{ - [c->pb selectItemAtIndex:n]; -} - -void uiComboboxOnSelected(uiCombobox *c, void (*f)(uiCombobox *c, void *data), void *data) -{ - c->onSelected = f; - c->onSelectedData = data; -} - -static void defaultOnSelected(uiCombobox *c, void *data) -{ - // do nothing -} - -uiCombobox *uiNewCombobox(void) -{ - uiCombobox *c; - NSPopUpButtonCell *pbcell; - - uiDarwinNewControl(uiCombobox, c); - - c->pb = [[NSPopUpButton alloc] initWithFrame:NSZeroRect pullsDown:NO]; - [c->pb setPreferredEdge:NSMinYEdge]; - pbcell = (NSPopUpButtonCell *) [c->pb cell]; - [pbcell setArrowPosition:NSPopUpArrowAtBottom]; - // the font defined by Interface Builder is Menu 13, which is lol - // just use the regular control size for consistency - uiDarwinSetControlFont(c->pb, NSRegularControlSize); - - // NSPopUpButton doesn't work like a combobox - // - it automatically selects the first item - // - it doesn't support duplicates - // but we can use a NSArrayController and Cocoa bindings to bypass these restrictions - c->pbac = [NSArrayController new]; - [c->pbac setAvoidsEmptySelection:NO]; - [c->pbac setSelectsInsertedObjects:NO]; - [c->pbac setAutomaticallyRearrangesObjects:NO]; - [c->pb bind:@"contentValues" - toObject:c->pbac - withKeyPath:@"arrangedObjects" - options:nil]; - [c->pb bind:@"selectedIndex" - toObject:c->pbac - withKeyPath:@"selectionIndex" - options:nil]; - - if (comboboxDelegate == nil) { - comboboxDelegate = [[comboboxDelegateClass new] autorelease]; - [delegates addObject:comboboxDelegate]; - } - [comboboxDelegate registerCombobox:c]; - uiComboboxOnSelected(c, defaultOnSelected, NULL); - - return c; -} diff --git a/src/libui_sdl/libui/darwin/control.m b/src/libui_sdl/libui/darwin/control.m deleted file mode 100644 index 9eaf47a..0000000 --- a/src/libui_sdl/libui/darwin/control.m +++ /dev/null @@ -1,84 +0,0 @@ -// 16 august 2015 -#import "uipriv_darwin.h" - -void uiDarwinControlSyncEnableState(uiDarwinControl *c, int state) -{ - (*(c->SyncEnableState))(c, state); -} - -void uiDarwinControlSetSuperview(uiDarwinControl *c, NSView *superview) -{ - (*(c->SetSuperview))(c, superview); -} - -BOOL uiDarwinControlHugsTrailingEdge(uiDarwinControl *c) -{ - return (*(c->HugsTrailingEdge))(c); -} - -BOOL uiDarwinControlHugsBottom(uiDarwinControl *c) -{ - return (*(c->HugsBottom))(c); -} - -void uiDarwinControlChildEdgeHuggingChanged(uiDarwinControl *c) -{ - (*(c->ChildEdgeHuggingChanged))(c); -} - -NSLayoutPriority uiDarwinControlHuggingPriority(uiDarwinControl *c, NSLayoutConstraintOrientation orientation) -{ - return (*(c->HuggingPriority))(c, orientation); -} - -void uiDarwinControlSetHuggingPriority(uiDarwinControl *c, NSLayoutPriority priority, NSLayoutConstraintOrientation orientation) -{ - (*(c->SetHuggingPriority))(c, priority, orientation); -} - -void uiDarwinControlChildVisibilityChanged(uiDarwinControl *c) -{ - (*(c->ChildVisibilityChanged))(c); -} - -void uiDarwinSetControlFont(NSControl *c, NSControlSize size) -{ - [c setFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:size]]]; -} - -#define uiDarwinControlSignature 0x44617277 - -uiDarwinControl *uiDarwinAllocControl(size_t n, uint32_t typesig, const char *typenamestr) -{ - return uiDarwinControl(uiAllocControl(n, uiDarwinControlSignature, typesig, typenamestr)); -} - -BOOL uiDarwinShouldStopSyncEnableState(uiDarwinControl *c, BOOL enabled) -{ - int ce; - - ce = uiControlEnabled(uiControl(c)); - // only stop if we're going from disabled back to enabled; don't stop under any other condition - // (if we stop when going from enabled to disabled then enabled children of a disabled control won't get disabled at the OS level) - if (!ce && enabled) - return YES; - return NO; -} - -void uiDarwinNotifyEdgeHuggingChanged(uiDarwinControl *c) -{ - uiControl *parent; - - parent = uiControlParent(uiControl(c)); - if (parent != NULL) - uiDarwinControlChildEdgeHuggingChanged(uiDarwinControl(parent)); -} - -void uiDarwinNotifyVisibilityChanged(uiDarwinControl *c) -{ - uiControl *parent; - - parent = uiControlParent(uiControl(c)); - if (parent != NULL) - uiDarwinControlChildVisibilityChanged(uiDarwinControl(parent)); -} diff --git a/src/libui_sdl/libui/darwin/datetimepicker.m b/src/libui_sdl/libui/darwin/datetimepicker.m deleted file mode 100644 index 44364d9..0000000 --- a/src/libui_sdl/libui/darwin/datetimepicker.m +++ /dev/null @@ -1,42 +0,0 @@ -// 14 august 2015 -#import "uipriv_darwin.h" - -struct uiDateTimePicker { - uiDarwinControl c; - NSDatePicker *dp; -}; - -uiDarwinControlAllDefaults(uiDateTimePicker, dp) - -static uiDateTimePicker *finishNewDateTimePicker(NSDatePickerElementFlags elements) -{ - uiDateTimePicker *d; - - uiDarwinNewControl(uiDateTimePicker, d); - - d->dp = [[NSDatePicker alloc] initWithFrame:NSZeroRect]; - [d->dp setBordered:NO]; - [d->dp setBezeled:YES]; - [d->dp setDrawsBackground:YES]; - [d->dp setDatePickerStyle:NSTextFieldAndStepperDatePickerStyle]; - [d->dp setDatePickerElements:elements]; - [d->dp setDatePickerMode:NSSingleDateMode]; - uiDarwinSetControlFont(d->dp, NSRegularControlSize); - - return d; -} - -uiDateTimePicker *uiNewDateTimePicker(void) -{ - return finishNewDateTimePicker(NSYearMonthDayDatePickerElementFlag | NSHourMinuteSecondDatePickerElementFlag); -} - -uiDateTimePicker *uiNewDatePicker(void) -{ - return finishNewDateTimePicker(NSYearMonthDayDatePickerElementFlag); -} - -uiDateTimePicker *uiNewTimePicker(void) -{ - return finishNewDateTimePicker(NSHourMinuteSecondDatePickerElementFlag); -} diff --git a/src/libui_sdl/libui/darwin/debug.m b/src/libui_sdl/libui/darwin/debug.m deleted file mode 100644 index c91c6a7..0000000 --- a/src/libui_sdl/libui/darwin/debug.m +++ /dev/null @@ -1,19 +0,0 @@ -// 13 may 2016 -#import "uipriv_darwin.h" - -// LONGTERM don't halt on release builds - -void realbug(const char *file, const char *line, const char *func, const char *prefix, const char *format, va_list ap) -{ - NSMutableString *str; - NSString *formatted; - - str = [NSMutableString new]; - [str appendString:[NSString stringWithFormat:@"[libui] %s:%s:%s() %s", file, line, func, prefix]]; - formatted = [[NSString alloc] initWithFormat:[NSString stringWithUTF8String:format] arguments:ap]; - [str appendString:formatted]; - [formatted release]; - NSLog(@"%@", str); - [str release]; - __builtin_trap(); -} diff --git a/src/libui_sdl/libui/darwin/draw.m b/src/libui_sdl/libui/darwin/draw.m deleted file mode 100644 index 262ad3e..0000000 --- a/src/libui_sdl/libui/darwin/draw.m +++ /dev/null @@ -1,454 +0,0 @@ -// 6 september 2015 -#import "uipriv_darwin.h" - -struct uiDrawPath { - CGMutablePathRef path; - uiDrawFillMode fillMode; - BOOL ended; -}; - -uiDrawPath *uiDrawNewPath(uiDrawFillMode mode) -{ - uiDrawPath *p; - - p = uiNew(uiDrawPath); - p->path = CGPathCreateMutable(); - p->fillMode = mode; - return p; -} - -void uiDrawFreePath(uiDrawPath *p) -{ - CGPathRelease((CGPathRef) (p->path)); - uiFree(p); -} - -void uiDrawPathNewFigure(uiDrawPath *p, double x, double y) -{ - if (p->ended) - userbug("You cannot call uiDrawPathNewFigure() on a uiDrawPath that has already been ended. (path; %p)", p); - CGPathMoveToPoint(p->path, NULL, x, y); -} - -void uiDrawPathNewFigureWithArc(uiDrawPath *p, double xCenter, double yCenter, double radius, double startAngle, double sweep, int negative) -{ - double sinStart, cosStart; - double startx, starty; - - if (p->ended) - userbug("You cannot call uiDrawPathNewFigureWithArc() on a uiDrawPath that has already been ended. (path; %p)", p); - sinStart = sin(startAngle); - cosStart = cos(startAngle); - startx = xCenter + radius * cosStart; - starty = yCenter + radius * sinStart; - CGPathMoveToPoint(p->path, NULL, startx, starty); - uiDrawPathArcTo(p, xCenter, yCenter, radius, startAngle, sweep, negative); -} - -void uiDrawPathLineTo(uiDrawPath *p, double x, double y) -{ - // TODO refine this to require being in a path - if (p->ended) - implbug("attempt to add line to ended path in uiDrawPathLineTo()"); - CGPathAddLineToPoint(p->path, NULL, x, y); -} - -void uiDrawPathArcTo(uiDrawPath *p, double xCenter, double yCenter, double radius, double startAngle, double sweep, int negative) -{ - bool cw; - - // TODO likewise - if (p->ended) - implbug("attempt to add arc to ended path in uiDrawPathArcTo()"); - if (sweep > 2 * uiPi) - sweep = 2 * uiPi; - cw = false; - if (negative) - cw = true; - CGPathAddArc(p->path, NULL, - xCenter, yCenter, - radius, - startAngle, startAngle + sweep, - cw); -} - -void uiDrawPathBezierTo(uiDrawPath *p, double c1x, double c1y, double c2x, double c2y, double endX, double endY) -{ - // TODO likewise - if (p->ended) - implbug("attempt to add bezier to ended path in uiDrawPathBezierTo()"); - CGPathAddCurveToPoint(p->path, NULL, - c1x, c1y, - c2x, c2y, - endX, endY); -} - -void uiDrawPathCloseFigure(uiDrawPath *p) -{ - // TODO likewise - if (p->ended) - implbug("attempt to close figure of ended path in uiDrawPathCloseFigure()"); - CGPathCloseSubpath(p->path); -} - -void uiDrawPathAddRectangle(uiDrawPath *p, double x, double y, double width, double height) -{ - if (p->ended) - userbug("You cannot call uiDrawPathAddRectangle() on a uiDrawPath that has already been ended. (path; %p)", p); - CGPathAddRect(p->path, NULL, CGRectMake(x, y, width, height)); -} - -void uiDrawPathEnd(uiDrawPath *p) -{ - p->ended = TRUE; -} - -struct uiDrawContext { - CGContextRef c; - CGFloat height; // needed for text; see below -}; - -uiDrawContext *newContext(CGContextRef ctxt, CGFloat height) -{ - uiDrawContext *c; - - c = uiNew(uiDrawContext); - c->c = ctxt; - c->height = height; - return c; -} - -void freeContext(uiDrawContext *c) -{ - uiFree(c); -} - -// a stroke is identical to a fill of a stroked path -// we need to do this in order to stroke with a gradient; see http://stackoverflow.com/a/25034854/3408572 -// doing this for other brushes works too -void uiDrawStroke(uiDrawContext *c, uiDrawPath *path, uiDrawBrush *b, uiDrawStrokeParams *p) -{ - CGLineCap cap; - CGLineJoin join; - CGPathRef dashPath; - CGFloat *dashes; - size_t i; - uiDrawPath p2; - - if (!path->ended) - userbug("You cannot call uiDrawStroke() on a uiDrawPath that has not been ended. (path: %p)", path); - - switch (p->Cap) { - case uiDrawLineCapFlat: - cap = kCGLineCapButt; - break; - case uiDrawLineCapRound: - cap = kCGLineCapRound; - break; - case uiDrawLineCapSquare: - cap = kCGLineCapSquare; - break; - } - switch (p->Join) { - case uiDrawLineJoinMiter: - join = kCGLineJoinMiter; - break; - case uiDrawLineJoinRound: - join = kCGLineJoinRound; - break; - case uiDrawLineJoinBevel: - join = kCGLineJoinBevel; - break; - } - - // create a temporary path identical to the previous one - dashPath = (CGPathRef) path->path; - if (p->NumDashes != 0) { - dashes = (CGFloat *) uiAlloc(p->NumDashes * sizeof (CGFloat), "CGFloat[]"); - for (i = 0; i < p->NumDashes; i++) - dashes[i] = p->Dashes[i]; - dashPath = CGPathCreateCopyByDashingPath(path->path, - NULL, - p->DashPhase, - dashes, - p->NumDashes); - uiFree(dashes); - } - // the documentation is wrong: this produces a path suitable for calling CGPathCreateCopyByStrokingPath(), not for filling directly - // the cast is safe; we never modify the CGPathRef and always cast it back to a CGPathRef anyway - p2.path = (CGMutablePathRef) CGPathCreateCopyByStrokingPath(dashPath, - NULL, - p->Thickness, - cap, - join, - p->MiterLimit); - if (p->NumDashes != 0) - CGPathRelease(dashPath); - - // always draw stroke fills using the winding rule - // otherwise intersecting figures won't draw correctly - p2.fillMode = uiDrawFillModeWinding; - p2.ended = path->ended; - uiDrawFill(c, &p2, b); - // and clean up - CGPathRelease((CGPathRef) (p2.path)); -} - -// for a solid fill, we can merely have Core Graphics fill directly -static void fillSolid(CGContextRef ctxt, uiDrawPath *p, uiDrawBrush *b) -{ - // TODO this uses DeviceRGB; switch to sRGB - CGContextSetRGBFillColor(ctxt, b->R, b->G, b->B, b->A); - switch (p->fillMode) { - case uiDrawFillModeWinding: - CGContextFillPath(ctxt); - break; - case uiDrawFillModeAlternate: - CGContextEOFillPath(ctxt); - break; - } -} - -// for a gradient fill, we need to clip to the path and then draw the gradient -// see http://stackoverflow.com/a/25034854/3408572 -static void fillGradient(CGContextRef ctxt, uiDrawPath *p, uiDrawBrush *b) -{ - CGGradientRef gradient; - CGColorSpaceRef colorspace; - CGFloat *colors; - CGFloat *locations; - size_t i; - - // gradients need a color space - // for consistency with windows, use sRGB - colorspace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB); - - // make the gradient - colors = uiAlloc(b->NumStops * 4 * sizeof (CGFloat), "CGFloat[]"); - locations = uiAlloc(b->NumStops * sizeof (CGFloat), "CGFloat[]"); - for (i = 0; i < b->NumStops; i++) { - colors[i * 4 + 0] = b->Stops[i].R; - colors[i * 4 + 1] = b->Stops[i].G; - colors[i * 4 + 2] = b->Stops[i].B; - colors[i * 4 + 3] = b->Stops[i].A; - locations[i] = b->Stops[i].Pos; - } - gradient = CGGradientCreateWithColorComponents(colorspace, colors, locations, b->NumStops); - uiFree(locations); - uiFree(colors); - - // because we're mucking with clipping, we need to save the graphics state and restore it later - CGContextSaveGState(ctxt); - - // clip - switch (p->fillMode) { - case uiDrawFillModeWinding: - CGContextClip(ctxt); - break; - case uiDrawFillModeAlternate: - CGContextEOClip(ctxt); - break; - } - - // draw the gradient - switch (b->Type) { - case uiDrawBrushTypeLinearGradient: - CGContextDrawLinearGradient(ctxt, - gradient, - CGPointMake(b->X0, b->Y0), - CGPointMake(b->X1, b->Y1), - kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation); - break; - case uiDrawBrushTypeRadialGradient: - CGContextDrawRadialGradient(ctxt, - gradient, - CGPointMake(b->X0, b->Y0), - // make the start circle radius 0 to make it a point - 0, - CGPointMake(b->X1, b->Y1), - b->OuterRadius, - kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation); - break; - } - - // and clean up - CGContextRestoreGState(ctxt); - CGGradientRelease(gradient); - CGColorSpaceRelease(colorspace); -} - -void uiDrawFill(uiDrawContext *c, uiDrawPath *path, uiDrawBrush *b) -{ - if (!path->ended) - userbug("You cannot call uiDrawStroke() on a uiDrawPath that has not been ended. (path: %p)", path); - CGContextAddPath(c->c, (CGPathRef) (path->path)); - switch (b->Type) { - case uiDrawBrushTypeSolid: - fillSolid(c->c, path, b); - return; - case uiDrawBrushTypeLinearGradient: - case uiDrawBrushTypeRadialGradient: - fillGradient(c->c, path, b); - return; -// case uiDrawBrushTypeImage: - // TODO - return; - } - userbug("Unknown brush type %d passed to uiDrawFill().", b->Type); -} - -static void m2c(uiDrawMatrix *m, CGAffineTransform *c) -{ - c->a = m->M11; - c->b = m->M12; - c->c = m->M21; - c->d = m->M22; - c->tx = m->M31; - c->ty = m->M32; -} - -static void c2m(CGAffineTransform *c, uiDrawMatrix *m) -{ - m->M11 = c->a; - m->M12 = c->b; - m->M21 = c->c; - m->M22 = c->d; - m->M31 = c->tx; - m->M32 = c->ty; -} - -void uiDrawMatrixTranslate(uiDrawMatrix *m, double x, double y) -{ - CGAffineTransform c; - - m2c(m, &c); - c = CGAffineTransformTranslate(c, x, y); - c2m(&c, m); -} - -void uiDrawMatrixScale(uiDrawMatrix *m, double xCenter, double yCenter, double x, double y) -{ - CGAffineTransform c; - double xt, yt; - - m2c(m, &c); - xt = x; - yt = y; - scaleCenter(xCenter, yCenter, &xt, &yt); - c = CGAffineTransformTranslate(c, xt, yt); - c = CGAffineTransformScale(c, x, y); - c = CGAffineTransformTranslate(c, -xt, -yt); - c2m(&c, m); -} - -void uiDrawMatrixRotate(uiDrawMatrix *m, double x, double y, double amount) -{ - CGAffineTransform c; - - m2c(m, &c); - c = CGAffineTransformTranslate(c, x, y); - c = CGAffineTransformRotate(c, amount); - c = CGAffineTransformTranslate(c, -x, -y); - c2m(&c, m); -} - -void uiDrawMatrixSkew(uiDrawMatrix *m, double x, double y, double xamount, double yamount) -{ - fallbackSkew(m, x, y, xamount, yamount); -} - -void uiDrawMatrixMultiply(uiDrawMatrix *dest, uiDrawMatrix *src) -{ - CGAffineTransform c; - CGAffineTransform d; - - m2c(dest, &c); - m2c(src, &d); - c = CGAffineTransformConcat(c, d); - c2m(&c, dest); -} - -// there is no test for invertibility; CGAffineTransformInvert() is merely documented as returning the matrix unchanged if it isn't invertible -// therefore, special care must be taken to catch matrices who are their own inverses -// TODO figure out which matrices these are and do so -int uiDrawMatrixInvertible(uiDrawMatrix *m) -{ - CGAffineTransform c, d; - - m2c(m, &c); - d = CGAffineTransformInvert(c); - return CGAffineTransformEqualToTransform(c, d) == false; -} - -int uiDrawMatrixInvert(uiDrawMatrix *m) -{ - CGAffineTransform c, d; - - m2c(m, &c); - d = CGAffineTransformInvert(c); - if (CGAffineTransformEqualToTransform(c, d)) - return 0; - c2m(&d, m); - return 1; -} - -void uiDrawMatrixTransformPoint(uiDrawMatrix *m, double *x, double *y) -{ - CGAffineTransform c; - CGPoint p; - - m2c(m, &c); - p = CGPointApplyAffineTransform(CGPointMake(*x, *y), c); - *x = p.x; - *y = p.y; -} - -void uiDrawMatrixTransformSize(uiDrawMatrix *m, double *x, double *y) -{ - CGAffineTransform c; - CGSize s; - - m2c(m, &c); - s = CGSizeApplyAffineTransform(CGSizeMake(*x, *y), c); - *x = s.width; - *y = s.height; -} - -void uiDrawTransform(uiDrawContext *c, uiDrawMatrix *m) -{ - CGAffineTransform cm; - - m2c(m, &cm); - CGContextConcatCTM(c->c, cm); -} - -void uiDrawClip(uiDrawContext *c, uiDrawPath *path) -{ - if (!path->ended) - userbug("You cannot call uiDrawCilp() on a uiDrawPath that has not been ended. (path: %p)", path); - CGContextAddPath(c->c, (CGPathRef) (path->path)); - switch (path->fillMode) { - case uiDrawFillModeWinding: - CGContextClip(c->c); - break; - case uiDrawFillModeAlternate: - CGContextEOClip(c->c); - break; - } -} - -// TODO figure out what besides transforms these save/restore on all platforms -void uiDrawSave(uiDrawContext *c) -{ - CGContextSaveGState(c->c); -} - -void uiDrawRestore(uiDrawContext *c) -{ - CGContextRestoreGState(c->c); -} - -void uiDrawText(uiDrawContext *c, double x, double y, uiDrawTextLayout *layout) -{ - doDrawText(c->c, c->height, x, y, layout); -} diff --git a/src/libui_sdl/libui/darwin/drawtext.m b/src/libui_sdl/libui/darwin/drawtext.m deleted file mode 100644 index c376536..0000000 --- a/src/libui_sdl/libui/darwin/drawtext.m +++ /dev/null @@ -1,655 +0,0 @@ -// 6 september 2015 -#import "uipriv_darwin.h" - -// TODO -#define complain(...) implbug(__VA_ARGS__) - -// TODO double-check that we are properly handling allocation failures (or just toll free bridge from cocoa) -struct uiDrawFontFamilies { - CFArrayRef fonts; -}; - -uiDrawFontFamilies *uiDrawListFontFamilies(void) -{ - uiDrawFontFamilies *ff; - - ff = uiNew(uiDrawFontFamilies); - ff->fonts = CTFontManagerCopyAvailableFontFamilyNames(); - if (ff->fonts == NULL) - implbug("error getting available font names (no reason specified) (TODO)"); - return ff; -} - -int uiDrawFontFamiliesNumFamilies(uiDrawFontFamilies *ff) -{ - return CFArrayGetCount(ff->fonts); -} - -char *uiDrawFontFamiliesFamily(uiDrawFontFamilies *ff, int n) -{ - CFStringRef familystr; - char *family; - - familystr = (CFStringRef) CFArrayGetValueAtIndex(ff->fonts, n); - // toll-free bridge - family = uiDarwinNSStringToText((NSString *) familystr); - // Get Rule means we do not free familystr - return family; -} - -void uiDrawFreeFontFamilies(uiDrawFontFamilies *ff) -{ - CFRelease(ff->fonts); - uiFree(ff); -} - -struct uiDrawTextFont { - CTFontRef f; -}; - -uiDrawTextFont *mkTextFont(CTFontRef f, BOOL retain) -{ - uiDrawTextFont *font; - - font = uiNew(uiDrawTextFont); - font->f = f; - if (retain) - CFRetain(font->f); - return font; -} - -uiDrawTextFont *mkTextFontFromNSFont(NSFont *f) -{ - // toll-free bridging; we do retain, though - return mkTextFont((CTFontRef) f, YES); -} - -static CFMutableDictionaryRef newAttrList(void) -{ - CFMutableDictionaryRef attr; - - attr = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - if (attr == NULL) - complain("error creating attribute dictionary in newAttrList()()"); - return attr; -} - -static void addFontFamilyAttr(CFMutableDictionaryRef attr, const char *family) -{ - CFStringRef cfstr; - - cfstr = CFStringCreateWithCString(NULL, family, kCFStringEncodingUTF8); - if (cfstr == NULL) - complain("error creating font family name CFStringRef in addFontFamilyAttr()"); - CFDictionaryAddValue(attr, kCTFontFamilyNameAttribute, cfstr); - CFRelease(cfstr); // dictionary holds its own reference -} - -static void addFontSizeAttr(CFMutableDictionaryRef attr, double size) -{ - CFNumberRef n; - - n = CFNumberCreate(NULL, kCFNumberDoubleType, &size); - CFDictionaryAddValue(attr, kCTFontSizeAttribute, n); - CFRelease(n); -} - -#if 0 -TODO -// See http://stackoverflow.com/questions/4810409/does-coretext-support-small-caps/4811371#4811371 and https://git.gnome.org/browse/pango/tree/pango/pangocoretext-fontmap.c for what these do -// And fortunately, unlike the traits (see below), unmatched features are simply ignored without affecting the other features :D -static void addFontSmallCapsAttr(CFMutableDictionaryRef attr) -{ - CFMutableArrayRef outerArray; - CFMutableDictionaryRef innerDict; - CFNumberRef numType, numSelector; - int num; - - outerArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - if (outerArray == NULL) - complain("error creating outer CFArray for adding small caps attributes in addFontSmallCapsAttr()"); - - // Apple's headers say these are deprecated, but a few fonts still rely on them - num = kLetterCaseType; - numType = CFNumberCreate(NULL, kCFNumberIntType, &num); - num = kSmallCapsSelector; - numSelector = CFNumberCreate(NULL, kCFNumberIntType, &num); - innerDict = newAttrList(); - CFDictionaryAddValue(innerDict, kCTFontFeatureTypeIdentifierKey, numType); - CFRelease(numType); - CFDictionaryAddValue(innerDict, kCTFontFeatureSelectorIdentifierKey, numSelector); - CFRelease(numSelector); - CFArrayAppendValue(outerArray, innerDict); - CFRelease(innerDict); // and likewise for CFArray - - // these are the non-deprecated versions of the above; some fonts have these instead - num = kLowerCaseType; - numType = CFNumberCreate(NULL, kCFNumberIntType, &num); - num = kLowerCaseSmallCapsSelector; - numSelector = CFNumberCreate(NULL, kCFNumberIntType, &num); - innerDict = newAttrList(); - CFDictionaryAddValue(innerDict, kCTFontFeatureTypeIdentifierKey, numType); - CFRelease(numType); - CFDictionaryAddValue(innerDict, kCTFontFeatureSelectorIdentifierKey, numSelector); - CFRelease(numSelector); - CFArrayAppendValue(outerArray, innerDict); - CFRelease(innerDict); // and likewise for CFArray - - CFDictionaryAddValue(attr, kCTFontFeatureSettingsAttribute, outerArray); - CFRelease(outerArray); -} -#endif - -// Named constants for these were NOT added until 10.11, and even then they were added as external symbols instead of macros, so we can't use them directly :( -// kode54 got these for me before I had access to El Capitan; thanks to him. -#define ourNSFontWeightUltraLight -0.800000 -#define ourNSFontWeightThin -0.600000 -#define ourNSFontWeightLight -0.400000 -#define ourNSFontWeightRegular 0.000000 -#define ourNSFontWeightMedium 0.230000 -#define ourNSFontWeightSemibold 0.300000 -#define ourNSFontWeightBold 0.400000 -#define ourNSFontWeightHeavy 0.560000 -#define ourNSFontWeightBlack 0.620000 -static const CGFloat ctWeights[] = { - // yeah these two have their names swapped; blame Pango - [uiDrawTextWeightThin] = ourNSFontWeightUltraLight, - [uiDrawTextWeightUltraLight] = ourNSFontWeightThin, - [uiDrawTextWeightLight] = ourNSFontWeightLight, - // for this one let's go between Light and Regular - // we're doing nearest so if there happens to be an exact value hopefully it's close enough - [uiDrawTextWeightBook] = ourNSFontWeightLight + ((ourNSFontWeightRegular - ourNSFontWeightLight) / 2), - [uiDrawTextWeightNormal] = ourNSFontWeightRegular, - [uiDrawTextWeightMedium] = ourNSFontWeightMedium, - [uiDrawTextWeightSemiBold] = ourNSFontWeightSemibold, - [uiDrawTextWeightBold] = ourNSFontWeightBold, - // for this one let's go between Bold and Heavy - [uiDrawTextWeightUltraBold] = ourNSFontWeightBold + ((ourNSFontWeightHeavy - ourNSFontWeightBold) / 2), - [uiDrawTextWeightHeavy] = ourNSFontWeightHeavy, - [uiDrawTextWeightUltraHeavy] = ourNSFontWeightBlack, -}; - -// Unfortunately there are still no named constants for these. -// Let's just use normalized widths. -// As far as I can tell (OS X only ships with condensed fonts, not expanded fonts; TODO), regardless of condensed or expanded, negative means condensed and positive means expanded. -// TODO verify this is correct -static const CGFloat ctStretches[] = { - [uiDrawTextStretchUltraCondensed] = -1.0, - [uiDrawTextStretchExtraCondensed] = -0.75, - [uiDrawTextStretchCondensed] = -0.5, - [uiDrawTextStretchSemiCondensed] = -0.25, - [uiDrawTextStretchNormal] = 0.0, - [uiDrawTextStretchSemiExpanded] = 0.25, - [uiDrawTextStretchExpanded] = 0.5, - [uiDrawTextStretchExtraExpanded] = 0.75, - [uiDrawTextStretchUltraExpanded] = 1.0, -}; - -struct closeness { - CFIndex index; - CGFloat weight; - CGFloat italic; - CGFloat stretch; - CGFloat distance; -}; - -// Stupidity: CTFont requires an **exact match for the entire traits dictionary**, otherwise it will **drop ALL the traits**. -// We have to implement the closest match ourselves. -// Also we have to do this before adding the small caps flags, because the matching descriptors won't have those. -CTFontDescriptorRef matchTraits(CTFontDescriptorRef against, uiDrawTextWeight weight, uiDrawTextItalic italic, uiDrawTextStretch stretch) -{ - CGFloat targetWeight; - CGFloat italicCloseness, obliqueCloseness, normalCloseness; - CGFloat targetStretch; - CFArrayRef matching; - CFIndex i, n; - struct closeness *closeness; - CTFontDescriptorRef current; - CTFontDescriptorRef out; - - targetWeight = ctWeights[weight]; - switch (italic) { - case uiDrawTextItalicNormal: - italicCloseness = 1; - obliqueCloseness = 1; - normalCloseness = 0; - break; - case uiDrawTextItalicOblique: - italicCloseness = 0.5; - obliqueCloseness = 0; - normalCloseness = 1; - break; - case uiDrawTextItalicItalic: - italicCloseness = 0; - obliqueCloseness = 0.5; - normalCloseness = 1; - break; - } - targetStretch = ctStretches[stretch]; - - matching = CTFontDescriptorCreateMatchingFontDescriptors(against, NULL); - if (matching == NULL) - // no matches; give the original back and hope for the best - return against; - n = CFArrayGetCount(matching); - if (n == 0) { - // likewise - CFRelease(matching); - return against; - } - - closeness = (struct closeness *) uiAlloc(n * sizeof (struct closeness), "struct closeness[]"); - for (i = 0; i < n; i++) { - CFDictionaryRef traits; - CFNumberRef cfnum; - CTFontSymbolicTraits symbolic; - - closeness[i].index = i; - - current = CFArrayGetValueAtIndex(matching, i); - traits = CTFontDescriptorCopyAttribute(current, kCTFontTraitsAttribute); - if (traits == NULL) { - // couldn't get traits; be safe by ranking it lowest - // LONGTERM figure out what the longest possible distances are - closeness[i].weight = 3; - closeness[i].italic = 2; - closeness[i].stretch = 3; - continue; - } - - symbolic = 0; // assume no symbolic traits if none are listed - cfnum = CFDictionaryGetValue(traits, kCTFontSymbolicTrait); - if (cfnum != NULL) { - SInt32 s; - - if (CFNumberGetValue(cfnum, kCFNumberSInt32Type, &s) == false) - complain("error getting symbolic traits in matchTraits()"); - symbolic = (CTFontSymbolicTraits) s; - // Get rule; do not release cfnum - } - - // now try weight - cfnum = CFDictionaryGetValue(traits, kCTFontWeightTrait); - if (cfnum != NULL) { - CGFloat val; - - // LONGTERM instead of complaining for this and width and possibly also symbolic traits above, should we just fall through to the default? - if (CFNumberGetValue(cfnum, kCFNumberCGFloatType, &val) == false) - complain("error getting weight value in matchTraits()"); - closeness[i].weight = val - targetWeight; - } else - // okay there's no weight key; let's try the literal meaning of the symbolic constant - // LONGTERM is the weight key guaranteed? - if ((symbolic & kCTFontBoldTrait) != 0) - closeness[i].weight = ourNSFontWeightBold - targetWeight; - else - closeness[i].weight = ourNSFontWeightRegular - targetWeight; - - // italics is a bit harder because Core Text doesn't expose a concept of obliqueness - // Pango just does a g_strrstr() (backwards case-sensitive search) for "Oblique" in the font's style name (see https://git.gnome.org/browse/pango/tree/pango/pangocoretext-fontmap.c); let's do that too I guess - if ((symbolic & kCTFontItalicTrait) != 0) - closeness[i].italic = italicCloseness; - else { - CFStringRef styleName; - BOOL isOblique; - - isOblique = NO; // default value - styleName = CTFontDescriptorCopyAttribute(current, kCTFontStyleNameAttribute); - if (styleName != NULL) { - CFRange range; - - // note the use of the toll-free bridge for the string literal, since CFSTR() *can* return NULL - range = CFStringFind(styleName, (CFStringRef) @"Oblique", kCFCompareBackwards); - if (range.location != kCFNotFound) - isOblique = YES; - CFRelease(styleName); - } - if (isOblique) - closeness[i].italic = obliqueCloseness; - else - closeness[i].italic = normalCloseness; - } - - // now try width - // TODO this does not seem to be enough for Skia's extended variants; the width trait is 0 but the Expanded flag is on - // TODO verify the rest of this matrix (what matrix?) - cfnum = CFDictionaryGetValue(traits, kCTFontWidthTrait); - if (cfnum != NULL) { - CGFloat val; - - if (CFNumberGetValue(cfnum, kCFNumberCGFloatType, &val) == false) - complain("error getting width value in matchTraits()"); - closeness[i].stretch = val - targetStretch; - } else - // okay there's no width key; let's try the literal meaning of the symbolic constant - // LONGTERM is the width key guaranteed? - if ((symbolic & kCTFontExpandedTrait) != 0) - closeness[i].stretch = 1.0 - targetStretch; - else if ((symbolic & kCTFontCondensedTrait) != 0) - closeness[i].stretch = -1.0 - targetStretch; - else - closeness[i].stretch = 0.0 - targetStretch; - - CFRelease(traits); - } - - // now figure out the 3-space difference between the three and sort by that - for (i = 0; i < n; i++) { - CGFloat weight, italic, stretch; - - weight = closeness[i].weight; - weight *= weight; - italic = closeness[i].italic; - italic *= italic; - stretch = closeness[i].stretch; - stretch *= stretch; - closeness[i].distance = sqrt(weight + italic + stretch); - } - qsort_b(closeness, n, sizeof (struct closeness), ^(const void *aa, const void *bb) { - const struct closeness *a = (const struct closeness *) aa; - const struct closeness *b = (const struct closeness *) bb; - - // via http://www.gnu.org/software/libc/manual/html_node/Comparison-Functions.html#Comparison-Functions - // LONGTERM is this really the best way? isn't it the same as if (*a < *b) return -1; if (*a > *b) return 1; return 0; ? - return (a->distance > b->distance) - (a->distance < b->distance); - }); - // and the first element of the sorted array is what we want - out = CFArrayGetValueAtIndex(matching, closeness[0].index); - CFRetain(out); // get rule - - // release everything - uiFree(closeness); - CFRelease(matching); - // and release the original descriptor since we no longer need it - CFRelease(against); - - return out; -} - -// Now remember what I said earlier about having to add the small caps traits after calling the above? This gets a dictionary back so we can do so. -CFMutableDictionaryRef extractAttributes(CTFontDescriptorRef desc) -{ - CFDictionaryRef dict; - CFMutableDictionaryRef mdict; - - dict = CTFontDescriptorCopyAttributes(desc); - // this might not be mutable, so make a mutable copy - mdict = CFDictionaryCreateMutableCopy(NULL, 0, dict); - CFRelease(dict); - return mdict; -} - -uiDrawTextFont *uiDrawLoadClosestFont(const uiDrawTextFontDescriptor *desc) -{ - CTFontRef f; - CFMutableDictionaryRef attr; - CTFontDescriptorRef cfdesc; - - attr = newAttrList(); - addFontFamilyAttr(attr, desc->Family); - addFontSizeAttr(attr, desc->Size); - - // now we have to do the traits matching, so create a descriptor, match the traits, and then get the attributes back - cfdesc = CTFontDescriptorCreateWithAttributes(attr); - // TODO release attr? - cfdesc = matchTraits(cfdesc, desc->Weight, desc->Italic, desc->Stretch); - - // specify the initial size again just to be safe - f = CTFontCreateWithFontDescriptor(cfdesc, desc->Size, NULL); - // TODO release cfdesc? - - return mkTextFont(f, NO); // we hold the initial reference; no need to retain again -} - -void uiDrawFreeTextFont(uiDrawTextFont *font) -{ - CFRelease(font->f); - uiFree(font); -} - -uintptr_t uiDrawTextFontHandle(uiDrawTextFont *font) -{ - return (uintptr_t) (font->f); -} - -void uiDrawTextFontDescribe(uiDrawTextFont *font, uiDrawTextFontDescriptor *desc) -{ - // TODO -} - -// text sizes and user space points are identical: -// - https://developer.apple.com/library/mac/documentation/TextFonts/Conceptual/CocoaTextArchitecture/TypoFeatures/TextSystemFeatures.html#//apple_ref/doc/uid/TP40009459-CH6-51627-BBCCHIFF text points are 72 per inch -// - https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CocoaDrawingGuide/Transforms/Transforms.html#//apple_ref/doc/uid/TP40003290-CH204-SW5 user space points are 72 per inch -void uiDrawTextFontGetMetrics(uiDrawTextFont *font, uiDrawTextFontMetrics *metrics) -{ - metrics->Ascent = CTFontGetAscent(font->f); - metrics->Descent = CTFontGetDescent(font->f); - metrics->Leading = CTFontGetLeading(font->f); - metrics->UnderlinePos = CTFontGetUnderlinePosition(font->f); - metrics->UnderlineThickness = CTFontGetUnderlineThickness(font->f); -} - -struct uiDrawTextLayout { - CFMutableAttributedStringRef mas; - CFRange *charsToRanges; - double width; -}; - -uiDrawTextLayout *uiDrawNewTextLayout(const char *str, uiDrawTextFont *defaultFont, double width) -{ - uiDrawTextLayout *layout; - CFAttributedStringRef immutable; - CFMutableDictionaryRef attr; - CFStringRef backing; - CFIndex i, j, n; - - layout = uiNew(uiDrawTextLayout); - - // TODO docs say we need to use a different set of key callbacks - // TODO see if the font attribute key callbacks need to be the same - attr = newAttrList(); - // this will retain defaultFont->f; no need to worry - CFDictionaryAddValue(attr, kCTFontAttributeName, defaultFont->f); - - immutable = CFAttributedStringCreate(NULL, (CFStringRef) [NSString stringWithUTF8String:str], attr); - if (immutable == NULL) - complain("error creating immutable attributed string in uiDrawNewTextLayout()"); - CFRelease(attr); - - layout->mas = CFAttributedStringCreateMutableCopy(NULL, 0, immutable); - if (layout->mas == NULL) - complain("error creating attributed string in uiDrawNewTextLayout()"); - CFRelease(immutable); - - uiDrawTextLayoutSetWidth(layout, width); - - // unfortunately the CFRanges for attributes expect UTF-16 codepoints - // we want graphemes - // fortunately CFStringGetRangeOfComposedCharactersAtIndex() is here for us - // https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Strings/Articles/stringsClusters.html says that this does work on all multi-codepoint graphemes (despite the name), and that this is the preferred function for this particular job anyway - backing = CFAttributedStringGetString(layout->mas); - n = CFStringGetLength(backing); - // allocate one extra, just to be safe - layout->charsToRanges = (CFRange *) uiAlloc((n + 1) * sizeof (CFRange), "CFRange[]"); - i = 0; - j = 0; - while (i < n) { - CFRange range; - - range = CFStringGetRangeOfComposedCharactersAtIndex(backing, i); - i = range.location + range.length; - layout->charsToRanges[j] = range; - j++; - } - // and set the last one - layout->charsToRanges[j].location = i; - layout->charsToRanges[j].length = 0; - - return layout; -} - -void uiDrawFreeTextLayout(uiDrawTextLayout *layout) -{ - uiFree(layout->charsToRanges); - CFRelease(layout->mas); - uiFree(layout); -} - -void uiDrawTextLayoutSetWidth(uiDrawTextLayout *layout, double width) -{ - layout->width = width; -} - -struct framesetter { - CTFramesetterRef fs; - CFMutableDictionaryRef frameAttrib; - CGSize extents; -}; - -// TODO CTFrameProgression for RTL/LTR -// TODO kCTParagraphStyleSpecifierMaximumLineSpacing, kCTParagraphStyleSpecifierMinimumLineSpacing, kCTParagraphStyleSpecifierLineSpacingAdjustment for line spacing -static void mkFramesetter(uiDrawTextLayout *layout, struct framesetter *fs) -{ - CFRange fitRange; - CGFloat width; - - fs->fs = CTFramesetterCreateWithAttributedString(layout->mas); - if (fs->fs == NULL) - complain("error creating CTFramesetter object in mkFramesetter()"); - - // TODO kCTFramePathWidthAttributeName? - fs->frameAttrib = NULL; - - width = layout->width; - if (layout->width < 0) - width = CGFLOAT_MAX; - // TODO these seem to be floor()'d or truncated? - fs->extents = CTFramesetterSuggestFrameSizeWithConstraints(fs->fs, - CFRangeMake(0, 0), - fs->frameAttrib, - CGSizeMake(width, CGFLOAT_MAX), - &fitRange); // not documented as accepting NULL -} - -static void freeFramesetter(struct framesetter *fs) -{ - if (fs->frameAttrib != NULL) - CFRelease(fs->frameAttrib); - CFRelease(fs->fs); -} - -// LONGTERM allow line separation and leading to be factored into a wrapping text layout - -// TODO reconcile differences in character wrapping on platforms -void uiDrawTextLayoutExtents(uiDrawTextLayout *layout, double *width, double *height) -{ - struct framesetter fs; - - mkFramesetter(layout, &fs); - *width = fs.extents.width; - *height = fs.extents.height; - freeFramesetter(&fs); -} - -// Core Text doesn't draw onto a flipped view correctly; we have to do this -// see the iOS bits of the first example at https://developer.apple.com/library/mac/documentation/StringsTextFonts/Conceptual/CoreText_Programming/LayoutOperations/LayoutOperations.html#//apple_ref/doc/uid/TP40005533-CH12-SW1 (iOS is naturally flipped) -// TODO how is this affected by the CTM? -static void prepareContextForText(CGContextRef c, CGFloat cheight, double *y) -{ - CGContextSaveGState(c); - CGContextTranslateCTM(c, 0, cheight); - CGContextScaleCTM(c, 1.0, -1.0); - CGContextSetTextMatrix(c, CGAffineTransformIdentity); - - // wait, that's not enough; we need to offset y values to account for our new flipping - *y = cheight - *y; -} - -// TODO placement is incorrect for Helvetica -void doDrawText(CGContextRef c, CGFloat cheight, double x, double y, uiDrawTextLayout *layout) -{ - struct framesetter fs; - CGRect rect; - CGPathRef path; - CTFrameRef frame; - - prepareContextForText(c, cheight, &y); - mkFramesetter(layout, &fs); - - // oh, and since we're flipped, y is the bottom-left coordinate of the rectangle, not the top-left - // since we are flipped, we subtract - y -= fs.extents.height; - - rect.origin = CGPointMake(x, y); - rect.size = fs.extents; - path = CGPathCreateWithRect(rect, NULL); - - frame = CTFramesetterCreateFrame(fs.fs, - CFRangeMake(0, 0), - path, - fs.frameAttrib); - if (frame == NULL) - complain("error creating CTFrame object in doDrawText()"); - CTFrameDraw(frame, c); - CFRelease(frame); - - CFRelease(path); - - freeFramesetter(&fs); - CGContextRestoreGState(c); -} - -// LONGTERM provide an equivalent to CTLineGetTypographicBounds() on uiDrawTextLayout? - -// LONGTERM keep this for later features and documentation purposes -#if 0 - w = CTLineGetTypographicBounds(line, &ascent, &descent, NULL); - // though CTLineGetTypographicBounds() returns 0 on error, it also returns 0 on an empty string, so we can't reasonably check for error - CFRelease(line); - - // LONGTERM provide a way to get the image bounds as a separate function later - bounds = CTLineGetImageBounds(line, c); - // though CTLineGetImageBounds() returns CGRectNull on error, it also returns CGRectNull on an empty string, so we can't reasonably check for error - - // CGContextSetTextPosition() positions at the baseline in the case of CTLineDraw(); we need the top-left corner instead - CTLineGetTypographicBounds(line, &yoff, NULL, NULL); - // remember that we're flipped, so we subtract - y -= yoff; - CGContextSetTextPosition(c, x, y); -#endif - -static CFRange charsToRange(uiDrawTextLayout *layout, int startChar, int endChar) -{ - CFRange start, end; - CFRange out; - - start = layout->charsToRanges[startChar]; - end = layout->charsToRanges[endChar]; - out.location = start.location; - out.length = end.location - start.location; - return out; -} - -#define rangeToCFRange() charsToRange(layout, startChar, endChar) - -void uiDrawTextLayoutSetColor(uiDrawTextLayout *layout, int startChar, int endChar, double r, double g, double b, double a) -{ - CGColorSpaceRef colorspace; - CGFloat components[4]; - CGColorRef color; - - // for consistency with windows, use sRGB - colorspace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB); - components[0] = r; - components[1] = g; - components[2] = b; - components[3] = a; - color = CGColorCreate(colorspace, components); - CGColorSpaceRelease(colorspace); - - CFAttributedStringSetAttribute(layout->mas, - rangeToCFRange(), - kCTForegroundColorAttributeName, - color); - CGColorRelease(color); // TODO safe? -} diff --git a/src/libui_sdl/libui/darwin/editablecombo.m b/src/libui_sdl/libui/darwin/editablecombo.m deleted file mode 100644 index 434add7..0000000 --- a/src/libui_sdl/libui/darwin/editablecombo.m +++ /dev/null @@ -1,185 +0,0 @@ -// 14 august 2015 -#import "uipriv_darwin.h" - -// So why did I split uiCombobox into uiCombobox and uiEditableCombobox? Here's (90% of the; the other 10% is GTK+ events) answer: -// When you type a value into a NSComboBox that just happens to be in the list, it will autoselect that item! -// I can't seem to find a workaround. -// Fortunately, there's other weird behaviors that made this split worth it. -// And besides, selected items make little sense with editable comboboxes... you either separate or combine them with the text entry :V - -// NSComboBoxes have no intrinsic width; we'll use the default Interface Builder width for them. -#define comboboxWidth 96 - -@interface libui_intrinsicWidthNSComboBox : NSComboBox -@end - -@implementation libui_intrinsicWidthNSComboBox - -- (NSSize)intrinsicContentSize -{ - NSSize s; - - s = [super intrinsicContentSize]; - s.width = comboboxWidth; - return s; -} - -@end - -struct uiEditableCombobox { - uiDarwinControl c; - NSComboBox *cb; - void (*onChanged)(uiEditableCombobox *, void *); - void *onChangedData; -}; - -@interface editableComboboxDelegateClass : NSObject<NSComboBoxDelegate> { - struct mapTable *comboboxes; -} -- (void)controlTextDidChange:(NSNotification *)note; -- (void)comboBoxSelectionDidChange:(NSNotification *)note; -- (void)registerCombobox:(uiEditableCombobox *)c; -- (void)unregisterCombobox:(uiEditableCombobox *)c; -@end - -@implementation editableComboboxDelegateClass - -- (id)init -{ - self = [super init]; - if (self) - self->comboboxes = newMap(); - return self; -} - -- (void)dealloc -{ - mapDestroy(self->comboboxes); - [super dealloc]; -} - -- (void)controlTextDidChange:(NSNotification *)note -{ - uiEditableCombobox *c; - - c = uiEditableCombobox(mapGet(self->comboboxes, [note object])); - (*(c->onChanged))(c, c->onChangedData); -} - -// the above doesn't handle when an item is selected; this will -- (void)comboBoxSelectionDidChange:(NSNotification *)note -{ - // except this is sent BEFORE the entry is changed, and that doesn't send the above, so - // this is via http://stackoverflow.com/a/21059819/3408572 - it avoids the need to manage selected items - // this still isn't perfect — I get residual changes to the same value while navigating the list — but it's good enough - [self performSelector:@selector(controlTextDidChange:) - withObject:note - afterDelay:0]; -} - -- (void)registerCombobox:(uiEditableCombobox *)c -{ - mapSet(self->comboboxes, c->cb, c); - [c->cb setDelegate:self]; -} - -- (void)unregisterCombobox:(uiEditableCombobox *)c -{ - [c->cb setDelegate:nil]; - mapDelete(self->comboboxes, c->cb); -} - -@end - -static editableComboboxDelegateClass *comboboxDelegate = nil; - -uiDarwinControlAllDefaultsExceptDestroy(uiEditableCombobox, cb) - -static void uiEditableComboboxDestroy(uiControl *cc) -{ - uiEditableCombobox *c = uiEditableCombobox(cc); - - [comboboxDelegate unregisterCombobox:c]; - [c->cb release]; - uiFreeControl(uiControl(c)); -} - -void uiEditableComboboxAppend(uiEditableCombobox *c, const char *text) -{ - [c->cb addItemWithObjectValue:toNSString(text)]; -} - -char *uiEditableComboboxText(uiEditableCombobox *c) -{ - return uiDarwinNSStringToText([c->cb stringValue]); -} - -void uiEditableComboboxSetText(uiEditableCombobox *c, const char *text) -{ - NSString *t; - - t = toNSString(text); - [c->cb setStringValue:t]; - // yes, let's imitate the behavior that caused uiEditableCombobox to be separate in the first place! - // just to avoid confusion when users see an option in the list in the text field but not selected in the list - [c->cb selectItemWithObjectValue:t]; -} - -#if 0 -// LONGTERM -void uiEditableComboboxSetSelected(uiEditableCombobox *c, int n) -{ - if (c->editable) { - // see https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ComboBox/Tasks/SettingComboBoxValue.html#//apple_ref/doc/uid/20000256 - id delegate; - - // this triggers the delegate; turn it off for now - delegate = [c->cb delegate]; - [c->cb setDelegate:nil]; - - // this seems to work fine for -1 too - [c->cb selectItemAtIndex:n]; - if (n == -1) - [c->cb setObjectValue:@""]; - else - [c->cb setObjectValue:[c->cb objectValueOfSelectedItem]]; - - [c->cb setDelegate:delegate]; - return; - } - [c->pb selectItemAtIndex:n]; -} -#endif - -void uiEditableComboboxOnChanged(uiEditableCombobox *c, void (*f)(uiEditableCombobox *c, void *data), void *data) -{ - c->onChanged = f; - c->onChangedData = data; -} - -static void defaultOnChanged(uiEditableCombobox *c, void *data) -{ - // do nothing -} - -uiEditableCombobox *uiNewEditableCombobox(void) -{ - uiEditableCombobox *c; - - uiDarwinNewControl(uiEditableCombobox, c); - - c->cb = [[libui_intrinsicWidthNSComboBox alloc] initWithFrame:NSZeroRect]; - [c->cb setUsesDataSource:NO]; - [c->cb setButtonBordered:YES]; - [c->cb setCompletes:NO]; - uiDarwinSetControlFont(c->cb, NSRegularControlSize); - - if (comboboxDelegate == nil) { - comboboxDelegate = [[editableComboboxDelegateClass new] autorelease]; - [delegates addObject:comboboxDelegate]; - } - [comboboxDelegate registerCombobox:c]; - uiEditableComboboxOnChanged(c, defaultOnChanged, NULL); - - return c; -} diff --git a/src/libui_sdl/libui/darwin/entry.m b/src/libui_sdl/libui/darwin/entry.m deleted file mode 100644 index 219d080..0000000 --- a/src/libui_sdl/libui/darwin/entry.m +++ /dev/null @@ -1,251 +0,0 @@ -// 14 august 2015 -#import "uipriv_darwin.h" - -// Text fields for entering text have no intrinsic width; we'll use the default Interface Builder width for them. -#define textfieldWidth 96 - -@interface libui_intrinsicWidthNSTextField : NSTextField -@end - -@implementation libui_intrinsicWidthNSTextField - -- (NSSize)intrinsicContentSize -{ - NSSize s; - - s = [super intrinsicContentSize]; - s.width = textfieldWidth; - return s; -} - -@end - -// TODO does this have one on its own? -@interface libui_intrinsicWidthNSSecureTextField : NSSecureTextField -@end - -@implementation libui_intrinsicWidthNSSecureTextField - -- (NSSize)intrinsicContentSize -{ - NSSize s; - - s = [super intrinsicContentSize]; - s.width = textfieldWidth; - return s; -} - -@end - -// TODO does this have one on its own? -@interface libui_intrinsicWidthNSSearchField : NSSearchField -@end - -@implementation libui_intrinsicWidthNSSearchField - -- (NSSize)intrinsicContentSize -{ - NSSize s; - - s = [super intrinsicContentSize]; - s.width = textfieldWidth; - return s; -} - -@end - -struct uiEntry { - uiDarwinControl c; - NSTextField *textfield; - void (*onChanged)(uiEntry *, void *); - void *onChangedData; -}; - -static BOOL isSearchField(NSTextField *tf) -{ - return [tf isKindOfClass:[NSSearchField class]]; -} - -@interface entryDelegateClass : NSObject<NSTextFieldDelegate> { - struct mapTable *entries; -} -- (void)controlTextDidChange:(NSNotification *)note; -- (IBAction)onSearch:(id)sender; -- (void)registerEntry:(uiEntry *)e; -- (void)unregisterEntry:(uiEntry *)e; -@end - -@implementation entryDelegateClass - -- (id)init -{ - self = [super init]; - if (self) - self->entries = newMap(); - return self; -} - -- (void)dealloc -{ - mapDestroy(self->entries); - [super dealloc]; -} - -- (void)controlTextDidChange:(NSNotification *)note -{ - [self onSearch:[note object]]; -} - -- (IBAction)onSearch:(id)sender -{ - uiEntry *e; - - e = (uiEntry *) mapGet(self->entries, sender); - (*(e->onChanged))(e, e->onChangedData); -} - -- (void)registerEntry:(uiEntry *)e -{ - mapSet(self->entries, e->textfield, e); - if (isSearchField(e->textfield)) { - [e->textfield setTarget:self]; - [e->textfield setAction:@selector(onSearch:)]; - } else - [e->textfield setDelegate:self]; -} - -- (void)unregisterEntry:(uiEntry *)e -{ - if (isSearchField(e->textfield)) - [e->textfield setTarget:nil]; - else - [e->textfield setDelegate:nil]; - mapDelete(self->entries, e->textfield); -} - -@end - -static entryDelegateClass *entryDelegate = nil; - -uiDarwinControlAllDefaultsExceptDestroy(uiEntry, textfield) - -static void uiEntryDestroy(uiControl *c) -{ - uiEntry *e = uiEntry(c); - - [entryDelegate unregisterEntry:e]; - [e->textfield release]; - uiFreeControl(uiControl(e)); -} - -char *uiEntryText(uiEntry *e) -{ - return uiDarwinNSStringToText([e->textfield stringValue]); -} - -void uiEntrySetText(uiEntry *e, const char *text) -{ - [e->textfield setStringValue:toNSString(text)]; - // don't queue the control for resize; entry sizes are independent of their contents -} - -void uiEntryOnChanged(uiEntry *e, void (*f)(uiEntry *, void *), void *data) -{ - e->onChanged = f; - e->onChangedData = data; -} - -int uiEntryReadOnly(uiEntry *e) -{ - return [e->textfield isEditable] == NO; -} - -void uiEntrySetReadOnly(uiEntry *e, int readonly) -{ - BOOL editable; - - editable = YES; - if (readonly) - editable = NO; - [e->textfield setEditable:editable]; -} - -static void defaultOnChanged(uiEntry *e, void *data) -{ - // do nothing -} - -// these are based on interface builder defaults; my comments in the old code weren't very good so I don't really know what talked about what, sorry :/ -void finishNewTextField(NSTextField *t, BOOL isEntry) -{ - uiDarwinSetControlFont(t, NSRegularControlSize); - - // THE ORDER OF THESE CALLS IS IMPORTANT; CHANGE IT AND THE BORDERS WILL DISAPPEAR - [t setBordered:NO]; - [t setBezelStyle:NSTextFieldSquareBezel]; - [t setBezeled:isEntry]; - - // we don't need to worry about substitutions/autocorrect here; see window_darwin.m for details - - [[t cell] setLineBreakMode:NSLineBreakByClipping]; - [[t cell] setScrollable:YES]; -} - -static NSTextField *realNewEditableTextField(Class class) -{ - NSTextField *tf; - - tf = [[class alloc] initWithFrame:NSZeroRect]; - [tf setSelectable:YES]; // otherwise the setting is masked by the editable default of YES - finishNewTextField(tf, YES); - return tf; -} - -NSTextField *newEditableTextField(void) -{ - return realNewEditableTextField([libui_intrinsicWidthNSTextField class]); -} - -static uiEntry *finishNewEntry(Class class) -{ - uiEntry *e; - - uiDarwinNewControl(uiEntry, e); - - e->textfield = realNewEditableTextField(class); - - if (entryDelegate == nil) { - entryDelegate = [[entryDelegateClass new] autorelease]; - [delegates addObject:entryDelegate]; - } - [entryDelegate registerEntry:e]; - uiEntryOnChanged(e, defaultOnChanged, NULL); - - return e; -} - -uiEntry *uiNewEntry(void) -{ - return finishNewEntry([libui_intrinsicWidthNSTextField class]); -} - -uiEntry *uiNewPasswordEntry(void) -{ - return finishNewEntry([libui_intrinsicWidthNSSecureTextField class]); -} - -uiEntry *uiNewSearchEntry(void) -{ - uiEntry *e; - NSSearchField *s; - - e = finishNewEntry([libui_intrinsicWidthNSSearchField class]); - s = (NSSearchField *) (e->textfield); - // TODO these are only on 10.10 -// [s setSendsSearchStringImmediately:NO]; -// [s setSendsWholeSearchString:NO]; - [s setBordered:NO]; - [s setBezelStyle:NSTextFieldRoundedBezel]; - [s setBezeled:YES]; - return e; -} diff --git a/src/libui_sdl/libui/darwin/fontbutton.m b/src/libui_sdl/libui/darwin/fontbutton.m deleted file mode 100644 index 22bc646..0000000 --- a/src/libui_sdl/libui/darwin/fontbutton.m +++ /dev/null @@ -1,218 +0,0 @@ -// 14 april 2016 -#import "uipriv_darwin.h" - -@interface fontButton : NSButton { - uiFontButton *libui_b; - NSFont *libui_font; -} -- (id)initWithFrame:(NSRect)frame libuiFontButton:(uiFontButton *)b; -- (void)updateFontButtonLabel; -- (IBAction)fontButtonClicked:(id)sender; -- (void)activateFontButton; -- (void)deactivateFontButton:(BOOL)activatingAnother; -- (void)deactivateOnClose:(NSNotification *)note; -- (uiDrawTextFont *)libuiFont; -@end - -// only one may be active at one time -static fontButton *activeFontButton = nil; - -struct uiFontButton { - uiDarwinControl c; - fontButton *button; - void (*onChanged)(uiFontButton *, void *); - void *onChangedData; -}; - -@implementation fontButton - -- (id)initWithFrame:(NSRect)frame libuiFontButton:(uiFontButton *)b -{ - self = [super initWithFrame:frame]; - if (self) { - self->libui_b = b; - - // imitate a NSColorWell in appearance - [self setButtonType:NSPushOnPushOffButton]; - [self setBordered:YES]; - [self setBezelStyle:NSShadowlessSquareBezelStyle]; - - // default font values according to the CTFontDescriptor reference - // this is autoreleased (thanks swillits in irc.freenode.net/#macdev) - self->libui_font = [[NSFont fontWithName:@"Helvetica" size:12.0] retain]; - [self updateFontButtonLabel]; - - // for when clicked - [self setTarget:self]; - [self setAction:@selector(fontButtonClicked:)]; - } - return self; -} - -- (void)dealloc -{ - // clean up notifications - if (activeFontButton == self) - [self deactivateFontButton:NO]; - [self->libui_font release]; - [super dealloc]; -} - -- (void)updateFontButtonLabel -{ - NSString *title; - - title = [NSString stringWithFormat:@"%@ %g", - [self->libui_font displayName], - [self->libui_font pointSize]]; - [self setTitle:title]; -} - -- (IBAction)fontButtonClicked:(id)sender -{ - if ([self state] == NSOnState) - [self activateFontButton]; - else - [self deactivateFontButton:NO]; -} - -- (void)activateFontButton -{ - NSFontManager *sfm; - - sfm = [NSFontManager sharedFontManager]; - if (activeFontButton != nil) - [activeFontButton deactivateFontButton:YES]; - [sfm setTarget:self]; - [sfm setSelectedFont:self->libui_font isMultiple:NO]; - [sfm orderFrontFontPanel:self]; - activeFontButton = self; - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(deactivateOnClose:) - name:NSWindowWillCloseNotification - object:[NSFontPanel sharedFontPanel]]; - [self setState:NSOnState]; -} - -- (void)deactivateFontButton:(BOOL)activatingAnother -{ - NSFontManager *sfm; - - sfm = [NSFontManager sharedFontManager]; - [sfm setTarget:nil]; - if (!activatingAnother) - [[NSFontPanel sharedFontPanel] orderOut:self]; - activeFontButton = nil; - [[NSNotificationCenter defaultCenter] removeObserver:self - name:NSWindowWillCloseNotification - object:[NSFontPanel sharedFontPanel]]; - [self setState:NSOffState]; -} - -- (void)deactivateOnClose:(NSNotification *)note -{ - [self deactivateFontButton:NO]; -} - -- (void)changeFont:(id)sender -{ - NSFontManager *fm; - NSFont *old; - uiFontButton *b = self->libui_b; - - fm = (NSFontManager *) sender; - old = self->libui_font; - self->libui_font = [sender convertFont:self->libui_font]; - // do this even if it returns the same; we don't own anything that isn't from a new or alloc/init - [self->libui_font retain]; - // do this second just in case - [old release]; - [self updateFontButtonLabel]; - (*(b->onChanged))(b, b->onChangedData); -} - -- (NSUInteger)validModesForFontPanel:(NSFontPanel *)panel -{ - return NSFontPanelFaceModeMask | - NSFontPanelSizeModeMask | - NSFontPanelCollectionModeMask; -} - -- (uiDrawTextFont *)libuiFont -{ - return mkTextFontFromNSFont(self->libui_font); -} - -@end - -uiDarwinControlAllDefaults(uiFontButton, button) - -// we do not want font change events to be sent to any controls other than the font buttons -// see main.m for more details -BOOL fontButtonInhibitSendAction(SEL sel, id from, id to) -{ - if (sel != @selector(changeFont:)) - return NO; - return ![to isKindOfClass:[fontButton class]]; -} - -// we do not want NSFontPanelValidation messages to be sent to any controls other than the font buttons when a font button is active -// see main.m for more details -BOOL fontButtonOverrideTargetForAction(SEL sel, id from, id to, id *override) -{ - if (activeFontButton == nil) - return NO; - if (sel != @selector(validModesForFontPanel:)) - return NO; - *override = activeFontButton; - return YES; -} - -// we also don't want the panel to be usable when there's a dialog running; see stddialogs.m for more details on that -// unfortunately the panel seems to ignore -setWorksWhenModal: so we'll have to do things ourselves -@interface nonModalFontPanel : NSFontPanel -@end - -@implementation nonModalFontPanel - -- (BOOL)worksWhenModal -{ - return NO; -} - -@end - -void setupFontPanel(void) -{ - [NSFontManager setFontPanelFactory:[nonModalFontPanel class]]; -} - -static void defaultOnChanged(uiFontButton *b, void *data) -{ - // do nothing -} - -uiDrawTextFont *uiFontButtonFont(uiFontButton *b) -{ - return [b->button libuiFont]; -} - -void uiFontButtonOnChanged(uiFontButton *b, void (*f)(uiFontButton *, void *), void *data) -{ - b->onChanged = f; - b->onChangedData = data; -} - -uiFontButton *uiNewFontButton(void) -{ - uiFontButton *b; - - uiDarwinNewControl(uiFontButton, b); - - b->button = [[fontButton alloc] initWithFrame:NSZeroRect libuiFontButton:b]; - uiDarwinSetControlFont(b->button, NSRegularControlSize); - - uiFontButtonOnChanged(b, defaultOnChanged, NULL); - - return b; -} diff --git a/src/libui_sdl/libui/darwin/form.m b/src/libui_sdl/libui/darwin/form.m deleted file mode 100644 index 7cdb965..0000000 --- a/src/libui_sdl/libui/darwin/form.m +++ /dev/null @@ -1,561 +0,0 @@ -// 7 june 2016 -#import "uipriv_darwin.h" - -// TODO in the test program, sometimes one of the radio buttons can disappear (try when spaced) - -@interface formChild : NSView -@property uiControl *c; -@property (strong) NSTextField *label; -@property BOOL stretchy; -@property NSLayoutPriority oldHorzHuggingPri; -@property NSLayoutPriority oldVertHuggingPri; -@property (strong) NSLayoutConstraint *baseline; -@property (strong) NSLayoutConstraint *leading; -@property (strong) NSLayoutConstraint *top; -@property (strong) NSLayoutConstraint *trailing; -@property (strong) NSLayoutConstraint *bottom; -- (id)initWithLabel:(NSTextField *)l; -- (void)onDestroy; -- (NSView *)view; -@end - -@interface formView : NSView { - uiForm *f; - NSMutableArray *children; - int padded; - - NSLayoutConstraint *first; - NSMutableArray *inBetweens; - NSLayoutConstraint *last; - NSMutableArray *widths; - NSMutableArray *leadings; - NSMutableArray *middles; - NSMutableArray *trailings; -} -- (id)initWithF:(uiForm *)ff; -- (void)onDestroy; -- (void)removeOurConstraints; -- (void)syncEnableStates:(int)enabled; -- (CGFloat)paddingAmount; -- (void)establishOurConstraints; -- (void)append:(NSString *)label c:(uiControl *)c stretchy:(int)stretchy; -- (void)delete:(int)n; -- (int)isPadded; -- (void)setPadded:(int)p; -- (BOOL)hugsTrailing; -- (BOOL)hugsBottom; -- (int)nStretchy; -@end - -struct uiForm { - uiDarwinControl c; - formView *view; -}; - -@implementation formChild - -- (id)initWithLabel:(NSTextField *)l -{ - self = [super initWithFrame:NSZeroRect]; - if (self) { - self.label = l; - [self.label setTranslatesAutoresizingMaskIntoConstraints:NO]; - [self.label setContentHuggingPriority:NSLayoutPriorityRequired forOrientation:NSLayoutConstraintOrientationHorizontal]; - [self.label setContentHuggingPriority:NSLayoutPriorityRequired forOrientation:NSLayoutConstraintOrientationVertical]; - [self.label setContentCompressionResistancePriority:NSLayoutPriorityRequired forOrientation:NSLayoutConstraintOrientationHorizontal]; - [self.label setContentCompressionResistancePriority:NSLayoutPriorityRequired forOrientation:NSLayoutConstraintOrientationVertical]; - [self addSubview:self.label]; - - self.leading = mkConstraint(self.label, NSLayoutAttributeLeading, - NSLayoutRelationGreaterThanOrEqual, - self, NSLayoutAttributeLeading, - 1, 0, - @"uiForm label leading"); - [self addConstraint:self.leading]; - self.top = mkConstraint(self.label, NSLayoutAttributeTop, - NSLayoutRelationEqual, - self, NSLayoutAttributeTop, - 1, 0, - @"uiForm label top"); - [self addConstraint:self.top]; - self.trailing = mkConstraint(self.label, NSLayoutAttributeTrailing, - NSLayoutRelationEqual, - self, NSLayoutAttributeTrailing, - 1, 0, - @"uiForm label trailing"); - [self addConstraint:self.trailing]; - self.bottom = mkConstraint(self.label, NSLayoutAttributeBottom, - NSLayoutRelationEqual, - self, NSLayoutAttributeBottom, - 1, 0, - @"uiForm label bottom"); - [self addConstraint:self.bottom]; - } - return self; -} - -- (void)onDestroy -{ - [self removeConstraint:self.trailing]; - self.trailing = nil; - [self removeConstraint:self.top]; - self.top = nil; - [self removeConstraint:self.bottom]; - self.bottom = nil; - - [self.label removeFromSuperview]; - self.label = nil; -} - -- (NSView *)view -{ - return (NSView *) uiControlHandle(self.c); -} - -@end - -@implementation formView - -- (id)initWithF:(uiForm *)ff -{ - self = [super initWithFrame:NSZeroRect]; - if (self != nil) { - self->f = ff; - self->padded = 0; - self->children = [NSMutableArray new]; - - self->inBetweens = [NSMutableArray new]; - self->widths = [NSMutableArray new]; - self->leadings = [NSMutableArray new]; - self->middles = [NSMutableArray new]; - self->trailings = [NSMutableArray new]; - } - return self; -} - -- (void)onDestroy -{ - formChild *fc; - - [self removeOurConstraints]; - [self->inBetweens release]; - [self->widths release]; - [self->leadings release]; - [self->middles release]; - [self->trailings release]; - - for (fc in self->children) { - [self removeConstraint:fc.baseline]; - fc.baseline = nil; - uiControlSetParent(fc.c, NULL); - uiDarwinControlSetSuperview(uiDarwinControl(fc.c), nil); - uiControlDestroy(fc.c); - [fc onDestroy]; - [fc removeFromSuperview]; - } - [self->children release]; -} - -- (void)removeOurConstraints -{ - if (self->first != nil) { - [self removeConstraint:self->first]; - [self->first release]; - self->first = nil; - } - if ([self->inBetweens count] != 0) { - [self removeConstraints:self->inBetweens]; - [self->inBetweens removeAllObjects]; - } - if (self->last != nil) { - [self removeConstraint:self->last]; - [self->last release]; - self->last = nil; - } - if ([self->widths count] != 0) { - [self removeConstraints:self->widths]; - [self->widths removeAllObjects]; - } - if ([self->leadings count] != 0) { - [self removeConstraints:self->leadings]; - [self->leadings removeAllObjects]; - } - if ([self->middles count] != 0) { - [self removeConstraints:self->middles]; - [self->middles removeAllObjects]; - } - if ([self->trailings count] != 0) { - [self removeConstraints:self->trailings]; - [self->trailings removeAllObjects]; - } -} - -- (void)syncEnableStates:(int)enabled -{ - formChild *fc; - - for (fc in self->children) - uiDarwinControlSyncEnableState(uiDarwinControl(fc.c), enabled); -} - -- (CGFloat)paddingAmount -{ - if (!self->padded) - return 0.0; - return uiDarwinPaddingAmount(NULL); -} - -- (void)establishOurConstraints -{ - formChild *fc; - CGFloat padding; - NSView *prev, *prevlabel; - NSLayoutConstraint *c; - - [self removeOurConstraints]; - if ([self->children count] == 0) - return; - padding = [self paddingAmount]; - - // first arrange the children vertically and make them the same width - prev = nil; - for (fc in self->children) { - [fc setHidden:!uiControlVisible(fc.c)]; - if (!uiControlVisible(fc.c)) - continue; - if (prev == nil) { // first view - self->first = mkConstraint(self, NSLayoutAttributeTop, - NSLayoutRelationEqual, - [fc view], NSLayoutAttributeTop, - 1, 0, - @"uiForm first vertical constraint"); - [self addConstraint:self->first]; - [self->first retain]; - prev = [fc view]; - prevlabel = fc; - continue; - } - // not the first; link it - c = mkConstraint(prev, NSLayoutAttributeBottom, - NSLayoutRelationEqual, - [fc view], NSLayoutAttributeTop, - 1, -padding, - @"uiForm in-between vertical constraint"); - [self addConstraint:c]; - [self->inBetweens addObject:c]; - // and make the same width - c = mkConstraint(prev, NSLayoutAttributeWidth, - NSLayoutRelationEqual, - [fc view], NSLayoutAttributeWidth, - 1, 0, - @"uiForm control width constraint"); - [self addConstraint:c]; - [self->widths addObject:c]; - c = mkConstraint(prevlabel, NSLayoutAttributeWidth, - NSLayoutRelationEqual, - fc, NSLayoutAttributeWidth, - 1, 0, - @"uiForm label lwidth constraint"); - [self addConstraint:c]; - [self->widths addObject:c]; - prev = [fc view]; - prevlabel = fc; - } - if (prev == nil) // all hidden; act as if nothing there - return; - self->last = mkConstraint(prev, NSLayoutAttributeBottom, - NSLayoutRelationEqual, - self, NSLayoutAttributeBottom, - 1, 0, - @"uiForm last vertical constraint"); - [self addConstraint:self->last]; - [self->last retain]; - - // now arrange the controls horizontally - for (fc in self->children) { - if (!uiControlVisible(fc.c)) - continue; - c = mkConstraint(self, NSLayoutAttributeLeading, - NSLayoutRelationEqual, - fc, NSLayoutAttributeLeading, - 1, 0, - @"uiForm leading constraint"); - [self addConstraint:c]; - [self->leadings addObject:c]; - // coerce the control to be as wide as possible - // see http://stackoverflow.com/questions/37710892/in-auto-layout-i-set-up-labels-that-shouldnt-grow-horizontally-and-controls-th - c = mkConstraint(self, NSLayoutAttributeLeading, - NSLayoutRelationEqual, - [fc view], NSLayoutAttributeLeading, - 1, 0, - @"uiForm leading constraint"); - [c setPriority:NSLayoutPriorityDefaultHigh]; - [self addConstraint:c]; - [self->leadings addObject:c]; - c = mkConstraint(fc, NSLayoutAttributeTrailing, - NSLayoutRelationEqual, - [fc view], NSLayoutAttributeLeading, - 1, -padding, - @"uiForm middle constraint"); - [self addConstraint:c]; - [self->middles addObject:c]; - c = mkConstraint([fc view], NSLayoutAttributeTrailing, - NSLayoutRelationEqual, - self, NSLayoutAttributeTrailing, - 1, 0, - @"uiForm trailing constraint"); - [self addConstraint:c]; - [self->trailings addObject:c]; - // TODO - c = mkConstraint(fc, NSLayoutAttributeBottom, - NSLayoutRelationLessThanOrEqual, - self, NSLayoutAttributeBottom, - 1, 0, - @"TODO"); - [self addConstraint:c]; - [self->trailings addObject:c]; - } - - // and make all stretchy controls have the same height - prev = nil; - for (fc in self->children) { - if (!uiControlVisible(fc.c)) - continue; - if (!fc.stretchy) - continue; - if (prev == nil) { - prev = [fc view]; - continue; - } - c = mkConstraint([fc view], NSLayoutAttributeHeight, - NSLayoutRelationEqual, - prev, NSLayoutAttributeHeight, - 1, 0, - @"uiForm stretchy constraint"); - [self addConstraint:c]; - // TODO make a dedicated array for this - [self->leadings addObject:c]; - } - - // we don't arrange the labels vertically; that's done when we add the control since those constraints don't need to change (they just need to be at their baseline) -} - -- (void)append:(NSString *)label c:(uiControl *)c stretchy:(int)stretchy -{ - formChild *fc; - NSLayoutPriority priority; - NSLayoutAttribute attribute; - int oldnStretchy; - - fc = [[formChild alloc] initWithLabel:newLabel(label)]; - fc.c = c; - fc.stretchy = stretchy; - fc.oldHorzHuggingPri = uiDarwinControlHuggingPriority(uiDarwinControl(fc.c), NSLayoutConstraintOrientationHorizontal); - fc.oldVertHuggingPri = uiDarwinControlHuggingPriority(uiDarwinControl(fc.c), NSLayoutConstraintOrientationVertical); - [fc setTranslatesAutoresizingMaskIntoConstraints:NO]; - [self addSubview:fc]; - - uiControlSetParent(fc.c, uiControl(self->f)); - uiDarwinControlSetSuperview(uiDarwinControl(fc.c), self); - uiDarwinControlSyncEnableState(uiDarwinControl(fc.c), uiControlEnabledToUser(uiControl(self->f))); - - // if a control is stretchy, it should not hug vertically - // otherwise, it should *forcibly* hug - if (fc.stretchy) - priority = NSLayoutPriorityDefaultLow; - else - // LONGTERM will default high work? - priority = NSLayoutPriorityRequired; - uiDarwinControlSetHuggingPriority(uiDarwinControl(fc.c), priority, NSLayoutConstraintOrientationVertical); - // make sure controls don't hug their horizontal direction so they fill the width of the view - uiDarwinControlSetHuggingPriority(uiDarwinControl(fc.c), NSLayoutPriorityDefaultLow, NSLayoutConstraintOrientationHorizontal); - - // and constrain the baselines to position the label vertically - // if the view is a scroll view, align tops, not baselines - // this is what Interface Builder does - attribute = NSLayoutAttributeBaseline; - if ([[fc view] isKindOfClass:[NSScrollView class]]) - attribute = NSLayoutAttributeTop; - fc.baseline = mkConstraint(fc.label, attribute, - NSLayoutRelationEqual, - [fc view], attribute, - 1, 0, - @"uiForm baseline constraint"); - [self addConstraint:fc.baseline]; - - oldnStretchy = [self nStretchy]; - [self->children addObject:fc]; - - [self establishOurConstraints]; - if (fc.stretchy) - if (oldnStretchy == 0) - uiDarwinNotifyEdgeHuggingChanged(uiDarwinControl(self->f)); - - [fc release]; // we don't need the initial reference now -} - -- (void)delete:(int)n -{ - formChild *fc; - int stretchy; - - fc = (formChild *) [self->children objectAtIndex:n]; - stretchy = fc.stretchy; - - uiControlSetParent(fc.c, NULL); - uiDarwinControlSetSuperview(uiDarwinControl(fc.c), nil); - - uiDarwinControlSetHuggingPriority(uiDarwinControl(fc.c), fc.oldHorzHuggingPri, NSLayoutConstraintOrientationHorizontal); - uiDarwinControlSetHuggingPriority(uiDarwinControl(fc.c), fc.oldVertHuggingPri, NSLayoutConstraintOrientationVertical); - - [fc onDestroy]; - [self->children removeObjectAtIndex:n]; - - [self establishOurConstraints]; - if (stretchy) - if ([self nStretchy] == 0) - uiDarwinNotifyEdgeHuggingChanged(uiDarwinControl(self->f)); -} - -- (int)isPadded -{ - return self->padded; -} - -- (void)setPadded:(int)p -{ - CGFloat padding; - NSLayoutConstraint *c; - - self->padded = p; - padding = [self paddingAmount]; - for (c in self->inBetweens) - [c setConstant:-padding]; - for (c in self->middles) - [c setConstant:-padding]; -} - -- (BOOL)hugsTrailing -{ - return YES; // always hug trailing -} - -- (BOOL)hugsBottom -{ - // only hug if we have stretchy - return [self nStretchy] != 0; -} - -- (int)nStretchy -{ - formChild *fc; - int n; - - n = 0; - for (fc in self->children) { - if (!uiControlVisible(fc.c)) - continue; - if (fc.stretchy) - n++; - } - return n; -} - -@end - -static void uiFormDestroy(uiControl *c) -{ - uiForm *f = uiForm(c); - - [f->view onDestroy]; - [f->view release]; - uiFreeControl(uiControl(f)); -} - -uiDarwinControlDefaultHandle(uiForm, view) -uiDarwinControlDefaultParent(uiForm, view) -uiDarwinControlDefaultSetParent(uiForm, view) -uiDarwinControlDefaultToplevel(uiForm, view) -uiDarwinControlDefaultVisible(uiForm, view) -uiDarwinControlDefaultShow(uiForm, view) -uiDarwinControlDefaultHide(uiForm, view) -uiDarwinControlDefaultEnabled(uiForm, view) -uiDarwinControlDefaultEnable(uiForm, view) -uiDarwinControlDefaultDisable(uiForm, view) - -static void uiFormSyncEnableState(uiDarwinControl *c, int enabled) -{ - uiForm *f = uiForm(c); - - if (uiDarwinShouldStopSyncEnableState(uiDarwinControl(f), enabled)) - return; - [f->view syncEnableStates:enabled]; -} - -uiDarwinControlDefaultSetSuperview(uiForm, view) - -static BOOL uiFormHugsTrailingEdge(uiDarwinControl *c) -{ - uiForm *f = uiForm(c); - - return [f->view hugsTrailing]; -} - -static BOOL uiFormHugsBottom(uiDarwinControl *c) -{ - uiForm *f = uiForm(c); - - return [f->view hugsBottom]; -} - -static void uiFormChildEdgeHuggingChanged(uiDarwinControl *c) -{ - uiForm *f = uiForm(c); - - [f->view establishOurConstraints]; -} - -uiDarwinControlDefaultHuggingPriority(uiForm, view) -uiDarwinControlDefaultSetHuggingPriority(uiForm, view) - -static void uiFormChildVisibilityChanged(uiDarwinControl *c) -{ - uiForm *f = uiForm(c); - - [f->view establishOurConstraints]; -} - -void uiFormAppend(uiForm *f, const char *label, uiControl *c, int stretchy) -{ - // LONGTERM on other platforms - // or at leat allow this and implicitly turn it into a spacer - if (c == NULL) - userbug("You cannot add NULL to a uiForm."); - [f->view append:toNSString(label) c:c stretchy:stretchy]; -} - -void uiFormDelete(uiForm *f, int n) -{ - [f->view delete:n]; -} - -int uiFormPadded(uiForm *f) -{ - return [f->view isPadded]; -} - -void uiFormSetPadded(uiForm *f, int padded) -{ - [f->view setPadded:padded]; -} - -uiForm *uiNewForm(void) -{ - uiForm *f; - - uiDarwinNewControl(uiForm, f); - - f->view = [[formView alloc] initWithF:f]; - - return f; -} diff --git a/src/libui_sdl/libui/darwin/grid.m b/src/libui_sdl/libui/darwin/grid.m deleted file mode 100644 index d5c5fb1..0000000 --- a/src/libui_sdl/libui/darwin/grid.m +++ /dev/null @@ -1,800 +0,0 @@ -// 11 june 2016 -#import "uipriv_darwin.h" - -// TODO the assorted test doesn't work right at all - -@interface gridChild : NSView -@property uiControl *c; -@property int left; -@property int top; -@property int xspan; -@property int yspan; -@property int hexpand; -@property uiAlign halign; -@property int vexpand; -@property uiAlign valign; - -@property (strong) NSLayoutConstraint *leadingc; -@property (strong) NSLayoutConstraint *topc; -@property (strong) NSLayoutConstraint *trailingc; -@property (strong) NSLayoutConstraint *bottomc; -@property (strong) NSLayoutConstraint *xcenterc; -@property (strong) NSLayoutConstraint *ycenterc; - -@property NSLayoutPriority oldHorzHuggingPri; -@property NSLayoutPriority oldVertHuggingPri; -- (void)setC:(uiControl *)c grid:(uiGrid *)g; -- (void)onDestroy; -- (NSView *)view; -@end - -@interface gridView : NSView { - uiGrid *g; - NSMutableArray *children; - int padded; - - NSMutableArray *edges; - NSMutableArray *inBetweens; - - NSMutableArray *emptyCellViews; -} -- (id)initWithG:(uiGrid *)gg; -- (void)onDestroy; -- (void)removeOurConstraints; -- (void)syncEnableStates:(int)enabled; -- (CGFloat)paddingAmount; -- (void)establishOurConstraints; -- (void)append:(gridChild *)gc; -- (void)insert:(gridChild *)gc after:(uiControl *)c at:(uiAt)at; -- (int)isPadded; -- (void)setPadded:(int)p; -- (BOOL)hugsTrailing; -- (BOOL)hugsBottom; -- (int)nhexpand; -- (int)nvexpand; -@end - -struct uiGrid { - uiDarwinControl c; - gridView *view; -}; - -@implementation gridChild - -- (void)setC:(uiControl *)c grid:(uiGrid *)g -{ - self.c = c; - self.oldHorzHuggingPri = uiDarwinControlHuggingPriority(uiDarwinControl(self.c), NSLayoutConstraintOrientationHorizontal); - self.oldVertHuggingPri = uiDarwinControlHuggingPriority(uiDarwinControl(self.c), NSLayoutConstraintOrientationVertical); - - uiControlSetParent(self.c, uiControl(g)); - uiDarwinControlSetSuperview(uiDarwinControl(self.c), self); - uiDarwinControlSyncEnableState(uiDarwinControl(self.c), uiControlEnabledToUser(uiControl(g))); - - if (self.halign == uiAlignStart || self.halign == uiAlignFill) { - self.leadingc = mkConstraint(self, NSLayoutAttributeLeading, - NSLayoutRelationEqual, - [self view], NSLayoutAttributeLeading, - 1, 0, - @"uiGrid child horizontal alignment start constraint"); - [self addConstraint:self.leadingc]; - } - if (self.halign == uiAlignCenter) { - self.xcenterc = mkConstraint(self, NSLayoutAttributeCenterX, - NSLayoutRelationEqual, - [self view], NSLayoutAttributeCenterX, - 1, 0, - @"uiGrid child horizontal alignment center constraint"); - [self addConstraint:self.xcenterc]; - } - if (self.halign == uiAlignEnd || self.halign == uiAlignFill) { - self.trailingc = mkConstraint(self, NSLayoutAttributeTrailing, - NSLayoutRelationEqual, - [self view], NSLayoutAttributeTrailing, - 1, 0, - @"uiGrid child horizontal alignment end constraint"); - [self addConstraint:self.trailingc]; - } - - if (self.valign == uiAlignStart || self.valign == uiAlignFill) { - self.topc = mkConstraint(self, NSLayoutAttributeTop, - NSLayoutRelationEqual, - [self view], NSLayoutAttributeTop, - 1, 0, - @"uiGrid child vertical alignment start constraint"); - [self addConstraint:self.topc]; - } - if (self.valign == uiAlignCenter) { - self.ycenterc = mkConstraint(self, NSLayoutAttributeCenterY, - NSLayoutRelationEqual, - [self view], NSLayoutAttributeCenterY, - 1, 0, - @"uiGrid child vertical alignment center constraint"); - [self addConstraint:self.ycenterc]; - } - if (self.valign == uiAlignEnd || self.valign == uiAlignFill) { - self.bottomc = mkConstraint(self, NSLayoutAttributeBottom, - NSLayoutRelationEqual, - [self view], NSLayoutAttributeBottom, - 1, 0, - @"uiGrid child vertical alignment end constraint"); - [self addConstraint:self.bottomc]; - } -} - -- (void)onDestroy -{ - if (self.leadingc != nil) { - [self removeConstraint:self.leadingc]; - self.leadingc = nil; - } - if (self.topc != nil) { - [self removeConstraint:self.topc]; - self.topc = nil; - } - if (self.trailingc != nil) { - [self removeConstraint:self.trailingc]; - self.trailingc = nil; - } - if (self.bottomc != nil) { - [self removeConstraint:self.bottomc]; - self.bottomc = nil; - } - if (self.xcenterc != nil) { - [self removeConstraint:self.xcenterc]; - self.xcenterc = nil; - } - if (self.ycenterc != nil) { - [self removeConstraint:self.ycenterc]; - self.ycenterc = nil; - } - - uiControlSetParent(self.c, NULL); - uiDarwinControlSetSuperview(uiDarwinControl(self.c), nil); - uiDarwinControlSetHuggingPriority(uiDarwinControl(self.c), self.oldHorzHuggingPri, NSLayoutConstraintOrientationHorizontal); - uiDarwinControlSetHuggingPriority(uiDarwinControl(self.c), self.oldVertHuggingPri, NSLayoutConstraintOrientationVertical); -} - -- (NSView *)view -{ - return (NSView *) uiControlHandle(self.c); -} - -@end - -@implementation gridView - -- (id)initWithG:(uiGrid *)gg -{ - self = [super initWithFrame:NSZeroRect]; - if (self != nil) { - self->g = gg; - self->padded = 0; - self->children = [NSMutableArray new]; - - self->edges = [NSMutableArray new]; - self->inBetweens = [NSMutableArray new]; - - self->emptyCellViews = [NSMutableArray new]; - } - return self; -} - -- (void)onDestroy -{ - gridChild *gc; - - [self removeOurConstraints]; - [self->edges release]; - [self->inBetweens release]; - - [self->emptyCellViews release]; - - for (gc in self->children) { - [gc onDestroy]; - uiControlDestroy(gc.c); - [gc removeFromSuperview]; - } - [self->children release]; -} - -- (void)removeOurConstraints -{ - NSView *v; - - if ([self->edges count] != 0) { - [self removeConstraints:self->edges]; - [self->edges removeAllObjects]; - } - if ([self->inBetweens count] != 0) { - [self removeConstraints:self->inBetweens]; - [self->inBetweens removeAllObjects]; - } - - for (v in self->emptyCellViews) - [v removeFromSuperview]; - [self->emptyCellViews removeAllObjects]; -} - -- (void)syncEnableStates:(int)enabled -{ - gridChild *gc; - - for (gc in self->children) - uiDarwinControlSyncEnableState(uiDarwinControl(gc.c), enabled); -} - -- (CGFloat)paddingAmount -{ - if (!self->padded) - return 0.0; - return uiDarwinPaddingAmount(NULL); -} - -// LONGTERM stop early if all controls are hidden -- (void)establishOurConstraints -{ - gridChild *gc; - CGFloat padding; - int xmin, ymin; - int xmax, ymax; - int xcount, ycount; - BOOL first; - int **gg; - NSView ***gv; - BOOL **gspan; - int x, y; - int i; - NSLayoutConstraint *c; - int firstx, firsty; - BOOL *hexpand, *vexpand; - BOOL doit; - BOOL onlyEmptyAndSpanning; - - [self removeOurConstraints]; - if ([self->children count] == 0) - return; - padding = [self paddingAmount]; - - // first, figure out the minimum and maximum row and column numbers - // ignore hidden controls - first = YES; - for (gc in self->children) { - // this bit is important: it ensures row ymin and column xmin have at least one cell to draw, so the onlyEmptyAndSpanning logic below will never run on those rows - if (!uiControlVisible(gc.c)) - continue; - if (first) { - xmin = gc.left; - ymin = gc.top; - xmax = gc.left + gc.xspan; - ymax = gc.top + gc.yspan; - first = NO; - continue; - } - if (xmin > gc.left) - xmin = gc.left; - if (ymin > gc.top) - ymin = gc.top; - if (xmax < (gc.left + gc.xspan)) - xmax = gc.left + gc.xspan; - if (ymax < (gc.top + gc.yspan)) - ymax = gc.top + gc.yspan; - } - if (first != NO) // the entire grid is hidden; do nothing - return; - xcount = xmax - xmin; - ycount = ymax - ymin; - - // now build a topological map of the grid gg[y][x] - // also figure out which cells contain spanned views so they can be ignored later - // treat hidden controls by keeping the indices -1 - gg = (int **) uiAlloc(ycount * sizeof (int *), "int[][]"); - gspan = (BOOL **) uiAlloc(ycount * sizeof (BOOL *), "BOOL[][]"); - for (y = 0; y < ycount; y++) { - gg[y] = (int *) uiAlloc(xcount * sizeof (int), "int[]"); - gspan[y] = (BOOL *) uiAlloc(xcount * sizeof (BOOL), "BOOL[]"); - for (x = 0; x < xcount; x++) - gg[y][x] = -1; // empty - } - for (i = 0; i < [self->children count]; i++) { - gc = (gridChild *) [self->children objectAtIndex:i]; - if (!uiControlVisible(gc.c)) - continue; - for (y = gc.top; y < gc.top + gc.yspan; y++) - for (x = gc.left; x < gc.left + gc.xspan; x++) { - gg[y - ymin][x - xmin] = i; - if (x != gc.left || y != gc.top) - gspan[y - ymin][x - xmin] = YES; - } - } - - // if a row or column only contains emptys and spanning cells of a opposite-direction spannings, remove it by duplicating the previous row or column - for (y = 0; y < ycount; y++) { - onlyEmptyAndSpanning = YES; - for (x = 0; x < xcount; x++) - if (gg[y][x] != -1) { - gc = (gridChild *) [self->children objectAtIndex:gg[y][x]]; - if (gc.yspan == 1 || gc.top - ymin == y) { - onlyEmptyAndSpanning = NO; - break; - } - } - if (onlyEmptyAndSpanning) - for (x = 0; x < xcount; x++) { - gg[y][x] = gg[y - 1][x]; - gspan[y][x] = YES; - } - } - for (x = 0; x < xcount; x++) { - onlyEmptyAndSpanning = YES; - for (y = 0; y < ycount; y++) - if (gg[y][x] != -1) { - gc = (gridChild *) [self->children objectAtIndex:gg[y][x]]; - if (gc.xspan == 1 || gc.left - xmin == x) { - onlyEmptyAndSpanning = NO; - break; - } - } - if (onlyEmptyAndSpanning) - for (y = 0; y < ycount; y++) { - gg[y][x] = gg[y][x - 1]; - gspan[y][x] = YES; - } - } - - // now build a topological map of the grid's views gv[y][x] - // for any empty cell, create a dummy view - gv = (NSView ***) uiAlloc(ycount * sizeof (NSView **), "NSView *[][]"); - for (y = 0; y < ycount; y++) { - gv[y] = (NSView **) uiAlloc(xcount * sizeof (NSView *), "NSView *[]"); - for (x = 0; x < xcount; x++) - if (gg[y][x] == -1) { - gv[y][x] = [[NSView alloc] initWithFrame:NSZeroRect]; - [gv[y][x] setTranslatesAutoresizingMaskIntoConstraints:NO]; - [self addSubview:gv[y][x]]; - [self->emptyCellViews addObject:gv[y][x]]; - } else { - gc = (gridChild *) [self->children objectAtIndex:gg[y][x]]; - gv[y][x] = gc; - } - } - - // now figure out which rows and columns really expand - hexpand = (BOOL *) uiAlloc(xcount * sizeof (BOOL), "BOOL[]"); - vexpand = (BOOL *) uiAlloc(ycount * sizeof (BOOL), "BOOL[]"); - // first, which don't span - for (gc in self->children) { - if (!uiControlVisible(gc.c)) - continue; - if (gc.hexpand && gc.xspan == 1) - hexpand[gc.left - xmin] = YES; - if (gc.vexpand && gc.yspan == 1) - vexpand[gc.top - ymin] = YES; - } - // second, which do span - // the way we handle this is simple: if none of the spanned rows/columns expand, make all rows/columns expand - for (gc in self->children) { - if (!uiControlVisible(gc.c)) - continue; - if (gc.hexpand && gc.xspan != 1) { - doit = YES; - for (x = gc.left; x < gc.left + gc.xspan; x++) - if (hexpand[x - xmin]) { - doit = NO; - break; - } - if (doit) - for (x = gc.left; x < gc.left + gc.xspan; x++) - hexpand[x - xmin] = YES; - } - if (gc.vexpand && gc.yspan != 1) { - doit = YES; - for (y = gc.top; y < gc.top + gc.yspan; y++) - if (vexpand[y - ymin]) { - doit = NO; - break; - } - if (doit) - for (y = gc.top; y < gc.top + gc.yspan; y++) - vexpand[y - ymin] = YES; - } - } - - // now establish all the edge constraints - // leading and trailing edges - for (y = 0; y < ycount; y++) { - c = mkConstraint(self, NSLayoutAttributeLeading, - NSLayoutRelationEqual, - gv[y][0], NSLayoutAttributeLeading, - 1, 0, - @"uiGrid leading edge constraint"); - [self addConstraint:c]; - [self->edges addObject:c]; - c = mkConstraint(self, NSLayoutAttributeTrailing, - NSLayoutRelationEqual, - gv[y][xcount - 1], NSLayoutAttributeTrailing, - 1, 0, - @"uiGrid trailing edge constraint"); - [self addConstraint:c]; - [self->edges addObject:c]; - } - // top and bottom edges - for (x = 0; x < xcount; x++) { - c = mkConstraint(self, NSLayoutAttributeTop, - NSLayoutRelationEqual, - gv[0][x], NSLayoutAttributeTop, - 1, 0, - @"uiGrid top edge constraint"); - [self addConstraint:c]; - [self->edges addObject:c]; - c = mkConstraint(self, NSLayoutAttributeBottom, - NSLayoutRelationEqual, - gv[ycount - 1][x], NSLayoutAttributeBottom, - 1, 0, - @"uiGrid bottom edge constraint"); - [self addConstraint:c]; - [self->edges addObject:c]; - } - - // now align leading and top edges - // do NOT align spanning cells! - for (x = 0; x < xcount; x++) { - for (y = 0; y < ycount; y++) - if (!gspan[y][x]) - break; - firsty = y; - for (y++; y < ycount; y++) { - if (gspan[y][x]) - continue; - c = mkConstraint(gv[firsty][x], NSLayoutAttributeLeading, - NSLayoutRelationEqual, - gv[y][x], NSLayoutAttributeLeading, - 1, 0, - @"uiGrid column leading constraint"); - [self addConstraint:c]; - [self->edges addObject:c]; - } - } - for (y = 0; y < ycount; y++) { - for (x = 0; x < xcount; x++) - if (!gspan[y][x]) - break; - firstx = x; - for (x++; x < xcount; x++) { - if (gspan[y][x]) - continue; - c = mkConstraint(gv[y][firstx], NSLayoutAttributeTop, - NSLayoutRelationEqual, - gv[y][x], NSLayoutAttributeTop, - 1, 0, - @"uiGrid row top constraint"); - [self addConstraint:c]; - [self->edges addObject:c]; - } - } - - // now string adjacent views together - for (y = 0; y < ycount; y++) - for (x = 1; x < xcount; x++) - if (gv[y][x - 1] != gv[y][x]) { - c = mkConstraint(gv[y][x - 1], NSLayoutAttributeTrailing, - NSLayoutRelationEqual, - gv[y][x], NSLayoutAttributeLeading, - 1, -padding, - @"uiGrid internal horizontal constraint"); - [self addConstraint:c]; - [self->inBetweens addObject:c]; - } - for (x = 0; x < xcount; x++) - for (y = 1; y < ycount; y++) - if (gv[y - 1][x] != gv[y][x]) { - c = mkConstraint(gv[y - 1][x], NSLayoutAttributeBottom, - NSLayoutRelationEqual, - gv[y][x], NSLayoutAttributeTop, - 1, -padding, - @"uiGrid internal vertical constraint"); - [self addConstraint:c]; - [self->inBetweens addObject:c]; - } - - // now set priorities for all widgets that expand or not - // if a cell is in an expanding row, OR If it spans, then it must be willing to stretch - // otherwise, it tries not to - // note we don't use NSLayoutPriorityRequired as that will cause things to squish when they shouldn't - for (gc in self->children) { - NSLayoutPriority priority; - - if (!uiControlVisible(gc.c)) - continue; - if (hexpand[gc.left - xmin] || gc.xspan != 1) - priority = NSLayoutPriorityDefaultLow; - else - priority = NSLayoutPriorityDefaultHigh; - uiDarwinControlSetHuggingPriority(uiDarwinControl(gc.c), priority, NSLayoutConstraintOrientationHorizontal); - // same for vertical direction - if (vexpand[gc.top - ymin] || gc.yspan != 1) - priority = NSLayoutPriorityDefaultLow; - else - priority = NSLayoutPriorityDefaultHigh; - uiDarwinControlSetHuggingPriority(uiDarwinControl(gc.c), priority, NSLayoutConstraintOrientationVertical); - } - - // TODO make all expanding rows/columns the same height/width - - // and finally clean up - uiFree(hexpand); - uiFree(vexpand); - for (y = 0; y < ycount; y++) { - uiFree(gg[y]); - uiFree(gv[y]); - uiFree(gspan[y]); - } - uiFree(gg); - uiFree(gv); - uiFree(gspan); -} - -- (void)append:(gridChild *)gc -{ - BOOL update; - int oldnh, oldnv; - - [gc setTranslatesAutoresizingMaskIntoConstraints:NO]; - [self addSubview:gc]; - - // no need to set priority here; that's done in establishOurConstraints - - oldnh = [self nhexpand]; - oldnv = [self nvexpand]; - [self->children addObject:gc]; - - [self establishOurConstraints]; - update = NO; - if (gc.hexpand) - if (oldnh == 0) - update = YES; - if (gc.vexpand) - if (oldnv == 0) - update = YES; - if (update) - uiDarwinNotifyEdgeHuggingChanged(uiDarwinControl(self->g)); - - [gc release]; // we don't need the initial reference now -} - -- (void)insert:(gridChild *)gc after:(uiControl *)c at:(uiAt)at -{ - gridChild *other; - BOOL found; - - found = NO; - for (other in self->children) - if (other.c == c) { - found = YES; - break; - } - if (!found) - userbug("Existing control %p is not in grid %p; you cannot add other controls next to it", c, self->g); - - switch (at) { - case uiAtLeading: - gc.left = other.left - gc.xspan; - gc.top = other.top; - break; - case uiAtTop: - gc.left = other.left; - gc.top = other.top - gc.yspan; - break; - case uiAtTrailing: - gc.left = other.left + other.xspan; - gc.top = other.top; - break; - case uiAtBottom: - gc.left = other.left; - gc.top = other.top + other.yspan; - break; - // TODO add error checks to ALL enums - } - - [self append:gc]; -} - -- (int)isPadded -{ - return self->padded; -} - -- (void)setPadded:(int)p -{ - CGFloat padding; - NSLayoutConstraint *c; - -#if 0 /* TODO */ -dispatch_after( -dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC), -dispatch_get_main_queue(), -^{ [[self window] visualizeConstraints:[self constraints]]; } -); -#endif - self->padded = p; - padding = [self paddingAmount]; - for (c in self->inBetweens) - switch ([c firstAttribute]) { - case NSLayoutAttributeLeading: - case NSLayoutAttributeTop: - [c setConstant:padding]; - break; - case NSLayoutAttributeTrailing: - case NSLayoutAttributeBottom: - [c setConstant:-padding]; - break; - } -} - -- (BOOL)hugsTrailing -{ - // only hug if we have horizontally expanding - return [self nhexpand] != 0; -} - -- (BOOL)hugsBottom -{ - // only hug if we have vertically expanding - return [self nvexpand] != 0; -} - -- (int)nhexpand -{ - gridChild *gc; - int n; - - n = 0; - for (gc in self->children) { - if (!uiControlVisible(gc.c)) - continue; - if (gc.hexpand) - n++; - } - return n; -} - -- (int)nvexpand -{ - gridChild *gc; - int n; - - n = 0; - for (gc in self->children) { - if (!uiControlVisible(gc.c)) - continue; - if (gc.vexpand) - n++; - } - return n; -} - -@end - -static void uiGridDestroy(uiControl *c) -{ - uiGrid *g = uiGrid(c); - - [g->view onDestroy]; - [g->view release]; - uiFreeControl(uiControl(g)); -} - -uiDarwinControlDefaultHandle(uiGrid, view) -uiDarwinControlDefaultParent(uiGrid, view) -uiDarwinControlDefaultSetParent(uiGrid, view) -uiDarwinControlDefaultToplevel(uiGrid, view) -uiDarwinControlDefaultVisible(uiGrid, view) -uiDarwinControlDefaultShow(uiGrid, view) -uiDarwinControlDefaultHide(uiGrid, view) -uiDarwinControlDefaultEnabled(uiGrid, view) -uiDarwinControlDefaultEnable(uiGrid, view) -uiDarwinControlDefaultDisable(uiGrid, view) - -static void uiGridSyncEnableState(uiDarwinControl *c, int enabled) -{ - uiGrid *g = uiGrid(c); - - if (uiDarwinShouldStopSyncEnableState(uiDarwinControl(g), enabled)) - return; - [g->view syncEnableStates:enabled]; -} - -uiDarwinControlDefaultSetSuperview(uiGrid, view) - -static BOOL uiGridHugsTrailingEdge(uiDarwinControl *c) -{ - uiGrid *g = uiGrid(c); - - return [g->view hugsTrailing]; -} - -static BOOL uiGridHugsBottom(uiDarwinControl *c) -{ - uiGrid *g = uiGrid(c); - - return [g->view hugsBottom]; -} - -static void uiGridChildEdgeHuggingChanged(uiDarwinControl *c) -{ - uiGrid *g = uiGrid(c); - - [g->view establishOurConstraints]; -} - -uiDarwinControlDefaultHuggingPriority(uiGrid, view) -uiDarwinControlDefaultSetHuggingPriority(uiGrid, view) - -static void uiGridChildVisibilityChanged(uiDarwinControl *c) -{ - uiGrid *g = uiGrid(c); - - [g->view establishOurConstraints]; -} - -static gridChild *toChild(uiControl *c, int xspan, int yspan, int hexpand, uiAlign halign, int vexpand, uiAlign valign, uiGrid *g) -{ - gridChild *gc; - - if (xspan < 0) - userbug("You cannot have a negative xspan in a uiGrid cell."); - if (yspan < 0) - userbug("You cannot have a negative yspan in a uiGrid cell."); - gc = [gridChild new]; - gc.xspan = xspan; - gc.yspan = yspan; - gc.hexpand = hexpand; - gc.halign = halign; - gc.vexpand = vexpand; - gc.valign = valign; - [gc setC:c grid:g]; - return gc; -} - -void uiGridAppend(uiGrid *g, uiControl *c, int left, int top, int xspan, int yspan, int hexpand, uiAlign halign, int vexpand, uiAlign valign) -{ - gridChild *gc; - - // LONGTERM on other platforms - // or at leat allow this and implicitly turn it into a spacer - if (c == NULL) - userbug("You cannot add NULL to a uiGrid."); - gc = toChild(c, xspan, yspan, hexpand, halign, vexpand, valign, g); - gc.left = left; - gc.top = top; - [g->view append:gc]; -} - -void uiGridInsertAt(uiGrid *g, uiControl *c, uiControl *existing, uiAt at, int xspan, int yspan, int hexpand, uiAlign halign, int vexpand, uiAlign valign) -{ - gridChild *gc; - - gc = toChild(c, xspan, yspan, hexpand, halign, vexpand, valign, g); - [g->view insert:gc after:existing at:at]; -} - -int uiGridPadded(uiGrid *g) -{ - return [g->view isPadded]; -} - -void uiGridSetPadded(uiGrid *g, int padded) -{ - [g->view setPadded:padded]; -} - -uiGrid *uiNewGrid(void) -{ - uiGrid *g; - - uiDarwinNewControl(uiGrid, g); - - g->view = [[gridView alloc] initWithG:g]; - - return g; -} diff --git a/src/libui_sdl/libui/darwin/group.m b/src/libui_sdl/libui/darwin/group.m deleted file mode 100644 index 0050bbd..0000000 --- a/src/libui_sdl/libui/darwin/group.m +++ /dev/null @@ -1,194 +0,0 @@ -// 14 august 2015 -#import "uipriv_darwin.h" - -struct uiGroup { - uiDarwinControl c; - NSBox *box; - uiControl *child; - NSLayoutPriority oldHorzHuggingPri; - NSLayoutPriority oldVertHuggingPri; - int margined; - struct singleChildConstraints constraints; - NSLayoutPriority horzHuggingPri; - NSLayoutPriority vertHuggingPri; -}; - -static void removeConstraints(uiGroup *g) -{ - // set to contentView instead of to the box itself, otherwise we get clipping underneath the label - singleChildConstraintsRemove(&(g->constraints), [g->box contentView]); -} - -static void uiGroupDestroy(uiControl *c) -{ - uiGroup *g = uiGroup(c); - - removeConstraints(g); - if (g->child != NULL) { - uiControlSetParent(g->child, NULL); - uiDarwinControlSetSuperview(uiDarwinControl(g->child), nil); - uiControlDestroy(g->child); - } - [g->box release]; - uiFreeControl(uiControl(g)); -} - -uiDarwinControlDefaultHandle(uiGroup, box) -uiDarwinControlDefaultParent(uiGroup, box) -uiDarwinControlDefaultSetParent(uiGroup, box) -uiDarwinControlDefaultToplevel(uiGroup, box) -uiDarwinControlDefaultVisible(uiGroup, box) -uiDarwinControlDefaultShow(uiGroup, box) -uiDarwinControlDefaultHide(uiGroup, box) -uiDarwinControlDefaultEnabled(uiGroup, box) -uiDarwinControlDefaultEnable(uiGroup, box) -uiDarwinControlDefaultDisable(uiGroup, box) - -static void uiGroupSyncEnableState(uiDarwinControl *c, int enabled) -{ - uiGroup *g = uiGroup(c); - - if (uiDarwinShouldStopSyncEnableState(uiDarwinControl(g), enabled)) - return; - if (g->child != NULL) - uiDarwinControlSyncEnableState(uiDarwinControl(g->child), enabled); -} - -uiDarwinControlDefaultSetSuperview(uiGroup, box) - -static void groupRelayout(uiGroup *g) -{ - NSView *childView; - - removeConstraints(g); - if (g->child == NULL) - return; - childView = (NSView *) uiControlHandle(g->child); - singleChildConstraintsEstablish(&(g->constraints), - [g->box contentView], childView, - uiDarwinControlHugsTrailingEdge(uiDarwinControl(g->child)), - uiDarwinControlHugsBottom(uiDarwinControl(g->child)), - g->margined, - @"uiGroup"); - // needed for some very rare drawing errors... - jiggleViewLayout(g->box); -} - -// TODO rename these since I'm starting to get confused by what they mean by hugging -BOOL uiGroupHugsTrailingEdge(uiDarwinControl *c) -{ - uiGroup *g = uiGroup(c); - - // TODO make a function? - return g->horzHuggingPri < NSLayoutPriorityWindowSizeStayPut; -} - -BOOL uiGroupHugsBottom(uiDarwinControl *c) -{ - uiGroup *g = uiGroup(c); - - return g->vertHuggingPri < NSLayoutPriorityWindowSizeStayPut; -} - -static void uiGroupChildEdgeHuggingChanged(uiDarwinControl *c) -{ - uiGroup *g = uiGroup(c); - - groupRelayout(g); -} - -static NSLayoutPriority uiGroupHuggingPriority(uiDarwinControl *c, NSLayoutConstraintOrientation orientation) -{ - uiGroup *g = uiGroup(c); - - if (orientation == NSLayoutConstraintOrientationHorizontal) - return g->horzHuggingPri; - return g->vertHuggingPri; -} - -static void uiGroupSetHuggingPriority(uiDarwinControl *c, NSLayoutPriority priority, NSLayoutConstraintOrientation orientation) -{ - uiGroup *g = uiGroup(c); - - if (orientation == NSLayoutConstraintOrientationHorizontal) - g->horzHuggingPri = priority; - else - g->vertHuggingPri = priority; - uiDarwinNotifyEdgeHuggingChanged(uiDarwinControl(g)); -} - -static void uiGroupChildVisibilityChanged(uiDarwinControl *c) -{ - uiGroup *g = uiGroup(c); - - groupRelayout(g); -} - -char *uiGroupTitle(uiGroup *g) -{ - return uiDarwinNSStringToText([g->box title]); -} - -void uiGroupSetTitle(uiGroup *g, const char *title) -{ - [g->box setTitle:toNSString(title)]; -} - -void uiGroupSetChild(uiGroup *g, uiControl *child) -{ - NSView *childView; - - if (g->child != NULL) { - removeConstraints(g); - uiDarwinControlSetHuggingPriority(uiDarwinControl(g->child), g->oldHorzHuggingPri, NSLayoutConstraintOrientationHorizontal); - uiDarwinControlSetHuggingPriority(uiDarwinControl(g->child), g->oldVertHuggingPri, NSLayoutConstraintOrientationVertical); - uiControlSetParent(g->child, NULL); - uiDarwinControlSetSuperview(uiDarwinControl(g->child), nil); - } - g->child = child; - if (g->child != NULL) { - childView = (NSView *) uiControlHandle(g->child); - uiControlSetParent(g->child, uiControl(g)); - uiDarwinControlSetSuperview(uiDarwinControl(g->child), [g->box contentView]); - uiDarwinControlSyncEnableState(uiDarwinControl(g->child), uiControlEnabledToUser(uiControl(g))); - // don't hug, just in case we're a stretchy group - g->oldHorzHuggingPri = uiDarwinControlHuggingPriority(uiDarwinControl(g->child), NSLayoutConstraintOrientationHorizontal); - g->oldVertHuggingPri = uiDarwinControlHuggingPriority(uiDarwinControl(g->child), NSLayoutConstraintOrientationVertical); - uiDarwinControlSetHuggingPriority(uiDarwinControl(g->child), NSLayoutPriorityDefaultLow, NSLayoutConstraintOrientationHorizontal); - uiDarwinControlSetHuggingPriority(uiDarwinControl(g->child), NSLayoutPriorityDefaultLow, NSLayoutConstraintOrientationVertical); - } - groupRelayout(g); -} - -int uiGroupMargined(uiGroup *g) -{ - return g->margined; -} - -void uiGroupSetMargined(uiGroup *g, int margined) -{ - g->margined = margined; - singleChildConstraintsSetMargined(&(g->constraints), g->margined); -} - -uiGroup *uiNewGroup(const char *title) -{ - uiGroup *g; - - uiDarwinNewControl(uiGroup, g); - - g->box = [[NSBox alloc] initWithFrame:NSZeroRect]; - [g->box setTitle:toNSString(title)]; - [g->box setBoxType:NSBoxPrimary]; - [g->box setBorderType:NSLineBorder]; - [g->box setTransparent:NO]; - [g->box setTitlePosition:NSAtTop]; - // we can't use uiDarwinSetControlFont() because the selector is different - [g->box setTitleFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]]]; - - // default to low hugging to not hug edges - g->horzHuggingPri = NSLayoutPriorityDefaultLow; - g->vertHuggingPri = NSLayoutPriorityDefaultLow; - - return g; -} diff --git a/src/libui_sdl/libui/darwin/image.m b/src/libui_sdl/libui/darwin/image.m deleted file mode 100644 index b62de31..0000000 --- a/src/libui_sdl/libui/darwin/image.m +++ /dev/null @@ -1,82 +0,0 @@ -// 25 june 2016 -#import "uipriv_darwin.h" - -struct uiImage { - NSImage *i; - NSSize size; - NSMutableArray *swizzled; -}; - -uiImage *uiNewImage(double width, double height) -{ - uiImage *i; - - i = uiNew(uiImage); - i->size = NSMakeSize(width, height); - i->i = [[NSImage alloc] initWithSize:i->size]; - i->swizzled = [NSMutableArray new]; - return i; -} - -void uiFreeImage(uiImage *i) -{ - NSValue *v; - - [i->i release]; - // to be safe, do this after releasing the image - for (v in i->swizzled) - uiFree([v pointerValue]); - [i->swizzled release]; - uiFree(i); -} - -void uiImageAppend(uiImage *i, void *pixels, int pixelWidth, int pixelHeight, int pixelStride) -{ - NSBitmapImageRep *repCalibrated, *repsRGB; - uint8_t *swizzled, *bp, *sp; - int x, y; - unsigned char *pix[1]; - - // OS X demands that R and B are in the opposite order from what we expect - // we must swizzle :( - // LONGTERM test on a big-endian system - swizzled = (uint8_t *) uiAlloc((pixelStride * pixelHeight * 4) * sizeof (uint8_t), "uint8_t[]"); - bp = (uint8_t *) pixels; - sp = swizzled; - for (y = 0; y < pixelHeight * pixelStride; y += pixelStride) - for (x = 0; x < pixelStride; x++) { - sp[0] = bp[2]; - sp[1] = bp[1]; - sp[2] = bp[0]; - sp[3] = bp[3]; - sp += 4; - bp += 4; - } - - pix[0] = (unsigned char *) swizzled; - repCalibrated = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:pix - pixelsWide:pixelWidth - pixelsHigh:pixelHeight - bitsPerSample:8 - samplesPerPixel:4 - hasAlpha:YES - isPlanar:NO - colorSpaceName:NSCalibratedRGBColorSpace - bitmapFormat:0 - bytesPerRow:pixelStride - bitsPerPixel:32]; - repsRGB = [repCalibrated bitmapImageRepByRetaggingWithColorSpace:[NSColorSpace sRGBColorSpace]]; - [repCalibrated release]; - - [i->i addRepresentation:repsRGB]; - [repsRGB setSize:i->size]; - [repsRGB release]; - - // we need to keep swizzled alive for NSBitmapImageRep - [i->swizzled addObject:[NSValue valueWithPointer:swizzled]]; -} - -NSImage *imageImage(uiImage *i) -{ - return i->i; -} diff --git a/src/libui_sdl/libui/darwin/label.m b/src/libui_sdl/libui/darwin/label.m deleted file mode 100644 index 897bc3f..0000000 --- a/src/libui_sdl/libui/darwin/label.m +++ /dev/null @@ -1,43 +0,0 @@ -// 14 august 2015 -#import "uipriv_darwin.h" - -struct uiLabel { - uiDarwinControl c; - NSTextField *textfield; -}; - -uiDarwinControlAllDefaults(uiLabel, textfield) - -char *uiLabelText(uiLabel *l) -{ - return uiDarwinNSStringToText([l->textfield stringValue]); -} - -void uiLabelSetText(uiLabel *l, const char *text) -{ - [l->textfield setStringValue:toNSString(text)]; -} - -NSTextField *newLabel(NSString *str) -{ - NSTextField *tf; - - tf = [[NSTextField alloc] initWithFrame:NSZeroRect]; - [tf setStringValue:str]; - [tf setEditable:NO]; - [tf setSelectable:NO]; - [tf setDrawsBackground:NO]; - finishNewTextField(tf, NO); - return tf; -} - -uiLabel *uiNewLabel(const char *text) -{ - uiLabel *l; - - uiDarwinNewControl(uiLabel, l); - - l->textfield = newLabel(toNSString(text)); - - return l; -} diff --git a/src/libui_sdl/libui/darwin/main.m b/src/libui_sdl/libui/darwin/main.m deleted file mode 100644 index 59a8683..0000000 --- a/src/libui_sdl/libui/darwin/main.m +++ /dev/null @@ -1,239 +0,0 @@ -// 6 april 2015 -#import "uipriv_darwin.h" - -static BOOL canQuit = NO; -static NSAutoreleasePool *globalPool; -static applicationClass *app; -static appDelegate *delegate; - -static BOOL (^isRunning)(void); -static BOOL stepsIsRunning; - -@implementation applicationClass - -- (void)sendEvent:(NSEvent *)e -{ - if (sendAreaEvents(e) != 0) - return; - [super sendEvent:e]; -} - -// NSColorPanel always sends changeColor: to the first responder regardless of whether there's a target set on it -// we can override it here (see colorbutton.m) -// thanks to mikeash in irc.freenode.net/#macdev for informing me this is how the first responder chain is initiated -// it turns out NSFontManager also sends changeFont: through this; let's inhibit that here too (see fontbutton.m) -- (BOOL)sendAction:(SEL)sel to:(id)to from:(id)from -{ - if (colorButtonInhibitSendAction(sel, from, to)) - return NO; - if (fontButtonInhibitSendAction(sel, from, to)) - return NO; - return [super sendAction:sel to:to from:from]; -} - -// likewise, NSFontManager also sends NSFontPanelValidation messages to the first responder, however it does NOT use sendAction:from:to:! -// instead, it uses this one (thanks swillits in irc.freenode.net/#macdev) -// we also need to override it (see fontbutton.m) -- (id)targetForAction:(SEL)sel to:(id)to from:(id)from -{ - id override; - - if (fontButtonOverrideTargetForAction(sel, from, to, &override)) - return override; - return [super targetForAction:sel to:to from:from]; -} - -// hey look! we're overriding terminate:! -// we're going to make sure we can go back to main() whether Cocoa likes it or not! -// and just how are we going to do that, hm? -// (note: this is called after applicationShouldTerminate:) -- (void)terminate:(id)sender -{ - // yes that's right folks: DO ABSOLUTELY NOTHING. - // the magic is [NSApp run] will just... stop. - - // well let's not do nothing; let's actually quit our graceful way - NSEvent *e; - - if (!canQuit) - implbug("call to [NSApp terminate:] when not ready to terminate; definitely contact andlabs"); - - [realNSApp() stop:realNSApp()]; - // stop: won't register until another event has passed; let's synthesize one - e = [NSEvent otherEventWithType:NSApplicationDefined - location:NSZeroPoint - modifierFlags:0 - timestamp:[[NSProcessInfo processInfo] systemUptime] - windowNumber:0 - context:[NSGraphicsContext currentContext] - subtype:0 - data1:0 - data2:0]; - [realNSApp() postEvent:e atStart:NO]; // let pending events take priority (this is what PostQuitMessage() on Windows does so we have to do it here too for parity; thanks to mikeash in irc.freenode.net/#macdev for confirming that this parameter should indeed be NO) - - // and in case uiMainSteps() was called - stepsIsRunning = NO; -} - -@end - -@implementation appDelegate - -- (void)dealloc -{ - // Apple docs: "Don't Use Accessor Methods in Initializer Methods and dealloc" - [_menuManager release]; - [super dealloc]; -} - -- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)app -{ - // for debugging - NSLog(@"in applicationShouldTerminate:"); - if (shouldQuit()) { - canQuit = YES; - // this will call terminate:, which is the same as uiQuit() - return NSTerminateNow; - } - return NSTerminateCancel; -} - -- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)app -{ - return NO; -} - -@end - -uiInitOptions options; - -const char *uiInit(uiInitOptions *o) -{ - @autoreleasepool { - options = *o; - app = [[applicationClass sharedApplication] retain]; - // don't check for a NO return; something (launch services?) causes running from application bundles to always return NO when asking to change activation policy, even if the change is to the same activation policy! - // see https://github.com/andlabs/ui/issues/6 - [realNSApp() setActivationPolicy:NSApplicationActivationPolicyRegular]; - delegate = [appDelegate new]; - [realNSApp() setDelegate:delegate]; - - initAlloc(); - - // always do this so we always have an application menu - appDelegate().menuManager = [[menuManager new] autorelease]; - [realNSApp() setMainMenu:[appDelegate().menuManager makeMenubar]]; - - setupFontPanel(); - } - - globalPool = [[NSAutoreleasePool alloc] init]; - - return NULL; -} - -void uiUninit(void) -{ - if (!globalPool) { - userbug("You must call uiInit() first!"); - } - [globalPool release]; - - @autoreleasepool { - [delegate release]; - [realNSApp() setDelegate:nil]; - [app release]; - uninitAlloc(); - } -} - -void uiFreeInitError(const char *err) -{ -} - -void uiMain(void) -{ - isRunning = ^{ - return [realNSApp() isRunning]; - }; - [realNSApp() run]; -} - -void uiMainSteps(void) -{ - // SDL does this and it seems to be necessary for the menubar to work (see #182) - [realNSApp() finishLaunching]; - isRunning = ^{ - return stepsIsRunning; - }; - stepsIsRunning = YES; -} - -int uiMainStep(int wait) -{ - struct nextEventArgs nea; - - nea.mask = NSAnyEventMask; - - // ProPuke did this in his original PR requesting this - // I'm not sure if this will work, but I assume it will... - nea.duration = [NSDate distantPast]; - if (wait) // but this is normal so it will work - nea.duration = [NSDate distantFuture]; - - nea.mode = NSDefaultRunLoopMode; - nea.dequeue = YES; - - return mainStep(&nea, ^(NSEvent *e) { - return NO; - }); -} - -// see also: -// - http://www.cocoawithlove.com/2009/01/demystifying-nsapplication-by.html -// - https://github.com/gnustep/gui/blob/master/Source/NSApplication.m -int mainStep(struct nextEventArgs *nea, BOOL (^interceptEvent)(NSEvent *e)) -{ - NSDate *expire; - NSEvent *e; - NSEventType type; - - @autoreleasepool { - if (!isRunning()) - return 0; - - e = [realNSApp() nextEventMatchingMask:nea->mask - untilDate:nea->duration - inMode:nea->mode - dequeue:nea->dequeue]; - if (e == nil) - return 1; - - type = [e type]; - if (!interceptEvent(e)) - [realNSApp() sendEvent:e]; - [realNSApp() updateWindows]; - - // GNUstep does this - // it also updates the Services menu but there doesn't seem to be a public API for that so - if (type != NSPeriodic && type != NSMouseMoved) - [[realNSApp() mainMenu] update]; - - return 1; - } -} - -void uiQuit(void) -{ - canQuit = YES; - [realNSApp() terminate:realNSApp()]; -} - -// thanks to mikeash in irc.freenode.net/#macdev for suggesting the use of Grand Central Dispatch for this -// LONGTERM will dispatch_get_main_queue() break after _CFRunLoopSetCurrent()? -void uiQueueMain(void (*f)(void *data), void *data) -{ - // dispatch_get_main_queue() is a serial queue so it will not execute multiple uiQueueMain() functions concurrently - // the signature of f matches dispatch_function_t - dispatch_async_f(dispatch_get_main_queue(), data, f); -} diff --git a/src/libui_sdl/libui/darwin/map.m b/src/libui_sdl/libui/darwin/map.m deleted file mode 100644 index 46a7b8d..0000000 --- a/src/libui_sdl/libui/darwin/map.m +++ /dev/null @@ -1,59 +0,0 @@ -// 17 august 2015 -#import "uipriv_darwin.h" - -// unfortunately NSMutableDictionary copies its keys, meaning we can't use it for pointers -// hence, this file -// we could expose a NSMapTable directly, but let's treat all pointers as opaque and hide the implementation, just to be safe and prevent even more rewrites later -struct mapTable { - NSMapTable *m; -}; - -struct mapTable *newMap(void) -{ - struct mapTable *m; - - m = uiNew(struct mapTable); - m->m = [[NSMapTable alloc] initWithKeyOptions:(NSPointerFunctionsOpaqueMemory | NSPointerFunctionsOpaquePersonality) - valueOptions:(NSPointerFunctionsOpaqueMemory | NSPointerFunctionsOpaquePersonality) - capacity:0]; - return m; -} - -void mapDestroy(struct mapTable *m) -{ - if ([m->m count] != 0) - implbug("attempt to destroy map with items inside"); - [m->m release]; - uiFree(m); -} - -void *mapGet(struct mapTable *m, void *key) -{ - return NSMapGet(m->m, key); -} - -void mapSet(struct mapTable *m, void *key, void *value) -{ - NSMapInsert(m->m, key, value); -} - -void mapDelete(struct mapTable *m, void *key) -{ - NSMapRemove(m->m, key); -} - -void mapWalk(struct mapTable *m, void (*f)(void *key, void *value)) -{ - NSMapEnumerator e = NSEnumerateMapTable(m->m); - void *k = NULL; - void *v = NULL; - while (NSNextMapEnumeratorPair(&e, &k, &v)) { - f(k, v); - } - NSEndMapTableEnumeration(&e); -} - -void mapReset(struct mapTable *m) -{ - NSResetMapTable(m->m); -} diff --git a/src/libui_sdl/libui/darwin/menu.m b/src/libui_sdl/libui/darwin/menu.m deleted file mode 100644 index 735cac5..0000000 --- a/src/libui_sdl/libui/darwin/menu.m +++ /dev/null @@ -1,368 +0,0 @@ -// 28 april 2015 -#import "uipriv_darwin.h" - -static NSMutableArray *menus = nil; -static BOOL menusFinalized = NO; - -struct uiMenu { - NSMenu *menu; - NSMenuItem *item; - NSMutableArray *items; -}; - -struct uiMenuItem { - NSMenuItem *item; - int type; - BOOL disabled; - void (*onClicked)(uiMenuItem *, uiWindow *, void *); - void *onClickedData; -}; - -enum { - typeRegular, - typeCheckbox, - typeQuit, - typePreferences, - typeAbout, - typeSeparator, -}; - -static void mapItemReleaser(void *key, void *value) -{ - uiMenuItem *item; - - item = (uiMenuItem *)value; - [item->item release]; -} - -@implementation menuManager - -- (id)init -{ - self = [super init]; - if (self) { - self->items = newMap(); - self->hasQuit = NO; - self->hasPreferences = NO; - self->hasAbout = NO; - } - return self; -} - -- (void)dealloc -{ - mapWalk(self->items, mapItemReleaser); - mapReset(self->items); - mapDestroy(self->items); - uninitMenus(); - [super dealloc]; -} - -- (IBAction)onClicked:(id)sender -{ - uiMenuItem *item; - - item = (uiMenuItem *) mapGet(self->items, sender); - if (item->type == typeCheckbox) - uiMenuItemSetChecked(item, !uiMenuItemChecked(item)); - // use the key window as the source of the menu event; it's the active window - (*(item->onClicked))(item, windowFromNSWindow([realNSApp() keyWindow]), item->onClickedData); -} - -- (IBAction)onQuitClicked:(id)sender -{ - if (shouldQuit()) - uiQuit(); -} - -- (void)register:(NSMenuItem *)item to:(uiMenuItem *)smi -{ - switch (smi->type) { - case typeQuit: - if (self->hasQuit) - userbug("You can't have multiple Quit menu items in one program."); - self->hasQuit = YES; - break; - case typePreferences: - if (self->hasPreferences) - userbug("You can't have multiple Preferences menu items in one program."); - self->hasPreferences = YES; - break; - case typeAbout: - if (self->hasAbout) - userbug("You can't have multiple About menu items in one program."); - self->hasAbout = YES; - break; - } - mapSet(self->items, item, smi); -} - -// on OS X there are two ways to handle menu items being enabled or disabled: automatically and manually -// unfortunately, the application menu requires automatic menu handling for the Hide, Hide Others, and Show All items to work correctly -// therefore, we have to handle enabling of the other options ourselves -- (BOOL)validateMenuItem:(NSMenuItem *)item -{ - uiMenuItem *smi; - - // disable the special items if they aren't present - if (item == self.quitItem && !self->hasQuit) - return NO; - if (item == self.preferencesItem && !self->hasPreferences) - return NO; - if (item == self.aboutItem && !self->hasAbout) - return NO; - // then poll the item's enabled/disabled state - smi = (uiMenuItem *) mapGet(self->items, item); - return !smi->disabled; -} - -// Cocoa constructs the default application menu by hand for each program; that's what MainMenu.[nx]ib does -- (void)buildApplicationMenu:(NSMenu *)menubar -{ - NSString *appName; - NSMenuItem *appMenuItem; - NSMenu *appMenu; - NSMenuItem *item; - NSString *title; - NSMenu *servicesMenu; - - // note: no need to call setAppleMenu: on this anymore; see https://developer.apple.com/library/mac/releasenotes/AppKit/RN-AppKitOlderNotes/#X10_6Notes - appName = [[NSProcessInfo processInfo] processName]; - appMenuItem = [[[NSMenuItem alloc] initWithTitle:appName action:NULL keyEquivalent:@""] autorelease]; - appMenu = [[[NSMenu alloc] initWithTitle:appName] autorelease]; - [appMenuItem setSubmenu:appMenu]; - [menubar addItem:appMenuItem]; - - // first is About - title = [@"About " stringByAppendingString:appName]; - item = [[[NSMenuItem alloc] initWithTitle:title action:@selector(onClicked:) keyEquivalent:@""] autorelease]; - [item setTarget:self]; - [appMenu addItem:item]; - self.aboutItem = item; - - [appMenu addItem:[NSMenuItem separatorItem]]; - - // next is Preferences - item = [[[NSMenuItem alloc] initWithTitle:@"Preferences…" action:@selector(onClicked:) keyEquivalent:@","] autorelease]; - [item setTarget:self]; - [appMenu addItem:item]; - self.preferencesItem = item; - - [appMenu addItem:[NSMenuItem separatorItem]]; - - // next is Services - item = [[[NSMenuItem alloc] initWithTitle:@"Services" action:NULL keyEquivalent:@""] autorelease]; - servicesMenu = [[[NSMenu alloc] initWithTitle:@"Services"] autorelease]; - [item setSubmenu:servicesMenu]; - [realNSApp() setServicesMenu:servicesMenu]; - [appMenu addItem:item]; - - [appMenu addItem:[NSMenuItem separatorItem]]; - - // next are the three hiding options - title = [@"Hide " stringByAppendingString:appName]; - item = [[[NSMenuItem alloc] initWithTitle:title action:@selector(hide:) keyEquivalent:@"h"] autorelease]; - // the .xib file says they go to -1 ("First Responder", which sounds wrong...) - // to do that, we simply leave the target as nil - [appMenu addItem:item]; - item = [[[NSMenuItem alloc] initWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"] autorelease]; - [item setKeyEquivalentModifierMask:(NSAlternateKeyMask | NSCommandKeyMask)]; - [appMenu addItem:item]; - item = [[[NSMenuItem alloc] initWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""] autorelease]; - [appMenu addItem:item]; - - [appMenu addItem:[NSMenuItem separatorItem]]; - - // and finally Quit - // DON'T use @selector(terminate:) as the action; we handle termination ourselves - title = [@"Quit " stringByAppendingString:appName]; - item = [[[NSMenuItem alloc] initWithTitle:title action:@selector(onQuitClicked:) keyEquivalent:@"q"] autorelease]; - [item setTarget:self]; - [appMenu addItem:item]; - self.quitItem = item; -} - -- (NSMenu *)makeMenubar -{ - NSMenu *menubar; - - menubar = [[[NSMenu alloc] initWithTitle:@""] autorelease]; - [self buildApplicationMenu:menubar]; - return menubar; -} - -@end - -static void defaultOnClicked(uiMenuItem *item, uiWindow *w, void *data) -{ - // do nothing -} - -void uiMenuItemEnable(uiMenuItem *item) -{ - item->disabled = NO; - // we don't need to explicitly update the menus here; they'll be updated the next time they're opened (thanks mikeash in irc.freenode.net/#macdev) -} - -void uiMenuItemDisable(uiMenuItem *item) -{ - item->disabled = YES; -} - -void uiMenuItemOnClicked(uiMenuItem *item, void (*f)(uiMenuItem *, uiWindow *, void *), void *data) -{ - if (item->type == typeQuit) - userbug("You can't call uiMenuItemOnClicked() on a Quit item; use uiOnShouldQuit() instead."); - item->onClicked = f; - item->onClickedData = data; -} - -int uiMenuItemChecked(uiMenuItem *item) -{ - return [item->item state] != NSOffState; -} - -void uiMenuItemSetChecked(uiMenuItem *item, int checked) -{ - NSInteger state; - - state = NSOffState; - if ([item->item state] == NSOffState) - state = NSOnState; - [item->item setState:state]; -} - -static uiMenuItem *newItem(uiMenu *m, int type, const char *name) -{ - @autoreleasepool { - - uiMenuItem *item; - - if (menusFinalized) - userbug("You can't create a new menu item after menus have been finalized."); - - item = uiNew(uiMenuItem); - - item->type = type; - switch (item->type) { - case typeQuit: - item->item = [appDelegate().menuManager.quitItem retain]; - break; - case typePreferences: - item->item = [appDelegate().menuManager.preferencesItem retain]; - break; - case typeAbout: - item->item = [appDelegate().menuManager.aboutItem retain]; - break; - case typeSeparator: - item->item = [[NSMenuItem separatorItem] retain]; - [m->menu addItem:item->item]; - break; - default: - item->item = [[NSMenuItem alloc] initWithTitle:toNSString(name) action:@selector(onClicked:) keyEquivalent:@""]; - [item->item setTarget:appDelegate().menuManager]; - [m->menu addItem:item->item]; - break; - } - - [appDelegate().menuManager register:item->item to:item]; - item->onClicked = defaultOnClicked; - - [m->items addObject:[NSValue valueWithPointer:item]]; - - return item; - - } // @autoreleasepool -} - -uiMenuItem *uiMenuAppendItem(uiMenu *m, const char *name) -{ - return newItem(m, typeRegular, name); -} - -uiMenuItem *uiMenuAppendCheckItem(uiMenu *m, const char *name) -{ - return newItem(m, typeCheckbox, name); -} - -uiMenuItem *uiMenuAppendQuitItem(uiMenu *m) -{ - // duplicate check is in the register:to: selector - return newItem(m, typeQuit, NULL); -} - -uiMenuItem *uiMenuAppendPreferencesItem(uiMenu *m) -{ - // duplicate check is in the register:to: selector - return newItem(m, typePreferences, NULL); -} - -uiMenuItem *uiMenuAppendAboutItem(uiMenu *m) -{ - // duplicate check is in the register:to: selector - return newItem(m, typeAbout, NULL); -} - -void uiMenuAppendSeparator(uiMenu *m) -{ - newItem(m, typeSeparator, NULL); -} - -uiMenu *uiNewMenu(const char *name) -{ - @autoreleasepool { - - uiMenu *m; - - if (menusFinalized) - userbug("You can't create a new menu after menus have been finalized."); - if (menus == nil) - menus = [NSMutableArray new]; - - m = uiNew(uiMenu); - - m->menu = [[NSMenu alloc] initWithTitle:toNSString(name)]; - // use automatic menu item enabling for all menus for consistency's sake - - m->item = [[NSMenuItem alloc] initWithTitle:toNSString(name) action:NULL keyEquivalent:@""]; - [m->item setSubmenu:m->menu]; - - m->items = [NSMutableArray new]; - - [[realNSApp() mainMenu] addItem:m->item]; - - [menus addObject:[NSValue valueWithPointer:m]]; - - return m; - - } // @autoreleasepool -} - -void finalizeMenus(void) -{ - menusFinalized = YES; -} - -void uninitMenus(void) -{ - if (menus == NULL) - return; - [menus enumerateObjectsUsingBlock:^(id obj, NSUInteger index, BOOL *stop) { - NSValue *v; - uiMenu *m; - - v = (NSValue *) obj; - m = (uiMenu *) [v pointerValue]; - [m->items enumerateObjectsUsingBlock:^(id obj, NSUInteger index, BOOL *stop) { - NSValue *v; - uiMenuItem *mi; - - v = (NSValue *) obj; - mi = (uiMenuItem *) [v pointerValue]; - uiFree(mi); - }]; - [m->items release]; - uiFree(m); - }]; - [menus release]; -} diff --git a/src/libui_sdl/libui/darwin/multilineentry.m b/src/libui_sdl/libui/darwin/multilineentry.m deleted file mode 100644 index 605e900..0000000 --- a/src/libui_sdl/libui/darwin/multilineentry.m +++ /dev/null @@ -1,233 +0,0 @@ -// 8 december 2015 -#import "uipriv_darwin.h" - -// NSTextView has no intrinsic content size by default, which wreaks havoc on a pure-Auto Layout system -// we'll have to take over to get it to work -// see also http://stackoverflow.com/questions/24210153/nstextview-not-properly-resizing-with-auto-layout and http://stackoverflow.com/questions/11237622/using-autolayout-with-expanding-nstextviews -@interface intrinsicSizeTextView : NSTextView { - uiMultilineEntry *libui_e; -} -- (id)initWithFrame:(NSRect)r e:(uiMultilineEntry *)e; -@end - -struct uiMultilineEntry { - uiDarwinControl c; - NSScrollView *sv; - intrinsicSizeTextView *tv; - struct scrollViewData *d; - void (*onChanged)(uiMultilineEntry *, void *); - void *onChangedData; - BOOL changing; -}; - -@implementation intrinsicSizeTextView - -- (id)initWithFrame:(NSRect)r e:(uiMultilineEntry *)e -{ - self = [super initWithFrame:r]; - if (self) - self->libui_e = e; - return self; -} - -- (NSSize)intrinsicContentSize -{ - NSTextContainer *textContainer; - NSLayoutManager *layoutManager; - NSRect rect; - - textContainer = [self textContainer]; - layoutManager = [self layoutManager]; - [layoutManager ensureLayoutForTextContainer:textContainer]; - rect = [layoutManager usedRectForTextContainer:textContainer]; - return rect.size; -} - -- (void)didChangeText -{ - [super didChangeText]; - [self invalidateIntrinsicContentSize]; - if (!self->libui_e->changing) - (*(self->libui_e->onChanged))(self->libui_e, self->libui_e->onChangedData); -} - -@end - -uiDarwinControlAllDefaultsExceptDestroy(uiMultilineEntry, sv) - -static void uiMultilineEntryDestroy(uiControl *c) -{ - uiMultilineEntry *e = uiMultilineEntry(c); - - scrollViewFreeData(e->sv, e->d); - [e->tv release]; - [e->sv release]; - uiFreeControl(uiControl(e)); -} - -static void defaultOnChanged(uiMultilineEntry *e, void *data) -{ - // do nothing -} - -char *uiMultilineEntryText(uiMultilineEntry *e) -{ - return uiDarwinNSStringToText([e->tv string]); -} - -void uiMultilineEntrySetText(uiMultilineEntry *e, const char *text) -{ - [[e->tv textStorage] replaceCharactersInRange:NSMakeRange(0, [[e->tv string] length]) - withString:toNSString(text)]; - // must be called explicitly according to the documentation of shouldChangeTextInRange:replacementString: - e->changing = YES; - [e->tv didChangeText]; - e->changing = NO; -} - -// TODO scroll to end? -void uiMultilineEntryAppend(uiMultilineEntry *e, const char *text) -{ - [[e->tv textStorage] replaceCharactersInRange:NSMakeRange([[e->tv string] length], 0) - withString:toNSString(text)]; - e->changing = YES; - [e->tv didChangeText]; - e->changing = NO; -} - -void uiMultilineEntryOnChanged(uiMultilineEntry *e, void (*f)(uiMultilineEntry *e, void *data), void *data) -{ - e->onChanged = f; - e->onChangedData = data; -} - -int uiMultilineEntryReadOnly(uiMultilineEntry *e) -{ - return [e->tv isEditable] == NO; -} - -void uiMultilineEntrySetReadOnly(uiMultilineEntry *e, int readonly) -{ - BOOL editable; - - editable = YES; - if (readonly) - editable = NO; - [e->tv setEditable:editable]; -} - -static uiMultilineEntry *finishMultilineEntry(BOOL hscroll) -{ - uiMultilineEntry *e; - NSFont *font; - struct scrollViewCreateParams p; - - uiDarwinNewControl(uiMultilineEntry, e); - - e->tv = [[intrinsicSizeTextView alloc] initWithFrame:NSZeroRect e:e]; - - // verified against Interface Builder for a sufficiently customized text view - - // NSText properties: - // this is what Interface Builder sets the background color to - [e->tv setBackgroundColor:[NSColor colorWithCalibratedWhite:1.0 alpha:1.0]]; - [e->tv setDrawsBackground:YES]; - [e->tv setEditable:YES]; - [e->tv setSelectable:YES]; - [e->tv setFieldEditor:NO]; - [e->tv setRichText:NO]; - [e->tv setImportsGraphics:NO]; - [e->tv setUsesFontPanel:NO]; - [e->tv setRulerVisible:NO]; - // we'll handle font last - // while setAlignment: has been around since 10.0, the named constant "NSTextAlignmentNatural" seems to have only been introduced in 10.11 -#define ourNSTextAlignmentNatural 4 - [e->tv setAlignment:ourNSTextAlignmentNatural]; - // textColor is set to nil, just keep the dfault - [e->tv setBaseWritingDirection:NSWritingDirectionNatural]; - [e->tv setHorizontallyResizable:NO]; - [e->tv setVerticallyResizable:YES]; - - // NSTextView properties: - [e->tv setAllowsDocumentBackgroundColorChange:NO]; - [e->tv setAllowsUndo:YES]; - // default paragraph style is nil; keep default - [e->tv setAllowsImageEditing:NO]; - [e->tv setAutomaticQuoteSubstitutionEnabled:NO]; - [e->tv setAutomaticLinkDetectionEnabled:NO]; - [e->tv setDisplaysLinkToolTips:YES]; - [e->tv setUsesRuler:NO]; - [e->tv setUsesInspectorBar:NO]; - [e->tv setSelectionGranularity:NSSelectByCharacter]; - // there is a dedicated named insertion point color but oh well - [e->tv setInsertionPointColor:[NSColor controlTextColor]]; - // typing attributes is nil; keep default (we change it below for fonts though) - [e->tv setSmartInsertDeleteEnabled:NO]; - [e->tv setContinuousSpellCheckingEnabled:NO]; - [e->tv setGrammarCheckingEnabled:NO]; - [e->tv setUsesFindPanel:YES]; - [e->tv setEnabledTextCheckingTypes:0]; - [e->tv setAutomaticDashSubstitutionEnabled:NO]; - [e->tv setAutomaticDataDetectionEnabled:NO]; - [e->tv setAutomaticSpellingCorrectionEnabled:NO]; - [e->tv setAutomaticTextReplacementEnabled:NO]; - [e->tv setUsesFindBar:NO]; - [e->tv setIncrementalSearchingEnabled:NO]; - - // NSTextContainer properties: - [[e->tv textContainer] setWidthTracksTextView:YES]; - [[e->tv textContainer] setHeightTracksTextView:NO]; - - // NSLayoutManager properties: - [[e->tv layoutManager] setAllowsNonContiguousLayout:YES]; - - // now just to be safe; this will do some of the above but whatever - disableAutocorrect(e->tv); - - // see https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/TextUILayer/Tasks/TextInScrollView.html - // notice we don't use the Auto Layout code; see scrollview.m for more details - [e->tv setMaxSize:NSMakeSize(CGFLOAT_MAX, CGFLOAT_MAX)]; - [e->tv setVerticallyResizable:YES]; - [e->tv setHorizontallyResizable:hscroll]; - if (hscroll) { - [e->tv setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; - [[e->tv textContainer] setWidthTracksTextView:NO]; - } else { - [e->tv setAutoresizingMask:NSViewWidthSizable]; - [[e->tv textContainer] setWidthTracksTextView:YES]; - } - [[e->tv textContainer] setContainerSize:NSMakeSize(CGFLOAT_MAX, CGFLOAT_MAX)]; - - // don't use uiDarwinSetControlFont() directly; we have to do a little extra work to set the font - font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]]; - [e->tv setTypingAttributes:[NSDictionary - dictionaryWithObject:font - forKey:NSFontAttributeName]]; - // e->tv font from Interface Builder is nil, but setFont:nil throws an exception - // let's just set it to the standard control font anyway, just to be safe - [e->tv setFont:font]; - - memset(&p, 0, sizeof (struct scrollViewCreateParams)); - p.DocumentView = e->tv; - // this is what Interface Builder sets it to - p.BackgroundColor = [NSColor colorWithCalibratedWhite:1.0 alpha:1.0]; - p.DrawsBackground = YES; - p.Bordered = YES; - p.HScroll = hscroll; - p.VScroll = YES; - e->sv = mkScrollView(&p, &(e->d)); - - uiMultilineEntryOnChanged(e, defaultOnChanged, NULL); - - return e; -} - -uiMultilineEntry *uiNewMultilineEntry(void) -{ - return finishMultilineEntry(NO); -} - -uiMultilineEntry *uiNewNonWrappingMultilineEntry(void) -{ - return finishMultilineEntry(YES); -} diff --git a/src/libui_sdl/libui/darwin/progressbar.m b/src/libui_sdl/libui/darwin/progressbar.m deleted file mode 100644 index b538228..0000000 --- a/src/libui_sdl/libui/darwin/progressbar.m +++ /dev/null @@ -1,78 +0,0 @@ -// 14 august 2015 -#import "uipriv_darwin.h" - -// NSProgressIndicator has no intrinsic width by default; use the default width in Interface Builder -#define progressIndicatorWidth 100 - -@interface intrinsicWidthNSProgressIndicator : NSProgressIndicator -@end - -@implementation intrinsicWidthNSProgressIndicator - -- (NSSize)intrinsicContentSize -{ - NSSize s; - - s = [super intrinsicContentSize]; - s.width = progressIndicatorWidth; - return s; -} - -@end - -struct uiProgressBar { - uiDarwinControl c; - NSProgressIndicator *pi; -}; - -uiDarwinControlAllDefaults(uiProgressBar, pi) - -int uiProgressBarValue(uiProgressBar *p) -{ - if ([p->pi isIndeterminate]) - return -1; - return [p->pi doubleValue]; -} - -void uiProgressBarSetValue(uiProgressBar *p, int value) -{ - if (value == -1) { - [p->pi setIndeterminate:YES]; - [p->pi startAnimation:p->pi]; - return; - } - - if ([p->pi isIndeterminate]) { - [p->pi setIndeterminate:NO]; - [p->pi stopAnimation:p->pi]; - } - - if (value < 0 || value > 100) - userbug("Value %d out of range for a uiProgressBar.", value); - - // on 10.8 there's an animation when the progress bar increases, just like with Aero - if (value == 100) { - [p->pi setMaxValue:101]; - [p->pi setDoubleValue:101]; - [p->pi setDoubleValue:100]; - [p->pi setMaxValue:100]; - return; - } - [p->pi setDoubleValue:((double) (value + 1))]; - [p->pi setDoubleValue:((double) value)]; -} - -uiProgressBar *uiNewProgressBar(void) -{ - uiProgressBar *p; - - uiDarwinNewControl(uiProgressBar, p); - - p->pi = [[intrinsicWidthNSProgressIndicator alloc] initWithFrame:NSZeroRect]; - [p->pi setControlSize:NSRegularControlSize]; - [p->pi setBezeled:YES]; - [p->pi setStyle:NSProgressIndicatorBarStyle]; - [p->pi setIndeterminate:NO]; - - return p; -} diff --git a/src/libui_sdl/libui/darwin/radiobuttons.m b/src/libui_sdl/libui/darwin/radiobuttons.m deleted file mode 100644 index 25d773c..0000000 --- a/src/libui_sdl/libui/darwin/radiobuttons.m +++ /dev/null @@ -1,207 +0,0 @@ -// 14 august 2015 -#import "uipriv_darwin.h" - -// TODO resizing the controlgallery vertically causes the third button to still resize :| - -// In the old days you would use a NSMatrix for this; as of OS X 10.8 this was deprecated and now you need just a bunch of NSButtons with the same superview AND same action method. -// This is documented on the NSMatrix page, but the rest of the OS X documentation says to still use NSMatrix. -// NSMatrix has weird quirks anyway... - -// LONGTERM 6 units of spacing between buttons, as suggested by Interface Builder? - -@interface radioButtonsDelegate : NSObject { - uiRadioButtons *libui_r; -} -- (id)initWithR:(uiRadioButtons *)r; -- (IBAction)onClicked:(id)sender; -@end - -struct uiRadioButtons { - uiDarwinControl c; - NSView *view; - NSMutableArray *buttons; - NSMutableArray *constraints; - NSLayoutConstraint *lastv; - radioButtonsDelegate *delegate; - void (*onSelected)(uiRadioButtons *, void *); - void *onSelectedData; -}; - -@implementation radioButtonsDelegate - -- (id)initWithR:(uiRadioButtons *)r -{ - self = [super init]; - if (self) - self->libui_r = r; - return self; -} - -- (IBAction)onClicked:(id)sender -{ - uiRadioButtons *r = self->libui_r; - - (*(r->onSelected))(r, r->onSelectedData); -} - -@end - -uiDarwinControlAllDefaultsExceptDestroy(uiRadioButtons, view) - -static void defaultOnSelected(uiRadioButtons *r, void *data) -{ - // do nothing -} - -static void uiRadioButtonsDestroy(uiControl *c) -{ - uiRadioButtons *r = uiRadioButtons(c); - NSButton *b; - - // drop the constraints - [r->view removeConstraints:r->constraints]; - [r->constraints release]; - if (r->lastv != nil) - [r->lastv release]; - // destroy the buttons - for (b in r->buttons) { - [b setTarget:nil]; - [b removeFromSuperview]; - } - [r->buttons release]; - // destroy the delegate - [r->delegate release]; - // and destroy ourselves - [r->view release]; - uiFreeControl(uiControl(r)); -} - -static NSButton *buttonAt(uiRadioButtons *r, int n) -{ - return (NSButton *) [r->buttons objectAtIndex:n]; -} - -void uiRadioButtonsAppend(uiRadioButtons *r, const char *text) -{ - NSButton *b, *b2; - NSLayoutConstraint *constraint; - - b = [[NSButton alloc] initWithFrame:NSZeroRect]; - [b setTitle:toNSString(text)]; - [b setButtonType:NSRadioButton]; - // doesn't seem to have an associated bezel style - [b setBordered:NO]; - [b setTransparent:NO]; - uiDarwinSetControlFont(b, NSRegularControlSize); - [b setTranslatesAutoresizingMaskIntoConstraints:NO]; - - [b setTarget:r->delegate]; - [b setAction:@selector(onClicked:)]; - - [r->buttons addObject:b]; - [r->view addSubview:b]; - - // pin horizontally to the edges of the superview - constraint = mkConstraint(b, NSLayoutAttributeLeading, - NSLayoutRelationEqual, - r->view, NSLayoutAttributeLeading, - 1, 0, - @"uiRadioButtons button leading constraint"); - [r->view addConstraint:constraint]; - [r->constraints addObject:constraint]; - constraint = mkConstraint(b, NSLayoutAttributeTrailing, - NSLayoutRelationEqual, - r->view, NSLayoutAttributeTrailing, - 1, 0, - @"uiRadioButtons button trailing constraint"); - [r->view addConstraint:constraint]; - [r->constraints addObject:constraint]; - - // if this is the first view, pin it to the top - // otherwise pin to the bottom of the last - if ([r->buttons count] == 1) - constraint = mkConstraint(b, NSLayoutAttributeTop, - NSLayoutRelationEqual, - r->view, NSLayoutAttributeTop, - 1, 0, - @"uiRadioButtons first button top constraint"); - else { - b2 = buttonAt(r, [r->buttons count] - 2); - constraint = mkConstraint(b, NSLayoutAttributeTop, - NSLayoutRelationEqual, - b2, NSLayoutAttributeBottom, - 1, 0, - @"uiRadioButtons non-first button top constraint"); - } - [r->view addConstraint:constraint]; - [r->constraints addObject:constraint]; - - // if there is a previous bottom constraint, remove it - if (r->lastv != nil) { - [r->view removeConstraint:r->lastv]; - [r->constraints removeObject:r->lastv]; - [r->lastv release]; - } - - // and make the new bottom constraint - r->lastv = mkConstraint(b, NSLayoutAttributeBottom, - NSLayoutRelationEqual, - r->view, NSLayoutAttributeBottom, - 1, 0, - @"uiRadioButtons last button bottom constraint"); - [r->view addConstraint:r->lastv]; - [r->constraints addObject:r->lastv]; - [r->lastv retain]; -} - -int uiRadioButtonsSelected(uiRadioButtons *r) -{ - NSButton *b; - NSUInteger i; - - for (i = 0; i < [r->buttons count]; i++) { - b = (NSButton *) [r->buttons objectAtIndex:i]; - if ([b state] == NSOnState) - return i; - } - return -1; -} - -void uiRadioButtonsSetSelected(uiRadioButtons *r, int n) -{ - NSButton *b; - NSInteger state; - - state = NSOnState; - if (n == -1) { - n = uiRadioButtonsSelected(r); - if (n == -1) // from nothing to nothing; do nothing - return; - state = NSOffState; - } - b = (NSButton *) [r->buttons objectAtIndex:n]; - [b setState:state]; -} - -void uiRadioButtonsOnSelected(uiRadioButtons *r, void (*f)(uiRadioButtons *, void *), void *data) -{ - r->onSelected = f; - r->onSelectedData = data; -} - -uiRadioButtons *uiNewRadioButtons(void) -{ - uiRadioButtons *r; - - uiDarwinNewControl(uiRadioButtons, r); - - r->view = [[NSView alloc] initWithFrame:NSZeroRect]; - r->buttons = [NSMutableArray new]; - r->constraints = [NSMutableArray new]; - - r->delegate = [[radioButtonsDelegate alloc] initWithR:r]; - - uiRadioButtonsOnSelected(r, defaultOnSelected, NULL); - - return r; -} diff --git a/src/libui_sdl/libui/darwin/scrollview.m b/src/libui_sdl/libui/darwin/scrollview.m deleted file mode 100644 index b0b4040..0000000 --- a/src/libui_sdl/libui/darwin/scrollview.m +++ /dev/null @@ -1,61 +0,0 @@ -// 27 may 2016 -#include "uipriv_darwin.h" - -// see http://stackoverflow.com/questions/37979445/how-do-i-properly-set-up-a-scrolling-nstableview-using-auto-layout-what-ive-tr for why we don't use auto layout -// TODO do the same with uiGroup and uiTab? - -struct scrollViewData { - BOOL hscroll; - BOOL vscroll; -}; - -NSScrollView *mkScrollView(struct scrollViewCreateParams *p, struct scrollViewData **dout) -{ - NSScrollView *sv; - NSBorderType border; - struct scrollViewData *d; - - sv = [[NSScrollView alloc] initWithFrame:NSZeroRect]; - if (p->BackgroundColor != nil) - [sv setBackgroundColor:p->BackgroundColor]; - [sv setDrawsBackground:p->DrawsBackground]; - border = NSNoBorder; - if (p->Bordered) - border = NSBezelBorder; - // document view seems to set the cursor properly - [sv setBorderType:border]; - [sv setAutohidesScrollers:YES]; - [sv setHasHorizontalRuler:NO]; - [sv setHasVerticalRuler:NO]; - [sv setRulersVisible:NO]; - [sv setScrollerKnobStyle:NSScrollerKnobStyleDefault]; - // the scroller style is documented as being set by default for us - // LONGTERM verify line and page for programmatically created NSTableView - [sv setScrollsDynamically:YES]; - [sv setFindBarPosition:NSScrollViewFindBarPositionAboveContent]; - [sv setUsesPredominantAxisScrolling:NO]; - [sv setHorizontalScrollElasticity:NSScrollElasticityAutomatic]; - [sv setVerticalScrollElasticity:NSScrollElasticityAutomatic]; - [sv setAllowsMagnification:NO]; - - [sv setDocumentView:p->DocumentView]; - d = uiNew(struct scrollViewData); - scrollViewSetScrolling(sv, d, p->HScroll, p->VScroll); - - *dout = d; - return sv; -} - -// based on http://blog.bjhomer.com/2014/08/nsscrollview-and-autolayout.html because (as pointed out there) Apple's official guide is really only for iOS -void scrollViewSetScrolling(NSScrollView *sv, struct scrollViewData *d, BOOL hscroll, BOOL vscroll) -{ - d->hscroll = hscroll; - [sv setHasHorizontalScroller:d->hscroll]; - d->vscroll = vscroll; - [sv setHasVerticalScroller:d->vscroll]; -} - -void scrollViewFreeData(NSScrollView *sv, struct scrollViewData *d) -{ - uiFree(d); -} diff --git a/src/libui_sdl/libui/darwin/separator.m b/src/libui_sdl/libui/darwin/separator.m deleted file mode 100644 index a37a376..0000000 --- a/src/libui_sdl/libui/darwin/separator.m +++ /dev/null @@ -1,45 +0,0 @@ -// 14 august 2015 -#import "uipriv_darwin.h" - -// TODO make this intrinsic -#define separatorWidth 96 -#define separatorHeight 96 - -struct uiSeparator { - uiDarwinControl c; - NSBox *box; -}; - -uiDarwinControlAllDefaults(uiSeparator, box) - -uiSeparator *uiNewHorizontalSeparator(void) -{ - uiSeparator *s; - - uiDarwinNewControl(uiSeparator, s); - - // make the initial width >= initial height to force horizontal - s->box = [[NSBox alloc] initWithFrame:NSMakeRect(0, 0, 100, 1)]; - [s->box setBoxType:NSBoxSeparator]; - [s->box setBorderType:NSGrooveBorder]; - [s->box setTransparent:NO]; - [s->box setTitlePosition:NSNoTitle]; - - return s; -} - -uiSeparator *uiNewVerticalSeparator(void) -{ - uiSeparator *s; - - uiDarwinNewControl(uiSeparator, s); - - // make the initial height >= initial width to force vertical - s->box = [[NSBox alloc] initWithFrame:NSMakeRect(0, 0, 1, 100)]; - [s->box setBoxType:NSBoxSeparator]; - [s->box setBorderType:NSGrooveBorder]; - [s->box setTransparent:NO]; - [s->box setTitlePosition:NSNoTitle]; - - return s; -} diff --git a/src/libui_sdl/libui/darwin/slider.m b/src/libui_sdl/libui/darwin/slider.m deleted file mode 100644 index f00da50..0000000 --- a/src/libui_sdl/libui/darwin/slider.m +++ /dev/null @@ -1,147 +0,0 @@ -// 14 august 2015 -#import "uipriv_darwin.h" - -// Horizontal sliders have no intrinsic width; we'll use the default Interface Builder width for them. -// This will also be used for the initial frame size, to ensure the slider is always horizontal (see below). -#define sliderWidth 92 - -@interface libui_intrinsicWidthNSSlider : NSSlider -@end - -@implementation libui_intrinsicWidthNSSlider - -- (NSSize)intrinsicContentSize -{ - NSSize s; - - s = [super intrinsicContentSize]; - s.width = sliderWidth; - return s; -} - -@end - -struct uiSlider { - uiDarwinControl c; - NSSlider *slider; - void (*onChanged)(uiSlider *, void *); - void *onChangedData; -}; - -@interface sliderDelegateClass : NSObject { - struct mapTable *sliders; -} -- (IBAction)onChanged:(id)sender; -- (void)registerSlider:(uiSlider *)b; -- (void)unregisterSlider:(uiSlider *)b; -@end - -@implementation sliderDelegateClass - -- (id)init -{ - self = [super init]; - if (self) - self->sliders = newMap(); - return self; -} - -- (void)dealloc -{ - mapDestroy(self->sliders); - [super dealloc]; -} - -- (IBAction)onChanged:(id)sender -{ - uiSlider *s; - - s = (uiSlider *) mapGet(self->sliders, sender); - (*(s->onChanged))(s, s->onChangedData); -} - -- (void)registerSlider:(uiSlider *)s -{ - mapSet(self->sliders, s->slider, s); - [s->slider setTarget:self]; - [s->slider setAction:@selector(onChanged:)]; -} - -- (void)unregisterSlider:(uiSlider *)s -{ - [s->slider setTarget:nil]; - mapDelete(self->sliders, s->slider); -} - -@end - -static sliderDelegateClass *sliderDelegate = nil; - -uiDarwinControlAllDefaultsExceptDestroy(uiSlider, slider) - -static void uiSliderDestroy(uiControl *c) -{ - uiSlider *s = uiSlider(c); - - [sliderDelegate unregisterSlider:s]; - [s->slider release]; - uiFreeControl(uiControl(s)); -} - -int uiSliderValue(uiSlider *s) -{ - return [s->slider integerValue]; -} - -void uiSliderSetValue(uiSlider *s, int value) -{ - [s->slider setIntegerValue:value]; -} - -void uiSliderOnChanged(uiSlider *s, void (*f)(uiSlider *, void *), void *data) -{ - s->onChanged = f; - s->onChangedData = data; -} - -static void defaultOnChanged(uiSlider *s, void *data) -{ - // do nothing -} - -uiSlider *uiNewSlider(int min, int max) -{ - uiSlider *s; - NSSliderCell *cell; - int temp; - - if (min >= max) { - temp = min; - min = max; - max = temp; - } - - uiDarwinNewControl(uiSlider, s); - - // a horizontal slider is defined as one where the width > height, not by a flag - // to be safe, don't use NSZeroRect, but make it horizontal from the get-go - s->slider = [[libui_intrinsicWidthNSSlider alloc] - initWithFrame:NSMakeRect(0, 0, sliderWidth, 2)]; - [s->slider setMinValue:min]; - [s->slider setMaxValue:max]; - [s->slider setAllowsTickMarkValuesOnly:NO]; - [s->slider setNumberOfTickMarks:0]; - [s->slider setTickMarkPosition:NSTickMarkAbove]; - - cell = (NSSliderCell *) [s->slider cell]; - [cell setSliderType:NSLinearSlider]; - - if (sliderDelegate == nil) { - sliderDelegate = [[sliderDelegateClass new] autorelease]; - [delegates addObject:sliderDelegate]; - } - [sliderDelegate registerSlider:s]; - uiSliderOnChanged(s, defaultOnChanged, NULL); - - return s; -} diff --git a/src/libui_sdl/libui/darwin/spinbox.m b/src/libui_sdl/libui/darwin/spinbox.m deleted file mode 100644 index 73474d0..0000000 --- a/src/libui_sdl/libui/darwin/spinbox.m +++ /dev/null @@ -1,214 +0,0 @@ -// 14 august 2015 -#import "uipriv_darwin.h" - -@interface libui_spinbox : NSView<NSTextFieldDelegate> { - NSTextField *tf; - NSNumberFormatter *formatter; - NSStepper *stepper; - - NSInteger value; - NSInteger minimum; - NSInteger maximum; - - uiSpinbox *spinbox; -} -- (id)initWithFrame:(NSRect)r spinbox:(uiSpinbox *)sb; -// see https://github.com/andlabs/ui/issues/82 -- (NSInteger)libui_value; -- (void)libui_setValue:(NSInteger)val; -- (void)setMinimum:(NSInteger)min; -- (void)setMaximum:(NSInteger)max; -- (IBAction)stepperClicked:(id)sender; -- (void)controlTextDidChange:(NSNotification *)note; -@end - -struct uiSpinbox { - uiDarwinControl c; - libui_spinbox *spinbox; - void (*onChanged)(uiSpinbox *, void *); - void *onChangedData; -}; - -// yes folks, this varies by operating system! woo! -// 10.10 started drawing the NSStepper one point too low, so we have to fix it up conditionally -// TODO test this; we'll probably have to substitute 10_9 -static CGFloat stepperYDelta(void) -{ - // via https://developer.apple.com/library/mac/releasenotes/AppKit/RN-AppKit/ - if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_9) - return 0; - return -1; -} - -@implementation libui_spinbox - -- (id)initWithFrame:(NSRect)r spinbox:(uiSpinbox *)sb -{ - self = [super initWithFrame:r]; - if (self) { - self->tf = newEditableTextField(); - [self->tf setTranslatesAutoresizingMaskIntoConstraints:NO]; - - self->formatter = [NSNumberFormatter new]; - [self->formatter setFormatterBehavior:NSNumberFormatterBehavior10_4]; - [self->formatter setLocalizesFormat:NO]; - [self->formatter setUsesGroupingSeparator:NO]; - [self->formatter setHasThousandSeparators:NO]; - [self->formatter setAllowsFloats:NO]; - [self->tf setFormatter:self->formatter]; - - self->stepper = [[NSStepper alloc] initWithFrame:NSZeroRect]; - [self->stepper setIncrement:1]; - [self->stepper setValueWraps:NO]; - [self->stepper setAutorepeat:YES]; // hold mouse button to step repeatedly - [self->stepper setTranslatesAutoresizingMaskIntoConstraints:NO]; - - [self->tf setDelegate:self]; - [self->stepper setTarget:self]; - [self->stepper setAction:@selector(stepperClicked:)]; - - [self addSubview:self->tf]; - [self addSubview:self->stepper]; - - [self addConstraint:mkConstraint(self->tf, NSLayoutAttributeLeading, - NSLayoutRelationEqual, - self, NSLayoutAttributeLeading, - 1, 0, - @"uiSpinbox left edge")]; - [self addConstraint:mkConstraint(self->stepper, NSLayoutAttributeTrailing, - NSLayoutRelationEqual, - self, NSLayoutAttributeTrailing, - 1, 0, - @"uiSpinbox right edge")]; - [self addConstraint:mkConstraint(self->tf, NSLayoutAttributeTop, - NSLayoutRelationEqual, - self, NSLayoutAttributeTop, - 1, 0, - @"uiSpinbox top edge text field")]; - [self addConstraint:mkConstraint(self->tf, NSLayoutAttributeBottom, - NSLayoutRelationEqual, - self, NSLayoutAttributeBottom, - 1, 0, - @"uiSpinbox bottom edge text field")]; - [self addConstraint:mkConstraint(self->stepper, NSLayoutAttributeTop, - NSLayoutRelationEqual, - self, NSLayoutAttributeTop, - 1, stepperYDelta(), - @"uiSpinbox top edge stepper")]; - [self addConstraint:mkConstraint(self->stepper, NSLayoutAttributeBottom, - NSLayoutRelationEqual, - self, NSLayoutAttributeBottom, - 1, stepperYDelta(), - @"uiSpinbox bottom edge stepper")]; - [self addConstraint:mkConstraint(self->tf, NSLayoutAttributeTrailing, - NSLayoutRelationEqual, - self->stepper, NSLayoutAttributeLeading, - 1, -3, // arbitrary amount; good enough visually (and it seems to match NSDatePicker too, at least on 10.11, which is even better) - @"uiSpinbox space between text field and stepper")]; - - self->spinbox = sb; - } - return self; -} - -- (void)dealloc -{ - [self->tf setDelegate:nil]; - [self->tf removeFromSuperview]; - [self->tf release]; - [self->formatter release]; - [self->stepper setTarget:nil]; - [self->stepper removeFromSuperview]; - [self->stepper release]; - [super dealloc]; -} - -- (NSInteger)libui_value -{ - return self->value; -} - -- (void)libui_setValue:(NSInteger)val -{ - self->value = val; - if (self->value < self->minimum) - self->value = self->minimum; - if (self->value > self->maximum) - self->value = self->maximum; - [self->tf setIntegerValue:self->value]; - [self->stepper setIntegerValue:self->value]; -} - -- (void)setMinimum:(NSInteger)min -{ - self->minimum = min; - [self->formatter setMinimum:[NSNumber numberWithInteger:self->minimum]]; - [self->stepper setMinValue:((double) (self->minimum))]; -} - -- (void)setMaximum:(NSInteger)max -{ - self->maximum = max; - [self->formatter setMaximum:[NSNumber numberWithInteger:self->maximum]]; - [self->stepper setMaxValue:((double) (self->maximum))]; -} - -- (IBAction)stepperClicked:(id)sender -{ - [self libui_setValue:[self->stepper integerValue]]; - (*(self->spinbox->onChanged))(self->spinbox, self->spinbox->onChangedData); -} - -- (void)controlTextDidChange:(NSNotification *)note -{ - [self libui_setValue:[self->tf integerValue]]; - (*(self->spinbox->onChanged))(self->spinbox, self->spinbox->onChangedData); -} - -@end - -uiDarwinControlAllDefaults(uiSpinbox, spinbox) - -int uiSpinboxValue(uiSpinbox *s) -{ - return [s->spinbox libui_value]; -} - -void uiSpinboxSetValue(uiSpinbox *s, int value) -{ - [s->spinbox libui_setValue:value]; -} - -void uiSpinboxOnChanged(uiSpinbox *s, void (*f)(uiSpinbox *, void *), void *data) -{ - s->onChanged = f; - s->onChangedData = data; -} - -static void defaultOnChanged(uiSpinbox *s, void *data) -{ - // do nothing -} - -uiSpinbox *uiNewSpinbox(int min, int max) -{ - uiSpinbox *s; - int temp; - - if (min >= max) { - temp = min; - min = max; - max = temp; - } - - uiDarwinNewControl(uiSpinbox, s); - - s->spinbox = [[libui_spinbox alloc] initWithFrame:NSZeroRect spinbox:s]; - [s->spinbox setMinimum:min]; - [s->spinbox setMaximum:max]; - [s->spinbox libui_setValue:min]; - - uiSpinboxOnChanged(s, defaultOnChanged, NULL); - - return s; -} diff --git a/src/libui_sdl/libui/darwin/stddialogs.m b/src/libui_sdl/libui/darwin/stddialogs.m deleted file mode 100644 index c826035..0000000 --- a/src/libui_sdl/libui/darwin/stddialogs.m +++ /dev/null @@ -1,123 +0,0 @@ -// 26 june 2015 -#import "uipriv_darwin.h" - -// LONGTERM restructure this whole file -// LONGTERM explicitly document this works as we want -// LONGTERM note that font and color buttons also do this - -#define windowWindow(w) ((NSWindow *) uiControlHandle(uiControl(w))) - -// source of code modal logic: http://stackoverflow.com/questions/604768/wait-for-nsalert-beginsheetmodalforwindow - -// note: whether extensions are actually shown depends on a user setting in Finder; we can't control it here -static void setupSavePanel(NSSavePanel *s) -{ - [s setCanCreateDirectories:YES]; - [s setShowsHiddenFiles:YES]; - [s setExtensionHidden:NO]; - [s setCanSelectHiddenExtension:NO]; - [s setTreatsFilePackagesAsDirectories:YES]; -} - -static char *runSavePanel(NSWindow *parent, NSSavePanel *s) -{ - char *filename; - - [s beginSheetModalForWindow:parent completionHandler:^(NSInteger result) { - [realNSApp() stopModalWithCode:result]; - }]; - if ([realNSApp() runModalForWindow:s] != NSFileHandlingPanelOKButton) - return NULL; - filename = uiDarwinNSStringToText([[s URL] path]); - return filename; -} - -char *uiOpenFile(uiWindow *parent, const char* filter, const char* initpath) -{ - NSOpenPanel *o; - - o = [NSOpenPanel openPanel]; - [o setCanChooseFiles:YES]; - [o setCanChooseDirectories:NO]; - [o setResolvesAliases:NO]; - [o setAllowsMultipleSelection:NO]; - setupSavePanel(o); - // panel is autoreleased - return runSavePanel(windowWindow(parent), o); -} - -char *uiSaveFile(uiWindow *parent, const char* filter, const char* initpath) -{ - NSSavePanel *s; - - s = [NSSavePanel savePanel]; - setupSavePanel(s); - // panel is autoreleased - return runSavePanel(windowWindow(parent), s); -} - -// I would use a completion handler for NSAlert as well, but alas NSAlert's are 10.9 and higher only -@interface libuiCodeModalAlertPanel : NSObject { - NSAlert *panel; - NSWindow *parent; -} -- (id)initWithPanel:(NSAlert *)p parent:(NSWindow *)w; -- (NSInteger)run; -- (void)panelEnded:(NSAlert *)panel result:(NSInteger)result data:(void *)data; -@end - -@implementation libuiCodeModalAlertPanel - -- (id)initWithPanel:(NSAlert *)p parent:(NSWindow *)w -{ - self = [super init]; - if (self) { - self->panel = p; - self->parent = w; - } - return self; -} - -- (NSInteger)run -{ - [self->panel beginSheetModalForWindow:self->parent - modalDelegate:self - didEndSelector:@selector(panelEnded:result:data:) - contextInfo:NULL]; - return [realNSApp() runModalForWindow:[self->panel window]]; -} - -- (void)panelEnded:(NSAlert *)panel result:(NSInteger)result data:(void *)data -{ - [realNSApp() stopModalWithCode:result]; -} - -@end - -static void msgbox(NSWindow *parent, const char *title, const char *description, NSAlertStyle style) -{ - NSAlert *a; - libuiCodeModalAlertPanel *cm; - - a = [NSAlert new]; - [a setAlertStyle:style]; - [a setShowsHelp:NO]; - [a setShowsSuppressionButton:NO]; - [a setMessageText:toNSString(title)]; - [a setInformativeText:toNSString(description)]; - [a addButtonWithTitle:@"OK"]; - cm = [[libuiCodeModalAlertPanel alloc] initWithPanel:a parent:parent]; - [cm run]; - [cm release]; - [a release]; -} - -void uiMsgBox(uiWindow *parent, const char *title, const char *description) -{ - msgbox(windowWindow(parent), title, description, NSInformationalAlertStyle); -} - -void uiMsgBoxError(uiWindow *parent, const char *title, const char *description) -{ - msgbox(windowWindow(parent), title, description, NSCriticalAlertStyle); -} diff --git a/src/libui_sdl/libui/darwin/tab.m b/src/libui_sdl/libui/darwin/tab.m deleted file mode 100644 index 3d2ca9f..0000000 --- a/src/libui_sdl/libui/darwin/tab.m +++ /dev/null @@ -1,292 +0,0 @@ -// 15 august 2015 -#import "uipriv_darwin.h" - -// TODO need to jiggle on tab change too (second page disabled tab label initially ambiguous) - -@interface tabPage : NSObject { - struct singleChildConstraints constraints; - int margined; - NSView *view; // the NSTabViewItem view itself - NSObject *pageID; -} -@property uiControl *c; -@property NSLayoutPriority oldHorzHuggingPri; -@property NSLayoutPriority oldVertHuggingPri; -- (id)initWithView:(NSView *)v pageID:(NSObject *)o; -- (NSView *)childView; -- (void)establishChildConstraints; -- (void)removeChildConstraints; -- (int)isMargined; -- (void)setMargined:(int)m; -@end - -struct uiTab { - uiDarwinControl c; - NSTabView *tabview; - NSMutableArray *pages; - NSLayoutPriority horzHuggingPri; - NSLayoutPriority vertHuggingPri; -}; - -@implementation tabPage - -- (id)initWithView:(NSView *)v pageID:(NSObject *)o -{ - self = [super init]; - if (self != nil) { - self->view = [v retain]; - self->pageID = [o retain]; - } - return self; -} - -- (void)dealloc -{ - [self removeChildConstraints]; - [self->view release]; - [self->pageID release]; - [super dealloc]; -} - -- (NSView *)childView -{ - return (NSView *) uiControlHandle(self.c); -} - -- (void)establishChildConstraints -{ - [self removeChildConstraints]; - if (self.c == NULL) - return; - singleChildConstraintsEstablish(&(self->constraints), - self->view, [self childView], - uiDarwinControlHugsTrailingEdge(uiDarwinControl(self.c)), - uiDarwinControlHugsBottom(uiDarwinControl(self.c)), - self->margined, - @"uiTab page"); -} - -- (void)removeChildConstraints -{ - singleChildConstraintsRemove(&(self->constraints), self->view); -} - -- (int)isMargined -{ - return self->margined; -} - -- (void)setMargined:(int)m -{ - self->margined = m; - singleChildConstraintsSetMargined(&(self->constraints), self->margined); -} - -@end - -static void uiTabDestroy(uiControl *c) -{ - uiTab *t = uiTab(c); - tabPage *page; - - // first remove all tab pages so we can destroy all the children - while ([t->tabview numberOfTabViewItems] != 0) - [t->tabview removeTabViewItem:[t->tabview tabViewItemAtIndex:0]]; - // then destroy all the children - for (page in t->pages) { - [page removeChildConstraints]; - uiControlSetParent(page.c, NULL); - uiDarwinControlSetSuperview(uiDarwinControl(page.c), nil); - uiControlDestroy(page.c); - } - // and finally destroy ourselves - [t->pages release]; - [t->tabview release]; - uiFreeControl(uiControl(t)); -} - -uiDarwinControlDefaultHandle(uiTab, tabview) -uiDarwinControlDefaultParent(uiTab, tabview) -uiDarwinControlDefaultSetParent(uiTab, tabview) -uiDarwinControlDefaultToplevel(uiTab, tabview) -uiDarwinControlDefaultVisible(uiTab, tabview) -uiDarwinControlDefaultShow(uiTab, tabview) -uiDarwinControlDefaultHide(uiTab, tabview) -uiDarwinControlDefaultEnabled(uiTab, tabview) -uiDarwinControlDefaultEnable(uiTab, tabview) -uiDarwinControlDefaultDisable(uiTab, tabview) - -static void uiTabSyncEnableState(uiDarwinControl *c, int enabled) -{ - uiTab *t = uiTab(c); - tabPage *page; - - if (uiDarwinShouldStopSyncEnableState(uiDarwinControl(t), enabled)) - return; - for (page in t->pages) - uiDarwinControlSyncEnableState(uiDarwinControl(page.c), enabled); -} - -uiDarwinControlDefaultSetSuperview(uiTab, tabview) - -static void tabRelayout(uiTab *t) -{ - tabPage *page; - - for (page in t->pages) - [page establishChildConstraints]; - // and this gets rid of some weird issues with regards to box alignment - jiggleViewLayout(t->tabview); -} - -BOOL uiTabHugsTrailingEdge(uiDarwinControl *c) -{ - uiTab *t = uiTab(c); - - return t->horzHuggingPri < NSLayoutPriorityWindowSizeStayPut; -} - -BOOL uiTabHugsBottom(uiDarwinControl *c) -{ - uiTab *t = uiTab(c); - - return t->vertHuggingPri < NSLayoutPriorityWindowSizeStayPut; -} - -static void uiTabChildEdgeHuggingChanged(uiDarwinControl *c) -{ - uiTab *t = uiTab(c); - - tabRelayout(t); -} - -static NSLayoutPriority uiTabHuggingPriority(uiDarwinControl *c, NSLayoutConstraintOrientation orientation) -{ - uiTab *t = uiTab(c); - - if (orientation == NSLayoutConstraintOrientationHorizontal) - return t->horzHuggingPri; - return t->vertHuggingPri; -} - -static void uiTabSetHuggingPriority(uiDarwinControl *c, NSLayoutPriority priority, NSLayoutConstraintOrientation orientation) -{ - uiTab *t = uiTab(c); - - if (orientation == NSLayoutConstraintOrientationHorizontal) - t->horzHuggingPri = priority; - else - t->vertHuggingPri = priority; - uiDarwinNotifyEdgeHuggingChanged(uiDarwinControl(t)); -} - -static void uiTabChildVisibilityChanged(uiDarwinControl *c) -{ - uiTab *t = uiTab(c); - - tabRelayout(t); -} - -void uiTabAppend(uiTab *t, const char *name, uiControl *child) -{ - uiTabInsertAt(t, name, [t->pages count], child); -} - -void uiTabInsertAt(uiTab *t, const char *name, int n, uiControl *child) -{ - tabPage *page; - NSView *view; - NSTabViewItem *i; - NSObject *pageID; - - uiControlSetParent(child, uiControl(t)); - - view = [[[NSView alloc] initWithFrame:NSZeroRect] autorelease]; - // note: if we turn off the autoresizing mask, nothing shows up - uiDarwinControlSetSuperview(uiDarwinControl(child), view); - uiDarwinControlSyncEnableState(uiDarwinControl(child), uiControlEnabledToUser(uiControl(t))); - - // the documentation says these can be nil but the headers say these must not be; let's be safe and make them non-nil anyway - pageID = [NSObject new]; - page = [[[tabPage alloc] initWithView:view pageID:pageID] autorelease]; - page.c = child; - - // don't hug, just in case we're a stretchy tab - page.oldHorzHuggingPri = uiDarwinControlHuggingPriority(uiDarwinControl(page.c), NSLayoutConstraintOrientationHorizontal); - page.oldVertHuggingPri = uiDarwinControlHuggingPriority(uiDarwinControl(page.c), NSLayoutConstraintOrientationVertical); - uiDarwinControlSetHuggingPriority(uiDarwinControl(page.c), NSLayoutPriorityDefaultLow, NSLayoutConstraintOrientationHorizontal); - uiDarwinControlSetHuggingPriority(uiDarwinControl(page.c), NSLayoutPriorityDefaultLow, NSLayoutConstraintOrientationVertical); - - [t->pages insertObject:page atIndex:n]; - - i = [[[NSTabViewItem alloc] initWithIdentifier:pageID] autorelease]; - [i setLabel:toNSString(name)]; - [i setView:view]; - [t->tabview insertTabViewItem:i atIndex:n]; - - tabRelayout(t); -} - -void uiTabDelete(uiTab *t, int n) -{ - tabPage *page; - uiControl *child; - NSTabViewItem *i; - - page = (tabPage *) [t->pages objectAtIndex:n]; - - uiDarwinControlSetHuggingPriority(uiDarwinControl(page.c), page.oldHorzHuggingPri, NSLayoutConstraintOrientationHorizontal); - uiDarwinControlSetHuggingPriority(uiDarwinControl(page.c), page.oldVertHuggingPri, NSLayoutConstraintOrientationVertical); - - child = page.c; - [page removeChildConstraints]; - [t->pages removeObjectAtIndex:n]; - - uiControlSetParent(child, NULL); - uiDarwinControlSetSuperview(uiDarwinControl(child), nil); - - i = [t->tabview tabViewItemAtIndex:n]; - [t->tabview removeTabViewItem:i]; - - tabRelayout(t); -} - -int uiTabNumPages(uiTab *t) -{ - return [t->pages count]; -} - -int uiTabMargined(uiTab *t, int n) -{ - tabPage *page; - - page = (tabPage *) [t->pages objectAtIndex:n]; - return [page isMargined]; -} - -void uiTabSetMargined(uiTab *t, int n, int margined) -{ - tabPage *page; - - page = (tabPage *) [t->pages objectAtIndex:n]; - [page setMargined:margined]; -} - -uiTab *uiNewTab(void) -{ - uiTab *t; - - uiDarwinNewControl(uiTab, t); - - t->tabview = [[NSTabView alloc] initWithFrame:NSZeroRect]; - // also good for NSTabView (same selector and everything) - uiDarwinSetControlFont((NSControl *) (t->tabview), NSRegularControlSize); - - t->pages = [NSMutableArray new]; - - // default to low hugging to not hug edges - t->horzHuggingPri = NSLayoutPriorityDefaultLow; - t->vertHuggingPri = NSLayoutPriorityDefaultLow; - - return t; -} diff --git a/src/libui_sdl/libui/darwin/text.m b/src/libui_sdl/libui/darwin/text.m deleted file mode 100644 index f0d3dab..0000000 --- a/src/libui_sdl/libui/darwin/text.m +++ /dev/null @@ -1,19 +0,0 @@ -// 10 april 2015 -#import "uipriv_darwin.h" - -char *uiDarwinNSStringToText(NSString *s) -{ - char *out; - - out = strdup([s UTF8String]); - if (out == NULL) { - fprintf(stderr, "memory exhausted in uiDarwinNSStringToText()\n"); - abort(); - } - return out; -} - -void uiFreeText(char *s) -{ - free(s); -} diff --git a/src/libui_sdl/libui/darwin/uipriv_darwin.h b/src/libui_sdl/libui/darwin/uipriv_darwin.h deleted file mode 100644 index 6bca87b..0000000 --- a/src/libui_sdl/libui/darwin/uipriv_darwin.h +++ /dev/null @@ -1,146 +0,0 @@ -// 6 january 2015 -#define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_8 -#define MAC_OS_X_VERSION_MAX_ALLOWED MAC_OS_X_VERSION_10_8 -#import <Cocoa/Cocoa.h> -#import "../ui.h" -#import "../ui_darwin.h" -#import "../common/uipriv.h" - -#if __has_feature(objc_arc) -#error Sorry, libui cannot be compiled with ARC. -#endif - -#define toNSString(str) [NSString stringWithUTF8String:(str)] -#define fromNSString(str) [(str) UTF8String] - -#ifndef NSAppKitVersionNumber10_9 -#define NSAppKitVersionNumber10_9 1265 -#endif - -/*TODO remove this*/typedef struct uiImage uiImage; - -// menu.m -@interface menuManager : NSObject { - struct mapTable *items; - BOOL hasQuit; - BOOL hasPreferences; - BOOL hasAbout; -} -@property (strong) NSMenuItem *quitItem; -@property (strong) NSMenuItem *preferencesItem; -@property (strong) NSMenuItem *aboutItem; -// NSMenuValidation is only informal -- (BOOL)validateMenuItem:(NSMenuItem *)item; -- (NSMenu *)makeMenubar; -@end -extern void finalizeMenus(void); -extern void uninitMenus(void); - -// main.m -@interface applicationClass : NSApplication -@end -// this is needed because NSApp is of type id, confusing clang -#define realNSApp() ((applicationClass *) NSApp) -@interface appDelegate : NSObject <NSApplicationDelegate> -@property (strong) menuManager *menuManager; -@end -#define appDelegate() ((appDelegate *) [realNSApp() delegate]) -struct nextEventArgs { - NSEventMask mask; - NSDate *duration; - // LONGTERM no NSRunLoopMode? - NSString *mode; - BOOL dequeue; -}; -extern int mainStep(struct nextEventArgs *nea, BOOL (^interceptEvent)(NSEvent *)); - -// util.m -extern void disableAutocorrect(NSTextView *); - -// entry.m -extern void finishNewTextField(NSTextField *, BOOL); -extern NSTextField *newEditableTextField(void); - -// window.m -@interface libuiNSWindow : NSWindow -- (void)libui_doMove:(NSEvent *)initialEvent; -- (void)libui_doResize:(NSEvent *)initialEvent on:(uiWindowResizeEdge)edge; -@end -extern uiWindow *windowFromNSWindow(NSWindow *); - -// alloc.m -extern NSMutableArray *delegates; -extern void initAlloc(void); -extern void uninitAlloc(void); - -// autolayout.m -extern NSLayoutConstraint *mkConstraint(id view1, NSLayoutAttribute attr1, NSLayoutRelation relation, id view2, NSLayoutAttribute attr2, CGFloat multiplier, CGFloat c, NSString *desc); -extern void jiggleViewLayout(NSView *view); -struct singleChildConstraints { - NSLayoutConstraint *leadingConstraint; - NSLayoutConstraint *topConstraint; - NSLayoutConstraint *trailingConstraintGreater; - NSLayoutConstraint *trailingConstraintEqual; - NSLayoutConstraint *bottomConstraintGreater; - NSLayoutConstraint *bottomConstraintEqual; -}; -extern void singleChildConstraintsEstablish(struct singleChildConstraints *c, NSView *contentView, NSView *childView, BOOL hugsTrailing, BOOL hugsBottom, int margined, NSString *desc); -extern void singleChildConstraintsRemove(struct singleChildConstraints *c, NSView *cv); -extern void singleChildConstraintsSetMargined(struct singleChildConstraints *c, int margined); - -// map.m -extern struct mapTable *newMap(void); -extern void mapDestroy(struct mapTable *m); -extern void *mapGet(struct mapTable *m, void *key); -extern void mapSet(struct mapTable *m, void *key, void *value); -extern void mapDelete(struct mapTable *m, void *key); -extern void mapWalk(struct mapTable *m, void (*f)(void *key, void *value)); -extern void mapReset(struct mapTable *m); - -// area.m -extern int sendAreaEvents(NSEvent *); - -// areaevents.m -extern BOOL fromKeycode(unsigned short keycode, uiAreaKeyEvent *ke); -extern BOOL keycodeModifier(unsigned short keycode, uiModifiers *mod); - -// draw.m -extern uiDrawContext *newContext(CGContextRef, CGFloat); -extern void freeContext(uiDrawContext *); - -// drawtext.m -extern uiDrawTextFont *mkTextFont(CTFontRef f, BOOL retain); -extern uiDrawTextFont *mkTextFontFromNSFont(NSFont *f); -extern void doDrawText(CGContextRef c, CGFloat cheight, double x, double y, uiDrawTextLayout *layout); - -// fontbutton.m -extern BOOL fontButtonInhibitSendAction(SEL sel, id from, id to); -extern BOOL fontButtonOverrideTargetForAction(SEL sel, id from, id to, id *override); -extern void setupFontPanel(void); - -// colorbutton.m -extern BOOL colorButtonInhibitSendAction(SEL sel, id from, id to); - -// scrollview.m -struct scrollViewCreateParams { - NSView *DocumentView; - NSColor *BackgroundColor; - BOOL DrawsBackground; - BOOL Bordered; - BOOL HScroll; - BOOL VScroll; -}; -struct scrollViewData; -extern NSScrollView *mkScrollView(struct scrollViewCreateParams *p, struct scrollViewData **dout); -extern void scrollViewSetScrolling(NSScrollView *sv, struct scrollViewData *d, BOOL hscroll, BOOL vscroll); -extern void scrollViewFreeData(NSScrollView *sv, struct scrollViewData *d); - -// label.m -extern NSTextField *newLabel(NSString *str); - -// image.m -extern NSImage *imageImage(uiImage *); - -// winmoveresize.m -extern void doManualMove(NSWindow *w, NSEvent *initialEvent); -extern void doManualResize(NSWindow *w, NSEvent *initialEvent, uiWindowResizeEdge edge); diff --git a/src/libui_sdl/libui/darwin/util.m b/src/libui_sdl/libui/darwin/util.m deleted file mode 100644 index ab87390..0000000 --- a/src/libui_sdl/libui/darwin/util.m +++ /dev/null @@ -1,15 +0,0 @@ -// 7 april 2015 -#import "uipriv_darwin.h" - -// LONGTERM do we really want to do this? make it an option? -void disableAutocorrect(NSTextView *tv) -{ - [tv setEnabledTextCheckingTypes:0]; - [tv setAutomaticDashSubstitutionEnabled:NO]; - // don't worry about automatic data detection; it won't change stringValue (thanks pretty_function in irc.freenode.net/#macdev) - [tv setAutomaticSpellingCorrectionEnabled:NO]; - [tv setAutomaticTextReplacementEnabled:NO]; - [tv setAutomaticQuoteSubstitutionEnabled:NO]; - [tv setAutomaticLinkDetectionEnabled:NO]; - [tv setSmartInsertDeleteEnabled:NO]; -} diff --git a/src/libui_sdl/libui/darwin/window.m b/src/libui_sdl/libui/darwin/window.m deleted file mode 100644 index 97c22e6..0000000 --- a/src/libui_sdl/libui/darwin/window.m +++ /dev/null @@ -1,407 +0,0 @@ -// 15 august 2015 -#import "uipriv_darwin.h" - -#define defaultStyleMask (NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask) - -struct uiWindow { - uiDarwinControl c; - NSWindow *window; - uiControl *child; - int margined; - int (*onClosing)(uiWindow *, void *); - void *onClosingData; - struct singleChildConstraints constraints; - void (*onContentSizeChanged)(uiWindow *, void *); - void *onContentSizeChangedData; - BOOL suppressSizeChanged; - int fullscreen; - int borderless; -}; - -@implementation libuiNSWindow - -- (void)libui_doMove:(NSEvent *)initialEvent -{ - doManualMove(self, initialEvent); -} - -- (void)libui_doResize:(NSEvent *)initialEvent on:(uiWindowResizeEdge)edge -{ - doManualResize(self, initialEvent, edge); -} - -@end - -@interface windowDelegateClass : NSObject<NSWindowDelegate> { - struct mapTable *windows; -} -- (BOOL)windowShouldClose:(id)sender; -- (void)windowDidResize:(NSNotification *)note; -- (void)windowDidEnterFullScreen:(NSNotification *)note; -- (void)windowDidExitFullScreen:(NSNotification *)note; -- (void)registerWindow:(uiWindow *)w; -- (void)unregisterWindow:(uiWindow *)w; -- (uiWindow *)lookupWindow:(NSWindow *)w; -@end - -@implementation windowDelegateClass - -- (id)init -{ - self = [super init]; - if (self) - self->windows = newMap(); - return self; -} - -- (void)dealloc -{ - mapDestroy(self->windows); - [super dealloc]; -} - -- (BOOL)windowShouldClose:(id)sender -{ - uiWindow *w; - - w = [self lookupWindow:((NSWindow *) sender)]; - // w should not be NULL; we are only the delegate of registered windows - if ((*(w->onClosing))(w, w->onClosingData)) - uiControlDestroy(uiControl(w)); - return NO; -} - -- (void)windowDidResize:(NSNotification *)note -{ - uiWindow *w; - - w = [self lookupWindow:((NSWindow *) [note object])]; - if (!w->suppressSizeChanged) - (*(w->onContentSizeChanged))(w, w->onContentSizeChangedData); -} - -- (void)windowDidEnterFullScreen:(NSNotification *)note -{ - uiWindow *w; - - w = [self lookupWindow:((NSWindow *) [note object])]; - if (!w->suppressSizeChanged) - w->fullscreen = 1; -} - -- (void)windowDidExitFullScreen:(NSNotification *)note -{ - uiWindow *w; - - w = [self lookupWindow:((NSWindow *) [note object])]; - if (!w->suppressSizeChanged) - w->fullscreen = 0; -} - -- (void)registerWindow:(uiWindow *)w -{ - mapSet(self->windows, w->window, w); - [w->window setDelegate:self]; -} - -- (void)unregisterWindow:(uiWindow *)w -{ - [w->window setDelegate:nil]; - mapDelete(self->windows, w->window); -} - -- (uiWindow *)lookupWindow:(NSWindow *)w -{ - uiWindow *v; - - v = uiWindow(mapGet(self->windows, w)); - // this CAN (and IS ALLOWED TO) return NULL, just in case we're called with some OS X-provided window as the key window - return v; -} - -@end - -static windowDelegateClass *windowDelegate = nil; - -static void removeConstraints(uiWindow *w) -{ - NSView *cv; - - cv = [w->window contentView]; - singleChildConstraintsRemove(&(w->constraints), cv); -} - -static void uiWindowDestroy(uiControl *c) -{ - uiWindow *w = uiWindow(c); - - // hide the window - [w->window orderOut:w->window]; - removeConstraints(w); - if (w->child != NULL) { - uiControlSetParent(w->child, NULL); - uiDarwinControlSetSuperview(uiDarwinControl(w->child), nil); - uiControlDestroy(w->child); - } - [windowDelegate unregisterWindow:w]; - [w->window release]; - uiFreeControl(uiControl(w)); -} - -uiDarwinControlDefaultHandle(uiWindow, window) - -uiControl *uiWindowParent(uiControl *c) -{ - return NULL; -} - -void uiWindowSetParent(uiControl *c, uiControl *parent) -{ - uiUserBugCannotSetParentOnToplevel("uiWindow"); -} - -static int uiWindowToplevel(uiControl *c) -{ - return 1; -} - -static int uiWindowVisible(uiControl *c) -{ - uiWindow *w = uiWindow(c); - - return [w->window isVisible]; -} - -static void uiWindowShow(uiControl *c) -{ - uiWindow *w = (uiWindow *) c; - - [w->window makeKeyAndOrderFront:w->window]; -} - -static void uiWindowHide(uiControl *c) -{ - uiWindow *w = (uiWindow *) c; - - [w->window orderOut:w->window]; -} - -uiDarwinControlDefaultEnabled(uiWindow, window) -uiDarwinControlDefaultEnable(uiWindow, window) -uiDarwinControlDefaultDisable(uiWindow, window) - -static void uiWindowSyncEnableState(uiDarwinControl *c, int enabled) -{ - uiWindow *w = uiWindow(c); - - if (uiDarwinShouldStopSyncEnableState(uiDarwinControl(w), enabled)) - return; - if (w->child != NULL) - uiDarwinControlSyncEnableState(uiDarwinControl(w->child), enabled); -} - -static void uiWindowSetSuperview(uiDarwinControl *c, NSView *superview) -{ - // TODO -} - -static void windowRelayout(uiWindow *w) -{ - NSView *childView; - NSView *contentView; - - removeConstraints(w); - if (w->child == NULL) - return; - childView = (NSView *) uiControlHandle(w->child); - contentView = [w->window contentView]; - singleChildConstraintsEstablish(&(w->constraints), - contentView, childView, - uiDarwinControlHugsTrailingEdge(uiDarwinControl(w->child)), - uiDarwinControlHugsBottom(uiDarwinControl(w->child)), - w->margined, - @"uiWindow"); -} - -uiDarwinControlDefaultHugsTrailingEdge(uiWindow, window) -uiDarwinControlDefaultHugsBottom(uiWindow, window) - -static void uiWindowChildEdgeHuggingChanged(uiDarwinControl *c) -{ - uiWindow *w = uiWindow(c); - - windowRelayout(w); -} - -// TODO -uiDarwinControlDefaultHuggingPriority(uiWindow, window) -uiDarwinControlDefaultSetHuggingPriority(uiWindow, window) -// end TODO - -static void uiWindowChildVisibilityChanged(uiDarwinControl *c) -{ - uiWindow *w = uiWindow(c); - - windowRelayout(w); -} - -char *uiWindowTitle(uiWindow *w) -{ - return uiDarwinNSStringToText([w->window title]); -} - -void uiWindowSetTitle(uiWindow *w, const char *title) -{ - [w->window setTitle:toNSString(title)]; -} - -void uiWindowContentSize(uiWindow *w, int *width, int *height) -{ - NSRect r; - - r = [w->window contentRectForFrameRect:[w->window frame]]; - *width = r.size.width; - *height = r.size.height; -} - -void uiWindowSetContentSize(uiWindow *w, int width, int height) -{ - w->suppressSizeChanged = YES; - [w->window setContentSize:NSMakeSize(width, height)]; - w->suppressSizeChanged = NO; -} - -int uiWindowFullscreen(uiWindow *w) -{ - return w->fullscreen; -} - -void uiWindowSetFullscreen(uiWindow *w, int fullscreen) -{ - if (w->fullscreen && fullscreen) - return; - if (!w->fullscreen && !fullscreen) - return; - w->fullscreen = fullscreen; - if (w->fullscreen && w->borderless) // borderless doesn't play nice with fullscreen; don't toggle while borderless - return; - w->suppressSizeChanged = YES; - [w->window toggleFullScreen:w->window]; - w->suppressSizeChanged = NO; - if (!w->fullscreen && w->borderless) // borderless doesn't play nice with fullscreen; restore borderless after removing - [w->window setStyleMask:NSBorderlessWindowMask]; -} - -void uiWindowOnContentSizeChanged(uiWindow *w, void (*f)(uiWindow *, void *), void *data) -{ - w->onContentSizeChanged = f; - w->onContentSizeChangedData = data; -} - -void uiWindowOnClosing(uiWindow *w, int (*f)(uiWindow *, void *), void *data) -{ - w->onClosing = f; - w->onClosingData = data; -} - -int uiWindowBorderless(uiWindow *w) -{ - return w->borderless; -} - -void uiWindowSetBorderless(uiWindow *w, int borderless) -{ - w->borderless = borderless; - if (w->borderless) { - // borderless doesn't play nice with fullscreen; wait for later - if (!w->fullscreen) - [w->window setStyleMask:NSBorderlessWindowMask]; - } else { - [w->window setStyleMask:defaultStyleMask]; - // borderless doesn't play nice with fullscreen; restore state - if (w->fullscreen) { - w->suppressSizeChanged = YES; - [w->window toggleFullScreen:w->window]; - w->suppressSizeChanged = NO; - } - } -} - -void uiWindowSetChild(uiWindow *w, uiControl *child) -{ - NSView *childView; - - if (w->child != NULL) { - childView = (NSView *) uiControlHandle(w->child); - [childView removeFromSuperview]; - uiControlSetParent(w->child, NULL); - } - w->child = child; - if (w->child != NULL) { - uiControlSetParent(w->child, uiControl(w)); - childView = (NSView *) uiControlHandle(w->child); - uiDarwinControlSetSuperview(uiDarwinControl(w->child), [w->window contentView]); - uiDarwinControlSyncEnableState(uiDarwinControl(w->child), uiControlEnabledToUser(uiControl(w))); - } - windowRelayout(w); -} - -int uiWindowMargined(uiWindow *w) -{ - return w->margined; -} - -void uiWindowSetMargined(uiWindow *w, int margined) -{ - w->margined = margined; - singleChildConstraintsSetMargined(&(w->constraints), w->margined); -} - -static int defaultOnClosing(uiWindow *w, void *data) -{ - return 0; -} - -static void defaultOnPositionContentSizeChanged(uiWindow *w, void *data) -{ - // do nothing -} - -uiWindow *uiNewWindow(const char *title, int width, int height, int hasMenubar) -{ - uiWindow *w; - - finalizeMenus(); - - uiDarwinNewControl(uiWindow, w); - - w->window = [[libuiNSWindow alloc] initWithContentRect:NSMakeRect(0, 0, (CGFloat) width, (CGFloat) height) - styleMask:defaultStyleMask - backing:NSBackingStoreBuffered - defer:YES]; - [w->window setTitle:toNSString(title)]; - - // do NOT release when closed - // we manually do this in uiWindowDestroy() above - [w->window setReleasedWhenClosed:NO]; - - if (windowDelegate == nil) { - windowDelegate = [[windowDelegateClass new] autorelease]; - [delegates addObject:windowDelegate]; - } - [windowDelegate registerWindow:w]; - uiWindowOnClosing(w, defaultOnClosing, NULL); - uiWindowOnContentSizeChanged(w, defaultOnPositionContentSizeChanged, NULL); - - return w; -} - -// utility function for menus -uiWindow *windowFromNSWindow(NSWindow *w) -{ - if (w == nil) - return NULL; - if (windowDelegate == nil) // no windows were created yet; we're called with some OS X-provided window - return NULL; - return [windowDelegate lookupWindow:w]; -} diff --git a/src/libui_sdl/libui/darwin/winmoveresize.m b/src/libui_sdl/libui/darwin/winmoveresize.m deleted file mode 100644 index 9145b7b..0000000 --- a/src/libui_sdl/libui/darwin/winmoveresize.m +++ /dev/null @@ -1,253 +0,0 @@ -// 1 november 2016 -#import "uipriv_darwin.h" - -// because we are changing the window frame each time the mouse moves, the successive -[NSEvent locationInWindow]s cannot be meaningfully used together -// make sure they are all following some sort of standard to avoid this problem; the screen is the most obvious possibility since it requires only one conversion (the only one that a NSWindow provides) -static NSPoint makeIndependent(NSPoint p, NSWindow *w) -{ - NSRect r; - - r.origin = p; - // mikeash in irc.freenode.net/#macdev confirms both that any size will do and that we can safely ignore the resultant size - r.size = NSZeroSize; - return [w convertRectToScreen:r].origin; -} - -struct onMoveDragParams { - NSWindow *w; - // using the previous point causes weird issues like the mouse seeming to fall behind the window edge... so do this instead - // TODO will this make things like the menubar and dock easier too? - NSRect initialFrame; - NSPoint initialPoint; -}; - -void onMoveDrag(struct onMoveDragParams *p, NSEvent *e) -{ - NSPoint new; - NSRect frame; - CGFloat offx, offy; - - new = makeIndependent([e locationInWindow], p->w); - frame = p->initialFrame; - - offx = new.x - p->initialPoint.x; - offy = new.y - p->initialPoint.y; - frame.origin.x += offx; - frame.origin.y += offy; - - // TODO handle the menubar - // TODO wait the system does this for us already?! - - [p->w setFrameOrigin:frame.origin]; -} - -void doManualMove(NSWindow *w, NSEvent *initialEvent) -{ - __block struct onMoveDragParams mdp; - struct nextEventArgs nea; - BOOL (^handleEvent)(NSEvent *e); - __block BOOL done; - - // this is only available on 10.11 and newer (LONGTERM FUTURE) - // but use it if available; this lets us use the real OS dragging code, which means we can take advantage of OS features like Spaces - if ([w respondsToSelector:@selector(performWindowDragWithEvent:)]) { - [((id) w) performWindowDragWithEvent:initialEvent]; - return; - } - - mdp.w = w; - mdp.initialFrame = [mdp.w frame]; - mdp.initialPoint = makeIndependent([initialEvent locationInWindow], mdp.w); - - nea.mask = NSLeftMouseDraggedMask | NSLeftMouseUpMask; - nea.duration = [NSDate distantFuture]; - nea.mode = NSEventTrackingRunLoopMode; // nextEventMatchingMask: docs suggest using this for manual mouse tracking - nea.dequeue = YES; - handleEvent = ^(NSEvent *e) { - if ([e type] == NSLeftMouseUp) { - done = YES; - return YES; // do not send - } - onMoveDrag(&mdp, e); - return YES; // do not send - }; - done = NO; - while (mainStep(&nea, handleEvent)) - if (done) - break; -} - -// see http://stackoverflow.com/a/40352996/3408572 -static void minMaxAutoLayoutSizes(NSWindow *w, NSSize *min, NSSize *max) -{ - NSLayoutConstraint *cw, *ch; - NSView *contentView; - NSRect prevFrame; - - // if adding these constraints causes the window to change size somehow, don't show it to the user and change it back afterwards - NSDisableScreenUpdates(); - prevFrame = [w frame]; - - // minimum: encourage the window to be as small as possible - contentView = [w contentView]; - cw = mkConstraint(contentView, NSLayoutAttributeWidth, - NSLayoutRelationEqual, - nil, NSLayoutAttributeNotAnAttribute, - 0, 0, - @"window minimum width finding constraint"); - [cw setPriority:NSLayoutPriorityDragThatCanResizeWindow]; - [contentView addConstraint:cw]; - ch = mkConstraint(contentView, NSLayoutAttributeHeight, - NSLayoutRelationEqual, - nil, NSLayoutAttributeNotAnAttribute, - 0, 0, - @"window minimum height finding constraint"); - [ch setPriority:NSLayoutPriorityDragThatCanResizeWindow]; - [contentView addConstraint:ch]; - *min = [contentView fittingSize]; - [contentView removeConstraint:cw]; - [contentView removeConstraint:ch]; - - // maximum: encourage the window to be as large as possible - contentView = [w contentView]; - cw = mkConstraint(contentView, NSLayoutAttributeWidth, - NSLayoutRelationEqual, - nil, NSLayoutAttributeNotAnAttribute, - 0, CGFLOAT_MAX, - @"window maximum width finding constraint"); - [cw setPriority:NSLayoutPriorityDragThatCanResizeWindow]; - [contentView addConstraint:cw]; - ch = mkConstraint(contentView, NSLayoutAttributeHeight, - NSLayoutRelationEqual, - nil, NSLayoutAttributeNotAnAttribute, - 0, CGFLOAT_MAX, - @"window maximum height finding constraint"); - [ch setPriority:NSLayoutPriorityDragThatCanResizeWindow]; - [contentView addConstraint:ch]; - *max = [contentView fittingSize]; - [contentView removeConstraint:cw]; - [contentView removeConstraint:ch]; - - [w setFrame:prevFrame display:YES]; // TODO really YES? - NSEnableScreenUpdates(); -} - -static void handleResizeLeft(NSRect *frame, NSPoint old, NSPoint new) -{ - frame->origin.x += new.x - old.x; - frame->size.width -= new.x - old.x; -} - -// TODO properly handle the menubar -// TODO wait, OS X does it for us?! -static void handleResizeTop(NSRect *frame, NSPoint old, NSPoint new) -{ - frame->size.height += new.y - old.y; -} - -static void handleResizeRight(NSRect *frame, NSPoint old, NSPoint new) -{ - frame->size.width += new.x - old.x; -} - - -// TODO properly handle the menubar -static void handleResizeBottom(NSRect *frame, NSPoint old, NSPoint new) -{ - frame->origin.y += new.y - old.y; - frame->size.height -= new.y - old.y; -} - -struct onResizeDragParams { - NSWindow *w; - // using the previous point causes weird issues like the mouse seeming to fall behind the window edge... so do this instead - // TODO will this make things like the menubar and dock easier too? - NSRect initialFrame; - NSPoint initialPoint; - uiWindowResizeEdge edge; - NSSize min; - NSSize max; -}; - -static void onResizeDrag(struct onResizeDragParams *p, NSEvent *e) -{ - NSPoint new; - NSRect frame; - - new = makeIndependent([e locationInWindow], p->w); - frame = p->initialFrame; - - // horizontal - switch (p->edge) { - case uiWindowResizeEdgeLeft: - case uiWindowResizeEdgeTopLeft: - case uiWindowResizeEdgeBottomLeft: - handleResizeLeft(&frame, p->initialPoint, new); - break; - case uiWindowResizeEdgeRight: - case uiWindowResizeEdgeTopRight: - case uiWindowResizeEdgeBottomRight: - handleResizeRight(&frame, p->initialPoint, new); - break; - } - // vertical - switch (p->edge) { - case uiWindowResizeEdgeTop: - case uiWindowResizeEdgeTopLeft: - case uiWindowResizeEdgeTopRight: - handleResizeTop(&frame, p->initialPoint, new); - break; - case uiWindowResizeEdgeBottom: - case uiWindowResizeEdgeBottomLeft: - case uiWindowResizeEdgeBottomRight: - handleResizeBottom(&frame, p->initialPoint, new); - break; - } - - // constrain - // TODO should we constrain against anything else as well? minMaxAutoLayoutSizes() already gives us nonnegative sizes, but... - if (frame.size.width < p->min.width) - frame.size.width = p->min.width; - if (frame.size.height < p->min.height) - frame.size.height = p->min.height; - // TODO > or >= ? - if (frame.size.width > p->max.width) - frame.size.width = p->max.width; - if (frame.size.height > p->max.height) - frame.size.height = p->max.height; - - [p->w setFrame:frame display:YES]; // and do reflect the new frame immediately -} - -// TODO do our events get fired with this? *should* they? -void doManualResize(NSWindow *w, NSEvent *initialEvent, uiWindowResizeEdge edge) -{ - __block struct onResizeDragParams rdp; - struct nextEventArgs nea; - BOOL (^handleEvent)(NSEvent *e); - __block BOOL done; - - rdp.w = w; - rdp.initialFrame = [rdp.w frame]; - rdp.initialPoint = makeIndependent([initialEvent locationInWindow], rdp.w); - rdp.edge = edge; - // TODO what happens if these change during the loop? - minMaxAutoLayoutSizes(rdp.w, &(rdp.min), &(rdp.max)); - - nea.mask = NSLeftMouseDraggedMask | NSLeftMouseUpMask; - nea.duration = [NSDate distantFuture]; - nea.mode = NSEventTrackingRunLoopMode; // nextEventMatchingMask: docs suggest using this for manual mouse tracking - nea.dequeue = YES; - handleEvent = ^(NSEvent *e) { - if ([e type] == NSLeftMouseUp) { - done = YES; - return YES; // do not send - } - onResizeDrag(&rdp, e); - return YES; // do not send - }; - done = NO; - while (mainStep(&nea, handleEvent)) - if (done) - break; -} |