1 /*	Public domain	*/
2 
3 /*
4  * Implementation of a typical Agar widget which uses surface mappings to
5  * efficiently draw surfaces, regardless of the underlying graphics system.
6  *
7  * If you are not familiar with the way the Agar object system handles
8  * inheritance, see demos/objsystem.
9  */
10 
11 #include "agartest.h"
12 #include "customwidget_mywidget.h"
13 
14 /*
15  * This is a generic constructor function. It is completely optional, but
16  * customary of FooNew() functions to allocate, initialize and attach an
17  * instance of the class.
18  */
19 MyWidget *
MyWidgetNew(void * parent,const char * foo)20 MyWidgetNew(void *parent, const char *foo)
21 {
22 	MyWidget *my;
23 
24 	/* Create a new instance of the MyWidget class */
25 	my = malloc(sizeof(MyWidget));
26 	AG_ObjectInit(my, &myWidgetClass);
27 
28 	/* Set some constructor arguments */
29 	my->foo = foo;
30 
31 	/* Attach the object to the parent (no-op if parent is NULL) */
32 	AG_ObjectAttach(parent, my);
33 
34 	return (my);
35 }
36 
37 /*
38  * This function requests a minimal geometry for displaying the widget.
39  * It is expected to return the width and height in pixels into r.
40  *
41  * Note: Some widgets will provide FooSizeHint() functions to allow the
42  * programmer to request an initial size in pixels or some other metric
43  * FooSizeHint() typically sets some structure variable, which are then
44  * used here.
45  */
46 static void
SizeRequest(void * p,AG_SizeReq * r)47 SizeRequest(void *p, AG_SizeReq *r)
48 {
49 	MyWidget *my = p;
50 
51 	if (my->mySurface == -1) {
52 		/*
53 		 * We can use AG_TextSize() to return the dimensions of rendered
54 		 * text, without rendering it.
55 		 */
56 		AG_TextSize("Custom widget!", &r->w, &r->h);
57 	} else {
58 		/*
59 		 * We can use the geometry of the rendered surface. The
60 		 * AGWIDGET_SURFACE() macro returns the AG_Surface given a
61 		 * Widget surface handle.
62 		 */
63 		r->w = AGWIDGET_SURFACE(my,my->mySurface)->w;
64 		r->h = AGWIDGET_SURFACE(my,my->mySurface)->h;
65 	}
66 }
67 
68 /*
69  * This function is called by the parent widget after it decided how much
70  * space to allocate to this widget. It is mostly useful to container
71  * widgets, but other widgets generally use it to check if the allocated
72  * geometry can be handled by Draw().
73  */
74 static int
SizeAllocate(void * p,const AG_SizeAlloc * a)75 SizeAllocate(void *p, const AG_SizeAlloc *a)
76 {
77 	MyWidget *my = p;
78 
79 	/* If we return -1, Draw() will not be called. */
80 	if (a->w < 5 || a->h < 5)
81 		return (-1);
82 
83 	TestMsg(my->ti, "Allocated %dx%d pixels", a->w, a->h);
84 	return (0);
85 }
86 
87 /*
88  * Draw function. Invoked from GUI rendering context to draw the widget
89  * at its current location. All primitive and surface operations operate
90  * on widget coordinates.
91  */
92 static void
Draw(void * p)93 Draw(void *p)
94 {
95 	MyWidget *my = p;
96 	AG_Color c;
97 
98 	/*
99 	 * Draw a box spanning the widget area. Use the widget's
100 	 * default color (the "color" style property).
101 	 */
102 	AG_DrawBox(my,
103 	    AG_RECT(0, 0, AGWIDGET(my)->w, AGWIDGET(my)->h), 1,
104 	    AG_WCOLOR(my,0));
105 
106 	/*
107 	 * Render some text onto a surface. The default text color
108 	 * (the "text-color" style property) will be used.
109 	 */
110 	if (my->mySurface == -1) {
111 		my->mySurface = AG_WidgetMapSurface(my,
112 		    AG_TextRender("Custom widget!"));
113 	}
114 
115 	c = AG_ColorRGB(250, 250, 0);
116 	AG_DrawLine(my, 0, 0,					my->x, my->y, c);
117 	AG_DrawLine(my, AGWIDGET(my)->w, 0,			my->x, my->y, c);
118 	AG_DrawLine(my, 0, AGWIDGET(my)->h,			my->x, my->y, c);
119 	AG_DrawLine(my, AGWIDGET(my)->w, AGWIDGET(my)->h,	my->x, my->y, c);
120 	AG_DrawCircle(my, my->x, my->y, 50, c);
121 
122 	/* Draw the mapped surface centered around the cursor. */
123 	AG_WidgetBlitSurface(my, my->mySurface,
124 	    my->x - AGWIDGET_SURFACE(my,my->mySurface)->w/2,
125 	    my->y - AGWIDGET_SURFACE(my,my->mySurface)->h/2);
126 }
127 
128 /* Mouse motion event handler */
129 static void
MouseMotion(AG_Event * event)130 MouseMotion(AG_Event *event)
131 {
132 	MyWidget *my = AG_SELF();
133 	int x = AG_INT(1);
134 	int y = AG_INT(2);
135 
136 	if (x != my->x || y != my->y) {
137 		AG_Redraw(my);
138 	}
139 	my->x = x;
140 	my->y = y;
141 }
142 
143 /* Mouse click event handler */
144 static void
MouseButtonDown(AG_Event * event)145 MouseButtonDown(AG_Event *event)
146 {
147 	MyWidget *my = AG_SELF();
148 	int button = AG_INT(1);
149 	int x = AG_INT(2);
150 	int y = AG_INT(3);
151 
152 	if (button != AG_MOUSE_LEFT) {
153 		return;
154 	}
155 	TestMsg(my->ti, "Click at %d,%d", x, y);
156 	AG_WidgetFocus(my);
157 }
158 
159 /* Mouse click event handler */
160 static void
MouseButtonUp(AG_Event * event)161 MouseButtonUp(AG_Event *event)
162 {
163 /*	MyWidget *my = AG_SELF(); */
164 /*	int button = AG_INT(1); */
165 /*	int x = AG_INT(2); */
166 /*	int y = AG_INT(3); */
167 
168 	/* ... */
169 }
170 
171 /* Keystroke event handler */
172 static void
KeyDown(AG_Event * event)173 KeyDown(AG_Event *event)
174 {
175 	MyWidget *my = AG_SELF();
176 	int keysym = AG_INT(1);
177 /*	int keymod = AG_INT(2); */
178 	Uint32 unicode = AG_INT(3);
179 
180 	TestMsg(my->ti, "Keystroke: 0x%x (Uni=%x)", keysym, unicode);
181 }
182 
183 /* Keystroke event handler */
184 static void
KeyUp(AG_Event * event)185 KeyUp(AG_Event *event)
186 {
187 /*	MyWidget *my = AG_SELF(); */
188 /*	int keysym = AG_INT(1); */
189 
190 	/* ... */
191 }
192 
193 /*
194  * Initialization routine. Note that the object system will automatically
195  * invoke the initialization routines of the parent classes first.
196  */
197 static void
Init(void * obj)198 Init(void *obj)
199 {
200 	MyWidget *my = obj;
201 
202 	/* Allow this widget to grab focus. */
203 	AGWIDGET(my)->flags |= AG_WIDGET_FOCUSABLE;
204 
205 	/* Receive mouse motion events unconditionally. */
206 	AGWIDGET(my)->flags |= AG_WIDGET_UNFOCUSED_MOTION;
207 
208 	/* The widget will be using the font engine. */
209 	AGWIDGET(my)->flags |= AG_WIDGET_USE_TEXT;
210 
211 	/* The widget will react to mouse hover events. */
212 	AGWIDGET(my)->flags |= AG_WIDGET_USE_MOUSEOVER;
213 
214 	/* Initialize instance variables. */
215 	my->foo = "";
216 	my->x = 0;
217 	my->y = 0;
218 
219 	/*
220 	 * We'll eventually need to create and map a surface, but we cannot
221 	 * do this from Init(), because it involves texture operations in
222 	 * GL mode which are thread-unsafe. We wait until Draw() to do that.
223 	 */
224 	my->mySurface = -1;
225 
226 	/*
227 	 * Map our event handlers. For a list of all meaningful events
228 	 * we can handle, see AG_Object(3), AG_Widget(3) and AG_Window(3).
229 	 *
230 	 * Here we register handlers for the common AG_Window(3) events.
231 	 */
232 	AG_SetEvent(my, "mouse-button-up", MouseButtonUp, NULL);
233 	AG_SetEvent(my, "mouse-button-down", MouseButtonDown, NULL);
234 	AG_SetEvent(my, "mouse-motion", MouseMotion, NULL);
235 	AG_SetEvent(my, "key-up", KeyUp, NULL);
236 	AG_SetEvent(my, "key-down", KeyDown, NULL);
237 }
238 
239 /*
240  * This structure describes our widget class. It inherits from AG_ObjectClass.
241  * Any of the function members may be NULL. See AG_Widget(3) for details.
242  */
243 AG_WidgetClass myWidgetClass = {
244 	{
245 		"AG_Widget:MyWidget",	/* Name of class */
246 		sizeof(MyWidget),	/* Size of structure */
247 		{ 0,0 },		/* Version for load/save */
248 		Init,			/* Initialize dataset */
249 		NULL,			/* Free dataset */
250 		NULL,			/* Destroy widget */
251 		NULL,			/* Load widget (for GUI builder) */
252 		NULL,			/* Save widget (for GUI builder) */
253 		NULL			/* Edit (for GUI builder) */
254 	},
255 	Draw,				/* Render widget */
256 	SizeRequest,			/* Default size requisition */
257 	SizeAllocate			/* Size allocation callback */
258 };
259