More implementation of the new uiWindows control parenting and sizing system.

This commit is contained in:
Pietro Gagliardi 2022-07-30 04:14:16 -04:00
parent 8823ebacfb
commit 1d7c530c32
8 changed files with 119 additions and 6 deletions

View File

@ -86,4 +86,8 @@
#define uiprivProgrammerErrorCannotHaveWindowsAsChildren() \ #define uiprivProgrammerErrorCannotHaveWindowsAsChildren() \
uiprivProgrammerError("cannot set a uiWindow as the child of another uiControl") uiprivProgrammerError("cannot set a uiWindow as the child of another uiControl")
// for Windows only
#define uiprivProgrammerErrorCannotCallSetControlPosOnWindow() \
uiprivProgrammerError("cannot call uiWindowsControlSetControlPos() on a uiWindow")
// } // }

View File

@ -79,19 +79,19 @@ If your parent control is not a container, return `NULL`. TODO programmer error?
As libui ensures that the arguments to `ParentHandleForChild()` are actually related, you do not need to check that `child` is actually your child yourself. As libui ensures that the arguments to `ParentHandleForChild()` are actually related, you do not need to check that `child` is actually your child yourself.
### `uiWindowsSetControlPos()` ### `uiWindowsControlSetControlPos()`
```c ```c
uiprivExtern HRESULT uiWindowsSetControlPos(uiControl *c, const RECT *r); uiprivExtern HRESULT uiWindowsControlSetControlPos(uiControl *c, const RECT *r);
``` ```
`uiWindowsSetControlPos()` causes `c` to be moved and resized to fill `r`. `r` must be in the *client* coordinates of `c`'s parent handle. `uiWindowsControlSetControlPos()` causes `c` to be moved and resized to fill `r`. `r` must be in the *client* coordinates of `c`'s parent handle.
This function should be called by container implementations to reposition its children, either in response to a window being resized or when children need to be laid out due to some change (such as visibility). Users should not call this function directly. This function should be called by container implementations to reposition its children, either in response to a window being resized or when children need to be laid out due to some change (such as visibility). Users should not call this function directly.
It returns `S_OK` if the resize succeeded or some error if the resize failed *from the perspective of the OS*. It will not return an error in the event of a libui-specific programmer or internal error of some other sort. This error return is only intended for libui-internal use; see the control implementation details below. It returns `S_OK` if the resize succeeded or some error if the resize failed *from the perspective of the OS*. It will not return an error in the event of a libui-specific programmer or internal error of some other sort. This error return is only intended for libui-internal use; see the control implementation details below.
It is a programmer error to pass `NULL` for `c` or `r`. It is a programmer error to pass `NULL` for `c` or `r`. It is also a programmer error to call `uiWindowsControlSetControlPos()` on a `uiWindow`.
**For control implementations**: This function calls your `SetControlPos()` method. For a simple control with a single window handle, the method should do nothing but call `uiWindowsSetControlHandlePos()` and return its return value: **For control implementations**: This function calls your `SetControlPos()` method. For a simple control with a single window handle, the method should do nothing but call `uiWindowsSetControlHandlePos()` and return its return value:

View File

