Integrated the extracted Popover code with the Windows Popover.
This commit is contained in:
parent
cd265df14e
commit
a15c27e81d
|
@ -18,15 +18,14 @@
|
||||||
#include <windowsx.h>
|
#include <windowsx.h>
|
||||||
#include <vsstyle.h>
|
#include <vsstyle.h>
|
||||||
#include <vssym32.h>
|
#include <vssym32.h>
|
||||||
|
#include "popover.h"
|
||||||
|
|
||||||
// #qo LIBS: user32 kernel32 gdi32
|
// #qo LIBS: user32 kernel32 gdi32
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
// - investigate visual styles
|
|
||||||
// - make sure redrawing is correct (especially for backgrounds)
|
|
||||||
// - should the parent window appear deactivated?
|
// - should the parent window appear deactivated?
|
||||||
|
|
||||||
HWND popover;
|
HWND popoverWindow;
|
||||||
|
|
||||||
void xpanic(char *msg, DWORD err)
|
void xpanic(char *msg, DWORD err)
|
||||||
{
|
{
|
||||||
|
@ -34,114 +33,23 @@ void xpanic(char *msg, DWORD err)
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ARROWHEIGHT 8
|
popover *p;
|
||||||
#define ARROWWIDTH 8 /* should be the same for smooth lines */
|
|
||||||
|
|
||||||
struct popover {
|
|
||||||
void *gopopover;
|
|
||||||
|
|
||||||
// a nice consequence of this design is that it allows four arrowheads to jut out at once; in practice only one will ever be used, but hey — simple implementation!
|
|
||||||
LONG arrowLeft;
|
|
||||||
LONG arrowRight;
|
|
||||||
LONG arrowTop;
|
|
||||||
LONG arrowBottom;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct popover _p = { NULL, -1, -1, 20, -1 };
|
|
||||||
struct popover *p = &_p;
|
|
||||||
|
|
||||||
HRGN makePopoverRegion(HDC dc, LONG width, LONG height)
|
HRGN makePopoverRegion(HDC dc, LONG width, LONG height)
|
||||||
{
|
{
|
||||||
|
popoverPoint ppt[20];
|
||||||
POINT pt[20];
|
POINT pt[20];
|
||||||
int n;
|
int i, n;
|
||||||
HRGN region;
|
HRGN region;
|
||||||
LONG xmax, ymax;
|
|
||||||
|
n = popoverMakeFramePoints(p, (intptr_t) width, (intptr_t) height, ppt);
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
pt[i].x = (LONG) (ppt[i].x);
|
||||||
|
pt[i].y = (LONG) (ppt[i].y);
|
||||||
|
}
|
||||||
|
|
||||||
if (BeginPath(dc) == 0)
|
if (BeginPath(dc) == 0)
|
||||||
xpanic("error beginning path for Popover shape", GetLastError());
|
xpanic("error beginning path for Popover shape", GetLastError());
|
||||||
n = 0;
|
|
||||||
|
|
||||||
// figure out the xmax and ymax of the box
|
|
||||||
xmax = width;
|
|
||||||
if (p->arrowRight >= 0)
|
|
||||||
xmax -= ARROWWIDTH;
|
|
||||||
ymax = height;
|
|
||||||
if (p->arrowBottom >= 0)
|
|
||||||
ymax -= ARROWHEIGHT;
|
|
||||||
|
|
||||||
// the first point is either at (0,0), (0,arrowHeight), (arrowWidth,0), or (arrowWidth,arrowHeight)
|
|
||||||
pt[n].x = 0;
|
|
||||||
if (p->arrowLeft >= 0)
|
|
||||||
pt[n].x = ARROWWIDTH;
|
|
||||||
pt[n].y = 0;
|
|
||||||
if (p->arrowTop >= 0)
|
|
||||||
pt[n].y = ARROWHEIGHT;
|
|
||||||
n++;
|
|
||||||
|
|
||||||
// the left side
|
|
||||||
pt[n].x = pt[n - 1].x;
|
|
||||||
if (p->arrowLeft >= 0) {
|
|
||||||
pt[n].y = pt[n - 1].y + p->arrowLeft;
|
|
||||||
n++;
|
|
||||||
pt[n].x = pt[n - 1].x - ARROWWIDTH;
|
|
||||||
pt[n].y = pt[n - 1].y + ARROWHEIGHT;
|
|
||||||
n++;
|
|
||||||
pt[n].x = pt[n - 1].x + ARROWWIDTH;
|
|
||||||
pt[n].y = pt[n - 1].y + ARROWHEIGHT;
|
|
||||||
n++;
|
|
||||||
pt[n].x = pt[n - 1].x;
|
|
||||||
}
|
|
||||||
pt[n].y = ymax;
|
|
||||||
n++;
|
|
||||||
|
|
||||||
// the bottom side
|
|
||||||
pt[n].y = pt[n - 1].y;
|
|
||||||
if (p->arrowBottom >= 0) {
|
|
||||||
pt[n].x = pt[n - 1].x + p->arrowBottom;
|
|
||||||
n++;
|
|
||||||
pt[n].x = pt[n - 1].x + ARROWWIDTH;
|
|
||||||
pt[n].y = pt[n - 1].y + ARROWHEIGHT;
|
|
||||||
n++;
|
|
||||||
pt[n].x = pt[n - 1].x + ARROWWIDTH;
|
|
||||||
pt[n].y = pt[n - 1].y - ARROWHEIGHT;
|
|
||||||
n++;
|
|
||||||
pt[n].y = pt[n - 1].y;
|
|
||||||
}
|
|
||||||
pt[n].x = xmax;
|
|
||||||
n++;
|
|
||||||
|
|
||||||
// the right side
|
|
||||||
pt[n].x = pt[n - 1].x;
|
|
||||||
if (p->arrowRight >= 0) {
|
|
||||||
pt[n].y = pt[0].y + p->arrowRight + (ARROWHEIGHT * 2);
|
|
||||||
n++;
|
|
||||||
pt[n].x = pt[n - 1].x + ARROWWIDTH;
|
|
||||||
pt[n].y = pt[n - 1].y - ARROWHEIGHT;
|
|
||||||
n++;
|
|
||||||
pt[n].x = pt[n - 1].x - ARROWWIDTH;
|
|
||||||
pt[n].y = pt[n - 1].y - ARROWHEIGHT;
|
|
||||||
n++;
|
|
||||||
pt[n].x = pt[n - 1].x;
|
|
||||||
}
|
|
||||||
pt[n].y = pt[0].y;
|
|
||||||
n++;
|
|
||||||
|
|
||||||
// the top side
|
|
||||||
pt[n].y = pt[n - 1].y;
|
|
||||||
if (p->arrowTop >= 0) {
|
|
||||||
pt[n].x = pt[0].x + p->arrowTop + (ARROWWIDTH * 2);
|
|
||||||
n++;
|
|
||||||
pt[n].x = pt[n - 1].x - ARROWWIDTH;
|
|
||||||
pt[n].y = pt[n - 1].y - ARROWHEIGHT;
|
|
||||||
n++;
|
|
||||||
pt[n].x = pt[n - 1].x - ARROWWIDTH;
|
|
||||||
pt[n].y = pt[n - 1].y + ARROWHEIGHT;
|
|
||||||
n++;
|
|
||||||
pt[n].y = pt[n - 1].y;
|
|
||||||
}
|
|
||||||
pt[n].x = pt[0].x;
|
|
||||||
n++;
|
|
||||||
|
|
||||||
if (Polyline(dc, pt, n) == 0)
|
if (Polyline(dc, pt, n) == 0)
|
||||||
xpanic("error drawing lines in Popover shape", GetLastError());
|
xpanic("error drawing lines in Popover shape", GetLastError());
|
||||||
if (EndPath(dc) == 0)
|
if (EndPath(dc) == 0)
|
||||||
|
@ -207,21 +115,19 @@ LRESULT CALLBACK popoverproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
RECT *r = (RECT *) lParam;
|
RECT *r = (RECT *) lParam;
|
||||||
NCCALCSIZE_PARAMS *np = (NCCALCSIZE_PARAMS *) lParam;
|
NCCALCSIZE_PARAMS *np = (NCCALCSIZE_PARAMS *) lParam;
|
||||||
|
popoverRect pr;
|
||||||
|
|
||||||
if (wParam != FALSE)
|
if (wParam != FALSE)
|
||||||
r = &np->rgrc[0];
|
r = &np->rgrc[0];
|
||||||
r->left++;
|
pr.left = (intptr_t) (r->left);
|
||||||
r->top++;
|
pr.top = (intptr_t) (r->top);
|
||||||
r->right--;
|
pr.right = (intptr_t) (r->right);
|
||||||
r->bottom--;
|
pr.bottom = (intptr_t) (r->bottom);
|
||||||
if (p->arrowLeft >= 0)
|
popoverWindowSizeToClientSize(p, &pr);
|
||||||
r->left += ARROWWIDTH;
|
r->left = (LONG) (pr.left);
|
||||||
if (p->arrowRight >= 0)
|
r->top = (LONG) (pr.top);
|
||||||
r->right -= ARROWWIDTH;
|
r->right = (LONG) (pr.right);
|
||||||
if (p->arrowTop >= 0)
|
r->bottom = (LONG) (pr.bottom);
|
||||||
r->top += ARROWHEIGHT;
|
|
||||||
if (p->arrowBottom >= 0)
|
|
||||||
r->bottom -= ARROWHEIGHT;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
case WM_PAINT:
|
case WM_PAINT:
|
||||||
|
@ -236,29 +142,27 @@ LRESULT CALLBACK popoverproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
// TODO window edge detection
|
// TODO window edge detection
|
||||||
{
|
{
|
||||||
RECT r;
|
RECT r;
|
||||||
LONG x, y;
|
|
||||||
LONG width = 200, height = 200;
|
LONG width = 200, height = 200;
|
||||||
|
popoverRect control;
|
||||||
|
uintptr_t side;
|
||||||
|
popoverRect out;
|
||||||
|
|
||||||
if (GetWindowRect((HWND) wParam, &r) == 0)
|
if (GetWindowRect((HWND) wParam, &r) == 0)
|
||||||
xpanic("error getting window rect of Popover target", GetLastError());
|
xpanic("error getting window rect of Popover target", GetLastError());
|
||||||
width += 2;
|
control.left = (intptr_t) (r.left);
|
||||||
height += 2;
|
control.top = (intptr_t) (r.top);
|
||||||
p->arrowLeft = -1;
|
control.right = (intptr_t) (r.right);
|
||||||
p->arrowRight = -1;
|
control.bottom = (intptr_t) (r.bottom);
|
||||||
p->arrowTop = -1;
|
switch (uMsg) {
|
||||||
p->arrowBottom = -1;
|
case msgPopoverPrepareLeftRight:
|
||||||
if (uMsg == msgPopoverPrepareLeftRight) {
|
side = popoverPointLeft;
|
||||||
width += ARROWWIDTH;
|
break;
|
||||||
p->arrowLeft = height / 2 - ARROWHEIGHT;
|
case msgPopoverPrepareTopBottom:
|
||||||
x = r.right;
|
side = popoverPointTop;
|
||||||
y = r.top - ((height - (r.bottom - r.top)) / 2);
|
break;
|
||||||
} else {
|
|
||||||
height += ARROWHEIGHT;
|
|
||||||
p->arrowTop = width / 2 - ARROWWIDTH;
|
|
||||||
x = r.left - ((width - (r.right - r.left)) / 2);
|
|
||||||
y = r.bottom;
|
|
||||||
}
|
}
|
||||||
if (MoveWindow(hwnd, x, y, width, height, TRUE) == 0)
|
out = popoverPointAt(p, control, (intptr_t) width, (intptr_t) height, side);
|
||||||
|
if (MoveWindow(hwnd, out.left, out.top, out.right - out.left, out.bottom - out.top, TRUE) == 0)
|
||||||
xpanic("error repositioning Popover", GetLastError());
|
xpanic("error repositioning Popover", GetLastError());
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -273,9 +177,9 @@ LRESULT CALLBACK wndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
switch (uMsg) {
|
switch (uMsg) {
|
||||||
case WM_COMMAND:
|
case WM_COMMAND:
|
||||||
if (HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == 100) {
|
if (HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == 100) {
|
||||||
SendMessageW(popover, msgPopoverPrepareLeftRight, (WPARAM) button, 0);
|
SendMessageW(popoverWindow, msgPopoverPrepareLeftRight, (WPARAM) button, 0);
|
||||||
ShowWindow(popover, SW_SHOW);
|
ShowWindow(popoverWindow, SW_SHOW);
|
||||||
UpdateWindow(popover);
|
UpdateWindow(popoverWindow);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -292,6 +196,9 @@ int main(int argc, char *argv[])
|
||||||
HWND mainwin;
|
HWND mainwin;
|
||||||
MSG msg;
|
MSG msg;
|
||||||
|
|
||||||
|
p = popoverDataNew(NULL);
|
||||||
|
// TODO null check
|
||||||
|
|
||||||
ZeroMemory(&wc, sizeof (WNDCLASSW));
|
ZeroMemory(&wc, sizeof (WNDCLASSW));
|
||||||
wc.lpszClassName = L"popover";
|
wc.lpszClassName = L"popover";
|
||||||
wc.lpfnWndProc = popoverproc;
|
wc.lpfnWndProc = popoverproc;
|
||||||
|
@ -299,12 +206,12 @@ int main(int argc, char *argv[])
|
||||||
wc.style = CS_DROPSHADOW | CS_NOCLOSE;
|
wc.style = CS_DROPSHADOW | CS_NOCLOSE;
|
||||||
if (RegisterClassW(&wc) == 0)
|
if (RegisterClassW(&wc) == 0)
|
||||||
abort();
|
abort();
|
||||||
popover = CreateWindowExW(WS_EX_TOPMOST,
|
popoverWindow = CreateWindowExW(WS_EX_TOPMOST,
|
||||||
L"popover", L"",
|
L"popover", L"",
|
||||||
WS_POPUP,
|
WS_POPUP,
|
||||||
0, 0, 150, 100,
|
0, 0, 150, 100,
|
||||||
NULL, NULL, NULL, NULL);
|
NULL, NULL, NULL, NULL);
|
||||||
if (popover == NULL)
|
if (popoverWindow == NULL)
|
||||||
abort();
|
abort();
|
||||||
|
|
||||||
ZeroMemory(&wc, sizeof (WNDCLASSW));
|
ZeroMemory(&wc, sizeof (WNDCLASSW));
|
||||||
|
|
|
@ -144,6 +144,7 @@ popoverRect popoverPointAt(popover *p, popoverRect control, intptr_t width, intp
|
||||||
intptr_t x, y;
|
intptr_t x, y;
|
||||||
popoverRect out;
|
popoverRect out;
|
||||||
|
|
||||||
|
// account for border
|
||||||
width += 2;
|
width += 2;
|
||||||
height += 2;
|
height += 2;
|
||||||
p->arrowLeft = -1;
|
p->arrowLeft = -1;
|
||||||
|
|
|
@ -22,7 +22,7 @@ enum {
|
||||||
popoverPointRight,
|
popoverPointRight,
|
||||||
popoverPointTop,
|
popoverPointTop,
|
||||||
popoverPointBottom,
|
popoverPointBottom,
|
||||||
}
|
};
|
||||||
|
|
||||||
popover *popoverDataNew(void *);
|
popover *popoverDataNew(void *);
|
||||||
int popoverMakeFramePoints(popover *, intptr_t, intptr_t, popoverPoint[20]);
|
int popoverMakeFramePoints(popover *, intptr_t, intptr_t, popoverPoint[20]);
|
||||||
|
|
Loading…
Reference in New Issue