Forum Replies Created
-
AuthorPosts
-
Can’t you just use MX2’s built-in event handling mechanisms to generate mouse movement events? Eg:
[/crayon]Monkey123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051[crayon-5cba87d85a068672525172 inline="true" ]#Import "<std>"#Import "<mojo>"Using std..Using mojo..Class MyWindow Extends WindowMethod New( title:String="Simple mojo app",width:Int=640,height:Int=480,flags:WindowFlags=Null )Super.New( title,width,height,flags )EndMethod OnRender( canvas:Canvas ) OverrideApp.RequestRender()canvas.DrawText( "Press space...",Width/2,Height/2,.5,.5 )EndMethod OnKeyEvent(event:KeyEvent) OverrideIf event.Type = EventType.KeyRepeatIf event.Key = Key.SpacePrint "Spacebar pressed."Local loc:Vec2iLocal wheel:Vec2iLocal modi:ModifierLocal clicks := 0Local button := MouseButton.LeftSendMouseEvent(New MouseEvent(EventType.MouseMove, Self, loc, button, wheel, modi, clicks))EndifEndifEndMethod OnMouseEvent(event:MouseEvent) OverrideIf event.Type = EventType.MouseClick Then Print "CLICK!"If event.Type = EventType.MouseMovePrint "Mouse moved."EndifEndEndFunction Main()New AppInstanceNew MyWindowApp.Run()EndThere’s a bug in the Window.BeginFullscreen method. I posted an issue on Github…
When it’s fixed the following *rough* example should work. It gets your primary display’s supported modes and allows you to switch through them at run time:
[/crayon]Monkey123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163[crayon-5cba87d85fd30400056555 inline="true" ]#Import "<std>"#Import "<sdl2>"#Import "<mojo>"Using std..Using sdl2..Using mojo..Function Main()New AppInstanceNew MyWindowApp.Run()EndClass MyWindow Extends WindowField _curScreenMode:ScreenModeField _curScreenModeStr:StringMethod New( title:String="Simple mojo app",width:Int=640,height:Int=480,flags:WindowFlags=Null )Super.New( title,width,height,flags )'In this example, assuming mojo is using SDL display id = 0.ScreenMode.GetAll(0)ScreenMode.DebugPrintAll()If ScreenMode.Stack.Length <= 0Print "ERROR: Could not find a valid screen mode."App.Terminate()EndSetScreenMode(0)EndMethod SetScreenMode:Void(idx:int)If Fullscreen Then EndFullscreen()If idx < 0 Or idx >= ScreenMode.Stack.Length Then idx = 0_curScreenMode = ScreenMode.Stack[idx]_curScreenModeStr = _curScreenMode.ToString()BeginFullscreen(_curScreenMode.Width, _curScreenMode.Height, _curScreenMode.Rate)App.RequestRender()EndMethod OnRender( canvas:Canvas ) OverrideApp.RequestRender()canvas.DrawText("[TAB] - toggle fullscreen, [LEFT] [RIGHT] change screen mode.", Width / 2, Height / 4, 0.5, 0.5)canvas.DrawText(_curScreenModeStr, Width / 2, Height / 2, 0.5, 0.5)canvas.Flush()EndMethod OnKeyEvent:Void(event:KeyEvent) OverrideIf event.Type = EventType.KeyDownSelect event.KeyCase Key.EscapeApp.Terminate()Case Key.TabIf Fullscreen Then EndFullscreen() Else SetScreenMode(_curScreenMode.ModeId)Case Key.LeftSetScreenMode(_curScreenMode.ModeId - 1)Case Key.RightSetScreenMode(_curScreenMode.ModeId + 1)EndEndifEndEndClass ScreenMode'TODO: DPI information for each display?PublicGlobal Stack:Stack<ScreenMode>Function GetAll:Void(displayId:Int = -1)Stack = New Stack<ScreenMode>Local numDisplays := SDL_GetNumVideoDisplays()For Local i:Int = 0 Until numDisplays'Only include modes matvhing the specified displayId'otherwise if < 0 then inlclude all modes for all detected displays.If displayId >= 0 And i <> displayId Then ContinueLocal displayName := String.FromCString(SDL_GetDisplayName(i))Local numModes := SDL_GetNumDisplayModes(i)For Local j := 0 Until numModesLocal displayMode:SDL_DisplayModeLocal displayModePtr:SDL_DisplayMode Ptr = Varptr displayModeSDL_GetDisplayMode(i, j, displayModePtr)Stack.Push(New ScreenMode(i, j, displayMode))NextNextEndFunction DebugPrintAll:Void()For Local mode := Eachin StackPrint mode.ToString()NextEnd'----------PrivateField _displayId:IntField _modeId:IntField _mode:SDL_DisplayModePublicMethod New(displayId:Int, modeId:Int, mode:SDL_DisplayMode)_displayId = displayId_modeId = modeId_mode = modeEndProperty DisplayId:Int()Return _displayIdEndProperty ModeId:Int()Return _modeIdEndProperty Width:Int()Return _mode.wEndProperty Height:Int()Return _mode.hEndProperty Rate:Int()Return _mode.refresh_rateEndMethod ToString:String()Local str := "(" + _displayId + ") " + String.FromCString(SDL_GetDisplayName(_displayId))str += " -- [" + _modeId + "] " + _mode.w + "x" + _mode.h + " @ " + _mode.refresh_rate + "hz"Return strEndEndYour TestE function is wrong. Hint: it has something to do with your while condition.
EDIT: Okay here’s a solution (because Lists in MX2 are apparently circular):
[/crayon]Monkey1234567891011[crayon-5cba87d867d4b049406553 inline="true" ]Function TestE()'ELocal firstNode := Collection_.ToNode()Local node := firstNodeRepeat'Do something useful here.node = node.SuccUntil node = firstNodeEnd FunctionOn iOS and MacOS, assuming I understand the information in this link:
Persistent user-specific files like app configuration and save game files should be stored in the user’s Library folder.
eg:
Users/Dude/Library/Application Support/TheGame/options.cfg
Users/Dude/Library/Application Support/TheGame/save001.dat
etc..Try this:
[/crayon]Monkey123456789101112131415161718[crayon-5cba87d86d3c9666716273 inline="true" ]#Import "<std>"#Import "table.data"Using std..Function Main()Local url := AssetsDir() + "table.data"Local dataIn := FileStream.Open(url, "r")If Not dataInRuntimeError("unable to find data file: " + url)ElseWhile Not dataIn.EofPrint dataIn.ReadByte()WenddataIn.Close()EndEndWell, that was simpler than I thought. Works on MacOSX, untested on Windows. It pays to poke around monkey2’s source code (I merely copied and modified the DesktopDir function).
[/crayon]Monkey1234567891011121314151617181920[crayon-5cba87d870afe306330703 inline="true" ]#Import "<std>"#Import "<libc>"Using std..Using libc..Function Main()Print DocumentsDir()EndFunction DocumentsDir:String()#If __TARGET__="windows"Return (String.FromCString( getenv( "HOMEDRIVE" ) )+String.FromCString( getenv( "HOMEPATH" ) )).Replace( "\","/" )+"/Documents/"#Else If __DESKTOP_TARGET__Return String.FromCString( getenv( "HOME" ) )+"/Documents/"#EndifReturn ""EndEDIT: And it works in place of the DesktopDir() function in my earlier file creation/reading/writing test code. Just remember to import libc..
Actually, it would be nice if I could do this on MacOS X to access/read/write to the user’s Documents directory:
[/crayon]Monkey12345678910111213141516171819[crayon-5cba87d8741bf007199269 inline="true" ]#Import "<std>"Using std..Function Main()Local url:="~~/Documents"Print urlChangeDir(url)Local docs := LoadDir(".")For Local doc := Eachin docsPrint docNextEndBut, alas, it’s not that simple.
I think we need to expose a few additional folders so we can do our file handling in a more “appropriate” manner, ie according to modern expectations.
Here’s a good link for iOS / MacOS X:
I don’t have time right now, but later I’ll have a crack at exposing the Documents and Library folders via a wrapper or maybe a modification to std.filesystem (if nobody else does it first).
I haven’t looked into the other target platforms yet, but the principles are the same IIRC. In any case I need the functionality for Mac OS X and Windows 10, so minimally that’s what I need to get working at some point…
IIRC Brucey had a “bah.volumes” BlitzMax module that exposed appropriate folders/directories on the various platforms – I wonder if any of that c/c++ native code would be useful for us…
Monkey 2’s file streaming capabilities have some “quirks” depending on the target platform. (eg The “rw” mode is not working for me on MacOS). You’re also limited to the file types you can “#Import”.
You can, however, create, load and save files at runtime. The location of the created files will depend on the target platform and the chosen target directory.
Here’s an example that creates, saves and loads one text and one binary file to your desktop (tested on MacOS, might encounter file permission issues on other platforms?)
[/crayon]Monkey123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177[crayon-5cba87d87a07f019010053 inline="true" ]#Import "<std>"Using std..Function Main()Local urlText := DesktopDir() + "test.csv"Local urlBinary := DesktopDir() + "test.dat"Local scores := New Scores()'****Check if our text-based csv file already exists.Local file := FileStream.Open(urlText, "r")If Not file 'If not then create it using some test data.scores.ParseCSV("Bob, 200~nAnna, 220~nMick, 18~nAi, 333")scores.SaveCSV(urlText)Elsefile.Close()Endif'****'****Check if our binary data file already exists.file = FileStream.Open(urlBinary, "r")If Not file 'If not then create it using some test data.scores.ParseCSV("Don, 0~nPeta, 499~nStu, 88~nCarl, 600")scores.SaveBinary(urlBinary)Elsefile.Close()Endif'****'Load Both files into our scores manager and print them all.scores.LoadCSV(urlText)scores.LoadBinary(urlBinary, True)scores.PrintAll()End'--------------Class ScoresPrivateField _scores:Stack<Score>PublicMethod New()_scores = New Stack<Score>EndMethod LoadCSV:Void(url:String)If Not url Then ReturnParseCSV(LoadString(url))EndMethod SaveCSV:Void(url:String)If Not url Then ReturnIf Not _scores Then ReturnLocal str:StringFor Local score := eachin _scoresstr += score.ToCSVString()EndIf Not SaveString(str, url)Print "Could not save csv file: " + urlEndifEndMethod ParseCSV:Void(csvDB:String, append:Bool = False)If Not csvDB Or csvDB.Length <= 0Print "Invalid CSV data."ReturnEndifLocal csvRecords := csvDB.Split("~n")If Not _scores Then _scores = New Stack<Score>()If Not append Then _scores.Clear()For Local i := 0 Until csvRecords.LengthLocal csvRecordFields := csvRecords[i].Split(",")If csvRecordFields.Length < 2 Then Continue 'Invalid record so skip it._scores.Push(New Score(csvRecordFields[0].Trim(), Cast<UInt>(csvRecordFields[1])))NextEndMethod LoadBinary:Void(url:String, append:Bool = False)If Not url Then ReturnLocal file := FileStream.Open(url, "r")If Not filePrint "Could not read binary file: " + urlReturnEndifIf Not _scores Then _scores = New Stack<Score>()If Not append Then _scores.Clear()Local numRecords := file.ReadInt()Local recordCounter := 0While (Not file.Eof) And (recordCounter < numRecords)_scores.Push(New Score(Cast<String>(file.ReadCString()), file.ReadUInt()))recordCounter += 1Wendfile.Close()EndMethod SaveBinary:Void(url:String)If Not url Then ReturnIf Not _scores Then ReturnLocal file := FileStream.Open(url, "w")If Not filePrint "Could not write binary file: " + urlReturnEndiffile.WriteInt(_scores.Length)For Local score := Eachin _scoresfile.WriteCString(score.Name)file.WriteUInt(score.Value)Nextfile.Close()EndMethod PrintAll:Void()For Local score:= Eachin _scoresPrint score.ToString()NextEndEnd' ----------Struct ScorePublicField Name:StringField Value:UIntMethod New(name:String, value:UInt)Name = nameValue = valueEndMethod ToString:String()Return Name + "~t~t" + ValueEndMethod ToCSVString:String()Return Name + ", " + Value + "~n"EndEndcanvas.CopyPixmap(New Recti(0, 0, canvas.Viewport.Width, canvas.Viewport.Height))
?
example: (press F10 to save capture to your desktop)
[/crayon]Monkey123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657[crayon-5cba87d881ae4615292104 inline="true" ]Namespace myapp#Import "<std>"#Import "<mojo>"Using std..Using mojo..Class MyWindow Extends WindowField _capture:PixmapField _takeSnapShot:BoolMethod New( title:String="Simple mojo app",width:Int=640,height:Int=480,flags:WindowFlags=Null )Super.New( title,width,height,flags )_takeSnapShot = FalseEndMethod OnRender( canvas:Canvas ) OverrideApp.RequestRender()canvas.DrawText( "Hello World!",Width/2,Height/2,.5,.5 )canvas.Flush()If _takeSnapShot_capture = canvas.CopyPixmap(New Recti(0, 0, canvas.Viewport.Width, canvas.Viewport.Height))Local url:String = DesktopDir() + "cap.png"_capture.Save(url)Print "Capture saved: " + url_takeSnapShot = FalseEndifEndMethod OnKeyEvent(event:KeyEvent) OverrideIf event.Type = EventType.KeyDownIf event.Key = Key.F10_takeSnapShot = TrueEndifEndifEndEndFunction Main()New AppInstanceNew MyWindowApp.Run()EndMark just beat me to it, about the ‘<=>’ operator. Anyway, here’s what I whipped up:
[/crayon]Monkey12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364[crayon-5cba87d886187744094160 inline="true" ]#Import "<std>"Using std..Function Main()Local scores := New Stack<Score>()Local PrintAllScores := Lambda:Void(heading:String)Print heading + "~n"For Local score:= Eachin scoresPrint score.ToString()NextPrint "~n~n"Endscores.Push(New Score("Joe Blogs", 11))scores.Push(New Score("Iron Man", 23))scores.Push(New Score("Jane Doe", 12))scores.Push(New Score("Dudeson", 10))PrintAllScores("Before Sort")scores.Sort(False)PrintAllScores("After Sort")EndClass ScorePrivateField _name:StringField _value:IntPublicMethod New(name:String, value:Int)Name = nameValue = valueEndProperty Name:String()Return _nameSetter (name:String)_name = nameEndProperty Value:Int()Return _valueSetter (value:Int)_value = valueEndOperator<=>:Int(cmp:Score)Return Value<=>cmp.ValueEndMethod ToString:String()Return Name + "~t~t" + ValueEndEndI think there’s a node/pathfinding demo in blitzmax!
samples/aaronkoolen/AStar/astar_demo.bmx?
EDIT: Removed possibly incorrect info.
@hezkore: I’m not sure I understand your requirements. Do you want to calculate the most efficient route through a set of given nodes?
Yes, looks great. Any plans for an iOS edition?
I’m seriously considering writing some comprehensive Mojo/MojoX docs. However, it would be a big job and distract me from my current project… Probably worth it though… We’ll see…
Here’s a “better” example, doing things “properly”, using only skins this time. Themes should be stored in a “assets/themes” folder along with the relevant skin images. Bizarrely, setting the initial “UP”/default state skin in the theme file isn’t working – I must be missing something obvious. Instead I set the required image as the icon on Button creation. I’ll update this example when/if I figure it out…
BTW: In this example use “skinColor” if you want to change the button state colors.
[/crayon]Monkey12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697[crayon-5cba87d891f2e506511360 inline="true" ]#Import "<std>"#Import "<mojo>"#Import "<mojox>"Using std..Using mojo..Using mojox..Function Main()New AppInstanceNew MyWindowApp.Run()End'------Class MyWindow Extends WindowMethod New()Super.New( "Button Demo",640,480,WindowFlags.Resizable )Local themeDir := AssetsDir() + "/themes"CreateDir(themeDir, False, False)CreateButtonPNGs(200, 40, themeDir + "/myButton")CreateButtonTheme(themeDir + "/myTheme.json")App.Theme.Load("theme::myTheme.json")Local image := Image.Load("theme::myButtonUp.png")Local button:=New PushButton("", image)'Local button:=New PushButton("")button.Layout="float"button.Gravity=New Vec2f( .5,.5 )button.Style = GetStyle("myButton")button.Clicked=Lambda()Alert( "Well done sir!" )EndClearColor = Color.LightGreyContentView=buttonEndEnd'---- Generated Content:Function CreateButtonTheme:Void(url:String)Local strJson:StringstrJson += "{~n~qextends~q:~qdefault~q,~n"strJson += "~qstyles~q:{~n"strJson += "~t~qmyButton~q:{~n"strJson += "~t~t~qskin~q:~qmyButtonUp.png~q,~n"strJson += "~t~t~qstates~q:{~n"strJson += "~t~t~t~qselected~q:{~n"strJson += "~t~t~t~t~qskin~q:~qmyButtonSelected.png~q~n~t~t~t},~n"strJson += "~t~t~t~qhover~q:{~n"strJson += "~t~t~t~t~qskin~q:~qmyButtonHover.png~q~n~t~t~t},~n"strJson += "~t~t~t~qactive~q:{~n"strJson += "~t~t~t~t~qskin~q:~qmyButtonActive.png~q~n~t~t~t}~n"strJson += "~n~t~t}~n"strJson += "~t}~n}~n}"Print strJsonSaveString(strJson, url)EndFunction CreateButtonPNGs:Void(w:Int, h:Int, urlStem:String)Local bLabs:=New String[]("Up", "Active", "Hover", "Selected")For Local n:=0 until bLabs.LengthLocal img := New Image(w, h)local canvas := New Canvas(img)canvas.Clear(New Color(Rnd(), Rnd(), Rnd(), 1.0))canvas.Color=Color.Blackcanvas.DrawText(bLabs[n], 0, 0)canvas.Flush()Local pm := canvas.CopyPixmap(New Recti(0, 0, img.Width, img.Height))pm.Save(urlStem + bLabs[n] + ".png")canvas = Nullimg = NullNextGCCollect()EndYes, someone needs to document MojoX: it’s actually a very powerful GUI library. Currently you need to poke around the module’s source files (and the TED source code) to figure it out, and that can take ages.
-
AuthorPosts