move way merge to a toolbox function rather than shift-click
[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" 
6         headerHeight="6" headerColors="[black, gray]" 
7         borderThicknessRight="0" borderThicknessLeft="0" borderThicknessBottom="0" 
8         paddingLeft="4" paddingTop="4" layout="absolute" >
9
10                 <mx:Image data="@Embed('../../../embedded/close_small.png')"
11                         includeInLayout="false" id="toolboxClose" click="toggle();" 
12                         y="-6" x="115" />
13
14                 <!-- Top row -->
15
16                 <mx:Button icon="@Embed('../../../embedded/delete.svg')"
17                         click='doDelete();' 
18                         enabled="{canDo('delete')}" 
19                         alpha="{getAlpha('delete')}" 
20                         toolTip="{deleteToolTipText()}" 
21                         width="28" height="28" textAlign="left" y="4" x="6" paddingLeft="6" paddingRight="0" />
22                 <mx:Button icon="@Embed('../../../embedded/direction.svg')" 
23                         click='doReverseDirection();'
24                         enabled="{canDo('reverseDirection')}" 
25                         alpha="{getAlpha('reverseDirection')}" 
26                         toolTip="Reverse direction (V)" 
27                         width="28" height="28" textAlign="left" y="4" x="36" paddingLeft="8" paddingRight="0" />
28                 <mx:Button icon="@Embed('../../../embedded/cut.svg')" 
29                         click='doSplit();'
30                         enabled="{canDo('split')}" 
31                         alpha="{getAlpha('split')}" 
32                         toolTip="Split way (X)" 
33                         width="28" height="28" textAlign="left" y="4" x="66" paddingLeft="8" paddingRight="0" />
34                 <mx:Button icon="@Embed('../../../embedded/merge.svg')" 
35                         click='doMerge();'
36                         enabled="{canDo('merge')}" 
37                         alpha="{getAlpha('merge')}" 
38                         toolTip="Merge ways" 
39                         width="28" height="28" textAlign="left" y="4" x="96" paddingLeft="3" paddingRight="0" />
40
41                 <!-- Second row -->
42
43                 <mx:Button icon="@Embed('../../../embedded/straighten.svg')" 
44                         click='doStraighten();' 
45                         enabled="{canDo('straighten')}" 
46                         alpha="{getAlpha('straighten')}" 
47                         toolTip="Straighten way" 
48                         width="28" height="28" textAlign="left" y="34" x="6" paddingLeft="5" paddingRight="0" />
49                 <mx:Button icon="@Embed('../../../embedded/circle.svg')" 
50                         click='doCircularise();' 
51                         enabled="{canDo('circularise')}" 
52                         alpha="{getAlpha('circularise')}" 
53                         toolTip="Make circular" 
54                         width="28" height="28" textAlign="left" y="34" x="36" paddingLeft="4" paddingRight="0" />
55                 <mx:Button icon="@Embed('../../../embedded/quadrilateralise.svg')" 
56                         click='doQuadrilateralise();' 
57                         enabled="{canDo('quadrilateralise')}" 
58                         alpha="{getAlpha('quadrilateralise')}" 
59                         toolTip="Make right-angled" 
60                         width="28" height="28" textAlign="left" y="34" x="66" paddingLeft="6" paddingRight="0" />
61                 <mx:Button icon="@Embed('../../../embedded/parallel.svg')" 
62                         click='doParallelise();' 
63                         enabled="{canDo('parallelise')}" 
64                         alpha="{getAlpha('parallelise')}" 
65                         toolTip="Create parallel way (P)" 
66                         width="28" height="28" textAlign="left" y="34" x="96" paddingLeft="8" paddingRight="0" />
67
68         <mx:Script><![CDATA[
69
70                 import flash.events.Event;
71                 import flash.events.MouseEvent;
72                 import net.systemeD.halcyon.connection.*;
73                 import net.systemeD.halcyon.connection.actions.*;
74                 import net.systemeD.potlatch2.controller.*;
75                 import net.systemeD.potlatch2.tools.*;
76
77                 private var controller:EditController;
78
79                 public function init(controller:EditController):void {
80                         this.controller=controller;
81                         /* check if the toolbox was explictly turned off in a previous session */
82                         if( SharedObject.getLocal("user_state").data['toolbox_visible'] == false) {
83                           this.visible = false;
84                         }
85                 }
86
87                 override protected function createChildren():void {
88                         super.createChildren();
89                         super.titleBar.addEventListener(MouseEvent.MOUSE_DOWN,handleDown);
90                         super.titleBar.addEventListener(MouseEvent.MOUSE_UP,handleUp);
91                 }
92
93                 public function updateSelectionUI():void {
94                         dispatchEvent(new Event("updateSkin"));
95                         dispatchEvent(new Event("updateAlpha"));
96                 }
97
98                 private function handleDown(e:Event):void {
99                         this.startDrag();
100                 }
101
102                 private function handleUp(e:Event):void {
103                         this.stopDrag();
104                 }
105                 
106                 public function toggle():void {
107                         this.visible=!this.visible;
108                         var obj:SharedObject = SharedObject.getLocal("user_state");
109                         obj.setProperty("toolbox_visible",this.visible);
110                         obj.flush();
111                 }
112                 
113                 // --------------------------------------------------------------------------------
114                 // Enable/disable toolbox buttons
115                 // (ideally we'd use CSS to set alpha in disabled state, but Flex's CSS
116                 //      capabilities aren't up to it)
117                 
118                 [Bindable(event="updateSkin")]
119                 public function canDo(op:String):Boolean {
120                         if (controller.state.selectCount==0) return false;
121
122                         switch (op) {
123                                 case 'delete':                          return true;
124                                 case 'reverseDirection':        return controller.state.hasSelectedWays();
125                                 case 'quadrilateralise':        return controller.state.hasSelectedAreas();
126                                 case 'straighten':                      return controller.state.hasSelectedUnclosedWays();
127                                 case 'circularise':                     return controller.state.hasSelectedAreas();
128                                 case 'split':                           return (controller.state is SelectedWayNode);
129                                 case 'parallelise':                     return (controller.state is SelectedWay);
130                                 case 'merge':                           return controller.state.hasAdjoiningWays();
131                         }
132                         return false;
133                 }
134
135                 [Bindable(event="updateAlpha")]
136                 public function getAlpha(op:String):Number {
137                         if (canDo(op)) { return 1; }
138                         return 0.5;
139                 }
140
141                 [Bindable(event="updateSkin")]
142                 private function deleteToolTipText():String {
143                         var entity:Entity=controller.state.firstSelected;
144                         if (entity is Node) { return "Delete Node (Delete)"; }
145                         if (entity is Way && Way(entity).isArea()) { return "Delete Area (Shift+Delete)"; }
146                         if (entity is Way) { return "Delete Way (Shift+Delete)"; }
147                         return "Delete Item"; // When nothing is selected
148                 }
149
150                 // --------------------------------------------------------------------------------
151                 // Individual toolbox actions
152
153                 public function doDelete():void {
154                         var undo:CompositeUndoableAction = new CompositeUndoableAction("Delete objects");
155                         for each (var entity:Entity in controller.state.selection) {
156                                 if (entity is Node) { controller.connection.unregisterPOI(Node(entity)); }
157                                 entity.remove(undo.push);
158                         }
159                         MainUndoStack.getGlobalStack().addAction(undo);
160
161                         if (controller.state is SelectedWayNode) {
162                                 controller.setState(new SelectedWay(SelectedWayNode(controller.state).selectedWay));
163                         } else {
164                                 controller.setState(new NoSelection());
165                         }
166                 }
167                 
168                 public function doMerge():void {
169                         var changed:Boolean;
170                         var waylist:Array=controller.state.selectedWays;
171                         do {
172                                 // ** FIXME - we should have one CompositeUndoableAction for the whole caboodle,
173                                 // but that screws up the execution order and can make the merge not work
174                                 var undo:CompositeUndoableAction = new CompositeUndoableAction("Merge ways");
175                                 changed=tryMerge(waylist, undo);
176                                 MainUndoStack.getGlobalStack().addAction(undo);
177                         } while (changed==true);
178                         controller.setState(controller.findStateForSelection(waylist));
179                 }
180                 
181                 private function tryMerge(waylist:Array, undo:CompositeUndoableAction):Boolean {
182                         var way1:Way, way2:Way, del:uint;
183                         for (var i:uint=0; i<waylist.length; i++) {
184                                 for (var j:uint=0; j<waylist.length; j++) {
185                                         if (waylist[i]!=waylist[j]) {
186
187                                                 // Preserve positive IDs if we can
188                                                 if (waylist[i].id < waylist[j].id && waylist[i].id >= 0) {
189                                                         way1=waylist[i]; way2=waylist[j]; del=j;
190                                                 } else {
191                                                         way1=waylist[j]; way2=waylist[i]; del=i;
192                                                 }
193
194                                                 // Merge as appropriate
195                                                 if (way1.getNode(0)==way2.getNode(0)) {
196                                                         waylist.splice(del,1);
197                                                         undo.push(new MergeWaysAction(way1,way2,0,0));
198                                                         return true;
199                                                 } else if (way1.getNode(0)==way2.getLastNode()) { 
200                                                         waylist.splice(del,1);
201                                                         undo.push(new MergeWaysAction(way1,way2,0,way2.length-1));
202                                                         return true;
203                                                 } else if (way1.getLastNode()==way2.getNode(0)) {
204                                                         waylist.splice(del,1);
205                                                         undo.push(new MergeWaysAction(way1,way2,way1.length-1,0));
206                                                         return true;
207                                                 } else if (way1.getLastNode()==way2.getLastNode()) { 
208                                                         waylist.splice(del,1);
209                                                         undo.push(new MergeWaysAction(way1,way2,way1.length-1,way2.length-1));
210                                                         return true;
211                                                 }
212                                         }
213                                 }
214                         }
215                         return false;
216                 }
217
218                 public function doReverseDirection():void {
219                         var undo:CompositeUndoableAction = new CompositeUndoableAction("Reverse direction of objects");
220                         for each (var way:Way in controller.state.selectedWays) {
221                                 way.reverseNodes(undo.push);
222                         }
223                         MainUndoStack.getGlobalStack().addAction(undo);
224                 }
225
226                 public function doQuadrilateralise():void {
227                         var undo:CompositeUndoableAction = new CompositeUndoableAction("Make objects right-angled");
228                         for each (var way:Way in controller.state.selectedWays) {
229                                 Quadrilateralise.quadrilateralise(way, undo.push);
230                         }
231                         MainUndoStack.getGlobalStack().addAction(undo);
232                 }
233
234                 public function doStraighten():void {
235                         var undo:CompositeUndoableAction = new CompositeUndoableAction("Straighten objects");
236                         for each (var way:Way in controller.state.selectedWays) {
237                                 Straighten.straighten(way, controller.map, undo.push);
238                         }
239                         MainUndoStack.getGlobalStack().addAction(undo);
240                 }
241
242                 public function doCircularise():void {
243                         var undo:CompositeUndoableAction = new CompositeUndoableAction("Make objects circular ");
244                         for each (var way:Way in controller.state.selectedWays) {
245                                 Circularise.circularise(way, controller.map, undo.push);
246                         }
247                         MainUndoStack.getGlobalStack().addAction(undo);
248                 }
249
250                 public function doSplit():void {
251                         if (controller.state is SelectedWayNode) {
252                                 controller.setState(SelectedWayNode(controller.state).splitWay());
253                         }
254                 }
255                 
256                 public function doParallelise():void {
257                         if (controller.state is SelectedWay) {
258                                 controller.setState(new SelectedParallelWay(Way(controller.state.firstSelected)));
259                         }
260                 }
261
262
263         ]]>
264 </mx:Script>    
265 </mx:Panel>