Ok, I've almost got the listbox working as a dialogue, it gets a lot more complicated when allowing other things to continue along side it.
new include stringlist.bb:
gui.bb
place the following in editor.bb just before the FLIP command:
press L with debug on to see the ListBox functioning
There are some issues with it still, for instance the tooltip and the up and down arrows selecting the item does not scroll the box.
I also added colour options to the various controls, as demonstrated by pressing E whilst the editor is running.
*EDIT*
there is an issue with the OK and CANCEL buttons on the test inputbox in that when you press them, you end up overwriting the tile underneath. No amount of FlushMouse() commands or bashing the keyboard with a banana seems to affect it.
*EDIT*
oh yeah, nice graphics btw Rob :)
new include stringlist.bb:
; Use a reasonably large number to limit the number ; of lines that a stringlist can contain Const MaxStringListSize = 512 Type TStringItem Field FString$ Field FObject% Field FUsed = False End Type Type TStringList Field FItems.TStringItem[MaxStringListSize] Field FCount End Type ;CONSTRUCTOR; ;;;;;;;;;;;;;;;;;;; ; FUNCTION Create ; ;;;;;;;;;;;;;;;;;;; Function Create.TStringList() Local sList.TStringList = New TStringList ;can add any initialization code here so that all new stringlists ;start with the same values For t = 0 To MaxStringListSize sList\FItems.TStringItem[t] = New TStringItem Next Return sList End Function ;DESTRUCTOR; ;;;;;;;;;;;;;;;;;;;; ; FUNCTION Destroy ; ;;;;;;;;;;;;;;;;;;;; Function Destroy(sList.TStringList) For t = 0 To MaxStringListSize Delete sList\FItems[t] Next Delete sList End Function ;;;;;;;;;;;;;;;;;;;; ; FUNCTION GetText ; ;;;;;;;;;;;;;;;;;;;; ;returns all the items as one single string Function GetText$(sList.TStringList) ;VARS Local result$ = "" ;MAIN For i = 0 To GetCount(sList) result$ = result$ + sList\FItems[i]\FString$ Next Return result$ End Function ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; FUNCTION Strings ; ; return the string of the item at the specified index ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Function Strings$(sList.TStringList, Index%) Return sList\FItems[Index]\FString$ End Function ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; FUNCTION AddItem ; ; if index > -1 then insert the item at the specified index ; ; will return the index the item is added at. ; ; if the return value is <0 then an error has occured ; ; (probably exceeded MaxStringListSize) ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Function AddItem(sList.TStringList, txt$, Obj%=0, Index%=-1) Local result = -1 ;set the default result to a failure, only a success will change this Local Count = GetCount(sList) If Index > MaxStringListSize Then Return -1 If Count => MaxStringListSize Then Return -1 If Index < 0 Then ;add to the end sList\FItems[Count]\FString$ = txt$ sList\FItems[Count]\FObject% = Obj% sList\FItems[Count]\FUsed = True result = Count Else For i = Count To Index + 1 Step -1 sList\FItems[i]\FString$ = sList\FItems[i-1]\FString$ sList\FItems[i]\FObject% = sList\FItems[i-1]\FObject% sList\FItems[i]\FUsed = sList\FItems[i-1]\FUsed Next sList\FItems[Index]\FString$ = txt$ sList\FItems[Index]\FObject% = Obj% sList\FItems[Index]\FUsed = True result = Index EndIf GetCount(sList) Return result End Function ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; FUNCTION DeleteItem ; ; Delete the line with the specified index ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Function DeleteItem(sList.TStringList, Index%) ;If the index passed is out of bounds then leave the function If (index < 0) Or (Index > MaxStringListSize) Then Return If Index < MaxStringListSize Then For i = Index To MaxStringListSize-1 If i < MaxStringListSize Then sList\FItems[i]\FString$ = sList\FItems[i+1]\FString$ sList\FItems[i]\FObject% = sList\FItems[i+1]\FObject% sList\FItems[i]\FUsed = sList\FItems[i+1]\FUsed EndIf ;clear the next line, this will result in the last line not being used sList\FItems[i+1]\FString$ = "" sList\FItems[i+1]\FObject% = 0 sList\FItems[i+1]\FUsed = False ;EndIf Next Else ;if the Index is equal to the MaxStringListSize then just clear it sList\FItems[Index]\FString$ = "" sList\FItems[Index]\FObject% = 0 sList\FItems[Index]\FUsed = False EndIf GetCount(sList) End Function ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; FUNCTION GetCount ; ; Returns the number of items ; ; in the list (Not THE HIGHEST INDEX) ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Function GetCount(sList.TStringList) ;VARS Local Used = 1 Local Count = 0 ;MAIN While (Used <> 0) And (Count < MaxStringListSize) Used = sList\FItems[Count]\FUsed If used Then Count = Count + 1 Wend sList\FCount = Count Return sList\FCount End Function ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;TEST;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Print Getcount(sl) ;AddItem(sl,"Third Line of Text" + Chr$(13)) ;Print Getcount(sl) ;AddItem(sl,"Fourth Line of Text") ;Print Getcount(sl) ;Print GetText(sl) ;DeleteItem(sl,0) ;Print GetText(sl) ;Print Getcount(sl) ;Print strings(sl,2) ;Print GetText(sl) ; ;AddItem(sl,"New Line inserted at 1",0,1) ; ; ;Print Str(sl) ;For i = 0 To GetCount(sl)-1 ; Print Strings(sl,i) ;Next ; ;Destroy sl ; ;Print Str(sl) ; ;WaitKey() ;End
gui.bb
;Global font = LoadFont("Arial.ttf",15) ;Global symbFont = LoadFont("Symbol.ttf",15) Include "inc\stringlist.bb" Dim CharWidths(1) Const KeyRepeat% = 100 Const CaratSymbol$ = "¦" Type TRGB Field ColRed% Field ColGreen% Field ColBlue% End Type Global myRGB.TRGB = New TRGB Type TCarat ;X and Y in characters not pixels Field X% Field Y% Field PX% Field PY% Field Symbol$ = "¦" End Type Type TKeyState Field Scancode% Field Ascii% Field Shift Field Ctrl End Type Type TLine Field LineNum% Field Txt$ Field Owner$ End Type ;;;;;;;;;;;;;;;;;;;; ; FUNCTION InitGUI ; ;;;;;;;;;;;;;;;;;;;; Function InitGUI() SetFont font ;INPUT BOX SETUP ;Get the character widths Dim charwidths(512) charwidths(32) = 4 For c = 33 To 512 charwidths(c) = StringWidth(Chr$(c)) Next End Function ;;;;;;;;;;;;;;;;;;; ; FUNCTION Button ; ;;;;;;;;;;;;;;;;;;; Function Button(x,y,width,name$,active=False, symbol=False, ShortCutKey=KEY_NONE, ShowShortCut = True, OffCol%=$A0A0A0, OverCol%=$C8C8C8, TextCol%=$000000) ;VARS Local result = False ;MAIN If RectsOverlap(MouseX(),MouseY(),1,1,x,y,width,16) Then myRGB = GetRGB(OverCol) Color myRGB\ColRed, myRGB\ColGreen, myRGB\ColBlue Else myRGB = GetRGB(OffCol) Color myRGB\ColRed, myRGB\ColGreen, myRGB\ColBlue EndIf Rect x,y,width,16 myRGB = GetRGB(TextCol) Color myRGB\ColRed, myRGB\ColGreen, myRGB\ColBlue If Symbol Then SetFont symbFont If (ShortCutKey > KEY_NONE) And (ShowShortCut) Then name = name + " ("+ KeyNames(ShortCutKey) +")" Text x+width/2,y+7,name,True,True If Symbol Then SetFont Font If active Then Color 255,0,0:Rect x,y,width,16,False If RectsOverlap(MouseX(),MouseY(),1,1,x,y,width,16) And MouseDown(1) Then result = True If ShortCutKey > KEY_NONE Then If KeyDown(ShortCutKey) Then Result = True EndIf Return Result End Function ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; FUNCTION InputBox ; ; Parameters: ; ; msg$ : any message to display above the input box ; ; x,y : top left coords ; ; width, height: outer width and height of inputbox ; ; rtnSubmit : if the return key is pressed, then ; ; automatically submit the text ; ; If this is false, then an OK button is ; ; displayed at the bottom of the box ; ; DefaultText : automatically inserts this into the ; ; input box, the carat will be positioned at the end ; ; of this text. ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Function InputBox$(Msg$,x,y,width,height,rtnSubmit=True, DefaultText$="", BGCol%=$FFFFFF, TextCol%=$000000, BorderCol%=$A0A0A0) SetFont Font ;;;;;; ;vars; ;;;;;; Local leave = False Local InnerWidth = Width - 6 Local InnerHeight = Height - 40 Local InnerX = 6 Local InnerY = 20 Local retString$ = "" Local fntWidth = FontWidth()/4 Local fntHeight = FontHeight() Local EditWin = CreateImage(width, height) Local Delimiters$ = "|() "+Chr$(13) Local FoundDelim = False Local TopLine = 0 Local Carat.TCarat = New TCarat Carat\X = 0 Carat\Y = 0 Local SelStart% = 0 Local SelEnd% = 0 Local CaratPos% = 0 Local ScrollPos = 0 Local ScrollWidth = 12 ;;;;;; ;main; ;;;;;; If rtnSubmit Then InnerHeight = Height - 6 FlushKeys() CaratPos = Len(DefaultText) retString = retString+DefaultText Repeat ;quit the function without returning any text if escape is pressed If KeyHit(1) Then leave = True retString$ = "" EndIf ;;;;;;;;;;;;;;;;;;;;; ;get character input; ;;;;;;;;;;;;;;;;;;;;; get = GetKey() If Get = 13 Then If rtnSubmit Then leave = True ;if return is pressed and rtnSubmit is True then leave Else LeftSide$ = Left$(retString$,CaratPos) RightSide$ = Right$(retString$, Len(RetString)-CaratPos) retString$ = LeftSide$ + Chr(get) + RightSide$ CaratPos = CaratPos + 1 EndIf ElseIf KeyDown(14); backspace If MilliSecs()-LastInput > KeyRepeat Then If Len(retString$) > 0 Then LeftSide$ = Left$(retString$,CaratPos) RightSide$ = Right$(retString$, Len(RetString)-CaratPos) retString$ = Left$(LeftSide$, Len(LeftSide$) -1) + RightSide$ EndIf LastInput = MilliSecs() CaratPos = CaratPos - 1 If CaratPos < 0 Then CaratPos = 0 EndIf ElseIf KeyDown(203) ;Left Cursor If MilliSecs()-LastInput > KeyRepeat Then If KeyDown(157) ; CTRL ; Allow CTRL+Left to jump the carat pos to the next delimiter to the left of the cursor For i = CaratPos To 1 Step -1 d = 1 While (d < Len(Delimiters$)+1) And (Not FoundDelim ) If Mid(retString$, i,1) = Mid(Delimiters$, d,1) Then CaratPos = i-1 FoundDelim = True EndIf d = d + 1 Wend If FoundDelim Then Exit Next If Not FoundDelim Then CaratPos = CaratPos - 1 If CaratPos < 0 Then CaratPos = 0 FoundDelim = False Else CaratPos = CaratPos - 1 If CaratPos < 0 Then CaratPos = 0 EndIf LastInput = MilliSecs() EndIf ElseIf KeyDown(205) ; RIGHT CURSOR If MilliSecs()-LastInput > KeyRepeat Then If KeyDown(157) ;CTRL ; Allow CTRL+RIGHT to jump the carat pos to the next delimiter to the right of the cursor For i = CaratPos+1 To Len(retString$) d = 1 While (d < Len(Delimiters$)+1) And (Not FoundDelim ) If Mid(retString$, i,1) = Mid(Delimiters$, d,1) Then CaratPos = i FoundDelim = True EndIf d = d + 1 Wend If FoundDelim Then Exit Next If Not FoundDelim Then CaratPos = CaratPos + 1 If CaratPos > Len(retString$) Then CaratPos = Len(retString$) FoundDelim = False Else CaratPos = CaratPos + 1 If CaratPos > Len(retString$) Then CaratPos = Len(retString$) EndIf LastInput = MilliSecs() EndIf ElseIf KeyDown(207) ; end CaratPos = Len(retString$) ElseIf KeyDown(199) ; home CaratPos = 0 ElseIf (get > 31) ;is a letter, number or symbol LeftSide$ = Left$(retString$,CaratPos) RightSide$ = Right$(retString$, Len(RetString)-CaratPos) retString$ = LeftSide$ + Chr(get) + RightSide$ CaratPos = CaratPos + 1 EndIf ;Draw the edit window oldbuffer = GraphicsBuffer() SetBuffer ImageBuffer(EditWin) myRGB = GetRGB(BorderCol) Color myRGB\ColRed, myRGB\ColGreen, myRGB\ColBlue Rect 0,0,width,height myRGB = GetRGB(BGCol) Color myRGB\ColRed, myRGB\ColGreen, myRGB\ColBlue Rect 2, 17, InnerWidth , InnerHeight myRGB = GetRGB(TextCol) Color myRGB\ColRed, myRGB\ColGreen, myRGB\ColBlue Text width/2,8,msg,True,True Viewport 2, 17, InnerWidth ,InnerHeight ;Draw Edit Content Local WCount% = 0 Local LineCount% = 0 Local CharCount% = 0 Local tempString$ = "" ;Local tempString2$ = "" Local StringLength% = Len(retString$) Local CurrentChar$ = "" Local LineLength% = 0 While CharCount < StringLength Repeat CharCount = CharCount + 1 Currentchar$ = Mid$(retString$, CharCount,1) If Charcount = CaratPos+1 Then tempString$ = tempString$ + CaratSymbol$ tempString$ = tempString$ + CurrentChar$ charWidth = CharWidths(Asc(CurrentChar)) WCount = WCount + charWidth Until (WCount > InnerWidth - 8) Or (CharCount = StringLength) Or (Asc(CurrentChar) = 13) If Right$(tempString,1) = Chr(13) Then tempString$ = Left(TempString$,Len(TempString$)-1) EndIf myRGB = GetRGB(TextCol) Color myRGB\ColRed, myRGB\ColGreen, myRGB\ColBlue If (CaratPos = StringLength) And (CaratPos = CharCount) Then tempString = tempString + CaratSymbol Text InnerX,InnerY + (LineCount * fntHeight),tempString$,False,False LineCount = LineCount + 1 tempString$ = "" WCount = 0 Wend SetBuffer OldBuffer DrawImage EditWin,x,y Viewport 0,0,GraphicsWidth(), GraphicsHeight() If Not rtnSubmit Then If Button(x+(Width/2)-95,y+Height-20,80,"OK",False,False,KEY_INSERT,False,BorderCol,BGCol,TextCol) Then leave = True If Button(x+(Width/2)+5,y+Height-20,100,"Cancel",False,False,KEY_ESCAPE,False,BorderCol,BGCol,TextCol) Then retString = "" leave = True EndIf EndIf Flip Until leave = True FlushKeys() FlushMouse() FreeImage EditWin Return retString$ End Function ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; FUNCTION GetRGB ; ; converts an int to R/G/B colour ; ; returns a type of TRGB ; ; example Usage: ; ; myRGB.TRGB = New TRGB ; ; myRGB = GetRGB($FF55FF) ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Function GetRGB.TRGB(InColour%) Local tempRGB.TRGB = New TRGB tempRGB\ColRed = InColour% Shr 16 And 255 Shl 0 tempRGB\ColGreen = InColour% Shr 8 And 255 Shl 0 tempRGB\ColBlue = InColour% Shr 0 And 255 Shl 0 Return tempRGB End Function ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; FUNCTION ListBox ; ; returns the index of the selected item ; ; parameters: ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Function ListDlg%(X%, Y%, Width%, Height%, Items.TStringList, BGCol%=$FFFFFF, TextCol%=$000000, BorderCol%=$A0A0A0) ; myRGB = GetRGB(TextCol) ; Color myRGB\ColRed, myRGB\ColGreen, myRGB\ColBlue SetFont Font ;;;;;; ;VARS; ;;;;;; Local BorderWidth% = 2 Local InnerX% = X + BorderWidth Local InnerY% = Y + BorderWidth Local InnerWidth% = Width - (BorderWidth * 2) Local InnerHeight% = Height - (BorderWidth * 2) Local ListWin = CreateImage(Width, Height) Local LastTipRect = CreateImage(1,FontHeight()) Local Selected% = -1 Local ScrollOffset% = 0 Local ScrollBarWidth = 12 Local leave = False Local Result = -1 ;;;;;; ;MAIN; ;;;;;; If GetCount(items) < 1 Then Return -1 While Not Leave ;check keyboard input If KeyHit(1) Then Result = -1 Leave = True EndIf ;28 Or 156 = Return Or Enter If KeyHit(28) Or KeyHit(156) Then Result=Selected Leave = True EndIf ;up arrow If KeyHit(200) Then selected = selected -1 If selected < 0 Then selected = 0 EndIf ;down arrow If KeyHit(208) Then selected = selected + 1 If selected > GetCount(Items)-1 Then Selected = Getcount(Items)-1 EndIf ;check mouse input mx = MouseX() my = MouseY() If (mx > InnerX+2) And (mx < InnerX + (InnerWidth-ScrollWidth-4)) Then If (my > InnerY+2) And (my < (InnerY + (InnerHeight-2)) ) Then If MouseDown(1) Then Selected = ( ( (my - InnerY) - ScrollOffset) / FontHeight()) If Selected < 0 Then selected = 0 If selected > GetCount(Items)-1 Then selected = Getcount(Items)-1 EndIf ;maybe do a tooltip here if the item the mouse ;is over is longer than the width of the list EndIf EndIf ;draw listbox If GetCount(items) * FontHeight() > InnerHeight Then ScrollBarWidth = 16 Else ScrollBarWidth = 0 EndIf InnerWidth = ((Width - (BorderWidth * 2)) - ScrollBarWidth ) + 4 oldbuffer = GraphicsBuffer() SetBuffer ImageBuffer(ListWin) ;draw Border myRGB = GetRGB(BorderCol) Color myRGB\ColRed, myRGB\ColGreen, myRGB\ColBlue Rect 0, 0, Width, Height, True ;Draw background myRGB = GetRGB(BGCol) Color myRGB\ColRed, myRGB\ColGreen, myRGB\ColBlue Rect BorderWidth, BorderWidth, InnerWidth - (BorderWidth*2), InnerHeight - (BorderWidth), True ;clip to inner rectangle Viewport BorderWidth + 2, BorderWidth + 2, InnerWidth-8, InnerHeight-8 ;draw the text For i% = 0 To GetCount(items)-1 If i = selected Then ;draw a rect over the selected area myRGB = GetRGB(TextCol) Color myRGB\ColRed+2, myRGB\ColGreen+2, myRGB\ColBlue+2 ;for some reason, changing the following colour to black (0,0,0), draws as transparent ;Color 10,10,10 Rect BorderWidth + 2, (i * FontHeight())+ ScrollOffset, InnerWidth%, FontHeight(), True myRGB = GetRGB(BGCol) Color myRGB\ColRed, myRGB\ColGreen, myRGB\ColBlue Else myRGB = GetRGB(TextCol) Color myRGB\ColRed, myRGB\ColGreen, myRGB\ColBlue EndIf Text BorderWidth+2, (i * FontHeight())+ ScrollOffset, Strings(items, i), False, False Next Viewport 0,0,Width,Height SetBuffer oldbuffer DrawImage Listwin, x,y mz = MouseZSpeed() If Button (X + Width - ScrollBarWidth, y + BorderWidth, 12, "", False, True) Or mz = 1 Then ;scroll up ScrollOffset = ScrollOffset + FontHeight() If ScrollOffset > 0 Then ScrollOffset = 0 EndIf If Button (x + Width - ScrollBarWidth, (y + Height - FontHeight()) - BorderWidth, 12, "¯", False, True) Or mz = -1 Then ;scroll down ScrollOffset = ScrollOffset - FontHeight() If ScrollOffset < -( (GetCount(Items)-1) * FontHeight()) Then ScrollOffset = -( (GetCount(Items)-1) * FontHeight()) EndIf If selected > -1 Then s$ = Strings(items, selected) If StringWidth(s$)>InnerWidth-4 Then tooltip(InnerX+2,InnerY + (Selected * FontHeight()),s$) EndIf Flip Wend Return result End Function ;;;;;;;;;;;;;;;;;;;; ; FUNCTION ToolTip ; ;;;;;;;;;;;;;;;;;;;; Function ToolTip(x,y,txt$) Color 255,255,225 Rect x,y,StringWidth(txt$)+4,FontHeight()+4,True Color 0,0,0 Rect x,y,StringWidth(txt$)+4,FontHeight()+4,False Text x+2,y+2,txt$ End Function
place the following in editor.bb just before the FLIP command:
;test section ;L Key for list ;If KeyDown(38) Then DebugLog List(10,10,180,200,"test1|test2|test3",0) If KeyDown(38) Then ;lbShow = True mySL.TStringList = Create() addItem(mySL, "Item 1") addItem(mySL, "Item 2") addItem(mySL, "Item 3") addItem(mySL, "Item 4") addItem(mySL, "Item 5") addItem(mySL, "Item 6 is a longer item than the others, I am testing the overflow issue and it appears to clip nicely.") addItem(mySL, "Item 7") addItem(mySL, "Item 8") addItem(mySL, "Item 9") addItem(mySL, "Item 10") addItem(mySL, "Item 7") addItem(mySL, "Item 8") addItem(mySL, "Item 9") addItem(mySL, "Item 10") addItem(mySL, "Item 7") addItem(mySL, "Item 8") addItem(mySL, "Item 9") addItem(mySL, "Item 10") addItem(mySL, "Item 7") addItem(mySL, "Item 8") addItem(mySL, "Item 9") addItem(mySL, "Item 10") addItem(mySL, "Item 7") addItem(mySL, "Item 8") addItem(mySL, "Item 9") addItem(mySL, "Item 10") DebugLog ListDlg(10,10,240,350,mySL) EndIf ;slowdown issues with this ;If lbShow Then ;DebugLog ListDlg(10,10,240,350,mySL) ;EndIf If KeyDown(18) Then InputBox$("Welcome to Intex Systems", 100, 100, 300, 300, False, "InputBox1", $004400, $00FF00, $002200) FlushMouse() EndIf
press L with debug on to see the ListBox functioning
There are some issues with it still, for instance the tooltip and the up and down arrows selecting the item does not scroll the box.
I also added colour options to the various controls, as demonstrated by pressing E whilst the editor is running.
*EDIT*
there is an issue with the OK and CANCEL buttons on the test inputbox in that when you press them, you end up overwriting the tile underneath. No amount of FlushMouse() commands or bashing the keyboard with a banana seems to affect it.
*EDIT*
oh yeah, nice graphics btw Rob :)