From 9b2b351c92fa876490f6716f8dcd7a8849b36ad3 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Sun, 17 May 2015 15:42:49 -0400 Subject: [PATCH] Added a new API for more roubst resizing. GTK+ resizes the whole window when a resize is requested; we have to as well, otherwise we won't have correct results. --- redo/ui.idl.TODO | 152 +++++++++++++++++++++++++++++++++++++ redo/windows/resize.c.TODO | 121 +++++++++++++++++++++++++++++ 2 files changed, 273 insertions(+) create mode 100644 redo/ui.idl.TODO create mode 100644 redo/windows/resize.c.TODO diff --git a/redo/ui.idl.TODO b/redo/ui.idl.TODO new file mode 100644 index 00000000..ed9e4cbe --- /dev/null +++ b/redo/ui.idl.TODO @@ -0,0 +1,152 @@ +// 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 { + +raw "#include "; +raw "#include "; + +raw "#ifndef _UI_EXTERN"; +raw "#define _UI_EXTERN extern"; +raw "#endif"; + +struct InitOptions { + field Size size_t; +}; + +func Init(options *InitOptions) *const char; +func Uninit(void); +func FreeInitError(err *const char); + +func Main(void); +func Quit(void); + +func OnShouldQuit(f *func(data *void) int, data *void); + +func FreeText(text *char); + +raw "typedef struct uiSizingSys uiSizingSys;"; + +struct Sizing { + field XPadding intmax_t; + field YPadding intmax_t; + field Sys *uiSizingSys; +}; + +raw "typedef struct uiControlSysFuncParams uiControlSysFuncParams;"; +raw "#define uiControlSysFuncNop 0"; + +interface Control { + field Internal *void; // for use by ui only + func Destroy(void); + func Handle(void) uintptr_t; + func Parent(void) *Control; + func SetParent(c *Control); + 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 QueueResize(void); + func GetSizing(d *Sizing); + func ContainerVisible(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); + func SysFunc(p *uiControlSysFuncParams); + func StartZOrder(p *uiControlSysFuncParams) int; +}; + +func MakeContainer(c *Control); + +interface Window from Control { + func Title(void) *char; + func SetTitle(title *const char); + 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 OnChanged(f *func(e *Entry, data *void), data *void); + func ReadOnly(void) int; + func SetReadOnly(readonly int); +}; +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 { + func AppendPage(name *const char, c *Control); + func InsertPageBefore(name *const char, before uintmax_t, c *Control); + func DeletePage(index uintmax_t); + func NumPages(void) uintmax_t; + func Margined(page uintmax_t) int; + func SetMargined(page uintmax_t, margined int); +}; +func NewTab(void) *Tab; + +interface Group from Control { + // TODO text and settext + func SetChild(c *Control); + // TODO margined and setmargined +}; +func NewGroup(text *const char) *Group; + +interface Menu { + func AppendItem(name *const char) *MenuItem; + func AppendCheckItem(name *const char) *MenuItem; + func AppendQuitItem(void) *MenuItem; + func AppendPreferencesItem(void) *MenuItem; + func AppendAboutItem(void) *MenuItem; + func AppendSeparator(void); +}; +func NewMenu(name *const char) *Menu; + +interface MenuItem { + func Enable(void); + func Disable(void); + func OnClicked(f *func(sender *MenuItem, window *Window, data *void), data *void); + func Checked(void) int; + func SetChecked(checked int); +}; + +}; diff --git a/redo/windows/resize.c.TODO b/redo/windows/resize.c.TODO new file mode 100644 index 00000000..db981803 --- /dev/null +++ b/redo/windows/resize.c.TODO @@ -0,0 +1,121 @@ +// 14 may 2015 +#include "uipriv_windows.h" + +static struct ptrArray *resizes; + +void initResizes(void) +{ + resizes = newPtrArray(); +} + +void uninitResizes(void) +{ + while (resizes->len != 0) + ptrArrayDelete(resizes, 0); + ptrArrayDestroy(resizes); +} + +void queueResize(uiControl *c) +{ + uintmax_t i; + uiControl *d; + + // resizing a control requires us to reocmpute the sizes of everything in the top-level window + for (;;) { + if (uiIsWindow(c)) + break; + if (uiControlParent(c) == NULL) // not in a window; don't bother resizing + return; + c = uiControlParent(c); + } + // make sure we're only queued once + for (i = 0 ; i < resizes->len; i++) { + d = ptrArrayIndex(resizes, uiControl *, i); + if (c == d) + return; + } + ptrArrayAppend(resizes, c); +} + +// TODO dequeueResize + +void doResizes(void) +{ + uiControl *c, *parent; + intmax_t x, y, width, height; + uiSizing d; + uiSizingSys sys; + HWND hwnd; + + while (resizes->len != 0) { + c = ptrArrayIndex(resizes, uiControl *, 0); + ptrArrayDelete(resizes, 0); + parent = uiControlParent(c); + if (parent == NULL) // not in a parent; can't resize + continue; // this is for uiBox, etc. + d.Sys = &sys; + uiControlGetSizing(parent, &d); + uiControlComputeChildSize(parent, &x, &y, &width, &height, &d); + uiControlResize(c, x, y, width, height, &d); + hwnd = (HWND) uiControlHandle(c); + // we used SWP_NOREDRAW; we need to queue a redraw ourselves + // TODO use RedrawWindow() to bypass WS_CLIPCHILDREN complications + if (InvalidateRect(hwnd, NULL, TRUE) == 0) + logLastError("error redrawing controls after a resize in doResizes()"); + } +} + +#define swpflags (SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOREDRAW) + +void moveWindow(HWND hwnd, intmax_t x, intmax_t y, intmax_t width, intmax_t height) +{ + if (SetWindowPos(hwnd, NULL, x, y, width, height, swpflags | SWP_NOZORDER) == 0) + logLastError("error moving window in moveWindow()"); +} + +void moveAndReorderWindow(HWND hwnd, HWND insertAfter, intmax_t x, intmax_t y, intmax_t width, intmax_t height) +{ + if (SetWindowPos(hwnd, insertAfter, x, y, width, height, swpflags) == 0) + logLastError("error moving and reordering window in moveAndReorderWindow()"); +} + +// from https://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing and https://msdn.microsoft.com/en-us/library/windows/desktop/bb226818%28v=vs.85%29.aspx +// this X value is really only for buttons but I don't see a better one :/ +#define winXPadding 4 +#define winYPadding 4 + +void uiWindowsGetSizing(uiControl *c, uiSizing *d) +{ + HWND hwnd; + HDC dc; + HFONT prevfont; + TEXTMETRICW tm; + SIZE size; + + hwnd = (HWND) uiControlHandle(c); + + dc = GetDC(hwnd); + if (dc == NULL) + logLastError("error getting DC in uiWindowsGetSizing()"); + prevfont = (HFONT) SelectObject(dc, hMessageFont); + if (prevfont == NULL) + logLastError("error loading control font into device context in uiWindowsGetSizing()"); + + ZeroMemory(&tm, sizeof (TEXTMETRICW)); + if (GetTextMetricsW(dc, &tm) == 0) + logLastError("error getting text metrics in uiWindowsGetSizing()"); + if (GetTextExtentPoint32W(dc, L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 52, &size) == 0) + logLastError("error getting text extent point in uiWindowsGetSizing()"); + + d->Sys->BaseX = (int) ((size.cx / 26 + 1) / 2); + d->Sys->BaseY = (int) tm.tmHeight; + d->Sys->InternalLeading = tm.tmInternalLeading; + + if (SelectObject(dc, prevfont) != hMessageFont) + logLastError("error restoring previous font into device context in uiWindowsGetSizing()"); + if (ReleaseDC(hwnd, dc) == 0) + logLastError("error releasing DC in uiWindowsGetSizing()"); + + d->XPadding = uiWindowsDlgUnitsToX(winXPadding, d->Sys->BaseX); + d->YPadding = uiWindowsDlgUnitsToY(winYPadding, d->Sys->BaseY); +}