@ -11,10 +11,16 @@ static HWND osVtableNopParentHandleForChild(uiControl *c, void *implData, uiCont
return NULL; return NULL;
} }
HRESULT osVtableNopSetControlPos(uiControl *c, void *implData, const RECT *r)
{
return S_OK;
}
static const uiControlOSVtable osVtable = { static const uiControlOSVtable osVtable = {
.Size = sizeof (uiControlOSVtable), .Size = sizeof (uiControlOSVtable),
.Handle = osVtableNopHandle, .Handle = osVtableNopHandle,
.ParentHandleForChild = osVtableNopParentHandleForChild, .ParentHandleForChild = osVtableNopParentHandleForChild,
.SetControlPos = osVtableNopSetControlPos,
}; };
const uiControlOSVtable *testOSVtable(void) const uiControlOSVtable *testOSVtable(void)
@ -64,6 +70,20 @@ Test(ControlOSVtableWithMissingParentHandleForChildMethodIsProgrammerError)
endCheckProgrammerError(ctx); endCheckProgrammerError(ctx);
} }
Test(ControlOSVtableWithMissingSetControlPosMethodIsProgrammerError)
{
uiControlVtable vtable;
uiControlOSVtable osvt;
void *ctx;
testControlLoadNopVtable(&vtable);
ctx = beginCheckProgrammerError("uiRegisterControlType(): required uiControlOSVtable method SetControlPos() missing for uiControl type name");
osvt = osVtable;
osvt.SetControlPos = NULL;
uiRegisterControlType("name", &vtable, &osvt, 0);
endCheckProgrammerError(ctx);
}
Test(GettingWindowsHandleOfNullControlIsProgrammerError) Test(GettingWindowsHandleOfNullControlIsProgrammerError)
{ {
void *ctx; void *ctx;
@ -81,3 +101,27 @@ Test(GettingWindowsParentHandleOfNullControlIsProgrammerError)
uiWindowsControlParentHandle(NULL); uiWindowsControlParentHandle(NULL);
endCheckProgrammerError(ctx); endCheckProgrammerError(ctx);
} }
Test(SettingWindowsControlPosOfNullControlIsProgrammerError)
{
void *ctx;
ctx = beginCheckProgrammerError("uiWindowsControlSetControlPos(): invalid null pointer for uiControl");
uiWindowsControlSetControlPos(NULL, NULL);
endCheckProgrammerError(ctx);
}
Test(SettingWindowsControlPosOfNullControlIsProgrammerError)
{
#if 0
// TODO
uiControl *c;
void *ctx;
ctx = beginCheckProgrammerError("uiWindowsControlSetControlPos(): invalid null pointer for RECT");
uiWindowsControlSetControlPos(c, NULL);
endCheckProgrammerError(ctx);
#endif
}
// TODO uiWindowsSetControlHandlePos errors

View File

@ -78,3 +78,22 @@ Test(SetWindowTitle_OSLevel_Invalid)
{ {
testSetWindowTitleImpl(testUTF8InvalidInput, testUTF16InvalidOutput); testSetWindowTitleImpl(testUTF8InvalidInput, testUTF16InvalidOutput);
} }
Test(WindowsCannotSetWindowControlPos)
{
uiWindow *w;
RECT r;
void *ctx;
w = uiNewWindow();
ctx = beginCheckProgrammerError("cannot set a uiWindow as the child of another uiControl");
r.left = 0;
r.top = 0;
r.right = 640;
r.bottom = 480;
uiWindowsControlSetControlPos(uiControl(w), &r);
endCheckProgrammerError(ctx);
uiControlFree(uiControl(w));
}

View File

