1
4 import org.aswing.Component;
5 import org.aswing.Container;
6 import org.aswing.Event;
7 import org.aswing.geom.Dimension;
8 import org.aswing.Insets;
9 import org.aswing.JAccordion;
10 import org.aswing.LookAndFeel;
11 import org.aswing.plaf.AccordionUI;
12 import org.aswing.plaf.basic.accordion.AccordionHeader;
13 import org.aswing.plaf.basic.accordion.BasicAccordionHeader;
14 import org.aswing.utils.Timer;
15
16
20 class org.aswing.plaf.basic.BasicAccordionUI extends AccordionUI {
21
22 private static var MOTION_SPEED:Number = 50;
23 private static var MOTION_CYCLE:Number = 40;
24
25 private var accordion:JAccordion;
26 private var headers:Array;
27 private var stateListener:Object;
28 private var motionTimer:Timer;
29 private var headerDestinations:Array;
30 private var childrenDestinations:Array;
31
32 public function BasicAccordionUI() {
33 super();
34 }
35
36 public function installUI(c:Component):Void{
37 headers = new Array();
38 accordion = JAccordion(c);
39 installDefaults();
40 installComponents();
41 installListeners();
42 }
43
44 public function uninstallUI(c:Component):Void{
45 accordion = JAccordion(c);
46 uninstallDefaults();
47 uninstallComponents();
48 uninstallListeners();
49 }
50
51 private function installDefaults():Void{
52 var pp:String = "Accordion.";
53 LookAndFeel.installBorder(accordion, pp + "border");
54 LookAndFeel.installColorsAndFont(accordion, pp + "background", pp + "foreground", pp + "font");
55 }
56
57 private function uninstallDefaults():Void{
58 LookAndFeel.uninstallBorder(accordion);
59 }
60
61 private function installComponents():Void{
62 __synTabs();
63 }
64 private function uninstallComponents():Void{
65 for(var i:Number=0; i<headers.length; i++){
66 getHeader(i).getComponent().destroy();
67 }
68 headers.splice(0);
69 }
70
71 private function installListeners():Void{
72 stateListener = accordion.addEventListener(Component.ON_STATE_CHANGED, __selectionChanged, this);
73 motionTimer = new Timer(MOTION_CYCLE);
74 motionTimer.addActionListener(__motion, this);
75 }
76
77 private function uninstallListeners():Void{
78 accordion.removeEventListener(stateListener);
79 motionTimer.stop();
80 }
81
82
85 private function createNewHeader():AccordionHeader{
86 return new BasicAccordionHeader();
87 }
88
89 private function __synTabs():Void{
90 var comCount:Number = accordion.getComponentCount();
91 if(comCount != headers.length){
92 if(comCount > headers.length){
93 for(var i:Number = headers.length; i<comCount; i++){
94 var header:AccordionHeader = createNewHeader();
95 header.setTextAndIcon(accordion.getTitleAt(i), accordion.getIconAt(i));
96 header.getComponent().setToolTipText(accordion.getTipAt(i));
97 header.getComponent().addEventListener(Component.ON_RELEASE, __tabPressed, this);
98 header.getComponent().addTo(accordion);
99 headers.push(header);
100 }
101 }else{
102 for(var i:Number = headers.length-comCount; i>0; i--){
103 var header:AccordionHeader = AccordionHeader(headers.pop());
104 header.getComponent().destroy();
105 }
106 }
107 }
108 }
109
110 private function __ensureHeadersDisplayable():Void{
111 for(var i:Number=0; i<headers.length; i++){
112 var header:AccordionHeader = getHeader(i);
113 header.setTextAndIcon(accordion.getTitleAt(i), accordion.getIconAt(i));
114 header.getComponent().setToolTipText(accordion.getTipAt(i));
115 if(!header.getComponent().isDisplayable()){
116 header.getComponent().addTo(accordion);
117 }
118 }
119 }
120
121 private function __ensureHeadersOnTopDepths():Void{
122 if(accordion.getComponentCount()<=0){
123 return;
124 }
125 var firstComDepth:Number = accordion.getComponent(0).getDepth();
126 if(firstComDepth == undefined){
127 return;
128 }
129
130 for(var i:Number=0; i<headers.length; i++){
131 var header:AccordionHeader = getHeader(i);
132
133 if(header.getComponent().isDisplayable()){
134 var needDepth:Number = firstComDepth + headers.length + i;
135 if(header.getComponent().getDepth() != needDepth){
136 header.getComponent().swapDepths(needDepth);
137
138 }
139 }
140 }
141 }
142
143 public function create(c:Component):Void{
144 __ensureHeadersDisplayable();
145 __ensureHeadersOnTopDepths();
146 }
147
148 private function getHeader(i:Number):AccordionHeader{
149 return AccordionHeader(headers[i]);
150 }
151
152 private function indexOfHeaderComponent(tab:Component):Number{
153 for(var i:Number=0; i<headers.length; i++){
154 if(getHeader(i).getComponent() == tab){
155 return i;
156 }
157 }
158 return -1;
159 }
160
161 private function __selectionChanged(event:Event):Void{
162 accordion.revalidate();
163 }
164
165 private function __tabPressed(event:Event):Void{
166 accordion.setSelectedIndex(indexOfHeaderComponent(Component(event.getSource())));
167 }
168
169
170
171
174 public function addLayoutComponent(comp:Component, constraints:Object):Void{
175 __synTabs();
176 }
177
178
181 public function removeLayoutComponent(comp:Component):Void{
182 __synTabs();
183 }
184
185
188 public function preferredLayoutSize(target:Container):Dimension{
189 if(target === accordion){
190 var insets:Insets = accordion.getInsets();
191
192 var w:Number = 0;
193 var h:Number = 0;
194
195 for(var i:Number=accordion.getComponentCount()-1; i>=0; i--){
196 var size:Dimension = accordion.getComponent(i).getPreferredSize();
197 w = Math.max(w, size.width);
198 h = Math.max(h, size.height);
199 }
200
201 for(var i:Number=accordion.getComponentCount()-1; i>=0; i--){
202 var size:Dimension = getHeader(i).getComponent().getPreferredSize();
203 w = Math.max(w, size.width);
204 h += size.height;
205 }
206
207 return insets.roundsSize(new Dimension(w, h));
208 }
209 return null;
210 }
211
212
215 public function minimumLayoutSize(target:Container):Dimension{
216 if(target === accordion){
217 var insets:Insets = accordion.getInsets();
218
219 var w:Number = 0;
220 var h:Number = 0;
221
222 for(var i:Number=accordion.getComponentCount()-1; i>=0; i--){
223 var size:Dimension = accordion.getComponent(i).getMinimumSize();
224 w = Math.max(w, size.width);
225 }
226
227 for(var i:Number=accordion.getComponentCount()-1; i>=0; i--){
228 var size:Dimension = getHeader(i).getComponent().getMinimumSize();
229 w = Math.max(w, size.width);
230 h += size.height;
231 }
232
233 return insets.roundsSize(new Dimension(w, h));
234 }
235 return null;
236 }
237
238 private function __motion():Void{
239 var isFinished:Boolean = true;
240 var n:Number = headerDestinations.length;
241 var selected:Number = accordion.getSelectedIndex();
242
243 for(var i:Number=0; i<n; i++){
244 var header:AccordionHeader = getHeader(i);
245 var tab:Component = header.getComponent();
246 var curY:Number = tab.getY();
247 var desY:Number = headerDestinations[i];
248 var toY:Number;
249 if(Math.abs(desY - curY) <= MOTION_SPEED){
250 toY = desY;
251 }else{
252 if(desY > curY){
253 toY = curY + MOTION_SPEED;
254 }else{
255 toY = curY - MOTION_SPEED;
256 }
257 isFinished = false;
258 }
259 tab.setLocation(tab.getX(), toY);
260 tab.validate();
261 var child:Component = accordion.getComponent(i);
262 child.setLocation(child.getX(), toY + tab.getHeight());
263 child.validate();
264 }
265
266 if(isFinished){
267 motionTimer.stop();
268 for(var i:Number=0; i<n; i++){
269 var child:Component = accordion.getComponent(i);
270 if(selected == i){
271 child.setVisible(true);
272 }else{
273 child.setVisible(false);
274 }
275 }
276 }
277 updateAfterEvent();
278 }
279
280
283 public function layoutContainer(target:Container):Void{
284 var insets:Insets = accordion.getInsets();
285 var x:Number = insets.left;
286 var y:Number = insets.top;
287 var w:Number = accordion.getWidth() - x - insets.right;
288 var h:Number = accordion.getHeight() - y - insets.bottom;
289
290 var count:Number = accordion.getComponentCount();
291 var selected:Number = accordion.getSelectedIndex();
292 if(selected < 0){
293 return;
294 }
295
296 headerDestinations = new Array(count);
297
298 var vX:Number, vY:Number, vWidth:Number, vHeight:Number;
299 vHeight = h;
300 vWidth = w;
301 vX = x;
302 for(var i:Number=0; i<=selected; i++){
303 var header:AccordionHeader = getHeader(i);
304 var tab:Component = header.getComponent();
305 var size:Dimension = tab.getPreferredSize();
306 tab.setSize(w, size.height);
307 tab.setLocation(x, tab.getY());
308 accordion.getComponent(i).setLocation(x, tab.getY()+size.height);
309 headerDestinations[i] = y;
310 y += size.height;
311 vHeight -= size.height;
312 if(i == selected){
313 header.setSelected(true);
314 accordion.getComponent(i).setVisible(true);
315 }else{
316 header.setSelected(false);
317 }
318 tab.validate();
319 }
320 vY = y;
321
322 y = accordion.getHeight() - insets.bottom;
323 for(var i:Number=count-1; i>selected; i--){
324 var header:AccordionHeader = getHeader(i);
325 var tab:Component = header.getComponent();
326 var size:Dimension = tab.getPreferredSize();
327 y -= size.height;
328 headerDestinations[i] = y;
329 tab.setSize(w, size.height);
330 tab.setLocation(x, tab.getY());
331 accordion.getComponent(i).setLocation(x, tab.getY()+size.height);
332 header.setSelected(false);
333 vHeight -= size.height;
334 tab.validate();
335 }
336 for(var i:Number=0; i<count; i++){
337 accordion.getComponent(i).setSize(vWidth, vHeight);
338 }
339 motionTimer.restart();
340 __ensureHeadersOnTopDepths();
341 }
342
343
344 }
345