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