Replace SuperTabNavigator (not compatible with Flex 4) with standard TabNavigator...
[potlatch2.git] / net / systemeD / potlatch2 / Toolbox.mxml
1 <?xml version="1.0" encoding="utf-8"?>
2 <mx:Panel
3     xmlns:fx="http://ns.adobe.com/mxml/2009"
4         xmlns:mx="library://ns.adobe.com/flex/mx"
5         xmlns:potlatch2="net.systemeD.potlatch2.*"
6         height="76" width="129" layout="absolute"
7         styleName="theToolBox">
8
9         <fx:Declarations>
10         <!-- the animation effect that controls the rotation of the reverse arrow.
11               We could get more fancy by using previous angle in angleFrom, and a longer duration, to give a nice animated effect -->
12         <mx:Rotate id="rotate" angleFrom="{angle-1}" angleTo="{angle}" target="{arrowBox}" originX="{arrowBox.width/2}" originY="{arrowBox.height/2}" duration="4"/>
13         </fx:Declarations>
14
15                 <mx:Image data="@Embed('../../../embedded/close_small.png')"
16                         includeInLayout="false" id="toolboxClose" click="toggle();" 
17                         y="-6" x="115" />
18
19                 <!-- Top row -->
20
21                 <mx:Button icon="@Embed('../../../embedded/delete.svg')"
22                         click='doDelete();' 
23                         enabled="{canDo('delete')}" 
24                         alpha="{getAlpha('delete')}" 
25                         toolTip="{deleteToolTipText()}" 
26                         width="28" height="28" textAlign="left" y="4" x="6" paddingLeft="6" paddingRight="0" />
27
28         <mx:HBox id="reverseButton" width="28" height="28" y="4" x="36" borderStyle="solid" cornerRadius="4"
29                   click="reverseClicked();" horizontalAlign="center" verticalAlign="middle" toolTip="Reverse direction (V)">
30             <mx:ViewStack id="rotateButtonStack" creationPolicy="all">
31                 <mx:HBox id="arrowBoxWrapper"><!-- changing the viewstack back onto a rotated hbox causes positioning glitches, hence this wrapper -->
32                     <!-- I can totally recommend adding borderStyle="solid" to arrowBox when debugging -->
33                     <mx:HBox id="arrowBox" horizontalAlign="center" verticalAlign="middle" width="24" height="24" borderStyle="solid" >
34                         <mx:Image id="arrow" source="@Embed('../../../embedded/arrow.svg')"
35                             alpha="{getAlpha('reverseDirection')}"
36                             width="22" height="22"/>
37                     </mx:HBox>
38                 </mx:HBox>
39                 <mx:HBox id="clockwiseBox" horizontalAlign="center" verticalAlign="middle">
40                     <mx:Image id="clockwise" source="@Embed('../../../embedded/clockwise.svg')"
41                         alpha="{getAlpha('reverseDirection')}"
42                         width="22" height="22" x="2" y="2"/>
43                 </mx:HBox>
44                 <mx:HBox id="antiClockwiseBox" horizontalAlign="center" verticalAlign="middle">
45                     <mx:Image id="anticlockwise" source="@Embed('../../../embedded/anti-clockwise.svg')"
46                         click='doReverseDirection();'
47                         enabled="{canDo('reverseDirection')}"
48                         alpha="{getAlpha('reverseDirection')}"
49                         width="22" height="22" x="2" y="2"/>
50                 </mx:HBox>
51             </mx:ViewStack>
52         </mx:HBox>
53                 <mx:Button icon="@Embed('../../../embedded/cut.svg')" 
54                         id="splitButton"
55                         click='doSplit();'
56                         enabled="{canDo('split')}" 
57                         alpha="{getAlpha('split')}" 
58                         toolTip="Split way (X)" 
59                         width="28" height="28" textAlign="left" y="4" x="66" paddingLeft="8" paddingRight="0" />
60                 <mx:Button icon="@Embed('../../../embedded/merge.svg')" 
61                         id="mergeButton"
62                         click='doMerge();'
63                         enabled="{canDo('merge')}" 
64                         alpha="{getAlpha('merge')}" 
65                         toolTip="Merge ways" 
66                         width="28" height="28" textAlign="left" y="4" x="96" paddingLeft="3" paddingRight="0" />
67
68                 <!-- Second row -->
69
70                 <mx:Button icon="@Embed('../../../embedded/straighten.svg')" 
71                         id="straightenButton"
72                         click='doStraighten();' 
73                         enabled="{canDo('straighten')}" 
74                         alpha="{getAlpha('straighten')}" 
75                         toolTip="Straighten way" 
76                         width="28" height="28" textAlign="left" y="34" x="6" paddingLeft="5" paddingRight="0" />
77                 <mx:Button icon="@Embed('../../../embedded/circle.svg')" 
78                         id="circulariseButton"
79                         click='doCircularise();' 
80                         enabled="{canDo('circularise')}" 
81                         alpha="{getAlpha('circularise')}" 
82                         toolTip="Make circular" 
83                         width="28" height="28" textAlign="left" y="34" x="36" paddingLeft="4" paddingRight="0" />
84                 <mx:Button icon="@Embed('../../../embedded/quadrilateralise.svg')" 
85                         id="quadrilateraliseButton"
86                         click='doQuadrilateralise();' 
87                         enabled="{canDo('quadrilateralise')}" 
88                         alpha="{getAlpha('quadrilateralise')}" 
89                         toolTip="Make right-angled (Q)"
90                         width="28" height="28" textAlign="left" y="34" x="66" paddingLeft="6" paddingRight="0" />
91                 <mx:Button icon="@Embed('../../../embedded/parallel.svg')" 
92                         id="parralleliseButton"
93                         click='doParallelise();' 
94                         enabled="{canDo('parallelise')}" 
95                         alpha="{getAlpha('parallelise')}" 
96                         toolTip="Create parallel way (P)" 
97                         width="28" height="28" textAlign="left" y="34" x="96" paddingLeft="8" paddingRight="0" />
98
99         <fx:Script><![CDATA[
100
101                 import flash.events.Event;
102                 import flash.events.MouseEvent;
103                 import net.systemeD.halcyon.connection.*;
104                 import net.systemeD.halcyon.connection.actions.*;
105                 import net.systemeD.potlatch2.controller.*;
106                 import net.systemeD.potlatch2.tools.*;
107
108                 private var controller:EditController;
109
110         [Bindable]
111         public var angle:int=0;
112
113         public var deleteNode:String = "Delete Node (Delete)";
114         public var deleteArea:String = "Delete Area (Shift+Delete)";
115         public var deleteWay:String = "Delete Way (Shift+Delete)";
116         public var deleteItem:String = "Delete Item"; // When nothing is selected
117
118                 public function init(controller:EditController):void {
119                         this.controller=controller;
120                         /* check if the toolbox was explictly turned off in a previous session */
121                         if( SharedObject.getLocal("user_state").data['toolbox_visible'] == false) {
122                           this.visible = false;
123                         }
124                 }
125
126                 override protected function createChildren():void {
127                         super.createChildren();
128                         super.titleBar.addEventListener(MouseEvent.MOUSE_DOWN,handleDown);
129                 }
130
131                 public function updateSelectionUI():void {
132                         dispatchEvent(new Event("updateSkin"));
133                         dispatchEvent(new Event("updateAlpha"));
134                         updateDirectionArrow();
135                 }
136
137                 private function handleDown(e:Event):void {
138                         this.startDrag();
139                         stage.addEventListener(MouseEvent.MOUSE_UP,handleUp);
140                 }
141
142                 private function handleUp(e:Event):void {
143                         this.stopDrag();
144                         stage.removeEventListener(MouseEvent.MOUSE_UP,handleUp);
145                 }
146                 
147                 public function toggle():void {
148                         this.visible=!this.visible;
149                         var obj:SharedObject = SharedObject.getLocal("user_state");
150                         obj.setProperty("toolbox_visible",this.visible);
151                         obj.flush();
152                 }
153                 
154                 // --------------------------------------------------------------------------------
155                 // Enable/disable toolbox buttons
156                 // (ideally we'd use CSS to set alpha in disabled state, but Flex's CSS
157                 //      capabilities aren't up to it)
158                 
159                 [Bindable(event="updateSkin")]
160                 public function canDo(op:String):Boolean {
161                         if (controller.state.selectCount==0) return false;
162
163                         switch (op) {
164                                 case 'delete':                          return true;
165                                 case 'reverseDirection':        return controller.state.hasSelectedWays();
166                                 case 'quadrilateralise':        return (controller.state.hasSelectedAreas() || controller.state.hasSelectedWayNodesInAreas());
167                                 case 'straighten':                      return controller.state.hasSelectedUnclosedWays();
168                                 case 'circularise':                     return controller.state.hasSelectedAreas();
169                                 case 'split':                           return (controller.state is SelectedWayNode);
170                                 case 'parallelise':                     return (controller.state is SelectedWay);
171                                 case 'merge':                           return controller.state.hasAdjoiningWays();
172                         }
173                         return false;
174                 }
175
176                 [Bindable(event="updateAlpha")]
177                 public function getAlpha(op:String):Number {
178                         if (canDo(op)) { return 1; }
179                         return 0.5;
180                 }
181
182                 [Bindable(event="updateSkin")]
183                 private function deleteToolTipText():String {
184                         var entity:Entity=controller.state.firstSelected;
185                         if (entity is Node) { return deleteNode; }
186                         if (entity is Way && Way(entity).isArea()) { return deleteArea; }
187                         if (entity is Way) { return deleteWay; }
188                         return deleteItem; // When nothing is selected
189                 }
190
191         private function updateDirectionArrow():void {
192             if (controller.state is SelectedWay) {
193                 var w:Way = Way(controller.state.firstSelected);
194                 if (w) { // not entirely sure why this protection is necessary, but it appears so
195                     if (w.isArea()) {
196                         // so Way.clockwise appears to give wrong results. Patches welcome, I guess, but for now...
197                         w.clockwise? rotateButtonStack.selectedChild = antiClockwiseBox : rotateButtonStack.selectedChild = clockwiseBox;
198                     } else {
199                         rotateButtonStack.selectedChild = arrowBoxWrapper;
200                         // reset and reposition back to the starting point relative to its parent
201                         rotate.end();
202                         angle = 0;
203                         rotate.play();
204                         arrowBox.x = 0;
205                         arrowBox.y = 0;
206
207                         // move
208                         rotate.end();
209                         angle = w.angle;
210                         rotate.play();
211                     }
212                 }
213             }
214         }
215
216         private function reverseClicked():void {
217             if(canDo('reverseDirection')) {
218                 doReverseDirection();
219             }
220         }
221
222                 // --------------------------------------------------------------------------------
223                 // Individual toolbox actions
224
225                 public function doDelete():void {
226                         var undo:CompositeUndoableAction = new CompositeUndoableAction("Delete objects");
227                         for each (var entity:Entity in controller.state.selection) {
228                                 if (entity is Node) { entity.connection.unregisterPOI(Node(entity)); }
229                                 entity.remove(undo.push);
230                         }
231                         MainUndoStack.getGlobalStack().addAction(undo);
232
233                         if (controller.state is SelectedWayNode) {
234                                 controller.setState(new SelectedWay(SelectedWayNode(controller.state).selectedWay));
235                         } else {
236                                 controller.setState(new NoSelection());
237                         }
238                 }
239                 
240                 public function doMerge():void {
241                         controller.setState(SelectedMultiple(controller.state).mergeWays());
242                 }
243
244                 public function doReverseDirection():void {
245                         var undo:CompositeUndoableAction = new CompositeUndoableAction("Reverse direction of objects");
246                         for each (var way:Way in controller.state.selectedWays) {
247                                 way.reverseNodes(undo.push);
248                         }
249                         MainUndoStack.getGlobalStack().addAction(undo);
250                 }
251
252                 public function doQuadrilateralise():void {
253                         var undo:CompositeUndoableAction = new CompositeUndoableAction("Make objects right-angled");
254                         for each (var way:Way in controller.state.selectedWays) {
255                                 Quadrilateralise.quadrilateralise(way, undo.push);
256                         }
257             for each (var node:Node in controller.state.selectedNodes) {
258                 for each (var parentWay:Way in node.parentWays) {
259                   Quadrilateralise.quadrilateralise(parentWay, undo.push);
260                 }
261             }
262                         MainUndoStack.getGlobalStack().addAction(undo);
263                 }
264
265                 public function doStraighten():void {
266                         var undo:CompositeUndoableAction = new CompositeUndoableAction("Straighten objects");
267                         for each (var way:Way in controller.state.selectedWays) {
268                                 Straighten.straighten(way, controller.map, undo.push);
269                         }
270                         MainUndoStack.getGlobalStack().addAction(undo);
271                 }
272
273                 public function doCircularise():void {
274                         var undo:CompositeUndoableAction = new CompositeUndoableAction("Make objects circular ");
275                         for each (var way:Way in controller.state.selectedWays) {
276                                 Circularise.circularise(way, controller.map, undo.push);
277                         }
278                         MainUndoStack.getGlobalStack().addAction(undo);
279                 }
280
281                 public function doSplit():void {
282                         if (controller.state is SelectedWayNode) {
283                                 controller.setState(SelectedWayNode(controller.state).splitWay());
284                         }
285                 }
286                 
287                 public function doParallelise():void {
288                         if (controller.state is SelectedWay) {
289                                 controller.setState(new SelectedParallelWay(Way(controller.state.firstSelected)));
290                         }
291                 }
292
293
294         ]]>
295 </fx:Script>
296 </mx:Panel>