--------------------- namespace settings -- functions to read and write config files (*.ini); --------------------- export constant version = "4.12.0" --# EXPORTS /* --functions: settings:Save() settings:Load() settings:Add() -- debug: -d SETTINGS */ include GtkEngine.e if not equal(version,gtk:version) then Error(,,"GtkSettings version mismatch","should be version " & gtk:version) end if constant fmt = """[].[]=[]""" ------------------------------------------------------------------------ export function Save(sequence inifile, object ctl_list, integer debug=0) ------------------------------------------------------------------------ -- writes an 'ini' type file (file name and extension are up to you) -- with an entry for each control on ctl_list. The controls MUST have -- been named, otherwise there's no way to save and retrieve the -- value/setting for that control. ------------------------------------------------------------------------ object comments = {} object txt,line if file_exists(inifile) then txt = read_lines(inifile) for i = 1 to length(txt) do -- extract the comments; line = txt[i] if match("--",line) = 1 or match("!",line) = 1 or match("+",line) = 1 or equal("\n",line) or equal({},line) then comments = append(comments,line) end if end for write_lines(inifile,comments) -- removing everything but the comments; end if -- file exists object setting, tmp = 0, pos = {0,0} object t1, name, prop atom handle integer class atom fn = open(inifile,"a") for x = 1 to length(ctl_list) do if string(ctl_list[x]) then handle = pointer(ctl_list[x]) else handle = ctl_list[x] end if name = get(handle,"name") class = class_id(handle) if class=GtkWindow then -- special handling for multiple properties; printf(fn,"%s\n",{get_setting(handle,"size")}) pos = get(handle,"position") printf(fn,"%s.position={%d,%d}\n",{name,pos[1],pos[2]}) else setting = get_setting(handle) -- others have 1 obvious 'saveable' property if length(setting) < 1 then continue end if if sequence(setting) then printf(fn,"%s\n",{setting}) end if end if end for flush(fn) close(fn) -- if ! exists for this control:property, then ignore the updated setting; tmp = read_lines(inifile) for i = 1 to length(tmp) do if match("--!",tmp[i]) = 1 then t1 = split(tmp[i],"=") t1 = t1[1][2..$] end if end for write_lines(inifile,tmp) return 1 end function ------------------------------------------------------------------------ export function Load(sequence inifile, integer debug=0) ------------------------------------------------------------------------ -- used to restore settings from the specified ini file. -- this should be called after the controls are 'realized' object txt, line, obj, prop, val1=0, val2=0, val3=0, val4=0 if not(file_exists(inifile)) then write_file(inifile,sprintf("--%s\n\n",{inifile}),TEXT_MODE) display("Creating ini file: []",{inifile}) else if debug then display("Reading []",{inifile}) end if end if txt = read_lines(inifile) integer err=0 object a,b for i = 1 to length(txt) do line = txt[i] if match("--",line) > 2 then -- strip trailing comments; line = line[1..match("--",line)-2] end if if match("--!",line) = 1 then line = line[4..$] -- keep it end if if match("+",line) = 1 or match("!",line) then line = line[2..$] -- dito end if if match("--",line) or match(";",line) or match("/*",line) then continue -- a comment, do nothing with it end if if length(line) > 0 then line = split(line,'=') a = line[1] b = line[2] a = split(a,'.') line = a & {b} if debug > 1 then display(line) end if if vlookup(line[1],registry,4,1,-1) = -1 then err = i Error(,"Ini Load Error", sprintf("Invalid object name: %s",{line[1]}), sprintf("Line #%d of %s",{i,filename(inifile)})) else if equal("data",line[2]) then set(line[1],"data",line[3],line[4]) else set(line[1],line[2],line[3]) end if end if end if end for if debug = 1 then for i = 1 to length(txt) do if i = err then display("ERROR:[:3]:[]",{i,txt[i]}) else display("[:3]:[]",{i,txt[i]}) end if end for end if write_lines(inifile,txt) return 1 end function ------------------------------------------------------------------------------------------- export function Add(object ini,object ctl, sequence prop, object v1=0, object v2=0) ------------------------------------------------------------------------------------------- if atom(ctl) then ctl = get(ctl,"name") end if Delete(ini,ctl,prop) if equal("position",prop) or equal("size",prop) then if string(v1) then v2 = v1[2] v1 = v1[1] end if end if if atom(v2) and v2=0 then writefln("+[].[]=[]",{ctl,prop,v1},{ini,"a"}) else writefln("+[].[]={[],[]}",{ctl,prop,v1,v2},{ini,"a"}) end if return 1 end function -------------------------------------------------------------------- export function Delete(object ini,object ctl, sequence prop) -------------------------------------------------------------------- if atom(ctl) then ctl = get(ctl,"name") end if object tmp = read_lines(ini) object out = {} object s1 = text:format("[].[]",{ctl,prop}) for i = 1 to length(tmp) do if match(s1,tmp[i]) then -- skip else out &= {tmp[i]} end if end for write_lines(ini,out) return 1 end function --------------------------------------------------------------------------------- function get_setting(object self, object property = 0) -- returns the 'important' value from a control --------------------------------------------------------------------------------- -- returns settings string -- object must be a named object, e.g. MyButton -- MyButton.active=1 -- My Calendar.date={YYYY,MM,DD} object name = 0 object dt if string(self) then name = self self = vlookup(self,registry,4,1) end if object val = 0 object txt = {} integer x = find(self,vslice(registry,1)) ifdef SETTINGS then display("SELF [] []",{x,self}) display(registry[x]) end ifdef switch class_id(self) do -- this decides which value is the important one to save; -- and stores the control's current value into the registry; case GtkEntry,GtkEntryBuffer then property = "text" case GtkCheckButton,GtkRadioButton, GtkToggleButton, GtkSwitch,GtkComboBox,GtkComboBoxText, GtkCheckMenuItem,GtkToggleToolButton, GtkSearchEntry then property = "active" case GtkPopover then property = "position" case GtkFontButton then property = "font name" case GtkAdjustment,GtkSpinButton,GtkScaleButton,GtkVolumeButton, GtkModelButton,GtkScale then property = "value" case GtkEntryCompletion then property = "model" case GtkLinkButton then property = "uri" case GtkMenuItem then property = "sensitive" case GtkPaned then property = "position" case GtkFileChooser, GtkFileChooserButton, GtkFileChooserWidget, GtkFileChooserDialog then property = "filename" case GtkFontChooser, GtkFontChooserWidget, GtkFontChooserDialog then property = "font" case GtkCalendar then dt = get(self,"datetime",0) registry[x][5] = {"date",dt[1..3]} txt &= text:format(fmt,{registry[x][4],"date",dt[1..3]}) return txt case GtkColorButton,GtkColorChooser,GtkColorChooserWidget, GtkColorChooserDialog then registry[x][5] = {"rgba",get(self,"rgba",1)} txt &= text:format(fmt,{registry[x][4],"rgba",get(self,"rgba",1)}) return txt end switch if atom(property) then return txt end if val = get(self,property) registry[x][5] = {property,val} txt &= text:format(fmt,{registry[x][4],property,val}) return txt end function