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() \
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.
### `uiWindowsSetControlPos()`
### `uiWindowsControlSetControlPos()`
```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.
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:

View File

@ -11,10 +11,16 @@ static HWND osVtableNopParentHandleForChild(uiControl *c, void *implData, uiCont
return NULL;
}
HRESULT osVtableNopSetControlPos(uiControl *c, void *implData, const RECT *r)
{
return S_OK;
}
static const uiControlOSVtable osVtable = {
.Size = sizeof (uiControlOSVtable),
.Handle = osVtableNopHandle,
.ParentHandleForChild = osVtableNopParentHandleForChild,
.SetControlPos = osVtableNopSetControlPos,
};
const uiControlOSVtable *testOSVtable(void)
@ -64,6 +70,20 @@ Test(ControlOSVtableWithMissingParentHandleForChildMethodIsProgrammerError)
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)
{
void *ctx;
@ -81,3 +101,27 @@ Test(GettingWindowsParentHandleOfNullControlIsProgrammerError)
uiWindowsControlParentHandle(NULL);
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);
}
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 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);

View File

@ -439,6 +439,23 @@ uiWindow *uiNewWindow(const char *title, int width, int height, int hasMenubar)
// } TODO
#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)
{
LONG_PTR ww;
@ -543,6 +560,12 @@ static HWND windowParentHandleForChild(uiControl *c, void *implData, uiControl *
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
// see also https://stackoverflow.com/questions/11516657/c-structure-initialization
static const uiControlVtable windowVtable = [](void) {
@ -564,6 +587,7 @@ static const uiControlOSVtable windowOSVtable = [](void) {
vt.Size = sizeof (uiControlOSVtable);
vt.Handle = windowHandle;
vt.ParentHandleForChild = windowParentHandleForChild;
vt.SetControlPos = windowSetControlPos;
return vt;
}();
@ -622,8 +646,10 @@ void uiprivSysWindowSetChild(uiWindow *w, uiControl *child)
if (wi->child != NULL)
uiControlSetParent(wi->child, NULL);
wi->child = child;
if (wi->child != NULL)
if (wi->child != NULL) {
uiControlSetParent(wi->child, uiControl(w));
windowRelayout(wi);
}
}
#if 0

View File

@ -98,3 +98,21 @@ HRESULT WINAPI uiprivHrDestroyWindow(HWND hwnd)
return lastErrorToHRESULT();
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 uiprivHrSetWindowTextW(HWND hwnd, LPCWSTR text);
extern HRESULT WINAPI uiprivHrDestroyWindow(HWND hwnd);
extern HRESULT WINAPI uiprivHrGetWindowRect(HWND hwnd, LPRECT r);
extern HRESULT WINAPI uiprivHrGetClientRect(HWND hwnd, LPRECT r);