About Monkey 2 › Forums › Monkey 2 Code Library › Preferences class
Tagged: preferences
This topic contains 11 replies, has 3 voices, and was last updated by
therevills 1 year, 3 months ago.
-
AuthorPosts
-
November 30, 2017 at 8:22 am #12028
This class allow us to store params inside of single class-container with load/save stuff.
Class is based on Json format. You can extend it by adding new methods like GetFloat() if needed.
You put any supported values using PutValue and get values using GetXxx methods like GetString, GetColor…
Monkey123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151Namespace jentos.prefsClass Preferences Final' globals'Function Get:Preferences( path:String )If _prefs.Contains( path ) Return _prefs[path]Local p:=New Preferences( path )_prefs[path]=pReturn pEndFunction SaveAll()For Local p:=Eachin _prefs.Valuesp.Save()NextEnd' signals'Field Changed:Void( key:String,value:Variant )' setters'Method PutValue( key:String,value:String )_data[key]=New JsonString( value )_dirty=TrueChanged( key,value )EndMethod PutValue( key:String,value:Bool )_data[key]=New JsonBool( value )_dirty=TrueChanged( key,value )EndMethod PutValue( key:String,value:Double )_data[key]=New JsonNumber( value )_dirty=TrueChanged( key,value )EndMethod PutValue( key:String,value:JsonValue )_data[key]=value_dirty=TrueChanged( key,value )EndMethod PutValue( key:String,value:Color )_data[key]=value.ToJson()_dirty=TrueChanged( key,value )End' getters'Method GetString:String( key:String,defValue:String="" )Return _data.GetString( key,defValue )EndMethod GetBool:Bool( key:String,defValue:Bool=False )Return _data.GetBool( key,defValue )EndMethod GetNumber:Double( key:String,defValue:Double=0 )Return _data.GetNumber( key,defValue )EndMethod GetJson:JsonValue( key:String,defValue:JsonValue=Null )Return _data.GetJson( key,defValue )EndMethod GetColor:Color( key:String,defValue:Color=Color.Magenta )If _data.Contains( key )Return Color.FromJson( _data[key] )EndifReturn defValueEnd' load'Method Load( path:String )_path=path_data=JsonObject.Load( path ) ?Else New JsonObject_dirty=FalseEnd' save'Method Save( path:String="" )If Not _dirty ReturnIf Not path Then path=_pathIf Not path ReturnSaveString( _data.ToJson(),path )_dirty=FalseEnd' raw data'Property Json:JsonObject()Return _dataEndMethod Contains:Bool( key:String )Return _data.Contains( key )EndPrivateField _data:JsonObjectField _path:StringField _dirty:BoolGlobal _prefs:=New StringMap<Preferences>' private constructors'Method New( path:String )Load( path )EndMethod New()EndEndHow do I use it:
Monkey1234567891011121314151617181920212223242526272829303132333435363738394041424344#Import "<std>"#Import "<mojo>"#Import "<mojox>"Using std..Using mojo..Using mojox..' imports'#Import "MyWindow"#Import "Preferences"#Import "assets/"' try to load prefs from fileConst Prefs:=Preferences.Get( AppDir()+"prefs.json" )Function Main()New AppInstance()' try to get windowRect from prefsLocal rect:RectiLocal flags:=WindowFlags.ResizableIf Prefs.Contains( "windowRect" )rect=ToRecti( Prefs.GetJson( "windowRect" ) )Else' not found in prefs, set to defaultsrect=New Recti( 0,0,900,800 )flags|=WindowFlags.CenterEndifLocal wnd:=New MainWindow( "Prefs test",rect,flags )wnd.CloseRequested+=Lambda()Prefs.PutValue( "windowRect",ToJson( wnd.Frame ) )Preferences.SaveAll()EndApp.Run()Endwnd.CloseRequested is my own signal:
Monkey123456789101112131415161718Class MainWindow Extends WindowField CloseRequested:Void()........ProtectedMethod OnWindowEvent( event:WindowEvent ) OverrideIf event.Type=EventType.WindowCloseCloseRequested()EndifSuper.OnWindowEvent( event )EndEndNovember 30, 2017 at 8:26 am #12030Also there is Changed( key,value ) signal which helps us to be notified about values changes.
Note: you should to cast value to concrete type from its Variant type.
November 30, 2017 at 8:30 am #12031I forgot one thing.
There is Color extension class to be able to convert colors from/to Json format:
Monkey123456789101112131415161718192021222324252627282930313233343536373839404142434445464748Struct Color ExtensionFunction FromHex:Color( hex:String )Local str:=hexLocal a:=1.0,r:=0.0,g:=0.0,b:=0.0If str.Length=4 '#RGBr=StringToULong( str.Slice( 1,2 ),16 )/15.0g=StringToULong( str.Slice( 2,3 ),16 )/15.0b=StringToULong( str.Slice( 3,4 ),16 )/15.0Else If str.Length=5 '#ARGBa=StringToULong( str.Slice( 1,2 ),16 )/15.0r=StringToULong( str.Slice( 2,3 ),16 )/15.0g=StringToULong( str.Slice( 3,4 ),16 )/15.0b=StringToULong( str.Slice( 4,5 ),16 )/15.0Else If str.Length=7 '#RRGGBBr=StringToULong( str.Slice( 1,3 ),16 )/255.0g=StringToULong( str.Slice( 3,5 ),16 )/255.0b=StringToULong( str.Slice( 5,7 ),16 )/255.0Else If str.Length=9 '#AARRGGBBa=StringToULong( str.Slice( 1,3 ),16 )/255.0r=StringToULong( str.Slice( 3,5 ),16 )/255.0g=StringToULong( str.Slice( 5,7 ),16 )/255.0b=StringToULong( str.Slice( 7,9 ),16 )/255.0ElseReturn Color.MagentaEndifReturn New Color( r,g,b,a )EndMethod ToJson:JsonValue()Return New JsonArray( New JsonValue[]( New JsonNumber( r ),New JsonNumber( g ),New JsonNumber( b ),New JsonNumber( a ) ) )EndFunction FromJson:Color( json:JsonValue )If json.IsArrayLocal arr:=json.ToArray()Return New Color( arr[0].ToNumber(),arr[1].ToNumber(),arr[2].ToNumber(),arr[3].ToNumber() )ElseReturn FromHex( json.ToString() )EndifEndEndNovember 30, 2017 at 8:36 am #12032Cool!
I dont know if its in MX2 yet, but for Windows we need a way to save to the “correct” Microsoft approved folder locations.
December 4, 2017 at 7:12 am #12099Very useful, thanks!
I’m thinking a good place to store the file would be in SDL_GetPrefPath() (is in MX2 now) like in
What do you think?
December 4, 2017 at 7:47 am #12100I still hope that the best way is to use pure monkey2’s path..
But I didn’t use mobile targets yet.
You can write own Function GetPrefsFile:String( file:String,author:String="defValue",name:String="defValue" ) that will use sdl prefs or what you want else, and you can change single place if needed to make changes for a whole project.
And to link with my code:
Const AppPrefs:=Preferences.Get( GetPrefsFile( "app.json" ) )
January 5, 2018 at 8:03 am #12665Note: The code from nerobot, needs the extensions from this post: http://monkeycoder.co.nz/forums/topic/json-extensions/
I’m also getting run time error: “Attempt to invoke method on null instance” on the “If _prefs.Contains( path ) Return _prefs[path]” line…
Test code, I had to “hack” some of the features to crappy returns etc:
Monkey123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326#Import "<std>"#Import "<mojo>"#Import "<mojox>"Using std..Using mojo..Using mojox..' imports'#Import "assets/"' try to load prefs from fileConst Prefs:=Preferences.Get( AppDir()+"prefs.json" )Function Main()New AppInstance()' try to get windowRect from prefsLocal rect:RectiLocal flags:=WindowFlags.ResizableIf Prefs.Contains( "windowRect" )rect=ToRecti( Prefs.GetJson( "windowRect" ) )Else' not found in prefs, set to defaultsrect=New Recti( 0,0,900,800 )flags|=WindowFlags.CenterEndifLocal wnd:=New MainWindow() ' "Prefs test",rect,flags ) ' <----- Main Window CTOR doesnt have paramswnd.CloseRequested+=Lambda()Prefs.PutValue( "windowRect",ToJson( wnd.Frame ) )Preferences.SaveAll()EndApp.Run()EndClass MainWindow Extends WindowField CloseRequested:Void()ProtectedMethod OnWindowEvent( event:WindowEvent ) OverrideIf event.Type=EventType.WindowCloseCloseRequested()EndifSuper.OnWindowEvent( event )EndEndClass Preferences Final' globals'Function Get:Preferences( path:String )If _prefs.Contains( path ) Return _prefs[path]Local p:=New Preferences( path )_prefs[path]=pReturn pEndFunction SaveAll()For Local p:=Eachin _prefs.Valuesp.Save()NextEnd' signals'Field Changed:Void( key:String,value:Variant )' setters'Method PutValue( key:String,value:String )_data[key]=New JsonString( value )_dirty=TrueChanged( key,value )EndMethod PutValue( key:String,value:Bool )_data[key]=New JsonBool( value )_dirty=TrueChanged( key,value )EndMethod PutValue( key:String,value:Double )_data[key]=New JsonNumber( value )_dirty=TrueChanged( key,value )EndMethod PutValue( key:String,value:JsonValue )_data[key]=value_dirty=TrueChanged( key,value )EndMethod PutValue( key:String,value:Color )_data[key]=value.ToJson()_dirty=TrueChanged( key,value )End' getters'Method GetString:String( key:String,defValue:String="" )Return _data.GetString( key,defValue )EndMethod GetBool:Bool( key:String,defValue:Bool=False )Return _data.GetBool( key,defValue )EndMethod GetNumber:Double( key:String,defValue:Double=0 )Return _data.GetNumber( key,defValue )EndMethod GetJson:JsonValue( key:String,defValue:JsonValue=Null )Return _data.GetJson( key,defValue )EndMethod GetColor:Color( key:String,defValue:Color=Color.Magenta )If _data.Contains( key )Return Color.FromJson( _data[key] )EndifReturn defValueEnd' load'Method Load( path:String )_path=path_data=JsonObject.Load( path ) ?Else New JsonObject_dirty=FalseEnd' save'Method Save( path:String="" )If Not _dirty ReturnIf Not path Then path=_pathIf Not path ReturnSaveString( _data.ToJson(),path )_dirty=FalseEnd' raw data'Property Json:JsonObject()Return _dataEndMethod Contains:Bool( key:String )Return _data.Contains( key )EndPrivateField _data:JsonObjectField _path:StringField _dirty:BoolGlobal _prefs:=New StringMap<Preferences>' private constructors'Method New( path:String )Load( path )EndMethod New()EndEndStruct Color ExtensionFunction FromHex:Color( hex:String )Local str:=hexLocal a:=1.0,r:=0.0,g:=0.0,b:=0.0If str.Length=4 '#RGBr=StringToULong( str.Slice( 1,2 ),16 )/15.0g=StringToULong( str.Slice( 2,3 ),16 )/15.0b=StringToULong( str.Slice( 3,4 ),16 )/15.0Else If str.Length=5 '#ARGBa=StringToULong( str.Slice( 1,2 ),16 )/15.0r=StringToULong( str.Slice( 2,3 ),16 )/15.0g=StringToULong( str.Slice( 3,4 ),16 )/15.0b=StringToULong( str.Slice( 4,5 ),16 )/15.0Else If str.Length=7 '#RRGGBBr=StringToULong( str.Slice( 1,3 ),16 )/255.0g=StringToULong( str.Slice( 3,5 ),16 )/255.0b=StringToULong( str.Slice( 5,7 ),16 )/255.0Else If str.Length=9 '#AARRGGBBa=StringToULong( str.Slice( 1,3 ),16 )/255.0r=StringToULong( str.Slice( 3,5 ),16 )/255.0g=StringToULong( str.Slice( 5,7 ),16 )/255.0b=StringToULong( str.Slice( 7,9 ),16 )/255.0ElseReturn Color.MagentaEndifReturn New Color( r,g,b,a )EndMethod ToJson:JsonValue()Return New JsonArray( New JsonValue[]( New JsonNumber( r ),New JsonNumber( g ),New JsonNumber( b ),New JsonNumber( a ) ) )EndFunction FromJson:Color( json:JsonValue )If json.IsArrayLocal arr:=json.ToArray()Return New Color( arr[0].ToNumber(),arr[1].ToNumber(),arr[2].ToNumber(),arr[3].ToNumber() )ElseReturn FromHex( json.ToString() )EndifEndEndClass JsonObject ExtensionMethod GetJson:JsonValue( key:String,defValue:Bool )Local json:=SelfReturn New JsonValue ' <------- crap Return value FIXMEEndMethod GetBool:Bool( key:String,defValue:Bool )Local json:=SelfReturn json.Contains( key ) ? json[key].ToBool() Else defValueEndMethod GetString:String( key:String,defValue:String )Local json:=SelfReturn json.Contains( key ) ? json[key].ToString() Else defValueEndMethod GetInt:Int( key:String,defValue:Int )Local json:=SelfReturn json.Contains( key ) ? Int(json[key].ToNumber()) Else defValueEndMethod GetNumber:Double( key:String,defValue:Int )Local json:=SelfReturn json.Contains( key ) ? Int(json[key].ToNumber()) Else defValueEndMethod FindValue:JsonValue( key:String )key=key.Replace( "\","/" )Local keys:=key.Split( "/" )Local json:=Self.DataLocal jval:JsonValueFor Local k:=0 Until keys.LengthIf Not json.Contains( keys[k] ) Return Nulljval=json[ keys[k] ]If k=keys.Length-1 ExitIf Not jval.IsObject Return Nulljson=jval.ToObject()NextReturn jvalEndEndClass JsonArray ExtensionFunction FromStrings:JsonArray( values:String[] )Local jvals:=New JsonValue[values.Length]For Local i:=0 Until values.Lengthjvals[i]=New JsonString( values[i] )NextReturn New JsonArray( jvals )EndEndJanuary 6, 2018 at 12:58 am #12681Here is a slightly fixed simpler runnable example:
Monkey123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215#Import "<std>"Using std..Const Prefs := New Preferences().Get(AppDir() + "prefs.json")Function Main()Print "Start"' try to get windowRect from prefsLocal x:IntPrefs.Get( AppDir()+"prefs.json" )If Prefs.Contains( "x" )Print "Prefs contains x"x= Prefs.GetInt("x")Print xElse' not found in prefs, set to defaultsPrint "Prefs does not contains x"x = Rnd(0, 100)Print xEndPrefs.PutValue("x", x)Preferences.SaveAll()Print "Finished"EndClass Preferences Final' globals'Function Get:Preferences( path:String )If _prefs.Contains( path ) Return _prefs[path]Local p:=New Preferences( path )_prefs[path]=pReturn pEndFunction SaveAll()For Local p:=Eachin _prefs.Valuesp.Save()NextEnd' signals'Field Changed:Void( key:String,value:Variant )' setters'Method PutValue( key:String,value:String )_data[key]=New JsonString( value )_dirty=TrueChanged( key,value )EndMethod PutValue( key:String,value:Bool )_data[key]=New JsonBool( value )_dirty=TrueChanged( key,value )EndMethod PutValue( key:String,value:Double )_data[key]=New JsonNumber( value )_dirty=TrueChanged( key,value )EndMethod PutValue( key:String,value:Int)_data[key]=New JsonNumber( value )_dirty=TrueChanged( key,value )EndMethod PutValue( key:String,value:JsonValue )_data[key]=value_dirty=TrueChanged( key,value )End' getters'Method GetString:String( key:String,defValue:String="" )Return _data.GetString( key,defValue )EndMethod GetBool:Bool( key:String,defValue:Bool=False )Return _data.GetBool( key,defValue )EndMethod GetInt:Double( key:String,defValue:Int=0 )Return _data.GetInt( key,defValue )EndMethod GetNumber:Double( key:String,defValue:Double=0 )Return _data.GetNumber( key,defValue )End' load'Method Load( path:String )_path=path_data=JsonObject.Load( path ) ?Else New JsonObject_dirty=FalseEnd' save'Method Save( path:String="" )If Not _dirty ReturnIf Not path Then path=_pathIf Not path ReturnSaveString( _data.ToJson(),path )_dirty=FalseEnd' raw data'Property Json:JsonObject()Return _dataEndMethod Contains:Bool( key:String )Return _data.Contains( key )EndPrivateField _data:JsonObjectField _path:StringField _dirty:BoolGlobal _prefs:=New StringMap<Preferences>' private constructors'Method New( path:String )Load( path )EndMethod New()EndEndClass JsonObject ExtensionMethod GetBool:Bool( key:String,defValue:Bool )Local json:=SelfReturn json.Contains( key ) ? json[key].ToBool() Else defValueEndMethod GetString:String( key:String,defValue:String )Local json:=SelfReturn json.Contains( key ) ? json[key].ToString() Else defValueEndMethod GetInt:Int( key:String,defValue:Int )Local json:=SelfReturn json.Contains( key ) ? Int(json[key].ToNumber()) Else defValueEndMethod GetNumber:Double( key:String,defValue:Int )Local json:=SelfReturn json.Contains( key ) ? Int(json[key].ToNumber()) Else defValueEndMethod FindValue:JsonValue( key:String )key=key.Replace( "\","/" )Local keys:=key.Split( "/" )Local json:=Self.DataLocal jval:JsonValueFor Local k:=0 Until keys.LengthIf Not json.Contains( keys[k] ) Return Nulljval=json[ keys[k] ]If k=keys.Length-1 ExitIf Not jval.IsObject Return Nulljson=jval.ToObject()NextReturn jvalEndEndClass JsonArray ExtensionFunction FromStrings:JsonArray( values:String[] )Local jvals:=New JsonValue[values.Length]For Local i:=0 Until values.Lengthjvals[i]=New JsonString( values[i] )NextReturn New JsonArray( jvals )EndEndJanuary 6, 2018 at 2:34 am #12685Thanks for concatenating all related parts here!
Note: “New Preferences().Get(…” – you needn’t to use New here because Get is a function not a method and it can be accessed by class name not an instance.
Syntax in my first post is correct.
January 6, 2018 at 2:47 am #12686That’s what I thought, but without the new you get “Attempt to invoke method on null instance” error…
January 6, 2018 at 2:50 am #12687Did you check line with error by debugger?
January 6, 2018 at 2:56 am #12688I’m also getting run time error: “Attempt to invoke method on null instance” on the “If _prefs.Contains( path ) Return _prefs[path]” line…
-
AuthorPosts
You must be logged in to reply to this topic.