1 /*	Public domain	*/
2 
3 #ifndef _AGAR_VG_VIEW_H_
4 #define _AGAR_VG_VIEW_H_
5 
6 #include <agar/gui/widget.h>
7 #include <agar/gui/button.h>
8 #include <agar/gui/menu.h>
9 #include <agar/gui/text_cache.h>
10 #include <agar/vg/vg.h>
11 #include <agar/vg/vg_tool.h>
12 
13 #define VG_GRIDS_MAX 4
14 
15 #include <agar/vg/begin.h>
16 
17 enum vg_grid_type {
18 	VG_GRID_POINTS,
19 	VG_GRID_LINES
20 };
21 
22 typedef struct vg_grid {
23 	enum vg_grid_type type;
24 	Uint flags;
25 #define VG_GRID_HIDE      0x01	/* Hide grid */
26 #define VG_GRID_UNDERSIZE 0x02	/* Grid too small to display */
27 
28 	int ival;		/* Nominal pixel interval */
29 	int ivalView;		/* Effective interval (dependent on wPixel) */
30 	VG_Color color;		/* Display color */
31 } VG_Grid;
32 
33 typedef struct vg_view {
34 	struct ag_widget wid;
35 
36 	Uint flags;
37 #define VG_VIEW_HFILL		0x01
38 #define VG_VIEW_VFILL		0x02
39 #define VG_VIEW_GRID		0x04		/* Display grid */
40 #define VG_VIEW_EXTENTS		0x08		/* Display extents (DEBUG) */
41 #define VG_VIEW_DISABLE_BG	0x10		/* Enable VG background */
42 #define VG_VIEW_CONSTRUCTION	0x20		/* Construction geometry */
43 #define VG_VIEW_EXPAND	(VG_VIEW_HFILL|VG_VIEW_VFILL)
44 
45 	VG *vg;					/* Vector graphics object */
46 
47 	float x, y;				/* Display offset */
48 	int scaleIdx;				/* Scaling factor index */
49 	float scale;				/* Display scaling factor */
50 	float scaleMin;				/* Minimum scaling factor */
51 	float scaleMax;				/* Maximum scaling factor */
52 	float wPixel;				/* Relative pixel size */
53 
54 	enum vg_snap_mode  snap_mode;		/* Snapping constraint */
55 	enum vg_ortho_mode ortho_mode;		/* Orthogonal constraint */
56 	VG_Grid grid[VG_GRIDS_MAX];		/* Grid settings */
57 	Uint nGrids;
58 
59 	AG_Event *draw_ev;			/* Draw callback */
60 	AG_Event *scale_ev;			/* Scaling/movement event */
61 	AG_Event *keydown_ev, *keyup_ev;	/* Keyboard events */
62 	AG_Event *btndown_ev, *btnup_ev;	/* Mouse button events */
63 	AG_Event *motion_ev;			/* Mouse motion event */
64 
65 	struct {
66 		float x, y;			/* Saved coords */
67 		int panning;			/* Panning mode */
68 	} mouse;
69 
70 	VG_Tool *curtool;			/* Selected tool */
71 	VG_Tool *deftool;			/* Default tool if any */
72 	AG_TAILQ_HEAD_(vg_tool) tools;		/* Map edition tools */
73 
74 	char status[128];			/* Status text buffer */
75 	AG_TextCache *tCache;			/* Text cache for VG_Text */
76 	AG_Widget **editAreas;			/* User-specified container */
77 	Uint nEditAreas;
78 	int pointSelRadius;			/* Point selection threshold */
79 	AG_Rect r;				/* View area */
80 } VG_View;
81 
82 #define VGVIEW(p) ((VG_View *)(p))
83 
84 #define VG_SKIP_CONSTRAINTS(vv) (AG_GetModState(vv) & AG_KEYMOD_SHIFT)
85 #define VG_SELECT_MULTI(vv)     (AG_GetModState(vv) & AG_KEYMOD_CTRL)
86 
87 __BEGIN_DECLS
88 extern AG_WidgetClass vgViewClass;
89 
90 VG_View	*VG_ViewNew(void *, VG *, Uint);
91 void     VG_ViewSetVG(struct vg_view *, VG *);
92 void     VG_ViewSetScale(struct vg_view *, float);
93 void     VG_ViewSetScalePreset(struct vg_view *, int);
94 void     VG_ViewSetScaleMin(struct vg_view *, float);
95 void     VG_ViewSetScaleMax(struct vg_view *, float);
96 void     VG_ViewSetSnapMode(struct vg_view *, enum vg_snap_mode);
97 void     VG_ViewSetOrthoMode(struct vg_view *, enum vg_ortho_mode);
98 void     VG_ViewSetGrid(struct vg_view *, int, enum vg_grid_type, int,
99                         VG_Color);
100 
101 void     VG_ViewDrawFn(VG_View *, AG_EventFn, const char *, ...);
102 void     VG_ViewScaleFn(VG_View *, AG_EventFn, const char *, ...);
103 void     VG_ViewKeydownFn(VG_View *, AG_EventFn, const char *, ...);
104 void     VG_ViewKeyupFn(VG_View *, AG_EventFn, const char *, ...);
105 void     VG_ViewButtondownFn(VG_View *, AG_EventFn, const char *, ...);
106 void     VG_ViewButtonupFn(VG_View *, AG_EventFn, const char *, ...);
107 void     VG_ViewMotionFn(VG_View *, AG_EventFn, const char *, ...);
108 
109 void     VG_ViewSelectTool(VG_View *, void *, void *);
110 void     VG_ViewSelectToolEv(AG_Event *);
111 VG_Tool *VG_ViewFindTool(VG_View *, const char *);
112 VG_Tool *VG_ViewFindToolByOps(VG_View *, const VG_ToolOps *);
113 VG_Tool	*VG_ViewRegTool(VG_View *, const VG_ToolOps *, void *);
114 void     VG_ViewSetDefaultTool(VG_View *, VG_Tool *);
115 void     VG_StatusS(VG_View *, const char *);
116 void     VG_Status(VG_View *, const char *, ...)
117 	    FORMAT_ATTRIBUTE(printf, 2, 3);
118 Uint     VG_AddEditArea(VG_View *, void *);
119 void     VG_ClearEditAreas(VG_View *);
120 void     VG_EditNode(VG_View *, Uint, VG_Node *);
121 void     VG_DrawSurface(VG_View *, int, int, float, int);
122 
123 /*
124  * Apply snapping constraints to given coordinates.
125  * VG_View must be locked.
126  */
127 static __inline__ void
VG_ApplyConstraints(VG_View * vv,VG_Vector * pos)128 VG_ApplyConstraints(VG_View *vv, VG_Vector *pos)
129 {
130 	VG_Grid *grid;
131 	float r, ival2;
132 
133 	switch (vv->snap_mode) {
134 	case VG_GRID:
135 		grid = &vv->grid[0];
136 		ival2 = (float)(grid->ival>>1);
137 
138 		r = VG_Mod(pos->x, grid->ival);
139 		pos->x -= r;
140 		if (r > ival2) { pos->x += grid->ival; }
141 		else if (r < -ival2) { pos->x -= grid->ival; }
142 
143 		r = VG_Mod(pos->y, grid->ival);
144 		pos->y -= r;
145 		if (r > ival2) { pos->y += grid->ival; }
146 		else if (r < -ival2) { pos->y -= grid->ival; }
147 		break;
148 	default:
149 		break;
150 	}
151 }
152 
153 /*
154  * Translate integer View coordinates to VG coordinates.
155  * VG_View must be locked.
156  */
157 static __inline__ void
VG_GetVGCoords(VG_View * vv,int x,int y,VG_Vector * v)158 VG_GetVGCoords(VG_View *vv, int x, int y, VG_Vector *v)
159 {
160 	v->x = ((float)x - vv->x)/vv->scale;
161 	v->y = ((float)y - vv->y)/vv->scale;
162 }
163 
164 /*
165  * Translate floating-point View coordinates to VG coordinates.
166  * VG_View must be locked.
167  */
168 static __inline__ void
VG_GetVGCoordsFlt(VG_View * vv,VG_Vector pos,VG_Vector * v)169 VG_GetVGCoordsFlt(VG_View *vv, VG_Vector pos, VG_Vector *v)
170 {
171 	v->x = (pos.x - vv->x)/vv->scale;
172 	v->y = (pos.y - vv->y)/vv->scale;
173 }
174 
175 /*
176  * Translate VG coordinates to integer view coordinates.
177  * VG_View must be locked.
178  */
179 static __inline__ void
VG_GetViewCoords(VG_View * vv,VG_Vector v,int * x,int * y)180 VG_GetViewCoords(VG_View *vv, VG_Vector v, int *x, int *y)
181 {
182 	*x = (int)(v.x*vv->scale + vv->x);
183 	*y = (int)(v.y*vv->scale + vv->y);
184 }
185 
186 /*
187  * Translate VG coordinates to floating-point view coordinates.
188  * VG_View must be locked.
189  */
190 static __inline__ void
VG_GetViewCoordsFlt(VG_View * vv,VG_Vector v,float * x,float * y)191 VG_GetViewCoordsFlt(VG_View *vv, VG_Vector v, float *x, float *y)
192 {
193 	*x = v.x*vv->scale + vv->x;
194 	*y = v.y*vv->scale + vv->y;
195 }
196 
197 /* Return the Point nearest to vPos. */
198 static __inline__ void *
VG_NearestPoint(VG_View * vv,VG_Vector vPos,void * ignore)199 VG_NearestPoint(VG_View *vv, VG_Vector vPos, void *ignore)
200 {
201 	float prox, proxNearest = AG_FLT_MAX;
202 	VG_Node *vn, *vnNearest = NULL;
203 	VG_Vector v;
204 
205 	AG_TAILQ_FOREACH(vn, &vv->vg->nodes, list) {
206 		if (vn->ops->pointProximity == NULL ||
207 		    vn == ignore ||
208 		    !VG_NodeIsClass(vn, "Point")) {
209 			continue;
210 		}
211 		v = vPos;
212 		prox = vn->ops->pointProximity(vn, vv, &v);
213 		if (prox < vv->grid[0].ival) {
214 			if (prox < proxNearest) {
215 				proxNearest = prox;
216 				vnNearest = vn;
217 			}
218 		}
219 	}
220 	return (vnNearest);
221 }
222 
223 /* Return the entity nearest to vPos. */
224 static __inline__ void *
VG_Nearest(VG_View * vv,VG_Vector vPos)225 VG_Nearest(VG_View *vv, VG_Vector vPos)
226 {
227 	VG *vg = vv->vg;
228 	float prox, proxNearest;
229 	VG_Node *vn, *vnNearest;
230 	VG_Vector v;
231 
232 	/* Prioritize points at a fixed distance. */
233 	proxNearest = AG_FLT_MAX;
234 	vnNearest = NULL;
235 	AG_TAILQ_FOREACH(vn, &vg->nodes, list) {
236 		if (!VG_NodeIsClass(vn, "Point")) {
237 			continue;
238 		}
239 		v = vPos;
240 		prox = vn->ops->pointProximity(vn, vv, &v);
241 		if (prox <= vv->pointSelRadius) {
242 			if (prox < proxNearest) {
243 				proxNearest = prox;
244 				vnNearest = vn;
245 			}
246 		}
247 	}
248 	if (vnNearest != NULL)
249 		return (vnNearest);
250 
251 	/* Fallback to a general query. */
252 	proxNearest = AG_FLT_MAX;
253 	vnNearest = NULL;
254 	AG_TAILQ_FOREACH(vn, &vg->nodes, list) {
255 		if (vn->ops->pointProximity == NULL) {
256 			continue;
257 		}
258 		v = vPos;
259 		prox = vn->ops->pointProximity(vn, vv, &v);
260 		if (prox < proxNearest) {
261 			proxNearest = prox;
262 			vnNearest = vn;
263 		}
264 	}
265 	return (vnNearest);
266 }
267 
268 /* Highlight and return the Point nearest to vPos. */
269 static __inline__ void *
VG_HighlightNearestPoint(VG_View * vv,VG_Vector vPos,void * ignore)270 VG_HighlightNearestPoint(VG_View *vv, VG_Vector vPos, void *ignore)
271 {
272 	VG *vg = vv->vg;
273 	float prox, proxNearest = AG_FLT_MAX;
274 	VG_Node *vn, *vnNearest = NULL;
275 	VG_Vector v;
276 
277 	AG_TAILQ_FOREACH(vn, &vg->nodes, list) {
278 		vn->flags &= ~(VG_NODE_MOUSEOVER);
279 		if (vn->ops->pointProximity == NULL ||
280 		    vn == ignore ||
281 		    !VG_NodeIsClass(vn, "Point")) {
282 			continue;
283 		}
284 		v = vPos;
285 		prox = vn->ops->pointProximity(vn, vv, &v);
286 		if (prox < vv->grid[0].ival) {
287 			if (prox < proxNearest) {
288 				proxNearest = prox;
289 				vnNearest = vn;
290 			}
291 		}
292 	}
293 	return (vnNearest);
294 }
295 __END_DECLS
296 
297 #include <agar/vg/close.h>
298 #endif /* _AGAR_VG_VIEW_H_ */
299