<?xml version="1.0" encoding="utf-8"?>
<mx:Panel
- xmlns:mx="http://www.adobe.com/2006/mxml"
+ xmlns:fx="http://ns.adobe.com/mxml/2009"
+ xmlns:mx="library://ns.adobe.com/flex/mx"
+ xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:potlatch2="net.systemeD.potlatch2.*"
- height="46" width="219"
- headerHeight="6" headerColors="[black, gray]"
- borderThicknessRight="0" borderThicknessLeft="0" borderThicknessBottom="0"
- paddingLeft="4" paddingTop="4" layout="absolute" >
+ height="76" width="129" layout="absolute"
+ styleName="theToolBox">
<mx:Image data="@Embed('../../../embedded/close_small.png')"
- includeInLayout="false" id="toolboxClose" click="toggle();"
- y="-6" x="205" />
+ includeInLayout="false" id="toolboxClose" click="toggle();"
+ y="-6" x="115" />
- <mx:Button icon="@Embed('../../../embedded/delete.svg')"
- click='doDelete();'
+ <!-- Top row -->
+
+ <s:Button icon="@Embed('../../../embedded/delete.svg')"
+ click='doDelete(event.ctrlKey,event.shiftKey);'
enabled="{canDo('delete')}"
alpha="{getAlpha('delete')}"
toolTip="{deleteToolTipText()}"
- width="28" height="28" textAlign="left" y="4" x="6" paddingLeft="6" paddingRight="0" />
- <mx:Button icon="@Embed('../../../embedded/direction.svg')"
- click='doReverseDirection();'
- enabled="{canDo('reverseDirection')}"
- alpha="{getAlpha('reverseDirection')}"
- toolTip="Reverse direction (V)"
- width="28" height="28" textAlign="left" y="4" x="36" paddingLeft="8" paddingRight="0" />
- <mx:Button icon="@Embed('../../../embedded/cut.svg')"
- click='doSplit();'
+ width="28" height="28" y="4" x="6" />
+
+ <mx:HBox id="reverseButton" width="28" height="28" y="4" x="36" borderStyle="none"
+ horizontalAlign="center" verticalAlign="middle" toolTip="Reverse direction (V)">
+ <mx:ViewStack id="rotateButtonStack" creationPolicy="all">
+ <mx:HBox id="arrowBoxWrapper">
+ <s:NavigatorContent width="28" height="28">
+ <s:Button id="arrow" icon="{Arrow}" width="28" height="28" alpha="{getAlpha('reverseDirection')}" click="reverseClicked();"/>
+ </s:NavigatorContent>
+ </mx:HBox>
+ <mx:HBox id="clockwiseBox" horizontalAlign="center" verticalAlign="middle">
+ <s:Button id="clockwise" icon="@Embed('../../../embedded/clockwise.svg')"
+ alpha="{getAlpha('reverseDirection')}"
+ width="28" height="28" click="reverseClicked();" />
+ </mx:HBox>
+ <mx:HBox id="antiClockwiseBox" horizontalAlign="center" verticalAlign="middle">
+ <s:Button id="anticlockwise" icon="@Embed('../../../embedded/anti-clockwise.svg')"
+ enabled="{canDo('reverseDirection')}"
+ alpha="{getAlpha('reverseDirection')}"
+ width="28" height="28" click="reverseClicked();" />
+ </mx:HBox>
+ </mx:ViewStack>
+ </mx:HBox>
+ <s:Button icon="@Embed('../../../embedded/cut.svg')"
+ id="splitButton"
+ click='doSplit();'
enabled="{canDo('split')}"
alpha="{getAlpha('split')}"
toolTip="Split way (X)"
- width="28" height="28" textAlign="left" y="4" x="66" paddingLeft="8" paddingRight="0" />
- <mx:Button icon="@Embed('../../../embedded/straighten.svg')"
+ width="28" height="28" y="4" x="66" />
+ <s:Button
+ id="mergeButton"
+ click='doMerge();'
+ toolTip="Merge ways"
+ width="28" height="28" y="4" x="96" />
+
+ <!-- Second row -->
+
+ <s:Button icon="@Embed('../../../embedded/straighten.svg')"
+ id="straightenButton"
click='doStraighten();'
enabled="{canDo('straighten')}"
alpha="{getAlpha('straighten')}"
toolTip="Straighten way"
- width="28" height="28" textAlign="left" y="4" x="96" paddingLeft="5" paddingRight="0" />
- <mx:Button icon="@Embed('../../../embedded/circle.svg')"
+ width="28" height="28" y="34" x="6" />
+ <s:Button icon="@Embed('../../../embedded/circle.svg')"
+ id="circulariseButton"
click='doCircularise();'
enabled="{canDo('circularise')}"
alpha="{getAlpha('circularise')}"
toolTip="Make circular"
- width="28" height="28" textAlign="left" y="4" x="126" paddingLeft="4" paddingRight="0" />
- <mx:Button icon="@Embed('../../../embedded/quadrilateralise.svg')"
+ width="28" height="28" y="34" x="36" />
+ <s:Button icon="@Embed('../../../embedded/quadrilateralise.svg')"
+ id="quadrilateraliseButton"
click='doQuadrilateralise();'
enabled="{canDo('quadrilateralise')}"
alpha="{getAlpha('quadrilateralise')}"
- toolTip="Make right-angled"
- width="28" height="28" textAlign="left" y="4" x="156" paddingLeft="6" paddingRight="0" />
- <mx:Button icon="@Embed('../../../embedded/parallel.svg')"
+ toolTip="Make right-angled (Q)"
+ width="28" height="28" y="34" x="66" />
+ <s:Button icon="@Embed('../../../embedded/parallel.svg')"
+ id="parralleliseButton"
click='doParallelise();'
enabled="{canDo('parallelise')}"
alpha="{getAlpha('parallelise')}"
toolTip="Create parallel way (P)"
- width="28" height="28" textAlign="left" y="4" x="186" paddingLeft="8" paddingRight="0" />
+ width="28" height="28" y="34" x="96" />
- <mx:Script><![CDATA[
+ <fx:Script><![CDATA[
import flash.events.Event;
import flash.events.MouseEvent;
import net.systemeD.halcyon.connection.*;
- import net.systemeD.potlatch2.controller.*;
- import net.systemeD.potlatch2.tools.*;
+ import net.systemeD.halcyon.connection.actions.*;
+ import net.systemeD.potlatch2.controller.*;
+ import net.systemeD.potlatch2.tools.*;
+ import embedded.*; // for FXG icons
private var controller:EditController;
+ [Bindable]
+ public var angle:int=0;
+
+ public var deleteNode:String = "Delete Node (Delete)";
+ public var deleteArea:String = "Delete Area (Shift+Delete)";
+ public var deleteWay:String = "Delete Way (Shift+Delete)";
+ public var deleteItem:String = "Delete Item"; // When nothing is selected
+
+ [Bindable] [Embed(source="../../../embedded/merge.svg" )] private var mergeIcon:Class;
+ [Bindable] [Embed(source="../../../embedded/multipolygon.svg")] private var multipolygonIcon:Class;
+
public function init(controller:EditController):void {
this.controller=controller;
- /* check if the toolbox was explictly turned off in a previous session */
- if( SharedObject.getLocal("user_state").data['toolbox_visible'] == false) {
- this.visible = false;
- }
+ /* check if the toolbox was explictly turned off in a previous session */
+ if( SharedObject.getLocal("user_state","/").data['toolbox_visible'] == false) {
+ this.visible = false;
+ }
}
override protected function createChildren():void {
super.createChildren();
super.titleBar.addEventListener(MouseEvent.MOUSE_DOWN,handleDown);
- super.titleBar.addEventListener(MouseEvent.MOUSE_UP,handleUp);
}
public function updateSelectionUI():void {
dispatchEvent(new Event("updateSkin"));
dispatchEvent(new Event("updateAlpha"));
+ updateDirectionArrow();
+ updateMergeIcon();
}
private function handleDown(e:Event):void {
this.startDrag();
+ stage.addEventListener(MouseEvent.MOUSE_UP,handleUp);
}
private function handleUp(e:Event):void {
this.stopDrag();
+ stage.removeEventListener(MouseEvent.MOUSE_UP,handleUp);
}
public function toggle():void {
this.visible=!this.visible;
- var obj:SharedObject = SharedObject.getLocal("user_state");
- obj.setProperty("toolbox_visible",this.visible);
- obj.flush();
+ var obj:SharedObject = SharedObject.getLocal("user_state","/");
+ obj.setProperty("toolbox_visible",this.visible);
+ obj.flush();
}
// --------------------------------------------------------------------------------
// Enable/disable toolbox buttons
// (ideally we'd use CSS to set alpha in disabled state, but Flex's CSS
- // capabilities aren't up to it)
+ // capabilities aren't up to it)
- [Bindable(event="updateSkin")]
+ [Bindable(event="updateSkin")]
public function canDo(op:String):Boolean {
if (controller.state.selectCount==0) return false;
- var entity:Entity=controller.state.firstSelected;
switch (op) {
case 'delete': return true;
- case 'reverseDirection': return (entity is Way);
- case 'quadrilateralise': return (entity is Way && Way(entity).isArea());
- case 'straighten': return (entity is Way && !Way(entity).isArea());
- case 'circularise': return (entity is Way && Way(entity).isArea());
+ case 'reverseDirection': return controller.state.hasSelectedWays();
+ case 'quadrilateralise': return (controller.state.hasSelectedAreas() || controller.state.hasSelectedWayNodesInAreas());
+ case 'straighten': return controller.state.hasSelectedUnclosedWays();
+ case 'circularise': return controller.state.hasSelectedAreas();
case 'split': return (controller.state is SelectedWayNode);
- case 'parallelise': return (entity is Way);
+ case 'parallelise': return (controller.state is SelectedWay);
}
return false;
}
- [Bindable(event="updateAlpha")]
+ [Bindable(event="updateAlpha")]
public function getAlpha(op:String):Number {
if (canDo(op)) { return 1; }
return 0.5;
}
- [Bindable(event="updateSkin")]
- private function deleteToolTipText():String {
+ [Bindable(event="updateSkin")]
+ private function deleteToolTipText():String {
var entity:Entity=controller.state.firstSelected;
- if (entity is Node) { return "Delete Node (Delete)"; }
- if (entity is Way && Way(entity).isArea()) { return "Delete Area (Shift+Delete)"; }
- if (entity is Way) { return "Delete Way (Shift+Delete)"; }
- return "Delete Item"; // When nothing is selected
+ if (entity is Node) { return deleteNode; }
+ if (entity is Way && Way(entity).isArea()) { return deleteArea; }
+ if (entity is Way) { return deleteWay; }
+ return deleteItem; // When nothing is selected
+ }
+
+ private function updateDirectionArrow():void {
+ if (controller.state is SelectedWay) {
+ var w:Way = Way(controller.state.firstSelected);
+ if (w) { // not entirely sure why this protection is necessary, but it appears so
+ if (w.isArea()) {
+ // so Way.clockwise appears to give wrong results. Patches welcome, I guess, but for now...
+ w.clockwise? rotateButtonStack.selectedChild = antiClockwiseBox : rotateButtonStack.selectedChild = clockwiseBox;
+ } else {
+ rotateButtonStack.selectedChild = arrowBoxWrapper;
+ arrow.iconDisplay.rotation=w.angle;
+ arrow.iconDisplay.smooth=true;
+ }
+ }
+ }
+ }
+
+ private function updateMergeIcon():void {
+ var multi:Object=controller.state.multipolygonMembers();
+ if (multi.outer) {
+ mergeButton.setStyle("icon",multipolygonIcon);
+ mergeButton.alpha=1;
+ mergeButton.enabled=true;
+ } else if (controller.state.hasAdjoiningWays()) {
+ mergeButton.setStyle("icon",mergeIcon);
+ mergeButton.alpha=1;
+ mergeButton.enabled=true;
+ } else {
+ mergeButton.setStyle("icon",mergeIcon);
+ mergeButton.alpha=0.5;
+ mergeButton.enabled=false;
+ }
+ }
+
+ private function reverseClicked():void {
+ if(canDo('reverseDirection')) {
+ doReverseDirection();
+ }
}
// --------------------------------------------------------------------------------
// Individual toolbox actions
- public function doDelete():void {
- var undo:CompositeUndoableAction = new CompositeUndoableAction("Delete objects");
- for each (var entity:Entity in controller.state.selection) {
- if (entity is Node) { controller.connection.unregisterPOI(Node(entity)); }
- entity.remove(undo.push);
- }
- MainUndoStack.getGlobalStack().addAction(undo);
+ public function doDelete(controlKey:Boolean,shiftKey:Boolean):void {
+ var undo:CompositeUndoableAction = new CompositeUndoableAction("Delete objects");
+ if (controlKey) {
+ // Temporary function to delete everything with non-accepting status
+ var conn:Connection=controller.state.selection[0].connection;
+ var o:Object=conn.getObjectsByBbox(controller.map.edge_l, controller.map.edge_r, controller.map.edge_t, controller.map.edge_b);
+ for each (var way:Way in o.waysInside) {
+ if (way.status=='no' || (shiftKey && way.status=='partial')) { way.remove(undo.push); }
+ }
+ for each (var poi:Node in o.poisInside) {
+ if (poi.status=='no' || (shiftKey && way.status=='partial')) { poi.connection.unregisterPOI(poi); poi.remove(undo.push); }
+ }
+ MainUndoStack.getGlobalStack().addAction(undo);
+ controller.setState(new NoSelection());
+
+ } else {
+ // Standard delete function
+ for each (var entity:Entity in controller.state.selection) {
+ if (entity is Node) { entity.connection.unregisterPOI(Node(entity)); }
+ entity.remove(undo.push);
+ }
+ MainUndoStack.getGlobalStack().addAction(undo);
- if (controller.state is SelectedWayNode) {
- controller.setState(new SelectedWay(SelectedWayNode(controller.state).selectedWay));
+ if (controller.state is SelectedWayNode) {
+ controller.setState(new SelectedWay(SelectedWayNode(controller.state).selectedWay));
+ } else {
+ controller.setState(new NoSelection());
+ }
+ }
+ }
+
+ public function doMerge():void {
+ var multi:Object=controller.state.multipolygonMembers();
+ if (multi.outer) {
+ controller.setState(SelectedMultiple(controller.state).createMultipolygon());
} else {
- controller.setState(new NoSelection());
+ controller.setState(SelectedMultiple(controller.state).mergeWays());
}
}
- public function doReverseDirection():void {
- if (controller.state is SelectedWay) {
- Way(controller.state.firstSelected).reverseNodes(MainUndoStack.getGlobalStack().addAction);
- }
- }
+ public function doReverseDirection():void {
+ var undo:CompositeUndoableAction = new CompositeUndoableAction("Reverse direction of objects");
+ for each (var way:Way in controller.state.selectedWays) {
+ way.reverseNodes(undo.push);
+ }
+ MainUndoStack.getGlobalStack().addAction(undo);
+ }
public function doQuadrilateralise():void {
- if (controller.state is SelectedWay) {
- Quadrilateralise.quadrilateralise(Way(controller.state.firstSelected));
+ var undo:CompositeUndoableAction = new CompositeUndoableAction("Make objects right-angled");
+ for each (var way:Way in controller.state.selectedWays) {
+ Quadrilateralise.quadrilateralise(way, undo.push);
}
+ for each (var node:Node in controller.state.selectedNodes) {
+ for each (var parentWay:Way in node.parentWays) {
+ Quadrilateralise.quadrilateralise(parentWay, undo.push);
+ }
+ }
+ MainUndoStack.getGlobalStack().addAction(undo);
}
public function doStraighten():void {
- if (controller.state is SelectedWay) {
- Straighten.straighten(Way(controller.state.firstSelected),controller.map);
+ var undo:CompositeUndoableAction = new CompositeUndoableAction("Straighten objects");
+ for each (var way:Way in controller.state.selectedWays) {
+ Straighten.straighten(way, controller.map, undo.push);
}
+ MainUndoStack.getGlobalStack().addAction(undo);
}
public function doCircularise():void {
- if (controller.state is SelectedWay) {
- Circularise.circularise(Way(controller.state.firstSelected),controller.map);
+ var undo:CompositeUndoableAction = new CompositeUndoableAction("Make objects circular ");
+ for each (var way:Way in controller.state.selectedWays) {
+ Circularise.circularise(way, controller.map, undo.push);
}
+ MainUndoStack.getGlobalStack().addAction(undo);
}
public function doSplit():void {
}
- ]]>
-</mx:Script>
+ ]]>
+</fx:Script>
</mx:Panel>