Skip to content

Commit 5fd8c3c

Browse files
committed
Version 7.3
- new file-based communicator - layout upgrade - improved one-window-toggle functionality
1 parent 36f1300 commit 5fd8c3c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+702
-427
lines changed

__init__.py

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
# -*- coding: utf-8 -*-
32

43
"""

components/__init__.py

-13
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
# -*- coding: utf-8 -*-
32

43
"""
@@ -8,15 +7,3 @@
87
For more information check the 'LICENSE.txt' file.
98
For complete license information of the dependencies, check the 'additional_licenses' directory.
109
"""
11-
12-
## Explicit
13-
#from .actionfilter import *
14-
#from .customstyle import *
15-
#from .fonts import *
16-
#from .gridgenerator import *
17-
#from .hexbuilder import *
18-
#from .hotspots import *
19-
#from .iconmanipulator import *
20-
#from .linelist import *
21-
#from .thesquid import *
22-
#from .signaldispatcher import *

components/actionfilter.py

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
# -*- coding: utf-8 -*-
32

43
"""

components/communicator.py

+81-1
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,13 @@
88
For complete license information of the dependencies, check the 'additional_licenses' directory.
99
"""
1010

11+
import os
12+
import json
1113
import time
14+
import queue
1215
import socket
1316
import functools
17+
import traceback
1418
import multiprocessing
1519
import multiprocessing.connection
1620
from typing import *
@@ -22,6 +26,10 @@
2226
DEBUG_MODE = False
2327
STATUS_MODE = False
2428

29+
30+
"""
31+
IPC-based communicator
32+
"""
2533
ADDRESS = 'localhost'
2634
PORT = 19991
2735
PASSWORD = "ExCo"
@@ -170,12 +178,13 @@ def close_connections(self):
170178
co.close()
171179

172180

173-
class Communicator(data.QObject):
181+
class IpcCommunicator(data.QObject):
174182
"""
175183
Object for passing messages between processes/applications
176184
"""
177185
# Signals
178186
received: data.pyqtSignal = data.pyqtSignal(object)
187+
179188
# Attributes
180189
name = None
181190
client = None
@@ -222,3 +231,74 @@ def send(self, message):
222231
self.multisend(message)
223232
else:
224233
self.send_to_server(message)
234+
235+
236+
"""
237+
File-based communicator
238+
"""
239+
class FileCommunicator(data.QObject):
240+
"""
241+
Object for communicating between processes using files
242+
"""
243+
# Constants
244+
COMM_FILE = "exco_comm.json"
245+
246+
# Signals
247+
received: data.pyqtSignal = data.pyqtSignal(object)
248+
__process_directory_queue: data.pyqtSignal = data.pyqtSignal()
249+
250+
# Attributes
251+
__name = ""
252+
__comm_file_path = None
253+
__file_watcher = None
254+
__processing_lock = multiprocessing.Lock()
255+
__processing_queue = multiprocessing.Queue()
256+
257+
def __init__(self, name):
258+
super().__init__()
259+
260+
self.__name = name
261+
self.__comm_file_path = os.path.join(
262+
data.settings_directory,
263+
self.COMM_FILE
264+
)
265+
266+
self.__file_watcher = data.QFileSystemWatcher(self)
267+
self.__file_watcher.directoryChanged.connect(self.__directory_changed)
268+
self.__file_watcher.fileChanged.connect(self.__file_changed)
269+
self.__file_watcher.addPath(data.settings_directory)
270+
271+
self.__process_directory_queue.connect(self.__process_change)
272+
273+
def __directory_changed(self, path):
274+
self.__processing_queue.put(path)
275+
self.__process_directory_queue.emit()
276+
277+
def __file_changed(self, path):
278+
self.__processing_queue.put(path)
279+
self.__process_directory_queue.emit()
280+
281+
def __process_change(self):
282+
acquired = self.__processing_lock.acquire(block=False)
283+
if not acquired:
284+
return
285+
286+
try:
287+
while True:
288+
path = self.__processing_queue.get_nowait()
289+
if os.path.isfile(self.__comm_file_path):
290+
with open(self.__comm_file_path, "r", encoding="utf-8") as f:
291+
text = f.read()
292+
_data = json.loads(text)
293+
self.received.emit(("FileCommunicator", _data))
294+
os.remove(self.__comm_file_path)
295+
except queue.Empty:
296+
pass
297+
except:
298+
traceback.print_exc()
299+
finally:
300+
self.__processing_lock.release()
301+
302+
def send_data(self, _data):
303+
with open(self.__comm_file_path, "w+", encoding="utf-8") as f:
304+
f.write(json.dumps(_data, indent=4, ensure_ascii=False))

components/customstyle.py

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
# -*- coding: utf-8 -*-
32

43
"""

