View Javadoc

1   package org.catacomb.druid.swing.split;
2   
3   import org.catacomb.interlish.interact.DComponent;
4   
5   import javax.swing.*;
6   import java.awt.*;
7   import java.awt.event.*;
8   
9   public class DSplitterBar extends JPanel implements DComponent {
10  
11      private static final long serialVersionUID = 1L;
12      static final Cursor VERT_CURSOR = new Cursor(Cursor.N_RESIZE_CURSOR);
13      static final Cursor HORIZ_CURSOR = new Cursor(Cursor.E_RESIZE_CURSOR);
14      static final Cursor DEF_CURSOR = new Cursor(Cursor.DEFAULT_CURSOR);
15      private int orientation = SplitterLayout.VERTICAL;
16  
17      private boolean alreadyDrawn = false;
18      private Rectangle originalBounds = null;
19      private Window wBar;
20  
21  
22      public DSplitterBar() {
23          addMouseMotionListener(new SplitterBarMouseMotionListener(this));
24          addMouseListener(new SplitterBarMouseListener(this));
25      }
26  
27      private void checkOtherComponents() {
28          Rectangle currBounds = getBounds();  // get current position
29          Component comps[] = getParent().getComponents();
30          Insets insets = getParent().getInsets();
31          Rectangle parentBounds = getParent().getBounds();
32  
33          // determine which component "this" is
34          int curr;
35          for (curr = 0; (curr<comps.length) && (comps[curr]!=this); curr++) ;
36          int origCurr = curr; // hold for part II check
37  
38          if (orientation==SplitterLayout.VERTICAL) {
39              if (currBounds.y<originalBounds.y) { // moved up
40                  // could have moved _into_ splitter bars above (or top edge)
41                  //   and/or away from splitter bars below (or bottom edge)
42  
43                  // check to see it we've bumped into a splitter above us.
44                  boolean done = false;
45                  for (int temp = curr-1; !done && temp>-1; temp--) {
46                      if (comps[temp] instanceof DSplitterBar) {
47                          Rectangle r = comps[temp].getBounds();
48                          if (currBounds.y<=r.y+r.height) { // touching or above...
49                              comps[temp].setLocation(r.x, currBounds.y-r.height);
50                              // any comps in between should be hidden
51                              for (int c = curr-1; c>temp; c--)
52                                  comps[c].setVisible(false);
53                              curr = temp;
54                              currBounds = comps[temp].getBounds();
55                          } // touching or above
56                          else
57                              done = true; // no more compression
58                      } // it's a splitter bar
59                  } // for each component before us
60  
61                  // did we push to far?
62                  if (currBounds.y<=insets.top) {
63                      int delta = currBounds.y-insets.top;
64                      // hide all components before that one
65                      for (int temp = curr-1; temp>-1; temp--)
66                          comps[temp].setVisible(false);
67                      // push all splitter bars into view
68                      done = false;
69                      for (int temp = curr; !done && temp<=origCurr; temp++)
70                          if (comps[temp] instanceof DSplitterBar) {
71                              Point p = comps[temp].getLocation();
72                              p.y -= delta;
73                              comps[temp].setLocation(p);
74                          } else
75                              done = comps[temp].isVisible();
76                  } // pushed highest component off top edge
77  
78                  // next, check if we exposed components below us
79                  curr = origCurr;
80                  // if the next component is not visible, show all between us & next
81                  //    splitter bar or bottom edge
82                  for (int temp = curr+1; temp<comps.length && !comps[temp].isVisible(); temp++)
83                      comps[temp].setVisible(true);
84              } // VERTICAL -- moved up
85              else if (currBounds.y>originalBounds.y) { // moved down
86                  // could have moved _into_ splitter bars below (or bottom edge)
87                  //   and/or away from splitter bars above (or top edge)
88  
89                  // check to see it we've bumped into a splitter below us.
90                  boolean done = false;
91                  for (int temp = curr+1; !done && temp<comps.length; temp++) {
92                      if (comps[temp] instanceof DSplitterBar) {
93                          Rectangle r = comps[temp].getBounds();
94                          if (currBounds.y+currBounds.height>= r.y) { // touching or below...
95                              comps[temp].setLocation(r.x, currBounds.y+currBounds.height);
96                              // any comps in between should be hidden
97                              for (int c = curr+1; c<temp; c++)
98                                  comps[c].setVisible(false);
99                              curr = temp;
100                             currBounds = comps[temp].getBounds();
101                         } // touching or above
102                         else
103                             done = true; // no more compression
104                     } // it's a splitter bar
105                 } // for each component before us
106 
107                 // did we push to far?
108                 if ((currBounds.y+currBounds.height)>= (parentBounds.height-insets.bottom)) {
109                     int delta = currBounds.y+currBounds.height-(parentBounds.height-insets.bottom);
110                     // hide all components before that one
111                     for (int temp = curr+1; temp<comps.length; temp++)
112                         comps[temp].setVisible(false);
113                     // push all splitter bars into view
114                     done = false;
115                     for (int temp = curr; !done && temp>= origCurr; temp--)
116                         if (comps[temp] instanceof DSplitterBar) {
117                             Point p = comps[temp].getLocation();
118                             p.y -= delta;
119                             comps[temp].setLocation(p);
120                         } else
121                             done = comps[temp].isVisible();
122                 } // pushed highest component off top edge
123 
124                 // next, check if we exposed components below us
125                 curr = origCurr;
126                 // if the next component is not visible, show all between us & next
127                 //    splitter bar or bottom edge
128                 for (int temp = curr-1; temp>-1 && !comps[temp].isVisible(); temp--)
129                     comps[temp].setVisible(true);
130             } // VERTICAL -- moved down
131         } // orientation==VERTICAL
132         else { // orientation == HORIZONTAL
133             if (currBounds.x<originalBounds.x) { // moved left
134                 // could have moved _into_ splitter bars to left (or left edge)
135                 //   and/or away from splitter bars to right (or right edge)
136 
137                 // check to see it we've bumped into a splitter above us.
138                 boolean done = false;
139                 for (int temp = curr-1; !done && temp>-1; temp--) {
140                     if (comps[temp] instanceof DSplitterBar) {
141                         Rectangle r = comps[temp].getBounds();
142                         if (currBounds.x<=r.x+r.width) { // touching or above...
143                             comps[temp].setLocation(currBounds.x-r.width, r.y);
144                             // any comps in between should be hidden
145                             for (int c = curr-1; c>temp; c--)
146                                 comps[c].setVisible(false);
147                             curr = temp;
148                             currBounds = comps[temp].getBounds();
149                         } // touching or above
150                         else
151                             done = true; // no more compression
152                     } // it's a splitter bar
153                 } // for each component before us
154 
155                 // did we push to far?
156                 if (currBounds.x<=insets.left) {
157                     int delta = currBounds.x-insets.left;
158                     // hide all components before that one
159                     for (int temp = curr-1; temp>-1; temp--)
160                         comps[temp].setVisible(false);
161                     // push all splitter bars into view
162                     done = false;
163                     for (int temp = curr; !done && temp<=origCurr; temp++)
164                         if (comps[temp] instanceof DSplitterBar) {
165                             Point p = comps[temp].getLocation();
166                             p.x -= delta;
167                             comps[temp].setLocation(p);
168                         } else
169                             done = comps[temp].isVisible();
170                 } // pushed highest component off top edge
171 
172                 // next, check if we exposed components below us
173                 curr = origCurr;
174                 // if the next component is not visible, show all between us & next
175                 //    splitter bar or bottom edge
176                 for (int temp = curr+1; temp<comps.length && !comps[temp].isVisible(); temp++)
177                     comps[temp].setVisible(true);
178             } // HORIZONTAL -- moved left
179             else if (currBounds.x>originalBounds.x) { // moved right
180                 // could have moved _into_ splitter bars to right (or right edge)
181                 //   and/or away from splitter bars to left (or left edge)
182 
183                 // check to see it we've bumped into a splitter to our right us.
184                 boolean done = false;
185                 for (int temp = curr+1; !done && temp<comps.length; temp++) {
186                     if (comps[temp] instanceof DSplitterBar) {
187                         Rectangle r = comps[temp].getBounds();
188                         if (currBounds.x+currBounds.width>= r.x) { // touching or to right...
189                             comps[temp].setLocation(currBounds.x+currBounds.width, r.y);
190                             // any comps in between should be hidden
191                             for (int c = curr+1; c<temp; c++)
192                                 comps[c].setVisible(false);
193                             curr = temp;
194                             currBounds = comps[temp].getBounds();
195                         } // touching or above
196                         else
197                             done = true; // no more compression
198                     } // it's a splitter bar
199                 } // for each component before us
200 
201                 // did we push to far?
202                 if ((currBounds.x+currBounds.width)>= (parentBounds.width-insets.right)) {
203                     int delta = currBounds.x+currBounds.width-(parentBounds.width-insets.right);
204                     // hide all components before that one
205                     for (int temp = curr+1; temp<comps.length; temp++)
206                         comps[temp].setVisible(false);
207                     // push all splitter bars into view
208                     done = false;
209                     for (int temp = curr; !done && temp>= origCurr; temp--)
210                         if (comps[temp] instanceof DSplitterBar) {
211                             Point p = comps[temp].getLocation();
212                             p.x -= delta;
213                             comps[temp].setLocation(p);
214                         } else
215                             done = comps[temp].isVisible();
216                 } // pushed highest component off top edge
217 
218                 // next, check if we exposed components below us
219                 curr = origCurr;
220                 // if the next component is not visible, show all between us & next
221                 //    splitter bar or bottom edge
222                 for (int temp = curr-1; temp>-1 && !comps[temp].isVisible(); temp--)
223                     comps[temp].setVisible(true);
224             } // HORIZONTAL -- moved right
225         } // orientation==HORIZONTAL
226 
227     } // checkComponents()
228 
229     public int getOrientation() {
230         return orientation;
231     }
232 
233     void mouseDrag(MouseEvent e) {
234         if (SplitterLayout.dragee==null)
235             SplitterLayout.dragee = this;
236         else if (SplitterLayout.dragee!=this)
237             return;
238         Component c = getParent();
239         Point fl = c.getLocationOnScreen();
240         while (c.getParent()!=null)
241             c = c.getParent();
242         if (!alreadyDrawn) {
243             originalBounds = getBounds();
244             wBar = new Window((Frame)c);
245             wBar.setBackground(getBackground().darker());
246         }
247         Container cp = getParent();
248         Dimension parentDim = cp.getSize();
249         Point l = getLocationOnScreen();
250         Insets insets = cp.getInsets();
251         if (orientation==SplitterLayout.VERTICAL)
252             parentDim.width -= insets.right+insets.left;
253         else
254             parentDim.height -= insets.top+insets.bottom;
255         Rectangle r = getBounds(); // mouse event is relative to this...
256         int x = l.x+(orientation==SplitterLayout.HORIZONTAL ? e.getX() : 0);
257         int y = l.y+(orientation==SplitterLayout.VERTICAL ? e.getY() : 0);
258         if (x<fl.x+insets.left)
259             x = fl.x+insets.left;
260         else if ((orientation==SplitterLayout.HORIZONTAL) && (x>fl.x+parentDim.width-r.width))
261             x = fl.x+parentDim.width-r.width;
262         if (y<fl.y+insets.top)
263             y = fl.y+insets.top;
264         else if ((orientation==SplitterLayout.VERTICAL) && (y>fl.y+parentDim.height-r.height))
265             y = fl.y+parentDim.height-r.height;
266         wBar.setBounds(x, y,
267                        (orientation==SplitterLayout.HORIZONTAL) ? 3 : parentDim.width,
268                        (orientation==SplitterLayout.VERTICAL) ? 3 : parentDim.height);
269         if (!alreadyDrawn) {
270             wBar.setVisible(true);
271             alreadyDrawn = true;
272         }
273     }
274     void mouseEnter(MouseEvent e) {
275         if (SplitterLayout.dragee!=null) return;
276         setCursor((orientation==SplitterLayout.VERTICAL) ? VERT_CURSOR : HORIZ_CURSOR);
277         // mouseInside = true;
278         invalidate();
279         validate();
280         repaint();
281     }
282     void mouseExit(MouseEvent e) {
283         if (SplitterLayout.dragee!=null) return;
284         setCursor(DEF_CURSOR);
285         // mouseInside = false;
286         invalidate();
287         validate();
288         repaint();
289     }
290 
291     void mouseRelease(MouseEvent e) {
292         if (alreadyDrawn) {
293             if (SplitterLayout.dragee!=this) return;
294             SplitterLayout.dragee = null;
295             wBar.setVisible(false);
296             wBar.dispose();
297             wBar = null;
298             alreadyDrawn = false;
299             Rectangle r = getBounds(); // mouse event is relative to this...
300             r.x += (orientation==SplitterLayout.HORIZONTAL ? e.getX() : 0);
301             r.y += (orientation==SplitterLayout.VERTICAL ? e.getY() : 0);
302             setLocation(r.x, r.y);
303             setCursor(DEF_CURSOR);
304 
305             // check to see if we need to move other splitters and hide other
306             // components that are controlled by the layout
307             // First -- find what component this one is
308 
309             checkOtherComponents();
310             // mouseInside = false;
311             invalidate();
312             getParent().validate();
313             SplitterLayout.dragee = null;
314         }
315     }
316 
317     /**
318      * Paints the image of a JSplitterBar.  If nothing was added to
319      * the JSplitterBar, this image will only be a thin, 3D raised line that
320      * will act like a handle for moving the JSplitterBar.
321      * If other components were added the JSplitterBar, the thin 3D raised
322      * line will onlty appear where JSplitterSpace components were added.
323      */
324     public void paint(Graphics g) {
325         super.paint(g);
326         g.setColor(getBackground());
327 //        if(mouseInside)
328 //            g.setColor(Color.yellow);
329 //        else
330 //            g.setColor(Colors.lightSkyBlue3);
331         Component c[] = getComponents();
332         if (c!=null && c.length>0)
333             for (int i = 0; i<c.length; i++) {
334                 if (c[i] instanceof DSplitterSpace) {
335                     // only draw boxes where JSplitterSpace components appear
336                     Rectangle r = c[i].getBounds();
337                     if (orientation==SplitterLayout.VERTICAL)
338                         g.fill3DRect(r.x+2, r.y+r.height/2-1, r.width-5, 3, true);
339                     else
340                         g.fill3DRect(r.x+r.width/2-1, r.y+2, 3, r.y+r.height-5, true);
341                 }
342             }
343         else {
344             Rectangle r = getBounds();
345             if (orientation==SplitterLayout.VERTICAL)
346                 g.fill3DRect(2, r.height/2-1, r.width-5, 3, true);
347             else
348                 g.fill3DRect(r.width/2-1, 2, 3, r.height-5, true);
349         }
350     }
351 
352     void setOrientation(int o) {
353         orientation = o;
354     }
355 
356     public void swapOrientation() {
357         setOrientation(getOrientation()==SplitterLayout.HORIZONTAL ? SplitterLayout.VERTICAL : SplitterLayout.HORIZONTAL);
358     }
359 
360     /**
361      * Called by AWT to update the image produced by the JSplitterBar
362      */
363     public void update(Graphics g) {
364         paint(g);
365     }
366 
367     public void setTooltip(String s) {
368         // setToolTipText(s);
369     }
370 
371 
372 }