gambas-source-code/main/lib/geom/crect_temp.h
Benoît Minisini 3c1a76248b Add Expand() and Shrink() methods to the rectangle classes.
[GB.GEOM]
* NEW: Add Expand() and Shrink() methods to the rectangle classes.
2023-01-02 20:22:30 +01:00

427 lines
51 KiB
C

/***************************************************************************
crect_temp.h
(c) 2000-2017 Benoît Minisini <benoit.minisini@gambas-basic.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA.
***************************************************************************/
#define IMPLEMENT_RECT_CLASS(__struct, __name, __gtype, __ctype, __sign, __return, __this, __pstruct, __pname) \
\
static void __struct##_normalize(__struct *_object) \
{ \
if (__this->w < 0) \
{ \
__this->w = (- __this->w); \
__this->x -= __this->w; \
} \
\
if (__this->h < 0) \
{ \
__this->h = (- __this->h); \
__this->y -= __this->h; \
} \
} \
\
__struct * __struct##_create(void) \
{ \
return GB.New(GB.FindClass(#__name), NULL, NULL); \
} \
\
\
BEGIN_METHOD(__name##_new, __gtype x; __gtype y; __gtype w; __gtype h) \
\
if (!MISSING(x) && !MISSING(y) && !MISSING(w) && !MISSING(h)) \
{ \
__this->x = VARG(x); \
__this->y = VARG(y); \
__this->w = VARG(w); \
__this->h = VARG(h); \
__struct##_normalize(__this); \
} \
else if (!MISSING(x) || !MISSING(y) || !MISSING(w) || !MISSING(h)) \
{ \
GB.Error("Not enough arguments"); \
} \
\
END_METHOD \
\
BEGIN_METHOD(__name##_call, __gtype x; __gtype y; __gtype w; __gtype h) \
\
__struct *rect = __struct##_create(); \
\
rect->x = VARG(x); \
rect->y = VARG(y); \
rect->w = VARG(w); \
rect->h = VARG(h); \
__struct##_normalize(rect); \
\
GB.ReturnObject(rect); \
\
END_METHOD \
\
BEGIN_PROPERTY(__name##_X) \
\
if (READ_PROPERTY) \
__return(__this->x); \
else \
__this->x = VPROP(__gtype); \
\
END_PROPERTY \
\
BEGIN_PROPERTY(__name##_Y) \
\
if (READ_PROPERTY) \
__return(__this->y); \
else \
__this->y = VPROP(__gtype); \
\
END_PROPERTY \
\
BEGIN_PROPERTY(__name##_Width) \
\
if (READ_PROPERTY) \
__return(__this->w); \
else \
{ \
__this->w = VPROP(__gtype); \
__struct##_normalize(__this); \
} \
\
END_PROPERTY \
\
BEGIN_PROPERTY(__name##_Height) \
\
if (READ_PROPERTY) \
__return(__this->h); \
else \
{ \
__this->h = VPROP(__gtype); \
__struct##_normalize(__this); \
} \
\
END_PROPERTY \
\
BEGIN_PROPERTY(__name##_Left) \
\
if (READ_PROPERTY) \
__return(__this->x); \
else \
{ \
__ctype dx = VPROP(__gtype) - __this->x; \
if (dx > __this->w) \
dx = __this->w; \
\
__this->x += dx; \
__this->w -= dx; \
} \
\
END_PROPERTY \
\
BEGIN_PROPERTY(__name##_Top) \
\
if (READ_PROPERTY) \
__return(__this->y); \
else \
{ \
__ctype dy = VPROP(__gtype) - __this->y; \
if (dy > __this->h) \
dy = __this->h; \
\
__this->y += dy; \
__this->h -= dy; \
} \
\
END_PROPERTY \
\
BEGIN_PROPERTY(__name##_Right) \
\
if (READ_PROPERTY) \
__return(__this->x + __this->w); \
else \
{ \
__ctype x2 = VPROP(__gtype); \
if (x2 < __this->x) \
x2 = __this->x; \
\
__this->w = x2 - __this->x; \
} \
\
END_PROPERTY \
\
BEGIN_PROPERTY(__name##_Bottom) \
\
if (READ_PROPERTY) \
__return(__this->y + __this->h); \
else \
{ \
__ctype y2 = VPROP(__gtype); \
if (y2 < __this->y) \
y2 = __this->y; \
\
__this->h = y2 - __this->y; \
} \
\
END_PROPERTY \
\
BEGIN_METHOD_VOID(__name##_Clear) \
\
__this->x = __this->y = __this->w = __this->h = 0; \
\
END_METHOD \
\
BEGIN_METHOD_VOID(__name##_IsVoid) \
\
GB.ReturnBoolean(__this->w <= 0 || __this->h <= 0); \
\
END_METHOD \
\
BEGIN_METHOD_VOID(__name##_Copy) \
\
__struct *copy = __struct##_create(); \
\
copy->x = __this->x; \
copy->y = __this->y; \
copy->w = __this->w; \
copy->h = __this->h; \
\
GB.ReturnObject(copy); \
\
END_METHOD \
\
BEGIN_METHOD(__name##_Move, __gtype x; __gtype y; __gtype w; __gtype h) \
\
__this->x = VARG(x); \
__this->y = VARG(y); \
if (!MISSING(w) && !MISSING(h)) \
{ \
__this->w = VARG(w); \
__this->h = VARG(h); \
__struct##_normalize(__this); \
} \
\
END_METHOD \
\
BEGIN_METHOD(__name##_Resize, __gtype w; __gtype h) \
\
__this->w = VARG(w); \
__this->h = VARG(h); \
__struct##_normalize(__this); \
\
END_METHOD \
\
BEGIN_METHOD(__name##_Translate, __gtype dx; __gtype dy) \
\
__this->x += VARG(dx); \
__this->y += VARG(dy); \
\
END_METHOD \
\
BEGIN_METHOD(__name##_Union, GB_OBJECT rect) \
\
__struct *dest; \
__ctype x, y, w, h; \
__struct *rect = (__struct *)VARG(rect); \
\
if (GB.CheckObject(rect)) \
return; \
\
dest = __struct##_create(); \
\
x = Min(__this->x, rect->x); \
y = Min(__this->y, rect->y); \
w = Max(__this->x + __this->w, rect->x + rect->w) - x; \
h = Max(__this->y + __this->h, rect->y + rect->h) - y; \
\
dest->x = x; \
dest->y = y; \
dest->w = w; \
dest->h = h; \
\
GB.ReturnObject(dest); \
\
END_METHOD \
\
BEGIN_METHOD(__name##_Intersection, GB_OBJECT rect) \
\
__struct *dest; \
__ctype x, y, x2, y2; \
__struct *rect = (__struct *)VARG(rect); \
\
if (GB.CheckObject(rect)) \
return; \
\
x = Max(__this->x, rect->x); \
y = Max(__this->y, rect->y); \
x2 = Min(__this->x + __this->w, rect->x + rect->w); \
y2 = Min(__this->y + __this->h, rect->y + rect->h); \
\
if (x2 > x && y2 > y) \
{ \
dest = __struct##_create(); \
\
dest->x = x; \
dest->y = y; \
dest->w = x2 - x; \
dest->h = y2 - y; \
\
GB.ReturnObject(dest); \
} \
else \
{ \
GB.ReturnNull(); \
} \
\
END_METHOD \
\
BEGIN_METHOD(__name##_Contains, __gtype x; __gtype y) \
\
__ctype x = VARG(x); \
__ctype y = VARG(y); \
\
GB.ReturnBoolean((x >= __this->x) && (x < (__this->x + __this->w)) && (y >= __this->y) && (y < (__this->y + __this->h))); \
\
END_METHOD \
\
BEGIN_METHOD(__name##_Shrink, __gtype left; __gtype top; __gtype right; __gtype bottom) \
\
__ctype left = VARG(left); \
__ctype top = VARGOPT(top, left); \
__ctype right = VARGOPT(right, left); \
__ctype bottom = VARGOPT(bottom, top); \
\
__this->x += left; \
__this->w -= (left + right); \
__this->y += top; \
__this->h -= (top + bottom); \
\
if (__this->w < 1 || __this->h < 1) \
__this->w = __this->h = 0; \
\
END_METHOD \
\
BEGIN_METHOD(__name##_Expand, __gtype left; __gtype top; __gtype right; __gtype bottom) \
\
__ctype left = VARG(left); \
__ctype top = VARGOPT(top, left); \
__ctype right = VARGOPT(right, left); \
__ctype bottom = VARGOPT(bottom, top); \
\
__this->x -= left; \
__this->w += (left + right); \
__this->y -= top; \
__this->h += (top + bottom); \
\
if (__this->w < 1 || __this->h < 1) \
__this->w = __this->h = 0; \
\
END_METHOD \
\
BEGIN_METHOD_VOID(__name##_Center) \
\
__pstruct *point = GB.New(GB.FindClass(#__pname), NULL, NULL); \
point->x = __this->x + __this->w / 2; \
point->y = __this->y + __this->h / 2; \
GB.ReturnObject(point); \
\
END_METHOD \
\
BEGIN_METHOD(__name##_Stretch, __gtype width; __gtype height; GB_OBJECT frame; GB_INTEGER align) \
\
__struct *frame = (__struct *)VARG(frame); \
int align = VARGOPT(align, ALIGN_CENTER); \
__ctype w = VARG(width); \
__ctype h = VARG(height); \
\
__struct *result; \
double scalew, scaleh; \
\
if (GB.CheckObject(frame)) \
return; \
\
result = __struct##_create(); \
if (w <= 0 || h <= 0 || frame->w <= 0 || frame->h <= 0) \
{ \
GB.ReturnObject(result); \
return; \
} \
\
scalew = (double)frame->w / w; \
scaleh = (double)frame->h / h; \
if (scalew > scaleh) \
scalew = scaleh; \
else \
scaleh = scalew; \
\
result->w = w * scalew; \
result->h = h * scaleh; \
\
if (ALIGN_IS_LEFT(align)) \
result->x = frame->x; \
else if (ALIGN_IS_CENTER(align)) \
result->x = frame->x + (frame->w - result->w) / 2; \
else if (ALIGN_IS_RIGHT(align)) \
result->x = frame->x + frame->w - result->w; \
\
if (ALIGN_IS_TOP(align)) \
result->y = frame->y; \
else if (ALIGN_IS_MIDDLE(align)) \
result->y = frame->y + (frame->h - result->h) / 2; \
else if (ALIGN_IS_BOTTOM(align)) \
result->y = frame->y + frame->h - result->h; \
\
GB.ReturnObject(result); \
\
END_METHOD \
\
GB_DESC __name##Desc[] = \
{ \
GB_DECLARE(#__name, sizeof(__struct)), \
\
GB_METHOD("_new", NULL, __name##_new, "[(X)" __sign "(Y)" __sign "(Width)" __sign "(Height)" __sign "]"), \
GB_STATIC_METHOD("_call", #__name, __name##_call, "(X)" __sign "(Y)" __sign "(Width)" __sign "(Height)" __sign), \
\
GB_PROPERTY("X", __sign, __name##_X), \
GB_PROPERTY("Y", __sign, __name##_Y), \
GB_PROPERTY("W", __sign, __name##_Width), \
GB_PROPERTY("H", __sign, __name##_Height), \
GB_PROPERTY("Width", __sign, __name##_Width), \
GB_PROPERTY("Height", __sign, __name##_Height), \
GB_PROPERTY("Left", __sign, __name##_Left), \
GB_PROPERTY("Top", __sign, __name##_Top), \
GB_PROPERTY("Right", __sign, __name##_Right), \
GB_PROPERTY("Bottom", __sign, __name##_Bottom), \
\
GB_METHOD("Clear", NULL, __name##_Clear, NULL), \
GB_METHOD("IsVoid", "b", __name##_IsVoid, NULL), \
GB_METHOD("Copy", #__name, __name##_Copy, NULL), \
GB_METHOD("Move", NULL, __name##_Move, "(X)" __sign "(Y)" __sign "[(Width)" __sign "(Height)" __sign "]"), \
GB_METHOD("Resize", NULL, __name##_Resize, "(Width)" __sign "(Height)" __sign ""), \
GB_METHOD("Translate", NULL, __name##_Translate, "(DX)" __sign "(DY)" __sign ""), \
GB_METHOD("Union", #__name, __name##_Union, "(Rect)" #__name ";"), \
GB_METHOD("Intersection", #__name, __name##_Intersection, "(Rect)" #__name ";"), \
GB_METHOD("Contains", "b", __name##_Contains, "(X)" __sign "(Y)" __sign ""), \
GB_METHOD("Adjust", NULL, __name##_Shrink, "(Left)" __sign "[(Top)" __sign "(Right)" __sign "(Bottom)" __sign "]"), \
GB_METHOD("Expand", NULL, __name##_Expand, "(Left)" __sign "[(Top)" __sign "(Right)" __sign "(Bottom)" __sign "]"), \
GB_METHOD("Shrink", NULL, __name##_Shrink, "(Left)" __sign "[(Top)" __sign "(Right)" __sign "(Bottom)" __sign "]"), \
GB_METHOD("Center", #__pname, __name##_Center, NULL), \
\
GB_STATIC_METHOD("Stretch", #__name, __name##_Stretch, "(Width)" __sign "(Height)" __sign "(Frame)" #__name ";[(Alignment)i]"), \
\
GB_END_DECLARE \
};