diff --git a/GNUmakefile b/GNUmakefile index 4e845414..7de974ad 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -25,6 +25,7 @@ baseHFILES = \ baseCFILES = \ areaevents.c \ control.c \ + matrix.c \ menu.c \ ptrarray.c \ shouldquit.c \ diff --git a/TODO.md b/TODO.md index f7736241..35fb7239 100644 --- a/TODO.md +++ b/TODO.md @@ -1,3 +1,5 @@ +- make sure graphics state is saved and restored around each draw call + - all ports: update state when adding a control to a parent - should uiWindowsSizing be computed against the window handle, not the parent? diff --git a/matrix.c b/matrix.c new file mode 100644 index 00000000..d98cdc92 --- /dev/null +++ b/matrix.c @@ -0,0 +1,17 @@ +// 11 october 2015 +#include "ui.h" +#include "uipriv.h" + +void setIdentity(uiDrawMatrix *m) +{ + m->M11 = 1; + m->M12 = 0; + m->M21 = 0; + m->M22 = 1; + m->M31 = 0; + m->M32 = 0; +} + +// TODO skew + +// see windows/draw.c for more information diff --git a/ui.h b/ui.h index ec1378c1..c8995dea 100644 --- a/ui.h +++ b/ui.h @@ -295,6 +295,7 @@ struct uiAreaDrawParams { typedef struct uiDrawPath uiDrawPath; typedef struct uiDrawBrush uiDrawBrush; typedef struct uiDrawStrokeParams uiDrawStrokeParams; +typedef struct uiDrawMatrix uiDrawMatrix; typedef enum uiDrawBrushType uiDrawBrushType; typedef struct uiDrawBrushGradientStop uiDrawBrushGradientStop; @@ -332,6 +333,15 @@ enum uiDrawFillMode { uiDrawFillModeAlternate, }; +struct uiDrawMatrix { + double M11; + double M12; + double M21; + double M22; + double M31; + double M32; +}; + struct uiDrawBrush { uiDrawBrushType Type; @@ -402,6 +412,21 @@ _UI_EXTERN void uiDrawFill(uiDrawContext *c, uiDrawPath *path, uiDrawBrush *b); // - elliptical arcs // - quadratic bezier curves +_UI_EXTERN void uiDrawMatrixSetIdentity(uiDrawMatrix *m); +_UI_EXTERN void uiDrawMatrixTranslate(uiDrawMatrix *m, double x, double y); +_UI_EXTERN void uiDrawMatrixScale(uiDrawMatrix *m, double x, double y); +_UI_EXTERN void uiDrawMatrixRotate(uiDrawMatrix *m, double x, double y, double amount); +_UI_EXTERN void uiDrawMatrixSkew(uiDrawMatrix *m, double x, double y, double amount); +_UI_EXTERN void uiDrawMatrixMultiply(uiDrawMatrix *dest, uiDrawMatrix *src); +_UI_EXTERN int uiDrawMatrixInvertible(uiDrawMatrix *m); +_UI_EXTERN int uiDrawMatrixInvert(uiDrawMatrix *m); +_UI_EXTERN void uiDrawMatrixTransformPoint(uiDrawMatrix *m, double *x, double *y); +_UI_EXTERN void uiDrawMatrixTransformSize(uiDrawMatrix *m, double *x, double *y); + +_UI_EXTERN void uiDrawSave(uiDrawContext *c); +_UI_EXTERN void uiDrawRestore(uiDrawContext *c); +_UI_EXTERN void uiDrawTransform(uiDrawContext *c, uiDrawMatrix *m); + typedef enum uiModifiers uiModifiers; enum uiModifiers { diff --git a/uipriv.h b/uipriv.h index e01a9331..641e2aac 100644 --- a/uipriv.h +++ b/uipriv.h @@ -59,3 +59,6 @@ struct clickCounter { extern uintmax_t clickCounterClick(clickCounter *, uintmax_t, intmax_t, intmax_t, uintptr_t, uintptr_t, intmax_t, intmax_t); extern void clickCounterReset(clickCounter *); extern int fromScancode(uintptr_t, uiAreaKeyEvent *); + +// matrix.c +extern void setIdentity(uiDrawMatrix *); diff --git a/unix/draw.c b/unix/draw.c index 25b79356..3d59aad2 100644 --- a/unix/draw.c +++ b/unix/draw.c @@ -296,3 +296,128 @@ void uiDrawFill(uiDrawContext *c, uiDrawPath *path, uiDrawBrush *b) cairo_fill(c->cr); cairo_pattern_destroy(pat); } + +static void m2c(uiDrawMatrix *m, cairo_matrix_t *c) +{ + c->xx = m->M11; + c->yx = m->M12; + c->xy = m->M21; + c->yy = m->M22; + c->x0 = m->M31; + c->y0 = m->M32; +} + +static void c2m(cairo_matrix_t *c, uiDrawMatrix *m) +{ + m->M11 = c->xx; + m->M12 = c->yx; + m->M21 = c->xy; + m->M22 = c->yy; + m->M31 = c->x0; + m->M32 = c->y0; +} + +void uiDrawMatrixSetIdentity(uiDrawMatrix *m) +{ + setIdentity(m); +} + +void uiDrawMatrixTranslate(uiDrawMatrix *m, double x, double y) +{ + cairo_matrix_t c; + + m2c(m, &c); + cairo_matrix_translate(&c, x, y); + c2m(&c, m); +} + +void uiDrawMatrixScale(uiDrawMatrix *m, double x, double y) +{ + cairo_matrix_t c; + + m2c(m, &c); + cairo_matrix_scale(&c, x, y); + c2m(&c, m); +} + +void uiDrawMatrixRotate(uiDrawMatrix *m, double x, double y, double amount) +{ + cairo_matrix_t c; + + m2c(m, &c); + // TODO verify this + cairo_matrix_translate(&c, x, y); + // TODO explain this + cairo_matrix_rotate(&c, -amount); + cairo_matrix_translate(&c, -x, -y); + c2m(&c, m); +} + +void uiDrawMatrixSkew(uiDrawMatrix *m, double x, double y, double amount) +{ + complain("TODO"); +} + +void uiDrawMatrixMultiply(uiDrawMatrix *dest, uiDrawMatrix *src) +{ + cairo_matrix_t c; + cairo_matrix_t d; + + m2c(dest, &c); + m2c(src, &d); + cairo_matrix_multiply(&c, &c, &d); + c2m(&c, dest); +} + +int uiDrawMatrixInvertible(uiDrawMatrix *m) +{ + cairo_matrix_t c; + + m2c(m, &c); + return cairo_matrix_invert(&c) == CAIRO_STATUS_SUCCESS; +} + +int uiDrawMatrixInvert(uiDrawMatrix *m) +{ + cairo_matrix_t c; + + m2c(m, &c); + if (cairo_matrix_invert(&c) != CAIRO_STATUS_SUCCESS) + return 0; + c2m(&c, m); + return 1; +} + +void uiDrawMatrixTransformPoint(uiDrawMatrix *m, double *x, double *y) +{ + cairo_matrix_t c; + + m2c(m, &c); + cairo_matrix_transform_point(&c, x, y); +} + +void uiDrawMatrixTransformSize(uiDrawMatrix *m, double *x, double *y) +{ + cairo_matrix_t c; + + m2c(m, &c); + cairo_matrix_transform_distance(&c, x, y); +} + +void uiDrawSave(uiDrawContext *c) +{ + cairo_save(c->cr); +} + +void uiDrawRestore(uiDrawContext *c) +{ + cairo_restore(c->cr); +} + +void uiDrawTransform(uiDrawContext *c, uiDrawMatrix *m) +{ + cairo_matrix_t cm; + + m2c(m, &cm); + cairo_transform(c->cr, &cm); +}