-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathutils.py
More file actions
160 lines (123 loc) · 4.96 KB
/
utils.py
File metadata and controls
160 lines (123 loc) · 4.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
import sys
from kivy.config import Config
from kivy.effects.scroll import ScrollEffect
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.label import MDLabel
from kivymd.uix.snackbar import MDSnackbar, MDSnackbarText
def create_snackbar(message='Default'):
t = MDSnackbarText(
size_hint=(None, None),
halign='center', valign='middle',
text=message, text_size=(None, None),
allow_copy=True
)
t.texture_update()
t.width = t.texture_size[0]
snackbar = MDSnackbar(
t,
y=24,
adaptive_width=True,
pos_hint={'center_x': 0.5},
duration=1.2 + int(len(message) * 0.01),
padding=[15, 8, 15, 8]
)
snackbar.ids.label_container.padding = [0, 0, 0, 0]
snackbar.ids.label_container.size_hint_x = None
snackbar.ids.label_container.width = snackbar.ids.label_container.children[0].width
snackbar.size_hint_x = None
snackbar.width = snackbar.children[-1].width + 30 # Account for horizontal padding
return snackbar
def reset_defaults(app):
""" Reset kivy config (Debugging) """
Config._sections.clear()
# Not sure if this actually works:
# for section in Config.sections():
# for option in Config.options(section):
# Config.setdefault(section, option, Config.get(section, option))
Config.write()
app.get_running_app().stop() # And restart
def convert_bytes(size):
"""Convert bytes to a human-readable format (KB, MB, GB)."""
for unit in ['bytes', 'KB', 'MB', 'GB', 'TB']:
if size < 1024.0:
return f'{size:.2f} {unit}'
size /= 1024.0
class NoOverscrollEffect(ScrollEffect):
"""Custom Scroll Effect to Disable Overscroll.
Used by the navigation drawer and scroll view widgets."""
def convert_overscroll(self, *args):
# Override to prevent overscroll
return 0, 0 # No overscroll effect
def reset_scale(self, *args):
# Override to prevent overscroll
return 0, 0 # No overscroll effect
def on_scroll_stop(self):
# Prevent overscroll by clamping scroll values
self.scroll_y = max(0, min(self.scroll_y, 1))
self.scroll_x = max(0, min(self.scroll_x, 1))
def get_size(obj, seen=None):
""" Recursively finds size of objects """
size = sys.getsizeof(obj)
if seen is None:
seen = set()
obj_id = id(obj)
if obj_id in seen:
return 0
# Important mark as seen *before* entering recursion to gracefully handle
# self-referential objects
seen.add(obj_id)
if isinstance(obj, dict):
size += sum([get_size(v, seen) for v in obj.values()])
size += sum([get_size(k, seen) for k in obj.keys()])
elif hasattr(obj, '__dict__'):
size += get_size(obj.__dict__, seen)
elif hasattr(obj, '__iter__') and not isinstance(obj, (str, bytes, bytearray)):
size += sum([get_size(i, seen) for i in obj])
return size
def callback_update_label_size(instance, value, label_sv=None):
instance.text_size = [None, None]
instance.texture_update()
if label_sv:
w, h = instance.size = instance.texture_size
label_sv.size = (min(w, 350), min(h, 350))
def generate_message_cont(text='', padding=(13, 13, 13, 13)):
""" Dialog content generating helper function """
from widgets.scrollview import ZScrollView
a_label = MDLabel(
size_hint=(None, None),
halign='center', valign='middle',
font_style='Table Cell Mono',
text=text, text_size=(None, None),
padding=padding,
allow_selection=True,
allow_copy=True
)
label_sv = ZScrollView(do_scroll_x=True)
label_sv.add_widget(a_label)
label_sv.size_hint = (None, None)
a_label.bind(text=lambda *args: callback_update_label_size(*args, label_sv=label_sv))
container = MDBoxLayout(label_sv,
orientation='vertical',
adaptive_size=True,
)
return container
def set_and_dismiss(objects, attributes, values, obj_to_dismiss=None):
""" Apply changes to widgets & dismiss dialog """
for obj, attribute, value in zip(objects, attributes, values):
setattr(obj, attribute, value)
# Dynamically dismiss object
if obj_to_dismiss and hasattr(obj_to_dismiss, 'dismiss'):
dismiss_method = getattr(obj_to_dismiss, 'dismiss')
if callable(dismiss_method):
dismiss_method()
def numpy_to_dict(array):
""" Serialize to a JSON-compatible format """
return {
'data': array.tolist(), # Convert to list
'dtype': str(array.dtype), # Store data type
'shape': array.shape # Store shape
}
def dict_to_numpy(d):
""" Deserialize back to NumPy array """
import numpy as np
return np.array(d['data'], dtype=d['dtype']).reshape(d['shape'])