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 /* Include necessary system files.  */
24 
25 #include "gx_api.h"
26 #include "gx_system.h"
27 #include "gx_display.h"
28 #include "gx_context.h"
29 #include "gx_widget.h"
30 #include "gx_utility.h"
31 #include "gx_scrollbar.h"
32 
33 /**************************************************************************/
34 /*                                                                        */
35 /*  FUNCTION                                               RELEASE        */
36 /*                                                                        */
37 /*    _gx_scrollbar_thumb_position_calculate              PORTABLE C      */
38 /*                                                           6.1          */
39 /*  AUTHOR                                                                */
40 /*                                                                        */
41 /*    Kenneth Maxwell, Microsoft Corporation                              */
42 /*                                                                        */
43 /*  DESCRIPTION                                                           */
44 /*                                                                        */
45 /*    Calculate and return the position of a GX_SCROLLBAR thumb button    */
46 /*    based scrollbar dimensions, current value, and visible range.       */
47 /*                                                                        */
48 /*                                                                        */
49 /*  INPUT                                                                 */
50 /*                                                                        */
51 /*    scroll                                Widget control block          */
52 /*                                                                        */
53 /*  OUTPUT                                                                */
54 /*                                                                        */
55 /*    None                                                                */
56 /*                                                                        */
57 /*  CALLS                                                                 */
58 /*                                                                        */
59 /*    _gx_context_pixelmap_get              Retrieve pixelmap image       */
60 /*    _gx_widget_resize                     Resize a widget               */
61 /*                                                                        */
62 /*  CALLED BY                                                             */
63 /*                                                                        */
64 /*    Application Code                                                    */
65 /*    GUIX Internal Code                                                  */
66 /*                                                                        */
67 /*  RELEASE HISTORY                                                       */
68 /*                                                                        */
69 /*    DATE              NAME                      DESCRIPTION             */
70 /*                                                                        */
71 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
72 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
73 /*                                            resulting in version 6.1    */
74 /*                                                                        */
75 /**************************************************************************/
_gx_scrollbar_thumb_position_calculate(GX_SCROLLBAR * scroll)76 VOID _gx_scrollbar_thumb_position_calculate(GX_SCROLLBAR *scroll)
77 {
78 INT  thumb_length = 0;
79 INT  travelsize;
80 INT  range;
81 INT  space;
82 INT  thumb_width;
83 INT  scroll_width;
84 
85 GX_RECTANGLE thumbrect;
86 ULONG        style;
87 GX_PIXELMAP *thumb_pixelmap = NULL;
88 
89     /* pick up scrollbar style */
90     style = scroll -> gx_widget_style;
91 
92     /* pick up the scroll width and thumb button width */
93 
94     thumb_width = scroll -> gx_scrollbar_appearance.gx_scroll_thumb_width;
95 
96     /* see if the thumb has a pixelmap */
97     if (scroll -> gx_scrollbar_appearance.gx_scroll_thumb_pixelmap)
98     {
99         _gx_widget_pixelmap_get((GX_WIDGET *) scroll, scroll -> gx_scrollbar_appearance.gx_scroll_thumb_pixelmap, &thumb_pixelmap);
100     }
101 
102     if (style & GX_SCROLLBAR_VERTICAL)
103     {
104         scroll_width = scroll -> gx_widget_size.gx_rectangle_right - scroll -> gx_widget_size.gx_rectangle_left + 1;
105 
106         travelsize = (scroll -> gx_widget_size.gx_rectangle_bottom -
107                       scroll -> gx_widget_size.gx_rectangle_top) + 1;
108     }
109     else
110     {
111         scroll_width = scroll -> gx_widget_size.gx_rectangle_bottom - scroll -> gx_widget_size.gx_rectangle_top + 1;
112 
113         travelsize = (scroll -> gx_widget_size.gx_rectangle_right -
114                       scroll -> gx_widget_size.gx_rectangle_left) + 1;
115     }
116 
117     travelsize -= scroll -> gx_scrollbar_appearance.gx_scroll_thumb_travel_max +
118                   scroll -> gx_scrollbar_appearance.gx_scroll_thumb_travel_min;
119 
120     range = scroll -> gx_scrollbar_info.gx_scroll_maximum - scroll -> gx_scrollbar_info.gx_scroll_minimum + 1;
121 
122     if (style & GX_SCROLLBAR_RELATIVE_THUMB)
123     {
124         if (scroll -> gx_scrollbar_info.gx_scroll_maximum !=
125             scroll -> gx_scrollbar_info.gx_scroll_minimum)
126         {
127             thumb_length = travelsize * scroll -> gx_scrollbar_info.gx_scroll_visible;
128             if (range)
129             {
130                 thumb_length /= range;
131             }
132             if (thumb_length < thumb_width)
133             {
134                 thumb_length = thumb_width;
135             }
136         }
137     }
138     else
139     {
140         if (thumb_pixelmap)
141         {
142             if (style & GX_SCROLLBAR_VERTICAL)
143             {
144                 thumb_length = thumb_pixelmap -> gx_pixelmap_height;
145                 thumb_width = thumb_pixelmap -> gx_pixelmap_width;
146             }
147             else
148             {
149                 thumb_length = thumb_pixelmap -> gx_pixelmap_width;
150                 thumb_width = thumb_pixelmap -> gx_pixelmap_height;
151             }
152         }
153         else
154         {
155             /* just a square thumb button */
156             thumb_length = thumb_width;
157         }
158     }
159     space = (travelsize - thumb_length);
160     space *= scroll -> gx_scrollbar_info.gx_scroll_value - scroll -> gx_scrollbar_info.gx_scroll_minimum;
161     range -= scroll -> gx_scrollbar_info.gx_scroll_visible;
162 
163     if (range)
164     {
165         space = (space + (range >> 1)) / range;
166     }
167 
168 
169     if((scroll -> gx_scrollbar_info.gx_scroll_value > scroll -> gx_scrollbar_info.gx_scroll_minimum) &&
170        (scroll -> gx_scrollbar_info.gx_scroll_value + scroll -> gx_scrollbar_info.gx_scroll_visible - 1 < scroll -> gx_scrollbar_info.gx_scroll_maximum))
171     {
172         if (space == 0)
173         {
174             space = 1;
175         }
176         else if (space == (travelsize - thumb_length))
177         {
178             space -= 1;
179         }
180     }
181 
182     thumbrect = scroll -> gx_widget_size;
183 
184     if (style & GX_SCROLLBAR_VERTICAL)
185     {
186         thumbrect.gx_rectangle_left = (GX_VALUE)(thumbrect.gx_rectangle_left + (scroll_width - thumb_width) / 2);
187         thumbrect.gx_rectangle_right = (GX_VALUE) (thumbrect.gx_rectangle_left + thumb_width - 1);
188         thumbrect.gx_rectangle_top = (GX_VALUE)(scroll -> gx_widget_size.gx_rectangle_top +
189                                                 scroll -> gx_scrollbar_appearance.gx_scroll_thumb_travel_min + space);
190         thumbrect.gx_rectangle_bottom = (GX_VALUE)(thumbrect.gx_rectangle_top + thumb_length - 1);
191     }
192     else
193     {
194         thumbrect.gx_rectangle_top = (GX_VALUE)(thumbrect.gx_rectangle_top + (scroll_width - thumb_width) / 2);
195         thumbrect.gx_rectangle_bottom = (GX_VALUE)(thumbrect.gx_rectangle_top + thumb_width - 1);
196 
197         thumbrect.gx_rectangle_left = (GX_VALUE)(scroll -> gx_widget_size.gx_rectangle_left +
198                                                  scroll -> gx_scrollbar_appearance.gx_scroll_thumb_travel_min + space);
199         thumbrect.gx_rectangle_right = (GX_VALUE)(thumbrect.gx_rectangle_left + thumb_length - 1);
200     }
201 
202     _gx_widget_resize((GX_WIDGET *)&scroll -> gx_scrollbar_thumb, &thumbrect);
203 }
204 
205