using UnityEngine;

using System.Collections;

using System.Collections.Generic;

using System.Linq;

using System;



public class ComboBox : MonoBehaviour

{

    private Dictionary<objectobject> dataSource;

    private object currentValue;

    private object currentDisplayText;

    private int currentIndex;

    private GUISkin skin;

    private Rect rect;

    private Rect relativeRect;

    private Rect parentWinRect;

    private Rect rectList;

    private Rect rectListView;

    private Rect rectListViewGroupTop;

    private Rect rectListViewGroupBottom;

    private bool showList;

    private int listItemCount;

    private Vector2 scrollPosition;

    private Texture2D scrollBarBg;

    private Texture2D scrollBarThumb;

    private float showListTime;

    private int guiDepth;

    private bool alreadyInitGuiDepth;

    

    /// <summary>

    
/// 选择项更改事件参数 

    
/// </summary>

    public class SelectItemChangedArgs : EventArgs

    {

        private object itemValue;

        private object itemDisplayText;

        public object ItemValue{

            get{

                return itemValue;

            }

        }

        public object ItemDisplayText{

            get{

                return itemDisplayText;

            }

        }

        public SelectItemChangedArgs (object iValue, object iDisplayText)

        {

            itemValue = iValue;

            itemDisplayText = iDisplayText;

        }

    }

    

    /// <summary>

    
/// 选择项更改事件 

    
/// </summary>

    public event EventHandler<SelectItemChangedArgs> OnSelectItemChanged;



    public object SelectValue {

        get { return currentValue; }

    }



    public object SelectDisplayText {

        get { return currentDisplayText; }

    }



    public float ShowListTime {

        get { return showListTime; }

    }

    

    /// <summary>

    
/// 数据源 

    
/// </summary>

    public Dictionary<objectobject> DataSource{

        set{

            dataSource = value;

            currentDisplayText = null;

            currentValue = null;

        }

        get{

            return dataSource;

        }

    }

    

    /// <summary>

    
/// 初始化各项参数,控件应该只调用一次此方法,进行重置数据源直接使用DataSource属性即可 

    
/// </summary>

    
/// <param name="s">

    
/// A <see cref="GUISkin"/>

    
/// </param>

    
/// <param name="data">

    
/// A <see cref="Dictionary<System.Object, System.Object>"/>

    
/// </param>

    
/// <param name="r">

    
/// A <see cref="Rect"/>

    
/// </param>

    
/// <param name="listCount">

    
/// A <see cref="System.Int32"/>

    
/// </param>

    
/// <param name="barBg">

    
/// A <see cref="Texture2D"/>

    
/// </param>

    
/// <param name="barThumb">

    
/// A <see cref="Texture2D"/>

    
/// </param>

    
/// <param name="depth">

    
/// A <see cref="System.Int32"/>

    
/// </param>

    public void Init(GUISkin s, Dictionary<objectobject> data, Rect r, int listCount, Texture2D barBg, Texture2D barThumb, int depth)

    {

        skin = s;

        dataSource = data;

        relativeRect = r;

        listItemCount = listCount;

        scrollBarBg = barBg;

        scrollBarThumb = barThumb;

        currentIndex = -1;

        

        //将控件置于当前GUI元素之上,并且只在第一次调用初始化方法设置GUI深度,防止循环中重复调用

        if (!alreadyInitGuiDepth){

            guiDepth = GUI.depth - 1;

            alreadyInitGuiDepth = true;

        }



        currentDisplayText = null;

        currentValue = null;

        

        GUI.skin.verticalScrollbar.normal.background = scrollBarBg;

        GUI.skin.verticalScrollbar.margin = new RectOffset (0000);

        GUI.skin.verticalScrollbarThumb.normal.background = scrollBarThumb;

    }

    

    /// <summary>

    
/// 设置父类容器的坐标范围,计算控件在屏幕上真正的坐标位置 

    
/// </summary>

    
/// <param name="rectParent">

    
/// A <see cref="Rect"/>

    
/// </param>

    public void SetParentRect(Rect rectParent)

    {

        parentWinRect = rectParent;

        rect = new Rect(parentWinRect.x + relativeRect.x, parentWinRect.y + relativeRect.y,relativeRect.width,relativeRect.height);

    }

    

    /// <summary>

    
/// 强行设置下拉列表是否是示 

    
/// </summary>

    
/// <param name="show">

    
/// A <see cref="System.Boolean"/>

    
/// </param>

    public void SetShowList(bool show)

    {

        if (showList){

            showList = show;

        }

    }

    

    /// <summary>

    
/// 绘制下拉列表框 

    
/// </summary>

    public void Draw ()

