feat: Infrastructure for automatic control widget creation for configuration fields

Change-Id: I87a0eb6ba5b2128c779f04c8971106b1c8fbd33f
diff --git a/dcs/config/store.py b/dcs/config/store.py
index 84801ba..7905ead 100644
--- a/dcs/config/store.py
+++ b/dcs/config/store.py
@@ -8,20 +8,41 @@
 
 import toml
 import json
-from typing import Dict, AnyStr, Callable, Type, Any, Optional
+from typing import Dict, AnyStr, Callable, Type, Any, Optional, List
 from pydantic import BaseModel, PrivateAttr
 import appdirs
 import os
 import logging
+from tkinter import ttk
+from abc import abstractmethod, ABC
 
 
-class ConfigObject(BaseModel):
+class ConfigControlFrame(ttk.Frame):
+    ctrl_widgets: List[ttk.Widget]
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.ctrl_widgets = []
+
+    def add_widget(self, w: ttk.Widget) -> None:
+        self.ctrl_widgets.append(w)
+
+    def widgets_on_change(self, cb) -> None:
+        for w in self.ctrl_widgets:
+            w.listen_change(cb)
+
+
+class ConfigObject(BaseModel, ABC):
     _KEY: AnyStr = PrivateAttr()
 
     @classmethod
     def get_key(cls) -> AnyStr:
         return cls._KEY
 
+    @abstractmethod
+    def make_config_widget(self, parent: ttk.Widget) -> ConfigControlFrame:
+        ...
+
 
 class Store:
     __instances: Dict[str, Store] = {}