components/gridgenerator.py

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
# -*- coding: utf-8 -*-
32

43
"""

components/hexbuilder.py

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
# -*- coding: utf-8 -*-
32

43
"""

components/hotspots.py

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
# -*- coding: utf-8 -*-
32

43
"""

components/internals.py

+177
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
# -*- coding: utf-8 -*-
2+
3+
"""
4+
Copyright (c) 2013-2023 Matic Kukovec.
5+
Released under the GNU GPL3 license.
6+
7+
For more information check the 'LICENSE.txt' file.
8+
For complete license information of the dependencies, check the 'additional_licenses' directory.
9+
"""
10+
11+
import re
12+
import math
13+
import typing
14+
import importlib
15+
import traceback
16+
17+
import data
18+
import functions
19+
20+
21+
class Internals:
22+
"""
23+
Icon manipulator for a widget inside a basic widget
24+
"""
25+
_parent = None
26+
__tab_widget = None
27+
corner_groupbox = None
28+
__id_counter = 0
29+
__id = None
30+
31+
def __init__(self, parent=None, tab_widget=None, forced_id=None):
32+
self._parent = parent
33+
self.__tab_widget = tab_widget
34+
if forced_id:
35+
self.__id = forced_id
36+
else:
37+
self.__id = Internals.__id_counter
38+
Internals.__id_counter += 1
39+
40+
self.__module_customeditor = importlib.import_module("gui.customeditor")
41+
self.__module_plaineditor = importlib.import_module("gui.plaineditor")
42+
self.__module_tabwidget = importlib.import_module("gui.tabwidget")
43+
self.__module_textdiffer = importlib.import_module("gui.textdiffer")
44+
45+
def __del__(self):
46+
self.remove_corner_groupbox()
47+
48+
def get_id(self):
49+
return self.__id
50+
51+
def set_icon(self, obj, icon):
52+
"""
53+
Set the current icon and update it by sending the signal to the
54+
parent basic widget
55+
"""
56+
obj.current_icon = icon
57+
self.update_icon(obj)
58+
59+
def update_tab_widget(self, new_tab_widget):
60+
self.__tab_widget = new_tab_widget
61+
62+
def update_icon(self, obj):
63+
try:
64+
self.__tab_widget.parent()
65+
except:
66+
traceback.print_exc()
67+
self.__del__()
68+
return
69+
"""
70+
Update the current icon and update it by sending the signal to the
71+
parent basic widget
72+
"""
73+
tab_widget = self.__tab_widget
74+
if isinstance(obj, self.__module_customeditor.CustomEditor):
75+
if isinstance(tab_widget, self.__module_tabwidget.TabWidget):
76+
tab_widget.update_tab_icon(obj)
77+
self.update_corner_widget(obj)
78+
elif isinstance(tab_widget, self.__module_textdiffer.TextDiffer):
79+
tab_widget._parent.update_tab_icon(obj)
80+
elif isinstance(obj, self.__module_plaineditor.PlainEditor):
81+
if isinstance(tab_widget, self.__module_tabwidget.TabWidget):
82+
tab_widget.update_tab_icon(obj)
83+
elif hasattr(obj, "_parent") and obj.current_icon is not None:
84+
obj._parent.update_tab_icon(obj)
85+
86+
def update_corner_widget(self, obj):
87+
if self.corner_groupbox is not None:
88+
try:
89+
self.__tab_widget.parent()
90+
except:
91+
self.__del__()
92+
return
93+
tab_widget = self.__tab_widget
94+
self.show_corner_groupbox(tab_widget)
95+
return True
96+
else:
97+
return False
98+
99+
def remove_corner_groupbox(self):
100+
if self.corner_groupbox is None:
101+
return
102+
self.corner_groupbox = None
103+
104+
def create_corner_button(self, icon, tooltip, function):
105+
button = data.QToolButton()
106+
if isinstance(icon, data.QIcon):
107+
button.setIcon(icon)
108+
else:
109+
button.setIcon(functions.create_icon(icon))
110+
button.setPopupMode(data.QToolButton.ToolButtonPopupMode.InstantPopup)
111+
button.setToolTip(tooltip)
112+
button.clicked.connect(function)
113+
return button
114+
115+
def add_corner_button(self, icon, tooltip, function):
116+
try:
117+
self.__tab_widget.parent()
118+
except:
119+
self.__del__()
120+
return
121+
# Create the group box for buttons if needed
122+
if self.corner_groupbox is None:
123+
self.corner_groupbox = data.QGroupBox(self.__tab_widget)
124+
corner_layout = data.QHBoxLayout()
125+
corner_layout.setSpacing(0)
126+
corner_layout.setContentsMargins(0, 0, 0, 0)
127+
self.corner_groupbox.setLayout(corner_layout)
128+
self.corner_groupbox.setStyleSheet("QGroupBox{border: 0px;}")
129+
self.corner_groupbox.show()
130+
# Add the button
131+
button = self.create_corner_button(icon, tooltip, function)
132+
layout = self.corner_groupbox.layout()
133+
layout.addWidget(button)
134+
for i in range(layout.count()):
135+
if data.custom_menu_scale is not None:
136+
layout.itemAt(i).widget().setIconSize(
137+
data.QSize(
138+
data.custom_menu_scale,
139+
data.custom_menu_scale
140+
)
141+
)
142+
143+
def restyle_corner_button_icons(self):
144+
if self.corner_groupbox is None:
145+
return
146+
layout = self.corner_groupbox.layout()
147+
for i in range(layout.count()):
148+
if data.custom_menu_scale is not None:
149+
layout.itemAt(i).widget().setIconSize(
150+
data.QSize(
151+
data.custom_menu_scale,
152+
data.custom_menu_scale
153+
)
154+
)
155+
156+
def update_corner_button_icon(self, icon, index=0):
157+
if self.corner_groupbox is None:
158+
return
159+
layout = self.corner_groupbox.layout()
160+
if isinstance(icon, data.QIcon):
161+
layout.itemAt(index).widget().setIcon(icon)
162+
else:
163+
layout.itemAt(index).widget().setIcon(
164+
functions.create_icon(icon)
165+
)
166+
167+
def show_corner_groupbox(self, tab_widget):
168+
if self.corner_groupbox is None:
169+
return
170+
try:
171+
tab_widget.setCornerWidget(self.corner_groupbox)
172+
self.corner_groupbox.show()
173+
self.corner_groupbox.setStyleSheet(
174+
"QGroupBox {border: 0px;}"
175+
)
176+
except:
177+
pass

components/linelist.py

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
# -*- coding: utf-8 -*-
32

43
"""

components/thesquid.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,8 @@ def set_style(menu):
8484
window.widget(i).corner_widget.setIconSize(
8585
data.QSize(16, 16)
8686
)
87-
if hasattr(window.widget(i), "icon_manipulator"):
88-
window.widget(i).icon_manipulator.restyle_corner_button_icons()
87+
if hasattr(window.widget(i), "internals"):
88+
window.widget(i).internals.restyle_corner_button_icons()
8989
if isinstance(window.widget(i), TheSquid.__module_customeditor.TreeDisplayBase):
9090
window.widget(i).update_styles()
9191

0 commit comments

Comments
 (0)