    {

        if (skin == null || dataSource == null) {

            return;

        }

        

        if (currentDisplayText == null || currentValue == null) {

            if (dataSource.Count > 0) {

                currentDisplayText = dataSource.Values.First ();

                currentValue = dataSource.Keys.First ();

                currentIndex = 0;

            }

            else{

                currentDisplayText = "";

                currentValue = -1;

                currentIndex = -1;

            }

        }

        

        if (GUI.Button (rect, currentDisplayText == null ? "" : currentDisplayText.ToString (), skin.GetStyle ("combobox"))) {

            showList = !showList;

            if (showList) {

                showListTime = Time.time;

            } else {

                showListTime = 0f;

            }

        }

        

        this.DrawList();

    }

    

    /// <summary>

    
/// 绘制列表项

    
/// </summary>

    public void DrawList ()

    {

        if (showList == true) {

            

            this.calculateItemCount();

            

            if (listItemCount < dataSource.Count) {

                

                //为了留出最方下的横线,这里高度减1

                rectList = new Rect (rect.x, rect.y + rect.height, rect.width, rect.height * listItemCount - 1);

                rectListView = new Rect (rect.x, rect.y + rect.height, rect.width - GUI.skin.verticalScrollbar.fixedWidth, rect.height * dataSource.Count);

                rectListViewGroupTop = new Rect (rectList.x, rectList.y, rectList.width, rectList.height + 1 - rect.height);

                rectListViewGroupBottom = new Rect (rectList.x, rectList.y + rectListViewGroupTop.height, rectList.width, rect.height);

                GUI.Box(rectListViewGroupTop,"", skin.GetStyle ("comboxlist"));

                GUI.Box(rectListViewGroupBottom,"", skin.GetStyle ("comboxlistbottom"));

                

                //scrollPosition = GUI.BeginScrollView (rectList, scrollPosition, rectListView, false, true);

                scrollPosition = Vector2.Lerp(scrollPosition,GUI.BeginScrollView(rectList, scrollPosition, rectListView, falsetrue),0.5f);



                float top = rectList.y;

                for (int i = 0; i < dataSource.Count; i++) {

                    drawItem(new Rect (rectList.x, top, rect.width, rect.height),i);

                    top += rect.height;

                }

                GUI.EndScrollView ();

            }

            else if (dataSource.Count>0){

                rectList = new Rect (rect.x, rect.y + rect.height, rect.width, rect.height * dataSource.Count - 1);

                rectListViewGroupTop = new Rect (rectList.x, rectList.y, rectList.width, rectList.height + 1 - rect.height);

                rectListViewGroupBottom = new Rect (rectList.x, rectList.y + rectListViewGroupTop.height, rectList.width, rect.height);

                GUI.Box(rectListViewGroupTop,"", skin.GetStyle ("comboxlist"));

                GUI.Box(rectListViewGroupBottom,"", skin.GetStyle ("comboxlistbottom"));

                GUI.BeginGroup(rectList);

                float top = 0;

                for (int i = 0; i < dataSource.Count; i++) {

                    drawItem(new Rect (0, top, rect.width, rect.height),i);

                    top += rect.height;

                }

                GUI.EndGroup();

            }

        }

    }

    

    /// <summary>

    
/// 当listItemCount为0时,动态计算可以容纳的数据行数 

    
/// </summary>

    private void calculateItemCount()

    {

        if (listItemCount==0){

            int availableAreaHeight = (int)(parentWinRect.height - relativeRect.y - relativeRect.height -1);

            listItemCount = availableAreaHeight/(int)relativeRect.height;

        }

    }

    

    /// <summary>

    
/// 绘制内容项,并响应事件 

    
/// </summary>

    
/// <param name="r">

    
/// A <see cref="Rect"/>

    
/// </param>

    
/// <param name="index">

    
/// A <see cref="System.Int32"/>

    
/// </param>

    private void drawItem (Rect r,int index)

    {

        if (GUI.Button (r, dataSource.Values.ElementAt(index).ToString (), skin.GetStyle ("comboxitem"))) {

            currentDisplayText = dataSource.Values.ElementAt (index);

            currentValue = dataSource.Keys.ElementAt (index);

            if (currentIndex!=index){

                currentIndex = index;

                if (OnSelectItemChanged!=null){

                    OnSelectItemChanged(this,new SelectItemChangedArgs(currentValue,currentDisplayText));

                }

            }

            showList = false;

        }

    }

    

    void OnGUI()

    {

        GUI.depth = guiDepth;

        this.Draw();

    }

    

    /// <summary>

    
/// 按时间比较各ComboBox控件的顺序,初衷是为了点击新的控件时,其它ComboBox控件下拉列表自动隐藏 

    
/// </summary>

    public class ShowListComparer : IComparer<ComboBox>

    {

        #region IComparer[ComboBox] implementation

        int IComparer<ComboBox>.Compare (ComboBox x, ComboBox y)

        {

            return x.showListTime.CompareTo (y.showListTime) * -1;

        }

        #endregion

    }

}
posted on 2012-10-09 14:29  雨季  阅读(16803)  评论(2编辑  收藏  举报