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