More uiArea work, this time on Windows.

This commit is contained in:
Pietro Gagliardi 2015-09-08 11:51:12 -04:00
parent 6e2ad99ce9
commit 4eed0d77ae
6 changed files with 411 additions and 5 deletions

View File

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

114
winarea/area.c Normal file
View File

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

16
winarea/area.h Normal file
View File

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

111
winarea/debug.c Normal file
View File

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

View File

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

162
winarea/main.c Normal file
View File

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