Skip to content

Commit 1ad3539

Browse files
committed
Refactor widgets and signals
1 parent c90907e commit 1ad3539

File tree

2 files changed

+110
-118
lines changed

2 files changed

+110
-118
lines changed

spritesheetExporter/controller.py

Lines changed: 42 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -15,80 +15,75 @@
1515
from .ui import Dialog
1616

1717

18-
class Controller:
19-
exporter = Exporter()
20-
dialog = Dialog()
18+
def _current_directory() -> Optional[Path]:
19+
doc = Krita.instance().activeDocument()
20+
if not doc or not doc.fileName():
21+
return None
22+
return Path(doc.fileName()).parent
23+
24+
25+
def _pick_directory_dialog(directory: str) -> str:
26+
file_dialog = QFileDialog()
27+
file_dialog.setWindowTitle(i18n("Choose Export Directory"))
28+
file_dialog.setSizeGripEnabled(True)
29+
30+
# QFileDialog already seems to handle invalid directories fine
31+
file_dialog.setDirectory(directory)
32+
33+
return file_dialog.getExistingDirectory()
34+
35+
36+
def _change_dir(input: QLineEdit):
37+
# Grab the output path on directory changed
38+
path = _pick_directory_dialog(input.text())
39+
if path != "":
40+
input.setText(path)
41+
2142

