aboutsummaryrefslogtreecommitdiff
path: root/components
diff options
context:
space:
mode:
Diffstat (limited to 'components')
-rw-r--r--components/__base__.py47
-rw-r--r--components/color.py27
-rw-r--r--components/image.py40
-rw-r--r--components/image.ui68
-rw-r--r--components/original.py16
-rw-r--r--components/text.py17
-rw-r--r--components/video.py119
-rw-r--r--components/video.ui50
8 files changed, 323 insertions, 61 deletions
diff --git a/components/__base__.py b/components/__base__.py
index 4fdf31f..88f22d4 100644
--- a/components/__base__.py
+++ b/components/__base__.py
@@ -1,7 +1,18 @@
-from PyQt4 import QtGui
+from PyQt4 import QtGui, QtCore
+from PIL import Image
-class Component:
+class Component(QtCore.QObject):
+ '''A base class for components to inherit from'''
+
+ # modified = QtCore.pyqtSignal(int, bool)
+
+ def __init__(self, moduleIndex, compPos):
+ super().__init__()
+ self.currentPreset = None
+ self.moduleIndex = moduleIndex
+ self.compPos = compPos
+
def __str__(self):
return self.__doc__
@@ -10,18 +21,38 @@ class Component:
return 1
def cancel(self):
- # make sure your component responds to these variables in frameRender()
+ # please stop any lengthy process in response to this variable
self.canceled = True
def reset(self):
self.canceled = False
+ def update(self):
+ self.modified.emit(self.compPos, self.savePreset())
+ # read your widget values, then call super().update()
+
+ def loadPreset(self, presetDict, presetName):
+ '''Children should take (presetDict, presetName=None) as args'''
+
+ # Use super().loadPreset(presetDict, presetName)
+ # Then update your widgets using the preset dict
+ self.currentPreset = presetName \
+ if presetName != None else presetDict['preset']
+ '''
+ def savePreset(self):
+ return {}
+ '''
def preFrameRender(self, **kwargs):
for var, value in kwargs.items():
exec('self.%s = value' % var)
+ def blankFrame(self, width, height):
+ return Image.new("RGBA", (width, height), (0, 0, 0, 0))
+
def pickColor(self):
- color = QtGui.QColorDialog.getColor()
+ dialog = QtGui.QColorDialog()
+ dialog.setOption(QtGui.QColorDialog.ShowAlphaChannel, True)
+ color = dialog.getColor()
if color.isValid():
RGBstring = '%s,%s,%s' % (
str(color.red()), str(color.green()), str(color.blue()))
@@ -57,7 +88,7 @@ class Component:
return page
def update(self):
- # read widget values
+ super().update()
self.parent.drawPreview()
def previewRender(self, previewWorker):
@@ -72,12 +103,6 @@ class Component:
image = Image.new("RGBA", (width, height), (0,0,0,0))
return image
- def loadPreset(self, presetDict):
- # update widgets using a preset dict
-
- def savePreset(self):
- return {}
-
def cancel(self):
self.canceled = True
diff --git a/components/color.py b/components/color.py
index b050fbd..36f3906 100644
--- a/components/color.py
+++ b/components/color.py
@@ -7,6 +7,9 @@ from . import __base__
class Component(__base__.Component):
'''Color'''
+
+ modified = QtCore.pyqtSignal(int, dict)
+
def widget(self, parent):
self.parent = parent
page = uic.loadUi(os.path.join(
@@ -20,14 +23,14 @@ class Component(__base__.Component):
page.lineEdit_color1.setText('%s,%s,%s' % self.color1)
page.lineEdit_color2.setText('%s,%s,%s' % self.color2)
- btnStyle = "QPushButton { background-color : %s; outline: none; }" \
+ btnStyle1 = "QPushButton { background-color : %s; outline: none; }" \
% QColor(*self.color1).name()
- btnStyle = "QPushButton { background-color : %s; outline: none; }" \
+ btnStyle2 = "QPushButton { background-color : %s; outline: none; }" \
% QColor(*self.color2).name()
- page.pushButton_color1.setStyleSheet(btnStyle)
- page.pushButton_color2.setStyleSheet(btnStyle)
+ page.pushButton_color1.setStyleSheet(btnStyle1)
+ page.pushButton_color2.setStyleSheet(btnStyle2)
page.pushButton_color1.clicked.connect(lambda: self.pickColor(1))
page.pushButton_color2.clicked.connect(lambda: self.pickColor(2))
@@ -50,6 +53,7 @@ class Component(__base__.Component):
self.x = self.page.spinBox_x.value()
self.y = self.page.spinBox_y.value()
self.parent.drawPreview()
+ super().update()
def previewRender(self, previewWorker):
width = int(previewWorker.core.settings.value('outputWidth'))
@@ -67,23 +71,26 @@ class Component(__base__.Component):
def drawFrame(self, width, height):
r, g, b = self.color1
- return Image.new("RGBA", (width, height), (r, g, b, 255))
+ return self.blankFrame(width, height)
+
+ def loadPreset(self, pr, presetName=None):
+ super().loadPreset(pr, presetName)
- def loadPreset(self, pr):
self.page.lineEdit_color1.setText('%s,%s,%s' % pr['color1'])
self.page.lineEdit_color2.setText('%s,%s,%s' % pr['color2'])
- btnStyle = "QPushButton { background-color : %s; outline: none; }" \
+ btnStyle1 = "QPushButton { background-color : %s; outline: none; }" \
% QColor(*pr['color1']).name()
- btnStyle = "QPushButton { background-color : %s; outline: none; }" \
+ btnStyle2 = "QPushButton { background-color : %s; outline: none; }" \
% QColor(*pr['color2']).name()
- self.page.pushButton_color1.setStyleSheet(btnStyle)
- self.page.pushButton_color2.setStyleSheet(btnStyle)
+ self.page.pushButton_color1.setStyleSheet(btnStyle1)
+ self.page.pushButton_color2.setStyleSheet(btnStyle2)
def savePreset(self):
return {
+ 'preset': self.currentPreset,
'color1': self.color1,
'color2': self.color2,
}
diff --git a/components/image.py b/components/image.py
index f9a92ca..b6aa29b 100644
--- a/components/image.py
+++ b/components/image.py
@@ -6,6 +6,9 @@ from . import __base__
class Component(__base__.Component):
'''Image'''
+
+ modified = QtCore.pyqtSignal(int, dict)
+
def widget(self, parent):
self.parent = parent
self.settings = parent.settings
@@ -17,15 +20,25 @@ class Component(__base__.Component):
page.lineEdit_image.textChanged.connect(self.update)
page.pushButton_image.clicked.connect(self.pickImage)
+ page.spinBox_scale.valueChanged.connect(self.update)
+ page.checkBox_stretch.stateChanged.connect(self.update)
+ page.spinBox_x.valueChanged.connect(self.update)
+ page.spinBox_y.valueChanged.connect(self.update)
self.page = page
return page
def update(self):
self.imagePath = self.page.lineEdit_image.text()
+ self.scale = self.page.spinBox_scale.value()
+ self.xPosition = self.page.spinBox_x.value()
+ self.yPosition = self.page.spinBox_y.value()
+ self.stretched = self.page.checkBox_stretch.isChecked()
self.parent.drawPreview()
+ super().update()
def previewRender(self, previewWorker):
+ self.imageFormats = previewWorker.core.imageFormats
width = int(previewWorker.core.settings.value('outputWidth'))
height = int(previewWorker.core.settings.value('outputHeight'))
return self.drawFrame(width, height)
@@ -40,27 +53,42 @@ class Component(__base__.Component):
return self.drawFrame(width, height)
def drawFrame(self, width, height):
- frame = Image.new("RGBA", (width, height), (0, 0, 0, 0))
+ frame = self.blankFrame(width, height)
if self.imagePath and os.path.exists(self.imagePath):
image = Image.open(self.imagePath)
- if image.size != (width, height):
+ if self.stretched and image.size != (width, height):
image = image.resize((width, height), Image.ANTIALIAS)
- frame.paste(image)
+ if self.scale != 100:
+ newHeight = int((image.height / 100) * self.scale)
+ newWidth = int((image.width / 100) * self.scale)
+ image = image.resize((newWidth, newHeight), Image.ANTIALIAS)
+ frame.paste(image, box=(self.xPosition, self.yPosition))
return frame
- def loadPreset(self, pr):
+ def loadPreset(self, pr, presetName=None):
+ super().loadPreset(pr, presetName)
self.page.lineEdit_image.setText(pr['image'])
+ self.page.spinBox_scale.setValue(pr['scale'])
+ self.page.spinBox_x.setValue(pr['x'])
+ self.page.spinBox_y.setValue(pr['y'])
+ self.page.checkBox_stretch.setChecked(pr['stretched'])
def savePreset(self):
return {
+ 'preset': self.currentPreset,
'image': self.imagePath,
+ 'scale': self.scale,
+ 'stretched': self.stretched,
+ 'x': self.xPosition,
+ 'y': self.yPosition,
}
def pickImage(self):
imgDir = self.settings.value("backgroundDir", os.path.expanduser("~"))
filename = QtGui.QFileDialog.getOpenFileName(
- self.page, "Choose Image", imgDir, "Image Files (*.jpg *.png)")
- if filename:
+ self.page, "Choose Image", imgDir,
+ "Image Files (%s)" % " ".join(self.imageFormats))
+ if filename:
self.settings.setValue("backgroundDir", os.path.dirname(filename))
self.page.lineEdit_image.setText(filename)
self.update()
diff --git a/components/image.ui b/components/image.ui
index 3cd5b1b..6df03a5 100644
--- a/components/image.ui
+++ b/components/image.ui
@@ -124,8 +124,11 @@
<height>16777215</height>
</size>
</property>
+ <property name="minimum">
+ <number>-10000</number>
+ </property>
<property name="maximum">
- <number>999999999</number>
+ <number>10000</number>
</property>
</widget>
</item>
@@ -163,10 +166,10 @@
</size>
</property>
<property name="minimum">
- <number>0</number>
+ <number>-1000</number>
</property>
<property name="maximum">
- <number>999999999</number>
+ <number>1000</number>
</property>
<property name="value">
<number>0</number>
@@ -178,6 +181,65 @@
</layout>
</item>
<item>
+ <layout class="QHBoxLayout" name="horizontalLayout_9">
+ <item>
+ <widget class="QCheckBox" name="checkBox_stretch">
+ <property name="text">
+ <string>Stretch</string>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_10">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>5</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Scale</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="spinBox_scale">
+ <property name="buttonSymbols">
+ <enum>QAbstractSpinBox::UpDownArrows</enum>
+ </property>
+ <property name="suffix">
+ <string>%</string>
+ </property>
+ <property name="minimum">
+ <number>10</number>
+ </property>
+ <property name="maximum">
+ <number>400</number>
+ </property>
+ <property name="value">
+ <number>100</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
diff --git a/components/original.py b/components/original.py
index 4d0e83b..5e2f9d4 100644
--- a/components/original.py
+++ b/components/original.py
@@ -1,9 +1,8 @@
import numpy
from PIL import Image, ImageDraw
-from PyQt4 import uic, QtGui
+from PyQt4 import uic, QtGui, QtCore
from PyQt4.QtGui import QColor
import os
-import random
from . import __base__
import time
from copy import copy
@@ -11,6 +10,9 @@ from copy import copy
class Component(__base__.Component):
'''Original Audio Visualization'''
+
+ modified = QtCore.pyqtSignal(int, dict)
+
def widget(self, parent):
self.parent = parent
self.visColor = (255, 255, 255)
@@ -36,8 +38,11 @@ class Component(__base__.Component):
self.layout = self.page.comboBox_visLayout.currentIndex()
self.visColor = self.RGBFromString(self.page.lineEdit_visColor.text())
self.parent.drawPreview()
+ super().update()
+
+ def loadPreset(self, pr, presetName=None):
+ super().loadPreset(pr, presetName)
- def loadPreset(self, pr):
self.page.lineEdit_visColor.setText('%s,%s,%s' % pr['visColor'])
btnStyle = "QPushButton { background-color : %s; outline: none; }" \
% QColor(*pr['visColor']).name()
@@ -46,6 +51,7 @@ class Component(__base__.Component):
def savePreset(self):
return {
+ 'preset': self.currentPreset,
'layout': self.layout,
'visColor': self.visColor,
}
@@ -139,7 +145,7 @@ class Component(__base__.Component):
bF = width / 64
bH = bF / 2
bQ = bF / 4
- imTop = Image.new("RGBA", (width, height), (0, 0, 0, 0))
+ imTop = self.blankFrame(width, height)
draw = ImageDraw.Draw(imTop)
r, g, b = color
color2 = (r, g, b, 125)
@@ -157,7 +163,7 @@ class Component(__base__.Component):
imBottom = imTop.transpose(Image.FLIP_TOP_BOTTOM)
- im = Image.new("RGBA", (width, height), (0, 0, 0, 0))
+ im = self.blankFrame(width, height)
if layout == 0:
y = 0 - int(height/100*43)
diff --git a/components/text.py b/components/text.py
index 6cdc0dd..f8ef7b3 100644
--- a/components/text.py
+++ b/components/text.py
@@ -9,8 +9,11 @@ from . import __base__
class Component(__base__.Component):
'''Title Text'''
- def __init__(self):
- super().__init__()
+
+ modified = QtCore.pyqtSignal(int, dict)
+
+ def __init__(self, *args):
+ super().__init__(*args)
self.titleFont = QFont()
def widget(self, parent):
@@ -31,7 +34,7 @@ class Component(__base__.Component):
page.comboBox_textAlign.addItem("Right")
page.lineEdit_textColor.setText('%s,%s,%s' % self.textColor)
- page.pushButton_textColor.clicked.connect(lambda: self.pickColor())
+ page.pushButton_textColor.clicked.connect(self.pickColor)
btnStyle = "QPushButton { background-color : %s; outline: none; }" \
% QColor(*self.textColor).name()
page.pushButton_textColor.setStyleSheet(btnStyle)
@@ -62,6 +65,7 @@ class Component(__base__.Component):
self.textColor = self.RGBFromString(
self.page.lineEdit_textColor.text())
self.parent.drawPreview()
+ super().update()
def getXY(self):
'''Returns true x, y after considering alignment settings'''
@@ -78,7 +82,9 @@ class Component(__base__.Component):
x = self.xPosition - offset
return x, self.yPosition
- def loadPreset(self, pr):
+ def loadPreset(self, pr, presetName=None):
+ super().loadPreset(pr, presetName)
+
self.page.lineEdit_title.setText(pr['title'])
font = QFont()
font.fromString(pr['titleFont'])
@@ -94,6 +100,7 @@ class Component(__base__.Component):
def savePreset(self):
return {
+ 'preset': self.currentPreset,
'title': self.title,
'titleFont': self.titleFont.toString(),
'alignment': self.alignment,
@@ -119,7 +126,7 @@ class Component(__base__.Component):
def addText(self, width, height):
x, y = self.getXY()
- im = Image.new("RGBA", (width, height), (0, 0, 0, 0))
+ im = self.blankFrame(width, height)
image = ImageQt(im)
painter = QPainter(image)
diff --git a/components/video.py b/components/video.py
index b28b81e..3d43a18 100644
--- a/components/video.py
+++ b/components/video.py
@@ -5,12 +5,22 @@ import subprocess
import threading
from queue import PriorityQueue
from . import __base__
-
+
+
class Video:
'''Video Component Frame-Fetcher'''
def __init__(self, **kwargs):
- mandatoryArgs = ['ffmpeg', 'videoPath', 'width', 'height',
- 'frameRate', 'chunkSize', 'parent']
+ mandatoryArgs = [
+ 'ffmpeg', # path to ffmpeg, usually core.FFMPEG_BIN
+ 'videoPath',
+ 'width',
+ 'height',
+ 'scale', # percentage scale
+ 'frameRate', # frames per second
+ 'chunkSize', # number of bytes in one frame
+ 'parent', # mainwindow object
+ 'component', # component object
+ ]
for arg in mandatoryArgs:
try:
exec('self.%s = kwargs[arg]' % arg)
@@ -31,7 +41,8 @@ class Video:
'-i', self.videoPath,
'-f', 'image2pipe',
'-pix_fmt', 'rgba',
- '-filter:v', 'scale='+str(self.width)+':'+str(self.height),
+ '-filter:v', 'scale=%s:%s' %
+ scale(self.scale, self.width, self.height, str),
'-vcodec', 'rawvideo', '-',
]
@@ -50,7 +61,9 @@ class Video:
while True:
if num in self.finishedFrames:
image = self.finishedFrames.pop(num)
- return Image.frombytes('RGBA', (self.width, self.height), image)
+ return finalizeFrame(
+ self.component, image, self.width, self.height)
+
i, image = self.frameBuffer.get()
self.finishedFrames[i] = image
self.frameBuffer.task_done()
@@ -78,6 +91,9 @@ class Video:
class Component(__base__.Component):
'''Video'''
+
+ modified = QtCore.pyqtSignal(int, dict)
+
def widget(self, parent):
self.parent = parent
self.settings = parent.settings
@@ -93,6 +109,10 @@ class Component(__base__.Component):
page.lineEdit_video.textChanged.connect(self.update)
page.pushButton_video.clicked.connect(self.pickVideo)
page.checkBox_loop.stateChanged.connect(self.update)
+ page.checkBox_distort.stateChanged.connect(self.update)
+ page.spinBox_scale.valueChanged.connect(self.update)
+ page.spinBox_x.valueChanged.connect(self.update)
+ page.spinBox_y.valueChanged.connect(self.update)
self.page = page
return page
@@ -100,15 +120,21 @@ class Component(__base__.Component):
def update(self):
self.videoPath = self.page.lineEdit_video.text()
self.loopVideo = self.page.checkBox_loop.isChecked()
+ self.distort = self.page.checkBox_distort.isChecked()
+ self.scale = self.page.spinBox_scale.value()
+ self.xPosition = self.page.spinBox_x.value()
+ self.yPosition = self.page.spinBox_y.value()
self.parent.drawPreview()
+ super().update()
def previewRender(self, previewWorker):
+ self.videoFormats = previewWorker.core.videoFormats
width = int(previewWorker.core.settings.value('outputWidth'))
height = int(previewWorker.core.settings.value('outputHeight'))
- self.chunkSize = 4*width*height
+ self.updateChunksize(width, height)
frame = self.getPreviewFrame(width, height)
if not frame:
- return Image.new("RGBA", (width, height), (0, 0, 0, 0))
+ return self.blankFrame(width, height)
else:
return frame
@@ -116,32 +142,49 @@ class Component(__base__.Component):
super().preFrameRender(**kwargs)
width = int(self.worker.core.settings.value('outputWidth'))
height = int(self.worker.core.settings.value('outputHeight'))
- self.chunkSize = 4*width*height
+ self.blankFrame_ = self.blankFrame(width, height)
+ self.updateChunksize(width, height)
self.video = Video(
ffmpeg=self.parent.core.FFMPEG_BIN, videoPath=self.videoPath,
width=width, height=height, chunkSize=self.chunkSize,
frameRate=int(self.settings.value("outputFrameRate")),
- parent=self.parent, loopVideo=self.loopVideo
- )
+ parent=self.parent, loopVideo=self.loopVideo,
+ component=self, scale=self.scale
+ ) if os.path.exists(self.videoPath) else None
def frameRender(self, moduleNo, arrayNo, frameNo):
- return self.video.frame(frameNo)
+ if self.video:
+ return self.video.frame(frameNo)
+ else:
+ return self.blankFrame_
- def loadPreset(self, pr):
+ def loadPreset(self, pr, presetName=None):
+ super().loadPreset(pr, presetName)
self.page.lineEdit_video.setText(pr['video'])
+ self.page.checkBox_loop.setChecked(pr['loop'])
+ self.page.checkBox_distort.setChecked(pr['distort'])
+ self.page.spinBox_scale.setValue(pr['scale'])
+ self.page.spinBox_x.setValue(pr['x'])
+ self.page.spinBox_y.setValue(pr['y'])
def savePreset(self):
return {
+ 'preset': self.currentPreset,
'video': self.videoPath,
+ 'loop': self.loopVideo,
+ 'distort': self.distort,
+ 'scale': self.scale,
+ 'x': self.xPosition,
+ 'y': self.yPosition,
}
def pickVideo(self):
imgDir = self.settings.value("backgroundDir", os.path.expanduser("~"))
filename = QtGui.QFileDialog.getOpenFileName(
self.page, "Choose Video",
- imgDir, "Video Files (*.mp4 *.mov)"
+ imgDir, "Video Files (%s)" % " ".join(self.videoFormats)
)
- if filename:
+ if filename:
self.settings.setValue("backgroundDir", os.path.dirname(filename))
self.page.lineEdit_video.setText(filename)
self.update()
@@ -149,13 +192,15 @@ class Component(__base__.Component):
def getPreviewFrame(self, width, height):
if not self.videoPath or not os.path.exists(self.videoPath):
return
+
command = [
self.parent.core.FFMPEG_BIN,
'-thread_queue_size', '512',
'-i', self.videoPath,
'-f', 'image2pipe',
'-pix_fmt', 'rgba',
- '-filter:v', 'scale='+str(width)+':'+str(height),
+ '-filter:v', 'scale=%s:%s' %
+ scale(self.scale, width, height, str),
'-vcodec', 'rawvideo', '-',
'-ss', '90',
'-vframes', '1',
@@ -165,7 +210,47 @@ class Component(__base__.Component):
stderr=subprocess.DEVNULL, bufsize=10**8
)
byteFrame = pipe.stdout.read(self.chunkSize)
- image = Image.frombytes('RGBA', (width, height), byteFrame)
+ frame = finalizeFrame(self, byteFrame, width, height)
pipe.stdout.close()
pipe.kill()
- return image
+
+ return frame
+
+ def updateChunksize(self, width, height):
+ if self.scale != 100 and not self.distort:
+ width, height = scale(self.scale, width, height, int)
+ self.chunkSize = 4*width*height
+
+def scale(scale, width, height, returntype=None):
+ width = (float(width) / 100.0) * float(scale)
+ height = (float(height) / 100.0) * float(scale)
+ if returntype == str:
+ return (str(int(width)), str(int(height)))
+ elif returntype == int:
+ return (int(width), int(height))
+ else:
+ return (width, height)
+
+def finalizeFrame(self, imageData, width, height):
+ if self.distort:
+ try:
+ image = Image.frombytes(
+ 'RGBA',
+ (width, height),
+ imageData)
+ except ValueError:
+ print('#### ignored invalid data caused by distortion ####')
+ image = self.blankFrame(width, height)
+ else:
+ image = Image.frombytes(
+ 'RGBA',
+ scale(self.scale, width, height, int),
+ imageData)
+
+ if self.scale != 100 \
+ or self.xPosition != 0 or self.yPosition != 0:
+ frame = self.blankFrame(width, height)
+ frame.paste(image, box=(self.xPosition, self.yPosition))
+ else:
+ frame = image
+ return frame
diff --git a/components/video.ui b/components/video.ui
index 6a01368..f05e8a5 100644
--- a/components/video.ui
+++ b/components/video.ui
@@ -111,7 +111,7 @@
</widget>
</item>
<item>
- <widget class="QSpinBox" name="spinBox_x_2">
+ <widget class="QSpinBox" name="spinBox_x">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
@@ -124,8 +124,11 @@
<height>16777215</height>
</size>
</property>
+ <property name="minimum">
+ <number>-10000</number>
+ </property>
<property name="maximum">
- <number>999999999</number>
+ <number>10000</number>
</property>
</widget>
</item>
@@ -163,10 +166,10 @@
</size>
</property>
<property name="minimum">
- <number>0</number>
+ <number>-10000</number>
</property>
<property name="maximum">
- <number>999999999</number>
+ <number>10000</number>
</property>
<property name="value">
<number>0</number>
@@ -202,6 +205,42 @@
</property>
</spacer>
</item>
+ <item>
+ <widget class="QCheckBox" name="checkBox_distort">
+ <property name="text">
+ <string>Distort by scale</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Scale</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="spinBox_scale">
+ <property name="buttonSymbols">
+ <enum>QAbstractSpinBox::UpDownArrows</enum>
+ </property>
+ <property name="suffix">
+ <string>%</string>
+ </property>
+ <property name="minimum">
+ <number>10</number>
+ </property>
+ <property name="maximum">
+ <number>400</number>
+ </property>
+ <property name="value">
+ <number>100</number>
+ </property>
+ </widget>
+ </item>
</layout>
</item>
<item>
@@ -217,6 +256,9 @@
</property>
</spacer>
</item>
+ <item>
+ <widget class="QWidget" name="widget" native="true"/>
+ </item>
</layout>
</widget>
<resources/>