1 /***************************************************************************
2  * Copyright (c) 2024 Microsoft Corporation
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the MIT License which is available at
6  * https://opensource.org/licenses/MIT.
7  *
8  * SPDX-License-Identifier: MIT
9  **************************************************************************/
10 
11 
12 /**************************************************************************/
13 /**************************************************************************/
14 /**                                                                       */
15 /** GUIX Component                                                        */
16 /**                                                                       */
17 /**   Scrollbar Management (Scrollbar)                                    */
18 /**                                                                       */
19 /**************************************************************************/
20 
21 #define GX_SOURCE_CODE
22 
23 
24 /* Include necessary system files.  */
25 
26 #include "gx_api.h"
27 #include "gx_system.h"
28 #include "gx_widget.h"
29 #include "gx_window.h"
30 #include "gx_utility.h"
31 #include "gx_scrollbar.h"
32 
33 
34 /**************************************************************************/
35 /*                                                                        */
36 /*  FUNCTION                                               RELEASE        */
37 /*                                                                        */
38 /*    _gx_scrollbar_event_process                         PORTABLE C      */
39 /*                                                           6.1          */
40 /*  AUTHOR                                                                */
41 /*                                                                        */
42 /*    Kenneth Maxwell, Microsoft Corporation                              */
43 /*                                                                        */
44 /*  DESCRIPTION                                                           */
45 /*                                                                        */
46 /*    This function processes events for the specified window.            */
47 /*                                                                        */
48 /*  INPUT                                                                 */
49 /*                                                                        */
50 /*    scrollbar                             Scrollbar control block       */
51 /*    event_ptr                             Incoming event to process     */
52 /*                                                                        */
53 /*  OUTPUT                                                                */
54 /*                                                                        */
55 /*    status                                Completion status             */
56 /*                                                                        */
57 /*  CALLS                                                                 */
58 /*                                                                        */
59 /*    _gx_utility_rectangle_center_find     Locate the center of a        */
60 /*                                             rectangle                  */
61 /*    [gx_widget_event_process_function]    Parent widget event process   */
62 /*                                            routine                     */
63 /*    _gx_scrollbar_thumb_position_calculate                              */
64 /*                                          Calculate the position of the */
65 /*                                            thumb                       */
66 /*    _gx_scrollbar_limit_check             Check for scroll limit        */
67 /*    _gx_system_dirty_mark                 Mark the widget dirty         */
68 /*    _gx_scrollbar_value_calcualte         Calculate the value of the    */
69 /*                                            scrollbar                   */
70 /*    _gx_scrollbar_reset                   Reset the scrollbar           */
71 /*    _gx_widget_border_width_get           Retrieve widget border width  */
72 /*    _gx_widget_child_clipping_update      Update widget child clipping  */
73 /*                                            area                        */
74 /*    _gx_widget_type_find                  Find the type of the widget   */
75 /*    _gx_scrollbar_size_update             Update the size of scrollbar  */
76 /*    _gx_widget_event_process              Invoke the widget event       */
77 /*                                            process routine             */
78 /*                                                                        */
79 /*  CALLED BY                                                             */
80 /*                                                                        */
81 /*    Application Code                                                    */
82 /*    GUIX Internal Code                                                  */
83 /*                                                                        */
84 /*  RELEASE HISTORY                                                       */
85 /*                                                                        */
86 /*    DATE              NAME                      DESCRIPTION             */
87 /*                                                                        */
88 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
89 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
90 /*                                            resulting in version 6.1    */
91 /*                                                                        */
92 /**************************************************************************/
_gx_scrollbar_event_process(GX_SCROLLBAR * scrollbar,GX_EVENT * event_ptr)93 UINT  _gx_scrollbar_event_process(GX_SCROLLBAR *scrollbar, GX_EVENT *event_ptr)
94 {
95 
96 UINT             status;
97 GX_EVENT         newevent;
98 GX_WINDOW       *win;
99 GX_SCROLLBAR    *scroll_ptr;
100 GX_SCROLL_THUMB *thumb;
101 GX_POINT         pen_point;
102 GX_VALUE         parent_border_width;
103 INT              temp_value;
104 GX_VALUE         edge;
105 GX_RECTANGLE     rect;
106 
107     status = GX_SUCCESS;
108 
109     /* Process relative to the type of event.  */
110     switch (event_ptr -> gx_event_type)
111     {
112     case GX_EVENT_PEN_DOWN:
113         rect = scrollbar->gx_widget_size;
114 
115         if (scrollbar->gx_scrollbar_upleft.gx_widget_size.gx_rectangle_left !=
116             scrollbar->gx_scrollbar_upleft.gx_widget_size.gx_rectangle_right)
117         {
118             if (scrollbar->gx_widget_style & GX_SCROLLBAR_VERTICAL)
119             {
120                 rect.gx_rectangle_top = (GX_VALUE)(scrollbar->gx_scrollbar_upleft.gx_widget_size.gx_rectangle_bottom + 1);
121                 rect.gx_rectangle_bottom = (GX_VALUE)(scrollbar->gx_scrollbar_downright.gx_widget_size.gx_rectangle_top - 1);
122             }
123             else
124             {
125                 rect.gx_rectangle_left = (GX_VALUE)(scrollbar->gx_scrollbar_upleft.gx_widget_size.gx_rectangle_right + 1);
126                 rect.gx_rectangle_right = (GX_VALUE)(scrollbar->gx_scrollbar_downright.gx_widget_size.gx_rectangle_left - 1);
127             }
128         }
129 
130         /* Calculate valid rectangle here to avoid situation that click on scrollbar end button, since we delivery PEN_DOWN event
131            to parent, if we click on scrollbar end buttons, the PEN_DOWN event will also be sent to it's parent, which handles scrollbar
132            thumb in another way.  */
133 
134         /* save the position */
135         pen_point = event_ptr -> gx_event_payload.gx_event_pointdata;
136 
137         if (_gx_utility_rectangle_point_detect(&rect, pen_point))
138         {
139             thumb = &scrollbar -> gx_scrollbar_thumb;
140             /* find center of thumb button */
141             _gx_utility_rectangle_center_find(&thumb -> gx_widget_size,
142                                               &event_ptr -> gx_event_payload.gx_event_pointdata);
143 
144             /* pass the even to my scroll thumb */
145             thumb -> gx_widget_event_process_function((GX_WIDGET *)thumb, event_ptr);
146 
147             /* now pass original position in drag message */
148             newevent.gx_event_type = GX_EVENT_PEN_DRAG;
149             newevent.gx_event_payload.gx_event_pointdata = pen_point;
150             thumb -> gx_widget_event_process_function((GX_WIDGET *)thumb, &newevent);
151         }
152         /* Return successful status.  */
153         return(GX_SUCCESS);
154 
155     case GX_SIGNAL(GX_ID_SCROLL_UP_LEFT, GX_EVENT_CLICKED):
156     case GX_SIGNAL(GX_ID_SCROLL_DOWN_RIGHT, GX_EVENT_CLICKED):
157         temp_value = scrollbar -> gx_scrollbar_info.gx_scroll_value;
158 
159         if (event_ptr -> gx_event_sender == GX_ID_SCROLL_UP_LEFT)
160         {
161             temp_value = temp_value - scrollbar -> gx_scrollbar_info.gx_scroll_increment;
162         }
163         else
164         {
165             temp_value = scrollbar -> gx_scrollbar_info.gx_scroll_value + scrollbar -> gx_scrollbar_info.gx_scroll_increment;
166         }
167 
168         _gx_scrollbar_value_set(scrollbar, temp_value);
169         break;
170 
171     case GX_EVENT_VERTICAL_SCROLL:
172     case GX_EVENT_HORIZONTAL_SCROLL:
173         /* this event arrives from my thumb button. Calculate new value
174            and send event to parent window
175          */
176         _gx_scrollbar_value_calculate(scrollbar, event_ptr -> gx_event_payload.gx_event_intdata[0],
177                                       event_ptr -> gx_event_payload.gx_event_intdata[1]);
178         break;
179 
180     case GX_EVENT_PEN_UP:
181         break;
182 
183     case GX_EVENT_PARENT_SIZED:
184         _gx_scrollbar_reset(scrollbar, GX_NULL);
185         break;
186 
187     case GX_EVENT_HIDE:
188         status = _gx_widget_event_process((GX_WIDGET *)scrollbar, event_ptr);
189 
190         /* adjust my parent window client size */
191         win = (GX_WINDOW *)scrollbar -> gx_widget_parent;
192         if (win)
193         {
194             _gx_widget_border_width_get((GX_WIDGET *)win, &parent_border_width);
195 
196             if (scrollbar -> gx_widget_type == GX_TYPE_VERTICAL_SCROLL)
197             {
198                 win -> gx_window_client.gx_rectangle_right = (GX_VALUE)(win -> gx_widget_size.gx_rectangle_right - parent_border_width);
199                 _gx_widget_child_clipping_update(scrollbar -> gx_widget_parent);
200                 _gx_widget_type_find(scrollbar -> gx_widget_parent,  GX_TYPE_HORIZONTAL_SCROLL, (GX_WIDGET **)&scroll_ptr);
201 
202                 if (scroll_ptr)
203                 {
204                     if (scroll_ptr -> gx_widget_status & GX_STATUS_VISIBLE)
205                     {
206                         _gx_scrollbar_size_update(scroll_ptr);
207                     }
208                 }
209             }
210             else
211             {
212                 win -> gx_window_client.gx_rectangle_bottom = (GX_VALUE)(win -> gx_widget_size.gx_rectangle_bottom - parent_border_width);
213                 _gx_widget_child_clipping_update(scrollbar -> gx_widget_parent);
214                 _gx_widget_type_find(scrollbar -> gx_widget_parent, GX_TYPE_VERTICAL_SCROLL, (GX_WIDGET **)&scroll_ptr);
215 
216                 if (scroll_ptr)
217                 {
218                     if (scroll_ptr -> gx_widget_status & GX_STATUS_VISIBLE)
219                     {
220                         _gx_scrollbar_size_update(scroll_ptr);
221                     }
222                 }
223             }
224 
225             /* notify window of client modification */
226 
227             if (win -> gx_widget_status & GX_STATUS_VISIBLE)
228             {
229                 newevent.gx_event_type = GX_EVENT_CLIENT_UPDATED;
230                 newevent.gx_event_target = (GX_WIDGET *)win;
231                 _gx_system_event_fold(&newevent);
232             }
233         }
234         break;
235 
236     case GX_EVENT_SHOW:
237         /* do the default handling */
238          status = _gx_widget_event_process((GX_WIDGET *)scrollbar, event_ptr);
239 
240         /* test to see if I should be marked transparent */
241         if (scrollbar -> gx_scrollbar_appearance.gx_scroll_fill_pixelmap)
242         {
243             if (_gx_widget_transparent_pixelmap_detect((GX_WIDGET *)scrollbar, scrollbar -> gx_scrollbar_appearance.gx_scroll_fill_pixelmap))
244             {
245                 scrollbar -> gx_widget_status |= GX_STATUS_TRANSPARENT;
246             }
247         }
248 
249         /* adjust my parent window client size */
250         win = (GX_WINDOW *) (scrollbar -> gx_widget_parent);
251 
252         if (win)
253         {
254             _gx_widget_border_width_get((GX_WIDGET *)win, &parent_border_width);
255 
256             if (scrollbar -> gx_widget_type == GX_TYPE_VERTICAL_SCROLL)
257             {
258                 edge = (GX_VALUE)(win -> gx_widget_size.gx_rectangle_right - parent_border_width);
259 
260                 if (!(scrollbar -> gx_widget_style & GX_STYLE_TRANSPARENT))
261                 {
262                     edge = (GX_VALUE)(win -> gx_window_client.gx_rectangle_right - scrollbar -> gx_scrollbar_appearance.gx_scroll_width);
263                 }
264                 if (win -> gx_window_client.gx_rectangle_right != edge)
265                 {
266                     win -> gx_window_client.gx_rectangle_right = edge;
267                     _gx_widget_child_clipping_update((GX_WIDGET *) win);
268                 }
269 
270                 /* if we have a horizontal scrollbar and it is already visible, it needs to be adjusted */
271                 _gx_widget_type_find((GX_WIDGET *)win, GX_TYPE_HORIZONTAL_SCROLL, (GX_WIDGET **)&scroll_ptr);
272 
273                 if (scroll_ptr)
274                 {
275                     if (scroll_ptr -> gx_widget_status & GX_STATUS_VISIBLE)
276                     {
277                         _gx_scrollbar_reset(scroll_ptr, GX_NULL);
278                     }
279                 }
280             }
281             else
282             {
283                 edge = (GX_VALUE)(win -> gx_widget_size.gx_rectangle_bottom - parent_border_width);
284 
285                 if (!(scrollbar -> gx_widget_style & GX_STYLE_TRANSPARENT))
286                 {
287                     edge = (GX_VALUE)(win -> gx_window_client.gx_rectangle_bottom - scrollbar -> gx_scrollbar_appearance.gx_scroll_width);
288                 }
289                 if (win -> gx_window_client.gx_rectangle_bottom != edge)
290                 {
291                     win -> gx_window_client.gx_rectangle_bottom = edge;
292                     _gx_widget_child_clipping_update((GX_WIDGET *) win);
293                 }
294 
295                 /* if we have a vertical scrollbar and it is already visible, it needs to be adjusted */
296                 _gx_widget_type_find(scrollbar -> gx_widget_parent, GX_TYPE_VERTICAL_SCROLL, (GX_WIDGET **)&scroll_ptr);
297 
298                 if (scroll_ptr)
299                 {
300                     if (scroll_ptr -> gx_widget_status & GX_STATUS_VISIBLE)
301                     {
302                         _gx_scrollbar_reset(scroll_ptr, GX_NULL);
303                     }
304                 }
305             }
306 
307             /* notify window of client modification */
308 
309             newevent.gx_event_type = GX_EVENT_CLIENT_UPDATED;
310             newevent.gx_event_target = (GX_WIDGET *) win;
311             _gx_system_event_fold(&newevent);
312         }
313         _gx_scrollbar_reset(scrollbar, GX_NULL);
314         break;
315 
316     default:
317 
318         /* Call the widget default processing.  */
319         status =  _gx_widget_event_process((GX_WIDGET *)scrollbar, event_ptr);
320     }
321     /* Return widget event processing status.  */
322     return(status);
323 }
324 
325