Converted and fixed the Mac OS X code for uiParent. I'm still not happy, but this is DEFINITELY a step in the right direction... Perhaps automatic deletion is a pipe dream :/ I should also really nail the parenting/unparenting logic, but for that I need to add one more method.

This commit is contained in:
Pietro Gagliardi 2015-04-13 12:53:05 -04:00
parent e4147f14af
commit 963feb6c06
6 changed files with 156 additions and 124 deletions

View File

@ -1,85 +0,0 @@
// 4 august 2014
#import "uipriv_darwin.h"
// calling -[className] on the content views of NSWindow, NSTabItem, and NSBox all return NSView, so I'm assuming I just need to override these
// fornunately:
// - NSWindow resizing calls -[setFrameSize:] (but not -[setFrame:])
// - NSTab resizing calls both -[setFrame:] and -[setFrameSIze:] on the current tab
// - NSTab switching tabs calls both -[setFrame:] and -[setFrameSize:] on the new tab
// so we just override setFrameSize:
// thanks to mikeash and JtRip in irc.freenode.net/#macdev
@implementation uiContainer {
BOOL uimargined;
}
uiLogObjCClassAllocations
- (void)viewDidMoveToSuperview
{
if ([self superview] == destroyedControlsView)
if (self.uiChild != NULL) {
uiControlDestroy(self.uiChild);
self.uiChild = NULL;
}
[super viewDidMoveToSuperview];
}
- (void)setFrameSize:(NSSize)s
{
[super setFrameSize:s];
[self uiUpdateNow];
}
// These are based on measurements from Interface Builder.
// These seem to be based on Auto Layout constants, but I don't see an API that exposes these...
#define macXMargin 20
#define macYMargin 20
// This one is 8 for most pairs of controls that I've tried; the only difference is between two pushbuttons, where it's 12...
#define macXPadding 8
// Likewise, this one appears to be 12 for pairs of push buttons...
#define macYPadding 8
- (void)uiUpdateNow
{
uiSizing d;
intmax_t x, y, width, height;
if (self.uiChild == NULL)
return;
x = [self bounds].origin.x;
y = [self bounds].origin.y;
width = [self bounds].size.width;
height = [self bounds].size.height;
if (self->uimargined) {
x += macXMargin;
y += macYMargin;
width -= 2 * macXMargin;
height -= 2 * macYMargin;
}
d.xPadding = macXPadding;
d.yPadding = macYPadding;
uiControlResize(self.uiChild, x, y, width, height, &d);
}
- (BOOL)uiMargined
{
return self->uimargined;
}
- (void)uiSetMargined:(BOOL)margined
{
self->uimargined = margined;
[self uiUpdateNow];
}
@end
void updateParent(uintptr_t parent)
{
uiContainer *c;
if (parent == 0)
return;
c = (uiContainer *) parent;
[c uiUpdateNow];
}

View File