@ -20,7 +20,7 @@ struct uiControlOSVtable {
uiprivExtern HWND uiWindowsControlHandle(uiControl *c); uiprivExtern HWND uiWindowsControlHandle(uiControl *c);
uiprivExtern HWND uiWindowsControlParentHandle(uiControl *c); uiprivExtern HWND uiWindowsControlParentHandle(uiControl *c);
uiprivExtern HRESULT uiWindowsSetControlPos(uiControl *c, const RECT *r); uiprivExtern HRESULT uiWindowsControlSetControlPos(uiControl *c, const RECT *r);
uiprivExtern HRESULT uiWindowsSetControlHandlePos(HWND hwnd, const RECT *r); uiprivExtern HRESULT uiWindowsSetControlHandlePos(HWND hwnd, const RECT *r);

View File

@ -439,6 +439,23 @@ uiWindow *uiNewWindow(const char *title, int width, int height, int hasMenubar)
// } TODO // } TODO
#endif #endif
static void windowRelayout(struct windowImplData *wi)
{
RECT r;
HRESULT hr;
if (wi->child == NULL)
return;
hr = uiprivHrGetClientRect(wi->hwnd, &r);
if (hr != S_OK) {
uiprivInternalError("GetClientRect() failed in windowRelayout(): 0x%08I32X", hr);
return;
}
hr = uiWindowsControlSetControlPos(wi->child, &r);
if (hr != S_OK)
uiprivInternalError("uiWindowsSetControlHandlePos() failed in windowRelayout(): 0x%08I32X", hr);
}
static LRESULT CALLBACK windowWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) static LRESULT CALLBACK windowWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{ {
LONG_PTR ww; LONG_PTR ww;
@ -543,6 +560,12 @@ static HWND windowParentHandleForChild(uiControl *c, void *implData, uiControl *
return wi->hwnd; return wi->hwnd;
} }
static HRESULT windowSetControlPos(uiControl *c, void *implData, const RECT *r)
{
uiprivProgrammerErrorCannotCallSetControlPosOnWindow();
return E_FAIL;
}
// gotta do this because of lack of C99-style initializers in C++11 // gotta do this because of lack of C99-style initializers in C++11
// see also https://stackoverflow.com/questions/11516657/c-structure-initialization // see also https://stackoverflow.com/questions/11516657/c-structure-initialization
static const uiControlVtable windowVtable = [](void) { static const uiControlVtable windowVtable = [](void) {
@ -564,6 +587,7 @@ static const uiControlOSVtable windowOSVtable = [](void) {
vt.Size = sizeof (uiControlOSVtable); vt.Size = sizeof (uiControlOSVtable);
vt.Handle = windowHandle; vt.Handle = windowHandle;
vt.ParentHandleForChild = windowParentHandleForChild; vt.ParentHandleForChild = windowParentHandleForChild;
vt.SetControlPos = windowSetControlPos;
return vt; return vt;
}(); }();
@ -622,8 +646,10 @@ void uiprivSysWindowSetChild(uiWindow *w, uiControl *child)
if (wi->child != NULL) if (wi->child != NULL)
uiControlSetParent(wi->child, NULL); uiControlSetParent(wi->child, NULL);
wi->child = child; wi->child = child;
if (wi->child != NULL) if (wi->child != NULL) {
uiControlSetParent(wi->child, uiControl(w)); uiControlSetParent(wi->child, uiControl(w));
windowRelayout(wi);
}
} }
#if 0 #if 0

View File

@ -98,3 +98,21 @@ HRESULT WINAPI uiprivHrDestroyWindow(HWND hwnd)
return lastErrorToHRESULT(); return lastErrorToHRESULT();
return S_OK; return S_OK;
} }
HRESULT WINAPI uiprivHrGetWindowRect(HWND hwnd, LPRECT r)
{
SetLastError(0);
if (GetWindowRect(hwnd, r) == 0)
// TODO set r to a zero rect?
return lastErrorToHRESULT();
return S_OK;
}
HRESULT WINAPI uiprivHrGetClientRect(HWND hwnd, LPRECT r)
{
SetLastError(0);
if (GetClientRect(hwnd, r) == 0)
// TODO set r to a zero rect?
return lastErrorToHRESULT();
return S_OK;
}

View File

@ -9,3 +9,5 @@ extern HRESULT WINAPI uiprivHrLoadIconW(HINSTANCE hInstance, LPCWSTR name, HICON
extern HRESULT WINAPI uiprivHrLoadCursorW(HINSTANCE hInstance, LPCWSTR name, HCURSOR *hCursor); extern HRESULT WINAPI uiprivHrLoadCursorW(HINSTANCE hInstance, LPCWSTR name, HCURSOR *hCursor);
extern HRESULT WINAPI uiprivHrSetWindowTextW(HWND hwnd, LPCWSTR text); extern HRESULT WINAPI uiprivHrSetWindowTextW(HWND hwnd, LPCWSTR text);
extern HRESULT WINAPI uiprivHrDestroyWindow(HWND hwnd); extern HRESULT WINAPI uiprivHrDestroyWindow(HWND hwnd);
extern HRESULT WINAPI uiprivHrGetWindowRect(HWND hwnd, LPRECT r);
extern HRESULT WINAPI uiprivHrGetClientRect(HWND hwnd, LPRECT r);