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