More uiArea work, this time on Windows.
This commit is contained in:
parent
6e2ad99ce9
commit
4eed0d77ae
|
@ -9,6 +9,7 @@ uiDrawContext *newContext(cairo_t *cr)
|
|||
{
|
||||
uiDrawContext *c;
|
||||
|
||||
// TODO use uiNew
|
||||
c = (uiDrawContext *) g_malloc0(sizeof (uiDrawContext));
|
||||
c->cr = cr;
|
||||
return c;
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
// 8 september 2015
|
||||
#include "area.h"
|
||||
|
||||
#define areaClass L"libui_uiAreaClass"
|
||||
|
||||
static void doPaint(uiArea *a, uiAreaHandler *ah, HDC dc, RECT *client, RECT *clip)
|
||||
{
|
||||
uiAreaDrawParams dp;
|
||||
|
||||
dp.Context = newContext(dc);
|
||||
|
||||
dp.ClientWidth = client->right - client->left;
|
||||
dp.ClientHeight = client->bottom - client->top;
|
||||
|
||||
dp.ClipX = clip->left;
|
||||
dp.ClipY = clip->top;
|
||||
dp.ClipWidth = clip->right - clip->left;
|
||||
dp.ClipHeight = clip->bottom - clip->top;
|
||||
|
||||
// TODO is this really the best for multimonitor setups?
|
||||
dp.DPIX = GetDeviceCaps(dc, LOGPIXELSX);
|
||||
dp.DPIY = GetDeviceCaps(dc, LOGPIXELSY);
|
||||
|
||||
/* TODO
|
||||
dp.HScrollPos = gtk_adjustment_get_value(ap->ha);
|
||||
dp.VScrollPos = gtk_adjustment_get_value(ap->va);
|
||||
*/
|
||||
|
||||
(*(ah->Draw))(ah, a, &dp);
|
||||
}
|
||||
|
||||
struct areainit {
|
||||
uiArea *a;
|
||||
uiAreaHandler *ah;
|
||||
};
|
||||
|
||||
#define gwlpArea 0
|
||||
#define gwlpAreaHandler (sizeof (uiArea *))
|
||||
|
||||
static LRESULT CALLBACK areaWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
uiArea *a;
|
||||
uiAreaHandler *ah;
|
||||
struct areainit *ai;
|
||||
CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam;
|
||||
HDC dc;
|
||||
PAINTSTRUCT ps;
|
||||
RECT client;
|
||||
|
||||
a = (uiArea *) GetWindowLongPtrW(hwnd, gwlpArea);
|
||||
ah = (uiAreaHandler *) GetWindowLongPtrW(hwnd, gwlpAreaHandler);
|
||||
if (a == NULL) {
|
||||
if (uMsg == WM_NCCREATE) {
|
||||
ai = (struct areainit *) (cs->lpCreateParams);
|
||||
SetWindowLongPtrW(hwnd, gwlpArea, (LONG_PTR) (ai->a));
|
||||
SetWindowLongPtrW(hwnd, gwlpAreaHandler, (LONG_PTR) (ai->ah));
|
||||
}
|
||||
// fall through to DefWindowProcW() anyway
|
||||
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
switch (uMsg) {
|
||||
case WM_PAINT:
|
||||
dc = BeginPaint(hwnd, &ps);
|
||||
if (dc == NULL)
|
||||
logLastError("error beginning paint in areaWndProc");
|
||||
if (GetClientRect(hwnd, &client) == 0)
|
||||
logLastError("error getting client rect in WM_PAINT in areaWndProc()");
|
||||
doPaint(a, ah, dc, &client, &(ps.rcPaint));
|
||||
EndPaint(hwnd, &ps);
|
||||
return 0;
|
||||
case WM_PRINTCLIENT:
|
||||
if (GetClientRect(hwnd, &client) == 0)
|
||||
logLastError("error getting client rect in WM_PRINTCLIENT in areaWndProc()");
|
||||
doPaint(a, ah, (HDC) wParam, &client, &client);
|
||||
return 0;
|
||||
}
|
||||
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
ATOM registerAreaClass(void)
|
||||
{
|
||||
WNDCLASSW wc;
|
||||
|
||||
ZeroMemory(&wc, sizeof (WNDCLASSW));
|
||||
wc.lpszClassName = areaClass;
|
||||
wc.lpfnWndProc = areaWndProc;
|
||||
wc.hInstance = hInstance;
|
||||
//TODO wc.hIcon = hDefaultIcon;
|
||||
//TODO wc.hCursor = hDefaultCursor;
|
||||
wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||
wc.cbWndExtra = sizeof (uiArea *) + sizeof (uiAreaHandler *);
|
||||
return RegisterClassW(&wc);
|
||||
}
|
||||
|
||||
void unregisterAreaClass(void)
|
||||
{
|
||||
if (UnregisterClassW(areaClass, hInstance) == 0)
|
||||
logLastError("error unregistering uiArea window class in unregisterAreaClass()");
|
||||
}
|
||||
|
||||
HWND makeArea(DWORD exstyle, DWORD style, int x, int y, int cx, int cy, HWND parent, uiAreaHandler *ah)
|
||||
{
|
||||
struct areainit ai;
|
||||
|
||||
ai.a = NULL;
|
||||
ai.ah = ah;
|
||||
return CreateWindowExW(exstyle,
|
||||
areaClass, L"",
|
||||
style | WS_HSCROLL | WS_VSCROLL,
|
||||
x, y, cx, cy,
|
||||
parent, NULL, hInstance, &ai);
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
// 8 september 2015
|
||||
#include "../windows/winapi.h"
|
||||
#include <stdint.h>
|
||||
#include "ui.h"
|
||||
|
||||
extern HINSTANCE hInstance;
|
||||
|
||||
extern ATOM registerAreaClass(void);
|
||||
extern void unregisterAreaClass(void);
|
||||
extern HWND makeArea(DWORD exstyle, DWORD style, int x, int y, int cx, int cy, HWND parent, uiAreaHandler *ah);
|
||||
|
||||
extern HRESULT logLastError(const char *);
|
||||
extern HRESULT logHRESULT(const char *, HRESULT);
|
||||
extern HRESULT logMemoryExhausted(const char *);
|
||||
|
||||
extern uiDrawContext *newContext(HDC);
|
|
@ -0,0 +1,111 @@
|
|||
// 25 february 2015
|
||||
#include "area.h"
|
||||
|
||||
// uncomment the following line to enable debug messages
|
||||
#define tableDebug
|
||||
// uncomment the following line to halt on a debug message
|
||||
#define tableDebugStop
|
||||
|
||||
#ifdef tableDebug
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
HRESULT logLastError(const char *context)
|
||||
{
|
||||
DWORD le;
|
||||
WCHAR *msg;
|
||||
BOOL parenthesize = FALSE;
|
||||
BOOL localFreeFailed = FALSE;
|
||||
DWORD localFreeLastError;
|
||||
|
||||
le = GetLastError();
|
||||
fprintf(stderr, "%s: ", context);
|
||||
if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, le, 0, (LPWSTR) (&msg), 0, NULL) != 0) {
|
||||
fprintf(stderr, "%S (", msg);
|
||||
if (LocalFree(msg) != NULL) {
|
||||
localFreeFailed = TRUE;
|
||||
localFreeLastError = GetLastError();
|
||||
}
|
||||
parenthesize = TRUE;
|
||||
}
|
||||
fprintf(stderr, "GetLastError() == %I32u", le);
|
||||
if (parenthesize)
|
||||
fprintf(stderr, ")");
|
||||
if (localFreeFailed)
|
||||
fprintf(stderr, "; local free of system message failed with last error %I32u", localFreeLastError);
|
||||
fprintf(stderr, "\n");
|
||||
#ifdef tableDebugStop
|
||||
DebugBreak();
|
||||
#endif
|
||||
SetLastError(le);
|
||||
// a function does not have to set a last error
|
||||
// if the last error we get is actually 0, then HRESULT_FROM_WIN32(0) will return S_OK (0 cast to an HRESULT, since 0 <= 0), which we don't want
|
||||
// prevent this by returning E_FAIL, so the rest of the Table code doesn't barge onward
|
||||
if (le == 0)
|
||||
return E_FAIL;
|
||||
return HRESULT_FROM_WIN32(le);
|
||||
}
|
||||
|
||||
HRESULT logHRESULT(const char *context, HRESULT hr)
|
||||
{
|
||||
WCHAR *msg;
|
||||
BOOL parenthesize = FALSE;
|
||||
BOOL localFreeFailed = FALSE;
|
||||
DWORD localFreeLastError;
|
||||
|
||||
fprintf(stderr, "%s: ", context);
|
||||
// this isn't technically documented, but everyone does it, including Microsoft (see the implementation of _com_error::ErrorMessage() in a copy of comdef.h that comes with the Windows DDK)
|
||||
if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, (DWORD) hr, 0, (LPWSTR) (&msg), 0, NULL) != 0) {
|
||||
fprintf(stderr, "%S (", msg);
|
||||
if (LocalFree(msg) != NULL) {
|
||||
localFreeFailed = TRUE;
|
||||
localFreeLastError = GetLastError();
|
||||
}
|
||||
parenthesize = TRUE;
|
||||
}
|
||||
fprintf(stderr, "HRESULT == 0x%I32X", hr);
|
||||
if (parenthesize)
|
||||
fprintf(stderr, ")");
|
||||
if (localFreeFailed)
|
||||
fprintf(stderr, "; local free of system message failed with last error %I32u", localFreeLastError);
|
||||
fprintf(stderr, "\n");
|
||||
#ifdef tableDebugStop
|
||||
DebugBreak();
|
||||
#endif
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT logMemoryExhausted(const char *reason)
|
||||
{
|
||||
fprintf(stderr, "memory exhausted %s\n", reason);
|
||||
#ifdef tableDebugStop
|
||||
DebugBreak();
|
||||
#endif
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
HRESULT logLastError(const char *reason)
|
||||
{
|
||||
DWORD le;
|
||||
|
||||
le = GetLastError();
|
||||
// we shouldn't need to do this, but let's do this anyway just to be safe
|
||||
SetLastError(le);
|
||||
if (le == 0)
|
||||
return E_FAIL;
|
||||
return HRESULT_FROM_WIN32(le);
|
||||
}
|
||||
|
||||
HRESULT logHRESULT(const char *reason, HRESULT hr)
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT logMemoryExhausted(const char *reason)
|
||||
{
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -17,7 +17,8 @@ uiDrawContext *newContext(HDC dc)
|
|||
{
|
||||
uiDrawContext *c;
|
||||
|
||||
c = (uiDrawContext *) g_malloc0(sizeof (uiDrawContext));
|
||||
// TODO use uiNew
|
||||
c = (uiDrawContext *) malloc(sizeof (uiDrawContext));
|
||||
c->dc = dc;
|
||||
return c;
|
||||
}
|
||||
|
@ -70,7 +71,7 @@ void uiDrawArc(uiDrawContext *c, intmax_t xCenter, intmax_t yCenter, intmax_t ra
|
|||
}
|
||||
// TODO convert radians to degrees
|
||||
if (AngleArc(c->dc,
|
||||
xCenter, yCenter
|
||||
xCenter, yCenter,
|
||||
radius,
|
||||
startAngle,
|
||||
// the "sweep angle" is relative to the start angle, not to 0
|
||||
|
@ -94,7 +95,7 @@ void uiDrawBezierTo(uiDrawContext *c, intmax_t c1x, intmax_t c1y, intmax_t c2x,
|
|||
|
||||
void uiDrawCloseFigure(uiDrawContext *c)
|
||||
{
|
||||
if (CloseFigure(c->currentDC) == 0)
|
||||
if (CloseFigure(c->dc) == 0)
|
||||
logLastError("error closing figure in uiDrawCloseFigure()");
|
||||
}
|
||||
|
||||
|
@ -199,7 +200,7 @@ static void startAlpha(uiDrawContext *c, struct alpha *a)
|
|||
logLastError("error creating compatible DC in startAlpha()");
|
||||
|
||||
// now create and select in a *device-independent* bitmap that will hold the data that we're going to alpha blend
|
||||
ZeroMemory(&bmi, sizeof (BITMAPINFO));
|
||||
ZeroMemory(&bi, sizeof (BITMAPINFO));
|
||||
bi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
|
||||
bi.bmiHeader.biWidth = a->r.right - a->r.left;
|
||||
bi.bmiHeader.biHeight = -(a->r.bottom - a->r.top); // negative to draw top-down
|
||||
|
@ -299,6 +300,7 @@ static HBRUSH toBrush(uiDrawContext *c)
|
|||
return brush;
|
||||
}
|
||||
// TODO
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void uiDrawFill(uiDrawContext *c, uiDrawFillMode mode)
|
||||
|
@ -333,7 +335,7 @@ void uiDrawFill(uiDrawContext *c, uiDrawFillMode mode)
|
|||
logLastError("error selecting brush into DC in uiDrawFill()");
|
||||
if (FillPath(fillDC) == 0)
|
||||
logLastError("error filling path in uiDrawFill()");
|
||||
if (SelectObject(strokeDC, prevbrush) != brush)
|
||||
if (SelectObject(fillDC, prevbrush) != brush)
|
||||
logLastError("error deselecting brush from DC in uiDrawFill()");
|
||||
if (DeleteObject(brush) == 0)
|
||||
logLastError("error deleting pen in uiDrawStroke()");
|
||||
|
|
|
@ -0,0 +1,162 @@
|
|||
// 4 september 2015
|
||||
#define _GNU_SOURCE
|
||||
#include "area.h"
|
||||
#include <math.h>
|
||||
|
||||
// #qo LIBS: user32 kernel32 gdi32 msimg32
|
||||
|
||||
struct handler {
|
||||
uiAreaHandler ah;
|
||||
};
|
||||
|
||||
static HWND area;
|
||||
static struct handler h;
|
||||
|
||||
static void handlerDraw(uiAreaHandler *a, uiArea *area, uiAreaDrawParams *p)
|
||||
{
|
||||
uiDrawStrokeParams sp;
|
||||
|
||||
uiDrawBeginPathRGB(p->Context, 0xFF, 0x00, 0x00);
|
||||
uiDrawMoveTo(p->Context, p->ClipX + 5, p->ClipY + 5);
|
||||
uiDrawLineTo(p->Context, (p->ClipX + p->ClipWidth) - 5, (p->ClipY + p->ClipHeight) - 5);
|
||||
sp.Cap = uiDrawLineCapFlat;
|
||||
sp.Join = uiDrawLineJoinMiter;
|
||||
sp.Thickness = 1;
|
||||
sp.MiterLimit = uiDrawDefaultMiterLimit;
|
||||
uiDrawStroke(p->Context, &sp);
|
||||
|
||||
uiDrawBeginPathRGB(p->Context, 0x00, 0x00, 0xC0);
|
||||
uiDrawMoveTo(p->Context, p->ClipX, p->ClipY);
|
||||
uiDrawLineTo(p->Context, p->ClipX + p->ClipWidth, p->ClipY);
|
||||
uiDrawLineTo(p->Context, 50, 150);
|
||||
uiDrawLineTo(p->Context, 50, 50);
|
||||
uiDrawCloseFigure(p->Context);
|
||||
sp.Cap = uiDrawLineCapFlat;
|
||||
sp.Join = uiDrawLineJoinRound;
|
||||
sp.Thickness = 5;
|
||||
uiDrawStroke(p->Context, &sp);
|
||||
|
||||
uiDrawBeginPathRGBA(p->Context, 0x00, 0xC0, 0x00, 0x80);
|
||||
uiDrawRectangle(p->Context, 120, 80, 50, 50);
|
||||
uiDrawFill(p->Context, uiDrawFillModeWinding);
|
||||
|
||||
uiDrawBeginPathRGB(p->Context, 0x00, 0x80, 0x00);
|
||||
uiDrawMoveTo(p->Context, 5, 10);
|
||||
uiDrawLineTo(p->Context, 5, 50);
|
||||
sp.Cap = uiDrawLineCapFlat;
|
||||
sp.Join = uiDrawLineJoinMiter;
|
||||
sp.Thickness = 1;
|
||||
sp.MiterLimit = uiDrawDefaultMiterLimit;
|
||||
uiDrawStroke(p->Context, &sp);
|
||||
|
||||
uiDrawBeginPathRGB(p->Context, 0x80, 0xC0, 0x00);
|
||||
uiDrawMoveTo(p->Context, 400, 100);
|
||||
uiDrawArc(p->Context,
|
||||
400, 100,
|
||||
50,
|
||||
30. * (M_PI / 180.),
|
||||
// note the end angle here
|
||||
// in GDI, the second angle to AngleArc() is relative to the start, not to 0
|
||||
330. * (M_PI / 180.),
|
||||
1);
|
||||
// TODO add a checkbox for this
|
||||
uiDrawLineTo(p->Context, 400, 100);
|
||||
uiDrawArc(p->Context,
|
||||
510, 100,
|
||||
50,
|
||||
30. * (M_PI / 180.),
|
||||
330. * (M_PI / 180.),
|
||||
0);
|
||||
uiDrawCloseFigure(p->Context);
|
||||
sp.Cap = uiDrawLineCapFlat;
|
||||
sp.Join = uiDrawLineJoinMiter;
|
||||
sp.Thickness = 1;
|
||||
sp.MiterLimit = uiDrawDefaultMiterLimit;
|
||||
uiDrawStroke(p->Context, &sp);
|
||||
|
||||
uiDrawBeginPathRGB(p->Context, 0x00, 0x80, 0xC0);
|
||||
uiDrawMoveTo(p->Context, 300, 300);
|
||||
uiDrawBezierTo(p->Context,
|
||||
350, 320,
|
||||
310, 390,
|
||||
435, 372);
|
||||
sp.Cap = uiDrawLineCapFlat;
|
||||
sp.Join = uiDrawLineJoinMiter;
|
||||
sp.Thickness = 1;
|
||||
sp.MiterLimit = uiDrawDefaultMiterLimit;
|
||||
uiDrawStroke(p->Context, &sp);
|
||||
}
|
||||
|
||||
static uintmax_t handlerHScrollMax(uiAreaHandler *a, uiArea *area)
|
||||
{
|
||||
return 0;//TODO return gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(nhspinb));
|
||||
}
|
||||
|
||||
static uintmax_t handlerVScrollMax(uiAreaHandler *a, uiArea *area)
|
||||
{
|
||||
return 0;//TODO return gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(nvspinb));
|
||||
}
|
||||
|
||||
/* TODO
|
||||
static void recalcScroll(GtkSpinButton *sb, gpointer data)
|
||||
{
|
||||
areaUpdateScroll(area);
|
||||
}
|
||||
|
||||
static GtkWidget *makeSpinbox(int min)
|
||||
{
|
||||
GtkWidget *sb;
|
||||
|
||||
sb = gtk_spin_button_new_with_range(min, 100000, 1);
|
||||
gtk_spin_button_set_digits(GTK_SPIN_BUTTON(sb), 0);
|
||||
g_signal_connect(sb, "value-changed", G_CALLBACK(recalcScroll), NULL);
|
||||
return sb;
|
||||
}
|
||||
*/
|
||||
|
||||
HINSTANCE hInstance;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
MSG msg;
|
||||
|
||||
hInstance = GetModuleHandle(NULL);
|
||||
|
||||
h.ah.Draw = handlerDraw;
|
||||
h.ah.HScrollMax = handlerHScrollMax;
|
||||
h.ah.VScrollMax = handlerVScrollMax;
|
||||
|
||||
registerAreaClass();
|
||||
|
||||
area = makeArea(0,
|
||||
WS_OVERLAPPEDWINDOW,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
NULL,
|
||||
(uiAreaHandler *) (&h));
|
||||
|
||||
/* TODO
|
||||
gtk_grid_attach(GTK_GRID(grid),
|
||||
gtk_label_new("H Count"),
|
||||
0, 0, 1, 1);
|
||||
nhspinb = makeSpinbox(0);
|
||||
gtk_grid_attach(GTK_GRID(grid), nhspinb,
|
||||
1, 0, 1, 1);
|
||||
|
||||
gtk_grid_attach(GTK_GRID(grid),
|
||||
gtk_label_new("V Count"),
|
||||
0, 1, 1, 1);
|
||||
nvspinb = makeSpinbox(0);
|
||||
gtk_grid_attach(GTK_GRID(grid), nvspinb,
|
||||
1, 1, 1, 1);
|
||||
*/
|
||||
|
||||
ShowWindow(area, SW_SHOWDEFAULT);
|
||||
UpdateWindow(area);
|
||||
|
||||
while (GetMessage(&msg, NULL, 0, 0)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue