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