Skip to content

Commit 87c6f39

Browse files
authored
Merge pull request #34 from Interpause/ui-overhaul
UI overhaul
2 parents f577ef4 + 60227c6 commit 87c6f39

File tree

15 files changed

+181
-157
lines changed

15 files changed

+181
-157
lines changed
Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,63 @@
11
from krita import DockWidgetFactory, DockWidgetFactoryBase, Krita
22

3-
from .docker import SDPluginDocker
4-
from .hotkeys import Hotkeys
3+
from .docker import create_docker
4+
from .extension import SDPluginExtension
5+
from .pages import (
6+
ConfigPage,
7+
Img2ImgPage,
8+
InpaintPage,
9+
SDCommonPage,
10+
Txt2ImgPage,
11+
UpscalePage,
12+
)
13+
14+
# TODO:
15+
# - split each tab into its own Docker
16+
# - by default, dock all the tabs onto each other except quick config
17+
# - see https://scripting.krita.org/lessons/docker-widgets
18+
# - Might want to seriously consider drawing the line on what is done by backend/frontend
519

620
instance = Krita.instance()
7-
instance.addExtension(Hotkeys(instance))
21+
instance.addExtension(SDPluginExtension(instance))
22+
instance.addDockWidgetFactory(
23+
DockWidgetFactory(
24+
"krita_diff_sdcommon",
25+
DockWidgetFactoryBase.DockLeft,
26+
create_docker(SDCommonPage),
27+
)
28+
)
29+
instance.addDockWidgetFactory(
30+
DockWidgetFactory(
31+
"krita_diff_txt2img",
32+
DockWidgetFactoryBase.DockLeft,
33+
create_docker(Txt2ImgPage),
34+
)
35+
)
36+
instance.addDockWidgetFactory(
37+
DockWidgetFactory(
38+
"krita_diff_img2img",
39+
DockWidgetFactoryBase.DockLeft,
40+
create_docker(Img2ImgPage),
41+
)
42+
)
43+
instance.addDockWidgetFactory(
44+
DockWidgetFactory(
45+
"krita_diff_inpaint",
46+
DockWidgetFactoryBase.DockLeft,
47+
create_docker(InpaintPage),
48+
)
49+
)
50+
instance.addDockWidgetFactory(
51+
DockWidgetFactory(
52+
"krita_diff_upscale",
53+
DockWidgetFactoryBase.DockLeft,
54+
create_docker(UpscalePage),
55+
)
56+
)
857
instance.addDockWidgetFactory(
9-
DockWidgetFactory("krita_diff", DockWidgetFactoryBase.DockLeft, SDPluginDocker)
58+
DockWidgetFactory(
59+
"krita_diff_config",
60+
DockWidgetFactoryBase.DockLeft,
61+
create_docker(ConfigPage),
62+
)
1063
)

frontends/krita/krita_diff/client.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ def request(cls, *args, **kwargs):
128128

129129
class Client(QObject):
130130
status = pyqtSignal(str)
131-
"""error message, Exception object"""
131+
config_updated = pyqtSignal()
132132

133133
def __init__(self, cfg: Config, ext_cfg: Config):
134134
"""It is highly dependent on config's structure to the point it writes directly to it. :/"""
@@ -207,7 +207,7 @@ def get_common_params(self, has_selection):
207207
)
208208
return params
209209

210-
def get_config(self) -> bool:
210+
def get_config(self):
211211
def cb(obj):
212212
try:
213213
assert "sample_path" in obj
@@ -254,6 +254,7 @@ def cb(obj):
254254

255255
self.is_connected = True
256256
self.status.emit(STATE_READY)
257+
self.config_updated.emit()
257258

258259
# only get config if there are no pending post requests jamming the backend
259260
# NOTE: this might prevent get_config() from ever working if zombie requests can happen

frontends/krita/krita_diff/docker.py

Lines changed: 25 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,108 +1,35 @@
1-
from functools import partial
1+
from krita import DockWidget, QScrollArea
22

