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