@ -7,7 +7,7 @@ struct singleView {
NSView *view; NSView *view;
NSScrollView *scrollView; NSScrollView *scrollView;
NSView *immediate; // the control that is added to the parent container; either view or scrollView NSView *immediate; // the control that is added to the parent container; either view or scrollView
uintptr_t parent; uiParent *parent;
BOOL userHid; BOOL userHid;
BOOL containerHid; BOOL containerHid;
BOOL userDisabled; BOOL userDisabled;
@ -28,15 +28,15 @@ static uintptr_t singleHandle(uiControl *c)
return (uintptr_t) (s->view); return (uintptr_t) (s->view);
} }
static void singleSetParent(uiControl *c, uintptr_t parent) static void singleSetParent(uiControl *c, uiParent *parent)
{ {
singleView *s = (singleView *) (c->internal); singleView *s = (singleView *) (c->internal);
NSView *parentView; NSView *parentView;
s->parent = parent; s->parent = parent;
parentView = (NSView *) (s->parent); parentView = (NSView *) uiParentHandle(s->parent);
[parentView addSubview:s->immediate]; [parentView addSubview:s->immediate];
updateParent(s->parent); uiParentUpdate(s->parent);
} }
static void singleRemoveParent(uiControl *c) static void singleRemoveParent(uiControl *c)
@ -47,7 +47,7 @@ static void singleRemoveParent(uiControl *c)
oldparent = s->parent; oldparent = s->parent;
s->parent = NULL; s->parent = NULL;
[s->immediate removeFromSuperview]; [s->immediate removeFromSuperview];
updateParent(oldparent); uiParentUpdate(oldparent);
} }
// also good for NSBox and NSProgressIndicator // also good for NSBox and NSProgressIndicator
@ -95,7 +95,8 @@ static void singleShow(uiControl *c)
s->userHid = NO; s->userHid = NO;
if (!s->containerHid) { if (!s->containerHid) {
[s->immediate setHidden:NO]; [s->immediate setHidden:NO];
updateParent(s->parent); if (s->parent != NULL)
uiParentUpdate(s->parent);
} }
} }
@ -105,7 +106,8 @@ static void singleHide(uiControl *c)
s->userHid = YES; s->userHid = YES;
[s->immediate setHidden:YES]; [s->immediate setHidden:YES];
updateParent(s->parent); if (s->parent != NULL)
uiParentUpdate(s->parent);
} }
static void singleContainerShow(uiControl *c) static void singleContainerShow(uiControl *c)
@ -115,7 +117,8 @@ static void singleContainerShow(uiControl *c)
s->containerHid = NO; s->containerHid = NO;
if (!s->userHid) { if (!s->userHid) {
[s->immediate setHidden:NO]; [s->immediate setHidden:NO];
updateParent(s->parent); if (s->parent != NULL)
uiParentUpdate(s->parent);
} }
} }
@ -125,7 +128,8 @@ static void singleContainerHide(uiControl *c)
s->containerHid = YES; s->containerHid = YES;
[s->immediate setHidden:YES]; [s->immediate setHidden:YES];
updateParent(s->parent); if (s->parent != NULL)
uiParentUpdate(s->parent);
} }
static void enable(singleView *s) static void enable(singleView *s)

118
new/parent_darwin.m Normal file
View File

@ -0,0 +1,118 @@
// 4 august 2014
#import "uipriv_darwin.h"
// calling -[className] on the content views of NSWindow, NSTabItem, and NSBox all return NSView, so I'm assuming I just need to override these
// fornunately:
// - NSWindow resizing calls -[setFrameSize:] (but not -[setFrame:])
// - NSTabView resizing calls both -[setFrame:] and -[setFrameSIze:] on the current tab
// - NSTabView switching tabs calls both -[setFrame:] and -[setFrameSize:] on the new tab
// so we just override setFrameSize:
// thanks to mikeash and JtRip in irc.freenode.net/#macdev
@interface uipParent : NSView {
// TODO
@public
uiControl *child;
intmax_t marginLeft;
intmax_t marginTop;
intmax_t marginRight;
intmax_t marginBottom;
}
- (void)uiUpdateNow;
@end
@implementation uipParent
uiLogObjCClassAllocations
- (void)viewDidMoveToSuperview
{
// we can't just use nil because NSTabView will set page views to nil when they're tabbed away
// this means that we have to explicitly move them to the destroyed controls view when we're done with them, and likewise in NSWindow
if ([self superview] == destroyedControlsView)
if (self->child != NULL) {
uiControlDestroy(self->child);
self->child = NULL;
[self release];
}
[super viewDidMoveToSuperview];
}
- (void)setFrameSize:(NSSize)s
{
[super setFrameSize:s];
[self uiUpdateNow];
}
// These are based on measurements from Interface Builder.
// These seem to be based on Auto Layout constants, but I don't see an API that exposes these...
// This one is 8 for most pairs of controls that I've tried; the only difference is between two pushbuttons, where it's 12...
#define macXPadding 8
// Likewise, this one appears to be 12 for pairs of push buttons...
#define macYPadding 8
- (void)uiUpdateNow
{
uiSizing d;
intmax_t x, y, width, height;
if (self->child == NULL)
return;
x = [self bounds].origin.x + self->marginLeft;
y = [self bounds].origin.y + self->marginTop;
width = [self bounds].size.width - (self->marginLeft + self->marginRight);
height = [self bounds].size.height - (self->marginTop + self->marginBottom);
d.xPadding = macXPadding;
d.yPadding = macYPadding;
uiControlResize(self->child, x, y, width, height, &d);
}
@end
static uintptr_t parentHandle(uiParent *p)
{
uipParent *pp = (uipParent *) (p->Internal);
return (uintptr_t) pp;
}
static void parentSetChild(uiParent *p, uiControl *child)
{
uipParent *pp = (uipParent *) (p->Internal);
pp->child = child;
if (pp->child != NULL)
uiControlSetParent(child, p);
}
static void parentSetMargins(uiParent *p, intmax_t left, intmax_t top, intmax_t right, intmax_t bottom)
{
uipParent *pp = (uipParent *) (p->Internal);
pp->marginLeft = left;
pp->marginTop = top;
pp->marginRight = right;
pp->marginBottom = bottom;
}
static void parentUpdate(uiParent *p)
{
uipParent *pp = (uipParent *) (p->Internal);
[pp uiUpdateNow];
}
uiParent *uiNewParent(uintptr_t osParent)
{
uiParent *p;
p = uiNew(uiParent);
p->Internal = [[uipParent alloc] initWithFrame:NSZeroRect];
p->Handle = parentHandle;
p->SetChild = parentSetChild;
p->SetMargins = parentSetMargins;
p->Update = parentUpdate;
// don't use osParent; we'll need to call specific selectors to set the parent view
// and keep the view alive so we can release it properly later
[((uipParent *) (p->Internal)) retain];
return p;
}

