1 import org.aswing.ASColor;
2 import org.aswing.ASWingUtils;
3 import org.aswing.border.LineBorder;
4 import org.aswing.Component;
5 import org.aswing.Container;
6 import org.aswing.ElementCreater;
7 import org.aswing.geom.Dimension;
8 import org.aswing.geom.Point;
9 import org.aswing.geom.Rectangle;
10 import org.aswing.graphices.Graphics;
11 import org.aswing.graphices.SolidBrush;
12 import org.aswing.Insets;
13 import org.aswing.JButton;
14 import org.aswing.JComboBox;
15 import org.aswing.JList;
16 import org.aswing.JScrollPane;
17 import org.aswing.LayoutManager;
18 import org.aswing.LookAndFeel;
19 import org.aswing.MCPanel;
20 import org.aswing.plaf.basic.icon.ArrowIcon;
21 import org.aswing.plaf.ComboBoxUI;
22 import org.aswing.UIManager;
23 import org.aswing.utils.Delegate;
24 import org.aswing.utils.Timer;
25
26
29 class org.aswing.plaf.basic.BasicComboBoxUI extends ComboBoxUI implements LayoutManager{
30
31 private var dropDownButton:Component;
32 private var box:JComboBox;
33 private var mcPane:MCPanel;
34 private var maskMC:MovieClip;
35 private var scollPane:JScrollPane;
36 private var mouseListener:Object;
37 private var listListener:Object;
38 private var boxListener:Object;
39
40 private var popupTimer:Timer;
41 private var popupDestinationY:Number;
42 private var moveDir:Number;
43
44 private var shadowColor:ASColor;
45
46 public function BasicComboBoxUI() {
47 super();
48 }
49
50 public function installUI(c:Component):Void{
51 box = JComboBox(c);
52 installDefaults();
53 installComponents();
54 installListeners();
55 }
56
57 public function uninstallUI(c:Component):Void{
58 box = JComboBox(c);
59 uninstallDefaults();
60 uninstallComponents();
61 uninstallListeners();
62 }
63
64 private function installDefaults():Void{
65 var pp:String = "ComboBox.";
66 LookAndFeel.installBorder(box, pp + "border");
67 LookAndFeel.installColorsAndFont(box, pp + "background", pp + "foreground", pp + "font");
68 LookAndFeel.installBasicProperties(box, pp);
69 box.setLayout(this);
70 shadowColor = UIManager.getColor("ComboBox.shadow");
71 }
72
73 private function uninstallDefaults():Void{
74 LookAndFeel.uninstallBorder(box);
75 }
76
77 private function installComponents():Void{
78 dropDownButton = createDropDownButton();
79 box.append(dropDownButton);
80 }
81 private function uninstallComponents():Void{
82 box.remove(dropDownButton);
83 }
84
85 private var dropDownListener:Object;
86 private function installListeners():Void{
87 dropDownListener = dropDownButton.addEventListener(Component.ON_PRESS, __onDropDownPressed, this);
88
89 mouseListener = {onMouseDown:Delegate.create(this, __onMouseDown)};
90
91 listListener = new Object();
92 listListener[JList.ON_ITEM_RELEASE] = listListener[JList.ON_ITEM_RELEASEOUTSIDE] = Delegate.create(this, __listItemReleased);
93 getPopupList().addEventListener(listListener);
94
95 boxListener = box.addEventListener(Component.ON_PRESS, __onDropDownPressed, this);
96
97 popupTimer = new Timer(40);
98 popupTimer.addActionListener(__movePopup, this);
99 }
100
101 private function uninstallListeners():Void{
102 dropDownButton.removeEventListener(dropDownListener);
103 getPopupList().removeEventListener(listListener);
104 box.removeEventListener(boxListener);
105 popupTimer.stop();
106 popupTimer = null;
107 }
108
109 private function paintBackGround(c:Component, g:Graphics, b:Rectangle):Void{
110 if(c.isOpaque()){
111 var bgColor:ASColor;
112 if(box.isEditable()){
113 bgColor = (c.getBackground() == null ? ASColor.WHITE : c.getBackground());
114 }else{
115 bgColor = shadowColor;
116 }
117 g.fillRectangle(new SolidBrush(bgColor), b.x, b.y, b.width, b.height);
118 }
119 }
120
121
124 private function createDropDownButton():Component{
125 var btn:JButton = new JButton(new ArrowIcon(
126 Math.PI/2, 5,
127 new ASColor(0x000000,100),
128 new ASColor(0x666666,100),
129 new ASColor(0x666666,100),
130 new ASColor(0xFF0000,100)
131 ));
132 btn.setPreferredSize(16, 16);
133 return btn;
134 }
135
136 private function getMCPane():MCPanel{
137 if(mcPane == null){
138 mcPane = new MCPanel(ASWingUtils.getRootMovieClip(), 10000, 10000);
139 }
140 return mcPane;
141 }
142 private function getScollPane():JScrollPane{
143 if(scollPane == null){
144 scollPane = new JScrollPane(getPopupList());
145 scollPane.setBorder(new LineBorder());
146 scollPane.setOpaque(true);
147 }
148 return scollPane;
149 }
150 private function getPopupList():JList{
151 return box.getPopupList();
152 }
153 private function viewPopup():Void{
154 var popupPane:JScrollPane = getScollPane();
155 var mcPanel:MCPanel = getMCPane();
156 if(!mcPanel.contains(popupPane)){
157 mcPanel.append(popupPane);
158 var paneMC:MovieClip = mcPanel.getPanelMC();
159 var width:Number = box.getWidth();
160 var cellHeight:Number;
161 if(box.getListCellFactory().isAllCellHasSameHeight()){
162 cellHeight = box.getListCellFactory().getCellHeight();
163 }else{
164 cellHeight = box.getPreferredSize().height;
165 }
166 var height:Number = Math.min(box.getItemCount(), box.getMaximumRowCount())*cellHeight;
167 var i:Insets = getScollPane().getInsets();
168 height += i.top + i.bottom;
169 i = getPopupList().getInsets();
170 height += i.top + i.bottom;
171 popupPane.setSize(width, height);
172
173 var p:Point = startMoveToView(height);
174
175 Mouse.addListener(mouseListener);
176 dropDownButton.setTriggerEnabled(false);
177 box.setTriggerEnabled(false);
178
179 var popupPaneMC:MovieClip = MovieClip(paneMC.getInstanceAtDepth(paneMC.getNextHighestDepth()-1));
180 maskMC = ElementCreater.getInstance().createMC(paneMC, "comb_pop_mask");
181 if(popupPaneMC != undefined){
182 var g:Graphics = new Graphics(maskMC);
183 g.fillRectangle(new SolidBrush(0), p.x, p.y, width, height);
184 popupPaneMC.setMask(maskMC);
185 }else{
186 trace("Mask popup list failed!");
187 maskMC.removeMovieClip();
188 maskMC = null;
189 }
190 }
191 }
192 private function hidePopup():Void{
193 getMCPane().remove(getScollPane());
194 maskMC.unloadMovie();
195 maskMC.removeMovieClip();
196 maskMC = null;
197 Mouse.removeListener(mouseListener);
198 dropDownButton.setTriggerEnabled(true);
199 box.setTriggerEnabled(true);
200 popupTimer.stop();
201 }
202
203 private function startMoveToView(height:Number):Point{
204 var popupPane:JScrollPane = getScollPane();
205 var popupPaneHeight:Number = height;
206 var downDest:Point = box.componentToGlobal(new Point(0, box.getHeight()));
207 var upDest:Point = new Point(downDest.x, downDest.y - box.getHeight() - popupPaneHeight);
208 var visibleBounds:Rectangle = ASWingUtils.getVisibleMaximizedBounds();
209
210 var distToBottom:Number = visibleBounds.y + visibleBounds.height - downDest.y - popupPaneHeight;
211 var distToTop:Number = upDest.y - visibleBounds.y;
212
213 var dest:Point;
214 if(distToBottom > 0 || (distToBottom < 0 && distToTop < 0 && distToBottom > distToTop)){
215 moveDir = 1;
216 popupDestinationY = downDest.y;
217 popupPane.setGlobalLocation(downDest.x, popupDestinationY - popupPaneHeight);
218 dest = downDest;
219 }else{
220 moveDir = -1;
221 popupDestinationY = upDest.y;
222 popupPane.setGlobalLocation(upDest.x, popupDestinationY + popupPaneHeight);
223 dest = upDest;
224 }
225
226 popupTimer.restart();
227
228 return new Point(dest);
229 }
230
231 private function __movePopup():Void{
232 var popupPane:JScrollPane = getScollPane();
233 var popupPaneHeight:Number = popupPane.getHeight();
234 var maxTime:Number = 10;
235 var minTime:Number = 3;
236 var speed:Number = 50;
237 if(popupPaneHeight < speed*minTime){
238 speed = Math.ceil(popupPaneHeight/minTime);
239 }else if(popupPaneHeight > speed*maxTime){
240 speed = Math.ceil(popupPaneHeight/maxTime);
241 }
242 var p:Point = popupPane.getGlobalLocation();
243 if(Math.abs(popupDestinationY - p.y) < speed){
244 p.y = popupDestinationY;
245 popupPane.setLocation(p);
246 popupTimer.stop();
247 }else if(moveDir > 0){
248 p.y += speed;
249 popupPane.setLocation(p);
250 }else{
251 p.y -= speed;
252 popupPane.setLocation(p);
253 }
254 popupPane.revalidate();
255 updateAfterEvent();
256 }
257 private function __listItemReleased():Void{
258 hidePopup();
259 var selectedValue:Object = getPopupList().getSelectedValue();
260 box.setSelectedItem(selectedValue);
261 }
262 private function __onDropDownPressed():Void{
263 if(!isPopupVisible(box)){
264 setPopupVisible(box, true);
265 }
266 }
267 private function __onMouseDown():Void{
268 if(!getScollPane().hitTest(_root._xmouse, _root._ymouse)){
269 hidePopup();
270 }
271 }
272
273
276 public function setPopupVisible(c:JComboBox, v:Boolean):Void{
277 if(v){
278 viewPopup();
279 }else{
280 hidePopup();
281 }
282 }
283
284
287 public function isPopupVisible(c:JComboBox):Boolean{
288 return getScollPane().isDisplayable() && getScollPane().isVisible();
289 }
290
291
294 public function isFocusTraversable(c:JComboBox):Boolean{
295 return false;
296 }
297
298
299
300
303 public function addLayoutComponent(comp:Component, constraints:Object):Void{
304 }
305
306
309 public function removeLayoutComponent(comp:Component):Void{
310 }
311
312 public function preferredLayoutSize(target:Container):Dimension{
313 var insets:Insets = box.getInsets();
314 var listPreferSize:Dimension = getPopupList().getPreferredSize();
315 var ew:Number = listPreferSize.width;
316 var wh:Number = box.getEditor().getEditorComponent().getPreferredSize().height;
317 var buttonSize:Dimension = dropDownButton.getPreferredSize();
318 buttonSize.width += ew;
319 if(wh > buttonSize.height){
320 buttonSize.height = wh;
321 }
322 return insets.roundsSize(buttonSize);
323 }
324
325 public function minimumLayoutSize(target:Container):Dimension{
326 return box.getInsets().roundsSize(dropDownButton.getPreferredSize());
327 }
328
329
332 public function maximumLayoutSize(target:Container):Dimension{
333 return new Dimension(Number.MAX_VALUE, Number.MAX_VALUE);
334 }
335
336
339 public function layoutContainer(target:Container):Void{
340 var td:Dimension = target.getSize();
341 var insets:Insets = target.getInsets();
342 var top:Number = insets.top;
343 var bottom:Number = td.height - insets.bottom;
344 var left:Number = insets.left;
345 var right:Number = td.width - insets.right;
346
347 var height:Number = td.height - insets.top - insets.bottom;
348 var buttonSize:Dimension = dropDownButton.getPreferredSize();
349 dropDownButton.setSize(buttonSize.width, height);
350 dropDownButton.setLocation(right - buttonSize.width, top);
351 box.getEditor().getEditorComponent().setLocation(left, top);
352 box.getEditor().getEditorComponent().setSize(td.width-insets.left-insets.right- buttonSize.width, height);
353 }
354
355
358 public function getLayoutAlignmentX(target:Container):Number{
359 return 0.5;
360 }
361
362
365 public function getLayoutAlignmentY(target:Container):Number{
366 return 0.5;
367 }
368
369
372 public function invalidateLayout(target:Container):Void{
373 }
374 }