3-
from krita import DockWidget, QScrollArea, QTabWidget, QTimer, QVBoxLayout, QWidget
4-
5-
from .defaults import REFRESH_INTERVAL, STATE_INIT, STATE_READY, STATE_URLERROR
6-
from .pages import (
7-
ConfigTabWidget,
8-
Img2ImgTabWidget,
9-
InpaintTabWidget,
10-
SDCommonWidget,
11-
Txt2ImgTabWidget,
12-
UpscaleTabWidget,
13-
)
143
from .script import script
154
from .style import style
16-
from .widgets import QLabel
17-
18-
# Notes:
19-
# - Consider making QuickConfig an accordion to save vertical space
20-
# - There's no accordion in Qt. Cry. I wanna go back to using Preact & JSX...
21-
22-
# TODO:
23-
# - split each tab into its own Docker
24-
# - by default, dock all the tabs onto each other except quick config
25-
# - see https://scripting.krita.org/lessons/docker-widgets
26-
# - Might want to seriously consider drawing the line on what is done by backend/frontend
27-
28-
29-
class SDPluginDocker(DockWidget):
30-
def __init__(self, *args, **kwargs):
31-
super(SDPluginDocker, self).__init__(*args, **kwargs)
32-
self.setWindowTitle("SD Plugin")
33-
self.create_interfaces()
34-
self.update_remote_config()
35-
self.update_interfaces()
36-
self.connect_interfaces()
37-
self.setWidget(self.widget)
38-
39-
def create_interfaces(self):
40-
self.quick_widget = SDCommonWidget()
41-
self.txt2img_widget = Txt2ImgTabWidget()
42-
self.img2img_widget = Img2ImgTabWidget()
43-
self.inpaint_widget = InpaintTabWidget()
44-
self.upscale_widget = UpscaleTabWidget()
45-
self.config_widget = ConfigTabWidget(self.update_interfaces)
46-
47-
self.tabs = tabs = QTabWidget()
48-
tabs.addTab(self.txt2img_widget, "Txt2Img")
49-
tabs.addTab(self.img2img_widget, "Img2Img")
50-
tabs.addTab(self.inpaint_widget, "Inpaint")
51-
tabs.addTab(self.upscale_widget, "Upscale")
52-
tabs.addTab(self.config_widget, "Config")
53-
tabs.setTabPosition(QTabWidget.West)
54-
55-
self.status_bar = QLabel()
56-
self.update_status_bar(STATE_INIT)
57-
58-
layout = QVBoxLayout()
59-
layout.setContentsMargins(0, 0, 0, 0)
60-
61-
layout.addWidget(self.quick_widget)
62-
layout.addWidget(self.status_bar)
63-
layout.addWidget(tabs)
64-
layout.addStretch()
65-
66-
self.widget = QScrollArea()
67-
self.widget.setStyleSheet(style)
68-
widget = QWidget(self)
69-
widget.setLayout(layout)
70-
self.widget.setWidget(widget)
71-
self.widget.setWidgetResizable(True)
72-
73-
self.update_timer = QTimer()
745

75-
def update_interfaces(self):
76-
self.quick_widget.cfg_init()
77-
self.txt2img_widget.cfg_init()
78-
self.img2img_widget.cfg_init()
79-
self.inpaint_widget.cfg_init()
80-
self.upscale_widget.cfg_init()
81-
self.config_widget.cfg_init()
826

83-
self.tabs.setCurrentIndex(script.cfg("tab_index", int))
7+
def create_docker(page):
8+
class Docker(DockWidget):
9+
def __init__(self, *args, **kwargs):
10+
super(Docker, self).__init__(*args, **kwargs)
11+
self.setWindowTitle(page.name)
12+
self.create_interface()
13+
self.update_interface()
14+
self.connect_interface()
15+
self.setWidget(self.widget)
8416

