1 /**************************************************************************/
2 /* */
3 /* Copyright (c) Microsoft Corporation. All rights reserved. */
4 /* */
5 /* This software is licensed under the Microsoft Software License */
6 /* Terms for Microsoft Azure RTOS. Full text of the license can be */
7 /* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
8 /* and in the root directory of this software. */
9 /* */
10 /**************************************************************************/
11
12
13 /**************************************************************************/
14 /**************************************************************************/
15 /** */
16 /** GUIX Component */
17 /** */
18 /** Vertical List (List) */
19 /** */
20 /**************************************************************************/
21
22 #define GX_SOURCE_CODE
23
24
25 /* Include necessary system files. */
26
27 #include "gx_api.h"
28 #include "gx_widget.h"
29 #include "gx_window.h"
30 #include "gx_system.h"
31 #include "gx_scrollbar.h"
32
33 /**************************************************************************/
34 /* */
35 /* FUNCTION RELEASE */
36 /* */
37 /* _gx_vertical_list_event_process PORTABLE C */
38 /* 6.1.12 */
39 /* AUTHOR */
40 /* */
41 /* Kenneth Maxwell, Microsoft Corporation */
42 /* */
43 /* DESCRIPTION */
44 /* */
45 /* This service processes an event for the vertical list. */
46 /* */
47 /* INPUT */
48 /* */
49 /* list Vertical list control block */
50 /* event_ptr Pointer to event to process */
51 /* */
52 /* OUTPUT */
53 /* */
54 /* status Completion status */
55 /* */
56 /* CALLS */
57 /* */
58 /* _gx_vertical_list_selected_set Set the list entry at the */
59 /* current list index */
60 /* _gx_widget_find Retrieve the height of the */
61 /* widget */
62 /* _gx_vertical_list_children_position Position the children for */
63 /* the vertical list */
64 /* _gx_first_client_child_get Get the first client child */
65 /* _gx_vertical_list_scroll Move up or down the scrollbar */
66 /* _gx_vertical_list_slide_back_check Check the sliding back of */
67 /* the scrollbar */
68 /* _gx_window_scrollbar_find Assign a background wallpaper */
69 /* to a GX_WINDOW object */
70 /* _gx_scrollbar_reset Calculate new scrollbar value */
71 /* _gx_system_timer_start Allocate a free timer and */
72 /* activates it */
73 /* _gx_system_top_widget_find Find top widget under pen */
74 /* _gx_system_timer_stop Stop an active GUIX timer */
75 /* _gx_window_event_process Process events for the */
76 /* specified window */
77 /* */
78 /* CALLED BY */
79 /* */
80 /* Application Code */
81 /* */
82 /* RELEASE HISTORY */
83 /* */
84 /* DATE NAME DESCRIPTION */
85 /* */
86 /* 05-19-2020 Kenneth Maxwell Initial Version 6.0 */
87 /* 09-30-2020 Kenneth Maxwell Modified comment(s), */
88 /* resulting in version 6.1 */
89 /* 07-29-2022 Kenneth Maxwell Modified comment(s), */
90 /* fixed bug in EVENT_PEN_DRAG */
91 /* handler, */
92 /* resulting in version 6.1.12 */
93 /* */
94 /**************************************************************************/
_gx_vertical_list_event_process(GX_VERTICAL_LIST * list,GX_EVENT * event_ptr)95 UINT _gx_vertical_list_event_process(GX_VERTICAL_LIST *list, GX_EVENT *event_ptr)
96 {
97 GX_WIDGET *widget = (GX_WIDGET *)list;
98 GX_SCROLLBAR *pScroll;
99 INT snap_dist;
100 UINT timer_id;
101 UINT status = GX_SUCCESS;
102 GX_WIDGET *child;
103 INT list_height;
104 INT widget_height;
105 INT new_pen_index;
106 GX_WIDGET **stackptr;
107 GX_WIDGET **stacktop;
108 GX_EVENT input_release_event;
109
110 switch (event_ptr -> gx_event_type)
111 {
112 case GX_EVENT_SHOW:
113
114 /* show the children before attempting to position them, because child
115 widgets often do not know their size until shown
116 */
117
118 status = _gx_window_event_process((GX_WINDOW *)list, event_ptr);
119
120 /* now position the child widgets */
121 if (!list -> gx_vertical_list_child_count)
122 {
123 _gx_vertical_list_children_position(list);
124 }
125
126 /* and now re-calculate scrolling parameters */
127 _gx_window_scrollbar_find((GX_WINDOW *)list, GX_TYPE_VERTICAL_SCROLL, &pScroll);
128
129 if (pScroll)
130 {
131 _gx_scrollbar_reset(pScroll, GX_NULL);
132 }
133 break;
134
135 case GX_EVENT_FOCUS_NEXT:
136 if (list -> gx_vertical_list_selected < list -> gx_vertical_list_total_rows - 1)
137 {
138 _gx_vertical_list_selected_set(list, list -> gx_vertical_list_selected + 1);
139 }
140 break;
141
142 case GX_EVENT_FOCUS_PREVIOUS:
143 if (list -> gx_vertical_list_selected > 0)
144 {
145 _gx_vertical_list_selected_set(list, list -> gx_vertical_list_selected - 1);
146 }
147 break;
148
149 case GX_EVENT_VERTICAL_SCROLL:
150 _gx_vertical_list_scroll(list, event_ptr -> gx_event_payload.gx_event_intdata[1] - event_ptr -> gx_event_payload.gx_event_intdata[0]);
151 return 0;
152
153 case GX_EVENT_PEN_DOWN:
154 _gx_system_input_capture(widget);
155 list -> gx_window_move_start = event_ptr -> gx_event_payload.gx_event_pointdata;
156
157 /* determine which child widget has been selected for future list select event */
158 child = _gx_system_top_widget_find((GX_WIDGET *)list, event_ptr -> gx_event_payload.gx_event_pointdata, GX_STATUS_SELECTABLE);
159
160 while (child && child -> gx_widget_parent != (GX_WIDGET *)list)
161 {
162 child = child -> gx_widget_parent;
163 }
164
165 if (child)
166 {
167 list -> gx_vertical_list_pen_index = list -> gx_vertical_list_top_index + _gx_widget_client_index_get(widget, child);
168 if (list -> gx_vertical_list_pen_index >= list -> gx_vertical_list_total_rows)
169 {
170 list -> gx_vertical_list_pen_index -= list -> gx_vertical_list_total_rows;
171 }
172 }
173 break;
174
175 case GX_EVENT_PEN_UP:
176 if (list -> gx_widget_status & GX_STATUS_OWNS_INPUT)
177 {
178 _gx_system_input_release(widget);
179
180 list_height = list -> gx_vertical_list_child_count * list -> gx_vertical_list_child_height;
181 widget_height = list -> gx_window_client.gx_rectangle_bottom - list -> gx_window_client.gx_rectangle_top + 1;
182
183 if (list_height > widget_height)
184 {
185 _gx_vertical_list_slide_back_check(list);
186 }
187 if (list -> gx_vertical_list_pen_index >= 0 && list -> gx_vertical_list_snap_back_distance == 0)
188 {
189 /* test to see if pen-up is over same child widget as pen-down */
190 child = _gx_system_top_widget_find((GX_WIDGET *)list, event_ptr -> gx_event_payload.gx_event_pointdata, GX_STATUS_SELECTABLE);
191 while (child && child -> gx_widget_parent != (GX_WIDGET *)list)
192 {
193 child = child -> gx_widget_parent;
194 }
195
196 if (child)
197 {
198 new_pen_index = list -> gx_vertical_list_top_index + _gx_widget_client_index_get(widget, child);
199 if (new_pen_index >= list -> gx_vertical_list_total_rows)
200 {
201 new_pen_index -= list -> gx_vertical_list_total_rows;
202 }
203 if (new_pen_index == list -> gx_vertical_list_pen_index)
204 {
205 _gx_vertical_list_selected_set(list, list -> gx_vertical_list_pen_index);
206 }
207 }
208 }
209 }
210 else
211 {
212 _gx_widget_event_to_parent((GX_WIDGET *)list, event_ptr);
213 }
214 break;
215
216 case GX_EVENT_PEN_DRAG:
217 if ((widget -> gx_widget_status & GX_STATUS_OWNS_INPUT) &&
218 (event_ptr -> gx_event_payload.gx_event_pointdata.gx_point_y - list -> gx_window_move_start.gx_point_y) != 0)
219 {
220 list_height = list -> gx_vertical_list_child_count * list -> gx_vertical_list_child_height;
221 widget_height = list -> gx_window_client.gx_rectangle_bottom - list -> gx_window_client.gx_rectangle_top + 1;
222
223 if (list_height > widget_height)
224 {
225 /* Start sliding, remove other widgets from input capture stack. */
226 stackptr = _gx_system_input_capture_stack;
227 stacktop = _gx_system_input_capture_stack + _gx_system_capture_count;
228
229 memset(&input_release_event, 0, sizeof(GX_EVENT));
230 input_release_event.gx_event_type = GX_EVENT_INPUT_RELEASE;
231
232 while (stackptr < stacktop)
233 {
234 if (*stackptr != GX_NULL && *stackptr != widget)
235 {
236 input_release_event.gx_event_target = *stackptr;
237 _gx_system_event_send(&input_release_event);
238 }
239 stackptr++;
240 }
241
242 _gx_vertical_list_scroll(list,
243 event_ptr -> gx_event_payload.gx_event_pointdata.gx_point_y -
244 list -> gx_window_move_start.gx_point_y);
245 _gx_window_scrollbar_find((GX_WINDOW *)list, GX_TYPE_VERTICAL_SCROLL, &pScroll);
246
247 if (pScroll)
248 {
249 _gx_scrollbar_reset(pScroll, GX_NULL);
250 }
251 list -> gx_window_move_start = event_ptr -> gx_event_payload.gx_event_pointdata;
252 list -> gx_vertical_list_pen_index = -1;
253 }
254 }
255 else
256 {
257 _gx_widget_event_to_parent((GX_WIDGET *)list, event_ptr);
258 }
259 break;
260
261 case GX_EVENT_VERTICAL_FLICK:
262 list_height = list -> gx_vertical_list_child_count * list -> gx_vertical_list_child_height;
263 widget_height = list -> gx_window_client.gx_rectangle_bottom - list -> gx_window_client.gx_rectangle_top + 1;
264
265 if (list_height > widget_height)
266 {
267 list -> gx_vertical_list_snap_back_distance = (GX_VALUE)(GX_FIXED_VAL_TO_INT(event_ptr -> gx_event_payload.gx_event_intdata[0]) * 8);
268 _gx_system_timer_start((GX_WIDGET *)list, GX_FLICK_TIMER, 1, 1);
269 }
270 list -> gx_vertical_list_pen_index = -1;
271 break;
272
273 case GX_EVENT_TIMER:
274 timer_id = event_ptr -> gx_event_payload.gx_event_timer_id;
275
276 if (timer_id == GX_FLICK_TIMER || timer_id == GX_SNAP_TIMER)
277 {
278 if (GX_ABS(list -> gx_vertical_list_snap_back_distance) < GX_ABS(list -> gx_vertical_list_child_height) / 3)
279 {
280 _gx_system_timer_stop(widget, event_ptr -> gx_event_payload.gx_event_timer_id);
281 _gx_vertical_list_scroll(list, list -> gx_vertical_list_snap_back_distance);
282
283 if (event_ptr -> gx_event_payload.gx_event_timer_id == GX_FLICK_TIMER)
284 {
285 _gx_vertical_list_slide_back_check(list);
286 }
287 }
288 else
289 {
290 snap_dist = (list -> gx_vertical_list_snap_back_distance) / 5;
291 list -> gx_vertical_list_snap_back_distance = (GX_VALUE)(list -> gx_vertical_list_snap_back_distance - snap_dist);
292 _gx_vertical_list_scroll(list, snap_dist);
293 }
294 _gx_window_scrollbar_find((GX_WINDOW *)list, GX_TYPE_VERTICAL_SCROLL, &pScroll);
295
296 if (pScroll)
297 {
298 _gx_scrollbar_reset(pScroll, GX_NULL);
299 }
300 }
301 else
302 {
303 status = _gx_window_event_process((GX_WINDOW *)list, event_ptr);
304 }
305 break;
306
307 default:
308 status = _gx_window_event_process((GX_WINDOW *)list, event_ptr);
309 break;
310 }
311
312 return status;
313 }
314
315