mirror of
https://github.com/thewesker/lazy-dsi-file-downloader.git
synced 2025-12-20 04:21:09 -05:00
Attempt to fix macOS issue
This commit is contained in:
366
tkmacosx/variables.py
Normal file
366
tkmacosx/variables.py
Normal file
@@ -0,0 +1,366 @@
|
||||
# Copyright 2020 Saad Mairaj
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import re
|
||||
import sys
|
||||
import ast
|
||||
import pickle as pkl
|
||||
|
||||
if sys.version_info.major == 2:
|
||||
import Tkinter as _tk
|
||||
elif sys.version_info.major == 3:
|
||||
import tkinter as _tk
|
||||
|
||||
|
||||
# Modified Misc._options(...) to make ColorVar work with tkinter
|
||||
# {(self, option, tag): (var, cbname)}
|
||||
_all_traces_colorvar = {}
|
||||
|
||||
|
||||
def _colorvar_patch_cget(fn):
|
||||
"""Internal function."""
|
||||
def _patch(self, key):
|
||||
"""Return the resource value for a KEY given as string."""
|
||||
if (self, key) in _all_traces_colorvar:
|
||||
return _all_traces_colorvar[(self, key)][0]
|
||||
return fn(self, key)
|
||||
return _patch
|
||||
|
||||
|
||||
def _colorvar_patch_destroy(fn):
|
||||
"""Internal function.\n
|
||||
Deletes the traces if any when widget is destroy."""
|
||||
|
||||
def _patch(self):
|
||||
"""Interanl function."""
|
||||
if self._tclCommands is not None:
|
||||
# Deletes the widget from the _all_traces_colorvar
|
||||
# and deletes the traces too.
|
||||
for key, value in dict(_all_traces_colorvar).items():
|
||||
if self == key[0]:
|
||||
var, cbname = value
|
||||
try: var.trace_vdelete('w', cbname)
|
||||
except: pass
|
||||
_all_traces_colorvar.pop(key)
|
||||
return fn(self)
|
||||
return _patch
|
||||
|
||||
|
||||
def _colorvar_patch_configure(fn):
|
||||
"""Internal function.\n
|
||||
Patch for Canvas items to support ColorVar functionality."""
|
||||
|
||||
def _patch(self, cmd, cnf, kw):
|
||||
"""Internal function."""
|
||||
|
||||
cnf = _tk._cnfmerge((cnf, kw))
|
||||
cnf_copy = dict(cnf)
|
||||
# -------------------- Added the below block --------------------
|
||||
# Add the resources to the list to have ColorVar functionality.
|
||||
if isinstance(cmd, tuple) and isinstance(self, _tk.Canvas):
|
||||
tags = self.find('withtag', cmd[1])
|
||||
for tag in tags:
|
||||
for i in ('activefill', 'activeoutline', 'disabledfill',
|
||||
'disabledoutline', 'fill', 'outline', 'background',
|
||||
'activebackground', 'activeforeground',
|
||||
'disabledbackground', 'disabledforeground',
|
||||
'foreground'):
|
||||
if isinstance(cnf_copy.get(i), _tk.Variable):
|
||||
var = cnf_copy[i]
|
||||
cbname = var.trace_variable('w', lambda a, b, c,
|
||||
cls=self, opt=i,
|
||||
tagId=tag, var=var:
|
||||
cls._configure(('itemconfigure',tagId),
|
||||
{opt: var.get()}, None))
|
||||
if (self, (i, tag)) in _all_traces_colorvar:
|
||||
v, cb = _all_traces_colorvar.get((self, (i, tag)))
|
||||
v.trace_vdelete('w', cb)
|
||||
_all_traces_colorvar[(self, (i, tag))] = (var, cbname)
|
||||
else:
|
||||
_all_traces_colorvar[(self, (i, tag))] = (var, cbname)
|
||||
cnf[i] = var.get()
|
||||
return fn(self, cmd, cnf, None)
|
||||
return _patch
|
||||
|
||||
|
||||
def _colorvar_patch_options(fn):
|
||||
"""Internal function.\n
|
||||
Patch for ColorVar to work with tkinter widgets."""
|
||||
|
||||
def _patch(self, cnf, kw=None):
|
||||
"""Internal function."""
|
||||
if kw:
|
||||
cnf = _tk._cnfmerge((cnf, kw))
|
||||
else:
|
||||
cnf = _tk._cnfmerge(cnf)
|
||||
|
||||
for i in ('fg', 'foreground', 'bg', 'background',
|
||||
'activebackground', 'activeforeground', 'disabledforeground',
|
||||
'highlightbackground', 'highlightcolor', 'selectforeground',
|
||||
'readonlybackground', 'selectbackground', 'insertbackground',
|
||||
'disabledbackground'):
|
||||
if isinstance(cnf.get(i), _tk.Variable):
|
||||
var = cnf[i]
|
||||
cbname = var.trace_variable('w', lambda a, b, c, i=i, var=var,
|
||||
cls=self: cls.config({i: var.get()}))
|
||||
if (self, i) in _all_traces_colorvar:
|
||||
v, cb = _all_traces_colorvar.get((self, i))
|
||||
v.trace_vdelete('w', cb)
|
||||
_all_traces_colorvar[(self, i)] = (var, cbname)
|
||||
else:
|
||||
_all_traces_colorvar[(self, i)] = (var, cbname)
|
||||
cnf[i] = var.get()
|
||||
# [issue-1] once a ColorVar is assigned, it cannot be removed
|
||||
# untill the widget is destroyed or give another ColorVar
|
||||
# [issue-1] (trial) the below doesn't work as excepted.
|
||||
# elif (self, i) in _all_traces_colorvar:
|
||||
# if self[i] != _all_traces_colorvar[(self, i)][0].get():
|
||||
# print( self, i, self[i])
|
||||
# v, cb = _all_traces_colorvar.pop((self, i))
|
||||
# v.trace_vdelete('w', cb)
|
||||
return fn(self, cnf, None)
|
||||
return _patch
|
||||
|
||||
|
||||
def _create(self, itemType, args, kw): # Args: (val, val, ..., cnf={})
|
||||
"""Internal function."""
|
||||
args = _tk._flatten(args)
|
||||
cnf = args[-1]
|
||||
if isinstance(cnf, (dict, tuple)):
|
||||
args = args[:-1]
|
||||
else:
|
||||
cnf = {}
|
||||
|
||||
# -------------------- Added the below block --------------------
|
||||
# Add the resources to the list to have ColorVar functionality.
|
||||
ckw = _tk._cnfmerge((cnf, kw))
|
||||
var = None
|
||||
for i in ('activefill', 'activeoutline', 'disabledfill',
|
||||
'disabledoutline', 'fill', 'outline', 'background',
|
||||
'activebackground', 'activeforeground', 'foreground',
|
||||
'disabledbackground', 'disabledforeground'):
|
||||
if isinstance(ckw.get(i), _tk.Variable):
|
||||
var = ckw[i]
|
||||
_all_traces_colorvar[(self, (i, None))] = (var, None)
|
||||
if isinstance(cnf, dict) and i in cnf:
|
||||
cnf[i] = var.get()
|
||||
elif i in kw:
|
||||
kw[i] = var.get()
|
||||
# ---------------------------------------------------------------
|
||||
|
||||
tagId = self.tk.getint(self.tk.call(
|
||||
self._w, 'create', itemType,
|
||||
*(args + self._options(cnf, kw))))
|
||||
|
||||
for key, value in dict(_all_traces_colorvar).items():
|
||||
if isinstance(key[1], (tuple, list)):
|
||||
wid, (opt, tag_id) = key
|
||||
var, cbname = value
|
||||
if tag_id is None and cbname is None:
|
||||
cbname = var.trace_variable('w', lambda a, b, c,
|
||||
cls=self, opt=opt,
|
||||
tagId=tagId, var=var:
|
||||
cls._configure(('itemconfigure',tagId),
|
||||
{opt: var.get()}, None))
|
||||
_all_traces_colorvar[(self, (opt, tagId))] = (var, cbname)
|
||||
_all_traces_colorvar.pop((self, (opt, None)))
|
||||
return tagId
|
||||
|
||||
|
||||
_tk.Misc.destroy = _colorvar_patch_destroy(_tk.Misc.destroy)
|
||||
_tk.Misc._options = _colorvar_patch_options(_tk.Misc._options)
|
||||
_tk.Misc._configure = _colorvar_patch_configure(_tk.Misc._configure)
|
||||
_tk.Canvas._create = _create
|
||||
|
||||
|
||||
class ColorVar(_tk.Variable):
|
||||
"""Value holder for HEX color. Default is white"""
|
||||
|
||||
_default = "white"
|
||||
_rgbstring = re.compile(r'#[a-fA-F0-9]{3}(?:[a-fA-F0-9]{3})?$')
|
||||
|
||||
def __init__(self, master=None, value=None, name=None):
|
||||
"""Construct a color variable. (bg, fg, ..)
|
||||
|
||||
MASTER can be given as master widget.
|
||||
VALUE is an optional value (defaults to "")
|
||||
NAME is an optional Tcl name (defaults to PY_VARnum).
|
||||
|
||||
If NAME matches an existing variable and VALUE is omitted
|
||||
then the existing value is retained.
|
||||
"""
|
||||
_tk.Variable.__init__(self, master, value, name)
|
||||
|
||||
def set(self, value=''):
|
||||
"""Set the variable to VALUE."""
|
||||
if value.startswith('#'):
|
||||
if not bool(self._rgbstring.match(value)):
|
||||
raise ValueError('"{}" is not a valid HEX.'.format(value))
|
||||
elif isinstance(value, str):
|
||||
try:
|
||||
r, g, b = self._root.winfo_rgb(value)
|
||||
c = (r/257, g/257, b/257)
|
||||
value = '#%02x%02x%02x' % (int(c[0]), int(c[1]), int(c[2]))
|
||||
except:
|
||||
raise ValueError(
|
||||
'Could not find right HEX for "{}".'.format(value))
|
||||
return self._tk.globalsetvar(self._name, value)
|
||||
initialize = set
|
||||
|
||||
def get(self):
|
||||
"""Return value of variable color."""
|
||||
value = self._tk.globalgetvar(self._name)
|
||||
if isinstance(value, str):
|
||||
return value
|
||||
return str(value)
|
||||
|
||||
|
||||
class DictVar(_tk.Variable):
|
||||
"""
|
||||
#### Value holder for Dictionaries.
|
||||
Get a specific value by getting the key from this \
|
||||
`get(self, key=None, d=None)` method if exists in the dictionary. \n
|
||||
if `key=None` it will return the complete dictionary.
|
||||
"""
|
||||
_default = {}
|
||||
|
||||
def __init__(self, master=None, value=None, name=None):
|
||||
"""Construct a string variable.
|
||||
|
||||
MASTER can be given as master widget.
|
||||
VALUE is an optional value (defaults to {})
|
||||
NAME is an optional Tcl name (defaults to PY_VARnum).
|
||||
|
||||
If NAME matches an existing variable and VALUE is omitted
|
||||
then the existing value is retained.
|
||||
"""
|
||||
_tk.Variable.__init__(self, master, value, name)
|
||||
|
||||
def get(self, key=None, d=None):
|
||||
"""Return value of variable as string."""
|
||||
value = self._tk.globalgetvar(self._name)
|
||||
if not isinstance(value, dict):
|
||||
value = ast.literal_eval(value)
|
||||
if key:
|
||||
return value.get(key, d)
|
||||
else:
|
||||
return value
|
||||
|
||||
|
||||
def SaveVar(var, master=None, value=None, name=None, filename='data.pkl'):
|
||||
"""Save tkinter variable data in a pickle file and load the
|
||||
same value when the program is executed next time.
|
||||
|
||||
#### If the content of the file changes, it might not load correct values \
|
||||
to the assigned variables. To avoid this issue use `name` to \
|
||||
refer to the exact assigned values later.
|
||||
|
||||
### Args:
|
||||
- `var`: Give the `tkinter.Variable` class like (`tk.StringVar`, `tk.IntVar`).
|
||||
- `master`: Parent widget.
|
||||
- `value`: Set value.
|
||||
- `name`: Set a name to group variables or to refer to assigned value when loaded.
|
||||
- `filename`: Set the name of the save file. (To make the file invisible in the \
|
||||
directory start the name of the file with "." like ".cache-savevar")
|
||||
|
||||
### Return:
|
||||
- returns the tk.Variable instance passed to `var` argument.
|
||||
|
||||
### Example:
|
||||
root = tk.Tk()
|
||||
var1 = SaveVar(tk.StringVar,'Enter Username','Var1','.cache-savevar')
|
||||
var2 = SaveVar(tk.StringVar,'Enter Password','Var2','.cache-savevar')
|
||||
tk.Entry(root,textvariable=var1).pack()
|
||||
tk.Entry(root,textvariable=var2).pack()
|
||||
root.mainloop()"""
|
||||
|
||||
def update_val(*args):
|
||||
"""Internal function for updating the value for variable"""
|
||||
try: # try/except , if the file doesn't exists.
|
||||
open1 = open(filename, 'rb')
|
||||
tmpdict = pkl.load(open1) # load saved dictionary data.
|
||||
# Block of code to check for the right value.
|
||||
if tmpdict.get(str(var)):
|
||||
old, default = tmpdict.get(str(var))
|
||||
new = var.get()
|
||||
if new != default:
|
||||
var.set(new)
|
||||
elif new == default and not startup[0]:
|
||||
var.set(default)
|
||||
else:
|
||||
var.set(old)
|
||||
tmpdict.update({str(var): (var.get(), defaultval)})
|
||||
open1.close()
|
||||
except Exception as e:
|
||||
tmpdict = {}
|
||||
tmpdict[str(var)] = (var.get(), defaultval)
|
||||
|
||||
open2 = open(filename, 'wb')
|
||||
pkl.dump(tmpdict, open2)
|
||||
startup[0] = False
|
||||
open2.close()
|
||||
|
||||
startup = [True]
|
||||
if not(filename.endswith('.pickle') or filename.endswith('.pkl')) \
|
||||
and not filename.startswith('.'):
|
||||
filename = filename+'.pkl'
|
||||
var = var(master=master, value=value, name=name)
|
||||
defaultval = var.get() # get a default value of the variable
|
||||
update_val()
|
||||
for mode, cbname in (var.trace_vinfo()):
|
||||
if mode[0] == 'w' and update_val.__name__ in cbname:
|
||||
try:
|
||||
var.trace_vdelete('w', cbname)
|
||||
except:
|
||||
pass
|
||||
res = var.trace_variable('w', update_val)
|
||||
return var
|
||||
|
||||
|
||||
# ------------------ Testing ------------------
|
||||
|
||||
def demo_colorvar():
|
||||
import tkmacosx.colors as colors
|
||||
root = _tk.Tk()
|
||||
root.geometry('100x100')
|
||||
color = ColorVar()
|
||||
color_list = list(colors.OrderedHex)
|
||||
L = _tk.Label(root, textvariable=color, bg=color)
|
||||
L.place(relx=0.5, rely=0.5, anchor='center')
|
||||
|
||||
def change_color(c=0):
|
||||
if root.winfo_exists():
|
||||
if c >= len(color_list):
|
||||
c = 0
|
||||
color.set(color_list[c])
|
||||
root.after(100, change_color, c+1)
|
||||
|
||||
change_color()
|
||||
root.mainloop()
|
||||
|
||||
|
||||
def demo_savevar():
|
||||
root = _tk.Tk()
|
||||
var1 = SaveVar(_tk.StringVar, root, 'Enter Username',
|
||||
'Var1', '.cache-savevar')
|
||||
var2 = SaveVar(_tk.StringVar, root, 'Enter Password',
|
||||
'Var2', '.cache-savevar')
|
||||
_tk.Entry(root, textvariable=var1).pack()
|
||||
_tk.Entry(root, textvariable=var2).pack()
|
||||
root.mainloop()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
demo_colorvar()
|
||||
demo_savevar()
|
||||
Reference in New Issue
Block a user