From 3052219e28be94383fb4e63c977f1d62aa555e6d Mon Sep 17 00:00:00 2001 From: Ian C Date: Thu, 12 Dec 2019 23:07:52 +0000 Subject: Tweaks to compile with BlitzMax NG. Removed the glflag module as it doesn't compile anymore. --- algorithm.mod/.cvsignore | 7 +- bitmapfont.mod/.cvsignore | 5 +- gfxmenu.mod/.cvsignore | 7 +- glflag.mod/.cvsignore | 4 - glflag.mod/glflag.bmx | 210 --- keysyms.mod/.cvsignore | 7 +- mwidget.mod/.cvsignore | 7 +- showlicense.mod/.cvsignore | 1 + simplegui.mod/.cvsignore | 7 +- simplegui.mod/simplegui.bmx | 3364 +++++++++++++++++++++---------------------- vector.mod/.cvsignore | 7 +- vectorgfx.mod/.cvsignore | 8 +- win32.mod/.cvsignore | 7 +- 13 files changed, 1711 insertions(+), 1930 deletions(-) delete mode 100644 glflag.mod/.cvsignore delete mode 100644 glflag.mod/glflag.bmx diff --git a/algorithm.mod/.cvsignore b/algorithm.mod/.cvsignore index 16d9505..0f5601a 100644 --- a/algorithm.mod/.cvsignore +++ b/algorithm.mod/.cvsignore @@ -1,6 +1,5 @@ .bmx doc -algorithm.debug.win32.a -algorithm.debug.win32.i -algorithm.release.win32.a -algorithm.release.win32.i +*.a +*.i +*.i2 diff --git a/bitmapfont.mod/.cvsignore b/bitmapfont.mod/.cvsignore index 75c593a..0f5601a 100644 --- a/bitmapfont.mod/.cvsignore +++ b/bitmapfont.mod/.cvsignore @@ -1,4 +1,5 @@ .bmx doc -bitmapfont.debug.win32.i -bitmapfont.release.win32.i +*.a +*.i +*.i2 diff --git a/gfxmenu.mod/.cvsignore b/gfxmenu.mod/.cvsignore index 9565593..0f5601a 100644 --- a/gfxmenu.mod/.cvsignore +++ b/gfxmenu.mod/.cvsignore @@ -1,6 +1,5 @@ -gfxmenu.release.win32.i -gfxmenu.debug.win32.a -gfxmenu.debug.win32.i -gfxmenu.release.win32.a .bmx doc +*.a +*.i +*.i2 diff --git a/glflag.mod/.cvsignore b/glflag.mod/.cvsignore deleted file mode 100644 index 84d3b1f..0000000 --- a/glflag.mod/.cvsignore +++ /dev/null @@ -1,4 +0,0 @@ -glflag.release.win32.i -glflag.debug.win32.i -.bmx -doc diff --git a/glflag.mod/glflag.bmx b/glflag.mod/glflag.bmx deleted file mode 100644 index 2efab50..0000000 --- a/glflag.mod/glflag.bmx +++ /dev/null @@ -1,210 +0,0 @@ -' Copyright (c) 2006 Ian Cowburn -' -' 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. -' -' $Id$ -' -Module noddybox.glflag - -ModuleInfo "Framework: Simple Open GL Backdrop flag" -ModuleInfo "Copyright: Ian Cowburn -- released under the MIT License" -ModuleInfo "Author: Ian Cowburn" -ModuleInfo "Version: $Revision$" - -Import brl.Basic -Import pub.OpenGL - -Strict - -Type TGLFlag - - ' These are public and can be used to modify the flag - ' - Field xpos:Float - Field ypos:Float - Field zpos:Float - Field xrot:Float - Field yrot:Float - Field zrot:Float - - ' These are considered private - ' - Global static:Int=False - Global si:Float[]=Null - Field v:TGLFlagVertex[,] - Field cell:Int - Field move:Int - Field width:Int - Field height:Int - Field txt:Int - - ' Creates a new flag - ' - ' texture - Flag texture - ' horiz - Number of horizontal vertices - ' vert - Number of vertical vertices - ' size - Size of each square - ' tile - Whether the texture is tiled or not - ' z - Distance of flag (flags always created in the XY plane) - ' - ' Returns null for invalid parameters. - ' - Function Create:TGLFlag(texture:Int, horiz:Int, vert:Int, size:Float, tile:Int, z:Float) - Local o:TGLFlag - - If (horiz<2 Or vert<2) - Return Null - EndIf - - o=New TGLFlag - - If (Not o.static) - o.si=New Float[3600] - For Local a:Float=0 Until 3600 - o.si[a]=Sin(a/10) - Next - o.static=True - EndIf - - o.xpos=0 - o.ypos=0 - o.zpos=z - o.xrot=0 - o.yrot=0 - o.zrot=0 - - o.txt=texture - o.width=horiz - o.height=vert - o.cell=size - o.move=size/2 - o.v=New TGLFlagVertex[horiz,vert] - - Local ox:Float - Local oy:Float - - ox=-(size*horiz)/2 - oy=-(size*horiz)/2 - - For Local x=0 Until horiz - For Local y=0 Until vert - Local v:TGLFlagVertex=New TGLFlagVertex - v.x=ox+x*size - v.y=oy+y*size - v.z=0 - - If (tile) - v.u=(x&1) - v.v=(y&1) - Else - v.u=1.0/(horiz-1)*x - v.v=1.0/(vert-1)*(vert-1-y) - EndIf - - o.v[x,y]=v - Next - Next - - Return o - End Function - - ' Call to render the flag - ' - Method Render() - glPushMatrix() - glTranslatef(xpos,ypos,zpos) - glRotatef(xrot,1,0,0) - glRotatef(yrot,0,1,0) - glRotatef(zrot,0,0,1) - glBindTexture(GL_TEXTURE_2D,txt) - - For Local vert:TGLFlagVertex=EachIn v - vert.ax=(vert.ax+vert.aix) Mod 3600 - vert.ay=(vert.ay+vert.aiy) Mod 3600 - vert.az=(vert.az+vert.aiz) Mod 3600 - vert.cx=vert.x+si[vert.ax]*move - vert.cy=vert.y+si[vert.ay]*move - vert.cz=vert.z+si[vert.az]*move - Next - - For Local x:Int=0 Until width-1 - glBegin(GL_TRIANGLE_STRIP) - For Local y:Int=0 Until height - glTexCoord2f(v[x,y].u,v[x,y].v) - glVertex3f(v[x,y].cx,v[x,y].cy,v[x,y].cz) - glTexCoord2f(v[x+1,y].u,v[x+1,y].v) - glVertex3f(v[x+1,y].cx,v[x+1,y].cy,v[x+1,y].cz) - Next - glEnd() - Next - glPopMatrix() - End Method - - ' Sets the amount of movement for vertex movement (defaults to half the cell size) - ' - Method SetMove(m:Int) - move=m - End Method - - ' Sets the movements for a vertex - ' - ' x - The X co-ord of the vertex - ' y - The Y co-ord of the vertex - ' angz - The initial angle (movement is done on a sine wave with 3600 positions) for the Z co-ord - ' angiz - The angle increment for the Z co-ord - ' angx - Ditto for X - ' angix - Ditto for X - ' angy - And Y - ' angiy - And Y - ' - ' Note increments must be positive - to simulate negative ones pass a large increment (eg. 3599 for -1) - ' - Method Nudge(x:Int, y:Int, angz:Float, angiz:Float=10, angx:Float=0, angix:Float=0, angy:Float=0, angiy:Float=0) - v[x,y].ax=angx - v[x,y].ay=angy - v[x,y].az=angz - v[x,y].aix=angix - v[x,y].aiy=angiy - v[x,y].aiz=angiz - End Method - -End Type - -Type TGLFlagVertex - Field x#,y#,z# - Field cx#,cy#,cz# - Field u#,v# - Field ax#,ay#,az# - Field aix#,aiy#,aiz# - - Method New() - x=0 - y=0 - z=0 - cx=0 - cy=0 - cz=0 - ax=0 - ay=0 - az=0 - aix=0 - aiy=0 - aiz=0 - End Method -End Type diff --git a/keysyms.mod/.cvsignore b/keysyms.mod/.cvsignore index e3c0b2d..0f5601a 100644 --- a/keysyms.mod/.cvsignore +++ b/keysyms.mod/.cvsignore @@ -1,6 +1,5 @@ .bmx doc -keysyms.debug.win32.a -keysyms.debug.win32.i -keysyms.release.win32.a -keysyms.release.win32.i +*.a +*.i +*.i2 diff --git a/mwidget.mod/.cvsignore b/mwidget.mod/.cvsignore index c7027e3..0f5601a 100644 --- a/mwidget.mod/.cvsignore +++ b/mwidget.mod/.cvsignore @@ -1,6 +1,5 @@ -mwidget.release.win32.i -mwidget.debug.win32.a -mwidget.debug.win32.i -mwidget.release.win32.a .bmx doc +*.a +*.i +*.i2 diff --git a/showlicense.mod/.cvsignore b/showlicense.mod/.cvsignore index a37585c..0bddba6 100644 --- a/showlicense.mod/.cvsignore +++ b/showlicense.mod/.cvsignore @@ -2,3 +2,4 @@ doc .bmx *.a *.i +*.i2 diff --git a/simplegui.mod/.cvsignore b/simplegui.mod/.cvsignore index 5c46a3b..f3c28d9 100644 --- a/simplegui.mod/.cvsignore +++ b/simplegui.mod/.cvsignore @@ -1,6 +1,5 @@ doc .bmx -simplegui.debug.win32.a -simplegui.debug.win32.i -simplegui.release.win32.a -simplegui.release.win32.i +*.a +*.i +*.i2 diff --git a/simplegui.mod/simplegui.bmx b/simplegui.mod/simplegui.bmx index e7e2319..fcf0c17 100644 --- a/simplegui.mod/simplegui.bmx +++ b/simplegui.mod/simplegui.bmx @@ -1,1682 +1,1682 @@ -' Copyright (c) 2006 Ian Cowburn -' -' 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. -' -' $Id$ -' -Rem -bbdoc: noddybox.simplegui -EndRem -Module noddybox.simplegui - -ModuleInfo "Framework: (Very) Simple GUI" -ModuleInfo "Copyright: Ian Cowburn -- released under the MIT License" -ModuleInfo "Author: Ian Cowburn" -ModuleInfo "Version: $Revision$" - -Strict -Import brl.max2d -Import brl.filesystem -Import brl.basic -Import noddybox.bitmapfont - -Rem -bbdoc: Defines the @TBitmapFont to be used by the GUI. -EndRem -Type TSGUIFont - Rem - bbdoc: The font to use. - EndRem - Global font:TBitmapFont -End Type - -Rem -bbdoc: The base widget type. -EndRem -Type TWidget Abstract - - Rem - bbdoc: This widget consumes click events - EndRem - Const HAS_CLICK:Int=1 - Rem - bbdoc: This widget consumes drag events - EndRem - Const HAS_DRAG:Int=2 - Rem - bbdoc: This widget consumes key events - EndRem - Const HAS_KEY:Int=4 - - Rem - bbdoc: If true the widget is displayed. - EndRem - Field displayed:Int - Rem - bbdoc: If true the widget can be interacted with. - EndRem - Field enabled:Int - Rem - bbdoc: The text displayed in the widget. - EndRem - Field text:String - Rem - bbdoc: The X co-ordinate of the widget. - EndRem - Field x:Int - Rem - bbdoc: The Y co-ordinate of the widget. - EndRem - Field y:Int - Rem - bbdoc: The width of the widget. - EndRem - Field w:Int - Rem - bbdoc: The height of the widget. - EndRem - Field h:Int - Rem - bbdoc: Callback to call when clicked. - EndRem - Field callback(w:TWidget) - Rem - bbdoc: True if the mouse is over this widget, False otherwise. - EndRem - Field mouse_over:Int - Rem - bbdoc: The @TGUIHandler that owns this widget. - EndRem - Field owner:TGUIHandler - Rem - bbdoc: The mask of consumed events, zero otherwise. - EndRem - Field consumes:Int - - Rem - bbdoc: Override this accept keypresses - EndRem - Method HandleKey(k:Int) - End Method - - Rem - bbdoc: Override this for when the mouse enters. Call this parent version to handle @mouse_over too. - EndRem - Method MouseEnter() - If displayed And enabled - mouse_over=True - EndIf - End Method - - Rem - bbdoc: Override this for when the mouse leaves. Call this parent version to handle @mouse_over too. - EndRem - Method MouseLeave() - mouse_over=False - End Method - - Rem - bbdoc: Override to handle a mouse button press. - EndRem - Method HandleClick() - End Method - - Rem - bbdoc: Handles mouse dragging. - about: @mx and @my are the changes in mouse co-ordinates since the last drag. - EndRem - Method HandleDrag(mx:Int, my:Int) - End Method - - Rem - bbdoc: Must be provided by a widget to draw itself. - EndRem - Method Draw() Abstract - - Rem - bbdoc: Helper to draw a wireframe rectangle. - EndRem - Function DrawBox(x:Int, y:Int, w:Int, h:Int) - DrawLine(x,y,x+w-1,y) - DrawLine(x+w-1,y,x+w-1,y+h-1) - DrawLine(x+w-1,y+h-1,x,y+h-1) - DrawLine(x,y+h-1,x,y) - End Function - - Rem - bbdoc: Helper to draw a 3D rectangle. - EndRem - Function Draw3DBox(x:Int, y:Int, w:Int, h:Int, invert:Int, size:Int=2) - Local f:Int - - SetColor(200,200,200) - DrawRect(x,y,w,h) - - If invert - SetColor(170,170,170) - Else - SetColor(230,230,230) - EndIf - - For f=0 Until size - DrawLine(x+f,y+f,x+w-1-f,y+f) - DrawLine(x+w-1-f,y+f,x+w-1-f,y+h-1-f) - Next - - If invert - SetColor(230,230,230) - Else - SetColor(170,170,170) - EndIf - - For f=0 Until size - DrawLine(x+w-1-f,y+h-1-f,x+f,y+h-1-f) - DrawLine(x+f,y+h-1-f,x+f,y+f) - Next - End Function - -End Type - -Rem -bbdoc: The panel widget (simply displays itself as a white bordered black box) -EndRem -Type TPanel Extends TWidget - - Rem - bbdoc: Create a TPanel widget. - returns: The created widget. - about: @gui is the @TGUIHandler object managing this wiget. @x, @y, @x and @h are its position and size. If @x or @y is -1 they are centered. - EndRem - Function Create:TPanel(gui:TGUIHandler,x:Int, y:Int, w:Int, h:Int) - Local o:TPanel=New TPanel - o.displayed=True - o.enabled=True - o.consumes=0 - - If x=-1 - x=(GraphicsWidth()-w)/2 - EndIf - - If y=-1 - y=(GraphicsHeight()-h)/2 - EndIf - - o.x=x - o.y=y - o.w=w - o.h=h - gui.Register(o) - Return o - End Function - - Method Draw() - SetColor(0,0,0) - DrawRect(x,y,w,h) - SetColor(255,255,255) - DrawBox(x,y,w,h) - End Method - -End Type - -Rem -bbdoc: The label widget (simply displays the supplied string) -EndRem -Type TLabel Extends TWidget - Rem - bbdoc: Create a TLabel widget. - returns: The created widget. - about: @gui is the @TGUIHandler object managing this wiget. @x and @y are its position and @text is the text to display in the label. - EndRem - Function Create:TLabel(gui:TGUIHandler,x:Int, y:Int, text:String) - Local o:TLabel=New TLabel - o.displayed=True - o.enabled=True - o.consumes=0 - o.x=x - o.y=y - o.w=TSGUIFont.font.TextWidth(text)+2 - o.h=TSGUIFont.font.MaxHeight()+1 - o.text=text - gui.Register(o) - Return o - End Function - - Method Draw() - TSGUIFont.font.Draw(text,x+1,y+1) - End Method - -End Type - -Rem -bbdoc: The text entry widget -EndRem -Type TText Extends TWidget - Field maxlen:Int - Field mode:Int - - Rem - bbdoc: The text box handles any text - EndRem - Const NORMAL:Int=0 - - Rem - bbdoc: The text box handles a number - EndRem - Const NUMERIC:Int=1 - - Rem - bbdoc: The text box handles only integer numbers - EndRem - Const INTEGER:Int=2 - - Rem - bbdoc: The text box handles only positive numbers - EndRem - Const POSITIVE:Int=4 - - Rem - bbdoc: The text box handles a basic set of filename characters (alphanumerics, periods, spaces and underscores) - EndRem - Const FILENAME:Int=8 - - Rem - bbdoc: The text box is readonly - EndRem - Const READONLY:Int=256 - - - Rem - bbdoc: Create a TText widget. - returns: The created widget. - about: @gui is the @TGUIHandler object managing this wiget. @x and @y are its position and @text is the initial text in the widget. - @maxlen is the maximum number of characters allowed. @mode defines the valid characters that can be entered. - @callback is called when RETURN is pressed in the text field. - EndRem - Function Create:TText(gui:TGUIHandler,x:Int, y:Int, text:String, maxlen:Int, mode:Int=0, callback(w:TWidget)=Null) - Local o:TText=New TText - o.displayed=True - o.enabled=True - o.consumes=HAS_CLICK|HAS_KEY - o.x=x - o.y=y - o.maxlen=maxlen - o.w=TSGUIFont.font.MaxWidth()*(maxlen+1)+2 - o.h=TSGUIFont.font.MaxHeight()+2 - o.text=text - o.callback=callback - o.mode=mode - gui.Register(o) - Return o - End Function - - Rem - bbdoc: Set the text to a floating point value. - about: @v is the floating point value (a double to cover both types). This value will be placed in the text - field with trailing zeros (and trailing dot if an integer) removed. - EndRem - Method SetFloat(v:Double) - Local s:String=v - - If s.Find(".")<>-1 - While s.length>1 And s[s.length-1]=Asc("0") - s=s[..s.length-1] - Wend - - While s.length>1 And s[s.length-1]=Asc(".") - s=s[..s.length-1] - Wend - EndIf - - text=s - End Method - - Method HandleClick() - If Not(mode & READONLY) - owner.SetFocus(Self) - EndIf - End Method - - Method HandleKey(k:Int) - If (mode & READONLY) - Return - EndIf - - If k=27 - text="" - Else If k=8 - If text.length>0 - text=text[0..text.length-1] - EndIf - Else If k=13 - If callback<>Null - callback(Self) - owner.SetFocus(Null) - EndIf - Else If k>31 And k<127 And text.length=Asc("0") And k<=Asc("9") - text:+Chr(k) - EndIf - - If k=Asc(".") And (Not (mode & INTEGER)) And text.Find(".")=-1 - text:+Chr(k) - EndIf - Else - If (mode & FILENAME) - If (k>=Asc("a") And k<=Asc("z")) Or (k>=Asc("A") And k<=Asc("Z")) Or (k>=Asc("0") And k<=Asc("9")) Or k=Asc(" ") Or k=Asc(".") Or k=Asc("_") - text:+Chr(k) - EndIf - Else - text:+Chr(k) - EndIf - EndIf - EndIf - End Method - - Method Draw() - Local s:String=text - - If owner.GetFocus()=Self And Not (mode & READONLY) - SetColor(128,128,128) - s:+"_" - Else - SetColor(64,64,64) - EndIf - - DrawRect(x,y,w,h) - - TSGUIFont.font.Draw(s,x+1,y+1) - End Method -End Type - -Rem -bbdoc: The checkbox widget -EndRem -Type TCheckbox Extends TWidget - - Rem - bbdoc: True if the box is checked, False otherwise. - EndRem - Field checked:Int - - Rem - bbdoc: Create a TCheckox widget. - returns: The created widget. - about: @gui is the @TGUIHandler object managing this wiget. @x and @y are its position and @text is the text to display by the checkbox. - @callback is called when the checkbox is toggled. - EndRem - Function Create:TCheckbox(gui:TGUIHandler, x:Int, y:Int, text:String, callback(w:TWidget)=Null) - Local o:TCheckbox=New TCheckbox - o.displayed=True - o.enabled=True - o.consumes=HAS_CLICK - o.x=x - o.y=y - o.w=TSGUIFont.font.TextWidth(" "+text)+4+TSGUIFont.font.MaxHeight() - o.h=TSGUIFont.font.MaxHeight()+2 - o.text=text - o.callback=callback - gui.Register(o) - Return o - End Function - - Method HandleClick() - checked=Not checked - - If callback<>Null - callback(Self) - EndIf - End Method - - Method Draw() - If (mouse_over) - SetColor(255,255,255) - Else - SetColor(200,200,200) - EndIf - - DrawBox(x,y,TSGUIFont.font.MaxHeight(),TSGUIFont.font.MaxHeight()) - - If checked - SetColor(255,100,100) - DrawRect(x+1,y+1,TSGUIFont.font.MaxHeight()-2,TSGUIFont.font.MaxHeight()-2) - EndIf - - TSGUIFont.font.Draw(" "+text,x+2+TSGUIFont.font.MaxHeight(),y+1) - End Method -End Type - -Rem -bbdoc: The button widget -EndRem -Type TButton Extends TWidget - - Field ox:Int - Field oy:Int - - Rem - bbdoc: Create a TButton widget. - returns: The created widget. - about: @gui is the @TGUIHandler object managing this wiget. @x, @y, @w and @h are its position and size, and @text is the text to display in the button. - @callback is called when the button is pressed. - EndRem - Function Create:TButton(gui:TGUIHandler, x:Int, y:Int, w:Int, h:Int, text:String, callback(w:TWidget)) - Local o:TButton=New TButton - o.displayed=True - o.enabled=True - o.consumes=HAS_CLICK - o.x=x - o.y=y - o.w=w - o.h=h - o.text=text - o.ox=x+w/2-TSGUIFont.font.TextWidth(text)/2 - o.oy=y+h/2-TSGUIFont.font.TextHeight(text)/2 - o.callback=callback - gui.Register(o) - Return o - End Function - - Method HandleClick() - If callback<>Null - callback(Self) - EndIf - End Method - - Method Draw() - If (mouse_over) - SetColor(255,255,255) - DrawBox(x,y,w,h) - EndIf - - Draw3DBox(x+1,y+1,w-2,h-2,False,2) - - TSGUIFont.font.Draw(text,ox,oy) - End Method -End Type - -Rem -bbdoc: A drop down list type widget -EndRem -Type TButtonList Extends TWidget - - Field options:String[] - - Rem - bbdoc: The selected item. - EndRem - Field selected:Int - - Rem - bbdoc: Create a TButtonList widget. - returns: The created widget. - about: @gui is the @TGUIHandler object managing this wiget. @x and @y are its position. @options are the options for the list and - @selected is the currently selected item. @callback is called when the selection changes. - EndRem - Function Create:TButtonList(gui:TGUIHandler, x:Int, y:Int, options:String[], selected:Int, callback(w:TWidget)) - Local o:TButtonList=New TButtonList - Local maxw:Int=0 - o.displayed=True - o.enabled=True - o.consumes=HAS_CLICK - o.x=x - o.y=y - o.options=options - o.selected=selected - o.text=options[selected] - - For Local s:String=EachIn options - maxw=Max(maxw,TSGUIFont.font.TextWidth(s)) - Next - - o.w=maxw+TSGUIFont.font.MaxHeight()+4 - o.h=TSGUIFont.font.MaxHeight()+2 - o.callback=callback - gui.Register(o) - Return o - End Function - - Method HandleClick() - Local sel:Int=GUIMenu("Select value",options,x,y) - - If sel<>-1 - selected=sel - text=options[selected] - If callback<>Null - callback(Self) - EndIf - EndIf - End Method - - Method Draw() - If (mouse_over) - SetColor(128,128,128) - Else - SetColor(64,64,64) - EndIf - - DrawRect(x,y,w,h) - Draw3DBox(x+2,y+2,h-4,h-4,False,1) - - TSGUIFont.font.Draw(text,x+TSGUIFont.font.MaxHeight()+3,y+1) - End Method -End Type - -Rem -bbdoc: Optional type to use for TTextList -about: If the objects stored as TTextList options are derived from this type then tabular lists can be created. -EndRem -Type TTextListItem Abstract - Rem - bbdoc: The number of columns. - returns: The number of columns - EndRem - Method Columns:Int() Abstract - - Rem - bbdoc: A column offset. - returns: The column offset for column @i (numbered from zero). - EndRem - Method ColumnOffset:Int(i:Int) Abstract - - Rem - bbdoc: Column data. - returns: The column data for column @i (numbered from zero). - EndRem - Method ColumnData:String(i:Int) Abstract -End Type - -Rem -bbdoc: A widget that displays text items as a list. -EndRem -Type TTextList Extends TWidget - - Field options:Object[] - Field selected:Int - Field num:Int - Field top:Int - Field rows:Int - - Rem - bbdoc: Create a TTextList widget. - returns: The created widget. - about: @gui is the @TGUIHandler object managing this wiget. @x, @y, and @w are its position and width. - @rows are the number of items to display at a time. - @callback is called when the selection changes. - EndRem - Function Create:TTextList(gui:TGUIHandler, x:Int, y:Int, w:Int, rows:Int, callback(w:TWidget)=Null) - Local o:TTextList=New TTextList - Local maxw:Int=0 - o.displayed=True - o.enabled=True - o.consumes=HAS_CLICK - o.x=x - o.y=y - o.options=Null - o.selected=-1 - o.num=0 - o.top=0 - o.rows=rows - - o.w=w - o.h=TSGUIFont.font.MaxHeight()*rows - o.callback=callback - gui.Register(o) - Return o - End Function - - Rem - bbdoc: Sets the options to display in the list. - about: @opts is an array of objects. Note: If the objects passed are derived from TTextListItem then tabular output is generated. - If they are not derived, ToString() is called on the objects to display them, so you are not restricted to the type of object that - can be passed. - EndRem - Method SetOptions(opts:Object[]) - options=opts - num=opts.length - selected=-1 - top=0 - End Method - - Rem - bbdoc: Gets the selected item's index. - returns: The selected item's index, or -1 if nothing is selected. - EndRem - Method GetSelectedIndex:Int() - Return selected - End Method - - Rem - bbdoc: Gets the selected item. - returns: The selected item, or null if nothing is selected. - EndRem - Method GetSelectedItem:Object() - If options<>Null And selected<>-1 - Return options[selected] - Else - Return Null - EndIf - End Method - - Rem - bbdoc: Set the top row. - about: @i is the index of the item to display in the first row of the widget. - EndRem - Method SetTopRow(i:Int) - If options<>Null And iNull - Return top - Else - Return -1 - EndIf - End Method - - Rem - bbdoc: Ensure an item is visible. - about: @i is the index of the item that is to be made visible. - EndRem - Method EnsureVisible(i:Int) - If options<>Null And i=top+rows - top=Max(0,i-rows+1) - EndIf - EndIf - End Method - - Method HandleClick() - If options<>Null - Local sel:Int=top+(MouseY()-y)/TSGUIFont.font.MaxHeight() - - If selNull - callback(Self) - EndIf - EndIf - EndIf - End Method - - Method Draw() - SetColor(64,64,64) - DrawRect(x,y,w,h) - - If options<>Null - Local vx:Int - Local vy:Int - Local vw:Int - Local vh:Int - - GetViewport(vx,vy,vw,vh) - - Local ty:Int=y - For Local f:Int=top Until top+rows - SetViewport(x,ty,w,TSGUIFont.font.MaxHeight()) - - If f=selected - If mouse_over And MouseY()>=ty And MouseY()=ty And MouseY()Null - For Local f:Int=0 Until li.Columns() - TSGUIFont.font.Draw(li.ColumnData(f),x+li.ColumnOffset(f),ty) - Next - Else - TSGUIFont.font.Draw(options[f].ToString(),x,ty) - EndIf - EndIf - - ty:+TSGUIFont.font.MaxHeight() - Next - - SetViewport(vx,vy,vw,vh) - EndIf - End Method -End Type - -Rem -bbdoc: A number up/down widget for doubles -EndRem -Type TNumberDouble Extends TWidget - - Rem - bbdoc: The value - EndRem - Field value:Double - - Rem - bbdoc: The increment/decrement - EndRem - Field change:Double - - Rem - bbdoc: The maximum value - EndRem - Field maxval:Double - - Rem - bbdoc: The minimum value - EndRem - Field minval:Double - - Rem - bbdoc: Create a TNumber widget. - returns: The created widget. - about: @gui is the @TGUIHandler object managing this wiget. @x and @y are its position. @callback is called when the value changes. - EndRem - Function Create:TNumberDouble(gui:TGUIHandler, x:Int, y:Int, callback(w:TWidget)=Null) - Local o:TNumberDouble=New TNumberDouble - o.displayed=True - o.enabled=True - o.consumes=HAS_CLICK - o.value=0 - o.minval=0 - o.maxval=100 - o.change=10 - o.x=x - o.y=y - o.w=TSGUIFont.font.MaxHeight()*2+8 - o.h=TSGUIFont.font.MaxHeight()+2 - o.callback=callback - gui.Register(o) - Return o - End Function - - Method HandleClick() - Local old:Double=value - - If MouseX()old And callback<>Null - callback(Self) - EndIf - End Method - - Method Draw() - If mouse_over - If MouseX()old And callback<>Null - callback(Self) - EndIf - End Method - - Method Draw() - If mouse_over - If MouseX()h) - o.SetBar(0,100,10) - o.callback=callback - gui.Register(o) - Return o - End Function - - Rem - bbdoc: Set parameters for scroll bar - about: @min_val and @max_val are the values at the top and bottom of the scroll bar. @page_size is the numbers between the two that - is covered by the block in the scrollbar. Note: The maximum value of @value is @max_val minus @page_size. - EndRem - Method SetBar(min_val:Double, max_val:Double, page_size:Double) - minval=min_val - maxval=max_val - page=page_size - - If horiz - stepsize=(maxval-minval)/w - blocksize=Min(w,Max(1,page/stepsize)) - bc=x - Else - stepsize=(maxval-minval)/h - blocksize=Min(h,Max(1,page/stepsize)) - bc=y - EndIf - End Method - - Rem - bbdoc: Get the current value of the scrollbar. - returns: The current position of the scrollbar inbetween the minimum and maximum values. - EndRem - Method GetValue:Double() - If horiz - Return minval+(bc-x)*stepsize - Else - Return minval+(bc-y)*stepsize - EndIf - End Method - - Rem - bbdoc: Sets the current value of the scrollbar. - EndRem - Method SetValue(val:Double) - If horiz - bc=Max(x,Min(x+w-blocksize,x+(val-minval)/stepsize)) - Else - bc=Max(y,Min(y+h-blocksize,y+(val-minval)/stepsize)) - EndIf - End Method - - Method HandleClick() - Local old:Double=GetValue() - - If horiz - bc=Max(x,Min(x+w-blocksize,MouseX())) - Else - bc=Max(y,Min(y+h-blocksize,MouseY())) - EndIf - - If GetValue()<>old And callback<>Null - callback(Self) - EndIf - End Method - - Method HandleDrag(mx:Int, my:Int) - Local old:Double=GetValue() - - If horiz - bc=Max(x,Min(x+w-blocksize,bc+mx)) - Else - bc=Max(y,Min(y+h-blocksize,bc+my)) - EndIf - - If GetValue()<>old And callback<>Null - callback(Self) - EndIf - End Method - - Method Draw() - SetColor(64,64,64) - DrawRect(x,y,w,h) - If horiz - Draw3DBox(bc,y,blocksize,h,False,1) - Else - Draw3DBox(x,bc,w,blocksize,False,1) - EndIf - End Method -End Type - -Rem -bbdoc: Handles the GUI. -EndRem -Type TGUIHandler - - ' These are private - ' - Field m_widgets:TList - Field m_focus:TWidget - Field m_over:TWidget - Field m_clicked:TWidget - Field m_dragging:Int - Field m_dragx:Int - Field m_dragy:Int - Field m_dragobj:TWidget - - Rem - bbdoc: Create a GUI Handler. - returns: The GUI Hanbler. - EndRem - Function Create:TGUIHandler() - Local o:TGUIHandler - - o=New TGUIHandler - - o.m_widgets=CreateList() - o.m_focus=Null - o.m_over=Null - o.m_clicked=Null - o.m_dragging=False - o.m_dragx=0 - o.m_dragy=0 - o.m_dragobj=Null - - Return o - End Function - - Rem - bbdoc: Register a widget. - about: Widgets in the library call this themselves when creating. - EndRem - Method Register(w:TWidget) - m_widgets.AddLast(w) - w.owner=Self - End Method - - Rem - bbdoc: Remove all widgets. - EndRem - Method Clear() - m_widgets.Clear() - End Method - - Rem - bbdoc: Sets the enable state of all widgets. - about: If @state is true then all widgets are enabled, otherwise all widgets are disabled. - EndRem - Method SetEnable(state:Int) - For Local w:TWidget=EachIn m_widgets - w.enabled=state - Next - End Method - - Rem - bbdoc: Sets the displayed state of all widgets. - about: If @state is true then all widgets are displayed, otherwise all widgets are hidden. - EndRem - Method SetDisplay(state:Int) - For Local w:TWidget=EachIn m_widgets - w.displayed=state - Next - End Method - - Rem - bbdoc: Sets the keyboard focus to the supplied widget. Pass null for no focus. - EndRem - Method SetFocus(w:TWidget) - m_focus=w - End Method - - Rem - bbdoc: Gets the keyboard focus. - returns: The currently focused TWidget, or null for no focus. - EndRem - Method GetFocus:TWidget() - Return m_focus - End Method - - Rem - bbdoc: Gets the last clicked widget. - returns: The last clicked TWidget. Null is returned if this is called again before another widget is clicked. - EndRem - Method Clicked:TWidget() - Local last:TWidget=m_clicked - m_clicked=Null - Return last - End Method - - Rem - bbdoc: Whether a widget is dragging - returns: True if a widget is consuming a mouse drag. - EndRem - Method IsDragging:Int() - Return m_dragging - End Method - - Rem - bbdoc: Perform the event loop and pass any necessary events. - about: KeyHit(KEY_MOUSELEFT) and GetChar() are used to consume events for the interface. - EndRem - Method EventLoop() - Local x:Int=MouseX() - Local y:Int=MouseY() - Local b:Int=MouseHit(1)>0 - Local drag:Int=MouseDown(1) - - Local w:TWidget=LocateWidget(x,y) - - For Local wid:TWidget=EachIn m_widgets - If wid.displayed - If wid.enabled - wid.Draw() - Else - SetAlpha(0.3) - wid.Draw() - SetAlpha(1) - EndIf - EndIf - Next - - If w<>m_over - If m_over<>Null - m_over.MouseLeave() - EndIf - m_over=w - If m_over<>Null - m_over.MouseEnter() - EndIf - EndIf - - If w<>Null And w.enabled And w.consumes&TWidget.HAS_CLICK=TWidget.HAS_CLICK And b And Not m_dragging - w.HandleClick() - m_clicked=w - EndIf - - Local k:Int=GetChar() - - If k<>0 And m_focus<>Null And m_focus.enabled And m_focus.consumes&TWidget.HAS_KEY=TWidget.HAS_KEY - m_focus.HandleKey(k) - EndIf - - If drag - If m_dragging - m_dragobj.HandleDrag(MouseX()-m_dragx,MouseY()-m_dragy) - m_dragx=MouseX() - m_dragy=MouseY() - Else - If w<>Null And w.consumes&TWidget.HAS_DRAG=TWidget.HAS_DRAG - m_dragging=True - m_dragx=MouseX() - m_dragy=MouseY() - m_dragobj=w - EndIf - EndIf - Else - m_dragging=False - m_dragobj=Null - EndIf - End Method - - ' Private method - ' - Method LocateWidget:TWidget(x:Int,y:Int) - For Local w:TWidget=EachIn m_widgets - If x>=w.x And y>=w.y And xbutton - Cls - SetAlpha(0.5) - DrawImage(back,0,0) - SetAlpha(1) - TWidget.Draw3DBox(x,y,w,h,False,2) - gui.EventLoop() - click=gui.Clicked() - - If i<>Null - SetColor(255,255,255) - DrawImage(i,MouseX(),MouseY()) - EndIf - - Flip - Wend -End Function - -Rem -bbdoc: Displays a yes/no alert with the supplied string. -returns: True if Yes selected, otherwise False. -about: The string @s can be split into multiple lines using the '|' character. If @i is not null then this image is drawn as a mouse cursor. -EndRem -Function GUIYesNo:Int(s:String, i:TImage=Null) - Local back:TImage=CreateImage(GraphicsWidth(),GraphicsHeight(),1,0) - GrabImage(back,0,0) - - Local txt:TSplitText=TSplitText.Create(s) - - Local w:Int=Max(txt.width+10,GraphicsWidth()/4) - Local h:Int=txt.Height+TSGUIFont.font.MaxHeight()*4 - Local x:Int=GraphicsWidth()/2-w/2 - Local y=GraphicsHeight()/2-h/2 - Local by=y+h-TSGUIFont.font.MaxHeight()*2.5 - - Local gui:TGUIHandler=TGUIHandler.Create() - - Local ty:Int=y+5 - - For Local t:String=EachIn txt.lines - Local label:TLabel=TLabel.Create(gui,x+5,ty,t) - ty:+TSGUIFont.font.TextHeight(t) - Next - - Local yes:TButton=TButton.Create(gui,x+5,by,w/2-10,TSGUIFont.font.MaxHeight()*2,"Yes",Null) - Local no:TButton=TButton.Create(gui,x+w/2+5,by,w/2-10,TSGUIFont.font.MaxHeight()*2,"No",Null) - - Local click:TWidget=Null - - While click=Null - Cls - SetAlpha(0.5) - DrawImage(back,0,0) - SetAlpha(1) - TWidget.Draw3DBox(x,y,w,h,False,2) - gui.EventLoop() - click=gui.Clicked() - - If i<>Null - SetColor(255,255,255) - DrawImage(i,MouseX(),MouseY()) - EndIf - - Flip - Wend - - Return click=yes -End Function - - -Rem -bbdoc: Displays a pop-up menu. -returns: The index of the selected option, -1 for none. -about: @title is the menu title, @options the options to display and @x and @y specify its position. -If @i is not null then this image is drawn as a mouse cursor. -EndRem -Function GUIMenu(title:String, options:String[], x:Int, y:Int, i:TImage=Null) - Local f:Int - Local back:TImage=CreateImage(GraphicsWidth(),GraphicsHeight(),1,0) - GrabImage(back,0,0) - - Local st:Int=TSGUIFont.font.MaxHeight()*2 - Local h:Int=TSGUIFont.font.MaxHeight()*3 - Local w:Int=TSGUIFont.font.TextWidth(title)+30 - - For f=0 Until options.length - w=Max(w,TSGUIFont.font.TextWidth(options[f])+30) - h:+st - Next - - Local gui:TGUIHandler=TGUIHandler.Create() - - x=Max(0,Min(x,GraphicsWidth()-w)) - y=Max(0,Min(y,GraphicsHeight()-h)) - - Local label:TLabel=TLabel.Create(gui,x+5,y+2,title) - Local button:TButton[]=New TButton[options.length] - - For f=0 Until options.length - button[f]=TButton.Create(gui,x+5,y+TSGUIFont.font.MaxHeight()*2+f*st,w-10,st-2,options[f],Null) - Next - - Local click:TWidget=Null - - While click=Null And MouseHit(2)=0 - Cls - SetAlpha(0.5) - DrawImage(back,0,0) - SetAlpha(1) - TWidget.Draw3DBox(x,y,w,h,False,2) - gui.EventLoop() - click=gui.Clicked() - - If i<>Null - SetColor(255,255,255) - DrawImage(i,MouseX(),MouseY()) - EndIf - - Flip - Wend - - For f=0 Until options.length - If button[f]=click - Return f - EndIf - Next - - Return -1 -End Function - -Rem -bbdoc: Displays a basic file selector. -returns: The selected file, or null for none. -about: @title is the title. @file is the initially selected file, and f set to null then no file is selected and the current directory displayed. -Set @save to true for a save dialog (the filename can be altered). -If @i is not null then this image is drawn as a mouse cursor. -EndRem -Function GUIFileSelect:String(title:String, file:String, save:Int, i:TImage=Null) - FlushKeys() - - Local oldpwd:String=CurrentDir() - Local dir:String - Local fn:String - Local sw:Int=GraphicsWidth() - Local sh:Int=GraphicsHeight() - Local fh:Int=TSGUIFont.font.MaxHeight() - Local fw:Int=TSGUIFont.font.MaxWidth() - Local rows:Int=(sh-fh*10)/fh - - If file<>Null And file<>"" - dir=ExtractDir(file) - - If dir="" - dir=oldpwd - EndIf - - If FileType(file)=FILETYPE_FILE - fn=StripDir(file) - Else - fn="" - EndIf - Else - dir=oldpwd - fn="" - EndIf - - Local gui:TGUIHandler=TGUIHandler.Create() - - TPanel.Create(gui,0,0,sw,sh) - TLabel.Create(gui,10,fh*0.5,title) - - Local list:TTextList=TTextList.Create(gui,20,fh*2,sw-40,rows) - Local scroll:TScrollbar=TScrollbar.Create(gui,list.x+list.w+5,list.y,10,list.h) - - Local fntext:TText - - If save - fntext=TText.Create(gui,20,sh-fh*6,fn,(sw-40)/fw,TText.FILENAME) - Else - fntext=TText.Create(gui,20,sh-fh*6,fn,(sw-40)/fw,TText.READONLY) - EndIf - - Local bw:Int=TSGUIFont.font.MaxWidth()*9 - - Local cancel:TButton=TButton.Create(gui,sw-bw-20,sh-fh*3.5,bw,fh*2.5,"Cancel",Null) - Local ok:Tbutton=TButton.Create(gui,cancel.x-bw-10,cancel.y,bw,fh*2.5,"OK",Null) - - Local last:TDirEntry=Null - - ChangeDir(dir) - LoadDirEnts(list,scroll,rows) - - Repeat - Cls - - gui.EventLoop() - - TSGUIFont.font.Draw(CurrentDir(),list.x,list.y+list.h+3) - - Local click:TWidget=gui.Clicked() - - If click=ok - Local ret:String=CurrentDir()+"/"+fntext.text - ChangeDir(oldpwd) - FlushKeys() - Return ret - EndIf - - If click=cancel Or (KeyHit(KEY_ESCAPE) And gui.GetFocus()=Null) - ChangeDir(oldpwd) - FlushKeys() - Return Null - EndIf - - If list.GetSelectedItem()<>last - last=TDirEntry(list.GetSelectedItem()) - - If last.is_dir - ChangeDir(last.filename) - LoadDirEnts(list,scroll,rows) - fntext.text="" - last=Null - Else - fntext.text=last.filename - EndIf - EndIf - - ok.enabled=(fntext.text<>"") - - list.SetTopRow(scroll.GetValue()) - - If i<>Null - SetColor(255,255,255) - DrawImage(i,MouseX(),MouseY()) - EndIf - - Flip - Forever -End Function - -Rem -bbdoc: Handles a TGUIHandler as if it's a modal dialog. -returns: True if @ok is pressed, False if @cancel or the ESCAPE key is pressed. ESCAPE is only allowed if nothing has the text focus. -about: @gui is the GUI handler and widgets to display as a dialog., @ok is the clickable widget that OK's the dialog, @cancel the widget that cancels it. -If @i is not null then this image is drawn as a mouse cursor. -EndRem -Function GUIDialog(gui:TGUIHandler, ok:TWidget, cancel:TWidget, i:TImage=Null) - FlushKeys() - - Local back:TImage=CreateImage(GraphicsWidth(),GraphicsHeight(),1,0) - GrabImage(back,0,0) - - Local done:Int=False - Local ok_pressed:Int - Local click:TWidget - - While done=False - Cls - SetAlpha(0.5) - DrawImage(back,0,0) - SetAlpha(1) - gui.EventLoop() - click=gui.Clicked() - - If click=ok - done=True - ok_pressed=True - EndIf - - If click=cancel Or (KeyHit(KEY_ESCAPE) And gui.GetFocus()=Null) - done=True - ok_pressed=False - EndIf - - If i<>Null - SetColor(255,255,255) - DrawImage(i,MouseX(),MouseY()) - EndIf - - Flip - Wend - - FlushKeys() - Return ok_pressed -End Function - -Private - -Type TSplitText - Field lines:TList - Field width:Int - Field height:Int - - Function Create:TSplitText(s:String) - Local o:TSplitText=New TSplitText - - o.lines=CreateList() - o.width=0 - o.height=0 - - Local sub:String="" - - For Local f:Int=0 Until s.length - Local c:Int=s[f] - If c=Asc("|") - o.lines.AddLast(sub) - o.width=Max(o.width,TSGUIFont.font.TextWidth(sub)) - o.height:+TSGUIFont.font.TextHeight(sub) - sub="" - Else - sub:+Chr(c) - EndIf - Next - - If sub.length>0 - o.lines.AddLast(sub) - o.width=Max(o.width,TSGUIFont.font.TextWidth(sub)) - o.height:+TSGUIFont.font.TextHeight(sub) - EndIf - - Return o - End Function -EndType - -Type TDirEntry Extends TTextListItem - Field path:String - Field dir:String - Field filename:String - Field size:Int - Field is_dir:Int - - Function Create:TDirEntry(path:String) - Local o:TDirEntry=New TDirEntry - o.path=path - o.dir=ExtractDir(path) - o.filename=StripDir(path) - o.is_dir=(FileType(path)=FILETYPE_DIR) - o.size=FileSize(path) - Return o - End Function - - Method Compare:Int(o:Object) - Local d:TDirEntry=TDirEntry(o) - - If d=Null - Return 0 - EndIf - - If is_dir=d.is_dir - Return filename.Compare(d.filename) - Else - If is_dir - Return -1 - Else - Return 1 - EndIf - EndIf - - Return 0 - End Method - - Method Columns:Int() - Return 2 - End Method - - Method ColumnOffset:Int(i:Int) - If i=0 - Return 0 - Else - Return GraphicsWidth()-TSGUIFont.font.MaxWidth()*20 - EndIf - End Method - - Method ColumnData:String(i:Int) - If i=0 - Return filename - Else - If is_dir - Return "DIR" - Else - Return size+" bytes" - EndIf - EndIf - End Method -End Type - -Function LoadDirEnts(list:TTextList, scroll:TScrollbar, rows:Int) - Local d:TList=CreateList() - - For Local s:String=EachIn LoadDir(CurrentDir(),False) - d.AddLast(TDirEntry.Create(CurrentDir()+"/"+s)) - Next - - d.Sort() - - list.SetOptions(d.ToArray()) - scroll.SetBar(0,Max(1,d.Count()-rows/2),1) -End Function +' Copyright (c) 2006 Ian Cowburn +' +' 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. +' +' $Id$ +' +Rem +bbdoc: noddybox.simplegui +EndRem +Module noddybox.simplegui + +ModuleInfo "Framework: (Very) Simple GUI" +ModuleInfo "Copyright: Ian Cowburn -- released under the MIT License" +ModuleInfo "Author: Ian Cowburn" +ModuleInfo "Version: $Revision$" + +Strict +Import brl.max2d +Import brl.filesystem +Import brl.basic +Import noddybox.bitmapfont + +Rem +bbdoc: Defines the @TBitmapFont to be used by the GUI. +EndRem +Type TSGUIFont + Rem + bbdoc: The font to use. + EndRem + Global font:TBitmapFont +End Type + +Rem +bbdoc: The base widget type. +EndRem +Type TWidget Abstract + + Rem + bbdoc: This widget consumes click events + EndRem + Const HAS_CLICK:Int=1 + Rem + bbdoc: This widget consumes drag events + EndRem + Const HAS_DRAG:Int=2 + Rem + bbdoc: This widget consumes key events + EndRem + Const HAS_KEY:Int=4 + + Rem + bbdoc: If true the widget is displayed. + EndRem + Field displayed:Int + Rem + bbdoc: If true the widget can be interacted with. + EndRem + Field enabled:Int + Rem + bbdoc: The text displayed in the widget. + EndRem + Field text:String + Rem + bbdoc: The X co-ordinate of the widget. + EndRem + Field x:Int + Rem + bbdoc: The Y co-ordinate of the widget. + EndRem + Field y:Int + Rem + bbdoc: The width of the widget. + EndRem + Field w:Int + Rem + bbdoc: The height of the widget. + EndRem + Field h:Int + Rem + bbdoc: Callback to call when clicked. + EndRem + Field callback(w:TWidget) + Rem + bbdoc: True if the mouse is over this widget, False otherwise. + EndRem + Field mouse_over:Int + Rem + bbdoc: The @TGUIHandler that owns this widget. + EndRem + Field owner:TGUIHandler + Rem + bbdoc: The mask of consumed events, zero otherwise. + EndRem + Field consumes:Int + + Rem + bbdoc: Override this accept keypresses + EndRem + Method HandleKey(k:Int) + End Method + + Rem + bbdoc: Override this for when the mouse enters. Call this parent version to handle @mouse_over too. + EndRem + Method MouseEnter() + If displayed And enabled + mouse_over=True + EndIf + End Method + + Rem + bbdoc: Override this for when the mouse leaves. Call this parent version to handle @mouse_over too. + EndRem + Method MouseLeave() + mouse_over=False + End Method + + Rem + bbdoc: Override to handle a mouse button press. + EndRem + Method HandleClick() + End Method + + Rem + bbdoc: Handles mouse dragging. + about: @mx and @my are the changes in mouse co-ordinates since the last drag. + EndRem + Method HandleDrag(mx:Int, my:Int) + End Method + + Rem + bbdoc: Must be provided by a widget to draw itself. + EndRem + Method Draw() Abstract + + Rem + bbdoc: Helper to draw a wireframe rectangle. + EndRem + Function DrawBox(x:Int, y:Int, w:Int, h:Int) + DrawLine(x,y,x+w-1,y) + DrawLine(x+w-1,y,x+w-1,y+h-1) + DrawLine(x+w-1,y+h-1,x,y+h-1) + DrawLine(x,y+h-1,x,y) + End Function + + Rem + bbdoc: Helper to draw a 3D rectangle. + EndRem + Function Draw3DBox(x:Int, y:Int, w:Int, h:Int, invert:Int, size:Int=2) + Local f:Int + + SetColor(200,200,200) + DrawRect(x,y,w,h) + + If invert + SetColor(170,170,170) + Else + SetColor(230,230,230) + EndIf + + For f=0 Until size + DrawLine(x+f,y+f,x+w-1-f,y+f) + DrawLine(x+w-1-f,y+f,x+w-1-f,y+h-1-f) + Next + + If invert + SetColor(230,230,230) + Else + SetColor(170,170,170) + EndIf + + For f=0 Until size + DrawLine(x+w-1-f,y+h-1-f,x+f,y+h-1-f) + DrawLine(x+f,y+h-1-f,x+f,y+f) + Next + End Function + +End Type + +Rem +bbdoc: The panel widget (simply displays itself as a white bordered black box) +EndRem +Type TPanel Extends TWidget + + Rem + bbdoc: Create a TPanel widget. + returns: The created widget. + about: @gui is the @TGUIHandler object managing this wiget. @x, @y, @x and @h are its position and size. If @x or @y is -1 they are centered. + EndRem + Function Create:TPanel(gui:TGUIHandler,x:Int, y:Int, w:Int, h:Int) + Local o:TPanel=New TPanel + o.displayed=True + o.enabled=True + o.consumes=0 + + If x=-1 + x=(GraphicsWidth()-w)/2 + EndIf + + If y=-1 + y=(GraphicsHeight()-h)/2 + EndIf + + o.x=x + o.y=y + o.w=w + o.h=h + gui.Register(o) + Return o + End Function + + Method Draw() + SetColor(0,0,0) + DrawRect(x,y,w,h) + SetColor(255,255,255) + DrawBox(x,y,w,h) + End Method + +End Type + +Rem +bbdoc: The label widget (simply displays the supplied string) +EndRem +Type TLabel Extends TWidget + Rem + bbdoc: Create a TLabel widget. + returns: The created widget. + about: @gui is the @TGUIHandler object managing this wiget. @x and @y are its position and @text is the text to display in the label. + EndRem + Function Create:TLabel(gui:TGUIHandler,x:Int, y:Int, text:String) + Local o:TLabel=New TLabel + o.displayed=True + o.enabled=True + o.consumes=0 + o.x=x + o.y=y + o.w=TSGUIFont.font.TextWidth(text)+2 + o.h=TSGUIFont.font.MaxHeight()+1 + o.text=text + gui.Register(o) + Return o + End Function + + Method Draw() + TSGUIFont.font.Draw(text,x+1,y+1) + End Method + +End Type + +Rem +bbdoc: The text entry widget +EndRem +Type TText Extends TWidget + Field maxlen:Int + Field mode:Int + + Rem + bbdoc: The text box handles any text + EndRem + Const NORMAL:Int=0 + + Rem + bbdoc: The text box handles a number + EndRem + Const NUMERIC:Int=1 + + Rem + bbdoc: The text box handles only integer numbers + EndRem + Const INTEGER:Int=2 + + Rem + bbdoc: The text box handles only positive numbers + EndRem + Const POSITIVE:Int=4 + + Rem + bbdoc: The text box handles a basic set of filename characters (alphanumerics, periods, spaces and underscores) + EndRem + Const FILENAME:Int=8 + + Rem + bbdoc: The text box is readonly + EndRem + Const READ_ONLY:Int=256 + + + Rem + bbdoc: Create a TText widget. + returns: The created widget. + about: @gui is the @TGUIHandler object managing this wiget. @x and @y are its position and @text is the initial text in the widget. + @maxlen is the maximum number of characters allowed. @mode defines the valid characters that can be entered. + @callback is called when RETURN is pressed in the text field. + EndRem + Function Create:TText(gui:TGUIHandler,x:Int, y:Int, text:String, maxlen:Int, mode:Int=0, callback(w:TWidget)=Null) + Local o:TText=New TText + o.displayed=True + o.enabled=True + o.consumes=HAS_CLICK|HAS_KEY + o.x=x + o.y=y + o.maxlen=maxlen + o.w=TSGUIFont.font.MaxWidth()*(maxlen+1)+2 + o.h=TSGUIFont.font.MaxHeight()+2 + o.text=text + o.callback=callback + o.mode=mode + gui.Register(o) + Return o + End Function + + Rem + bbdoc: Set the text to a floating point value. + about: @v is the floating point value (a double to cover both types). This value will be placed in the text + field with trailing zeros (and trailing dot if an integer) removed. + EndRem + Method SetFloat(v:Double) + Local s:String=v + + If s.Find(".")<>-1 + While s.length>1 And s[s.length-1]=Asc("0") + s=s[..s.length-1] + Wend + + While s.length>1 And s[s.length-1]=Asc(".") + s=s[..s.length-1] + Wend + EndIf + + text=s + End Method + + Method HandleClick() + If Not(mode & READ_ONLY) + owner.SetFocus(Self) + EndIf + End Method + + Method HandleKey(k:Int) + If (mode & READ_ONLY) + Return + EndIf + + If k=27 + text="" + Else If k=8 + If text.length>0 + text=text[0..text.length-1] + EndIf + Else If k=13 + If callback<>Null + callback(Self) + owner.SetFocus(Null) + EndIf + Else If k>31 And k<127 And text.length=Asc("0") And k<=Asc("9") + text:+Chr(k) + EndIf + + If k=Asc(".") And (Not (mode & INTEGER)) And text.Find(".")=-1 + text:+Chr(k) + EndIf + Else + If (mode & FILENAME) + If (k>=Asc("a") And k<=Asc("z")) Or (k>=Asc("A") And k<=Asc("Z")) Or (k>=Asc("0") And k<=Asc("9")) Or k=Asc(" ") Or k=Asc(".") Or k=Asc("_") + text:+Chr(k) + EndIf + Else + text:+Chr(k) + EndIf + EndIf + EndIf + End Method + + Method Draw() + Local s:String=text + + If owner.GetFocus()=Self And Not (mode & READ_ONLY) + SetColor(128,128,128) + s:+"_" + Else + SetColor(64,64,64) + EndIf + + DrawRect(x,y,w,h) + + TSGUIFont.font.Draw(s,x+1,y+1) + End Method +End Type + +Rem +bbdoc: The checkbox widget +EndRem +Type TCheckbox Extends TWidget + + Rem + bbdoc: True if the box is checked, False otherwise. + EndRem + Field checked:Int + + Rem + bbdoc: Create a TCheckox widget. + returns: The created widget. + about: @gui is the @TGUIHandler object managing this wiget. @x and @y are its position and @text is the text to display by the checkbox. + @callback is called when the checkbox is toggled. + EndRem + Function Create:TCheckbox(gui:TGUIHandler, x:Int, y:Int, text:String, callback(w:TWidget)=Null) + Local o:TCheckbox=New TCheckbox + o.displayed=True + o.enabled=True + o.consumes=HAS_CLICK + o.x=x + o.y=y + o.w=TSGUIFont.font.TextWidth(" "+text)+4+TSGUIFont.font.MaxHeight() + o.h=TSGUIFont.font.MaxHeight()+2 + o.text=text + o.callback=callback + gui.Register(o) + Return o + End Function + + Method HandleClick() + checked=Not checked + + If callback<>Null + callback(Self) + EndIf + End Method + + Method Draw() + If (mouse_over) + SetColor(255,255,255) + Else + SetColor(200,200,200) + EndIf + + DrawBox(x,y,TSGUIFont.font.MaxHeight(),TSGUIFont.font.MaxHeight()) + + If checked + SetColor(255,100,100) + DrawRect(x+1,y+1,TSGUIFont.font.MaxHeight()-2,TSGUIFont.font.MaxHeight()-2) + EndIf + + TSGUIFont.font.Draw(" "+text,x+2+TSGUIFont.font.MaxHeight(),y+1) + End Method +End Type + +Rem +bbdoc: The button widget +EndRem +Type TButton Extends TWidget + + Field ox:Int + Field oy:Int + + Rem + bbdoc: Create a TButton widget. + returns: The created widget. + about: @gui is the @TGUIHandler object managing this wiget. @x, @y, @w and @h are its position and size, and @text is the text to display in the button. + @callback is called when the button is pressed. + EndRem + Function Create:TButton(gui:TGUIHandler, x:Int, y:Int, w:Int, h:Int, text:String, callback(w:TWidget)) + Local o:TButton=New TButton + o.displayed=True + o.enabled=True + o.consumes=HAS_CLICK + o.x=x + o.y=y + o.w=w + o.h=h + o.text=text + o.ox=x+w/2-TSGUIFont.font.TextWidth(text)/2 + o.oy=y+h/2-TSGUIFont.font.TextHeight(text)/2 + o.callback=callback + gui.Register(o) + Return o + End Function + + Method HandleClick() + If callback<>Null + callback(Self) + EndIf + End Method + + Method Draw() + If (mouse_over) + SetColor(255,255,255) + DrawBox(x,y,w,h) + EndIf + + Draw3DBox(x+1,y+1,w-2,h-2,False,2) + + TSGUIFont.font.Draw(text,ox,oy) + End Method +End Type + +Rem +bbdoc: A drop down list type widget +EndRem +Type TButtonList Extends TWidget + + Field options:String[] + + Rem + bbdoc: The selected item. + EndRem + Field selected:Int + + Rem + bbdoc: Create a TButtonList widget. + returns: The created widget. + about: @gui is the @TGUIHandler object managing this wiget. @x and @y are its position. @options are the options for the list and + @selected is the currently selected item. @callback is called when the selection changes. + EndRem + Function Create:TButtonList(gui:TGUIHandler, x:Int, y:Int, options:String[], selected:Int, callback(w:TWidget)) + Local o:TButtonList=New TButtonList + Local maxw:Int=0 + o.displayed=True + o.enabled=True + o.consumes=HAS_CLICK + o.x=x + o.y=y + o.options=options + o.selected=selected + o.text=options[selected] + + For Local s:String=EachIn options + maxw=Max(maxw,TSGUIFont.font.TextWidth(s)) + Next + + o.w=maxw+TSGUIFont.font.MaxHeight()+4 + o.h=TSGUIFont.font.MaxHeight()+2 + o.callback=callback + gui.Register(o) + Return o + End Function + + Method HandleClick() + Local sel:Int=GUIMenu("Select value",options,x,y) + + If sel<>-1 + selected=sel + text=options[selected] + If callback<>Null + callback(Self) + EndIf + EndIf + End Method + + Method Draw() + If (mouse_over) + SetColor(128,128,128) + Else + SetColor(64,64,64) + EndIf + + DrawRect(x,y,w,h) + Draw3DBox(x+2,y+2,h-4,h-4,False,1) + + TSGUIFont.font.Draw(text,x+TSGUIFont.font.MaxHeight()+3,y+1) + End Method +End Type + +Rem +bbdoc: Optional type to use for TTextList +about: If the objects stored as TTextList options are derived from this type then tabular lists can be created. +EndRem +Type TTextListItem Abstract + Rem + bbdoc: The number of columns. + returns: The number of columns + EndRem + Method Columns:Int() Abstract + + Rem + bbdoc: A column offset. + returns: The column offset for column @i (numbered from zero). + EndRem + Method ColumnOffset:Int(i:Int) Abstract + + Rem + bbdoc: Column data. + returns: The column data for column @i (numbered from zero). + EndRem + Method ColumnData:String(i:Int) Abstract +End Type + +Rem +bbdoc: A widget that displays text items as a list. +EndRem +Type TTextList Extends TWidget + + Field options:Object[] + Field selected:Int + Field num:Int + Field top:Int + Field rows:Int + + Rem + bbdoc: Create a TTextList widget. + returns: The created widget. + about: @gui is the @TGUIHandler object managing this wiget. @x, @y, and @w are its position and width. + @rows are the number of items to display at a time. + @callback is called when the selection changes. + EndRem + Function Create:TTextList(gui:TGUIHandler, x:Int, y:Int, w:Int, rows:Int, callback(w:TWidget)=Null) + Local o:TTextList=New TTextList + Local maxw:Int=0 + o.displayed=True + o.enabled=True + o.consumes=HAS_CLICK + o.x=x + o.y=y + o.options=Null + o.selected=-1 + o.num=0 + o.top=0 + o.rows=rows + + o.w=w + o.h=TSGUIFont.font.MaxHeight()*rows + o.callback=callback + gui.Register(o) + Return o + End Function + + Rem + bbdoc: Sets the options to display in the list. + about: @opts is an array of objects. Note: If the objects passed are derived from TTextListItem then tabular output is generated. + If they are not derived, ToString() is called on the objects to display them, so you are not restricted to the type of object that + can be passed. + EndRem + Method SetOptions(opts:Object[]) + options=opts + num=opts.length + selected=-1 + top=0 + End Method + + Rem + bbdoc: Gets the selected item's index. + returns: The selected item's index, or -1 if nothing is selected. + EndRem + Method GetSelectedIndex:Int() + Return selected + End Method + + Rem + bbdoc: Gets the selected item. + returns: The selected item, or null if nothing is selected. + EndRem + Method GetSelectedItem:Object() + If options<>Null And selected<>-1 + Return options[selected] + Else + Return Null + EndIf + End Method + + Rem + bbdoc: Set the top row. + about: @i is the index of the item to display in the first row of the widget. + EndRem + Method SetTopRow(i:Int) + If options<>Null And iNull + Return top + Else + Return -1 + EndIf + End Method + + Rem + bbdoc: Ensure an item is visible. + about: @i is the index of the item that is to be made visible. + EndRem + Method EnsureVisible(i:Int) + If options<>Null And i=top+rows + top=Max(0,i-rows+1) + EndIf + EndIf + End Method + + Method HandleClick() + If options<>Null + Local sel:Int=top+(MouseY()-y)/TSGUIFont.font.MaxHeight() + + If selNull + callback(Self) + EndIf + EndIf + EndIf + End Method + + Method Draw() + SetColor(64,64,64) + DrawRect(x,y,w,h) + + If options<>Null + Local vx:Int + Local vy:Int + Local vw:Int + Local vh:Int + + GetViewport(vx,vy,vw,vh) + + Local ty:Int=y + For Local f:Int=top Until top+rows + SetViewport(x,ty,w,TSGUIFont.font.MaxHeight()) + + If f=selected + If mouse_over And MouseY()>=ty And MouseY()=ty And MouseY()Null + For Local f:Int=0 Until li.Columns() + TSGUIFont.font.Draw(li.ColumnData(f),x+li.ColumnOffset(f),ty) + Next + Else + TSGUIFont.font.Draw(options[f].ToString(),x,ty) + EndIf + EndIf + + ty:+TSGUIFont.font.MaxHeight() + Next + + SetViewport(vx,vy,vw,vh) + EndIf + End Method +End Type + +Rem +bbdoc: A number up/down widget for doubles +EndRem +Type TNumberDouble Extends TWidget + + Rem + bbdoc: The value + EndRem + Field value:Double + + Rem + bbdoc: The increment/decrement + EndRem + Field change:Double + + Rem + bbdoc: The maximum value + EndRem + Field maxval:Double + + Rem + bbdoc: The minimum value + EndRem + Field minval:Double + + Rem + bbdoc: Create a TNumber widget. + returns: The created widget. + about: @gui is the @TGUIHandler object managing this wiget. @x and @y are its position. @callback is called when the value changes. + EndRem + Function Create:TNumberDouble(gui:TGUIHandler, x:Int, y:Int, callback(w:TWidget)=Null) + Local o:TNumberDouble=New TNumberDouble + o.displayed=True + o.enabled=True + o.consumes=HAS_CLICK + o.value=0 + o.minval=0 + o.maxval=100 + o.change=10 + o.x=x + o.y=y + o.w=TSGUIFont.font.MaxHeight()*2+8 + o.h=TSGUIFont.font.MaxHeight()+2 + o.callback=callback + gui.Register(o) + Return o + End Function + + Method HandleClick() + Local old:Double=value + + If MouseX()old And callback<>Null + callback(Self) + EndIf + End Method + + Method Draw() + If mouse_over + If MouseX()old And callback<>Null + callback(Self) + EndIf + End Method + + Method Draw() + If mouse_over + If MouseX()h) + o.SetBar(0,100,10) + o.callback=callback + gui.Register(o) + Return o + End Function + + Rem + bbdoc: Set parameters for scroll bar + about: @min_val and @max_val are the values at the top and bottom of the scroll bar. @page_size is the numbers between the two that + is covered by the block in the scrollbar. Note: The maximum value of @value is @max_val minus @page_size. + EndRem + Method SetBar(min_val:Double, max_val:Double, page_size:Double) + minval=min_val + maxval=max_val + page=page_size + + If horiz + stepsize=(maxval-minval)/w + blocksize=Min(w,Max(1,page/stepsize)) + bc=x + Else + stepsize=(maxval-minval)/h + blocksize=Min(h,Max(1,page/stepsize)) + bc=y + EndIf + End Method + + Rem + bbdoc: Get the current value of the scrollbar. + returns: The current position of the scrollbar inbetween the minimum and maximum values. + EndRem + Method GetValue:Double() + If horiz + Return minval+(bc-x)*stepsize + Else + Return minval+(bc-y)*stepsize + EndIf + End Method + + Rem + bbdoc: Sets the current value of the scrollbar. + EndRem + Method SetValue(val:Double) + If horiz + bc=Max(x,Min(x+w-blocksize,x+(val-minval)/stepsize)) + Else + bc=Max(y,Min(y+h-blocksize,y+(val-minval)/stepsize)) + EndIf + End Method + + Method HandleClick() + Local old:Double=GetValue() + + If horiz + bc=Max(x,Min(x+w-blocksize,MouseX())) + Else + bc=Max(y,Min(y+h-blocksize,MouseY())) + EndIf + + If GetValue()<>old And callback<>Null + callback(Self) + EndIf + End Method + + Method HandleDrag(mx:Int, my:Int) + Local old:Double=GetValue() + + If horiz + bc=Max(x,Min(x+w-blocksize,bc+mx)) + Else + bc=Max(y,Min(y+h-blocksize,bc+my)) + EndIf + + If GetValue()<>old And callback<>Null + callback(Self) + EndIf + End Method + + Method Draw() + SetColor(64,64,64) + DrawRect(x,y,w,h) + If horiz + Draw3DBox(bc,y,blocksize,h,False,1) + Else + Draw3DBox(x,bc,w,blocksize,False,1) + EndIf + End Method +End Type + +Rem +bbdoc: Handles the GUI. +EndRem +Type TGUIHandler + + ' These are private + ' + Field m_widgets:TList + Field m_focus:TWidget + Field m_over:TWidget + Field m_clicked:TWidget + Field m_dragging:Int + Field m_dragx:Int + Field m_dragy:Int + Field m_dragobj:TWidget + + Rem + bbdoc: Create a GUI Handler. + returns: The GUI Hanbler. + EndRem + Function Create:TGUIHandler() + Local o:TGUIHandler + + o=New TGUIHandler + + o.m_widgets=CreateList() + o.m_focus=Null + o.m_over=Null + o.m_clicked=Null + o.m_dragging=False + o.m_dragx=0 + o.m_dragy=0 + o.m_dragobj=Null + + Return o + End Function + + Rem + bbdoc: Register a widget. + about: Widgets in the library call this themselves when creating. + EndRem + Method Register(w:TWidget) + m_widgets.AddLast(w) + w.owner=Self + End Method + + Rem + bbdoc: Remove all widgets. + EndRem + Method Clear() + m_widgets.Clear() + End Method + + Rem + bbdoc: Sets the enable state of all widgets. + about: If @state is true then all widgets are enabled, otherwise all widgets are disabled. + EndRem + Method SetEnable(state:Int) + For Local w:TWidget=EachIn m_widgets + w.enabled=state + Next + End Method + + Rem + bbdoc: Sets the displayed state of all widgets. + about: If @state is true then all widgets are displayed, otherwise all widgets are hidden. + EndRem + Method SetDisplay(state:Int) + For Local w:TWidget=EachIn m_widgets + w.displayed=state + Next + End Method + + Rem + bbdoc: Sets the keyboard focus to the supplied widget. Pass null for no focus. + EndRem + Method SetFocus(w:TWidget) + m_focus=w + End Method + + Rem + bbdoc: Gets the keyboard focus. + returns: The currently focused TWidget, or null for no focus. + EndRem + Method GetFocus:TWidget() + Return m_focus + End Method + + Rem + bbdoc: Gets the last clicked widget. + returns: The last clicked TWidget. Null is returned if this is called again before another widget is clicked. + EndRem + Method Clicked:TWidget() + Local last:TWidget=m_clicked + m_clicked=Null + Return last + End Method + + Rem + bbdoc: Whether a widget is dragging + returns: True if a widget is consuming a mouse drag. + EndRem + Method IsDragging:Int() + Return m_dragging + End Method + + Rem + bbdoc: Perform the event loop and pass any necessary events. + about: KeyHit(KEY_MOUSELEFT) and GetChar() are used to consume events for the interface. + EndRem + Method EventLoop() + Local x:Int=MouseX() + Local y:Int=MouseY() + Local b:Int=MouseHit(1)>0 + Local drag:Int=MouseDown(1) + + Local w:TWidget=LocateWidget(x,y) + + For Local wid:TWidget=EachIn m_widgets + If wid.displayed + If wid.enabled + wid.Draw() + Else + SetAlpha(0.3) + wid.Draw() + SetAlpha(1) + EndIf + EndIf + Next + + If w<>m_over + If m_over<>Null + m_over.MouseLeave() + EndIf + m_over=w + If m_over<>Null + m_over.MouseEnter() + EndIf + EndIf + + If w<>Null And w.enabled And w.consumes&TWidget.HAS_CLICK=TWidget.HAS_CLICK And b And Not m_dragging + w.HandleClick() + m_clicked=w + EndIf + + Local k:Int=GetChar() + + If k<>0 And m_focus<>Null And m_focus.enabled And m_focus.consumes&TWidget.HAS_KEY=TWidget.HAS_KEY + m_focus.HandleKey(k) + EndIf + + If drag + If m_dragging + m_dragobj.HandleDrag(MouseX()-m_dragx,MouseY()-m_dragy) + m_dragx=MouseX() + m_dragy=MouseY() + Else + If w<>Null And w.consumes&TWidget.HAS_DRAG=TWidget.HAS_DRAG + m_dragging=True + m_dragx=MouseX() + m_dragy=MouseY() + m_dragobj=w + EndIf + EndIf + Else + m_dragging=False + m_dragobj=Null + EndIf + End Method + + ' Private method + ' + Method LocateWidget:TWidget(x:Int,y:Int) + For Local w:TWidget=EachIn m_widgets + If x>=w.x And y>=w.y And xbutton + Cls + SetAlpha(0.5) + DrawImage(back,0,0) + SetAlpha(1) + TWidget.Draw3DBox(x,y,w,h,False,2) + gui.EventLoop() + click=gui.Clicked() + + If i<>Null + SetColor(255,255,255) + DrawImage(i,MouseX(),MouseY()) + EndIf + + Flip + Wend +End Function + +Rem +bbdoc: Displays a yes/no alert with the supplied string. +returns: True if Yes selected, otherwise False. +about: The string @s can be split into multiple lines using the '|' character. If @i is not null then this image is drawn as a mouse cursor. +EndRem +Function GUIYesNo:Int(s:String, i:TImage=Null) + Local back:TImage=CreateImage(GraphicsWidth(),GraphicsHeight(),1,0) + GrabImage(back,0,0) + + Local txt:TSplitText=TSplitText.Create(s) + + Local w:Int=Max(txt.width+10,GraphicsWidth()/4) + Local h:Int=txt.Height+TSGUIFont.font.MaxHeight()*4 + Local x:Int=GraphicsWidth()/2-w/2 + Local y=GraphicsHeight()/2-h/2 + Local by=y+h-TSGUIFont.font.MaxHeight()*2.5 + + Local gui:TGUIHandler=TGUIHandler.Create() + + Local ty:Int=y+5 + + For Local t:String=EachIn txt.lines + Local label:TLabel=TLabel.Create(gui,x+5,ty,t) + ty:+TSGUIFont.font.TextHeight(t) + Next + + Local yes:TButton=TButton.Create(gui,x+5,by,w/2-10,TSGUIFont.font.MaxHeight()*2,"Yes",Null) + Local no:TButton=TButton.Create(gui,x+w/2+5,by,w/2-10,TSGUIFont.font.MaxHeight()*2,"No",Null) + + Local click:TWidget=Null + + While click=Null + Cls + SetAlpha(0.5) + DrawImage(back,0,0) + SetAlpha(1) + TWidget.Draw3DBox(x,y,w,h,False,2) + gui.EventLoop() + click=gui.Clicked() + + If i<>Null + SetColor(255,255,255) + DrawImage(i,MouseX(),MouseY()) + EndIf + + Flip + Wend + + Return click=yes +End Function + + +Rem +bbdoc: Displays a pop-up menu. +returns: The index of the selected option, -1 for none. +about: @title is the menu title, @options the options to display and @x and @y specify its position. +If @i is not null then this image is drawn as a mouse cursor. +EndRem +Function GUIMenu(title:String, options:String[], x:Int, y:Int, i:TImage=Null) + Local f:Int + Local back:TImage=CreateImage(GraphicsWidth(),GraphicsHeight(),1,0) + GrabImage(back,0,0) + + Local st:Int=TSGUIFont.font.MaxHeight()*2 + Local h:Int=TSGUIFont.font.MaxHeight()*3 + Local w:Int=TSGUIFont.font.TextWidth(title)+30 + + For f=0 Until options.length + w=Max(w,TSGUIFont.font.TextWidth(options[f])+30) + h:+st + Next + + Local gui:TGUIHandler=TGUIHandler.Create() + + x=Max(0,Min(x,GraphicsWidth()-w)) + y=Max(0,Min(y,GraphicsHeight()-h)) + + Local label:TLabel=TLabel.Create(gui,x+5,y+2,title) + Local button:TButton[]=New TButton[options.length] + + For f=0 Until options.length + button[f]=TButton.Create(gui,x+5,y+TSGUIFont.font.MaxHeight()*2+f*st,w-10,st-2,options[f],Null) + Next + + Local click:TWidget=Null + + While click=Null And MouseHit(2)=0 + Cls + SetAlpha(0.5) + DrawImage(back,0,0) + SetAlpha(1) + TWidget.Draw3DBox(x,y,w,h,False,2) + gui.EventLoop() + click=gui.Clicked() + + If i<>Null + SetColor(255,255,255) + DrawImage(i,MouseX(),MouseY()) + EndIf + + Flip + Wend + + For f=0 Until options.length + If button[f]=click + Return f + EndIf + Next + + Return -1 +End Function + +Rem +bbdoc: Displays a basic file selector. +returns: The selected file, or null for none. +about: @title is the title. @file is the initially selected file, and f set to null then no file is selected and the current directory displayed. +Set @save to true for a save dialog (the filename can be altered). +If @i is not null then this image is drawn as a mouse cursor. +EndRem +Function GUIFileSelect:String(title:String, file:String, save:Int, i:TImage=Null) + FlushKeys() + + Local oldpwd:String=CurrentDir() + Local dir:String + Local fn:String + Local sw:Int=GraphicsWidth() + Local sh:Int=GraphicsHeight() + Local fh:Int=TSGUIFont.font.MaxHeight() + Local fw:Int=TSGUIFont.font.MaxWidth() + Local rows:Int=(sh-fh*10)/fh + + If file<>Null And file<>"" + dir=ExtractDir(file) + + If dir="" + dir=oldpwd + EndIf + + If FileType(file)=FILETYPE_FILE + fn=StripDir(file) + Else + fn="" + EndIf + Else + dir=oldpwd + fn="" + EndIf + + Local gui:TGUIHandler=TGUIHandler.Create() + + TPanel.Create(gui,0,0,sw,sh) + TLabel.Create(gui,10,fh*0.5,title) + + Local list:TTextList=TTextList.Create(gui,20,fh*2,sw-40,rows) + Local scroll:TScrollbar=TScrollbar.Create(gui,list.x+list.w+5,list.y,10,list.h) + + Local fntext:TText + + If save + fntext=TText.Create(gui,20,sh-fh*6,fn,(sw-40)/fw,TText.FILENAME) + Else + fntext=TText.Create(gui,20,sh-fh*6,fn,(sw-40)/fw,TText.READ_ONLY) + EndIf + + Local bw:Int=TSGUIFont.font.MaxWidth()*9 + + Local cancel:TButton=TButton.Create(gui,sw-bw-20,sh-fh*3.5,bw,fh*2.5,"Cancel",Null) + Local ok:Tbutton=TButton.Create(gui,cancel.x-bw-10,cancel.y,bw,fh*2.5,"OK",Null) + + Local last:TDirEntry=Null + + ChangeDir(dir) + LoadDirEnts(list,scroll,rows) + + Repeat + Cls + + gui.EventLoop() + + TSGUIFont.font.Draw(CurrentDir(),list.x,list.y+list.h+3) + + Local click:TWidget=gui.Clicked() + + If click=ok + Local ret:String=CurrentDir()+"/"+fntext.text + ChangeDir(oldpwd) + FlushKeys() + Return ret + EndIf + + If click=cancel Or (KeyHit(KEY_ESCAPE) And gui.GetFocus()=Null) + ChangeDir(oldpwd) + FlushKeys() + Return Null + EndIf + + If list.GetSelectedItem()<>last + last=TDirEntry(list.GetSelectedItem()) + + If last.is_dir + ChangeDir(last.filename) + LoadDirEnts(list,scroll,rows) + fntext.text="" + last=Null + Else + fntext.text=last.filename + EndIf + EndIf + + ok.enabled=(fntext.text<>"") + + list.SetTopRow(scroll.GetValue()) + + If i<>Null + SetColor(255,255,255) + DrawImage(i,MouseX(),MouseY()) + EndIf + + Flip + Forever +End Function + +Rem +bbdoc: Handles a TGUIHandler as if it's a modal dialog. +returns: True if @ok is pressed, False if @cancel or the ESCAPE key is pressed. ESCAPE is only allowed if nothing has the text focus. +about: @gui is the GUI handler and widgets to display as a dialog., @ok is the clickable widget that OK's the dialog, @cancel the widget that cancels it. +If @i is not null then this image is drawn as a mouse cursor. +EndRem +Function GUIDialog(gui:TGUIHandler, ok:TWidget, cancel:TWidget, i:TImage=Null) + FlushKeys() + + Local back:TImage=CreateImage(GraphicsWidth(),GraphicsHeight(),1,0) + GrabImage(back,0,0) + + Local done:Int=False + Local ok_pressed:Int + Local click:TWidget + + While done=False + Cls + SetAlpha(0.5) + DrawImage(back,0,0) + SetAlpha(1) + gui.EventLoop() + click=gui.Clicked() + + If click=ok + done=True + ok_pressed=True + EndIf + + If click=cancel Or (KeyHit(KEY_ESCAPE) And gui.GetFocus()=Null) + done=True + ok_pressed=False + EndIf + + If i<>Null + SetColor(255,255,255) + DrawImage(i,MouseX(),MouseY()) + EndIf + + Flip + Wend + + FlushKeys() + Return ok_pressed +End Function + +Private + +Type TSplitText + Field lines:TList + Field width:Int + Field height:Int + + Function Create:TSplitText(s:String) + Local o:TSplitText=New TSplitText + + o.lines=CreateList() + o.width=0 + o.height=0 + + Local sub:String="" + + For Local f:Int=0 Until s.length + Local c:Int=s[f] + If c=Asc("|") + o.lines.AddLast(sub) + o.width=Max(o.width,TSGUIFont.font.TextWidth(sub)) + o.height:+TSGUIFont.font.TextHeight(sub) + sub="" + Else + sub:+Chr(c) + EndIf + Next + + If sub.length>0 + o.lines.AddLast(sub) + o.width=Max(o.width,TSGUIFont.font.TextWidth(sub)) + o.height:+TSGUIFont.font.TextHeight(sub) + EndIf + + Return o + End Function +EndType + +Type TDirEntry Extends TTextListItem + Field path:String + Field dir:String + Field filename:String + Field size:Int + Field is_dir:Int + + Function Create:TDirEntry(path:String) + Local o:TDirEntry=New TDirEntry + o.path=path + o.dir=ExtractDir(path) + o.filename=StripDir(path) + o.is_dir=(FileType(path)=FILETYPE_DIR) + o.size=FileSize(path) + Return o + End Function + + Method Compare:Int(o:Object) + Local d:TDirEntry=TDirEntry(o) + + If d=Null + Return 0 + EndIf + + If is_dir=d.is_dir + Return filename.Compare(d.filename) + Else + If is_dir + Return -1 + Else + Return 1 + EndIf + EndIf + + Return 0 + End Method + + Method Columns:Int() + Return 2 + End Method + + Method ColumnOffset:Int(i:Int) + If i=0 + Return 0 + Else + Return GraphicsWidth()-TSGUIFont.font.MaxWidth()*20 + EndIf + End Method + + Method ColumnData:String(i:Int) + If i=0 + Return filename + Else + If is_dir + Return "DIR" + Else + Return size+" bytes" + EndIf + EndIf + End Method +End Type + +Function LoadDirEnts(list:TTextList, scroll:TScrollbar, rows:Int) + Local d:TList=CreateList() + + For Local s:String=EachIn LoadDir(CurrentDir(),False) + d.AddLast(TDirEntry.Create(CurrentDir()+"/"+s)) + Next + + d.Sort() + + list.SetOptions(d.ToArray()) + scroll.SetBar(0,Max(1,d.Count()-rows/2),1) +End Function diff --git a/vector.mod/.cvsignore b/vector.mod/.cvsignore index 5f1a86a..0f5601a 100644 --- a/vector.mod/.cvsignore +++ b/vector.mod/.cvsignore @@ -1,6 +1,5 @@ -vector.release.win32.i -vector.debug.win32.a -vector.debug.win32.i -vector.release.win32.a .bmx doc +*.a +*.i +*.i2 diff --git a/vectorgfx.mod/.cvsignore b/vectorgfx.mod/.cvsignore index eda0494..0f5601a 100644 --- a/vectorgfx.mod/.cvsignore +++ b/vectorgfx.mod/.cvsignore @@ -1,5 +1,5 @@ -vectorgfx.release.win32.i -vectorgfx.debug.win32.a -vectorgfx.debug.win32.i -vectorgfx.release.win32.a .bmx +doc +*.a +*.i +*.i2 diff --git a/win32.mod/.cvsignore b/win32.mod/.cvsignore index dd78089..0f5601a 100644 --- a/win32.mod/.cvsignore +++ b/win32.mod/.cvsignore @@ -1,6 +1,5 @@ -win32.release.win32.i -win32.debug.win32.a -win32.debug.win32.i -win32.release.win32.a .bmx doc +*.a +*.i +*.i2 -- cgit v1.2.3