//
// System.Windows.Forms.ComboBox.cs
//
// Author:
// stubbed out by Jaak Simm (jaaksimm@firm.ee)
// Dennis Hayes (dennish@Raytek.com)
// Alexandre Pigolkine (pigolkine@gmx.de)
//
// (C) Ximian, Inc., 2002/3
//
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System.ComponentModel;
using System.Collections;
using System.Drawing;
using System.Runtime.InteropServices;
namespace System.Windows.Forms{
/// <summary>
/// Represents a Windows combo box control.
/// </summary>
[MonoTODO]
public class ComboBox : ListControl {
// private fields
DrawMode drawMode;
ComboBoxStyle dropDownStyle;
bool droppedDown;
bool integralHeight;
bool sorted;
Image backgroundImage;
ControlStyles controlStyles;
int selectedLength;
string selectedText;
int selectedIndex;
object selectedItem;
int selecedStart;
private ComboBox.ObjectCollection Items_ = null;
int itemHeight_;
int maxDropDownItems;
bool updateing; // true when begin update has been called. do not paint when true;
// --- Constructor ---
public ComboBox() : base()
{
selectedLength = 0;
selectedText = "";
selectedIndex = -1;
selectedItem = null;
selecedStart = 0;
updateing = false;
//controlStyles = null;
drawMode = DrawMode.Normal;
dropDownStyle = ComboBoxStyle.DropDown;
droppedDown = false;
integralHeight = true;
sorted = false;
backgroundImage = null;
Items_ = new ComboBox.ObjectCollection(this);
itemHeight_ = 13;
maxDropDownItems = 8;
SubClassWndProc_ = true;
Size = DefaultSize;
}
// --- Properties ---
[MonoTODO]
public override Color BackColor {
get {
return base.BackColor;
}
set {
if(BackColor.A != 255){
if(
(controlStyles & ControlStyles.SupportsTransparentBackColor) !=
ControlStyles.SupportsTransparentBackColor
){
throw new
ArgumentOutOfRangeException("BackColor", BackColor, "Transparant background color not allowed.");
}
}
base.BackColor = value;
}
}
public override Image BackgroundImage {
get {
return backgroundImage;
}
set {
backgroundImage = value;
}
}
internal int getDropDownHeight() {
// FIXME: use PreferredHeight instead of DefaultSize.Height ?
// FIXME: those calculations probably wrong
return DefaultSize.Height + (maxDropDownItems + 1) * itemHeight_ - (itemHeight_ / 2);
}
[MonoTODO]
protected override CreateParams CreateParams {
get {
CreateParams createParams = base.CreateParams;
createParams.ClassName = "ComboBox";
if( DropDownStyle == ComboBoxStyle.Simple) {
createParams.Height = Height;
}
else {
createParams.Height = getDropDownHeight();
}
createParams.ExStyle = (int)( WindowExStyles.WS_EX_RIGHTSCROLLBAR | WindowExStyles.WS_EX_NOPARENTNOTIFY);
createParams.Style = (int) (
(int)WindowStyles.WS_CHILD |
(int)WindowStyles.WS_VISIBLE |
(int)WindowStyles.WS_VSCROLL |
(int)WindowStyles.WS_TABSTOP |
(int)ComboBoxStyles.CBS_HASSTRINGS );
switch( DrawMode){
case DrawMode.OwnerDrawFixed:
createParams.Style |= (int)ComboBoxStyles.CBS_OWNERDRAWFIXED;
break;
case DrawMode.OwnerDrawVariable:
createParams.Style |= (int)ComboBoxStyles.CBS_OWNERDRAWVARIABLE;
break;
}
switch(DropDownStyle) {
case ComboBoxStyle.Simple:
createParams.Style |= (int)ComboBoxStyles.CBS_SIMPLE;
break;
case ComboBoxStyle.DropDown:
createParams.Style |= (int)ComboBoxStyles.CBS_DROPDOWN;
break;
case ComboBoxStyle.DropDownList:
createParams.Style |= (int)ComboBoxStyles.CBS_DROPDOWNLIST;
break;
}
if( !integralHeight) {
createParams.Style |= (int)ComboBoxStyles.CBS_NOINTEGRALHEIGHT;
}
/*
* Keep Control unsorted, but sort data in Items (ArrayList)
if( sorted) {
createParams.Style |= (int)ComboBoxStyles.CBS_SORT;
}
*/
return createParams;
}
}
protected override Size DefaultSize {
get {
return new Size(121,21);//correct size
}
}
/*
public new Size Size {
//FIXME: should we return client size or someother size???
get {
return base.Size;
}
set {
if( dropDownStyle == ComboBoxStyle.Simple) {
Size sz = value;
sz.Height += maxDropDownItems * itemHeight_;
base.Size = sz;
}
else {
base.Size = value;
}
}
}
*/
public DrawMode DrawMode {
get {
return drawMode;
}
set {
if( drawMode != value) {
drawMode = value;
RecreateHandle();
}
}
}
public ComboBoxStyle DropDownStyle {
get {
return dropDownStyle;
}
set {
if( dropDownStyle != value) {
dropDownStyle = value;
RecreateHandle();
OnDropDownStyleChanged( new EventArgs());
}
}
}
[MonoTODO]
public int DropDownWidth {
get {
throw new NotImplementedException ();
}
set {
//FIXME:
}
}
public bool DroppedDown {
get {
return droppedDown;
}
set {
droppedDown = value;
}
}
[MonoTODO]
public override bool Focused {
get {
if (IsHandleCreated) {
IntPtr focusedWindow = Win32.GetFocus();
if (focusedWindow == Handle)
return true;
if( Win32.GetParent(focusedWindow) == Handle)
return true;
}
return false;
}
}
[MonoTODO]
public override Color ForeColor {
get {
//FIXME:
return base.ForeColor;
}
set {
//FIXME:
base.ForeColor = value;
}
}
public bool IntegralHeight {
get {
return integralHeight;
}
set {
if( integralHeight != value) {
integralHeight = value;
if( IsHandleCreated) {
if( integralHeight) {
Win32.UpdateWindowStyle(Handle, (int)ComboBoxStyles.CBS_NOINTEGRALHEIGHT, 0);
}
else {
Win32.UpdateWindowStyle(Handle, 0, (int)ComboBoxStyles.CBS_NOINTEGRALHEIGHT);
}
}
}
}
}
[MonoTODO]
public int ItemHeight {
get {
return itemHeight_;
}
set {
itemHeight_ = value;
if( IsHandleCreated) {
if( DrawMode != DrawMode.OwnerDrawVariable) {
Win32.SendMessage(Handle, (int)ComboBoxMessages.CB_SETITEMHEIGHT, 0, itemHeight_);
}
else {
for( int i = 0; i < Items.Count; i++) {
Win32.SendMessage(Handle, (int)ComboBoxMessages.CB_SETITEMHEIGHT, i, itemHeight_);
}
}
Win32.SendMessage(Handle, (int)ComboBoxMessages.CB_SETITEMHEIGHT, -1, itemHeight_);
}
}
}
[MonoTODO]
public ComboBox.ObjectCollection Items {
get {
return Items_;
}
}
[MonoTODO]
public int MaxDropDownItems {
get {
return maxDropDownItems;
}
set {
if( maxDropDownItems != value) {
maxDropDownItems = value;
if( DropDownStyle != ComboBoxStyle.Simple) {
Height = getDropDownHeight();
}
}
}
}
[MonoTODO]
public int MaxLength {
get {
throw new NotImplementedException ();
}
set {
//FIXME:
}
}
[MonoTODO]
public int PreferredHeight {
get {
return 20; //FIXME: this is the default, good as any?
}
}
[MonoTODO]
public override int SelectedIndex {
get {
if( IsHandleCreated) {
return Win32.SendMessage(Handle, (int)ComboBoxMessages.CB_GETCURSEL, 0, 0);
}
else {
return selectedIndex;
}
}
set {
if( selectedIndex != value) {
//FIXME: set exception parameters
if( value >= Items_.Count) {
throw new ArgumentOutOfRangeException();
}
selectedIndex = value;
if( IsHandleCreated) {
Win32.SendMessage(Handle, (int)ComboBoxMessages.CB_SETCURSEL, selectedIndex, 0);
}
OnSelectedIndexChanged(new EventArgs());
}
}
}
[MonoTODO]
public object SelectedItem {
get {
if( IsHandleCreated) {
return Items_[Win32.SendMessage(Handle, (int)ComboBoxMessages.CB_GETCURSEL, 0, 0)];
}
else {
return Items_[selectedIndex];
}
}
set {
//FIXME:
}
}
[MonoTODO]
public string SelectedText {
get {
throw new NotImplementedException ();
}
set {
//FIXME:
}
}
[MonoTODO]
public int SelectionLength {
get {
throw new NotImplementedException ();
}
set {
//FIXME:
}
}
[MonoTODO]
public int SelectionStart {
get {
throw new NotImplementedException ();
}
set {
//FIXME:
}
}
public bool Sorted {
get {
return sorted;
}
set {
if( sorted != value) {
sorted = value;
if( IsHandleCreated) {
if( sorted) {
object[] items = new object[Items.Count];
Items.CopyTo(items, 0);
Items.Clear();
Items.AddRange(items);
}
}
selectedIndex = -1;
}
}
}
[MonoTODO]
public override string Text {
get {
return base.Text;
}
set {
base.Text = value;
if (value == null || value == String.Empty) {
SelectedIndex = -1;
}
}
}
/// --- Methods ---
/// internal .NET framework supporting methods, not stubbed out:
internal void populateControl( ICollection items) {
if( IsHandleCreated && items != null) {
foreach( object obj in items) {
// CHECKME : shall we check for null here or in Add/Insert functions
if( obj != null) {
Win32.SendMessage(Handle, (int)ComboBoxMessages.CB_ADDSTRING, 0, getDisplayMemberOfObj(obj));
}
}
}
}
protected override void Dispose(bool disposing) {
base.Dispose(disposing);
}
[MonoTODO]
protected override void OnSelectedValueChanged(EventArgs e){ // .NET V1.1 Beta
//FIXME:
base.OnSelectedValueChanged(e);
}
[MonoTODO]
protected override void SetItemCore(int index,object value){
}
[MonoTODO]
protected virtual void AddItemsCore(object[] value) {
//FIXME:
}
[MonoTODO]
public void BeginUpdate()
{
updateing = true;
}
[MonoTODO]
public void EndUpdate()
{
updateing = false;
}
[MonoTODO]
public int FindString(string s)
{
throw new NotImplementedException ();
}
[MonoTODO]
public int FindString(string s,int startIndex)
{
throw new NotImplementedException ();
}
[MonoTODO]
public int FindStringExact(string s)
{
throw new NotImplementedException ();
}
[MonoTODO]
public int FindStringExact(string s,int startIndex)
{
throw new NotImplementedException ();
}
[MonoTODO]
public int GetItemHeight(int index)
{
throw new NotImplementedException ();
}
[MonoTODO]
protected override bool IsInputKey(Keys keyData)
{
//FIXME:
return base.IsInputKey(keyData);
}
/// [methods for events]
[MonoTODO]
protected override void OnBackColorChanged(EventArgs e)
{
//FIXME:
base.OnBackColorChanged(e);
}
[MonoTODO]
protected override void OnDataSourceChanged(EventArgs e)
{
//FIXME:
base.OnDataSourceChanged(e);
}
[MonoTODO]
protected override void OnDisplayMemberChanged(EventArgs e)
{
//FIXME:
base.OnDisplayMemberChanged(e);
}
[MonoTODO]
protected virtual void OnDrawItem(DrawItemEventArgs e)
{
if( DrawItem != null) {
DrawItem(this, e);
}
}
[MonoTODO]
protected virtual void OnDropDown(EventArgs e)
{
//FIXME:
}
[MonoTODO]
protected virtual void OnDropDownStyleChanged(EventArgs e)
{
if( DropDownStyleChanged != null) {
DropDownStyleChanged(this, e);
}
}
[MonoTODO]
protected override void OnFontChanged(EventArgs e)
{
//FIXME:
base.OnFontChanged(e);
}
[MonoTODO]
protected override void OnForeColorChanged(EventArgs e)
{
//FIXME:
base.OnForeColorChanged(e);
}
[MonoTODO]
protected override void OnHandleCreated(EventArgs e)
{
//FIXME:
base.OnHandleCreated(e);
populateControl(Items_);
if (DropDownStyle != ComboBoxStyle.DropDown || Text == String.Empty) {
if (selectedIndex == -1 && Items.Count != 0) {
selectedIndex = 0;
}
Win32.SendMessage(Handle, (int)ComboBoxMessages.CB_SETCURSEL, selectedIndex, 0);
}
}
[MonoTODO]
protected override void OnHandleDestroyed(EventArgs e)
{
//FIXME:
base.OnHandleDestroyed(e);
}
[MonoTODO]
protected override void OnKeyPress(KeyPressEventArgs e)
{
//FIXME:
base.OnKeyPress(e);
}
[MonoTODO]
protected virtual void OnMeasureItem(MeasureItemEventArgs e)
{
if(MeasureItem != null) {
MeasureItem(this, e);
}
}
[MonoTODO]
protected override void OnParentBackColorChanged(EventArgs e)
{
//FIXME:
base.OnParentBackColorChanged(e);
}
[MonoTODO]
protected override void OnResize(EventArgs e)
{
//FIXME:
base.OnResize(e);
}
[MonoTODO]
protected override void OnSelectedIndexChanged(EventArgs e)
{
if( SelectedIndexChanged != null) {
SelectedIndexChanged( this, e);
}
}
[MonoTODO]
protected virtual void OnSelectedItemChanged(EventArgs e) {
}
[MonoTODO]
protected virtual void OnSelectionChangeCommitted(EventArgs e)
{
//FIXME:
}
/// end of [methods for events]
[MonoTODO]
protected override void RefreshItem(int index)
{
//FIXME:
base.Refresh();
}
[MonoTODO]
public void Select(int start,int length)
{
//FIXME:
}
[MonoTODO]
public void SelectAll()
{
//FIXME:
}
[MonoTODO]
protected override void SetBoundsCore(int x,int y,int width,int height,BoundsSpecified specified)
{
//FIXME:
// If DropDownStyle == ComboBoxStyle.Simple, the heigth is a real window height - no control over it
// else,
// if Handle created - specify complete height, ComboBox-control will adjust window rectangle
// else - set the height to Default.
if(DropDownStyle != ComboBoxStyle.Simple) {
if( IsHandleCreated) {
height = getDropDownHeight();
}
else {
height = DefaultSize.Height;
}
}
if ( (specified & BoundsSpecified.X) == 0) x = Left;
if ( (specified & BoundsSpecified.Y) == 0) y = Top;
if ( (specified & BoundsSpecified.Width) == 0) width = Width;
//if ( (specified & BoundsSpecified.Height) == 0) height = Height;
if (IsHandleCreated){
SetWindowPosFlags flags = SetWindowPosFlags.SWP_NOZORDER | SetWindowPosFlags.SWP_FRAMECHANGED | SetWindowPosFlags.SWP_DRAWFRAME;
Win32.SetWindowPos (Handle, SetWindowPosZOrder.HWND_NOTOPMOST, x, y, width, height, flags);
RECT rect = new RECT();
Win32.GetWindowRect (Handle, ref rect);
if( Parent != null) {
Win32.ScreenToClient(Parent.Handle, ref rect);
}
x = rect.left;
y = rect.top;
width = rect.right - rect.left;
height = rect.bottom - rect.top;
}
UpdateBounds (x, y, width, height);
// FIXME: this is needed, otherwise painting is not correct
if( dropDownStyle == ComboBoxStyle.Simple ) {
Win32.InvalidateRect(Handle, IntPtr.Zero, 0);
Win32.UpdateWindow(Handle);
}
}
// for IList interface
// FIXME not sure how to handle this
//[MonoTODO]
//protected override void SetItemsCore(IList value)
//{
// throw new NotImplementedException ();
//}
[MonoTODO]
public override string ToString()
{
//FIXME:
return base.ToString();
}
[MonoTODO]
protected override void WndProc(ref Message m)
{
switch ((Msg) m.Msg) {
case Msg.WM_MEASUREITEM: {
MEASUREITEMSTRUCT mis = new MEASUREITEMSTRUCT();
mis = (MEASUREITEMSTRUCT)Marshal.PtrToStructure(m.LParam, mis.GetType());
MeasureItemEventArgs args = new MeasureItemEventArgs(CreateGraphics(),mis.itemID);
args.ItemHeight = mis.itemHeight;
args.ItemWidth = mis.itemWidth;
OnMeasureItem( args);
mis.itemHeight = args.ItemHeight;
mis.itemWidth = args.ItemWidth;
Marshal.StructureToPtr(mis, m.LParam, false);
m.Result = (IntPtr)1;
}
break;
case Msg.WM_DRAWITEM: {
DRAWITEMSTRUCT dis = new DRAWITEMSTRUCT();
dis = (DRAWITEMSTRUCT)Marshal.PtrToStructure(m.LParam, dis.GetType());
Rectangle rect = new Rectangle(dis.rcItem.left, dis.rcItem.top, dis.rcItem.right - dis.rcItem.left, dis.rcItem.bottom - dis.rcItem.top);
DrawItemEventArgs args = new DrawItemEventArgs(Graphics.FromHdc(dis.hDC), Font,
rect, dis.itemID, (DrawItemState)dis.itemState);
OnDrawItem( args);
//Marshal.StructureToPtr(dis, m.LParam, false);
m.Result = (IntPtr)1;
}
break;
/*
case Msg.WM_COMPAREITEM: {
int i = 10;
}
break;
*/
case Msg.WM_COMMAND:
if( m.LParam != Handle) {
base.WndProc(ref m);
}
else {
switch(m.HiWordWParam) {
case (uint)ComboBoxNotification.CBN_SELCHANGE:
SelectedIndex = Win32.SendMessage(Handle, (int)ComboBoxMessages.CB_GETCURSEL, 0, 0);
m.Result = IntPtr.Zero;
break;
default:
m.Result = IntPtr.Zero;
break;
}
}
break;
case Msg.WM_CTLCOLOREDIT :
CallControlWndProc ( ref m );
break;
default:
base.WndProc(ref m);
break;
}
}
[MonoTODO]
protected override void SetItemsCore (IList value){
}
/// --- Button events ---
/// commented out, cause it only supports the .NET Framework infrastructure
[MonoTODO]
public event DrawItemEventHandler DrawItem;
[MonoTODO]
public event EventHandler DropDown;
[MonoTODO]
public event EventHandler DropDownStyleChanged;
[MonoTODO]
public event MeasureItemEventHandler MeasureItem;
/* only supports .NET framework
[MonoTODO]
public new event PaintEventHandler Paint;
*/
[MonoTODO]
public event EventHandler SelectedIndexChanged;
[MonoTODO]
public event EventHandler SelectionChangeCommitted;
[MonoTODO]
public class ChildAccessibleObject : AccessibleObject {
/// the class is not stubbed, cause it's only used for .NET framework
}
/// sub-class: ComboBox.ObjectCollection
/// <summary>
/// Represents the collection of items in a ComboBox.
/// </summary>
[MonoTODO]
public class ObjectCollection : IList, ICollection, IEnumerable {
private ArrayList collection_ = new ArrayList ();
private ComboBox owner_ = null;
/// --- ObjectCollection.constructor ---
[MonoTODO]
public ObjectCollection (ComboBox owner) {
owner_ = owner;
}
/// --- ObjectCollection Properties ---
[MonoTODO]
public int Count {
get {
return collection_.Count;
}
}
[MonoTODO]
public bool IsReadOnly {
get {
return collection_.IsReadOnly;
}
}
object IList.this[int index] {
get { return collection_[index]; }
set { collection_[index] = value; }
}
[MonoTODO]
public object this[int index] {
get { return collection_[index]; }
set { collection_[index] = value; }
}
/// --- ICollection properties ---
bool IList.IsFixedSize {
[MonoTODO] get { return collection_.IsFixedSize; }
}
object ICollection.SyncRoot {
get { return collection_.SyncRoot; }
}
bool ICollection.IsSynchronized {
[MonoTODO] get { return collection_.IsSynchronized; }
}
/// --- methods ---
/// --- ObjectCollection Methods ---
/// Note: IList methods are stubbed out, otherwise IList interface cannot be implemented
[MonoTODO]
public int Add(object item) {
// FIXME: not optimal
int idx = collection_.Add(item);
if( owner_.Sorted) {
ListControl.ListControlComparer cic = new ListControl.ListControlComparer(owner_);
collection_.Sort(cic);
idx = collection_.BinarySearch(item,cic);
if( owner_.IsHandleCreated) {
Win32.SendMessage(owner_.Handle, (int)ComboBoxMessages.CB_INSERTSTRING, idx, owner_.getDisplayMemberOfObj(item));
}
}
else {
if( owner_.IsHandleCreated) {
Win32.SendMessage(owner_.Handle, (int)ComboBoxMessages.CB_ADDSTRING, 0, owner_.getDisplayMemberOfObj(item));
}
}
return idx;
}
[MonoTODO]
public void AddRange(object[] items)
{
// FIXME: not optimal
foreach(object item in items) {
Add(item);
}
// owner_.populateControl(items);
// collection_.AddRange(items);
}
[MonoTODO]
public void Clear()
{
collection_.Clear();
Win32.SendMessage(owner_.Handle, (int)ComboBoxMessages.CB_RESETCONTENT, 0, 0);
}
[MonoTODO]
public bool Contains(object value)
{
return collection_.Contains(value);
}
[MonoTODO]
public void CopyTo(object[] dest,int arrayIndex)
{
collection_.CopyTo(dest, arrayIndex);
}
/// for ICollection:
[MonoTODO]
void ICollection.CopyTo(Array dest,int index)
{
collection_.CopyTo(dest, index);
}
[MonoTODO]
public IEnumerator GetEnumerator()
{
return collection_.GetEnumerator();
}
[MonoTODO]
public int IndexOf(object value)
{
return collection_.IndexOf(value);
}
[MonoTODO]
public void Insert(int index,object item)
{
//FIXME:
}
[MonoTODO]
public void Remove(object value)
{
//FIXME:
}
[MonoTODO]
public void RemoveAt(int index)
{
//FIXME:
}
} // --- end of ComboBox.ObjectCollection ---
}
}
|