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
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user