Skip to content

Commit

Permalink
options as a module-level singleton
Browse files Browse the repository at this point in the history
This is more convenient when used in different modules, as we don't have to
find hacky ways to pass a reference to the instance held by main, we just
import the module and voila.
Of course, the module instance has to be initialized first, but
1) this shouldn't be an issue as Main will do that among the first things,
2) get & var calls are guarded against uninitialized access, just in case.
  • Loading branch information
Noiredd committed May 23, 2020
1 parent e2ba9f2 commit 09e12b5
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 8 deletions.
8 changes: 4 additions & 4 deletions filmatyk/gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,8 @@ def __init__(self, debugMode=False, isOnLinux=False):
# load the savefile
self.dataManager = DataManager(self.getFilename(), VERSION)
userdata = self.dataManager.load()
# create the options manager
self.options = Options(userdata.options_json)
# initialize the options manager
Options.init(userdata.options_json)
# construct the window: first the notebook for tabbed view
self.notebook = ttk.Notebook(root)
self.notebook.grid(row=0, column=0, padx=5, pady=5, sticky=tk.NW)
Expand Down Expand Up @@ -256,7 +256,7 @@ def saveUserData(self):
if not (
any([db.isDirty for db in self.databases]) or
any([ps.isDirty for ps in self.presenters]) or
self.options.isDirty
Options.isDirty
):
return
# construct the UserData object
Expand All @@ -268,7 +268,7 @@ def saveUserData(self):
series_data=self.databases[1].storeToString(),
games_conf=self.presenters[2].storeToString(),
games_data=self.databases[2].storeToString(),
options_json=self.options.storeToString(),
options_json=Options.storeToString(),
)
# request the manager to save it
self.dataManager.save(serialized_data)
Expand Down
38 changes: 34 additions & 4 deletions filmatyk/options.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,55 @@
"""Options is a globally accessible class holding all program options.
The only exported object is a singleton instance of the Options class. Usage:
from options import Options
The instance has to be initialized (by passing a JSON string with serialized
initial values) or at least confirmed on assuming default values:
Options.init(json_string)
After that - and ONLY after that - it can be used in two ways.
Access to an option value:
Options.get('option_name')
Direct access to the underlying TkVar:
Options.var('option_name')
This gives a convenient access to options from wherever in the program,
assuming the actual call to get or var happens AFTER the initialization of the
instance.
"""

import json
import os

import tkinter as tk
from tkinter import ttk


class Options():
class _Options():
"""Stores program options as named Tk variables, allowing easy serialization.
Options wraps around a simple dict of Tk vars, which enables the following:
* easy access to option values (using get),
* simple binding of option variables to Tk widgets (using variable),
* simple binding of option variables to Tk widgets (using var),
* serialization and deserialization to JSON (using storeToString).
Defining a new option is done simply by adding it to the prototypes list.
"""
option_prototypes = [
]

def __init__(self, json_string:str='{}'):
def __init__(self):
self.variables = {}
self.isDirty = False
self.isInit = False

def init(self, json_string:str='{}'):
"""Restore the JSON-serialized values."""
saved_values = json.loads(json_string)
for name, vtype, default in self.option_prototypes:
variable = vtype()
value = saved_values[name] if name in saved_values.keys() else default
variable.set(value)
variable.trace('w', self.__touched_callback)
self.variables[name] = variable
self.isInit = True

def storeToString(self):
"""Serialize the options to a JSON string."""
Expand All @@ -36,12 +59,19 @@ def storeToString(self):

def get(self, name):
"""Get the value of a named option."""
if not self.isInit:
raise AttributeError
return self.variables[name].get()

def variable(self, name):
def var(self, name):
"""Get Tk variable object of a named option."""
if not self.isInit:
raise AttributeError
return self.variables[name]

def __touched_callback(self, *args):
"""Set the dirty flag whenever an option changes."""
self.isDirty = True


Options = _Options()

0 comments on commit 09e12b5

Please sign in to comment.