Handle hostnames with upper-case letters
[webmin.git] / proc / CbScrollbar.java
1 // CbScrollbar.java
2 // A drop-in replacement for the AWT scrollbar class, with callbacks
3 // and a nicer look. This scrollbar is typically used to display some
4 // fraction of a list of items, with values ranging from min to max.
5 // The lvisible parameter determines how many of the list are lvisible
6 // at any one time. The value of the scrollbar ranges from min to
7 // max-lvisible+1 (the highest position in the list to start displaying)
8 import java.awt.*;
9
10 public class CbScrollbar extends Panel
11 {
12         static final int VERTICAL = 0;
13         static final int HORIZONTAL = 1;
14         CbScrollbarCallback callback;           // who to call back to
15         boolean inside, indent;
16         int orient;                     // horizontal or vertical?
17         int value;                      // position
18         int lvisible;                   // the number of lines lvisible
19         int num;                        // total number of lines
20         int lineinc = 1;                // how much the arrow buttons move by
21         Color lc1 = Util.light_edge, lc2 = Util.body, lc3 = Util.dark_edge;
22         Color hc1 = Util.light_edge_hi, hc2 = Util.body_hi, hc3 = Util.dark_edge_hi;
23         Color bc = Util.dark_bg;
24         int y1, y2, x1, x2, drag;
25
26         CbScrollbarArrow arrow1, arrow2;
27
28         CbScrollbar(int o, CbScrollbarCallback cb)
29         {
30         this(o, 0, 1, 1, cb);
31         }
32
33         /**Create a new scrollbar
34          */
35         CbScrollbar(int o, int v, int vis, int n, CbScrollbarCallback cb)
36         {
37         setValues(v, vis, n);
38         orient = o;
39         callback = cb;
40         setLayout(null);
41         if (orient == VERTICAL) {
42                 add(arrow1 = new CbScrollbarArrow(this, 0));
43                 add(arrow2 = new CbScrollbarArrow(this, 1));
44                 }
45         else {
46                 add(arrow1 = new CbScrollbarArrow(this, 2));
47                 add(arrow2 = new CbScrollbarArrow(this, 3));
48                 }
49         }
50
51         /**Set the current scrollbar parameters
52          * @param v             Current position
53          * @param vis           Number of lines lvisible
54          * @param n             Total number of lines
55          */
56         public void setValues(int v, int vis, int n)
57         {
58         value = v;
59         lvisible = vis;
60         num = n;
61         if (lvisible > num) lvisible = num;
62         checkValue();
63         repaint();
64         }
65
66         public int getValue() { return value; }
67
68         public void setValue(int v)
69         {
70         value = v;
71         checkValue();
72         repaint();
73         }
74
75         private void checkValue()
76         {
77         if (value < 0) value = 0;
78         else if (value > num-lvisible) value = num-lvisible;
79         }
80
81         public void paint(Graphics g)
82         {
83         if (num == 0) return;
84         int w = size().width, h = size().height;
85         boolean ins = inside && !(arrow1.inside || arrow2.inside);
86         Color c1 = ins ? hc1 : lc1, c2 = ins ? hc2 : lc2,
87               c3 = ins ? hc3 : lc3;
88         g.setColor(bc);
89         g.fillRect(0, 0, w, h);
90         g.setColor(c3);
91         g.drawLine(0, 0, w-1, 0); g.drawLine(0, 0, 0, h-1);
92         g.setColor(c1);
93         g.drawLine(w-1, h-1, w-1, 0); g.drawLine(w-1, h-1, 0, h-1);
94
95         if (orient == VERTICAL) {
96                 int va = h-w*2;
97                 y1 = w+va*value/num;
98                 y2 = w+va*(value+lvisible)/num-1;
99                 g.setColor(c2);
100                 g.fillRect(1, y1, w-2, y2-y1);
101                 g.setColor(indent ? c3 : c1);
102                 g.drawLine(1, y1, w-2, y1);
103                 g.drawLine(1, y1, 1, y2-1);
104                 g.setColor(indent ? c1 : c3);
105                 g.drawLine(w-2, y2-1, w-2, y1);
106                 g.drawLine(w-2, y2-1, 1, y2-1);
107                 if (ins) {
108                         g.drawLine(w-3, y2-2, w-3, y1+1);
109                         g.drawLine(w-3, y2-2, 2, y2-2);
110                         }
111                 }
112         else if (orient == HORIZONTAL) {
113                 int va = w-h*2;
114                 x1 = h+va*value/num;
115                 x2 = h+va*(value+lvisible)/num-1;
116                 g.setColor(c2);
117                 g.fillRect(x1, 1, x2-x1, h-2);
118                 g.setColor(indent ? c3 : c1);
119                 g.drawLine(x1, 1, x1, h-2);
120                 g.drawLine(x1, 1, x2-1, 1);
121                 g.setColor(indent ? c1 : c3);
122                 g.drawLine(x2-1, h-2, x1, h-2);
123                 g.drawLine(x2-1, h-2, x2-1, 1);
124                 if (ins) {
125                         g.drawLine(x2-2, h-3, x1+1, h-3);
126                         g.drawLine(x2-2, h-3, x2-2, 2);
127                         }
128                 }
129         }
130
131         /**Called by arrows to move the slider
132          */
133         void arrowClick(int d)
134         {
135         int oldvalue = value;
136         value += d;
137         checkValue();
138         if (value != oldvalue) {
139                 callback.moved(this, value);
140                 repaint();
141                 }
142         }
143
144         public void reshape(int nx, int ny, int nw, int nh)
145         {
146         super.reshape(nx, ny, nw, nh);
147         if (orient == VERTICAL) {
148                 arrow1.reshape(1, 1, nw-2, nw-1);
149                 arrow2.reshape(1, nh-nw-1, nw-2, nw-1);
150                 }
151         else {
152                 arrow1.reshape(1, 1, nh-1, nh-2);
153                 arrow2.reshape(nw-nh-1, 1, nh-1, nh-2);
154                 }
155         repaint();
156         }
157
158         public Dimension preferredSize()
159         {
160         return orient==VERTICAL ? new Dimension(16, 100)
161                                 : new Dimension(100, 16);
162         }
163
164         public Dimension minimumSize()
165         {
166         return preferredSize();
167         }
168
169         public boolean mouseDown(Event e, int mx, int my)
170         {
171         if (orient == VERTICAL) {
172                 // move up/down one page, or start dragging
173                 if (my < y1) arrowClick(-lvisible);
174                 else if (my > y2) arrowClick(lvisible);
175                 else {
176                         indent = true;
177                         drag = my-y1;
178                         repaint();
179                         }
180                 }
181         else {
182                 // move left/right one page, or start dragging
183                 if (mx < x1) arrowClick(-lvisible);
184                 else if (mx > x2) arrowClick(lvisible);
185                 else {
186                         indent = true;
187                         drag = mx-x1;
188                         repaint();
189                         }
190                 }
191         return true;
192         }
193
194         public boolean mouseDrag(Event e, int mx, int my)
195         {
196         if (indent) {
197                 int w = size().width, h = size().height;
198                 int oldvalue = value;
199                 if (orient == VERTICAL) {
200                         int va = h-w*2, ny = my-drag-w;
201                         value = ny*num/va;
202                         }
203                 else {
204                         int va = w-h*2, nx = mx-drag-h;
205                         value = nx*num/va;
206                         }
207                 checkValue();
208                 if (value != oldvalue) {
209                         callback.moving(this, value);
210                         repaint();
211                         }
212                 }
213         return indent;
214         }
215
216         public boolean mouseUp(Event e, int mx, int my)
217         {
218         if (indent) {
219                 indent = false;
220                 repaint();
221                 callback.moved(this, value);
222                 return true;
223                 }
224         return false;
225         }
226
227 /*
228         public boolean mouseEnter(Event e, int mx, int my)
229         {
230         inside = true;
231         repaint();
232         return true;
233         }
234
235         public boolean mouseExit(Event e, int mx, int my)
236         {
237         inside = false;
238         repaint();
239         return true;
240         }
241 */
242 }
243
244 class CbScrollbarArrow extends Canvas implements Runnable
245 {
246         int mode;
247         CbScrollbar scrollbar;
248         boolean inside, indent;
249         Thread th;
250
251         CbScrollbarArrow(CbScrollbar p, int m)
252         {
253         scrollbar = p;
254         mode = m;
255         }
256
257         public void paint(Graphics g)
258         {
259         int w = size().width, h = size().height;
260         Color c1 = inside ? scrollbar.hc1 : scrollbar.lc1,
261               c2 = inside ? scrollbar.hc2 : scrollbar.lc2,
262               c3 = inside ? scrollbar.hc3 : scrollbar.lc3;
263         g.setColor(scrollbar.bc);
264         g.fillRect(0, 0, w, h);
265         int xp[] = new int[3], yp[] = new int[3];
266         // blank, dark, light
267         if (mode == 0) {
268                 // up arrow
269                 xp[0] = w/2; xp[1] = w-1; xp[2] = 0;
270                 yp[0] = 0;   yp[1] = h-1; yp[2] = h-1;
271                 }
272         else if (mode == 1) {
273                 // down arrow
274                 xp[0] = 0;   xp[1] = w/2; xp[2] = w-1;
275                 yp[0] = 0;   yp[1] = h-1; yp[2] = 0;
276                 }
277         else if (mode == 2) {
278                 // left arrow
279                 xp[0] = 0;   xp[1] = w-1; xp[2] = w-1; 
280                 yp[0] = h/2; yp[1] = h-1; yp[2] = 0;
281                 }
282         else if (mode == 3) {
283                 // right arrow
284                 xp[0] = 0;   xp[1] = w-1; xp[2] = 0;
285                 yp[0] = 0;   yp[1] = h/2; yp[2] = h-1;
286                 }
287         g.setColor(c2);
288         g.fillPolygon(xp, yp, 3);
289         g.setColor(indent ? c1 : c3);
290         g.drawLine(xp[1], yp[1], xp[2], yp[2]);
291         g.setColor(indent ? c3 : c1);
292         g.drawLine(xp[0], yp[0], xp[2], yp[2]);
293         }
294
295         public boolean mouseDown(Event e, int mx, int my)
296         {
297         indent = true;
298         repaint();
299         (th = new Thread(this)).start();
300         return true;
301         }
302
303         public boolean mouseUp(Event e, int mx, int my)
304         {
305         indent = false;
306         repaint();
307         if (th != null) th.stop();
308         return true;
309         }
310
311         /**Thread for doing repeated scrolling
312          */
313         public void run()
314         {
315         int stime = 500;
316         while(true) {
317                 scrollbar.arrowClick(mode%2 == 0 ? -1 : 1);
318                 try { Thread.sleep(stime); } catch(Exception e) { }
319                 stime = 100;
320                 }
321         }
322 }
323
324
325 // CbScrollbarCallback
326 // Methods for reporting the movement of the scrollbar to another object
327 interface CbScrollbarCallback
328 {
329         /**Called when the scrollbar stops moving. This happens when an
330          * arrow is clicked, the scrollbar is moved by a page, or the user
331          * lets go of the scrollbar after dragging it.
332          * @param sb    The scrollar that has been moved
333          * @param v     The new value
334          */
335         void moved(CbScrollbar sb, int v);
336
337         /**Called upon every pixel movement of the scrollbar when it is
338          * being dragged, but NOT when moved() is called.
339          * @param sb    The scrollar that has been moved
340          * @param v     The new value
341          */
342         void moving(CbScrollbar sb, int v);
343 }
344
345