Vuo 2.4.2
Loading...
Searching...
No Matches
VuoInteraction.c
Go to the documentation of this file.
1
10#include <math.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include "type.h"
14// @todo
15// #include "VuoMouseUtility.h"
16
18#ifdef VUO_COMPILER
20 "title" : "UI Interaction",
21 "description" : "Stores information about a UI device's input.",
22 "keywords" : [ "gui" ],
23 "version" : "1.0.0",
24 "dependencies" : [
25 "VuoBoolean",
26 "VuoList_VuoInteraction",
27 "VuoReal",
28 "VuoText",
29 "VuoUuid",
30 "VuoPoint2d",
31 "VuoInteractionType"
32 // "VuoMouseUtility"
33 ]
34 });
35#endif
37
51{
52 VuoInteraction interaction = VuoInteraction_make();
53
54 json_object *o = NULL;
55
56 if (json_object_object_get_ex(js, "uuid", &o))
57 interaction.uuid = VuoUuid_makeFromJson(o);
58
59 if (json_object_object_get_ex(js, "position", &o))
60 interaction.position = VuoPoint2d_makeFromJson(o);
61
62 if (json_object_object_get_ex(js, "isPressed", &o))
63 interaction.isPressed = json_object_get_boolean(o);
64
65 if (json_object_object_get_ex(js, "type", &o))
66 interaction.type = VuoInteractionType_makeFromJson(o);
67
68 if( json_object_object_get_ex(js, "origin", &o))
69 interaction.origin = VuoPoint2d_makeFromJson(o);
70
71 if( json_object_object_get_ex(js, "timestamp", &o))
72 interaction.timestamp = json_object_get_double(o);
73
74 if( json_object_object_get_ex(js, "clickCount", &o))
75 interaction.clickCount = VuoInteger_makeFromJson(o);
76
77 return interaction;
78}
79
87{
88 json_object *js = json_object_new_object();
89
90 json_object_object_add(js, "uuid", VuoUuid_getJson(value.uuid));
91 json_object_object_add(js, "position", VuoPoint2d_getJson(value.position));
92 json_object_object_add(js, "isPressed", json_object_new_boolean(value.isPressed));
93 json_object_object_add(js, "type", VuoInteractionType_getJson(value.type));
94 json_object_object_add(js, "origin", VuoPoint2d_getJson(value.origin));
95 json_object_object_add(js, "timestamp", json_object_new_double(value.timestamp));
96 json_object_object_add(js, "clickCount", VuoInteger_getJson(value.clickCount));
97
98 return js;
99}
100
108{
109 char* typeStr = VuoInteractionType_getSummary(value.type);
110
111 char* sum = VuoText_format("<div>Type: %s</div><div>Position: %.2f, %.2f</div><div>Is Pressed: %s</div><div>Click Count: %lli</div>",
112 typeStr,
113 value.position.x,
114 value.position.y,
115 (value.isPressed ? "Yes" : "No"),
116 value.clickCount);
117
118 free(typeStr);
119 return sum;
120}
121
128{
129 return VuoPoint2d_areEqual(value1.position, value2.position) &&
130 VuoBoolean_areEqual(value1.isPressed, value2.isPressed) &&
131 VuoInteractionType_areEqual(value1.type, value2.type) &&
132 VuoPoint2d_areEqual(value1.origin, value2.origin) &&
133 VuoReal_areEqual(value1.timestamp, value2.timestamp);
134}
135
142{
143 // @todo
144 return (int)&a < (int)&b;
145}
146
147#define MAX_CLICK_DELTA .2
148
149#define MIN_DRAG_DISTANCE .08
150
156static bool VuoInteraction_isDrag(const VuoInteraction previous, const bool isPressed, const VuoPoint2d position)
157{
158 // if this frame isn't pressed and neither was the previous one this definitely isn't a drag
159 if(!isPressed || !previous.isPressed)
160 return false;
161
162 // If the last frame was a drag and the device is still engaged, it's still a drag
163 if(previous.type == VuoInteractionType_Drag || previous.type == VuoInteractionType_DragStart)
164 return true;
165
166 // if the device has been pressed for a long-ish time and moved slightly it could be a fine-grained drag
167 if( VuoLogGetTime() - previous.timestamp > MAX_CLICK_DELTA && fabs(VuoPoint2d_distance(previous.origin, position)) > .001 )
168 return true;
169 else
170 return fabs(VuoPoint2d_distance(position, previous.origin)) > MIN_DRAG_DISTANCE;
171}
172
179{
180 return .5;
181}
182
188bool VuoInteraction_update(const VuoPoint2d position, const VuoBoolean isPressed, VuoInteraction* interaction)
189{
190 bool changed = false;
191 VuoInteraction prev = *interaction;
192 interaction->type = VuoInteractionType_None;
193
194 bool isDrag = VuoInteraction_isDrag(prev, isPressed, position);
195
196 // type is a little hierarchy; sometimes multiple events can occur in a single interaction (move & release for example)
197 // release/click/press/drag take priority over move in these cases.
198 if(isDrag || !VuoPoint2d_areEqual(position, interaction->position))
199 {
200 changed = true;
201
202 if( isDrag )
203 interaction->type = (prev.type == VuoInteractionType_Drag || prev.type == VuoInteractionType_DragStart) ? VuoInteractionType_Drag : VuoInteractionType_DragStart;
204 else
205 interaction->type = VuoInteractionType_Move;
206
207 interaction->position = position;
208 interaction->clickCount = 0;
209 }
210
211 if( interaction->isPressed != isPressed )
212 {
213 changed = true;
214
215 if(isPressed)
216 {
217 interaction->type = VuoInteractionType_Press;
218 interaction->origin = position;
219 interaction->timestamp = VuoLogGetTime();
220
221 if(prev.clickCount < 1 || ((interaction->timestamp - prev.timestamp) < VuoMouseUtility_getDoubleClickInterval()))
222 {
223 interaction->clickCount = prev.clickCount + 1;
224 }
225 else
226 {
227 interaction->clickCount = 1;
228 }
229 }
230 else
231 {
232 // is drag?
233 // is click?
234 // is release.
235 if( prev.type == VuoInteractionType_DragStart || prev.type == VuoInteractionType_Drag )
236 {
237 interaction->clickCount = 0;
238 interaction->type = VuoInteractionType_DragFinish;
239 }
240 else if( VuoLogGetTime() - interaction->timestamp < MAX_CLICK_DELTA )
241 {
242 interaction->clickCount = prev.clickCount;
243 interaction->type = VuoInteractionType_Click;
244 }
245 else
246 {
247 interaction->clickCount = prev.clickCount;
248 interaction->type = VuoInteractionType_Release;
249 }
250 }
251
252 interaction->isPressed = isPressed;
253 }
254
255 return changed;
256}
257