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 c8ac8a6fea
commit 949cd56611
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;
NSScrollView *scrollView;
NSView *immediate; // the control that is added to the parent container; either view or scrollView
uintptr_t parent;
uiParent *parent;
BOOL userHid;
BOOL containerHid;
BOOL userDisabled;
@ -28,15 +28,15 @@ static uintptr_t singleHandle(uiControl *c)
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);
NSView *parentView;
s->parent = parent;
parentView = (NSView *) (s->parent);
parentView = (NSView *) uiParentHandle(s->parent);
[parentView addSubview:s->immediate];
updateParent(s->parent);
uiParentUpdate(s->parent);
}
static void singleRemoveParent(uiControl *c)
@ -47,7 +47,7 @@ static void singleRemoveParent(uiControl *c)
oldparent = s->parent;
s->parent = NULL;
[s->immediate removeFromSuperview];
updateParent(oldparent);
uiParentUpdate(oldparent);
}
// also good for NSBox and NSProgressIndicator
@ -95,7 +95,8 @@ static void singleShow(uiControl *c)
s->userHid = NO;
if (!s->containerHid) {
[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->immediate setHidden:YES];
updateParent(s->parent);
if (s->parent != NULL)
uiParentUpdate(s->parent);
}
static void singleContainerShow(uiControl *c)
@ -115,7 +117,8 @@ static void singleContainerShow(uiControl *c)
s->containerHid = NO;
if (!s->userHid) {
[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->immediate setHidden:YES];
updateParent(s->parent);
if (s->parent != NULL)
uiParentUpdate(s->parent);
}
static void enable(singleView *s)

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

View File

@ -31,13 +31,10 @@ extern NSView *destroyedControlsView;
extern void setStandardControlFont(NSControl *);
extern void disableAutocorrect(NSTextView *);
// container_darwin.m
@interface uiContainer : NSView
@property uiControl *uiChild;
- (void)uiUpdateNow;
- (BOOL)uiMargined;
- (void)uiSetMargined:(BOOL)margined;
@end
// 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
// entry_darwin.m
extern void finishNewTextField(NSTextField *, BOOL);

View File

@ -6,7 +6,7 @@
@interface uiWindowDelegate : NSObject <NSWindowDelegate>
@property (assign) NSWindow *w;
@property (assign) uiContainer *container;
@property uiParent *content;
@property int (*onClosing)(uiWindow *, void *);
@property void *onClosingData;
@property uiWindow *uiw;
@ -30,11 +30,11 @@ uiLogObjCClassAllocations
[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)
// this may not happen under certain conditions
// 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
// 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
// because we need to set the content view's superview to the destroyed controls view to trigger deletion, we need to do this manually
// first, replace the current content view...
[self.w setContentView:[[NSView alloc] initWithFrame:NSZeroRect]];
// ...then, trigger the deletion
[destroyedControlsView addSubview:((NSView *) uiParentHandle(self.content))];
uiFree(self.uiw);
[self release];
@ -44,6 +44,7 @@ uiLogObjCClassAllocations
struct uiWindow {
uiWindowDelegate *d;
int margined;
};
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
[d.w setReleasedWhenClosed:YES];
d.container = [[uiContainer alloc] initWithFrame:NSZeroRect];
[d.w setContentView:d.container];
d.content = uiNewParent(0);
[d.w setContentView:((NSView *) uiParentHandle(d.content))];
d.onClosing = defaultOnClosing;
[d.w setDelegate:d];
@ -125,23 +126,20 @@ void uiWindowOnClosing(uiWindow *w, int (*f)(uiWindow *, void *), void *data)
void uiWindowSetChild(uiWindow *w, uiControl *c)
{
D.container.uiChild = c;
uiControlSetParent(D.container.uiChild, (uintptr_t) (D.container));
uiParentSetChild(D.content, c);
}
int uiWindowMargined(uiWindow *w)
{
if ([D.container uiMargined])
return 1;
return 0;
return w->margined;
}
void uiWindowSetMargined(uiWindow *w, int margined)
{
BOOL m;
m = NO;
if (margined)
m = YES;
[D.container uiSetMargined:m];
w->margined = margined;
if (w->margined)
uiParentSetMargins(D.content, macXMargin, macYMargin, macXMargin, macYMargin);
else
uiParentSetMargins(D.content, 0, 0, 0, 0);
uiParentUpdate(D.content);
}