85-
def connect_interfaces(self):
86-
self.quick_widget.cfg_connect()
87-
self.txt2img_widget.cfg_connect()
88-
self.img2img_widget.cfg_connect()
89-
self.inpaint_widget.cfg_connect()
90-
self.upscale_widget.cfg_connect()
91-
self.config_widget.cfg_connect()
17+
def create_interface(self):
18+
self.page_widget = page()
19+
self.widget = QScrollArea()
20+
self.widget.setStyleSheet(style)
21+
self.widget.setWidget(self.page_widget)
22+
self.widget.setWidgetResizable(True)
9223

93-
self.update_timer.timeout.connect(self.update_remote_config)
94-
self.update_timer.start(REFRESH_INTERVAL)
95-
script.status_changed.connect(self.update_status_bar)
96-
self.tabs.currentChanged.connect(partial(script.cfg.set, "tab_index"))
24+
def update_interface(self):
25+
self.page_widget.cfg_init()
9726

98-
def update_status_bar(self, s):
99-
if s == STATE_READY and STATE_URLERROR not in self.status_bar.text():
100-
return
101-
self.status_bar.setText(f"<b>Status:</b> {s}")
27+
def connect_interface(self):
28+
self.page_widget.cfg_connect()
29+
script.config_updated.connect(self.update_interface)
10230

103-
def update_remote_config(self):
104-
script.update_config()
105-
self.update_interfaces()
31+
def canvasChanged(self, canvas):
32+
# TODO: use this callback to save config settings per document
33+
pass
10634

107-
def canvasChanged(self, canvas):
108-
pass
35+
return Docker

frontends/krita/krita_diff/hotkeys.py renamed to frontends/krita/krita_diff/extension.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
1-
from krita import Extension
1+
from krita import Extension, QTimer
22

3-
from .docker import script
3+
from .defaults import REFRESH_INTERVAL
4+
from .script import script
45

56

6-
class Hotkeys(Extension):
7+
class SDPluginExtension(Extension):
78
def __init__(self, parent):
89
super().__init__(parent)
910

1011
def setup(self):
11-
pass
12+
self.update_timer = QTimer()
13+
self.update_timer.timeout.connect(script.action_update_config)
14+
self.update_timer.start(REFRESH_INTERVAL)
15+
script.action_update_config()
1216

