Removed a whole bunch of files from the old source tree.
This commit is contained in:
parent
ca487ad18d
commit
bf401201f9
397
box.c
397
box.c
|
@ -1,397 +0,0 @@
|
|||
// 7 april 2015
|
||||
#include "uipriv.h"
|
||||
|
||||
typedef struct box box;
|
||||
typedef struct boxControl boxControl;
|
||||
|
||||
struct box {
|
||||
uiBox s;
|
||||
boxControl *controls;
|
||||
uintmax_t len;
|
||||
uintmax_t cap;
|
||||
int vertical;
|
||||
uiParent *parent;
|
||||
int padded;
|
||||
int userHid;
|
||||
int containerHid;
|
||||
int userDisabled;
|
||||
int containerDisabled;
|
||||
};
|
||||
|
||||
struct boxControl {
|
||||
uiControl *c;
|
||||
int stretchy;
|
||||
intmax_t width; // both used by resize(); preallocated to save time and reduce risk of failure
|
||||
intmax_t height;
|
||||
};
|
||||
|
||||
static void boxDestroy(uiControl *c)
|
||||
{
|
||||
box *b = (box *) c;
|
||||
uintmax_t i;
|
||||
|
||||
if (b->parent != NULL)
|
||||
complain("attempt to destroy a uiControl at %p while it still has a parent %p", c, b->parent);
|
||||
for (i = 0; i < b->len; i++)
|
||||
uiControlDestroy(b->controls[i].c);
|
||||
uiFree(b->controls);
|
||||
uiFree(b);
|
||||
}
|
||||
|
||||
static uintptr_t boxHandle(uiControl *c)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void boxSetParent(uiControl *c, uiParent *parent)
|
||||
{
|
||||
box *b = (box *) c;
|
||||
uintmax_t i;
|
||||
uiParent *oldparent;
|
||||
|
||||
oldparent = b->parent;
|
||||
b->parent = parent;
|
||||
for (i = 0; i < b->len; i++)
|
||||
uiControlSetParent(b->controls[i].c, b->parent);
|
||||
if (oldparent != NULL)
|
||||
uiParentUpdate(oldparent);
|
||||
if (b->parent != NULL)
|
||||
uiParentUpdate(b->parent);
|
||||
}
|
||||
|
||||
static void boxPreferredSize(uiControl *c, uiSizing *d, intmax_t *width, intmax_t *height)
|
||||
{
|
||||
box *b = (box *) c;
|
||||
int xpadding, ypadding;
|
||||
uintmax_t nStretchy;
|
||||
// these two contain the largest preferred width and height of all stretchy controls in the box
|
||||
// all stretchy controls will use this value to determine the final preferred size
|
||||
intmax_t maxStretchyWidth, maxStretchyHeight;
|
||||
uintmax_t i;
|
||||
intmax_t preferredWidth, preferredHeight;
|
||||
|
||||
*width = 0;
|
||||
*height = 0;
|
||||
if (b->len == 0)
|
||||
return;
|
||||
|
||||
// 0) get this Box's padding
|
||||
xpadding = 0;
|
||||
ypadding = 0;
|
||||
if (b->padded) {
|
||||
xpadding = d->xPadding;
|
||||
ypadding = d->yPadding;
|
||||
}
|
||||
|
||||
// 1) initialize the desired rect with the needed padding
|
||||
if (b->vertical)
|
||||
*height = (b->len - 1) * ypadding;
|
||||
else
|
||||
*width = (b->len - 1) * xpadding;
|
||||
|
||||
// 2) add in the size of non-stretchy controls and get (but not add in) the largest widths and heights of stretchy controls
|
||||
// we still add in like direction of stretchy controls
|
||||
nStretchy = 0;
|
||||
maxStretchyWidth = 0;
|
||||
maxStretchyHeight = 0;
|
||||
for (i = 0; i < b->len; i++) {
|
||||
if (!uiControlVisible(b->controls[i].c))
|
||||
continue;
|
||||
uiControlPreferredSize(b->controls[i].c, d, &preferredWidth, &preferredHeight);
|
||||
if (b->controls[i].stretchy) {
|
||||
nStretchy++;
|
||||
if (maxStretchyWidth < preferredWidth)
|
||||
maxStretchyWidth = preferredWidth;
|
||||
if (maxStretchyHeight < preferredHeight)
|
||||
maxStretchyHeight = preferredHeight;
|
||||
}
|
||||
if (b->vertical) {
|
||||
if (*width < preferredWidth)
|
||||
*width = preferredWidth;
|
||||
if (!b->controls[i].stretchy)
|
||||
*height += preferredHeight;
|
||||
} else {
|
||||
if (!b->controls[i].stretchy)
|
||||
*width += preferredWidth;
|
||||
if (*height < preferredHeight)
|
||||
*height = preferredHeight;
|
||||
}
|
||||
}
|
||||
|
||||
// 3) and now we can add in stretchy controls
|
||||
if (b->vertical)
|
||||
*height += nStretchy * maxStretchyHeight;
|
||||
else
|
||||
*width += nStretchy * maxStretchyWidth;
|
||||
}
|
||||
|
||||
static void boxResize(uiControl *c, intmax_t x, intmax_t y, intmax_t width, intmax_t height, uiSizing *d)
|
||||
{
|
||||
box *b = (box *) c;
|
||||
int xpadding, ypadding;
|
||||
uintmax_t nStretchy;
|
||||
intmax_t stretchywid, stretchyht;
|
||||
uintmax_t i;
|
||||
intmax_t preferredWidth, preferredHeight;
|
||||
|
||||
if (b->len == 0)
|
||||
return;
|
||||
|
||||
// -1) get this Box's padding
|
||||
xpadding = 0;
|
||||
ypadding = 0;
|
||||
if (b->padded) {
|
||||
xpadding = d->xPadding;
|
||||
ypadding = d->yPadding;
|
||||
}
|
||||
|
||||
// 0) inset the available rect by the needed padding
|
||||
if (b->vertical)
|
||||
height -= (b->len - 1) * ypadding;
|
||||
else
|
||||
width -= (b->len - 1) * xpadding;
|
||||
|
||||
// 1) get width and height of non-stretchy controls
|
||||
// this will tell us how much space will be left for stretchy controls
|
||||
stretchywid = width;
|
||||
stretchyht = height;
|
||||
nStretchy = 0;
|
||||
for (i = 0; i < b->len; i++) {
|
||||
if (!uiControlVisible(b->controls[i].c))
|
||||
continue;
|
||||
if (b->controls[i].stretchy) {
|
||||
nStretchy++;
|
||||
continue;
|
||||
}
|
||||
uiControlPreferredSize(b->controls[i].c, d, &preferredWidth, &preferredHeight);
|
||||
if (b->vertical) { // all controls have same width
|
||||
b->controls[i].width = width;
|
||||
b->controls[i].height = preferredHeight;
|
||||
stretchyht -= preferredHeight;
|
||||
} else { // all controls have same height
|
||||
b->controls[i].width = preferredWidth;
|
||||
b->controls[i].height = height;
|
||||
stretchywid -= preferredWidth;
|
||||
}
|
||||
}
|
||||
|
||||
// 2) now get the size of stretchy controls
|
||||
if (nStretchy != 0)
|
||||
if (b->vertical)
|
||||
stretchyht /= nStretchy;
|
||||
else
|
||||
stretchywid /= nStretchy;
|
||||
for (i = 0; i < b->len; i++) {
|
||||
if (!uiControlVisible(b->controls[i].c))
|
||||
continue;
|
||||
if (b->controls[i].stretchy) {
|
||||
b->controls[i].width = stretchywid;
|
||||
b->controls[i].height = stretchyht;
|
||||
}
|
||||
}
|
||||
|
||||
// 3) now we can position controls
|
||||
for (i = 0; i < b->len; i++) {
|
||||
if (!uiControlVisible(b->controls[i].c))
|
||||
continue;
|
||||
uiControlResize(b->controls[i].c, x, y, b->controls[i].width, b->controls[i].height, d);
|
||||
if (b->vertical)
|
||||
y += b->controls[i].height + ypadding;
|
||||
else
|
||||
x += b->controls[i].width + xpadding;
|
||||
}
|
||||
}
|
||||
|
||||
static int boxVisible(uiControl *c)
|
||||
{
|
||||
box *b = (box *) c;
|
||||
|
||||
return !(b->userHid);
|
||||
}
|
||||
|
||||
static void boxShow(uiControl *c)
|
||||
{
|
||||
box *b = (box *) c;
|
||||
uintmax_t i;
|
||||
|
||||
b->userHid = 0;
|
||||
if (!b->containerHid) {
|
||||
for (i = 0; i < b->len; i++)
|
||||
uiControlContainerShow(b->controls[i].c);
|
||||
if (b->parent != NULL)
|
||||
uiParentUpdate(b->parent);
|
||||
}
|
||||
}
|
||||
|
||||
static void boxHide(uiControl *c)
|
||||
{
|
||||
box *b = (box *) c;
|
||||
uintmax_t i;
|
||||
|
||||
b->userHid = 1;
|
||||
for (i = 0; i < b->len; i++)
|
||||
uiControlContainerHide(b->controls[i].c);
|
||||
if (b->parent != NULL)
|
||||
uiParentUpdate(b->parent);
|
||||
}
|
||||
|
||||
static void boxContainerShow(uiControl *c)
|
||||
{
|
||||
box *b = (box *) c;
|
||||
uintmax_t i;
|
||||
|
||||
b->containerHid = 0;
|
||||
if (!b->userHid) {
|
||||
for (i = 0; i < b->len; i++)
|
||||
uiControlContainerShow(b->controls[i].c);
|
||||
if (b->parent != NULL)
|
||||
uiParentUpdate(b->parent);
|
||||
}
|
||||
}
|
||||
|
||||
static void boxContainerHide(uiControl *c)
|
||||
{
|
||||
box *b = (box *) c;
|
||||
uintmax_t i;
|
||||
|
||||
b->containerHid = 1;
|
||||
for (i = 0; i < b->len; i++)
|
||||
uiControlContainerHide(b->controls[i].c);
|
||||
if (b->parent != NULL)
|
||||
uiParentUpdate(b->parent);
|
||||
}
|
||||
|
||||
static void boxEnable(uiControl *c)
|
||||
{
|
||||
box *b = (box *) c;
|
||||
uintmax_t i;
|
||||
|
||||
b->userDisabled = 0;
|
||||
if (!b->containerDisabled)
|
||||
for (i = 0; i < b->len; i++)
|
||||
uiControlContainerEnable(b->controls[i].c);
|
||||
}
|
||||
|
||||
static void boxDisable(uiControl *c)
|
||||
{
|
||||
box *b = (box *) c;
|
||||
uintmax_t i;
|
||||
|
||||
b->userDisabled = 1;
|
||||
for (i = 0; i < b->len; i++)
|
||||
uiControlContainerDisable(b->controls[i].c);
|
||||
}
|
||||
|
||||
static void boxContainerEnable(uiControl *c)
|
||||
{
|
||||
box *b = (box *) c;
|
||||
uintmax_t i;
|
||||
|
||||
b->containerDisabled = 0;
|
||||
if (!b->userDisabled)
|
||||
for (i = 0; i < b->len; i++)
|
||||
uiControlContainerEnable(b->controls[i].c);
|
||||
}
|
||||
|
||||
static void boxContainerDisable(uiControl *c)
|
||||
{
|
||||
box *b = (box *) c;
|
||||
uintmax_t i;
|
||||
|
||||
b->containerDisabled = 1;
|
||||
for (i = 0; i < b->len; i++)
|
||||
uiControlContainerDisable(b->controls[i].c);
|
||||
}
|
||||
|
||||
#define boxCapGrow 32
|
||||
|
||||
static void boxAppend(uiBox *ss, uiControl *c, int stretchy)
|
||||
{
|
||||
box *b = (box *) ss;
|
||||
|
||||
if (b->len >= b->cap) {
|
||||
b->cap += boxCapGrow;
|
||||
b->controls = (boxControl *) uiRealloc(b->controls, b->cap * sizeof (boxControl), "boxControl[]");
|
||||
}
|
||||
b->controls[b->len].c = c;
|
||||
b->controls[b->len].stretchy = stretchy;
|
||||
b->len++; // must be here for parent updates to work
|
||||
if (b->parent != NULL) {
|
||||
uiControlSetParent(b->controls[b->len - 1].c, b->parent);
|
||||
uiParentUpdate(b->parent);
|
||||
}
|
||||
}
|
||||
|
||||
static void boxDelete(uiBox *ss, uintmax_t index)
|
||||
{
|
||||
box *b = (box *) ss;
|
||||
uiControl *removed;
|
||||
uintmax_t i;
|
||||
|
||||
removed = b->controls[index].c;
|
||||
// TODO switch to memmove?
|
||||
for (i = index; i < b->len - 1; i++)
|
||||
b->controls[i] = b->controls[i + 1];
|
||||
// TODO memset the last one to NULL
|
||||
b->len--;
|
||||
if (b->parent != NULL) {
|
||||
uiControlSetParent(removed, NULL);
|
||||
uiParentUpdate(b->parent);
|
||||
}
|
||||
}
|
||||
|
||||
static int boxPadded(uiBox *ss)
|
||||
{
|
||||
box *b = (box *) ss;
|
||||
|
||||
return b->padded;
|
||||
}
|
||||
|
||||
static void boxSetPadded(uiBox *ss, int padded)
|
||||
{
|
||||
box *b = (box *) ss;
|
||||
|
||||
b->padded = padded;
|
||||
if (b->parent != NULL)
|
||||
uiParentUpdate(b->parent);
|
||||
}
|
||||
|
||||
uiBox *uiNewHorizontalBox(void)
|
||||
{
|
||||
box *b;
|
||||
|
||||
b = uiNew(box);
|
||||
|
||||
uiControl(b)->Destroy = boxDestroy;
|
||||
uiControl(b)->Handle = boxHandle;
|
||||
uiControl(b)->SetParent = boxSetParent;
|
||||
uiControl(b)->PreferredSize = boxPreferredSize;
|
||||
uiControl(b)->Resize = boxResize;
|
||||
uiControl(b)->Visible = boxVisible;
|
||||
uiControl(b)->Show = boxShow;
|
||||
uiControl(b)->Hide = boxHide;
|
||||
uiControl(b)->ContainerShow = boxContainerShow;
|
||||
uiControl(b)->ContainerHide = boxContainerHide;
|
||||
uiControl(b)->Enable = boxEnable;
|
||||
uiControl(b)->Disable = boxDisable;
|
||||
uiControl(b)->ContainerEnable = boxContainerEnable;
|
||||
uiControl(b)->ContainerDisable = boxContainerDisable;
|
||||
|
||||
uiBox(b)->Append = boxAppend;
|
||||
uiBox(b)->Delete = boxDelete;
|
||||
uiBox(b)->Padded = boxPadded;
|
||||
uiBox(b)->SetPadded = boxSetPadded;
|
||||
|
||||
return uiBox(b);
|
||||
}
|
||||
|
||||
uiBox *uiNewVerticalBox(void)
|
||||
{
|
||||
uiBox *ss;
|
||||
box *b;
|
||||
|
||||
ss = uiNewHorizontalBox();
|
||||
b = (box *) ss;
|
||||
b->vertical = 1;
|
||||
return ss;
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
// 4 december 2014
|
||||
#import <stdio.h>
|
||||
#import "uipriv_darwin.h"
|
||||
|
||||
void *uiAlloc(size_t size, const char *type)
|
||||
{
|
||||
void *out;
|
||||
|
||||
out = malloc(size);
|
||||
if (out == NULL) {
|
||||
fprintf(stderr, "memory exhausted in uiAlloc() allocating %s\n", type);
|
||||
abort();
|
||||
}
|
||||
memset(out, 0, size);
|
||||
if (options.debugLogAllocations)
|
||||
fprintf(stderr, "%p alloc %s\n", out, type);
|
||||
return out;
|
||||
}
|
||||
|
||||
void *uiRealloc(void *p, size_t size, const char *type)
|
||||
{
|
||||
void *out;
|
||||
|
||||
if (p == NULL)
|
||||
return uiAlloc(size, type);
|
||||
out = realloc(p, size);
|
||||
if (out == NULL) {
|
||||
fprintf(stderr, "memory exhausted in uiRealloc() reallocating %s\n", type);
|
||||
abort();
|
||||
}
|
||||
// TODO zero the extra memory
|
||||
if (options.debugLogAllocations)
|
||||
fprintf(stderr, "%p realloc %p\n", p, out);
|
||||
return out;
|
||||
}
|
||||
|
||||
void uiFree(void *p)
|
||||
{
|
||||
if (p == NULL)
|
||||
return;
|
||||
free(p);
|
||||
if (options.debugLogAllocations)
|
||||
fprintf(stderr, "%p free\n", p);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
// 7 april 2015
|
||||
#import "uipriv_darwin.h"
|
||||
|
||||
// also fine for NSCells and NSTexts (NSTextViews)
|
||||
void setStandardControlFont(NSControl *control)
|
||||
{
|
||||
[control setFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]]];
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
void complain(const char *fmt, ...)
|
||||
{
|
||||
// TODO
|
||||
}
|
163
darwin/window.m
163
darwin/window.m
|
@ -1,163 +0,0 @@
|
|||
// 6 april 2015
|
||||
#import "uipriv_darwin.h"
|
||||
|
||||
// TODO
|
||||
// - free chilld containers properly
|
||||
|
||||
@interface uiWindowDelegate : NSObject <NSWindowDelegate>
|
||||
@property (assign) NSWindow *w;
|
||||
@property uiParent *content;
|
||||
@property int (*onClosing)(uiWindow *, void *);
|
||||
@property void *onClosingData;
|
||||
@property struct window *uiw;
|
||||
@end
|
||||
|
||||
@implementation uiWindowDelegate
|
||||
|
||||
uiLogObjCClassAllocations
|
||||
|
||||
- (BOOL)windowShouldClose:(id)win
|
||||
{
|
||||
// return exact constants to be safe
|
||||
if ((*(self.onClosing))(uiWindow(self.uiw), self.onClosingData))
|
||||
return YES;
|
||||
return NO;
|
||||
}
|
||||
|
||||
// after this method returns we assume the window will be released (see below), so we can go too
|
||||
- (void)windowWillClose:(NSNotification *)note
|
||||
{
|
||||
[self.w setDelegate:nil]; // see http://stackoverflow.com/a/29523141/3408572
|
||||
|
||||
// just to be safe
|
||||
[self.w setContentView:[[NSView alloc] initWithFrame:NSZeroRect]];
|
||||
uiParentDestroy(self.content);
|
||||
|
||||
// now we need to release the window too
|
||||
[self.w release];
|
||||
|
||||
// and clean up
|
||||
uiFree(self.uiw);
|
||||
[self release];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
struct window {
|
||||
uiWindow w;
|
||||
uiWindowDelegate *d;
|
||||
int margined;
|
||||
};
|
||||
|
||||
static int defaultOnClosing(uiWindow *w, void *data)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define D (((struct window *) w)->d)
|
||||
|
||||
static void windowDestroy(uiWindow *w)
|
||||
{
|
||||
[D.w close];
|
||||
}
|
||||
|
||||
static uintptr_t windowHandle(uiWindow *w)
|
||||
{
|
||||
return (uintptr_t) (D.w);
|
||||
}
|
||||
|
||||
static char *windowTitle(uiWindow *w)
|
||||
{
|
||||
return uiDarwinNSStringToText([D.w title]);
|
||||
}
|
||||
|
||||
static void windowSetTitle(uiWindow *w, const char *title)
|
||||
{
|
||||
[D.w setTitle:toNSString(title)];
|
||||
}
|
||||
|
||||
static void windowShow(uiWindow *w)
|
||||
{
|
||||
[D.w makeKeyAndOrderFront:D.w];
|
||||
}
|
||||
|
||||
static void windowHide(uiWindow *w)
|
||||
{
|
||||
[D.w orderOut:D.w];
|
||||
}
|
||||
|
||||
static void windowOnClosing(uiWindow *w, int (*f)(uiWindow *, void *), void *data)
|
||||
{
|
||||
D.onClosing = f;
|
||||
D.onClosingData = data;
|
||||
}
|
||||
|
||||
static void windowSetChild(uiWindow *w, uiControl *c)
|
||||
{
|
||||
uiParentSetMainControl(D.content, c);
|
||||
}
|
||||
|
||||
static int windowMargined(uiWindow *ww)
|
||||
{
|
||||
struct window *w = (struct window *) ww;
|
||||
|
||||
return w->margined;
|
||||
}
|
||||
|
||||
static void windowSetMargined(uiWindow *ww, int margined)
|
||||
{
|
||||
struct window *w = (struct window *) ww;
|
||||
|
||||
w->margined = margined;
|
||||
if (w->margined)
|
||||
uiParentSetMargins(D.content, macXMargin, macYMargin, macXMargin, macYMargin);
|
||||
else
|
||||
uiParentSetMargins(D.content, 0, 0, 0, 0);
|
||||
uiParentUpdate(D.content);
|
||||
}
|
||||
|
||||
uiWindow *uiNewWindow(const char *title, int width, int height, int hasMenubar)
|
||||
{
|
||||
uiWindowDelegate *d;
|
||||
|
||||
d = [uiWindowDelegate new];
|
||||
|
||||
d.w = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, (CGFloat) width, (CGFloat) height)
|
||||
styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask)
|
||||
backing:NSBackingStoreBuffered
|
||||
defer:YES];
|
||||
[d.w setTitle:toNSString(title)];
|
||||
|
||||
// we do not want substitutions
|
||||
// text fields, labels, etc. take their smart quotes and other autocorrect settings from their parent window, which provides a shared "field editor"
|
||||
// so we have to turn them off here
|
||||
// thanks akempgen in irc.freenode.net/#macdev
|
||||
// for some reason, this selector returns NSText but is documented to return NSTextView...
|
||||
// NOTE: if you disagree with me about disabling substitutions, start a github issue with why and I'll be happy to consider it
|
||||
disableAutocorrect((NSTextView *) [d.w fieldEditor:YES forObject:nil]);
|
||||
|
||||
// don't release on close; we'll do it ourselves (see above)
|
||||
[d.w setReleasedWhenClosed:NO];
|
||||
|
||||
d.content = uiNewParent(0);
|
||||
[d.w setContentView:((NSView *) uiParentHandle(d.content))];
|
||||
|
||||
d.onClosing = defaultOnClosing;
|
||||
[d.w setDelegate:d];
|
||||
|
||||
d.uiw = uiNew(struct window);
|
||||
d.uiw->d = d;
|
||||
|
||||
uiWindow(d.uiw)->Destroy = windowDestroy;
|
||||
uiWindow(d.uiw)->Handle = windowHandle;
|
||||
uiWindow(d.uiw)->Title = windowTitle;
|
||||
uiWindow(d.uiw)->SetTitle = windowSetTitle;
|
||||
uiWindow(d.uiw)->Show = windowShow;
|
||||
uiWindow(d.uiw)->Hide = windowHide;
|
||||
uiWindow(d.uiw)->OnClosing = windowOnClosing;
|
||||
uiWindow(d.uiw)->SetChild = windowSetChild;
|
||||
uiWindow(d.uiw)->Margined = windowMargined;
|
||||
uiWindow(d.uiw)->SetMargined = windowSetMargined;
|
||||
|
||||
return uiWindow(d.uiw);
|
||||
}
|
149
ui.idl
149
ui.idl
|
@ -1,149 +0,0 @@
|
|||
// 6 april 2015
|
||||
|
||||
// This is not an IDL file for the conventional RPC or Microsoft IDLs.
|
||||
// Instead, this is for a custom IDL of my own creation.
|
||||
// You can find it at github.com/andlabs/pgidl
|
||||
|
||||
package ui {
|
||||
|
||||
// TODO autogenerate this somehow
|
||||
// TODO alternatively, move AFTER typedefs
|
||||
raw "#ifndef __UI_UI_H__";
|
||||
raw "#define __UI_UI_H__";
|
||||
|
||||
raw "#include <stdint.h>";
|
||||
|
||||
// TODO note that should be initialized to zero
|
||||
struct InitOptions {
|
||||
// TODO cbSize
|
||||
|
||||
// If nonzero, allocations will be logged to stderr.
|
||||
// See leaks.awk.
|
||||
field debugLogAllocations int;
|
||||
};
|
||||
|
||||
func Init(options *InitOptions) *const char;
|
||||
func FreeInitError(err *const char);
|
||||
|
||||
func Main(void);
|
||||
func Quit(void);
|
||||
|
||||
func FreeText(text *char);
|
||||
|
||||
raw "typedef struct uiSizingSys uiSizingSys;";
|
||||
|
||||
struct Sizing {
|
||||
field xPadding intmax_t;
|
||||
field yPadding intmax_t;
|
||||
field sys *uiSizingSys;
|
||||
};
|
||||
|
||||
interface Control {
|
||||
field Internal *void; // for use by ui only
|
||||
func Destroy(void);
|
||||
func Handle(void) uintptr_t;
|
||||
func SetHasParent(hasParent int);
|
||||
func SetOSContainer(c *OSContainer);
|
||||
func PreferredSize(d *Sizing, width *intmax_t, height *intmax_t);
|
||||
func Resize(x intmax_t, y intmax_t, width intmax_t, height intmax_t, d *Sizing);
|
||||
func Visible(void) int;
|
||||
func Show(void);
|
||||
func Hide(void);
|
||||
func ContainerShow(void);
|
||||
func ContainerHide(void);
|
||||
func Enable(void);
|
||||
func Disable(void);
|
||||
func ContainerEnable(void);
|
||||
func ContainerDisable(void);
|
||||
};
|
||||
|
||||
interface OSContainer {
|
||||
field Internal *void;
|
||||
func Destroy(void);
|
||||
func Handle(void) uintptr_t;
|
||||
func SetMainControl(c *Control);
|
||||
func SetMargins(left intmax_t, top intmax_t, right intmax_t, bottom intmax_t);
|
||||
func Update(void);
|
||||
};
|
||||
func NewOSContainer(osParent uintptr_t) *OSContainer;
|
||||
|
||||
interface Window {
|
||||
field Internal *void;
|
||||
func Destroy(void);
|
||||
func Handle(void) uintptr_t;
|
||||
func Title(void) *char;
|
||||
func SetTitle(title *const char);
|
||||
func Show(void);
|
||||
func Hide(void);
|
||||
func OnClosing(f *func(w *Window, data *void) int, data *void);
|
||||
func SetChild(c *Control);
|
||||
func Margined(void) int;
|
||||
func SetMargined(margined int);
|
||||
};
|
||||
func NewWindow(title *const char, width int, height int, hasMenubar int) *Window;
|
||||
|
||||
interface Button from Control {
|
||||
func Text(void) *char;
|
||||
func SetText(text *const char);
|
||||
func OnClicked(f *func(b *Button, data *void), data *void);
|
||||
};
|
||||
func NewButton(text *const char) *Button;
|
||||
|
||||
interface Box from Control {
|
||||
func Append(c *Control, stretchy int);
|
||||
func Delete(index uintmax_t);
|
||||
func Padded(void) int;
|
||||
func SetPadded(padded int);
|
||||
};
|
||||
func NewHorizontalBox(void) *Box;
|
||||
func NewVerticalBox(void) *Box;
|
||||
|
||||
interface Entry from Control {
|
||||
func Text(void) *char;
|
||||
func SetText(text *const char);
|
||||
};
|
||||
func NewEntry(void) *Entry;
|
||||
|
||||
interface Checkbox from Control {
|
||||
func Text(void) *char;
|
||||
func SetText(text *const char);
|
||||
func OnToggled(f *func(c *Checkbox, data *void), data *void);
|
||||
func Checked(void) int;
|
||||
func SetChecked(checked int);
|
||||
};
|
||||
func NewCheckbox(text *const char) *Checkbox;
|
||||
|
||||
interface Label from Control {
|
||||
func Text(void) *char;
|
||||
func SetText(text *const char);
|
||||
};
|
||||
func NewLabel(text *const char) *Label;
|
||||
|
||||
interface Tab from Control {
|
||||
// TODO rename to AppendPage()
|
||||
func AddPage(name *const char, c *Control);
|
||||
func DeletePage(index uintmax_t);
|
||||
};
|
||||
func NewTab(void) *Tab;
|
||||
|
||||
interface Menu {
|
||||
func AddItem(name string) *MenuItem;
|
||||
func AddCheckItem(name string) *MenuItem;
|
||||
func AddQuitItem(void) *MenuItem;
|
||||
func AddPreferencesItem(void) *MenuItem;
|
||||
func AddAboutItem(void) *MenuItem;
|
||||
func AddSeparator(void);
|
||||
};
|
||||
func NewMenu(name string) *Menu;
|
||||
|
||||
interface MenuItem {
|
||||
func Enable(void);
|
||||
func Disable(void);
|
||||
func OnClicked(f *func(sender *void, data *void), data *void);
|
||||
func Checked(void) int;
|
||||
func SetChecked(checked int);
|
||||
};
|
||||
|
||||
raw "#endif";
|
||||
|
||||
};
|
33
unix/alloc.c
33
unix/alloc.c
|
@ -1,33 +0,0 @@
|
|||
// 7 april 2015
|
||||
#include <stdio.h>
|
||||
#include "uipriv_unix.h"
|
||||
|
||||
void *uiAlloc(size_t size, const char *type)
|
||||
{
|
||||
void *out;
|
||||
|
||||
out = g_malloc0(size);
|
||||
if (options.debugLogAllocations)
|
||||
fprintf(stderr, "%p alloc %s\n", out, type);
|
||||
return out;
|
||||
}
|
||||
|
||||
void *uiRealloc(void *p, size_t size, const char *type)
|
||||
{
|
||||
void *out;
|
||||
|
||||
if (p == NULL)
|
||||
return uiAlloc(size, type);
|
||||
// TODO fill with 0s
|
||||
out = g_realloc(p, size);
|
||||
if (options.debugLogAllocations)
|
||||
fprintf(stderr, "%p realloc %p\n", p, out);
|
||||
return out;
|
||||
}
|
||||
|
||||
void uiFree(void *p)
|
||||
{
|
||||
g_free(p);
|
||||
if (options.debugLogAllocations)
|
||||
fprintf(stderr, "%p free\n", p);
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
// 9 april 2015
|
||||
#include "uipriv_unix.h"
|
||||
|
||||
void uiFreeText(char *t)
|
||||
{
|
||||
g_free(t);
|
||||
}
|
13
unix/util.c
13
unix/util.c
|
@ -1,13 +0,0 @@
|
|||
// 18 april 2015
|
||||
#include "uipriv_unix.h"
|
||||
|
||||
void complain(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
// there's no g_errorv() in glib 2.32, so do it manually instead
|
||||
g_logv(G_LOG_DOMAIN, G_LOG_LEVEL_ERROR, fmt, ap);
|
||||
va_end(ap);
|
||||
abort(); // just in case
|
||||
}
|
172
unix/window.c
172
unix/window.c
|
@ -1,172 +0,0 @@
|
|||
// 6 april 2015
|
||||
#include "uipriv_unix.h"
|
||||
|
||||
struct window {
|
||||
uiWindow w;
|
||||
GtkWidget *widget;
|
||||
GtkContainer *container;
|
||||
GtkWindow *window;
|
||||
uiParent *content;
|
||||
int (*onClosing)(uiWindow *, void *);
|
||||
void *onClosingData;
|
||||
int margined;
|
||||
gulong destroyBlocker;
|
||||
};
|
||||
|
||||
static gboolean onClosing(GtkWidget *win, GdkEvent *e, gpointer data)
|
||||
{
|
||||
struct window *w = (struct window *) data;
|
||||
|
||||
// manually destroy the window ourselves; don't let the delete-event handler do it
|
||||
if ((*(w->onClosing))(uiWindow(w), w->onClosingData))
|
||||
uiWindowDestroy(uiWindow(w));
|
||||
return TRUE; // don't continue to the default delete-event handler; we destroyed the window by now
|
||||
}
|
||||
|
||||
static int defaultOnClosing(uiWindow *w, void *data)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void destroyBlocker(GtkWidget *widget, gpointer data)
|
||||
{
|
||||
complain("attempt to dispose uiWindow at %p before uiWindowDestroy()", data);
|
||||
}
|
||||
|
||||
// TODO should we change the GtkWindow's child first?
|
||||
static void windowDestroy(uiWindow *ww)
|
||||
{
|
||||
struct window *w = (struct window *) ww;
|
||||
|
||||
// first, hide the window to prevent our cleanup from being noticed
|
||||
gtk_widget_hide(w->widget);
|
||||
// next, destroy the content uiParent
|
||||
uiParentDestroy(w->content);
|
||||
// now that we cleaned up properly, we can mark our window as ready to be destroyed
|
||||
g_signal_handler_disconnect(w->widget, w->destroyBlocker);
|
||||
// finally, destroy the window
|
||||
gtk_widget_destroy(w->widget);
|
||||
// and free ourselves
|
||||
uiFree(w);
|
||||
}
|
||||
|
||||
static uintptr_t windowHandle(uiWindow *ww)
|
||||
{
|
||||
struct window *w = (struct window *) ww;
|
||||
|
||||
return (uintptr_t) (w->widget);
|
||||
}
|
||||
|
||||
static char *windowTitle(uiWindow *ww)
|
||||
{
|
||||
struct window *w = (struct window *) ww;
|
||||
|
||||
return g_strdup(gtk_window_get_title(w->window));
|
||||
}
|
||||
|
||||
static void windowSetTitle(uiWindow *ww, const char *title)
|
||||
{
|
||||
struct window *w = (struct window *) ww;
|
||||
|
||||
gtk_window_set_title(w->window, title);
|
||||
}
|
||||
|
||||
static void windowShow(uiWindow *ww)
|
||||
{
|
||||
struct window *w = (struct window *) ww;
|
||||
|
||||
// don't use gtk_widget_show_all(); that will override user hidden settings
|
||||
gtk_widget_show(w->widget);
|
||||
}
|
||||
|
||||
static void windowHide(uiWindow *ww)
|
||||
{
|
||||
struct window *w = (struct window *) ww;
|
||||
gtk_widget_hide(w->widget);
|
||||
}
|
||||
|
||||
static void windowOnClosing(uiWindow *ww, int (*f)(uiWindow *, void *), void *data)
|
||||
{
|
||||
struct window *w = (struct window *) ww;
|
||||
|
||||
w->onClosing = f;
|
||||
w->onClosingData = data;
|
||||
}
|
||||
|
||||
static void windowSetChild(uiWindow *ww, uiControl *c)
|
||||
{
|
||||
struct window *w = (struct window *) ww;
|
||||
|
||||
uiParentSetMainControl(w->content, c);
|
||||
uiParentUpdate(w->content);
|
||||
}
|
||||
|
||||
static int windowMargined(uiWindow *ww)
|
||||
{
|
||||
struct window *w = (struct window *) ww;
|
||||
|
||||
return w->margined;
|
||||
}
|
||||
|
||||
static void windowSetMargined(uiWindow *ww, int margined)
|
||||
{
|
||||
struct window *w = (struct window *) ww;
|
||||
|
||||
w->margined = margined;
|
||||
if (w->margined)
|
||||
uiParentSetMargins(w->content, gtkXMargin, gtkYMargin, gtkXMargin, gtkYMargin);
|
||||
else
|
||||
uiParentSetMargins(w->content, 0, 0, 0, 0);
|
||||
uiParentUpdate(w->content);
|
||||
}
|
||||
|
||||
uiWindow *uiNewWindow(const char *title, int width, int height, int hasMenubar)
|
||||
{
|
||||
struct window *w;
|
||||
GtkWidget *vbox;
|
||||
GtkWidget *contentWidget;
|
||||
|
||||
w = uiNew(struct window);
|
||||
|
||||
w->widget = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
w->container = GTK_CONTAINER(w->widget);
|
||||
w->window = GTK_WINDOW(w->widget);
|
||||
|
||||
gtk_window_set_title(w->window, title);
|
||||
// TODO this does not take menus or CSD into account
|
||||
gtk_window_resize(w->window, width, height);
|
||||
|
||||
g_signal_connect(w->widget, "delete-event", G_CALLBACK(onClosing), w);
|
||||
w->destroyBlocker = g_signal_connect(w->widget, "destroy", G_CALLBACK(destroyBlocker), w);
|
||||
|
||||
if (hasMenubar) {
|
||||
vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_widget_show_all(vbox);
|
||||
gtk_container_add(w->container, vbox);
|
||||
|
||||
gtk_container_add(GTK_CONTAINER(vbox), makeMenubar());
|
||||
|
||||
w->content = uiNewParent((uintptr_t) GTK_CONTAINER(vbox));
|
||||
contentWidget = GTK_WIDGET(uiParentHandle(w->content));
|
||||
gtk_widget_set_hexpand(contentWidget, TRUE);
|
||||
gtk_widget_set_halign(contentWidget, GTK_ALIGN_FILL);
|
||||
gtk_widget_set_vexpand(contentWidget, TRUE);
|
||||
gtk_widget_set_valign(contentWidget, GTK_ALIGN_FILL);
|
||||
} else
|
||||
w->content = uiNewParent((uintptr_t) (w->container));
|
||||
|
||||
w->onClosing = defaultOnClosing;
|
||||
|
||||
uiWindow(w)->Destroy = windowDestroy;
|
||||
uiWindow(w)->Handle = windowHandle;
|
||||
uiWindow(w)->Title = windowTitle;
|
||||
uiWindow(w)->SetTitle = windowSetTitle;
|
||||
uiWindow(w)->Show = windowShow;
|
||||
uiWindow(w)->Hide = windowHide;
|
||||
uiWindow(w)->OnClosing = windowOnClosing;
|
||||
uiWindow(w)->SetChild = windowSetChild;
|
||||
uiWindow(w)->Margined = windowMargined;
|
||||
uiWindow(w)->SetMargined = windowSetMargined;
|
||||
|
||||
return uiWindow(w);
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
// 4 december 2014
|
||||
#include "uipriv_windows.h"
|
||||
|
||||
// wrappers for allocator of choice
|
||||
// panics on memory exhausted, undefined on heap corruption or other unreliably-detected malady (see http://stackoverflow.com/questions/28761680/is-there-a-windows-api-memory-allocator-deallocator-i-can-use-that-will-just-giv)
|
||||
// new memory is set to zero
|
||||
// passing NULL to tableRealloc() acts like tableAlloc()
|
||||
// passing NULL to tableFree() is a no-op
|
||||
|
||||
void *uiAlloc(size_t size, const char *type)
|
||||
{
|
||||
void *out;
|
||||
|
||||
out = malloc(size);
|
||||
if (out == NULL) {
|
||||
fprintf(stderr, "memory exhausted in uiAlloc() allocating %s\n", type);
|
||||
abort();
|
||||
}
|
||||
ZeroMemory(out, size);
|
||||
if (options.debugLogAllocations)
|
||||
fprintf(stderr, "%p alloc %s\n", out, type);
|
||||
return out;
|
||||
}
|
||||
|
||||
void *uiRealloc(void *p, size_t size, const char *type)
|
||||
{
|
||||
void *out;
|
||||
|
||||
if (p == NULL)
|
||||
return uiAlloc(size, type);
|
||||
out = realloc(p, size);
|
||||
if (out == NULL) {
|
||||
fprintf(stderr, "memory exhausted in uiRealloc() reallocating %s\n", type);
|
||||
abort();
|
||||
}
|
||||
// TODO zero the extra memory
|
||||
if (options.debugLogAllocations)
|
||||
fprintf(stderr, "%p realloc %p\n", p, out);
|
||||
return out;
|
||||
}
|
||||
|
||||
void uiFree(void *p)
|
||||
{
|
||||
if (p == NULL)
|
||||
return;
|
||||
free(p);
|
||||
if (options.debugLogAllocations)
|
||||
fprintf(stderr, "%p free\n", p);
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
// 9 april 2015
|
||||
#include "uipriv_windows.h"
|
||||
|
||||
// see http://stackoverflow.com/a/29556509/3408572
|
||||
|
||||
#define MBTWC(str, wstr, bufsiz) MultiByteToWideChar(CP_UTF8, 0, str, -1, wstr, bufsiz)
|
||||
|
||||
WCHAR *toUTF16(const char *str)
|
||||
{
|
||||
WCHAR *wstr;
|
||||
int n;
|
||||
|
||||
n = MBTWC(str, NULL, 0);
|
||||
if (n == 0)
|
||||
logLastError("error figuring out number of characters to convert to in toUTF16()");
|
||||
wstr = (WCHAR *) uiAlloc(n * sizeof (WCHAR), "WCHAR[]");
|
||||
if (MBTWC(str, wstr, n) != n)
|
||||
logLastError("error converting from UTF-8 to UTF-16 in toUTF16()");
|
||||
return wstr;
|
||||
}
|
||||
|
||||
#define WCTMB(wstr, str, bufsiz) WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, bufsiz, NULL, NULL)
|
||||
|
||||
char *toUTF8(const WCHAR *wstr)
|
||||
{
|
||||
char *str;
|
||||
int n;
|
||||
|
||||
n = WCTMB(wstr, NULL, 0);
|
||||
if (n == 0)
|
||||
logLastError("error figuring out number of characters to convert to in toUTF8()");
|
||||
str = (char *) uiAlloc(n * sizeof (char), "char[]");
|
||||
if (WCTMB(wstr, str, n) != n)
|
||||
logLastError("error converting from UTF-16 to UTF-8 in toUTFF8()");
|
||||
return str;
|
||||
}
|
||||
|
||||
WCHAR *windowText(HWND hwnd)
|
||||
{
|
||||
LRESULT n;
|
||||
WCHAR *text;
|
||||
|
||||
n = SendMessageW(hwnd, WM_GETTEXTLENGTH, 0, 0);
|
||||
// WM_GETTEXTLENGTH does not include the null terminator
|
||||
text = (WCHAR *) uiAlloc((n + 1) * sizeof (WCHAR), "WCHAR[]");
|
||||
// note the comparison: the size includes the null terminator, but the return does not
|
||||
if (GetWindowTextW(hwnd, text, n + 1) != n)
|
||||
logLastError("error getting window text in windowText()");
|
||||
return text;
|
||||
}
|
||||
|
||||
void uiFreeText(char *text)
|
||||
{
|
||||
uiFree(text);
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
// 6 april 2015
|
||||
#include "uipriv_windows.h"
|
||||
|
||||
intmax_t uiWindowsWindowTextWidth(HWND hwnd)
|
||||
{
|
||||
LRESULT len;
|
||||
WCHAR *text;
|
||||
HDC dc;
|
||||
HFONT prevfont;
|
||||
SIZE size;
|
||||
|
||||
size.cx = 0;
|
||||
size.cy = 0;
|
||||
|
||||
// first we need the window text
|
||||
len = SendMessageW(hwnd, WM_GETTEXTLENGTH, 0, 0);
|
||||
if (len == 0) // no text; nothing to do
|
||||
return 0;
|
||||
text = (WCHAR *) uiAlloc((len + 1) * sizeof (WCHAR), "WCHAR[]");
|
||||
// note the comparison: the size includes the null terminator, but the return does not
|
||||
if (GetWindowText(hwnd, text, len + 1) != len)
|
||||
logLastError("error getting window text in uiWindowsWindowTextWidth()");
|
||||
|
||||
// now we can do the calculations
|
||||
dc = GetDC(hwnd);
|
||||
if (dc == NULL)
|
||||
logLastError("error getting DC in uiWindowsWindowTextWidth()");
|
||||
prevfont = (HFONT) SelectObject(dc, hMessageFont);
|
||||
if (prevfont == NULL)
|
||||
logLastError("error loading control font into device context in uiWindowsWindowTextWidth()");
|
||||
if (GetTextExtentPoint32W(dc, text, len, &size) == 0)
|
||||
logLastError("error getting text extent point in uiWindowsWindowTextWidth()");
|
||||
if (SelectObject(dc, prevfont) != hMessageFont)
|
||||
logLastError("error restoring previous font into device context in uiWindowsWindowTextWidth()");
|
||||
if (ReleaseDC(hwnd, dc) == 0)
|
||||
logLastError("error releasing DC in uiWindowsWindowTextWidth()");
|
||||
uiFree(text);
|
||||
|
||||
return size.cx;
|
||||
}
|
||||
|
||||
// this is a helper function that takes the logic of determining window classes and puts it all in one place
|
||||
// there are a number of places where we need to know what window class an arbitrary handle has
|
||||
// theoretically we could use the class atom to avoid a _wcsicmp()
|
||||
// however, raymond chen advises against this - http://blogs.msdn.com/b/oldnewthing/archive/2004/10/11/240744.aspx (and we're not in control of the Tab class, before you say anything)
|
||||
// usage: windowClassOf(hwnd, L"class 1", L"class 2", ..., NULL)
|
||||
int windowClassOf(HWND hwnd, ...)
|
||||
{
|
||||
// MSDN says 256 is the maximum length of a class name; add a few characters just to be safe (because it doesn't say whether this includes the terminating null character)
|
||||
#define maxClassName 260
|
||||
WCHAR classname[maxClassName + 1];
|
||||
va_list ap;
|
||||
WCHAR *curname;
|
||||
int i;
|
||||
|
||||
if (GetClassNameW(hwnd, classname, maxClassName) == 0)
|
||||
logLastError("error getting name of window class in windowClassOf()");
|
||||
va_start(ap, hwnd);
|
||||
i = 0;
|
||||
for (;;) {
|
||||
curname = va_arg(ap, WCHAR *);
|
||||
if (curname == NULL)
|
||||
break;
|
||||
if (_wcsicmp(classname, curname) == 0) {
|
||||
va_end(ap);
|
||||
return i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
// no match
|
||||
va_end(ap);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void complain(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
abort();
|
||||
}
|
251
windows/window.c
251
windows/window.c
|
@ -1,251 +0,0 @@
|
|||
// 6 april 2015
|
||||
#include "uipriv_windows.h"
|
||||
|
||||
struct window {
|
||||
uiWindow w;
|
||||
HWND hwnd;
|
||||
uiParent *content;
|
||||
BOOL shownOnce;
|
||||
int (*onClosing)(uiWindow *, void *);
|
||||
void *onClosingData;
|
||||
int margined;
|
||||
BOOL canDestroy;
|
||||
};
|
||||
|
||||
#define uiWindowClass L"uiWindowClass"
|
||||
|
||||
static LRESULT CALLBACK uiWindowWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
struct window *w;
|
||||
CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam;
|
||||
WINDOWPOS *wp = (WINDOWPOS *) lParam;
|
||||
RECT r;
|
||||
HWND contenthwnd;
|
||||
const uiMenuItem *item;
|
||||
|
||||
w = (struct window *) GetWindowLongPtrW(hwnd, GWLP_USERDATA);
|
||||
if (w == NULL) {
|
||||
if (uMsg == WM_CREATE)
|
||||
SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR) (cs->lpCreateParams));
|
||||
// fall through to DefWindowProc() anyway
|
||||
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
switch (uMsg) {
|
||||
case WM_COMMAND:
|
||||
// not a menu
|
||||
if (lParam != 0)
|
||||
break;
|
||||
if (HIWORD(wParam) != 0)
|
||||
break;
|
||||
item = menuIDToItem(LOWORD(wParam));
|
||||
printf("%d", item->Type);
|
||||
if (item->Type == uiMenuItemTypeCommand)
|
||||
printf(" %s", item->Name);
|
||||
printf("\n");
|
||||
return 0;
|
||||
case WM_WINDOWPOSCHANGED:
|
||||
if ((wp->flags & SWP_NOSIZE) != 0)
|
||||
break;
|
||||
// fall through
|
||||
case msgUpdateChild:
|
||||
if (GetClientRect(w->hwnd, &r) == 0)
|
||||
logLastError("error getting window client rect for resize in uiWindowWndProc()");
|
||||
contenthwnd = uiParentHWND(w->content);
|
||||
if (MoveWindow(contenthwnd, r.left, r.top, r.right - r.left, r.bottom - r.top, TRUE) == 0)
|
||||
logLastError("error resizing window content parent in uiWindowWndProc()");
|
||||
return 0;
|
||||
case WM_CLOSE:
|
||||
if (!(*(w->onClosing))(uiWindow(w), w->onClosingData))
|
||||
uiWindowDestroy(uiWindow(w));
|
||||
return 0; // we destroyed it already
|
||||
case WM_DESTROY:
|
||||
if (!w->canDestroy)
|
||||
complain("attempt to destroy uiWindow at %p before uiWindowDestroy()", w);
|
||||
uiFree(w);
|
||||
break; // fall through to DefWindowProcW()
|
||||
}
|
||||
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
ATOM registerWindowClass(HICON hDefaultIcon, HCURSOR hDefaultCursor)
|
||||
{
|
||||
WNDCLASSW wc;
|
||||
|
||||
ZeroMemory(&wc, sizeof (WNDCLASSW));
|
||||
wc.lpszClassName = uiWindowClass;
|
||||
wc.lpfnWndProc = uiWindowWndProc;
|
||||
wc.hInstance = hInstance;
|
||||
wc.hIcon = hDefaultIcon;
|
||||
wc.hCursor = hDefaultCursor;
|
||||
wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
|
||||
return RegisterClassW(&wc);
|
||||
}
|
||||
|
||||
#define exstyle 0
|
||||
#define style WS_OVERLAPPEDWINDOW
|
||||
|
||||
static int defaultOnClosing(uiWindow *w, void *data)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void windowDestroy(uiWindow *ww)
|
||||
{
|
||||
struct window *w = (struct window *) ww;
|
||||
|
||||
// first destroy the content
|
||||
uiParentDestroy(w->content);
|
||||
// then mark that we're ready to destroy
|
||||
w->canDestroy = TRUE;
|
||||
// and finally destroy
|
||||
// TODO check for errors
|
||||
DestroyWindow(w->hwnd);
|
||||
// no need to explicitly destroy the menubar, if any; that's done automatically during window destruction
|
||||
}
|
||||
|
||||
static uintptr_t windowHandle(uiWindow *ww)
|
||||
{
|
||||
struct window *w = (struct window *) ww;
|
||||
|
||||
return (uintptr_t) (w->hwnd);
|
||||
}
|
||||
|
||||
static char *windowTitle(uiWindow *ww)
|
||||
{
|
||||
struct window *w = (struct window *) ww;
|
||||
WCHAR *wtext;
|
||||
char *text;
|
||||
|
||||
wtext = windowText(w->hwnd);
|
||||
text = toUTF8(wtext);
|
||||
uiFree(wtext);
|
||||
return text;
|
||||
}
|
||||
|
||||
static void windowSetTitle(uiWindow *ww, const char *text)
|
||||
{
|
||||
struct window *w = (struct window *) ww;
|
||||
WCHAR *wtext;
|
||||
|
||||
wtext = toUTF16(text);
|
||||
if (SetWindowTextW(w->hwnd, wtext) == 0)
|
||||
logLastError("error setting window title in uiWindowSetTitle()");
|
||||
uiFree(wtext);
|
||||
}
|
||||
|
||||
static void windowShow(uiWindow *ww)
|
||||
{
|
||||
struct window *w = (struct window *) ww;
|
||||
|
||||
if (w->shownOnce) {
|
||||
ShowWindow(w->hwnd, SW_SHOW);
|
||||
return;
|
||||
}
|
||||
w->shownOnce = TRUE;
|
||||
ShowWindow(w->hwnd, nCmdShow);
|
||||
if (UpdateWindow(w->hwnd) == 0)
|
||||
logLastError("error calling UpdateWindow() after showing uiWindow for the first time");
|
||||
}
|
||||
|
||||
static void windowHide(uiWindow *ww)
|
||||
{
|
||||
struct window *w = (struct window *) ww;
|
||||
|
||||
ShowWindow(w->hwnd, SW_HIDE);
|
||||
}
|
||||
|
||||
static void windowOnClosing(uiWindow *ww, int (*f)(uiWindow *, void *), void *data)
|
||||
{
|
||||
struct window *w = (struct window *) ww;
|
||||
|
||||
w->onClosing = f;
|
||||
w->onClosingData = data;
|
||||
}
|
||||
|
||||
static void windowSetChild(uiWindow *ww, uiControl *c)
|
||||
{
|
||||
struct window *w = (struct window *) ww;
|
||||
|
||||
uiParentSetMainControl(w->content, c);
|
||||
// don't call uiParentUpdate(); instead, synthesize a resize
|
||||
// otherwise, we'll have a 0x0 content area at first
|
||||
SendMessageW(w->hwnd, msgUpdateChild, 0, 0);
|
||||
}
|
||||
|
||||
static int windowMargined(uiWindow *ww)
|
||||
{
|
||||
struct window *w = (struct window *) ww;
|
||||
|
||||
return w->margined;
|
||||
}
|
||||
|
||||
// from https://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing
|
||||
#define windowMargin 7
|
||||
|
||||
static void windowSetMargined(uiWindow *ww, int margined)
|
||||
{
|
||||
struct window *w = (struct window *) ww;
|
||||
|
||||
w->margined = margined;
|
||||
if (w->margined)
|
||||
uiParentSetMargins(w->content, windowMargin, windowMargin, windowMargin, windowMargin);
|
||||
else
|
||||
uiParentSetMargins(w->content, 0, 0, 0, 0);
|
||||
uiParentUpdate(w->content);
|
||||
}
|
||||
|
||||
uiWindow *uiNewWindow(const char *title, int width, int height, int hasMenubar)
|
||||
{
|
||||
struct window *w;
|
||||
RECT adjust;
|
||||
WCHAR *wtitle;
|
||||
BOOL hasMenubarBOOL;
|
||||
HMENU hmenu;
|
||||
|
||||
w = uiNew(struct window);
|
||||
w->onClosing = defaultOnClosing;
|
||||
|
||||
hasMenubarBOOL = FALSE;
|
||||
if (hasMenubar)
|
||||
hasMenubarBOOL = TRUE;
|
||||
|
||||
adjust.left = 0;
|
||||
adjust.top = 0;
|
||||
adjust.right = width;
|
||||
adjust.bottom = height;
|
||||
// TODO does not handle menu wrapping; see http://blogs.msdn.com/b/oldnewthing/archive/2003/09/11/54885.aspx
|
||||
if (AdjustWindowRectEx(&adjust, style, hasMenubarBOOL, exstyle) == 0)
|
||||
logLastError("error getting real window coordinates in uiWindow()");
|
||||
|
||||
wtitle = toUTF16(title);
|
||||
w->hwnd = CreateWindowExW(exstyle,
|
||||
uiWindowClass, wtitle,
|
||||
style,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
adjust.right - adjust.left, adjust.bottom - adjust.top,
|
||||
NULL, NULL, hInstance, w);
|
||||
if (w->hwnd == NULL)
|
||||
logLastError("error creating window in uiWindow()");
|
||||
uiFree(wtitle);
|
||||
|
||||
w->content = uiNewParent((uintptr_t) (w->hwnd));
|
||||
|
||||
if (hasMenubar) {
|
||||
hmenu = makeMenubar();
|
||||
if (SetMenu(w->hwnd, hmenu) == 0)
|
||||
logLastError("error giving menu to window in uiNewWindow()");
|
||||
}
|
||||
|
||||
uiWindow(w)->Destroy = windowDestroy;
|
||||
uiWindow(w)->Handle = windowHandle;
|
||||
uiWindow(w)->Title = windowTitle;
|
||||
uiWindow(w)->SetTitle = windowSetTitle;
|
||||
uiWindow(w)->Show = windowShow;
|
||||
uiWindow(w)->Hide = windowHide;
|
||||
uiWindow(w)->OnClosing = windowOnClosing;
|
||||
uiWindow(w)->SetChild = windowSetChild;
|
||||
uiWindow(w)->Margined = windowMargined;
|
||||
uiWindow(w)->SetMargined = windowSetMargined;
|
||||
|
||||
return uiWindow(w);
|
||||
}
|
Loading…
Reference in New Issue