1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "config.h"
19 
20 #include <math.h>
21 
22 #include <gegl.h>
23 #include <gtk/gtk.h>
24 
25 #include "display-types.h"
26 
27 #include "core/gimpimage.h"
28 
29 #include "gimpdisplay.h"
30 #include "gimpdisplayshell.h"
31 #include "gimpdisplayshell-scale.h"
32 #include "gimpdisplayshell-scrollbars.h"
33 
34 
35 #define MINIMUM_STEP_AMOUNT 1.0
36 
37 
38 /**
39  * gimp_display_shell_scrollbars_update:
40  * @shell:
41  *
42  **/
43 void
gimp_display_shell_scrollbars_update(GimpDisplayShell * shell)44 gimp_display_shell_scrollbars_update (GimpDisplayShell *shell)
45 {
46   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
47 
48   if (! shell->display)
49     return;
50 
51   /* Horizontal scrollbar */
52 
53   g_object_freeze_notify (G_OBJECT (shell->hsbdata));
54 
55   /* Update upper and lower value before we set the new value */
56   gimp_display_shell_scrollbars_setup_horizontal (shell, shell->offset_x);
57 
58   g_object_set (shell->hsbdata,
59                 "value",          (gdouble) shell->offset_x,
60                 "page-size",      (gdouble) shell->disp_width,
61                 "page-increment", (gdouble) shell->disp_width / 2,
62                 NULL);
63 
64   g_object_thaw_notify (G_OBJECT (shell->hsbdata)); /* emits "changed" */
65 
66 
67   /* Vertcal scrollbar */
68 
69   g_object_freeze_notify (G_OBJECT (shell->vsbdata));
70 
71   /* Update upper and lower value before we set the new value */
72   gimp_display_shell_scrollbars_setup_vertical (shell, shell->offset_y);
73 
74   g_object_set (shell->vsbdata,
75                 "value",          (gdouble) shell->offset_y,
76                 "page-size",      (gdouble) shell->disp_height,
77                 "page-increment", (gdouble) shell->disp_height / 2,
78                 NULL);
79 
80   g_object_thaw_notify (G_OBJECT (shell->vsbdata)); /* emits "changed" */
81 }
82 
83 /**
84  * gimp_display_shell_scrollbars_setup_horizontal:
85  * @shell:
86  * @value:
87  *
88  * Setup the limits of the horizontal scrollbar
89  **/
90 void
gimp_display_shell_scrollbars_setup_horizontal(GimpDisplayShell * shell,gdouble value)91 gimp_display_shell_scrollbars_setup_horizontal (GimpDisplayShell *shell,
92                                                 gdouble           value)
93 {
94   gint    bounds_x;
95   gint    bounds_width;
96   gint    bounding_box_x;
97   gint    bounding_box_width;
98   gint    x1;
99   gint    x2;
100   gdouble lower;
101   gdouble upper;
102   gdouble scale_x;
103 
104   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
105 
106   if (! shell->display || ! gimp_display_get_image (shell->display))
107     return;
108 
109   gimp_display_shell_scale_get_image_bounds (shell,
110                                              &bounds_x,     NULL,
111                                              &bounds_width, NULL);
112 
113   if (! gimp_display_shell_get_infinite_canvas (shell))
114     {
115       bounding_box_x     = bounds_x;
116       bounding_box_width = bounds_width;
117     }
118   else
119     {
120       gimp_display_shell_scale_get_image_bounding_box (
121         shell,
122         &bounding_box_x,     NULL,
123         &bounding_box_width, NULL);
124     }
125 
126   x1 = bounding_box_x;
127   x2 = bounding_box_x + bounding_box_width;
128 
129   x1 = MIN (x1, bounds_x + bounds_width / 2 - shell->disp_width       / 2);
130   x2 = MAX (x2, bounds_x + bounds_width / 2 + (shell->disp_width + 1) / 2);
131 
132   lower = MIN (value,                     x1);
133   upper = MAX (value + shell->disp_width, x2);
134 
135   gimp_display_shell_get_rotated_scale (shell, &scale_x, NULL);
136 
137   g_object_set (shell->hsbdata,
138                 "lower",          lower,
139                 "upper",          upper,
140                 "step-increment", (gdouble) MAX (scale_x, MINIMUM_STEP_AMOUNT),
141                 NULL);
142 }
143 
144 /**
145  * gimp_display_shell_scrollbars_setup_vertical:
146  * @shell:
147  * @value:
148  *
149  * Setup the limits of the vertical scrollbar
150  **/
151 void
gimp_display_shell_scrollbars_setup_vertical(GimpDisplayShell * shell,gdouble value)152 gimp_display_shell_scrollbars_setup_vertical (GimpDisplayShell *shell,
153                                               gdouble           value)
154 {
155   gint    bounds_y;
156   gint    bounds_height;
157   gint    bounding_box_y;
158   gint    bounding_box_height;
159   gint    y1;
160   gint    y2;
161   gdouble lower;
162   gdouble upper;
163   gdouble scale_y;
164 
165   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
166 
167   if (! shell->display || ! gimp_display_get_image (shell->display))
168     return;
169 
170   gimp_display_shell_scale_get_image_bounds (shell,
171                                              NULL, &bounds_y,
172                                              NULL, &bounds_height);
173 
174   if (! gimp_display_shell_get_infinite_canvas (shell))
175     {
176       bounding_box_y      = bounds_y;
177       bounding_box_height = bounds_height;
178     }
179   else
180     {
181       gimp_display_shell_scale_get_image_bounding_box (
182         shell,
183         NULL, &bounding_box_y,
184         NULL, &bounding_box_height);
185     }
186 
187   y1 = bounding_box_y;
188   y2 = bounding_box_y + bounding_box_height;
189 
190   y1 = MIN (y1, bounds_y + bounds_height / 2 - shell->disp_height       / 2);
191   y2 = MAX (y2, bounds_y + bounds_height / 2 + (shell->disp_height + 1) / 2);
192 
193   lower = MIN (value,                      y1);
194   upper = MAX (value + shell->disp_height, y2);
195 
196   gimp_display_shell_get_rotated_scale (shell, NULL, &scale_y);
197 
198   g_object_set (shell->vsbdata,
199                 "lower",          lower,
200                 "upper",          upper,
201                 "step-increment", (gdouble) MAX (scale_y, MINIMUM_STEP_AMOUNT),
202                 NULL);
203 }
204 
205 /**
206  * gimp_display_shell_scrollbars_update_steppers:
207  * @shell:
208  * @min_offset_x:
209  * @max_offset_x:
210  * @min_offset_y:
211  * @max_offset_y:
212  *
213  * Sets the scrollbars' stepper sensitivity which is set differently
214  * from its adjustment limits because we support overscrolling.
215  **/
216 void
gimp_display_shell_scrollbars_update_steppers(GimpDisplayShell * shell,gint min_offset_x,gint max_offset_x,gint min_offset_y,gint max_offset_y)217 gimp_display_shell_scrollbars_update_steppers (GimpDisplayShell *shell,
218                                                gint              min_offset_x,
219                                                gint              max_offset_x,
220                                                gint              min_offset_y,
221                                                gint              max_offset_y)
222 {
223   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
224 
225   gtk_range_set_lower_stepper_sensitivity (GTK_RANGE (shell->hsb),
226                                            min_offset_x < shell->offset_x ?
227                                            GTK_SENSITIVITY_ON :
228                                            GTK_SENSITIVITY_OFF);
229 
230   gtk_range_set_upper_stepper_sensitivity (GTK_RANGE (shell->hsb),
231                                            max_offset_x > shell->offset_x ?
232                                            GTK_SENSITIVITY_ON :
233                                            GTK_SENSITIVITY_OFF);
234 
235   gtk_range_set_lower_stepper_sensitivity (GTK_RANGE (shell->vsb),
236                                            min_offset_y < shell->offset_y ?
237                                            GTK_SENSITIVITY_ON :
238                                            GTK_SENSITIVITY_OFF);
239 
240   gtk_range_set_upper_stepper_sensitivity (GTK_RANGE (shell->vsb),
241                                            max_offset_y > shell->offset_y ?
242                                            GTK_SENSITIVITY_ON :
243                                            GTK_SENSITIVITY_OFF);
244 }
245