1 /*	Public domain	*/
2 
3 #ifndef _AGAR_GUI_WIDGET_H_
4 #define _AGAR_GUI_WIDGET_H_
5 
6 #include <agar/config/have_sdl.h>
7 #include <agar/config/have_opengl.h>
8 
9 #include <agar/gui/gui.h>
10 #include <agar/gui/geometry.h>
11 #include <agar/gui/colors.h>
12 #include <agar/gui/surface.h>
13 #include <agar/gui/anim.h>
14 #include <agar/gui/stylesheet.h>
15 #include <agar/gui/mouse.h>
16 #include <agar/gui/keyboard.h>
17 #include <agar/gui/drv.h>
18 
19 #include <agar/gui/begin.h>
20 
21 struct ag_widget;
22 struct ag_cursor;
23 struct ag_font;
24 
25 /* Widget size requisition and allocation. */
26 typedef struct ag_size_req {
27 	int w, h;			/* Requested geometry in pixels */
28 } AG_SizeReq;
29 typedef struct ag_size_alloc {
30 	int w, h;			/* Allocated geometry in pixels */
31 	int x, y;			/* Allocated position in pixels */
32 } AG_SizeAlloc;
33 
34 /* Widget class description. */
35 typedef struct ag_widget_class {
36 	struct ag_object_class _inherit;
37 	void (*draw)(void *);
38 	void (*size_request)(void *, AG_SizeReq *);
39 	int  (*size_allocate)(void *, const AG_SizeAlloc *);
40 } AG_WidgetClass;
41 
42 /* Relative size specification of visual element. */
43 typedef enum ag_widget_sizespec {
44 	AG_WIDGET_BAD_SPEC,		/* Parser error */
45 	AG_WIDGET_PIXELS,		/* Pixel count */
46 	AG_WIDGET_PERCENT,		/* % of available space */
47 	AG_WIDGET_STRINGLEN,		/* Width of given string */
48 	AG_WIDGET_FILL			/* Fill remaining space */
49 } AG_SizeSpec;
50 
51 /* Packing mode (i.e., for container widgets). */
52 enum ag_widget_packing {
53 	AG_PACK_HORIZ,
54 	AG_PACK_VERT
55 };
56 
57 /* Flag description (i.e., for AG_Checkbox(3)) */
58 typedef struct ag_flag_descr {
59 	Uint bitmask;			/* Bitmask */
60 	const char *descr;		/* Bit(s) description */
61 	int writeable;			/* User-editable */
62 } AG_FlagDescr;
63 
64 /*
65  * Widget Actions
66  */
67 typedef enum ag_action_type {
68 	AG_ACTION_FN,			/* Execute function */
69 	AG_ACTION_SET_INT,		/* Set an integer */
70 	AG_ACTION_TOGGLE_INT,		/* Toggle an integer */
71 	AG_ACTION_SET_FLAG,		/* Set specified bits in a word */
72 	AG_ACTION_TOGGLE_FLAG		/* Toggle specified bits in a word */
73 } AG_ActionType;
74 
75 typedef struct ag_action {
76 	AG_ActionType type;
77 	struct ag_widget *widget;	/* Back pointer to widget */
78 	AG_Event *fn;			/* Callback function */
79 	void *p;			/* Target (for SET_*) */
80 	int val;			/* Value (for SET_*) */
81 	Uint bitmask;			/* Bitmask (for SET_FLAG) */
82 } AG_Action;
83 
84 typedef enum ag_action_event_type {
85 	AG_ACTION_ON_BUTTONDOWN,	/* On mouse-button-down */
86 	AG_ACTION_ON_BUTTONUP,		/* On mouse-button-up */
87 	AG_ACTION_ON_KEYDOWN,		/* On key-down */
88 	AG_ACTION_ON_KEYUP,		/* On key-up */
89 	AG_ACTION_ON_KEYREPEAT		/* On key-down, with key repeat */
90 #define AG_ACTION_ON_BUTTON \
91 	AG_ACTION_ON_BUTTONDOWN		/* For mousewheel events */
92 } AG_ActionEventType;
93 
94 typedef struct ag_action_tie {
95 	AG_ActionEventType type;		/* Trigger event type */
96 	union {
97 		AG_MouseButton button;		/* Button index */
98 		struct {
99 			AG_KeySym sym;		/* Matching symbol */
100 			AG_KeyMod mod;		/* Matching modifier */
101 			AG_Timer toRepeat;	/* Key repeat timer */
102 		} key;
103 	} data;
104 	char action[64];			/* Action name */
105 	AG_TAILQ_ENTRY(ag_action_tie) ties;
106 } AG_ActionTie;
107 
108 /* Redraw tie (for AG_RedrawOn*() feature). */
109 enum ag_redraw_tie_type {
110 	AG_REDRAW_ON_CHANGE,
111 	AG_REDRAW_ON_TICK
112 };
113 typedef struct ag_redraw_tie {
114 	enum ag_redraw_tie_type type;
115 	char name[AG_VARIABLE_NAME_MAX];	/* Polled variable */
116 	AG_Variable Vlast;			/* Last accessed data */
117 	int         VlastInited;
118 	AG_Timer to;				/* Polling timer */
119 	Uint ival;				/* Polling interval */
120 	AG_TAILQ_ENTRY(ag_redraw_tie) redrawTies; /* In widget */
121 } AG_RedrawTie;
122 
123 /* Cursor-change area */
124 typedef struct ag_cursor_area {
125 	AG_Rect r;					/* Area in window */
126 	struct ag_cursor *c;				/* Associated cursor */
127 	struct ag_widget *wid;				/* Associated widget */
128 	int stock;					/* Stock cursor? */
129 	AG_TAILQ_ENTRY(ag_cursor_area) cursorAreas;
130 } AG_CursorArea;
131 
132 /*
133  * Standard widget colors (CSS-defined, state-dependent, globally-inheritable).
134  *
135  * SYNC: agWidgetStateNames[], agWidgetColorNames[], agDefaultPalette[].
136  */
137 #define AG_WIDGET_NSTATES 5
138 #define AG_WIDGET_NCOLORS 5
139 enum ag_widget_color_state {
140 	AG_DEFAULT_STATE,		/* Unfocused state */
141 	AG_DISABLED_STATE,		/* Inactive state (#disabled) */
142 	AG_FOCUSED_STATE,		/* Active / focused state (#focused) */
143 	AG_HOVER_STATE,			/* "Mouse over" state (#hover) */
144 	AG_SELECTED_STATE		/* "Selected" state (#selected) */
145 };
146 enum ag_widget_color {
147 	AG_COLOR = 0,			/* Background ("color") */
148 	AG_TEXT_COLOR,			/* Rendered text ("text-color") */
149 	AG_LINE_COLOR,			/* Line drawing ("line-color") */
150 	AG_SHAPE_COLOR,			/* Filled shapes ("shape-color") */
151 	AG_BORDER_COLOR			/* Decorative borders ("border-color") */
152 };
153 typedef struct {
154 	AG_Color c[AG_WIDGET_NSTATES][AG_WIDGET_NCOLORS];
155 } AG_WidgetPalette;
156 #define AG_WCOLOR(wid,which)	 AGWIDGET(wid)->pal.c[AGWIDGET(wid)->cState][which]
157 #define AG_WCOLOR_DEF(wid,which) AGWIDGET(wid)->pal.c[AG_DEFAULT_STATE][which]
158 #define AG_WCOLOR_DIS(wid,which) AGWIDGET(wid)->pal.c[AG_DISABLED_STATE][which]
159 #define AG_WCOLOR_HOV(wid,which) AGWIDGET(wid)->pal.c[AG_HOVER_STATE][which]
160 #define AG_WCOLOR_SEL(wid,which) AGWIDGET(wid)->pal.c[AG_SELECTED_STATE][which]
161 
162 /* Base Agar widget */
163 typedef struct ag_widget {
164 	struct ag_object obj;
165 
166 	Uint flags;
167 #define AG_WIDGET_FOCUSABLE		0x000001 /* Can grab focus */
168 #define AG_WIDGET_FOCUSED		0x000002 /* Holds focus (computed) */
169 #define AG_WIDGET_UNFOCUSED_MOTION	0x000004 /* All mousemotion events */
170 #define AG_WIDGET_UNFOCUSED_BUTTONUP	0x000008 /* All mousebuttonup events */
171 #define AG_WIDGET_UNFOCUSED_BUTTONDOWN	0x000010 /* All mousebuttondown events */
172 #define AG_WIDGET_VISIBLE		0x000020 /* Widget is visible (computed) */
173 #define AG_WIDGET_HFILL			0x000040 /* Expand to fill width */
174 #define AG_WIDGET_VFILL			0x000080 /* Expand to fill height */
175 #define AG_WIDGET_USE_OPENGL		0x000100 /* Set up separate GL context */
176 #define AG_WIDGET_HIDE			0x000200 /* Don't draw this widget */
177 #define AG_WIDGET_DISABLED		0x000400 /* Don't respond to input */
178 #define AG_WIDGET_MOUSEOVER		0x000800 /* Mouseover state (computed) */
179 #define AG_WIDGET_CATCH_TAB		0x001000 /* Catch tab key events */
180 #define AG_WIDGET_GL_RESHAPE		0x002000 /* Pending GL view reshape */
181 #define AG_WIDGET_UNDERSIZE		0x004000 /* Size alloc failed (computed) */
182 #define AG_WIDGET_NOSPACING		0x008000 /* No box model (container-specific) */
183 #define AG_WIDGET_UNFOCUSED_KEYDOWN	0x010000 /* All mousebuttondown events */
184 #define AG_WIDGET_UNFOCUSED_KEYUP	0x020000 /* All mousebuttondown events */
185 #define AG_WIDGET_TABLE_EMBEDDABLE	0x080000 /* Usable in polled tables */
186 #define AG_WIDGET_UPDATE_WINDOW		0x100000 /* Request an AG_WindowUpdate() as soon as possible */
187 #define AG_WIDGET_QUEUE_SURFACE_BACKUP	0x200000 /* Must backup surfaces ASAP */
188 #define AG_WIDGET_USE_TEXT		0x400000 /* Use Agar's font engine */
189 #define AG_WIDGET_USE_MOUSEOVER		0x800000 /* Update MOUSEOVER flag and generate mouseover events */
190 #define AG_WIDGET_EXPAND		(AG_WIDGET_HFILL|AG_WIDGET_VFILL)
191 
192 	int x, y;			/* Coordinates in container */
193 	int w, h;			/* Allocated geometry */
194 	AG_Rect2 rView;			/* Computed view coordinates */
195 	AG_Rect2 rSens;			/* Cursor notification area */
196 	AG_Surface **surfaces;		/* Registered surfaces */
197 	Uint        *surfaceFlags;	/* Surface flags */
198 #define AG_WIDGET_SURFACE_NODUP	0x01	/* Don't free on destroy */
199 #define AG_WIDGET_SURFACE_REGEN	0x02	/* Texture needs to be regenerated */
200 	Uint        nsurfaces;
201 	Uint        *textures;		/* Cached textures (driver-specific) */
202 	AG_TexCoord *texcoords;		/* Cached texture coordinates */
203 
204 	struct ag_widget *focusFwd;		/* For ForwardFocus() */
205 	struct ag_window *window;		/* Back ptr to parent window */
206 	struct ag_driver *drv;			/* Back ptr to driver */
207 	struct ag_driver_class *drvOps;		/* Back ptr to driver class */
208 
209 	AG_Tbl actions;				 	/* Registered actions */
210 	AG_TAILQ_HEAD_(ag_action_tie) mouseActions;	/* Mouse action ties */
211 	AG_TAILQ_HEAD_(ag_action_tie) keyActions;	/* Kbd action ties */
212 	AG_TAILQ_HEAD_(ag_redraw_tie) redrawTies;	/* For AG_RedrawOn*() */
213 	AG_TAILQ_HEAD_(ag_cursor_area) cursorAreas;	/* Cursor-change areas
214 							   (not yet attached) */
215 
216 	AG_StyleSheet *css;			/* Alternate style sheet */
217 	enum ag_widget_color_state cState;	/* Current CSS color state */
218 	struct ag_font *font;			/* Computed font reference */
219 	AG_WidgetPalette pal;			/* Computed color palette */
220 
221 	struct {
222 		float mProjection[16];		/* Projection matrix */
223 		float mModelview[16];		/* Modelview matrix */
224 	} gl;
225 } AG_Widget;
226 
227 #define AGWIDGET(wi)		((AG_Widget *)(wi))
228 #define AGWIDGET_OPS(wi)	((AG_WidgetClass *)AGOBJECT(wi)->cls)
229 #define AGWIDGET_SUPER_OPS(wi)	((AG_WidgetClass *)AGOBJECT(wi)->cls->super)
230 
231 #define AGWIDGET_SURFACE(wi, ind)	AGWIDGET(wi)->surfaces[ind]
232 #define AGWIDGET_TEXTURE(wi, ind)	AGWIDGET(wi)->textures[ind]
233 #define AGWIDGET_SURFACE_NODUP(wi, ind)	(AGWIDGET(wi)->surfaceFlags[ind] & \
234 					 AG_WIDGET_SURFACE_NODUP)
235 #define AGSTYLE(p)			 AGWIDGET(p)->theme
236 
237 #define AGWIDGET_KEYBOARD(obj)				\
238     (((obj) != NULL) ? AGWIDGET(obj)->drv->kbd :	\
239      (agDriverSw != NULL) ? AGDRIVER(agDriverSw)->kbd:	\
240      NULL)
241 
242 #if defined(_AGAR_INTERNAL) || defined(_USE_AGAR_GUI)
243 # define WIDGET(wi)			AGWIDGET(wi)
244 # define WIDGET_OPS(wi)			AGWIDGET_OPS(wi)
245 # define WIDGET_SUPER_OPS(wi)		AGWIDGET_SUPER_OPS(wi)
246 # define WSURFACE(wi,ind)		AGWIDGET_SURFACE((wi),(ind))
247 # define WTEXTURE(wi,ind)		AGWIDGET_TEXTURE((wi),(ind))
248 # define WSURFACE_NODUP(wi,ind)		AGWIDGET_SURFACE_NODUP((wi),(ind))
249 # define STYLE(p)			AGSTYLE(p)
250 # define WIDTH(p)			AGWIDGET(p)->w
251 # define HEIGHT(p)			AGWIDGET(p)->h
252 # define WCOLOR(wid,which)		AG_WCOLOR((wid),(which))
253 # define WCOLOR_DEF(wid,which)		AG_WCOLOR_DEF((wid),(which))
254 # define WCOLOR_DIS(wid,which)		AG_WCOLOR_DIS((wid),(which))
255 # define WCOLOR_HOV(wid,which)		AG_WCOLOR_HOV((wid),(which))
256 # define WCOLOR_SEL(wid,which)		AG_WCOLOR_SEL((wid),(which))
257 # define TEXT_COLOR			AG_TEXT_COLOR
258 # define LINE_COLOR			AG_LINE_COLOR
259 # define SHAPE_COLOR			AG_SHAPE_COLOR
260 # define BORDER_COLOR			AG_BORDER_COLOR
261 #endif /* _AGAR_INTERNAL or _USE_AGAR_GUI */
262 
263 struct ag_window;
264 struct ag_font;
265 AG_TAILQ_HEAD(ag_widgetq, ag_widget);
266 
267 __BEGIN_DECLS
268 extern AG_WidgetClass agWidgetClass;
269 extern const char *agWidgetPropNames[];
270 extern const char *agWidgetStateNames[];
271 extern const char *agWidgetColorNames[];
272 extern AG_WidgetPalette agDefaultPalette;
273 
274 void       AG_WidgetDraw(void *);
275 void       AG_WidgetSizeReq(void *, AG_SizeReq *);
276 void       AG_WidgetSizeAlloc(void *, AG_SizeAlloc *);
277 void       AG_WidgetSetFocusable(void *, int);
278 void       AG_WidgetForwardFocus(void *, void *);
279 
280 int        AG_WidgetFocus(void *);
281 void       AG_WidgetUnfocus(void *);
282 AG_Widget *AG_WidgetFindFocused(void *);
283 void      *AG_WidgetFindPoint(const char *, int, int);
284 void      *AG_WidgetFindRect(const char *, int, int, int, int);
285 void       AG_WidgetUpdateCoords(void *, int, int);
286 
287 int	 AG_WidgetMapSurface(void *, AG_Surface *);
288 void	 AG_WidgetReplaceSurface(void *, int, AG_Surface *);
289 #define	 AG_WidgetUnmapSurface(w, n) \
290 	 AG_WidgetReplaceSurface((w),(n),NULL)
291 #define  AG_WidgetBlitSurface(p,n,x,y) \
292 	 AG_WidgetBlitFrom((p),(p),(n),NULL,(x),(y))
293 #ifdef HAVE_OPENGL
294 void	 AG_WidgetBlitGL(void *, AG_Surface *, float, float);
295 void	 AG_WidgetBlitSurfaceGL(void *, int, float, float);
296 void	 AG_WidgetBlitSurfaceFlippedGL(void *, int, float, float);
297 void	 AG_WidgetFreeResourcesGL(void *);
298 void	 AG_WidgetRegenResourcesGL(void *);
299 #endif
300 
301 int         AG_WidgetSensitive(void *, int, int);
302 AG_SizeSpec AG_WidgetParseSizeSpec(const char *, int *);
303 int         AG_WidgetScrollDelta(Uint32 *);
304 void       *AG_WidgetFind(void *, const char *);
305 
306 void        AG_WidgetShow(void *);
307 void        AG_WidgetHide(void *);
308 void        AG_WidgetShowAll(void *);
309 void        AG_WidgetHideAll(void *);
310 void        AG_WidgetEnableAll(void *);
311 void        AG_WidgetDisabledAll(void *);
312 
313 void        AG_WidgetInheritDraw(void *);
314 void        AG_WidgetInheritSizeRequest(void *, AG_SizeReq *);
315 int         AG_WidgetInheritSizeAllocate(void *, const AG_SizeAlloc *);
316 AG_Surface *AG_WidgetSurface(void *);
317 
318 void        AG_RedrawOnChange(void *, int, const char *);
319 void        AG_RedrawOnTick(void *, int);
320 
321 void        AG_WidgetStdKeyDown(AG_Event *);
322 void        AG_WidgetStdKeyUp(AG_Event *);
323 void        AG_WidgetStdMouseButtonDown(AG_Event *);
324 void        AG_WidgetStdMouseButtonUp(AG_Event *);
325 
326 AG_Action  *AG_ActionFn(void *, const char *, AG_EventFn, const char *, ...);
327 AG_Action  *AG_ActionSetInt(void *, const char *, int *, int);
328 AG_Action  *AG_ActionToggleInt(void *, const char *, int *);
329 AG_Action  *AG_ActionSetFlag(void *, const char *, Uint *, Uint, int);
330 AG_Action  *AG_ActionToggleFlag(void *, const char *, Uint *, Uint);
331 
332 void        AG_ActionOnButtonDown(void *, int, const char *);
333 void        AG_ActionOnButtonUp(void *, int, const char *);
334 #define     AG_ActionOnButton(w,b,a) \
335             AG_ActionOnButtonDown((w),(b),(a))
336 
337 void        AG_ActionOnKey(void *, AG_KeySym, AG_KeyMod, const char *);
338 void        AG_ActionOnKeyDown(void *, AG_KeySym, AG_KeyMod, const char *);
339 void        AG_ActionOnKeyUp(void *, AG_KeySym, AG_KeyMod, const char *);
340 
341 int         AG_ExecMouseAction(void *, AG_ActionEventType, int, int, int);
342 int         AG_ExecKeyAction(void *, AG_ActionEventType, AG_KeySym, AG_KeyMod);
343 int         AG_ExecAction(void *, AG_Action *);
344 
345 void        AG_WidgetEnable(void *);
346 void        AG_WidgetDisable(void *);
347 
348 void        AG_WidgetCompileStyle(void *);
349 void        AG_WidgetCopyStyle(void *, void *);
350 void        AG_WidgetFreeStyle(void *);
351 
352 void        AG_SetFont(void *, const struct ag_font *);
353 void        AG_SetStyle(void *, const char *, const char *);
354 
355 /* Return the widget state. The Widget object must be locked. */
356 static __inline__ int
AG_WidgetEnabled(void * p)357 AG_WidgetEnabled(void *p)
358 {
359 	return !(AGWIDGET(p)->flags & AG_WIDGET_DISABLED);
360 }
361 static __inline__ int
AG_WidgetDisabled(void * p)362 AG_WidgetDisabled(void *p)
363 {
364 	return (AGWIDGET(p)->flags & AG_WIDGET_DISABLED);
365 }
366 
367 /* Return the widget's visibility state. The Widget object must be locked. */
368 static __inline__ int
AG_WidgetVisible(void * p)369 AG_WidgetVisible(void *p)
370 {
371 	return (AGWIDGET(p)->flags & AG_WIDGET_VISIBLE);
372 }
373 
374 /*
375  * Return the focus state of the widget inside of its parent window (not
376  * necessarily the effective focus). The Widget object must be locked.
377  */
378 static __inline__ int
AG_WidgetIsFocusedInWindow(void * p)379 AG_WidgetIsFocusedInWindow(void *p)
380 {
381 	return (AGWIDGET(p)->flags & AG_WIDGET_FOCUSED);
382 }
383 
384 /* Test whether view coordinates x,y lie in widget's allocated space. */
385 static __inline__ int
AG_WidgetArea(void * p,int x,int y)386 AG_WidgetArea(void *p, int x, int y)
387 {
388 	AG_Widget *wid = AGWIDGET(p);
389 
390 	return (x > wid->rView.x1 && y > wid->rView.y1 &&
391 	        x < wid->rView.x2 && y < wid->rView.y2);
392 }
393 
394 /* Test whether widget coordinates x,y lie in widget's allocated space. */
395 static __inline__ int
AG_WidgetRelativeArea(void * p,int x,int y)396 AG_WidgetRelativeArea(void *p, int x, int y)
397 {
398 	AG_Widget *wid = AGWIDGET(p);
399 
400 	return (x >= 0 &&
401 	        y >= 0 &&
402 	        x < wid->w &&
403 		y < wid->h);
404 }
405 
406 /* Expand widget to fill available space in parent container. */
407 static __inline__ void
AG_Expand(void * wid)408 AG_Expand(void *wid)
409 {
410 	AG_ObjectLock(wid);
411 	AGWIDGET(wid)->flags |= AG_WIDGET_EXPAND;
412 	AG_ObjectUnlock(wid);
413 }
414 static __inline__ void
AG_ExpandHoriz(void * wid)415 AG_ExpandHoriz(void *wid)
416 {
417 	AG_ObjectLock(wid);
418 	AGWIDGET(wid)->flags |= AG_WIDGET_HFILL;
419 	AG_ObjectUnlock(wid);
420 }
421 static __inline__ void
AG_ExpandVert(void * wid)422 AG_ExpandVert(void *wid)
423 {
424 	AG_ObjectLock(wid);
425 	AGWIDGET(wid)->flags |= AG_WIDGET_VFILL;
426 	AG_ObjectUnlock(wid);
427 }
428 
429 /* Signal a change in a widget surface. */
430 #ifdef HAVE_OPENGL
431 # define AG_WidgetUpdateSurface(wid,name) do { \
432 	 AGWIDGET(wid)->surfaceFlags[(name)] |= AG_WIDGET_SURFACE_REGEN; \
433 } while (0)
434 #else
435 # define AG_WidgetUpdateSurface(wid,name)
436 #endif
437 
438 /*
439  * Request that all computed widget coordinates and geometries in the widget's
440  * current window be updated as soon as possible. The widget may or may not
441  * be currently attached to a window at the time the call is made.
442  */
443 static __inline__ void
AG_WidgetUpdate(void * obj)444 AG_WidgetUpdate(void *obj)
445 {
446 	AG_Widget *wid = (AG_Widget *)obj;
447 
448 	AG_ObjectLock(wid);
449 	wid->flags |= AG_WIDGET_UPDATE_WINDOW;
450 	AG_ObjectUnlock(wid);
451 }
452 
453 /*
454  * Push a clipping rectangle onto the stack, by widget-relative coordinates.
455  * Must be invoked from GUI rendering context.
456  */
457 static __inline__ void
AG_PushClipRect(void * obj,AG_Rect pr)458 AG_PushClipRect(void *obj, AG_Rect pr)
459 {
460 	AG_Widget *wid = (AG_Widget *)obj;
461 	AG_Rect r;
462 
463 	r.x = wid->rView.x1 + pr.x;
464 	r.y = wid->rView.y1 + pr.y;
465 	r.w = pr.w;
466 	r.h = pr.h;
467 	wid->drvOps->pushClipRect(wid->drv, r);
468 }
469 
470 /*
471  * Pop a clipping rectangle off the clipping rectangle stack.
472  * Must be invoked from GUI rendering context.
473  */
474 static __inline__ void
AG_PopClipRect(void * obj)475 AG_PopClipRect(void *obj)
476 {
477 	AG_Widget *wid = (AG_Widget *)obj;
478 
479 	wid->drvOps->popClipRect(wid->drv);
480 }
481 
482 /* Set the blending mode, pushing the current mode on a stack. */
483 static __inline__ void
AG_PushBlendingMode(void * obj,AG_BlendFn fnSrc,AG_BlendFn fnDst)484 AG_PushBlendingMode(void *obj, AG_BlendFn fnSrc, AG_BlendFn fnDst)
485 {
486 	AG_Widget *wid = (AG_Widget *)obj;
487 
488 	wid->drvOps->pushBlendingMode(wid->drv, fnSrc, fnDst);
489 }
490 
491 /* Restore the last blending mode. */
492 static __inline__ void
AG_PopBlendingMode(void * obj)493 AG_PopBlendingMode(void *obj)
494 {
495 	AG_Widget *wid = (AG_Widget *)obj;
496 
497 	wid->drvOps->popBlendingMode(wid->drv);
498 }
499 
500 /* Offset the coordinates of an AG_Rect per widget coordinates. */
501 static __inline__ void
AG_WidgetOffsetRect(void * obj,AG_Rect * r)502 AG_WidgetOffsetRect(void *obj, AG_Rect *r)
503 {
504 	AG_Widget *wid = (AG_Widget *)obj;
505 
506 	r->x += wid->rView.x1;
507 	r->y += wid->rView.y1;
508 }
509 
510 /*
511  * Variant of AG_WidgetMapSurface() that sets the NODUP flag such that
512  * the surface is not freed by the widget.
513  */
514 static __inline__ int
AG_WidgetMapSurfaceNODUP(void * obj,AG_Surface * su)515 AG_WidgetMapSurfaceNODUP(void *obj, AG_Surface *su)
516 {
517 	AG_Widget *wid = (AG_Widget *)obj;
518 	int name;
519 
520 	AG_ObjectLock(wid);
521 	if ((name = AG_WidgetMapSurface(wid, su)) != -1) {
522 		wid->surfaceFlags[name] |= AG_WIDGET_SURFACE_NODUP;
523 	}
524 	AG_ObjectUnlock(wid);
525 	return (name);
526 }
527 
528 /* Variant of WidgetReplaceSurface() that sets the NODUP flag. */
529 static __inline__ void
AG_WidgetReplaceSurfaceNODUP(void * obj,int name,AG_Surface * su)530 AG_WidgetReplaceSurfaceNODUP(void *obj, int name, AG_Surface *su)
531 {
532 	AG_Widget *wid = (AG_Widget *)obj;
533 
534 	AG_ObjectLock(wid);
535 #ifdef AG_DEBUG
536 	if (name < 0 || name >= (int)wid->nsurfaces)
537 		AG_FatalError("Bad surface handle");
538 #endif
539 	AG_WidgetReplaceSurface(wid, name, su);
540 	wid->surfaceFlags[name] |= AG_WIDGET_SURFACE_NODUP;
541 	AG_ObjectUnlock(wid);
542 }
543 
544 /*
545  * Draw an unmapped surface at given coordinates in the widget's coordinate
546  * system. With hardware-accelerated drivers, this operation is slow compared
547  * to drawing of mapped surfaces, since a software->hardware copy is done.
548  */
549 static __inline__ void
AG_WidgetBlit(void * obj,AG_Surface * s,int x,int y)550 AG_WidgetBlit(void *obj, AG_Surface *s, int x, int y)
551 {
552 	AG_Widget *wid = (AG_Widget *)obj;
553 
554 	wid->drvOps->blitSurface(wid->drv, wid, s,
555 	    wid->rView.x1 + x,
556 	    wid->rView.y1 + y);
557 }
558 
559 /*
560  * Perform a hardware or software blit from a mapped surface to the display
561  * at coordinates relative to the widget, using clipping.
562  */
563 static __inline__ void
AG_WidgetBlitFrom(void * obj,void * objSrc,int s,AG_Rect * r,int x,int y)564 AG_WidgetBlitFrom(void *obj, void *objSrc, int s, AG_Rect *r, int x, int y)
565 {
566 	AG_Widget *wid = (AG_Widget *)obj;
567 	AG_Widget *widSrc = (AG_Widget *)objSrc;
568 
569 	if (s == -1 || widSrc->surfaces[s] == NULL)
570 		return;
571 
572 	wid->drvOps->blitSurfaceFrom(wid->drv, wid, widSrc, s, r,
573 	    wid->rView.x1 + x,
574 	    wid->rView.y1 + y);
575 }
576 
577 /*
578  * Routines for direct access to keyboard key and modifier state
579  * from widget code.
580  */
581 static __inline__ int *
AG_GetKeyState(void * obj)582 AG_GetKeyState(void *obj)
583 {
584 	AG_Keyboard *kbd = AGWIDGET_KEYBOARD(obj);
585 	return (kbd->keyState);
586 }
587 static __inline__ void
AG_SetKeyState(void * obj,int * ks)588 AG_SetKeyState(void *obj, int *ks)
589 {
590 	AG_Keyboard *kbd = AGWIDGET_KEYBOARD(obj);
591 	memcpy(kbd->keyState, ks, kbd->keyCount*sizeof(int));
592 }
593 static __inline__ int
AG_GetKeyCount(void * obj)594 AG_GetKeyCount(void *obj)
595 {
596 	AG_Keyboard *kbd = AGWIDGET_KEYBOARD(obj);
597 	return (kbd->keyCount);
598 }
599 static __inline__ Uint
AG_GetModState(void * obj)600 AG_GetModState(void *obj)
601 {
602 	AG_Keyboard *kbd = AGWIDGET_KEYBOARD(obj);
603 	return (kbd->modState);
604 }
605 static __inline__ void
AG_SetModState(void * obj,Uint ms)606 AG_SetModState(void *obj, Uint ms)
607 {
608 	AG_Keyboard *kbd = AGWIDGET_KEYBOARD(obj);
609 	kbd->modState = ms;
610 }
611 __END_DECLS
612 
613 #ifdef AG_LEGACY
614 # include <agar/gui/widget_legacy.h>
615 #endif /* AG_LEGACY */
616 
617 #include <agar/gui/close.h>
618 #endif /* _AGAR_GUI_WIDGET_H_ */
619