View File

@ -13,6 +13,7 @@
- (void)viewDidMoveToSuperview - (void)viewDidMoveToSuperview
{ {
// TODO free all tabs explicitly
if (uiDarwinControlFreeWhenAppropriate(self.uiC, [self superview])) if (uiDarwinControlFreeWhenAppropriate(self.uiC, [self superview]))
self.uiC = NULL; self.uiC = NULL;
[super viewDidMoveToSuperview]; [super viewDidMoveToSuperview];
@ -52,16 +53,15 @@ uiControl *uiNewTab(void)
void uiTabAddPage(uiControl *c, const char *name, uiControl *child) void uiTabAddPage(uiControl *c, const char *name, uiControl *child)
{ {
uiNSTabView *tv; uiNSTabView *tv;
uiContainer *container; uiParent *content;
NSTabViewItem *i; NSTabViewItem *i;
container = [[uiContainer alloc] initWithFrame:NSZeroRect]; content = uiNewParent(0);
container.uiChild = child; uiParentSetChild(content, child);
uiControlSetParent(container.uiChild, (uintptr_t) container);
i = [[NSTabViewItem alloc] initWithIdentifier:nil]; i = [[NSTabViewItem alloc] initWithIdentifier:nil];
[i setLabel:toNSString(name)]; [i setLabel:toNSString(name)];
[i setView:container]; [i setView:((NSView *) uiParentHandle(content))];
tv = (uiNSTabView *) uiControlHandle(c); tv = (uiNSTabView *) uiControlHandle(c);
[tv addTabViewItem:i]; [tv addTabViewItem:i];
} }

View File

@ -31,13 +31,10 @@ extern NSView *destroyedControlsView;
extern void setStandardControlFont(NSControl *); extern void setStandardControlFont(NSControl *);
extern void disableAutocorrect(NSTextView *); extern void disableAutocorrect(NSTextView *);
// container_darwin.m // These are based on measurements from Interface Builder.
@interface uiContainer : NSView // These seem to be based on Auto Layout constants, but I don't see an API that exposes these...
@property uiControl *uiChild; #define macXMargin 20
- (void)uiUpdateNow; #define macYMargin 20
- (BOOL)uiMargined;
- (void)uiSetMargined:(BOOL)margined;
@end
// entry_darwin.m // entry_darwin.m
extern void finishNewTextField(NSTextField *, BOOL); extern void finishNewTextField(NSTextField *, BOOL);

View File

@ -6,7 +6,7 @@
@interface uiWindowDelegate : NSObject <NSWindowDelegate> @interface uiWindowDelegate : NSObject <NSWindowDelegate>
@property (assign) NSWindow *w; @property (assign) NSWindow *w;
@property (assign) uiContainer *container; @property uiParent *content;
@property int (*onClosing)(uiWindow *, void *); @property int (*onClosing)(uiWindow *, void *);
@property void *onClosingData; @property void *onClosingData;
@property uiWindow *uiw; @property uiWindow *uiw;
@ -30,11 +30,11 @@ uiLogObjCClassAllocations
[self.w setDelegate:nil]; // see http://stackoverflow.com/a/29523141/3408572 [self.w setDelegate:nil]; // see http://stackoverflow.com/a/29523141/3408572
// when we reach this point, we need to ensure that all the window's children are destroyed (for OS parity) // when we reach this point, we need to ensure that all the window's children are destroyed (for OS parity)
// this may not happen under certain conditions // because we need to set the content view's superview to the destroyed controls view to trigger deletion, we need to do this manually
// I'm not sure if calling uiQuit() in the close handler causes whatever causes our window to release its content view during deallocation to race with uiQuit()'s stopping of the run loop but that's one symptom I've noticed // first, replace the current content view...
// so let's manually change the content view now
// we'll set it to a new stock view; this should be enough to set our real container's superview to nil, triggering the destruction
[self.w setContentView:[[NSView alloc] initWithFrame:NSZeroRect]]; [self.w setContentView:[[NSView alloc] initWithFrame:NSZeroRect]];
// ...then, trigger the deletion
[destroyedControlsView addSubview:((NSView *) uiParentHandle(self.content))];
uiFree(self.uiw); uiFree(self.uiw);
[self release]; [self release];
@ -44,6 +44,7 @@ uiLogObjCClassAllocations
struct uiWindow { struct uiWindow {
uiWindowDelegate *d; uiWindowDelegate *d;
int margined;
}; };
static int defaultOnClosing(uiWindow *w, void *data) static int defaultOnClosing(uiWindow *w, void *data)
@ -74,8 +75,8 @@ uiWindow *uiNewWindow(char *title, int width, int height)
// this is what will destroy the window on close // this is what will destroy the window on close
[d.w setReleasedWhenClosed:YES]; [d.w setReleasedWhenClosed:YES];
d.container = [[uiContainer alloc] initWithFrame:NSZeroRect]; d.content = uiNewParent(0);
[d.w setContentView:d.container]; [d.w setContentView:((NSView *) uiParentHandle(d.content))];
d.onClosing = defaultOnClosing; d.onClosing = defaultOnClosing;
[d.w setDelegate:d]; [d.w setDelegate:d];
@ -125,23 +126,20 @@ void uiWindowOnClosing(uiWindow *w, int (*f)(uiWindow *, void *), void *data)
void uiWindowSetChild(uiWindow *w, uiControl *c) void uiWindowSetChild(uiWindow *w, uiControl *c)
{ {
D.container.uiChild = c; uiParentSetChild(D.content, c);
uiControlSetParent(D.container.uiChild, (uintptr_t) (D.container));
} }
int uiWindowMargined(uiWindow *w) int uiWindowMargined(uiWindow *w)
{ {
if ([D.container uiMargined]) return w->margined;
return 1;
return 0;
} }
void uiWindowSetMargined(uiWindow *w, int margined) void uiWindowSetMargined(uiWindow *w, int margined)
{ {
BOOL m; w->margined = margined;
if (w->margined)
m = NO; uiParentSetMargins(D.content, macXMargin, macYMargin, macXMargin, macYMargin);
if (margined) else
m = YES; uiParentSetMargins(D.content, 0, 0, 0, 0);
[D.container uiSetMargined:m]; uiParentUpdate(D.content);
} }