User Tools

Site Tools


pcb:preferences_subsystem

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
Next revision Both sides next revision
pcb:preferences_subsystem [2020/07/26 13:58]
cparker
pcb:preferences_subsystem [2020/09/19 18:24]
cparker
Line 11: Line 11:
   * The system should be partitionable such that a subsystem may keep track of their own preferences without having to interact with the preferences of any other subsystem.   * The system should be partitionable such that a subsystem may keep track of their own preferences without having to interact with the preferences of any other subsystem.
  
-=== Implementation Overview ​=== +=== Process ​=== 
-Preferences will be stored in a file as key/value pairs. An algorithm will read the file into a dictionary type structure, and then for every key it will look up that key in a "​preferences registry"​. The preferences registry will be a list of structures that include things like the name of the preference, some help text, default value, etc. and a pointer to a function that can be used to interpret the value string associated with the key. The function does its thing, and sets the destination variable with its value.+I'm breaking ​the preferences process ​into four steps:
  
-To save preferences ​this works in just the reverseThere is also a "​writer"​ function associated with preferences in the registry, and this is called to convert ​the data back into string. We generate a series ​of key/value pairs that are then written ​to a text file.+ 1. Read the preferences ​file and create a list of key value pairs (preference items) \\ pilist = ppm_read_pref_file(fname);​ \\ This returns a list of PreferenceItem objects that contains the keys and values read out of the specified file. 
 + 2. Apply preferences ​to the PCB data structures \\ ppm_apply_preferences(pdlist,​ pilist); \\ This iterates over the PreferenceItems ​in pilist. For each item it looks up the key in a preference definition list, pdlist, and calls the function associated with that preference definition. 
 + 3. Collect preferences from PCB data structures \\ pilist = ppm_collect_preferences(pdlist);​ \\ This goes through the preferences definitions in pdlist and creates ​set of key value pairs, pilist, ​that can be stored in the text file. 
 + 4. Write the preference data to a file. \\ ppm_write_pref_file(pilist);​ \\ Store the preferences in a file.
  
-The key/value pair structures ​can be returned to the calling function to be retained for future inquiryFor example, maybe a plug-in chooses to store a preference in the main pcb preferences ​file. When pcb is initialized,​ if the plug-in isn't loaded yet, the preference will still be read and retained so that when the plug-in does load, the read value will be available to it for conversion.+One of the considerations here is separating the storage and application so that the methods ​can changeIf we decide we'd rather ​store preferences in an SQL databasewe can do that without having to rewrite ​the whole system. We only have to write functions to load and save the key values pairs in the database.
  
-A python pseudo-code might look something like this: +I'm not too worried about the speed of these routinessoit doesn'​t matter much if the lists are sortedReadingapplyingcollectingand writing preferences doesn'​t happen very often.
-<code python>​ +
-def load_preferences(filenameregistry):​ +
-  file_data = read_pref_file(filename) +
-  for keyvalue in file_data:​ +
-    ​if key in registry: +
-      registry[key].reader(keyvalueregistry[key].ptr) +
-       +
-  return file_data +
-   +
-def save_preferences(filenameregistry):​ +
-  file_data = [] +
-  for key in registry: +
-    file_data.append([key,​ registry[key].writer(key,​ registry[key].ptr)]) +
-     +
-  write_pref_file(file_data) +
-  return len(file_data) +
-</​code>​ +
-(why is it always so much easier in python?)+
  
 === Data Structures === === Data Structures ===
-We're going to draw heavily on the work that's already been done with the preferences (HIDAttributes) in designing the data structures for this system. ​The first data structure is what's populated when a preference ​file is read:+We're going to draw heavily on the work that's already been done with the preferences (HIDAttributes) in designing the data structures for this system. ​ 
 + 
 +==PreferenceItem== 
 +preference ​item contains two strings, the key and the value that are read and stored to the file. 
  
 <code c> <code c>
Line 48: Line 36:
   /*! value */   /*! value */
   char * value;   char * value;
-PreferenceFileItem;+PreferenceItem;
 </​code>​ </​code>​
  
Line 55: Line 43:
 <code c> <code c>
 /*!  /*! 
- * \brief ​PreferenceItem ​data structure+ * \brief ​PreferenceDefinition ​data structure
  */  */
 typedef struct typedef struct
Line 73: Line 61:
   /*! a string that can be used to initialize the preference */   /*! a string that can be used to initialize the preference */
   char * default_str;​   char * default_str;​
-PreferenceItem;+PreferenceDefinition;
 </​code>​ </​code>​
  
