I made one for my own gui editor, its a bit ugly but it does the job. here you go =)
Note!.. the key handling doesnt work properly :/
proplist.bmx
It uses this to set the border on some of the gadgets WIN32 only (just comment out any SetGadgetBorder function calls if you dont want it)
GadgetBorder.bmx
And here is the test source:
test.bmx
EDIT: oh,, and heres the icon file for the test ;)
Note!.. the key handling doesnt work properly :/
proplist.bmx
SuperStrict Const PROP_TEXT:Int = 0 ' text input Const PROP_NUM:Int = 1 ' number input Const PROP_LIST:Int = 2 ' list Const PROP_ELIST:Int = 3 ' editable list Const PROP_ILIST:Int = 4 ' icon list Type TPropertyField Field Class:Int Field Caption:String Field Text:String Field Index:Int Field Items:String[] Field Icons:Int[] Field IconStrip:TIconStrip Field Owner:TPropertyList Method StartEdit() 'Local xx:Int = (GadgetWidth(Owner.gadget) / 2) - 2 Local xx:Int = (TPropertyList.PROPERTY_WIDTH * (FontSize(Owner.font) - 1)) - FontSize(Owner.font) SetGadgetShape( Owner.controls[Class], xx - 3, Index * TPropertyList.PROPERTY_HEIGHT, xx - 1,TPropertyList.PROPERTYFIELD_HEIGHT) Select Class Case PROP_LIST, PROP_ELIST ClearGadgetItems Owner.controls[Class] For Local i:Int = 0 Until Items.Length AddGadgetItem( Owner.controls[Class], Items[i]) If Text = Items[i] Then SelectGadgetItem Owner.controls[Class], i Next If SelectedGadgetItem( Owner.controls[Class]) < 0 Then SelectGadgetItem Owner.controls[Class], 0 EndIf Case PROP_ILIST ClearGadgetItems Owner.controls[Class] SetGadgetIconStrip Owner.controls[Class], IconStrip For Local i:Int = 0 Until Items.Length AddGadgetItem( Owner.controls[Class], Items[i], 0, Icons[i]) If Text = Items[i] Then SelectGadgetItem Owner.controls[Class], i Next If SelectedGadgetItem( Owner.controls[Class]) < 0 Then SelectGadgetItem Owner.controls[Class], 0 EndIf Case PROP_NUM If Text.Length <= 0 Then Text = "0" EndSelect Owner.controls[Class].SetText( Text) ShowGadget Owner.controls[Class] Select Class Case PROP_TEXT, PROP_NUM SelectTextAreaText( Owner.controls[Class]) EndSelect ActivateGadget Owner.controls[Class] EndMethod Method EndEdit( store:Int = True) Local t:String Select Class Case PROP_TEXT, PROP_NUM t = TextAreaText( Owner.controls[Class]) Case PROP_LIST, PROP_ELIST, PROP_ILIST t = Owner.controls[Class].GetText() EndSelect If (t <> Text) And store Then Text = t Owner.UpdateGadget() EndIf DeselectGadgetItem( Owner.Gadget, Index) HideGadget Owner.controls[Class] EndMethod EndType Type TPropertyList Const PROPERTY_HEIGHT:Int = 14 Const PROPERTY_WIDTH:Int = 20 Const PROPERTYFIELD_HEIGHT:Int = 17 Field props:TList = New TList Field Gadget:TGadget Field controls:TGadget[5] Field font:TGUIFont Field lastprop:TPropertyField Function Create:TPropertyList( x:Int,y:Int,w:Int,h:Int, group:TGadget) Local list:TPropertyList = New TPropertyList list.Init( x,y, w,h, group) Return list EndFunction Function FilterText:Int( event:TEvent, context:Object) If event.ID = EVENT_KEYDOWN Then Local props:TPropertyList = TPropertyList( context) If Not props Then Return True Select event.Data Case KEY_ENTER ' complete edit props.EndEdit() Return False Case KEY_ESCAPE ' cancel edit props.CancelEdit() Return False Case KEY_UP ' complete edit and goto previous property If props.lastprop Then Local index:Int = props.lastprop.Index - 1 If index >= 0 Then props.lastprop.EndEdit() ActivateGadget( props.Gadget) SelectGadgetItem( props.Gadget, index) 'props.lastprop = TPropertyField( props.Props.ValueAtIndex( index)) 'If props.lastprop Then props.lastprop.StartEdit() EndIf EndIf Case KEY_DOWN ' complete edit and goto next property If props.lastprop Then Local index:Int = props.lastprop.Index + 1 If index < props.lastprop.Owner.Props.Count() Then props.lastprop.EndEdit() ActivateGadget( props.Gadget) SelectGadgetItem( props.Gadget, index) 'props.lastprop = TPropertyField( props.Props.ValueAtIndex( index)) 'If props.lastprop Then props.lastprop.StartEdit() EndIf EndIf EndSelect EndIf Return True EndFunction Function FilterNum:Int( event:TEvent, context:Object) If FilterText( event, context) Then Return (event.Data >= Asc("0")) And (event.Data <= Asc("9")) EndIf Return False EndFunction Method CancelEdit() If lastprop Then lastprop.EndEdit( False) lastprop = Null EndIf EndMethod Method EndEdit() If lastprop Then lastprop.EndEdit( True) lastprop = Null EndIf EndMethod Method Init( x:Int,y:Int, w:Int,h:Int, group:TGadget) Gadget = CreateListBox( x,y, w,h, group) font = LoadGuiFont( "Lucida Console", 10) SetGadgetFont( Gadget, font) controls[PROP_TEXT] = CreateTextArea( 0,-64, 32,PROPERTYFIELD_HEIGHT, Gadget) SetGadgetFilter controls[PROP_TEXT], FilterText, Self controls[PROP_NUM] = CreateTextArea( 0,-64, 32,PROPERTYFIELD_HEIGHT, Gadget) SetGadgetFilter controls[PROP_NUM], FilterNum, Self controls[PROP_LIST] = CreateComboBox( 0,-64, 32,PROPERTYFIELD_HEIGHT, Gadget) controls[PROP_ELIST] = CreateComboBox( 0,-64, 32,PROPERTYFIELD_HEIGHT, Gadget, COMBOBOX_EDITABLE) controls[PROP_ILIST] = CreateComboBox( 0,-64, 32,PROPERTYFIELD_HEIGHT, Gadget) SetGadgetBorder( controls[PROP_TEXT], BORDER_THIN) SetGadgetBorder( controls[PROP_NUM], BORDER_THIN) HideGadget controls[PROP_TEXT] HideGadget controls[PROP_NUM] HideGadget controls[PROP_LIST] HideGadget controls[PROP_ELIST] HideGadget controls[PROP_ILIST] EndMethod Method AddTextProperty:TPropertyField( caption:String, text:String = Null) Local prop:TPropertyField = New TPropertyField prop.Class = PROP_TEXT prop.Caption = caption prop.Text = text prop.Owner = Self prop.Index = props.Count() props.AddLast( prop) Return prop EndMethod Method AddNumberProperty:TPropertyField( caption:String, text:String = "0") Local prop:TPropertyField = New TPropertyField prop.Class = PROP_NUM prop.Caption = caption prop.Text = text prop.Owner = Self prop.Index = props.Count() props.AddLast( prop) Return prop EndMethod Method AddListProperty:TPropertyField( caption:String, items:String[], index:Int = 0) Local prop:TPropertyField = New TPropertyField prop.Class = PROP_LIST prop.Caption = caption prop.Items = items If index < 0 Then prop.Text = items[0] ElseIf index >= items.Length Then prop.Text = items[items.Length-1] Else prop.Text = items[index] EndIf prop.Index = props.Count() prop.Owner = Self props.AddLast( prop) Return prop EndMethod Method AddEditListProperty:TPropertyField( caption:String, items:String[], index:Int = 0) Local prop:TPropertyField = New TPropertyField prop.Class = PROP_ELIST prop.Caption = caption prop.Items = items If index < 0 Then prop.Text = items[0] ElseIf index >= items.Length Then prop.Text = items[items.Length-1] Else prop.Text = items[index] EndIf prop.Index = props.Count() prop.Owner = Self props.AddLast( prop) Return prop EndMethod Method AddIconListProperty:TPropertyField( caption:String, items:String[], iconstrip:TIconStrip, icons:Int[] = Null, index:Int = 0) Local prop:TPropertyField = New TPropertyField prop.Class = PROP_ILIST prop.Caption = caption prop.Items = items prop.IconStrip = iconstrip prop.Icons = icons If index < 0 Then prop.Text = items[0] ElseIf index >= items.Length Then prop.Text = items[items.Length-1] Else prop.Text = items[index] EndIf prop.Index = props.Count() prop.Owner = Self props.AddLast( prop) Return prop EndMethod Method UpdateGadget() Local index:Int = SelectedGadgetItem( Gadget) ClearGadgetItems( Gadget) For Local prop:TPropertyField = EachIn props Local text:String = LSet( prop.Caption,PROPERTY_WIDTH) + "|" If prop.Text.Length > 0 Then If prop.Text.Length > PROPERTY_WIDTH Then ' downsize string AddGadgetItem( Gadget, text + prop.Text[..PROPERTY_WIDTH-3] + "...", 0,-1,"", prop) Else AddGadgetItem( Gadget, text + RSet( prop.Text, PROPERTY_WIDTH), 0,-1,"", prop) EndIf Else AddGadgetItem( Gadget, text + RSet( "", PROPERTY_WIDTH), 0,-1,"", prop) EndIf Next SelectGadgetItem( Gadget, index) EndMethod Method ProcessEvent:Int( event:TEvent) Select event.ID Case EVENT_GADGETSELECT Select event.Source Case Gadget EndEdit() Local prop:TPropertyField = TPropertyField( EventExtra()) If prop Then prop.StartEdit() lastprop = prop EndIf Return True EndSelect Case EVENT_GADGETACTION Select event.Source Case Gadget EndEdit() Return True Case Controls[PROP_LIST], Controls[PROP_ELIST] EndEdit() Return True EndSelect EndSelect Return False EndMethod EndType
It uses this to set the border on some of the gadgets WIN32 only (just comment out any SetGadgetBorder function calls if you dont want it)
GadgetBorder.bmx
SuperStrict ?MacOS DebugLog "GadgetBorder.bmx doesnt support MacOS" ?Linux DebugLog "GadgetBorder.bmx doesnt support Linux" ? Private ?Win32 Const SWP_DRAWFRAME:Int = 32 Const SWP_FRAMECHANGED:Int = 32 Const SWP_HIDEWINDOW:Int = 128 Const SWP_NOACTIVATE:Int = 16 Const SWP_NOCOPYBITS:Int = 256 Const SWP_NOMOVE:Int = 2 Const SWP_NOSIZE:Int = 1 Const SWP_NOREDRAW:Int = 8 Const SWP_NOZORDER:Int = 4 Const SWP_SHOWWINDOW:Int = 64 Const SWP_NOOWNERZORDER:Int = 512 Const SWP_NOREPOSITION:Int = 512 Const SWP_NOSENDCHANGING:Int = 1024 Const SWP_DEFERERASE:Int = 8192 Const SWP_ASYNCWINDOWPOS:Int = 16384 Const RDW_ERASE:Int = 4 Const RDW_FRAME:Int = 1024 Const RDW_INTERNALPAINT:Int = 2 Const RDW_INVALIDATE:Int = 1 Const RDW_NOERASE:Int = 32 Const RDW_NOFRAME:Int = 2048 Const RDW_NOINTERNALPAINT:Int = 16 Const RDW_VALIDATE:Int = 8 Const RDW_ERASENOW:Int = 512 Const RDW_UPDATENOW:Int = 256 Const RDW_ALLCHILDREN:Int = 128 Const RDW_NOCHILDREN:Int = 64 Const WS_BORDER:Int = $800000 ' thin border Const WS_EX_CLIENTEDGE:Int = 512 ' 3d border Extern "Win32" Function GetWindowLong:Int( hwnd:Int, index:Int) = "GetWindowLongA@8" Function SetWindowLong:Int( hwnd:Int, index:Int, value:Int) = "SetWindowLongA@12" Function SetWindowPos:Int( hwnd:Int, hwndafter:Int, x:Int,y:Int, cx:Int,cy:Int, flags:Int) Function RedrawWindow:Int( hwnd:Int, rect:Byte Ptr, region:Int, flags:Int) EndExtern ? Public Const BORDER_NONE:Int = 0 Const BORDER_3D:Int = 1 Const BORDER_THIN:Int = 2 Function SetGadgetBorder( gadget:TGadget, flags:Int) ?Win32 Local hwnd:Int = gadget.Query( QUERY_HWND) Local style:Int = GetWindowLong( hwnd, GWL_STYLE) Local exstyle:Int = GetWindowLong( hwnd, GWL_EXSTYLE) Select flags Case BORDER_NONE ' remove both border types If style & WS_BORDER Then SetWindowLong( hwnd, GWL_STYLE, style & ~WS_BORDER) If exstyle & WS_EX_CLIENTEDGE Then SetWindowLong( hwnd, GWL_EXSTYLE, exstyle & ~WS_EX_CLIENTEDGE) Case BORDER_THIN ' add thin border & remove 3d border If Not (style & WS_BORDER) Then SetWindowLong( hwnd, GWL_STYLE, style | WS_BORDER) If exstyle & WS_EX_CLIENTEDGE Then SetWindowLong( hwnd, GWL_EXSTYLE, exstyle & ~WS_EX_CLIENTEDGE) Case BORDER_3D ' remove thin border & add 3d border If style & WS_BORDER Then SetWindowLong( hwnd, GWL_STYLE, style & ~WS_BORDER) If Not (exstyle & WS_EX_CLIENTEDGE) Then SetWindowLong( hwnd, GWL_EXSTYLE, exstyle | WS_EX_CLIENTEDGE) EndSelect ' update window frame SetWindowPos( hwnd,0, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED) RedrawWindow( hwnd, Null,0, RDW_INVALIDATE | RDW_NOCHILDREN | RDW_UPDATENOW | RDW_FRAME) ? EndFunction
And here is the test source:
test.bmx
SuperStrict Import "proplist.bmx" Import "GadgetBorder.bmx" Const WINDOW_FLAGS:Int = WINDOW_TITLEBAR | WINDOW_RESIZABLE '| WINDOW_MENU ' main window Global window:TGadget = CreateWindow( "Properties", 64,64, 340,480, Null, WINDOW_FLAGS | WINDOW_CLIENTCOORDS) Global props:TPropertyList = TPropertyList.Create( 0,0, 340,ClientHeight(window), window) SetGadgetLayout props.Gadget, 1,1,1,1 Global StandardIconStrip:TIconStrip = LoadIconStrip( "icons.png") Local LayoutItems:String[] = [ "CENTERED", "ALIGNED", "RELATIVE" ] Local BooleanItems:String[] = [ "FALSE", "TRUE" ] Local IconStripItems:String[] = [ "NONE", "STANDARD" ] Local StandardIconItems:String[] = [ "NONE", "0", "1", "2", "3", "4", "5", "6", "7"] Local StandardIconIcons:Int[] = [ -1, 0, 1, 2, 3, 4, 5, 6, 7 ] Local prop:TPropertyField props.AddNumberProperty( "ID") props.AddTextProperty( "Caption") props.AddIconListProperty( "Icon", StandardIconItems, StandardIconStrip, StandardIconIcons) props.AddListProperty( "IconStrip", IconStripItems) props.AddTextProperty( "Description") props.AddListProperty( "Layout.Right", LayoutItems) props.AddListProperty( "Layout.Left", LayoutItems) props.AddListProperty( "Layout.Top", LayoutItems) props.AddListProperty( "Layout.Bottom", LayoutItems) props.UpdateGadget() While WaitEvent() If Not props.ProcessEvent( CurrentEvent) Then Select EventID() Case EVENT_WINDOWCLOSE Select EventSource() Case window Exit EndSelect EndSelect EndIf Wend End
EDIT: oh,, and heres the icon file for the test ;)