1317
def createActions(self, window):
1418
txt2img_action = window.createAction(
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
from .common import SDCommonWidget
2-
from .config import ConfigTabWidget
3-
from .img2img import Img2ImgTabWidget
4-
from .inpaint import InpaintTabWidget
5-
from .txt2img import Txt2ImgTabWidget
6-
from .upscale import UpscaleTabWidget
1+
from .common import SDCommonPage
2+
from .config import ConfigPage
3+
from .img2img import Img2ImgPage
4+
from .inpaint import InpaintPage
5+
from .txt2img import Txt2ImgPage
6+
from .upscale import UpscalePage

frontends/krita/krita_diff/pages/common.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@
88
# - move upscaler/face restorer to config?
99

1010

11-
class SDCommonWidget(QWidget):
11+
class SDCommonPage(QWidget):
12+
name = "SD Common Options"
13+
1214
def __init__(self, *args, **kwargs):
13-
super(SDCommonWidget, self).__init__(*args, **kwargs)
15+
super(SDCommonPage, self).__init__(*args, **kwargs)
1416

1517
self.title = QLabel("<em>Quick Config</em>")
1618

@@ -74,6 +76,7 @@ def __init__(self, *args, **kwargs):
7476
layout.addLayout(self.sd_model_layout)
7577
layout.addLayout(batch_layout)
7678
layout.addLayout(size_layout)
79+
layout.addStretch()
7780

7881
self.setLayout(layout)
7982

frontends/krita/krita_diff/pages/config.py

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,16 @@
44

55
from ..defaults import DEFAULTS
66
from ..script import script
7-
from ..widgets import QCheckBox, QLabel, QLineEditLayout
7+
from ..widgets import QCheckBox, QLabel, QLineEditLayout, StatusBar
88

99

10-
class ConfigTabWidget(QWidget):
11-
def __init__(self, update_func, *args, **kwargs):
12-
super(ConfigTabWidget, self).__init__(*args, **kwargs)
10+
class ConfigPage(QWidget):
11+
name = "SD Plugin Config"
1312

14-
# callback to update all the other widgets
15-
self.update_func = update_func
13+
def __init__(self, *args, **kwargs):
14+
super(ConfigPage, self).__init__(*args, **kwargs)
15+
16+
self.status_bar = StatusBar()
1617

1718
self.base_url = QLineEdit()
1819
self.base_url_reset = QPushButton("Default")
@@ -93,6 +94,7 @@ def __init__(self, update_func, *args, **kwargs):
9394
# scroll_area.setLayout(layout_inner)
9495
# scroll_area.setWidgetResizable(True)
9596
# layout.addWidget(scroll_area)
97+
layout.addWidget(self.status_bar)
9698
layout.addWidget(QLabel("<em>Backend url:</em>"))
9799
layout.addLayout(inline1)
98100
layout.addLayout(self.enc_key)
@@ -138,7 +140,7 @@ def cfg_init(self):
138140
def cfg_connect(self):
139141
self.base_url.textChanged.connect(partial(script.cfg.set, "base_url"))
140142
# NOTE: this triggers on every keystroke; theres no focus lost signal...
141-
self.base_url.textChanged.connect(script.update_config)
143+
self.base_url.textChanged.connect(script.action_update_config)
142144
self.base_url_reset.released.connect(
143145
lambda: self.base_url.setText(DEFAULTS.base_url)
144146
)
@@ -155,17 +157,12 @@ def cfg_connect(self):
155157
self.do_exact_steps.cfg_connect()
156158
self.minimize_ui.cfg_connect()
157159

158-
def update_remote_config():
159-
script.update_config()
160-
self.update_func()
161-
162160
def restore_defaults():
163161
script.restore_defaults()
164162
# retrieve list of available stuff again
165-
script.update_config()
166-
self.update_func()
163+
script.action_update_config()
167164

168-
self.refresh_btn.released.connect(update_remote_config)
165+
self.refresh_btn.released.connect(script.action_update_config)
169166
self.restore_defaults.released.connect(restore_defaults)
170-
# NOTE: crappy workaround because the config system doesnt emit signals
171-
self.minimize_ui.toggled.connect(lambda _: self.update_func())
167+
self.minimize_ui.toggled.connect(lambda _: script.config_updated.emit())
168+
script.status_changed.connect(self.status_bar.set_status)

frontends/krita/krita_diff/pages/img2img.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22

33
from ..script import script
44
from ..widgets import TipsLayout
5-
from .img_base import ImgTabBaseWidget
5+
from .img_base import SDImgPageBase
66

77

8-
class Img2ImgTabWidget(ImgTabBaseWidget):
8+
class Img2ImgPage(SDImgPageBase):
9+
name = "Img2Img"
10+
911
def __init__(self, *args, **kwargs):
10-
super(Img2ImgTabWidget, self).__init__(cfg_prefix="img2img", *args, **kwargs)
12+
super(Img2ImgPage, self).__init__(cfg_prefix="img2img", *args, **kwargs)
1113

1214
self.btn = QPushButton("Start img2img")
1315
self.tips = TipsLayout(
@@ -20,10 +22,10 @@ def __init__(self, *args, **kwargs):
2022
self.layout.addStretch()
2123

2224
def cfg_init(self):
23-
super(Img2ImgTabWidget, self).cfg_init()
25+
super(Img2ImgPage, self).cfg_init()
2426

2527
self.tips.setVisible(not script.cfg("minimize_ui", bool))
2628

2729
def cfg_connect(self):
28-
super(Img2ImgTabWidget, self).cfg_connect()
30+
super(Img2ImgPage, self).cfg_connect()
2931
self.btn.released.connect(lambda: script.action_img2img())

0 commit comments

Comments
 (0)