From 4fa0e70ede5528a95dfd0ee3e67c95e8e953229d Mon Sep 17 00:00:00 2001 From: Nathan Curtis Date: Thu, 1 May 2008 20:05:09 +0000 Subject: [PATCH] I'm still fiddling with several subclasses, but I believe this is mostly nailed down, and it'll simplify my testing to check it in, so let's do just that. git-svn-id: svn+ssh://src.earth.threerings.net/nenya/trunk@480 ed5b42cb-e716-0410-a449-f6a68f950b19 --- .../com/threerings/flex/AmbidextrousList.as | 21 ++ .../com/threerings/flex/NameLabelCreator.as | 32 +++ src/as/com/threerings/flex/PlayerList.as | 207 ++++++++++++++++++ 3 files changed, 260 insertions(+) create mode 100644 src/as/com/threerings/flex/NameLabelCreator.as create mode 100644 src/as/com/threerings/flex/PlayerList.as diff --git a/src/as/com/threerings/flex/AmbidextrousList.as b/src/as/com/threerings/flex/AmbidextrousList.as index 7c68eee4..0c2d2998 100644 --- a/src/as/com/threerings/flex/AmbidextrousList.as +++ b/src/as/com/threerings/flex/AmbidextrousList.as @@ -1,3 +1,24 @@ +// +// $Id$ +// +// Nenya library - tools for developing networked games +// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved +// http://www.threerings.net/code/nenya/ +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + package com.threerings.flex { import mx.controls.List; diff --git a/src/as/com/threerings/flex/NameLabelCreator.as b/src/as/com/threerings/flex/NameLabelCreator.as new file mode 100644 index 00000000..c8b7de0d --- /dev/null +++ b/src/as/com/threerings/flex/NameLabelCreator.as @@ -0,0 +1,32 @@ +// +// $Id$ +// +// Nenya library - tools for developing networked games +// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved +// http://www.threerings.net/code/nenya/ +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package com.threerings.flex { + +import mx.core.UIComponent; + +import com.threerings.util.Name; + +public interface NameLabelCreator +{ + function createLabel (name :Name) :UIComponent; +} +} diff --git a/src/as/com/threerings/flex/PlayerList.as b/src/as/com/threerings/flex/PlayerList.as new file mode 100644 index 00000000..f529dc10 --- /dev/null +++ b/src/as/com/threerings/flex/PlayerList.as @@ -0,0 +1,207 @@ +// +// $Id$ +// +// Nenya library - tools for developing networked games +// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved +// http://www.threerings.net/code/nenya/ +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package com.threerings.flex { + +import mx.collections.ArrayCollection; +import mx.collections.Sort; + +import mx.containers.VBox; + +import mx.core.ClassFactory; +import mx.core.ScrollPolicy; + +import com.threerings.util.Comparable; +import com.threerings.util.Hashable; +import com.threerings.util.HashMap; + +public class PlayerList extends VBox +{ + /** + * Create a new player list. + * + * @param labelCreator If null, will use a default implementation that does nothing special + * with text formatting or click behavior. + */ + public function PlayerList (labelCreator :NameLabelCreator = null) :void + { + _labelCreator = labelCreator; + if (_labelCreator == null) { + _labelCreator = new DefaultNameLabelCreator(); + } + + // set up the UI + width = 280; + height = 125; + _list = new AmbidextrousList(); + _list.verticalScrollPolicy = ScrollPolicy.ON; + _list.selectable = false; + _list.percentWidth = 100; + _list.percentHeight = 100; + _list.itemRenderer = new ClassFactory(getRenderingClass()); + _list.dataProvider = _players; + + addChild(_list); + + // set up the sort for the collection + var sort :Sort = new Sort(); + sort.compareFunction = sortFunction; + _players.sort = sort; + } + + /** + * The PlayerList is meant to include data that is at least as complicated as a Name, so to + * keep things simple and extendable, we require Hashables. This allows the issue of passing + * the NameLabelCreator into the player renderer to be kept simple and straightforward and still + * allow efficient item updating. + */ + public function addItem (value :Hashable) :void + { + var currentValue :Array = _values.get(value) as Array; + if (currentValue != null) { + currentValue[1] = value; + // this is the same array already contained in the list, so the proper renderer should + // be notified of the new value. + _players.itemUpdated(currentValue); + } else { + currentValue = [_labelCreator, value]; + _values.put(value, currentValue); + _players.addItem(currentValue); + } + } + + public function removeItem (value :Hashable) :void + { + var currentValue :Array = _values.remove(value) as Array; + if (currentValue != null) { + _players.removeItemAt(_players.getItemIndex(currentValue)); + } + } + + /** + * Notify the list that this value has changed internally, and the renderer should be told to + * redraw its contents. + */ + public function itemUpdated (value :Hashable) :void + { + var currentValue :Array = _values.get(value) as Array; + if (currentValue != null) { + currentValue[1] = value; + _players.itemUpdated(currentValue); + } + } + + protected function getRenderingClass () :Class + { + return PlayerRenderer; + } + + protected function sortFunction (o1 :Object, o2 :Object, fields :Array = null) :int + { + if (!(o1 is Array) || !(o2 is Array)) { + return 0; + } + + var data1 :Object = (o1 as Array)[1]; + var data2 :Object = (o2 as Array)[1]; + if (data1 is Comparable && data2 is Comparable) { + return (data1 as Comparable).compareTo(data2); + } else { + // default to actionscript's magical great than or less than operators + return data1 > data2 ? -1 : (data1 < data2 ? 1 : 0); + } + } + + protected var _labelCreator :NameLabelCreator; + protected var _list :AmbidextrousList; + protected var _players :ArrayCollection = new ArrayCollection(); + protected var _values :HashMap = new HashMap(); +} +} + +import mx.containers.HBox; + +import mx.controls.Label; + +import mx.core.ScrollPolicy; +import mx.core.UIComponent; + +import com.threerings.flex.NameLabelCreator; + +import com.threerings.util.Name; + +class DefaultNameLabelCreator implements NameLabelCreator +{ + public function createLabel (name :Name) :UIComponent + { + var label :Label = new Label(); + label.text = "" + name; + return label; + } +} + +/** + * A renederer for lists that contain Names. + */ +class PlayerRenderer extends HBox +{ + public function PlayerRenderer () + { + super(); + + verticalScrollPolicy = ScrollPolicy.OFF; + horizontalScrollPolicy = ScrollPolicy.OFF; + // the horizontalGap should be 8... + } + + override public function set data (value :Object) :void + { + super.data = value; + + if (processedDescriptors) { + configureUI(); + } + } + + override protected function createChildren () :void + { + super.createChildren(); + + configureUI(); + } + + /** + * Update the UI elements with the data we're displaying. + */ + protected function configureUI () :void + { + removeAllChildren(); + + if (this.data != null && (this.data is Array) && (this.data as Array).length == 2) { + var dataArray :Array = this.data as Array; + var creator :NameLabelCreator = dataArray[0] as NameLabelCreator; + var name :Name = dataArray[1] as Name; + if (creator != null && name != null) { + addChild(creator.createLabel(name)); + } + } + } +}