-There will be a number of "​reader"/"​writer"​ functions implemented by default to handle common data types like floats, ints, coords, etc. The data pointer will be passed to the reader and writer functions, and could contain anything. But it probably is a pointer to the variable to be set by the converted value from the PreferenceFileItem. Using function pointers like this allows for a lot of flexibility in how subsystems can use this code. The reader functions, for example, may also be responsible for notifying a GUI that the preference has been updated.+There will be a number of "​reader"/"​writer"​ functions implemented by default to handle common data types like floats, ints, coords, etc. The data pointer will be passed to the reader and writer functions, and could contain anything. But it probably is a pointer to the variable to be set by the converted value from the PreferenceItem. Using function pointers like this allows for a lot of flexibility in how subsystems can use this code. The reader functions, for example, may also be responsible for notifying a GUI that the preference has been updated.
  
 Note: the default_str should initialize the value to something that is SAFE, i.e. something that will never, ever cause PCB to crash. Note: the default_str should initialize the value to something that is SAFE, i.e. something that will never, ever cause PCB to crash.
 +
 +=== Implementation Overview ===
 +Preferences will be stored in a file as key/value pairs. An algorithm will read the file into a dictionary type structure, and then for every key it will look up that key in a "​preferences registry"​. The preferences registry will be a list of structures that include things like the name of the preference, some help text, default value, etc. and a pointer to a function that can be used to interpret the value string associated with the key. The function does its thing, and sets the destination variable with its value.
 +
 +To save preferences this works in just the reverse. There is also a "​writer"​ function associated with preferences in the registry, and this is called to convert the data back into a string. We generate a series of key/value pairs that are then written to a text file.
 +
 +The key/value pair structures can be returned to the calling function to be retained for future inquiry. For example, maybe a plug-in chooses to store a preference in the main pcb preferences file. When pcb is initialized,​ if the plug-in isn't loaded yet, the preference will still be read and retained so that when the plug-in does load, the read value will be available to it for conversion.
 +
 +A python pseudo-code might look something like this:
 +<code python>
 +def load_preferences(filename,​ registry):
 +  file_data = read_pref_file(filename)
 +  for key, value in file_data:
 +    if key in registry:
 +      registry[key].reader(key,​ value, registry[key].ptr)
 +      ​
 +  return file_data
 +  ​
 +def save_preferences(filename,​ registry):
 +  file_data = []
 +  for key in registry:
 +    file_data.append([key,​ registry[key].writer(key,​ registry[key].ptr)])
 +    ​
 +  write_pref_file(file_data)
 +  return len(file_data)
 +</​code>​
 +(why is it always so much easier in python?)
 +
  
 === Functions === === Functions ===
Line 160: Line 176:
 | drc-linewidth-min | 8 mil | | drc-linewidth-min | 8 mil |
  
-Thoughts on processing:+=== Thoughts on processing ​===
  
 I’ve also considered if there should be some type of hierarchical structure. Like for example, subsystems could register prefixes like “gtk-” with the system, and then the system passes them the preferences with that prefix. With the function calling system, I don’t think this is necessary. Although it is a good idea for subsystems to use such a prefix to make editing the files easier. I’ve also considered if there should be some type of hierarchical structure. Like for example, subsystems could register prefixes like “gtk-” with the system, and then the system passes them the preferences with that prefix. With the function calling system, I don’t think this is necessary. Although it is a good idea for subsystems to use such a prefix to make editing the files easier.
  
-Thoughts on implementation:+=== Thoughts on implementation ​===
  
 The pointer is probably often going to be the item that should be populated with the preference value, but doesn’t have to be. It could be the general preferences structure, for example, if there’s more than one parameter that needs to be updated. The pointer is probably often going to be the item that should be populated with the preference value, but doesn’t have to be. It could be the general preferences structure, for example, if there’s more than one parameter that needs to be updated.
Line 217: Line 233:
 </​code>​ </​code>​
  
-Questions: +=== Questions ​=== 
-If a user loads a new preferences file, does it need to notify anything that this happened? + If a user loads a new preferences file, does it need to notify anything that this happened? ​\\ Presently, with preferences,​ values are updated immediately. This means that all preferences need to be such that changing them at any given moment doesn’t lead to disaster. However, this model also provides the flexibility that, if there isn’t such a preference, it can specify its own handler function which could take care of any of the necessary tasks to enact the change. 
-Presently, with preferences,​ values are updated immediately. This means that all preferences need to be such that changing them at any given moment doesn’t lead to disaster. However, this model also provides the flexibility that, if there isn’t such a preference, it can specify its own handler function which could take care of any of the necessary tasks to enact the change.+ * Should I try to use the glib class structure and create an actual manager object 
 + * When collecting preferences,​ do we collect everything, or only things that aren't the same as the default?
  
pcb/preferences_subsystem.txt · Last modified: 2021/02/28 19:56 by cparker