wimba.com | e8e1910 | 2005-02-08 17:15:23 +0000 | [diff] [blame] | 1 | |
Constantin Kaplinsky | cf689b3 | 2008-04-30 12:50:34 +0000 | [diff] [blame^] | 2 | package com.tightvnc.rfbplayer; |
wimba.com | e8e1910 | 2005-02-08 17:15:23 +0000 | [diff] [blame] | 3 | |
| 4 | import java.awt.*; |
| 5 | import java.awt.event.*; |
| 6 | |
| 7 | class LWScrollPane extends Container implements AdjustmentListener { |
| 8 | |
| 9 | /** position info */ |
| 10 | private Point scrollPosition = new Point(0, 0); |
| 11 | |
| 12 | /** panel to hold component to scroll */ |
| 13 | private Panel innerPanel = new Panel() { |
| 14 | |
| 15 | public void update(Graphics g) { |
| 16 | if (needClear) { |
| 17 | super.update(g); |
| 18 | needClear = false; |
| 19 | } else |
| 20 | this.paint(g); |
| 21 | } |
| 22 | |
| 23 | }; |
| 24 | |
| 25 | /** component to display */ |
| 26 | private Component containedComp; |
| 27 | |
| 28 | /** layout info */ |
| 29 | private GridBagLayout gb; |
| 30 | private GridBagConstraints gbc; |
| 31 | |
| 32 | /** scroll bars */ |
| 33 | private Scrollbar xScroller; |
| 34 | private Scrollbar yScroller; |
| 35 | |
| 36 | /** flags indicating which scollbars are visible */ |
| 37 | private boolean showingXScroll = false; |
| 38 | private boolean showingYScroll = false; |
| 39 | |
| 40 | /** flag indicating when innerpanel needs to repaint background */ |
| 41 | private boolean needClear = false; |
| 42 | |
| 43 | /** dimensions for our preferred size */ |
| 44 | private int width = 0; |
| 45 | private int height = 0; |
| 46 | |
| 47 | /** c'tor for a new scroll pane */ |
| 48 | public LWScrollPane() { |
| 49 | // create scroll bars |
| 50 | xScroller = new Scrollbar(Scrollbar.HORIZONTAL) { |
| 51 | |
| 52 | public boolean isFocusable() { |
| 53 | return false; |
| 54 | } |
| 55 | |
| 56 | }; |
| 57 | yScroller = new Scrollbar(Scrollbar.VERTICAL) { |
| 58 | |
| 59 | public boolean isFocusable() { |
| 60 | return false; |
| 61 | } |
| 62 | |
| 63 | }; |
| 64 | xScroller.addAdjustmentListener(this); |
| 65 | yScroller.addAdjustmentListener(this); |
| 66 | |
| 67 | // layout info |
| 68 | gb = new GridBagLayout(); |
| 69 | gbc = new GridBagConstraints(); |
| 70 | setLayout(gb); |
| 71 | setBackground(Color.white); |
| 72 | |
| 73 | // added inner panel |
| 74 | //innerPanel.setBackground(Color.blue); |
| 75 | gbc.fill = GridBagConstraints.BOTH; |
| 76 | gbc.gridx = 0; |
| 77 | gbc.gridy = 0; |
| 78 | gbc.weightx = 100; |
| 79 | gbc.weighty = 100; |
| 80 | gb.setConstraints(innerPanel, gbc); |
| 81 | add(innerPanel); |
| 82 | innerPanel.setLayout(null); |
| 83 | } |
| 84 | /* |
| 85 | public void update(Graphics g) { |
| 86 | paint(g); |
| 87 | } |
| 88 | */ |
| 89 | /* |
| 90 | public void paint(Graphics g) { |
| 91 | super.paint(g); |
| 92 | } |
| 93 | */ |
| 94 | |
| 95 | /** |
| 96 | * Provided to allow the containing frame to resize. |
| 97 | * OS X JVM 1.3 would not allow a frame to be made |
| 98 | * smaller without overriding getMinimumSize. |
| 99 | */ |
| 100 | public Dimension getMinimumSize() { |
| 101 | return new Dimension(0, 0); |
| 102 | } |
| 103 | |
| 104 | public Dimension getPreferredSize() { |
| 105 | return new Dimension(width, height); |
| 106 | } |
| 107 | |
| 108 | public void setSize(int width, int height) { |
| 109 | this.width = width; |
| 110 | this.height = height; |
| 111 | super.setSize(width, height); |
| 112 | } |
| 113 | |
| 114 | public void setSize(Dimension d) { |
| 115 | setSize(d.width, d.height); |
| 116 | } |
| 117 | |
| 118 | /** |
| 119 | * Force component to clear itself before repainting. |
| 120 | * Primarily useful if the contained component shrinks |
| 121 | * without the scroll pane reducing in size. |
| 122 | */ |
| 123 | public void clearAndRepaint() { |
| 124 | needClear = true; |
| 125 | innerPanel.repaint(); |
| 126 | } |
| 127 | |
| 128 | /** Add the component to be scrolled by scroll pane */ |
| 129 | void addComp(Component comp) { |
| 130 | containedComp = comp; |
| 131 | innerPanel.add(containedComp); |
| 132 | } |
| 133 | |
| 134 | /** |
| 135 | * Set the point of the component to display in the |
| 136 | * upper left corner of the viewport. |
| 137 | */ |
| 138 | void setScrollPosition(int x, int y) { |
| 139 | Dimension vps = getViewportSize(); |
| 140 | Dimension ccs = containedComp.getPreferredSize(); |
| 141 | |
| 142 | // skip entirely if component smaller than viewer |
| 143 | if (ccs.width <= vps.width && ccs.height <= vps.height) |
| 144 | return; |
| 145 | |
| 146 | // don't scroll too far left or up |
| 147 | if (x < 0) |
| 148 | x = 0; |
| 149 | if (y < 0) |
| 150 | y = 0; |
| 151 | |
| 152 | // don't scroll too far right or down |
| 153 | if (ccs.width <= vps.width) |
| 154 | x = 0; |
| 155 | else if (x > (ccs.width - vps.width)) |
| 156 | x = ccs.width - vps.width; |
| 157 | if (ccs.height <= vps.height) |
| 158 | y = 0; |
| 159 | else if (y > (ccs.height - vps.height)) |
| 160 | y = ccs.height - vps.height; |
| 161 | |
| 162 | scrollPosition = new Point(x, y); |
| 163 | containedComp.setLocation(-scrollPosition.x, -scrollPosition.y); |
| 164 | xScroller.setValue(scrollPosition.x); |
| 165 | yScroller.setValue(scrollPosition.y); |
| 166 | } |
| 167 | |
| 168 | /** Returns the point at the upper left corner of viewport */ |
| 169 | Point getScrollPosition() { |
| 170 | return new Point(scrollPosition); |
| 171 | } |
| 172 | |
| 173 | /** Return the dimensions of the viewport */ |
| 174 | public Dimension getViewportSize() { |
| 175 | int vpW, vpH; |
| 176 | Dimension size = getSize(); |
| 177 | vpW = size.width; |
| 178 | vpH = size.height; |
| 179 | if (showingYScroll) |
| 180 | vpW -= yScroller.getSize().width; |
| 181 | if (showingXScroll) |
| 182 | vpH -= xScroller.getSize().height; |
| 183 | |
| 184 | return new Dimension(vpW, vpH); |
| 185 | } |
| 186 | |
| 187 | /** |
| 188 | * Ensure that the scroll pane is properly arranged after |
| 189 | * a component is added, the pane is resized, etc. |
| 190 | */ |
| 191 | public void doLayout() { |
| 192 | /** Add scroll bars as necessary */ |
| 193 | boolean needX = false, needY = false; |
| 194 | Dimension innerSize = containedComp.getPreferredSize(); |
| 195 | Dimension scrollDimension = getSize(); |
| 196 | |
| 197 | if (innerSize.width > scrollDimension.width) |
| 198 | needX = true; |
| 199 | if (innerSize.height > scrollDimension.height) |
| 200 | needY = true; |
| 201 | |
| 202 | showingXScroll = false; |
| 203 | showingYScroll = false; |
| 204 | remove(yScroller); |
| 205 | remove(xScroller); |
| 206 | |
| 207 | if (needY) { |
| 208 | gbc.gridy = 0; |
| 209 | gbc.gridx = 1; |
| 210 | gbc.weightx = 0; |
| 211 | gb.setConstraints(yScroller, gbc); |
| 212 | add(yScroller); |
| 213 | showingYScroll = true; |
| 214 | } |
| 215 | |
| 216 | if (needX) { |
| 217 | gbc.gridy = 1; |
| 218 | gbc.gridx = 0; |
| 219 | gbc.weightx = 100; |
| 220 | gbc.weighty = 0; |
| 221 | gb.setConstraints(xScroller, gbc); |
| 222 | add(xScroller); |
| 223 | showingXScroll = true; |
| 224 | } |
| 225 | |
| 226 | /* set scroll bar values */ |
| 227 | int vpW, vpH; |
| 228 | vpW = scrollDimension.width; |
| 229 | vpH = scrollDimension.height; |
| 230 | if (showingYScroll) |
| 231 | vpW -= yScroller.getSize().width; |
| 232 | if (showingXScroll) |
| 233 | vpH -= xScroller.getSize().height; |
| 234 | yScroller.setValues(0, vpH, 0, innerSize.height); |
| 235 | xScroller.setValues(0, vpW, 0, innerSize.width); |
| 236 | |
| 237 | containedComp.setLocation(0, 0); |
| 238 | super.doLayout(); |
| 239 | } |
| 240 | |
| 241 | /** |
| 242 | * Adjustment listener method for receiving callbacks |
| 243 | * from scroll actions. |
| 244 | * |
| 245 | * @param e the AdjustmentEvent |
| 246 | * @return void |
| 247 | */ |
| 248 | public void adjustmentValueChanged(AdjustmentEvent e) { |
| 249 | Point p = containedComp.getLocation(); |
| 250 | if (e.getAdjustable() == xScroller) { |
| 251 | p.x = -e.getValue(); |
| 252 | scrollPosition.x = e.getValue(); |
| 253 | } else { |
| 254 | p.y = -e.getValue(); |
| 255 | scrollPosition.y = e.getValue(); |
| 256 | } |
| 257 | containedComp.setLocation(p); |
| 258 | } |
| 259 | |
| 260 | } |