2025-03-07 08:03:18 +01:00

211 lines
7.3 KiB
Python

"""
Plugin for Krita UI Redesign, Copyright (C) 2020 Kapyia, Pedro Reis
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
from PyQt5.QtWidgets import QWidget, QToolButton, QDockWidget, QVBoxLayout, QSizePolicy, QScrollArea
from PyQt5.QtCore import Qt, QSize, QPoint
from .ntscrollareacontainer import ntScrollAreaContainer
from .nttogglevisiblebutton import ntToggleVisibleButton
from krita import Krita
class ntWidgetPad(QWidget):
"""
An on-canvas toolbox widget. I'm dubbing widgets that 'float'
on top of the canvas '(lily) pads' for the time being :) """
def __init__(self, parent):
super(ntWidgetPad, self).__init__(parent)
self.setAttribute(Qt.WA_DeleteOnClose)
self.setWindowFlags(
Qt.WindowStaysOnTopHint |
Qt.FramelessWindowHint
)
self.setLayout(QVBoxLayout())
self.layout().setContentsMargins(4,4,4,4)
self.alignment = 'left'
# Members to hold a borrowed widget and it's original parent docker for returning
self.widget = None
self.widgetDocker = None
# Visibility toggle
self.btnHide = ntToggleVisibleButton()
self.btnHide.clicked.connect(self.toggleWidgetVisible)
self.layout().addWidget(self.btnHide)
def activeView(self):
"""
Get the View widget of the active subwindow."""
subWin = self.parentWidget().activeSubWindow()
if subWin:
for child in subWin.children():
if 'view' in child.objectName(): # Grab the View from the active tab/sub-window
return child
def adjustToView(self):
"""
Adjust the position and size of the Pad to that of the active View."""
view = self.activeView()
if view:
self.resizeToView()
globalTargetPos = QPoint()
if self.alignment == 'left':
globalTargetPos = view.mapToGlobal(QPoint(0,0))
elif self.alignment == 'right':
globalTargetPos = view.mapToGlobal(QPoint(view.width() - self.width() - self.scrollBarMargin(), 0))
self.move(self.parentWidget().mapFromGlobal(globalTargetPos))
def borrowDocker(self, docker):
"""
Borrow a docker widget from Krita's existing list of dockers and
returns True. Returns False if invalid widget was passed."""
# Does requested widget exist?
if isinstance(docker, QDockWidget) and docker.widget():
# Return any previous widget to its original docker
self.returnDocker()
self.widgetDocker = docker
if isinstance(docker.widget(), QScrollArea):
self.widget = ntScrollAreaContainer(docker.widget())
else:
self.widget = docker.widget()
self.layout().addWidget(self.widget)
self.adjustToView()
self.widgetDocker.hide()
return True
return False
def closeEvent(self, e):
"""
Since the plugins works by borrowing the actual docker
widget we need to ensure its returned upon closing the pad"""
self.returnDocker()
return super().closeEvent(e)
def paintEvent(self, e):
"""
Needed to resize the Pad if the user decides to
change the icon size of the toolbox"""
self.adjustToView()
return super().paintEvent(e)
def resizeToView(self):
"""
Resize the Pad to an appropriate size that fits within the subwindow."""
view = self.activeView()
if view:
### GOAL: REMOVE THIS IF-STATEMENT
if isinstance(self.widget, ntScrollAreaContainer):
containerSize = self.widget.sizeHint()
if view.height() < containerSize.height() + self.btnHide.height() + 14 + self.scrollBarMargin():
containerSize.setHeight(view.height() - self.btnHide.height() - 14 - self.scrollBarMargin())
if view.width() < containerSize.width() + 8 + self.scrollBarMargin():
containerSize.setWidth(view.width() - 8 - self.scrollBarMargin())
self.widget.setFixedSize(containerSize)
newSize = self.sizeHint()
if view.height() < newSize.height():
newSize.setHeight(view.height())
if view.width() < newSize.width():
newSize.setWidth(view.width())
self.resize(newSize)
def returnDocker(self):
"""
Return the borrowed docker to it's original QDockWidget"""
# Ensure there's a widget to return
if self.widget:
if isinstance(self.widget, ntScrollAreaContainer):
self.widgetDocker.setWidget(self.widget.scrollArea())
else:
self.widgetDocker.setWidget(self.widget)
self.widgetDocker.show()
self.widget = None
self.widgetDocker = None
def scrollBarMargin(self):
if Krita.instance().readSetting("", "hideScrollbars", "false") == "true":
return 0
return 14 # Canvas crollbar pixel width/height on Windows
def setViewAlignment(self, newAlignment):
"""
Set the Pad's alignment to the view to either 'left' or 'right'.
Returns False if the argument is an invalid value."""
if isinstance(newAlignment, str):
if (newAlignment.lower() == 'left' or
newAlignment.lower() == 'right'):
self.alignment = newAlignment.lower()
self.btnHide.setArrow(self.alignment)
return True
return False
def toggleWidgetVisible(self, value=None):
if not value:
value = not self.widget.isVisible()
self.widget.setVisible(value)
self.adjustToView()
self.updateHideButtonIcon(value)
def updateHideButtonIcon(self, isVisible):
"""
Flip the direction of the arrow to fit the Pads current visibility"""
if self.alignment == 'left':
if isVisible:
self.btnHide.setArrowType(Qt.ArrowType.LeftArrow)
else:
self.btnHide.setArrowType(Qt.ArrowType.RightArrow)
elif self.alignment == 'right':
if isVisible:
self.btnHide.setArrowType(Qt.ArrowType.RightArrow)
else:
self.btnHide.setArrowType(Qt.ArrowType.LeftArrow)
def getViewAlignment(self):
return self.alignment