Skip to content

Commit 9a6c861

Browse files
Make input prompt drag resizable.
1 parent e8f78b9 commit 9a6c861

File tree

2 files changed

+64
-4
lines changed

2 files changed

+64
-4
lines changed

ai_diffusion/ui/region.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from __future__ import annotations
22
from enum import Enum
33
from PyQt5.QtWidgets import QWidget, QLabel, QToolButton, QHBoxLayout, QVBoxLayout, QFrame, QMenu
4-
from PyQt5.QtGui import QGuiApplication, QMouseEvent, QResizeEvent, QPixmap, QImage, QPainter, QIcon
4+
from PyQt5.QtGui import QGuiApplication, QMouseEvent, QResizeEvent, QPixmap, QImage, QPainter, QIcon, QFontMetrics
55
from PyQt5.QtCore import QObject, QEvent, Qt, QMetaObject, QSize, pyqtSignal
66

77
from ..root import root
@@ -123,12 +123,13 @@ def __init__(self, root: RootRegion, parent: QWidget, header=PromptHeader.full):
123123

124124
self._header = QWidget(self)
125125
self._header.setLayout(header_layout)
126-
126+
127127
self.positive = TextPromptWidget(parent=self)
128128
self.positive.line_count = min(settings.prompt_line_count, self._max_lines)
129129
self.positive.install_event_filter(self)
130130

131-
self.negative = TextPromptWidget(line_count=1, is_negative=True, parent=self)
131+
self.negative = TextPromptWidget(line_count=1, is_negative=True, parent=self, resize_handle=True)
132+
self.negative.handle_dragged.connect(self._handle_dragging)
132133
self.negative.install_event_filter(self)
133134

134135
self._no_region = QWidget(self)
@@ -398,6 +399,14 @@ def _layout_language_button(self):
398399
s = QSize(self.fontMetrics().width("EN"), self.fontMetrics().height())
399400
self._language_button.move(pos.x() - s.width() - 2, pos.y() - s.height() - 2)
400401
self._language_button.resize(s)
402+
403+
def _handle_dragging(self, y_pos: int):
404+
new_height = y_pos - self.negative.contentsRect().top() + self.positive.contentsRect().height()
405+
fm = QFontMetrics(ensure(self.positive._multi.document()).defaultFont())
406+
new_line_count = round((new_height - 3) / fm.lineSpacing()) - 1
407+
if 1 <= new_line_count <= 10:
408+
settings.prompt_line_count = new_line_count
409+
self.positive.line_count = new_line_count
401410

402411
def resizeEvent(self, a0):
403412
super().resizeEvent(a0)

ai_diffusion/ui/widget.py

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -440,18 +440,56 @@ def keyPressEvent(self, a0: QKeyEvent | None):
440440
super().keyPressEvent(a0)
441441

442442

443+
class ResizeHandle(QWidget):
444+
"""A small resize handle that appears at the bottom of the prompt widget."""
445+
446+
handle_dragged = pyqtSignal(int)
447+
448+
def __init__(self, parent: QWidget):
449+
super().__init__(parent)
450+
self.setCursor(Qt.CursorShape.SizeVerCursor)
451+
self.setFixedSize(20, 8)
452+
self._dragging = False
453+
self.setVisible(True)
454+
455+
def mousePressEvent(self, event: QMouseEvent | None) -> None:
456+
if ensure(event).button() == Qt.MouseButton.LeftButton:
457+
self._dragging = True
458+
459+
def mouseReleaseEvent(self, event: QMouseEvent | None) -> None:
460+
self._dragging = False
461+
462+
def mouseMoveEvent(self, event: QMouseEvent | None) -> None:
463+
if not self._dragging:
464+
return
465+
y_pos = self.mapToParent(ensure(event).pos()).y()
466+
self.handle_dragged.emit(y_pos)
467+
468+
def paintEvent(self, event: QPaintEvent | None) -> None:
469+
if self.isVisible():
470+
painter = QPainter(self)
471+
painter.setPen(self.palette().color(QPalette.ColorRole.Mid))
472+
painter.setBrush(painter.pen().color())
473+
w, h = self.width(), self.height()
474+
for i, x in enumerate(range(1, w, 3)):
475+
y = 2*h//3 if i % 2 == 0 else h//3
476+
painter.drawEllipse(x-1, y-1, 2, 2)
477+
478+
443479
class TextPromptWidget(QFrame):
444480
"""Wraps a single or multi-line text widget, with ability to switch between them.
445481
Using QPlainTextEdit set to a single line doesn't work properly because it still
446482
scrolls to the next line when eg. selecting and then looks like it's empty."""
447483

448484
activated = pyqtSignal()
449485
text_changed = pyqtSignal(str)
486+
handle_dragged = pyqtSignal(int)
450487

451488
_line_count = 2
452489
_is_negative = False
490+
_resize_handle: ResizeHandle = None
453491

454-
def __init__(self, line_count=2, is_negative=False, parent=None):
492+
def __init__(self, line_count=2, is_negative=False, parent=None, resize_handle=False):
455493
super().__init__(parent)
456494
self._line_count = line_count
457495
self._is_negative = is_negative
@@ -474,6 +512,10 @@ def __init__(self, line_count=2, is_negative=False, parent=None):
474512
self._layout.addWidget(self._multi)
475513
self._layout.addWidget(self._single)
476514

515+
if resize_handle:
516+
self._resize_handle = ResizeHandle(self)
517+
self._resize_handle.handle_dragged.connect(self.handle_dragged)
518+
477519
palette: QPalette = self._multi.palette()
478520
self._base_color = palette.color(QPalette.ColorRole.Base)
479521
self.is_negative = self._is_negative
@@ -510,6 +552,15 @@ def line_count(self, value: int):
510552
if self._line_count > 1:
511553
self._multi.line_count = self._line_count
512554

555+
def resizeEvent(self, event):
556+
super().resizeEvent(event)
557+
if self._resize_handle:
558+
rect = self.geometry()
559+
self._resize_handle.move(
560+
(rect.width() - self._resize_handle.width()) // 2,
561+
rect.height() - self._resize_handle.height()
562+
)
563+
513564
@property
514565
def is_negative(self):
515566
return self._is_negative

0 commit comments

Comments
 (0)