More rewriting imports. Also moved ui.h to out/.
This commit is contained in:
parent
b98de32786
commit
06cad86f55
|
@ -0,0 +1,63 @@
|
||||||
|
# 22 april 2015
|
||||||
|
|
||||||
|
OUTBASE = new
|
||||||
|
OUTDIR = out
|
||||||
|
OBJDIR = .obj
|
||||||
|
|
||||||
|
IDLFILES = \
|
||||||
|
ui.idl \
|
||||||
|
$(baseIDLFILES)
|
||||||
|
|
||||||
|
xHFILES = \
|
||||||
|
uipriv.h \
|
||||||
|
$(IDLFILES:%.idl=$(OUTDIR)/%.h) \
|
||||||
|
$(baseHFILES)
|
||||||
|
|
||||||
|
OFILES = \
|
||||||
|
$(baseCFILES:%.c=$(OBJDIR)/%.o) \
|
||||||
|
$(baseMFILES:%.m=$(OBJDIR)/%.o)
|
||||||
|
|
||||||
|
xCFLAGS = \
|
||||||
|
-g \
|
||||||
|
-Wall -Wextra \
|
||||||
|
-Wno-unused-parameter \
|
||||||
|
-Wno-switch \
|
||||||
|
--std=c99 \
|
||||||
|
$(CFLAGS) \
|
||||||
|
$(archmflag) \
|
||||||
|
$(baseCFLAGS)
|
||||||
|
|
||||||
|
xLDFLAGS = \
|
||||||
|
-g \
|
||||||
|
$(LDFLAGS) \
|
||||||
|
$(archmflag) \
|
||||||
|
$(baseLDFLAGS)
|
||||||
|
|
||||||
|
OUT = $(OUTDIR)/$(OUTBASE)$(baseSUFFIX)
|
||||||
|
|
||||||
|
$(OUT): $(OFILES) | $(OUTDIR)/.phony
|
||||||
|
@$(CC) -o $(OUT) $(OFILES) $(xLDFLAGS)
|
||||||
|
@echo ====== Linked $(OUT)
|
||||||
|
|
||||||
|
.SECONDEXPANSION:
|
||||||
|
$(OBJDIR)/%.o: %.c $(xHFILES) | $$(dir $$@).phony
|
||||||
|
@$(CC) -o $@ -c $< $(xCFLAGS)
|
||||||
|
@echo ====== Compiled $<
|
||||||
|
|
||||||
|
$(OBJDIR)/%.o: %.m $(xHFILES) | $$(dir $$@).phony
|
||||||
|
@$(CC) -o $@ -c $< $(xCFLAGS)
|
||||||
|
@echo ====== Compiled $<
|
||||||
|
|
||||||
|
# see http://www.cmcrossroads.com/article/making-directories-gnu-make
|
||||||
|
%/.phony:
|
||||||
|
@mkdir -p $(dir $@)
|
||||||
|
@touch $@
|
||||||
|
.PRECIOUS: %/.phony
|
||||||
|
|
||||||
|
$(OUTDIR)/%.h: %.idl tools/idl2h.go | $(OUTDIR)/.phony
|
||||||
|
@go run tools/idl2h.go -extern _UI_EXTERN -guard __UI_UI_H__ < $< > $@
|
||||||
|
@echo ====== Generated `basename $@`
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(OUTDIR) $(OBJDIR) ui.h
|
||||||
|
.PHONY: clean
|
|
@ -0,0 +1,46 @@
|
||||||
|
# 22 april 2015
|
||||||
|
|
||||||
|
# MAME does this so :/
|
||||||
|
ifeq ($(OS),Windows_NT)
|
||||||
|
OS = windows
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifndef OS
|
||||||
|
UNAME = $(shell uname -s)
|
||||||
|
ifeq ($(UNAME),Darwin)
|
||||||
|
OS = darwin
|
||||||
|
else
|
||||||
|
OS = unix
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
include $(OS)/GNUmakeinc.mk
|
||||||
|
|
||||||
|
#baseIDLFILES = \
|
||||||
|
# ui_$(OS).idl
|
||||||
|
|
||||||
|
baseHFILES = \
|
||||||
|
uipriv.h \
|
||||||
|
ui_$(OS).h \
|
||||||
|
$(osHFILES)
|
||||||
|
|
||||||
|
baseCFILES = \
|
||||||
|
box.c \
|
||||||
|
ptrarray.c \
|
||||||
|
shouldquit.c \
|
||||||
|
$(osCFILES)
|
||||||
|
|
||||||
|
baseMFILES = $(osMFILES)
|
||||||
|
|
||||||
|
baseCFLAGS = $(osCFLAGS)
|
||||||
|
baseLDFLAGS = \
|
||||||
|
-shared \
|
||||||
|
$(osLDWarnUndefinedFlags) \
|
||||||
|
$(osLDFLAGS)
|
||||||
|
baseSUFFIX = $(osLIBSUFFIX)
|
||||||
|
|
||||||
|
include GNUbase.mk
|
||||||
|
|
||||||
|
test: $(OUT)
|
||||||
|
@$(MAKE) -f GNUmaketest.mk osLIB=$(OUT) osEXESUFFIX=$(osEXESUFFIX) CC=$(CC) archmflag=$(archmflag)
|
||||||
|
.PHONY: test
|
|
@ -0,0 +1,16 @@
|
||||||
|
# 22 april 2015
|
||||||
|
# should never be invoked directly, only ever from the main makefile
|
||||||
|
|
||||||
|
include test/GNUmakeinc.mk
|
||||||
|
|
||||||
|
baseHFILES = \
|
||||||
|
ui.h \
|
||||||
|
$(testHFILES)
|
||||||
|
|
||||||
|
baseCFILES = $(testCFILES)
|
||||||
|
|
||||||
|
baseCFLAGS = $(testCFLAGS)
|
||||||
|
baseLDFLAGS = $(osLIB) $(testLDFLAGS)
|
||||||
|
baseSUFFIX = $(osEXESUFFIX)
|
||||||
|
|
||||||
|
include GNUbase.mk
|
|
@ -0,0 +1,296 @@
|
||||||
|
// 7 april 2015
|
||||||
|
#include "out/ui.h"
|
||||||
|
#include "uipriv.h"
|
||||||
|
|
||||||
|
struct box {
|
||||||
|
uiBox b;
|
||||||
|
void (*baseDestroy)(uiControl *);
|
||||||
|
struct ptrArray *controls;
|
||||||
|
int vertical;
|
||||||
|
void (*baseSetParent)(uiControl *, uiContainer *);
|
||||||
|
uiContainer *parent;
|
||||||
|
int padded;
|
||||||
|
};
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
struct box *b = (struct box *) c;
|
||||||
|
struct boxControl *bc;
|
||||||
|
|
||||||
|
if (b->parent != NULL)
|
||||||
|
complain("attempt to destroy uiBox %p while it has a parent", b);
|
||||||
|
// don't chain up to base here; we need to destroy children ourselves first
|
||||||
|
while (b->controls->len != 0) {
|
||||||
|
bc = ptrArrayIndex(b->controls, struct boxControl *, 0);
|
||||||
|
uiControlSetParent(bc->c, NULL);
|
||||||
|
uiControlDestroy(bc->c);
|
||||||
|
ptrArrayDelete(b->controls, 0);
|
||||||
|
uiFree(bc);
|
||||||
|
}
|
||||||
|
ptrArrayDestroy(b->controls);
|
||||||
|
// NOW we can chain up to base
|
||||||
|
(*(b->baseDestroy))(uiControl(b));
|
||||||
|
uiFree(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void boxSetParent(uiControl *c, uiContainer *parent)
|
||||||
|
{
|
||||||
|
struct box *b = (struct box *) c;
|
||||||
|
|
||||||
|
// this does all the actual work
|
||||||
|
(*(b->baseSetParent))(uiControl(b), parent);
|
||||||
|
// we just need to have a copy of the parent ourselves for boxSetPadded()
|
||||||
|
b->parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void boxPreferredSize(uiControl *c, uiSizing *d, intmax_t *width, intmax_t *height)
|
||||||
|
{
|
||||||
|
struct box *b = (struct box *) c;
|
||||||
|
struct boxControl *bc;
|
||||||
|
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->controls->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
|
||||||
|
// TODO this is wrong if any controls are hidden
|
||||||
|
if (b->vertical)
|
||||||
|
*height = (b->controls->len - 1) * ypadding;
|
||||||
|
else
|
||||||
|
*width = (b->controls->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->controls->len; i++) {
|
||||||
|
bc = ptrArrayIndex(b->controls, struct boxControl *, i);
|
||||||
|
if (!uiControlVisible(bc->c))
|
||||||
|
continue;
|
||||||
|
uiControlPreferredSize(bc->c, d, &preferredWidth, &preferredHeight);
|
||||||
|
if (bc->stretchy) {
|
||||||
|
nStretchy++;
|
||||||
|
if (maxStretchyWidth < preferredWidth)
|
||||||
|
maxStretchyWidth = preferredWidth;
|
||||||
|
if (maxStretchyHeight < preferredHeight)
|
||||||
|
maxStretchyHeight = preferredHeight;
|
||||||
|
}
|
||||||
|
if (b->vertical) {
|
||||||
|
if (*width < preferredWidth)
|
||||||
|
*width = preferredWidth;
|
||||||
|
if (!bc->stretchy)
|
||||||
|
*height += preferredHeight;
|
||||||
|
} else {
|
||||||
|
if (!bc->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 boxSysFunc(uiControl *c, uiControlSysFuncParams *p)
|
||||||
|
{
|
||||||
|
struct box *b = (struct box *) c;
|
||||||
|
struct boxControl *bc;
|
||||||
|
uintmax_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < b->controls->len; i++) {
|
||||||
|
bc = ptrArrayIndex(b->controls, struct boxControl *, i);
|
||||||
|
uiControlSysFunc(bc->c, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void boxResizeChildren(uiContainer *c, intmax_t x, intmax_t y, intmax_t width, intmax_t height, uiSizing *d)
|
||||||
|
{
|
||||||
|
struct box *b = (struct box *) c;
|
||||||
|
struct boxControl *bc;
|
||||||
|
int xpadding, ypadding;
|
||||||
|
uintmax_t nStretchy;
|
||||||
|
intmax_t stretchywid, stretchyht;
|
||||||
|
uintmax_t i;
|
||||||
|
intmax_t preferredWidth, preferredHeight;
|
||||||
|
|
||||||
|
if (b->controls->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
|
||||||
|
// TODO this is incorrect if any controls are hidden
|
||||||
|
if (b->vertical)
|
||||||
|
height -= (b->controls->len - 1) * ypadding;
|
||||||
|
else
|
||||||
|
width -= (b->controls->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->controls->len; i++) {
|
||||||
|
bc = ptrArrayIndex(b->controls, struct boxControl *, i);
|
||||||
|
if (!uiControlVisible(bc->c))
|
||||||
|
continue;
|
||||||
|
if (bc->stretchy) {
|
||||||
|
nStretchy++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
uiControlPreferredSize(bc->c, d, &preferredWidth, &preferredHeight);
|
||||||
|
if (b->vertical) { // all controls have same width
|
||||||
|
bc->width = width;
|
||||||
|
bc->height = preferredHeight;
|
||||||
|
stretchyht -= preferredHeight;
|
||||||
|
} else { // all controls have same height
|
||||||
|
bc->width = preferredWidth;
|
||||||
|
bc->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->controls->len; i++) {
|
||||||
|
bc = ptrArrayIndex(b->controls, struct boxControl *, i);
|
||||||
|
if (!uiControlVisible(bc->c))
|
||||||
|
continue;
|
||||||
|
if (bc->stretchy) {
|
||||||
|
bc->width = stretchywid;
|
||||||
|
bc->height = stretchyht;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3) now we can position controls
|
||||||
|
for (i = 0; i < b->controls->len; i++) {
|
||||||
|
bc = ptrArrayIndex(b->controls, struct boxControl *, i);
|
||||||
|
if (!uiControlVisible(bc->c))
|
||||||
|
continue;
|
||||||
|
uiControlResize(bc->c, x, y, bc->width, bc->height, d);
|
||||||
|
if (b->vertical)
|
||||||
|
y += bc->height + ypadding;
|
||||||
|
else
|
||||||
|
x += bc->width + xpadding;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void boxAppend(uiBox *ss, uiControl *c, int stretchy)
|
||||||
|
{
|
||||||
|
struct box *b = (struct box *) ss;
|
||||||
|
struct boxControl *bc;
|
||||||
|
|
||||||
|
bc = uiNew(struct boxControl);
|
||||||
|
bc->c = c;
|
||||||
|
bc->stretchy = stretchy;
|
||||||
|
uiControlSetParent(bc->c, uiContainer(b));
|
||||||
|
ptrArrayAppend(b->controls, bc);
|
||||||
|
uiContainerUpdate(uiContainer(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void boxDelete(uiBox *ss, uintmax_t index)
|
||||||
|
{
|
||||||
|
struct box *b = (struct box *) ss;
|
||||||
|
struct boxControl *bc;
|
||||||
|
uiControl *removed;
|
||||||
|
|
||||||
|
// TODO rearrange this
|
||||||
|
// TODO sync call order with that of Destroy()
|
||||||
|
bc = ptrArrayIndex(b->controls, struct boxControl *, index);
|
||||||
|
removed = bc->c;
|
||||||
|
ptrArrayDelete(b->controls, index);
|
||||||
|
uiControlSetParent(removed, NULL);
|
||||||
|
uiFree(bc);
|
||||||
|
uiContainerUpdate(uiContainer(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int boxPadded(uiBox *ss)
|
||||||
|
{
|
||||||
|
struct box *b = (struct box *) ss;
|
||||||
|
|
||||||
|
return b->padded;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void boxSetPadded(uiBox *ss, int padded)
|
||||||
|
{
|
||||||
|
struct box *b = (struct box *) ss;
|
||||||
|
|
||||||
|
b->padded = padded;
|
||||||
|
uiContainerUpdate(uiContainer(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
uiBox *uiNewHorizontalBox(void)
|
||||||
|
{
|
||||||
|
struct box *b;
|
||||||
|
|
||||||
|
b = uiNew(struct box);
|
||||||
|
|
||||||
|
uiMakeContainer(uiContainer(b));
|
||||||
|
|
||||||
|
b->controls = newPtrArray();
|
||||||
|
|
||||||
|
b->baseDestroy = uiControl(b)->Destroy;
|
||||||
|
uiControl(b)->Destroy = boxDestroy;
|
||||||
|
b->baseSetParent = uiControl(b)->SetParent;
|
||||||
|
uiControl(b)->SetParent = boxSetParent;
|
||||||
|
uiControl(b)->PreferredSize = boxPreferredSize;
|
||||||
|
uiControl(b)->SysFunc = boxSysFunc;
|
||||||
|
|
||||||
|
uiContainer(b)->ResizeChildren = boxResizeChildren;
|
||||||
|
|
||||||
|
uiBox(b)->Append = boxAppend;
|
||||||
|
uiBox(b)->Delete = boxDelete;
|
||||||
|
uiBox(b)->Padded = boxPadded;
|
||||||
|
uiBox(b)->SetPadded = boxSetPadded;
|
||||||
|
|
||||||
|
return uiBox(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
uiBox *uiNewVerticalBox(void)
|
||||||
|
{
|
||||||
|
uiBox *bb;
|
||||||
|
struct box *b;
|
||||||
|
|
||||||
|
bb = uiNewHorizontalBox();
|
||||||
|
b = (struct box *) bb;
|
||||||
|
b->vertical = 1;
|
||||||
|
return bb;
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
// 5 may 2015
|
||||||
|
#include <string.h>
|
||||||
|
#include "out/ui.h"
|
||||||
|
#include "uipriv.h"
|
||||||
|
|
||||||
|
struct ptrArray *newPtrArray(void)
|
||||||
|
{
|
||||||
|
return uiNew(struct ptrArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ptrArrayDestroy(struct ptrArray *p)
|
||||||
|
{
|
||||||
|
if (p->len != 0)
|
||||||
|
complain("attempt to destroy ptrarray %p while it still has pointers inside", p);
|
||||||
|
if (p->ptrs != NULL) // array was created but nothing was ever put inside
|
||||||
|
uiFree(p->ptrs);
|
||||||
|
uiFree(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define grow 32
|
||||||
|
|
||||||
|
void ptrArrayAppend(struct ptrArray *p, void *d)
|
||||||
|
{
|
||||||
|
if (p->len >= p->cap) {
|
||||||
|
p->cap += grow;
|
||||||
|
p->ptrs = (void **) uiRealloc(p->ptrs, p->cap * sizeof (void *), "void *[]");
|
||||||
|
}
|
||||||
|
p->ptrs[p->len] = d;
|
||||||
|
p->len++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ptrArrayInsertBefore(struct ptrArray *p, uintmax_t i, void *d)
|
||||||
|
{
|
||||||
|
if (i >= p->len)
|
||||||
|
complain("index out of range in ptrArrayInsertBefore()");
|
||||||
|
if (p->len >= p->cap) {
|
||||||
|
p->cap += grow;
|
||||||
|
p->ptrs = (void **) uiRealloc(p->ptrs, p->cap * sizeof (void *), "void *[]");
|
||||||
|
}
|
||||||
|
// thanks to ValleyBell
|
||||||
|
memmove(&(p->ptrs[i + 1]), &(p->ptrs[i]), (p->len - i) * sizeof (void *));
|
||||||
|
p->ptrs[i] = d;
|
||||||
|
p->len++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ptrArrayDelete(struct ptrArray *p, uintmax_t i)
|
||||||
|
{
|
||||||
|
if (i >= p->len)
|
||||||
|
complain("index out of range in ptrArrayRemove()");
|
||||||
|
// thanks to ValleyBell
|
||||||
|
memmove(&(p->ptrs[i]), &(p->ptrs[i + 1]), (p->len - i - 1) * sizeof (void *));
|
||||||
|
p->ptrs[p->len - 1] = NULL;
|
||||||
|
p->len--;
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
// 9 may 2015
|
||||||
|
#include "out/ui.h"
|
||||||
|
#include "uipriv.h"
|
||||||
|
|
||||||
|
static int defaultOnShouldQuit(void *data)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int (*onShouldQuit)(void *) = defaultOnShouldQuit;
|
||||||
|
static void *onShouldQuitData;
|
||||||
|
|
||||||
|
void uiOnShouldQuit(int (*f)(void *), void *data)
|
||||||
|
{
|
||||||
|
onShouldQuit = f;
|
||||||
|
onShouldQuitData = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
int shouldQuit(void)
|
||||||
|
{
|
||||||
|
return (*onShouldQuit)(onShouldQuitData);
|
||||||
|
}
|
|
@ -0,0 +1,188 @@
|
||||||
|
// 15 april 2015
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"flag"
|
||||||
|
"github.com/andlabs/pgidl"
|
||||||
|
)
|
||||||
|
|
||||||
|
var extern = flag.String("extern", "extern", "name for extern")
|
||||||
|
var guard = flag.String("guard", "", "#define name for include guards")
|
||||||
|
|
||||||
|
var pkgtypes = map[string]string{}
|
||||||
|
|
||||||
|
func typedecl(t *pgidl.Type, name string) string {
|
||||||
|
if t == nil {
|
||||||
|
return "void " + name
|
||||||
|
}
|
||||||
|
if t.IsFuncPtr {
|
||||||
|
return cfuncptrdecl(t.FuncType, name)
|
||||||
|
}
|
||||||
|
s := t.Name + " "
|
||||||
|
if pkgtypes[t.Name] != "" {
|
||||||
|
s = pkgtypes[t.Name] + " "
|
||||||
|
}
|
||||||
|
for i := uint(0); i < t.NumPtrs; i++ {
|
||||||
|
s += "*"
|
||||||
|
}
|
||||||
|
return s + name
|
||||||
|
}
|
||||||
|
|
||||||
|
func arglist(a []*pgidl.Arg) string {
|
||||||
|
if len(a) == 0 {
|
||||||
|
return "void"
|
||||||
|
}
|
||||||
|
s := typedecl(a[0].Type, a[0].Name)
|
||||||
|
for i := 1; i < len(a); i++ {
|
||||||
|
s += ", " + typedecl(a[i].Type, a[i].Name)
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func cfuncdecl(f *pgidl.Func, name string) string {
|
||||||
|
fd := name + "(" + arglist(f.Args) + ")"
|
||||||
|
return *extern + " " + typedecl(f.Ret, fd) + ";"
|
||||||
|
}
|
||||||
|
|
||||||
|
func cfuncptrdecl(f *pgidl.Func, name string) string {
|
||||||
|
name = "(*" + name + ")"
|
||||||
|
fd := name + "(" + arglist(f.Args) + ")"
|
||||||
|
return typedecl(f.Ret, fd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func cmethodmacro(f *pgidl.Func, typename string) string {
|
||||||
|
s := "#define " + typename + f.Name + "("
|
||||||
|
first := true
|
||||||
|
for _, a := range f.Args {
|
||||||
|
if !first {
|
||||||
|
s += ", "
|
||||||
|
}
|
||||||
|
s += a.Name
|
||||||
|
first = false
|
||||||
|
}
|
||||||
|
s += ") ("
|
||||||
|
s += "(*((this)->" + f.Name + "))"
|
||||||
|
s += "("
|
||||||
|
first = true
|
||||||
|
for _, a := range f.Args {
|
||||||
|
if !first {
|
||||||
|
s += ", "
|
||||||
|
}
|
||||||
|
s += "(" + a.Name + ")"
|
||||||
|
first = false
|
||||||
|
}
|
||||||
|
s += ")"
|
||||||
|
s += ")"
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func genpkgfunc(f *pgidl.Func, prefix string) {
|
||||||
|
fmt.Printf("%s\n", cfuncdecl(f, prefix + f.Name))
|
||||||
|
}
|
||||||
|
|
||||||
|
func genstruct(s *pgidl.Struct, prefix string) {
|
||||||
|
fmt.Printf("struct %s%s {\n", prefix, s.Name)
|
||||||
|
for _, f := range s.Fields {
|
||||||
|
fmt.Printf("\t%s;\n", typedecl(f.Type, f.Name))
|
||||||
|
}
|
||||||
|
fmt.Printf("};\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func geniface(i *pgidl.Interface, prefix string) {
|
||||||
|
fmt.Printf("struct %s%s {\n", prefix, i.Name)
|
||||||
|
if i.From != "" {
|
||||||
|
fmt.Printf("\t%s%s base;\n", prefix, i.From)
|
||||||
|
}
|
||||||
|
for _, f := range i.Fields {
|
||||||
|
fmt.Printf("\t%s;\n", typedecl(f.Type, f.Name))
|
||||||
|
}
|
||||||
|
for _, m := range i.Methods {
|
||||||
|
// hack our this pointer in
|
||||||
|
m.Args = append([]*pgidl.Arg{
|
||||||
|
&pgidl.Arg{
|
||||||
|
Name: "this",
|
||||||
|
Type: &pgidl.Type{
|
||||||
|
Name: prefix + i.Name,
|
||||||
|
NumPtrs: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, m.Args...)
|
||||||
|
fmt.Printf("\t%s;\n", cfuncptrdecl(m, m.Name))
|
||||||
|
fmt.Printf("%s\n", cmethodmacro(m, prefix + i.Name))
|
||||||
|
}
|
||||||
|
fmt.Printf("};\n")
|
||||||
|
fmt.Printf("#define %s%s(this) ((%s%s *) (this))\n",
|
||||||
|
prefix, i.Name,
|
||||||
|
prefix, i.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func genenum(e *pgidl.Enum, prefix string) {
|
||||||
|
fmt.Printf("enum %s%s {\n", prefix, e.Name)
|
||||||
|
for _, m := range e.Members {
|
||||||
|
fmt.Printf("\t%s%s%s,\n", prefix, e.Name, m)
|
||||||
|
}
|
||||||
|
fmt.Printf("};\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func genpkg(p *pgidl.Package) {
|
||||||
|
for _, s := range p.Structs {
|
||||||
|
fmt.Printf("typedef struct %s%s %s%s;\n",
|
||||||
|
p.Name, s.Name,
|
||||||
|
p.Name, s.Name)
|
||||||
|
pkgtypes[s.Name] = p.Name + s.Name
|
||||||
|
}
|
||||||
|
for _, i := range p.Interfaces {
|
||||||
|
fmt.Printf("typedef struct %s%s %s%s;\n",
|
||||||
|
p.Name, i.Name,
|
||||||
|
p.Name, i.Name)
|
||||||
|
pkgtypes[i.Name] = p.Name + i.Name
|
||||||
|
}
|
||||||
|
for _, e := range p.Enums {
|
||||||
|
fmt.Printf("typedef enum %s%s %s%s;\n",
|
||||||
|
p.Name, e.Name,
|
||||||
|
p.Name, e.Name)
|
||||||
|
pkgtypes[e.Name] = p.Name + e.Name
|
||||||
|
}
|
||||||
|
// apparently we have to fully define C enumerations before we can use them...
|
||||||
|
for _, e := range p.Enums {
|
||||||
|
genenum(e, p.Name)
|
||||||
|
}
|
||||||
|
for _, o := range p.Order {
|
||||||
|
switch o.Which {
|
||||||
|
case pgidl.Funcs:
|
||||||
|
genpkgfunc(p.Funcs[o.Index], p.Name)
|
||||||
|
case pgidl.Structs:
|
||||||
|
genstruct(p.Structs[o.Index], p.Name)
|
||||||
|
case pgidl.Interfaces:
|
||||||
|
geniface(p.Interfaces[o.Index], p.Name)
|
||||||
|
case pgidl.Raws:
|
||||||
|
fmt.Printf("%s\n", p.Raws[o.Index])
|
||||||
|
case pgidl.Enums:
|
||||||
|
// we did them already; see above
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.Parse()
|
||||||
|
idl, errs := pgidl.Parse(os.Stdin, "<stdin>")
|
||||||
|
if len(errs) != 0 {
|
||||||
|
for _, e := range errs {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s\n", e)
|
||||||
|
}
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
fmt.Printf("// generated by idl2h; do not edit\n")
|
||||||
|
if *guard != "" {
|
||||||
|
fmt.Printf("#ifndef %s\n", *guard)
|
||||||
|
fmt.Printf("#define %s\n", *guard)
|
||||||
|
}
|
||||||
|
for _, p := range idl {
|
||||||
|
genpkg(p)
|
||||||
|
}
|
||||||
|
if *guard != "" {
|
||||||
|
fmt.Printf("#endif\n")
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,79 @@
|
||||||
|
// 7 april 2015
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file assumes that you have included <windows.h> and "ui.h" beforehand. It provides API-specific functions for interfacing with foreign controls in Windows.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __UI_UI_WINDOWS_H__
|
||||||
|
#define __UI_UI_WINDOWS_H__
|
||||||
|
|
||||||
|
// uiWindowsMakeControl() initializes the given uiControl with the given Windows API control inside.
|
||||||
|
// You will need to provide the preferredSize() method yourself.
|
||||||
|
typedef struct uiWindowsMakeControlParams uiWindowsMakeControlParams;
|
||||||
|
struct uiWindowsMakeControlParams {
|
||||||
|
// These match the CreateWindowExW() function.
|
||||||
|
DWORD dwExStyle;
|
||||||
|
LPCWSTR lpClassName;
|
||||||
|
LPCWSTR lpWindowName;
|
||||||
|
DWORD dwStyle; // WS_CHILD and WS_VISIBLE are automatically applied.
|
||||||
|
HINSTANCE hInstance;
|
||||||
|
|
||||||
|
// Set this to non-FALSE to use the standard control font used by other ui controls.
|
||||||
|
BOOL useStandardControlFont;
|
||||||
|
|
||||||
|
// These are called when the control sends a WM_COMMAND or WM_NOTIFY (respectively) to its parent.
|
||||||
|
// ui redirects the message back and calls these functions.
|
||||||
|
// Store the result in *lResult and return any non-FALSE value (such as TRUE) to return the given result; return FALSE to pass the notification up to your window procedure.
|
||||||
|
// Note that these are only issued if they come from the uiControl itself; notifications from children of the uiControl (such as a header control) will be received normally.
|
||||||
|
BOOL (*onWM_COMMAND)(uiControl *c, WORD code, LRESULT *lResult);
|
||||||
|
BOOL (*onWM_NOTIFY)(uiControl *c, NMHDR *nm, LRESULT *lResult);
|
||||||
|
|
||||||
|
// This is called when the widget is ready to be destroyed.
|
||||||
|
void (*onDestroy)(void *data);
|
||||||
|
void *onDestroyData;
|
||||||
|
};
|
||||||
|
_UI_EXTERN void uiWindowsMakeControl(uiControl *c, uiWindowsMakeControlParams *p);
|
||||||
|
|
||||||
|
// This contains the Windows-specific parts of the uiSizing structure.
|
||||||
|
// BaseX and BaseY are the dialog base units.
|
||||||
|
// InternalLeading is the standard control font's internal leading; labels in uiForms use this for correct Y positioning.
|
||||||
|
struct uiSizingSys {
|
||||||
|
int BaseX;
|
||||||
|
int BaseY;
|
||||||
|
LONG InternalLeading;
|
||||||
|
|
||||||
|
// This is the window handle to pass to the hWndInsertAfter parameter of SetWindowPos().
|
||||||
|
// You should set this to your own window handle when done.
|
||||||
|
// Controls made with uiWindowsMakeControl() do this for you; you only need to do this if you are implementing uiControlResize() yourself.
|
||||||
|
HWND InsertAfter;
|
||||||
|
};
|
||||||
|
// Use these in your preferredSize() implementation with baseX and baseY.
|
||||||
|
#define uiWindowsDlgUnitsToX(dlg, baseX) MulDiv((dlg), baseX, 4)
|
||||||
|
#define uiWindowsDlgUnitsToY(dlg, baseY) MulDiv((dlg), baseY, 8)
|
||||||
|
|
||||||
|
// and use this if you need the text of the window width
|
||||||
|
_UI_EXTERN intmax_t uiWindowsWindowTextWidth(HWND hwnd);
|
||||||
|
|
||||||
|
// these functions get and set the window text for such a uiControl
|
||||||
|
// the value returned should be freed with uiFreeText()
|
||||||
|
_UI_EXTERN char *uiWindowsControlText(uiControl *);
|
||||||
|
_UI_EXTERN void uiWindowsControlSetText(uiControl *, const char *);
|
||||||
|
|
||||||
|
struct uiControlSysFuncParams {
|
||||||
|
int Func;
|
||||||
|
BOOL HasTabStops;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
// These should enable and disable the uiControl while preserving the user enable/disable setting.
|
||||||
|
// These are needed because while disabling a parent window does cause children to stop receiving events, they are not shown as disabled, which is not what we want.
|
||||||
|
uiWindowsSysFuncContainerEnable,
|
||||||
|
uiWindowsSysFuncContainerDisable,
|
||||||
|
// This is interpreted by controls that are tab stops; the control should set HasTabStops to TRUE if so, and *LEAVE IT ALONE* if not.
|
||||||
|
// You only need this if implementing your own uiControl.
|
||||||
|
// Controls created with uiWindowsMakeControl() check for the window being enabled and the presence of WS_TABSTOP.
|
||||||
|
// The name is "has tab stops" because it is used by uiTabs to say "does the current tab page have tab stops?".
|
||||||
|
uiWindowsSysFuncHasTabStops,
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,34 @@
|
||||||
|
// 6 april 2015
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
extern uiInitOptions options;
|
||||||
|
|
||||||
|
extern void *uiAlloc(size_t, const char *);
|
||||||
|
#define uiNew(T) ((T *) uiAlloc(sizeof (T), #T))
|
||||||
|
extern void *uiRealloc(void *, size_t, const char *);
|
||||||
|
extern void uiFree(void *);
|
||||||
|
|
||||||
|
extern void complain(const char *, ...);
|
||||||
|
|
||||||
|
extern uiBin *newBin(void);
|
||||||
|
extern int binHasOSParent(uiBin *);
|
||||||
|
extern void binSetOSParent(uiBin *, uintptr_t);
|
||||||
|
extern void binRemoveOSParent(uiBin *);
|
||||||
|
extern void binResizeRootAndUpdate(uiBin *, intmax_t, intmax_t, intmax_t, intmax_t);
|
||||||
|
extern void binTranslateMargins(uiBin *, intmax_t *, intmax_t *, intmax_t *, intmax_t *, uiSizing *);
|
||||||
|
|
||||||
|
// array.c
|
||||||
|
struct ptrArray {
|
||||||
|
void **ptrs;
|
||||||
|
uintmax_t len;
|
||||||
|
uintmax_t cap;
|
||||||
|
};
|
||||||
|
struct ptrArray *newPtrArray(void);
|
||||||
|
void ptrArrayDestroy(struct ptrArray *);
|
||||||
|
void ptrArrayAppend(struct ptrArray *, void *);
|
||||||
|
void ptrArrayInsertBefore(struct ptrArray *, uintmax_t, void *);
|
||||||
|
void ptrArrayDelete(struct ptrArray *, uintmax_t);
|
||||||
|
#define ptrArrayIndex(p, T, i) ((T) ((p)->ptrs[(i)]))
|
||||||
|
|
||||||
|
// shouldquit.c
|
||||||
|
int shouldQuit(void);
|
|
@ -0,0 +1,53 @@
|
||||||
|
# 22 april 2015
|
||||||
|
|
||||||
|
osCFILES = \
|
||||||
|
windows/alloc.c \
|
||||||
|
windows/bin.c \
|
||||||
|
windows/button.c \
|
||||||
|
windows/checkbox.c \
|
||||||
|
windows/comctl32.c \
|
||||||
|
windows/container.c \
|
||||||
|
windows/debug.c \
|
||||||
|
windows/entry.c \
|
||||||
|
windows/group.c \
|
||||||
|
windows/init.c \
|
||||||
|
windows/label.c \
|
||||||
|
windows/main.c \
|
||||||
|
windows/menu.c \
|
||||||
|
windows/newcontrol.c \
|
||||||
|
windows/tab.c \
|
||||||
|
windows/text.c \
|
||||||
|
windows/util.c \
|
||||||
|
windows/window.c
|
||||||
|
|
||||||
|
osHFILES = \
|
||||||
|
windows/uipriv_windows.h
|
||||||
|
|
||||||
|
# thanks ebassi in irc.gimp.net/#gtk+
|
||||||
|
osCFLAGS = \
|
||||||
|
-D_UI_EXTERN='__declspec(dllexport) extern'
|
||||||
|
|
||||||
|
osLDFLAGS = \
|
||||||
|
-static-libgcc \
|
||||||
|
-luser32 -lkernel32 -lgdi32 -luxtheme -lmsimg32 -lcomdlg32 -lole32 -loleaut32 -loleacc -luuid
|
||||||
|
|
||||||
|
osLDWarnUndefinedFlags = -Wl,--no-undefined -Wl,--no-allow-shlib-undefined
|
||||||
|
|
||||||
|
osLIBSUFFIX = .dll
|
||||||
|
osEXESUFFIX = .exe
|
||||||
|
|
||||||
|
ifeq ($(ARCH),amd64)
|
||||||
|
CC = x86_64-w64-mingw32-gcc
|
||||||
|
RC = x86_64-w64-mingw32-windres
|
||||||
|
archmflag = -m64
|
||||||
|
else
|
||||||
|
CC = i686-w64-mingw32-gcc
|
||||||
|
RC = i686-w64-mingw32-windres
|
||||||
|
archmflag = -m32
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(PROFILE),1)
|
||||||
|
osCFILES += windows/profiler.c
|
||||||
|
osCFLAGS += -finstrument-functions
|
||||||
|
osLDFLAGS += -finstrument-functions
|
||||||
|
endif
|
|
@ -0,0 +1,2 @@
|
||||||
|
// 14 may 2015
|
||||||
|
#include "uipriv_windows.h"
|
|
@ -0,0 +1,96 @@
|
||||||
|
// 6 january 2015
|
||||||
|
#define UNICODE
|
||||||
|
#define _UNICODE
|
||||||
|
#define STRICT
|
||||||
|
#define STRICT_TYPED_ITEMIDS
|
||||||
|
#define CINTERFACE
|
||||||
|
#define COBJMACROS
|
||||||
|
// see https://github.com/golang/go/issues/9916#issuecomment-74812211
|
||||||
|
#define INITGUID
|
||||||
|
// get Windows version right; right now Windows XP
|
||||||
|
#define WINVER 0x0501
|
||||||
|
#define _WIN32_WINNT 0x0501
|
||||||
|
#define _WIN32_WINDOWS 0x0501 /* according to Microsoft's winperf.h */
|
||||||
|
#define _WIN32_IE 0x0600 /* according to Microsoft's sdkddkver.h */
|
||||||
|
#define NTDDI_VERSION 0x05010000 /* according to Microsoft's sdkddkver.h */
|
||||||
|
#include <windows.h>
|
||||||
|
#include <commctrl.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <uxtheme.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
#include <windowsx.h>
|
||||||
|
#include <vsstyle.h>
|
||||||
|
#include <vssym32.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <oleacc.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "../out/ui.h"
|
||||||
|
#include "../ui_windows.h"
|
||||||
|
#include "../uipriv.h"
|
||||||
|
|
||||||
|
// ui internal window messages
|
||||||
|
enum {
|
||||||
|
// redirected WM_COMMAND and WM_NOTIFY
|
||||||
|
msgCOMMAND = WM_APP + 0x40, // start offset just to be safe
|
||||||
|
msgNOTIFY,
|
||||||
|
msgUpdateChild, // fake because Windows seems to SWP_NOSIZE MoveWindow()s and SetWindowPos()s that don't change the window size (even if SWP_NOSIZE isn't specified)
|
||||||
|
msgHasTabStops,
|
||||||
|
msgConsoleEndSession,
|
||||||
|
};
|
||||||
|
|
||||||
|
// debug.c
|
||||||
|
extern HRESULT logLastError(const char *);
|
||||||
|
extern HRESULT logHRESULT(const char *, HRESULT);
|
||||||
|
extern HRESULT logMemoryExhausted(const char *);
|
||||||
|
|
||||||
|
// init.c
|
||||||
|
extern HINSTANCE hInstance;
|
||||||
|
extern int nCmdShow;
|
||||||
|
extern HFONT hMessageFont;
|
||||||
|
extern HBRUSH hollowBrush;
|
||||||
|
|
||||||
|
// util.c
|
||||||
|
extern int windowClassOf(HWND, ...);
|
||||||
|
extern void mapWindowRect(HWND, HWND, RECT *);
|
||||||
|
extern DWORD getStyle(HWND);
|
||||||
|
extern void setStyle(HWND, DWORD);
|
||||||
|
extern DWORD getExStyle(HWND);
|
||||||
|
extern void setExStyle(HWND, DWORD);
|
||||||
|
extern void moveWindow(HWND, intmax_t, intmax_t, intmax_t, intmax_t);
|
||||||
|
extern void moveAndReorderWindow(HWND, HWND, intmax_t, intmax_t, intmax_t, intmax_t);
|
||||||
|
|
||||||
|
// text.c
|
||||||
|
extern WCHAR *toUTF16(const char *);
|
||||||
|
extern char *toUTF8(const WCHAR *);
|
||||||
|
extern WCHAR *windowText(HWND);
|
||||||
|
|
||||||
|
// comctl32.c
|
||||||
|
extern BOOL (*WINAPI fv_SetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR);
|
||||||
|
extern BOOL (*WINAPI fv_RemoveWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR);
|
||||||
|
extern LRESULT (*WINAPI fv_DefSubclassProc)(HWND, UINT, WPARAM, LPARAM);
|
||||||
|
extern const char *initCommonControls(void);
|
||||||
|
|
||||||
|
// window.c
|
||||||
|
extern ATOM registerWindowClass(HICON, HCURSOR);
|
||||||
|
extern void unregisterWindowClass(void);
|
||||||
|
|
||||||
|
// container.c
|
||||||
|
extern HWND initialParent;
|
||||||
|
extern const char *initContainer(HICON, HCURSOR);
|
||||||
|
extern void uninitContainer(void);
|
||||||
|
|
||||||
|
// menu.c
|
||||||
|
extern HMENU makeMenubar(void);
|
||||||
|
extern const uiMenuItem *menuIDToItem(UINT_PTR);
|
||||||
|
extern void runMenuEvent(WORD, uiWindow *);
|
||||||
|
extern void freeMenubar(HMENU);
|
||||||
|
extern void uninitMenus(void);
|
||||||
|
|
||||||
|
// alloc.c
|
||||||
|
extern int initAlloc(void);
|
||||||
|
extern void uninitAlloc(void);
|
||||||
|
|
||||||
|
// tab.c
|
||||||
|
extern void tabEnterTabNavigation(HWND);
|
||||||
|
extern void tabLeaveTabNavigation(HWND);
|
Loading…
Reference in New Issue