43+
class Controller:
2244
def __init__(self):
23-
self.dialog.common_settings.change_dir.clicked.connect(
24-
partial(self.change_dir, self.dialog.common_settings.directory)
45+
self.exporter = Exporter()
46+
self.dialog = Dialog()
47+
48+
self.dialog.main_settings.change_dir_clicked.connect(
49+
partial(_change_dir, self.dialog.main_settings.directory)
2550
)
26-
self.dialog.common_settings.reset_dir.clicked.connect(self.reset_export_dir)
51+
self.dialog.main_settings.reset_dir_clicked.connect(self.reset_export_dir)
2752

28-
self.dialog.frames.change_dir.clicked.connect(
29-
partial(self.change_dir, self.dialog.frames.directory)
53+
self.dialog.frames.change_dir_clicked.connect(
54+
partial(_change_dir, self.dialog.frames.directory)
3055
)
31-
self.dialog.frames.reset_dir.clicked.connect(self.reset_frames_dir)
32-
self.dialog.dialog_buttons.accepted.connect(self.confirm_button)
56+
self.dialog.frames.reset_dir_clicked.connect(self.reset_frames_dir)
57+
self.dialog.accepted.connect(self.export)
3358

3459
def show_dialog(self):
35-
if self.dialog.common_settings.directory.text() == "":
60+
if self.dialog.main_settings.directory.text() == "":
3661
self.reset_export_dir()
3762
if self.dialog.frames.directory.text() == "":
3863
self.reset_frames_dir()
3964

4065
self.dialog.show()
4166
self.dialog.activateWindow()
42-
self.dialog.setDisabled(False)
43-
44-
@staticmethod
45-
def current_directory() -> Optional[Path]:
46-
doc = Krita.instance().activeDocument()
47-
if not doc or not doc.fileName():
48-
return None
49-
return Path(doc.fileName()).parent
50-
51-
@staticmethod
52-
def pick_directory_dialog(directory: str) -> str:
53-
file_dialog = QFileDialog()
54-
file_dialog.setWindowTitle(i18n("Choose Export Directory"))
55-
file_dialog.setSizeGripEnabled(True)
56-
57-
# QFileDialog already seems to handle invalid directories fine
58-
file_dialog.setDirectory(directory)
59-
60-
return file_dialog.getExistingDirectory()
61-
62-
@staticmethod
63-
def change_dir(input: QLineEdit):
64-
# Grab the output path on directory changed
65-
path = Controller.pick_directory_dialog(input.text())
66-
if path != "":
67-
input.setText(path)
6867

6968
def reset_export_dir(self):
70-
path = Controller.current_directory()
69+
path = _current_directory()
7170
if path:
72-
self.dialog.common_settings.directory.setText(str(path))
71+
self.dialog.main_settings.directory.setText(str(path))
7372

7473
def reset_frames_dir(self):
75-
path = Controller.current_directory()
74+
path = _current_directory()
7675
if path:
7776
frames_dir = Path(
78-
path, self.dialog.common_settings.name.text().split(".")[0] + "_sprites"
77+
path, self.dialog.main_settings.name.text().split(".")[0] + "_sprites"
7978
)
8079
self.dialog.frames.directory.setText(str(frames_dir))
8180

82-
def confirm_button(self):
83-
# Block any function calls on subsequent clicks
84-
self.dialog.setDisabled(True)
85-
86-
self.dialog.common_settings.apply_settings(self.exporter)
81+
def export(self):
82+
self.dialog.main_settings.apply_settings(self.exporter)
8783
self.dialog.frames.apply_settings(self.exporter)
8884
self.dialog.placement.apply_settings(self.exporter)
8985
self.dialog.frame_times.apply_settings(self.exporter)
9086
self.dialog.edges.apply_settings(self.exporter)
9187
self.exporter.layers_as_animation = self.dialog.layers_as_animation.isChecked()
9288

9389
self.exporter.export()
94-
self.dialog.hide()

spritesheetExporter/ui.py

Lines changed: 68 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"""
44

55
from krita import Krita
6-
from PyQt5.QtCore import Qt
6+
from PyQt5.QtCore import Qt, pyqtSignal
77
from PyQt5.QtWidgets import (
88
QVBoxLayout,
99
QHBoxLayout,
@@ -28,34 +28,39 @@
2828
)
2929

3030

31-
class CommonSettings(QFormLayout):
32-
name = QLineEdit("spritesheet.png")
33-
directory = QLineEdit()
34-
change_dir = QPushButton(Krita.instance().icon("folder"), None)
35-
reset_dir = QPushButton(Krita.instance().icon("view-refresh"), None)
36-
37-
unique_frames = QCheckBox("Only unique frames")
38-
write_texture_atlas = QCheckBox("Write JSON texture atlas")
31+
class MainSettings(QFormLayout):
32+
change_dir_clicked = pyqtSignal()
33+
reset_dir_clicked = pyqtSignal()
3934

4035
def __init__(self):
4136
super().__init__()
37+
ki = Krita.instance()
4238

39+
self.name = QLineEdit("spritesheet.png")
4340
self.name.setToolTip("Name of the exported spritesheet file")
41+
42+
self.directory = QLineEdit()
4443
self.directory.setToolTip("Directory to export the spritesheet to")
4544

46-
self.change_dir.setToolTip("Open a file picker for the export directory")
47-
self.reset_dir.setToolTip(
45+
change_dir = QPushButton(ki.icon("folder"), None)
46+
change_dir.setToolTip("Open a file picker for the export directory")
47+
change_dir.clicked.connect(self.change_dir_clicked.emit)
48+
49+
reset_dir = QPushButton(ki.icon("view-refresh"), None)
50+
reset_dir.setToolTip(
4851
"Reset export directory to the current document's directory"
4952
)
53+
reset_dir.clicked.connect(self.reset_dir_clicked.emit)
5054

55+
self.unique_frames = QCheckBox("Only unique frames")
56+
self.write_texture_atlas = QCheckBox("Write JSON texture atlas")
5157
self.write_texture_atlas.setToolTip(
5258
"Write a JSON texture atlas that can be used in game frameworks (e.g. Phaser 3)"
5359
)
5460

5561
dir_layout = QHBoxLayout()
56-
dir_layout.addWidget(self.directory)
57-
dir_layout.addWidget(self.change_dir)
58-
dir_layout.addWidget(self.reset_dir)
62+
for w in (self.directory, change_dir, reset_dir):
63+
dir_layout.addWidget(w)
5964

6065
self.addRow("Export name:", self.name)
6166
self.addRow("Export directory:", dir_layout)
@@ -73,48 +78,47 @@ class FramesExport(QGroupBox):
7378
Controls configuration for exporting individual frames as an image sequence.
7479
"""
7580

76-
base_name = QLineEdit("sprite")
77-
78-
custom_dir = QCheckBox("Custom directory")
79-
directory = QLineEdit()
80-
change_dir = QPushButton(Krita.instance().icon("folder"), None)
81-
reset_dir = QPushButton(Krita.instance().icon("view-refresh"), None)
82-
83-
force_new = QCheckBox("Force new folder")
81+
change_dir_clicked = pyqtSignal()
82+
reset_dir_clicked = pyqtSignal()
8483

8584
def __init__(self):
8685
super().__init__("Export image sequence")
8786
self.setCheckable(True)
8887
self.setChecked(False)
88+
ki = Krita.instance()
8989

90-
self.toggle_custom_dir(Qt.Unchecked)
91-
self.custom_dir.stateChanged.connect(self.toggle_custom_dir)
90+
self.base_name = QLineEdit("sprite")
91+
self.custom_dir = QCheckBox("Custom directory")
9292

93+
self.directory = QLineEdit()
9394
self.directory.setToolTip("Directory the images will be exported to")
94-
self.change_dir.setToolTip("Open a file picker for the images directory")
95-
self.reset_dir.setToolTip("Reset images directory based on the export path")
9695

96+
change_dir = QPushButton(ki.icon("folder"), None)
97+
change_dir.setToolTip("Open a file picker for the images directory")
98+
change_dir.clicked.connect(self.change_dir_clicked.emit)
99+
100+
reset_dir = QPushButton(ki.icon("view-refresh"), None)
101+
reset_dir.setToolTip("Reset images directory based on the export path")
102+
reset_dir.clicked.connect(self.reset_dir_clicked.emit)
103+
104+
self.force_new = QCheckBox("Force new folder")
97105
self.force_new.setToolTip(
98106
"If checked, create a new frames folder if one exists.\nOtherwise, write the sprites in the existing folder (may overwrite files)"
99107
)
100108

101109
dir_layout = QHBoxLayout()
102110
dir_layout.addWidget(self.custom_dir)
103-
dir_layout.addWidget(self.directory)
104-
dir_layout.addWidget(self.change_dir)
105-
dir_layout.addWidget(self.reset_dir)
111+
112+
for w in (self.directory, change_dir, reset_dir):
113+
w.setEnabled(False)
114+
self.custom_dir.toggled.connect(w.setEnabled)
115+
dir_layout.addWidget(w)
106116

107117
layout = QFormLayout(self)
108118
layout.addRow("Base name:", self.base_name)
109119
layout.addRow(dir_layout)
110120
layout.addRow(self.force_new)
111121

112-
def toggle_custom_dir(self, state: int):
113-
enabled = state == Qt.Checked
114-
self.directory.setEnabled(enabled)
115-
self.change_dir.setEnabled(enabled)
116-
self.reset_dir.setEnabled(enabled)
117-
118122
def apply_settings(self, exporter: Exporter):
119123
if not self.isChecked():
120124
exporter.export_frame_sequence = False
@@ -137,24 +141,23 @@ class SpritePlacement(QFormLayout):
137141
oriented, and how many cells to put in that direction.
138142
"""
139143

140-
h_dir = QRadioButton("Horizontal")
141-
columns = QRadioButton("Columns")
142-
size = QSpinBox(value=DEFAULT_SPACE, minimum=DEFAULT_SPACE)
143-
144144
def __init__(self):
145145
super().__init__()
146146
self.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.AllNonFixedFieldsGrow)
147147
self.setHorizontalSpacing(12)
148148

149+
self.h_dir = QRadioButton("Horizontal")
149150
self.h_dir.setChecked(True)
150151
self.h_dir.setToolTip("Order sprites horizontally")
151152

152153
v_dir = QRadioButton("Vertical")
153154
v_dir.setToolTip("Order sprites vertically")
154155

156+
self.size = QSpinBox(value=DEFAULT_SPACE, minimum=DEFAULT_SPACE)
155157
self.size.setSpecialValueText("Auto")
156158
self.size.setToolTip("Number of columns or rows in the spritesheet")
157159

160+
self.columns = QRadioButton("Columns")
158161
self.columns.setChecked(True)
159162
rows = QRadioButton("Rows")
160163

@@ -192,16 +195,15 @@ def apply_settings(self, exporter: Exporter):
192195

193196

194197
class SpinBoxes(QFormLayout):
195-
start = QSpinBox(value=DEFAULT_TIME, minimum=DEFAULT_TIME, maximum=9999)
196-
end = QSpinBox(value=DEFAULT_TIME, minimum=DEFAULT_TIME, maximum=9999)
197-
step = QSpinBox(value=1, minimum=1)
198-
199198
def __init__(self):
200199
super().__init__()
201200

202-
self.start.setSpecialValueText("Auto")
203-
self.end.setSpecialValueText("Auto")
204-
self.step.setSpecialValueText("Auto")
201+
self.start = QSpinBox(value=DEFAULT_TIME, minimum=DEFAULT_TIME, maximum=9999)
202+
self.end = QSpinBox(value=DEFAULT_TIME, minimum=DEFAULT_TIME, maximum=9999)
203+
self.step = QSpinBox(value=1, minimum=1)
204+
205+
for spin_box in (self.start, self.end, self.step):
206+
spin_box.setSpecialValueText("Auto")
205207

206208
self.start.setToolTip("First frame time of the animation (inclusive)")
207209
self.end.setToolTip("Last frame time of the animation (inclusive)")
@@ -227,56 +229,51 @@ class EdgePadding(QFormLayout):
227229
def __init__(self):
228230
super().__init__()
229231

230-
self.left = self._make_spin_box("left")
231-
self.top = self._make_spin_box("top")
232-
self.right = self._make_spin_box("right")
233-
self.bottom = self._make_spin_box("bottom")
234-
235-
self.addRow("Padding left:", self.left)
236-
self.addRow("Padding top:", self.top)
237-
self.addRow("Padding right:", self.right)
238-
self.addRow("Padding bottom:", self.bottom)
232+
self.left = self._add_spin_box("left")
233+
self.top = self._add_spin_box("top")
234+
self.right = self._add_spin_box("right")
235+
self.bottom = self._add_spin_box("bottom")
239236

240237
def apply_settings(self, exp: Exporter) -> None:
241238
exp.pad_left = self.left.value()
242239
exp.pad_top = self.top.value()
243240
exp.pad_right = self.right.value()
244241
exp.pad_bottom = self.bottom.value()
245242

246-
@staticmethod
247-
def _make_spin_box(edge: str) -> QSpinBox:
243+
def _add_spin_box(self, edge: str) -> QSpinBox:
248244
spin_box = QSpinBox(value=0, minimum=-99, maximum=99)
249245
spin_box.setSuffix("px")
250246
spin_box.setToolTip(
251247
f"Pad the {edge} edge of each sprite, or clip it if negative"
252248
)
249+
250+
self.addRow(f"Padding {edge}:", spin_box)
253251
return spin_box
254252

255253

256254
class Dialog(QDialog):
257-
common_settings = CommonSettings()
258-
frames = FramesExport()
259-
edges = EdgePadding()
260-
261-
# Extra settings group
262-
layers_as_animation = QCheckBox("Use layers as animation frames")
263-
placement = SpritePlacement()
264-
frame_times = SpinBoxes()
265-
266-
dialog_buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
267-
268255
def __init__(self):
269256
super().__init__()
270257
self.setWindowTitle(i18n("SpritesheetExporter"))
271258
self.setWindowModality(Qt.NonModal) # Don't block input to other windows
272259
self.setMinimumSize(425, 480)
273260
self.setSizeGripEnabled(True)
274261

262+
self.main_settings = MainSettings()
263+
self.frames = FramesExport()
264+
self.edges = EdgePadding()
265+
266+
# Extra settings group
267+
self.layers_as_animation = QCheckBox("Use layers as animation frames")
275268
self.layers_as_animation.setToolTip(
276269
"Treat each layer as a frame instead of using the animation timeline"
277270
)
271+
self.placement = SpritePlacement()
272+
self.frame_times = SpinBoxes()
278273

279-
self.dialog_buttons.rejected.connect(self.close)
274+
dialog_buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
275+
dialog_buttons.accepted.connect(self.accept)
276+
dialog_buttons.rejected.connect(self.reject)
280277

281278
# Setup layouts
282279
spin_boxes = QHBoxLayout()
@@ -295,7 +292,7 @@ def __init__(self):
295292
extras.addLayout(spin_boxes)
296293

297294
root_layout = QVBoxLayout(self) # the box holding everything
298-
root_layout.addLayout(self.common_settings)
295+
root_layout.addLayout(self.main_settings)
299296
root_layout.addWidget(self.frames)
300297
root_layout.addWidget(extra_settings)
301-
root_layout.addWidget(self.dialog_buttons)
298+
root_layout.addWidget(dialog_buttons)

0 commit comments

Comments
 (0)