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