2 @package libtextworker.interface.manager
15 from ..
import THEMES_DIR
16 from ..general
import logger, CraftItems
17 from ..get_config
import ConfigurationError, GetConfig
18 from ..interface
import stock_ui_configs, colors
22 except ImportError
as e:
23 logger.exception(e.msg)
26 AUTOCOLOR = bool(darkdetect.theme())
28 def hextorgb(value: str):
29 value = value.lstrip(
"#")
31 return tuple(int(value[i : i + lv // 3], 16)
for i
in range(0, lv, lv // 3))
35 A class that automatically syncs your UI to match system settings.
38 * The original ColorManager.autocolor_run, which just makes a thread running ColorManager.configure, does not work.
39 * Easy to use, quick setup. No need to derive this class!
40 * I've looked for solutions from older builds of texteditor/textworker, found that v1.4
41 uses a custom class. So I made this:)
44 * The target function that will be used must accept at least arguments, with the first one
45 (excluding the self parameter if any) is for the widget, the second one is for the color.
46 * Nothing more (for now)
48 Don't get this class wrong: This only makes a thread that uses your custom function.
52 Func: typing.Callable | type
54 def __init__(this, Target: object, Func: typing.Callable | type):
60 from inspect
import signature
62 assert len(sig.parameters) > 0
67 this.thread = threading.Thread(target=darkdetect.listener,
68 args=(this.configure,), daemon=
True)
71 def configure(this, color: str):
73 return this.Func(this.Target, color)
78 A color manager for GUI widgets.
79 ColorManager can be used for multiple GUI widgets with only one call
82 setcolorfn: dict[object | type, list] = {}
83 setfontfn: dict[object | type, list] = {}
84 setfcfn: dict[object | type, list] = {}
86 _threads: dict[object, threading.Thread] = {}
88 def __init__(self, default_configs: dict[str, typing.Any] = stock_ui_configs,
89 customfilepath: str = CraftItems(THEMES_DIR,
"default.ini")):
91 Constructor of the class.
92 @param default_configs (dict[str]): Defaults to dev-premade configs
93 @param customfilepath (str): Custom file path. Disabled by default.
95 if customfilepath !=
"":
96 self.
_file_file = os.path.normpath(customfilepath)
98 self.
_file_file = CraftItems(THEMES_DIR,
"default.ini")
100 GetConfig.__init__(self, default_configs, self.
_file_file)
102 if os.path.exists(
"mergelist.json"):
103 self.
movemove(json.loads(open(
"mergelist.json",
"r").read()))
105 def reset(self, restore: bool =
False):
107 Reset the configuration file.
108 This is blocked as it can make conflicts with other instances of the class - unless you shutdown the app immediately..
110 raise NotImplementedError(
"reset() is blocked on ColorManager."
111 "Please use get_config.GetConfig class instead.")
114 def GetFont(self) -> typing.Any | tuple[str, int, str, str, str]:
116 Call the font definitions.
117 When called, this returns the following:
118 (font) size (int), style, weight, family
119 The output will vary on different GUI toolkits:
120 * wxPython: wx.Font object
121 * Tkinter: tkinter.font.Font object
124 if not self.has_section(
"font"):
125 return 10,
"system",
"system",
""
127 family = self.
getkeygetkey(
"font",
"family",
False,
True)
128 size = self.
getkeygetkey(
"font",
"size",
False,
True)
129 weight = self.
getkeygetkey(
"font",
"weight",
False,
True)
130 style = self.
getkeygetkey(
"font",
"style",
False,
True)
132 if family ==
"default":
143 raise ValueError(
"Font size must be higher than 0")
145 return size_, style, weight, family
147 def GetColor(self, color: str |
None =
None) -> tuple[str, str]:
149 Get the current foreground/background defined in the settings.
150 @since 0.1.4: Made to be a non-@property item
151 @param color (str | None = None): Defaults to darkdetect's output/current setting.
152 @return tuple[str, str]: Background - Foreground colors
156 if AUTOCOLOR: currmode = darkdetect.theme().lower()
157 else: currmode = str(self.
getkeygetkey(
"color",
"background",
True,
True)).lower()
162 if not currmode
in [
"dark",
"light"]:
167 test_back = self.
getkeygetkey(
"color",
"background-%s" % currmode, noraiseexp=
True)
168 test_fore = self.
getkeygetkey(
"color",
"foreground-%s" % currmode, noraiseexp=
True)
171 back_ = test_back
if test_back
else colors[currmode]
173 fore_ = self.
getkeygetkey(
"color",
"foreground", make=
True)
174 if fore_ ==
"default":
175 fore_ = colors[{
"light":
"dark",
"dark":
"light"}.get(currmode)]
180 elif fore_.startswith(
"#"):
183 elif fore_
in colors:
184 fore_ = colors[fore_]
186 elif test_fore
in colors:
187 fore_ = colors[test_fore]
193 except KeyError
or ConfigurationError:
196 def setcolorfunc(self, obj: type | object, func: typing.Callable | str, params: dict | tuple |
None =
None):
198 Set GUI widget background color-set function.
199 @param obj (type | object): Object (variable or type reference)
200 @param func (callable | str): Target function (no arg)
201 @param params (tuple | dict): Parameters to pass to func
203 Function paramers must have %(color) in order to
204 pass color value. Use %(color-rgb) if you want RGB value.
206 if not obj
in self.setcolorfn: self.setcolorfn[obj] = []
207 self.setcolorfn[obj].append({
"fn": func,
"params": params})
209 def setfontcfunc(self, obj: type | object, func: typing.Callable, params: dict | tuple |
None =
None):
211 Set GUI widget font color-set function.
212 @param obj (type | object): Object (variable or type reference)
213 @param func (callable | str): Function to set the font style (no arg)
214 @param params (tuple | dict): Parameters to pass to func
216 Function paramers must have %(font) in order to
217 pass color value. Use %(font-rgb) if you want RGB value.
219 if not obj
in self.setfontfn: self.setfontfn[obj] = []
220 self.setfontfn[obj].append({
"fn": func,
"params": params})
222 def setfontandcolorfunc(self, obj: type | object, func: typing.Callable | str, params: dict | tuple |
None =
None):
224 Add a function that sets both the background and font color.
225 @param obj (type | object): Object (variable or type reference)
226 @param func (typing.Callable | str): Function to use (Reference)
227 @param params (typle | dict): Function parameters
228 @since 0.1.4: First appearance
230 if not obj
in self.setfcfn: self.setfcfn[obj] = []
231 self.setfcfn[obj].append({
"fn": func,
"params": params})
233 def configure(self, widget: object, color: str |
None =
None):
235 Style a widget (only fore+back) with pre-defined settings.
236 This is usable for (almost) all GUI toolkits.
238 @param widget : Widget to configure
239 @param color: Color to use (optional)
245 logger.debug(f
"Widget {widget} died, skip configuring.")
246 self._threads.pop(widget,
None)
249 color, fontcolor = self.
GetColorGetColor(color)
251 def runfn(func: typing.Callable, args: dict|tuple):
257 def replacetext(target: str):
258 for key
in extra_aliases:
259 target = target.replace(key, extra_aliases[key])
262 if isinstance(args, dict):
264 if isinstance(args[key], str):
265 args[key] = replacetext(args[key])
268 elif isinstance(args, tuple):
272 if isinstance(arg, str):
273 arg = replacetext(arg)
277 def runloop(attr: typing.Literal[
"color",
"font",
"fc"]):
279 for item
in getattr(self, f
"set{attr}fn"):
280 if isinstance(item, type):
281 if not isinstance(widget, item):
continue
282 elif item != widget:
continue
284 dictionary = getattr(self, f
"set{attr}fn")[item]
286 for i
in range(len(dictionary)):
287 fn = getattr(self, f
"set{attr}fn")[item][i][
"fn"]
288 if isinstance(fn, str): fn = getattr(widget, fn)
290 runfn(fn, dictionary[i][
"params"])
296 def autocolor_run(self, widget: typing.Any):
297 autocolor = self.
getkeygetkey(
"color",
"auto")
298 if (
not AUTOCOLOR)
or (autocolor
in self.no_values):
299 logger.warning(
"ColorManager.autocolor_run() called when auto-color system is not usable."
300 "Detailed: auto coloring has been turned of or doesn't have required dependency (darkdetect).")
typing.Any|None getkey(this, str section, str option, bool needed=False, bool make=False, bool noraiseexp=False, bool raw=False)
def move(this, dict[str, dict[str, str]] list_)
def configure(self, object widget, str|None color=None)
def setfontcfunc(self, type|object obj, typing.Callable func, dict|tuple|None params=None)
def setcolorfunc(self, type|object obj, typing.Callable|str func, dict|tuple|None params=None)
tuple[str, str] GetColor(self, str|None color=None)
def setfontandcolorfunc(self, type|object obj, typing.Callable|str func, dict|tuple|None params=None)
def __init__(self, dict[str, typing.Any] default_configs=stock_ui_configs, str customfilepath=CraftItems(THEMES_DIR, "default.ini"))
def reset(self, bool restore=False)
typing.Any|tuple[str, int, str, str, str] GetFont(self)