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