Integrated the extracted Popover code with the Windows Popover.

This commit is contained in:
Pietro Gagliardi 2014-10-11 11:00:56 -04:00
parent cd265df14e
commit a15c27e81d
3 changed files with 47 additions and 139 deletions

View File

@ -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));

View File

@ -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;

View File

@ -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]);