1994 lines
101 KiB
Diff
1994 lines
101 KiB
Diff
From a3088503500e79877ce985e4784f75478d9b792e Mon Sep 17 00:00:00 2001
|
|
From: "FeRD (Frank Dana)" <ferdnyc@gmail.com>
|
|
Date: Mon, 20 Sep 2021 05:36:19 -0400
|
|
Subject: [PATCH 1/6] Preferences: Fix logging calls
|
|
|
|
---
|
|
src/launch.py | 2 +-
|
|
src/windows/preferences.py | 18 +++++++++++-------
|
|
2 files changed, 12 insertions(+), 8 deletions(-)
|
|
|
|
diff --git a/src/launch.py b/src/launch.py
|
|
index 9fc600b23..b614e9bc7 100755
|
|
--- a/src/launch.py
|
|
+++ b/src/launch.py
|
|
@@ -41,7 +41,7 @@
|
|
"""
|
|
|
|
import sys
|
|
-import os.path
|
|
+import os
|
|
import argparse
|
|
|
|
from PyQt5.QtCore import Qt
|
|
diff --git a/src/windows/preferences.py b/src/windows/preferences.py
|
|
index bf7d67b0c..325f496b3 100644
|
|
--- a/src/windows/preferences.py
|
|
+++ b/src/windows/preferences.py
|
|
@@ -102,7 +102,7 @@ def __init__(self):
|
|
|
|
def txtSearch_changed(self):
|
|
"""textChanged event handler for search box"""
|
|
- log.info("Search for %s" % self.txtSearch.text())
|
|
+ log.info("Search for %s", self.txtSearch.text())
|
|
|
|
# Populate preferences
|
|
self.Populate(filter=self.txtSearch.text())
|
|
@@ -317,7 +317,7 @@ def Populate(self, filter=""):
|
|
value_list.remove(value_item)
|
|
|
|
# Remove hardware mode items which cannot decode the example video
|
|
- log.debug("Preparing to test hardware decoding: %s" % (value_list))
|
|
+ log.debug("Preparing to test hardware decoding: %s", value_list)
|
|
for value_item in list(value_list):
|
|
v = value_item["value"]
|
|
if (not self.testHardwareDecode(value_list, v, 0)
|
|
@@ -470,7 +470,7 @@ def bool_value_changed(self, widget, param, state):
|
|
# Trigger specific actions
|
|
if param["setting"] == "debug-mode":
|
|
# Update debug setting of timeline
|
|
- log.info("Setting debug-mode to %s" % (state == Qt.Checked))
|
|
+ log.info("Setting debug-mode to %s", state == Qt.Checked)
|
|
debug_enabled = (state == Qt.Checked)
|
|
|
|
# Enable / Disable logger
|
|
@@ -528,7 +528,9 @@ def text_value_changed(self, widget, param, value=None):
|
|
if param.get("category") == "Keyboard":
|
|
previous_value = value
|
|
value = QKeySequence(value).toString()
|
|
- log.info("Parsing keyboard mapping via QKeySequence from %s to %s" % (previous_value, value))
|
|
+ log.info(
|
|
+ "Parsing keyboard mapping via QKeySequence from %s to %s",
|
|
+ previous_value, value)
|
|
|
|
# Save setting
|
|
self.s.set(param["setting"], value)
|
|
@@ -604,11 +606,13 @@ def testHardwareDecode(self, all_decoders, decoder, decoder_card="0"):
|
|
if reader.GetFrame(0).CheckPixel(0, 0, 2, 133, 255, 255, 5):
|
|
is_supported = True
|
|
self.hardware_tests_cards[decoder_card].append(int(decoder))
|
|
- log.debug("Successful hardware decoder! %s (%s-%s)" % (decoder_name, decoder, decoder_card))
|
|
+ log.debug(
|
|
+ "Successful hardware decoder! %s (%s-%s)",
|
|
+ decoder_name, decoder, decoder_card)
|
|
else:
|
|
log.debug(
|
|
"CheckPixel failed testing hardware decoding (i.e. wrong color found): %s (%s-%s)",
|
|
- (decoder_name, decoder, decoder_card))
|
|
+ decoder_name, decoder, decoder_card)
|
|
|
|
reader.Close()
|
|
clip.Close()
|
|
@@ -616,7 +620,7 @@ def testHardwareDecode(self, all_decoders, decoder, decoder_card="0"):
|
|
except Exception:
|
|
log.debug(
|
|
"Exception trying to test hardware decoding (this is expected): %s (%s-%s)",
|
|
- (decoder_name, decoder, decoder_card))
|
|
+ decoder_name, decoder, decoder_card)
|
|
|
|
# Resume current settings
|
|
openshot.Settings.Instance().HARDWARE_DECODER = current_decoder
|
|
|
|
From 1b14896d2057df80b0b20ba22e1380ba9e9bd6e6 Mon Sep 17 00:00:00 2001
|
|
From: "FeRD (Frank Dana)" <ferdnyc@gmail.com>
|
|
Date: Thu, 4 Nov 2021 21:01:39 -0400
|
|
Subject: [PATCH 2/6] Enforce integer function arguments
|
|
|
|
---
|
|
src/windows/export.py | 8 +-
|
|
src/windows/models/properties_model.py | 34 +-
|
|
src/windows/process_effect.py | 2 +-
|
|
src/windows/video_widget.py | 596 ++++++++++++++--------
|
|
src/windows/views/effects_listview.py | 7 +-
|
|
src/windows/views/effects_treeview.py | 7 +-
|
|
src/windows/views/emojis_listview.py | 7 +-
|
|
src/windows/views/files_listview.py | 7 +-
|
|
src/windows/views/files_treeview.py | 7 +-
|
|
src/windows/views/properties_tableview.py | 38 +-
|
|
src/windows/views/transitions_listview.py | 7 +-
|
|
src/windows/views/transitions_treeview.py | 7 +-
|
|
src/windows/views/tutorial.py | 14 +-
|
|
13 files changed, 476 insertions(+), 265 deletions(-)
|
|
|
|
diff --git a/src/windows/export.py b/src/windows/export.py
|
|
index a624eb2e2..6461afb25 100644
|
|
--- a/src/windows/export.py
|
|
+++ b/src/windows/export.py
|
|
@@ -290,7 +290,7 @@ def updateProgressBar(self, title_message, start_frame, end_frame, current_frame
|
|
percentage_string = format_of_progress_string % (( current_frame - start_frame ) / ( end_frame - start_frame ) * 100)
|
|
else:
|
|
percentage_string = "100%"
|
|
- self.progressExportVideo.setValue(current_frame)
|
|
+ self.progressExportVideo.setValue(int(current_frame))
|
|
self.progressExportVideo.setFormat(percentage_string)
|
|
self.setWindowTitle("%s %s" % (percentage_string, title_message))
|
|
|
|
@@ -690,9 +690,9 @@ def titlestring(sec, fps, mess):
|
|
fps_encode = 0
|
|
|
|
# Init progress bar
|
|
- self.progressExportVideo.setMinimum(self.txtStartFrame.value())
|
|
- self.progressExportVideo.setMaximum(self.txtEndFrame.value())
|
|
- self.progressExportVideo.setValue(self.txtStartFrame.value())
|
|
+ self.progressExportVideo.setMinimum(int(self.txtStartFrame.value()))
|
|
+ self.progressExportVideo.setMaximum(int(self.txtEndFrame.value()))
|
|
+ self.progressExportVideo.setValue(int(self.txtStartFrame.value()))
|
|
|
|
# Prompt error message
|
|
if self.txtStartFrame.value() == self.txtEndFrame.value():
|
|
diff --git a/src/windows/models/properties_model.py b/src/windows/models/properties_model.py
|
|
index c3236ed84..40897f642 100644
|
|
--- a/src/windows/models/properties_model.py
|
|
+++ b/src/windows/models/properties_model.py
|
|
@@ -414,8 +414,8 @@ def value_updated(self, item, interpolation=-1, value=None, interpolation_detail
|
|
new_value = None
|
|
|
|
log.info(
|
|
- "%s for %s changed to %s at frame %s with interpolation: %s at closest x: %s"
|
|
- % (property_key, clip_id, new_value, self.frame_number, interpolation, closest_point_x))
|
|
+ "%s for %s changed to %s at frame %s with interpolation: %s at closest x: %s",
|
|
+ property_key, clip_id, new_value, self.frame_number, interpolation, closest_point_x)
|
|
|
|
# Find this clip
|
|
c = None
|
|
@@ -518,35 +518,35 @@ def value_updated(self, item, interpolation=-1, value=None, interpolation_detail
|
|
try:
|
|
clip_data[property_key] = int(new_value)
|
|
except Exception as ex:
|
|
- log.warn('Invalid Integer value passed to property: %s' % ex)
|
|
+ log.warn('Invalid Integer value passed to property', exc_info=1)
|
|
|
|
elif property_type == "float":
|
|
clip_updated = True
|
|
try:
|
|
clip_data[property_key] = float(new_value)
|
|
except Exception as ex:
|
|
- log.warn('Invalid Float value passed to property: %s' % ex)
|
|
+ log.warn('Invalid Float value passed to property', exc_info=1)
|
|
|
|
elif property_type == "bool":
|
|
clip_updated = True
|
|
try:
|
|
clip_data[property_key] = bool(new_value)
|
|
except Exception as ex:
|
|
- log.warn('Invalid Boolean value passed to property: %s' % ex)
|
|
+ log.warn('Invalid Boolean value passed to property', exc_info=1)
|
|
|
|
elif property_type == "string":
|
|
clip_updated = True
|
|
try:
|
|
clip_data[property_key] = str(new_value)
|
|
- except Exception as ex:
|
|
- log.warn('Invalid String value passed to property: %s' % ex)
|
|
+ except Exception:
|
|
+ log.warn('Invalid String value passed to property', exc_info=1)
|
|
|
|
elif property_type in ["font", "caption"]:
|
|
clip_updated = True
|
|
try:
|
|
clip_data[property_key] = str(new_value)
|
|
- except Exception as ex:
|
|
- log.warn('Invalid Font/Caption value passed to property: %s' % ex)
|
|
+ except Exception:
|
|
+ log.warn('Invalid Font/Caption value passed to property', exc_info=1)
|
|
|
|
elif property_type == "reader":
|
|
# Transition
|
|
@@ -557,8 +557,8 @@ def value_updated(self, item, interpolation=-1, value=None, interpolation_detail
|
|
clip_data[property_key] = json.loads(clip_object.Reader().Json())
|
|
clip_object.Close()
|
|
clip_object = None
|
|
- except Exception as ex:
|
|
- log.warn('Invalid Reader value passed to property: %s (%s)' % (value, ex))
|
|
+ except Exception:
|
|
+ log.warn('Invalid Reader value passed to property: %s (%s)', value, exc_info=1)
|
|
|
|
# Reduce # of clip properties we are saving (performance boost)
|
|
clip_data = {property_key: clip_data.get(property_key)}
|
|
@@ -688,9 +688,9 @@ def set_property(self, property, filter, c, item_type, object_id=None):
|
|
|
|
if type == "color":
|
|
# Color needs to be handled special
|
|
- red = property[1]["red"]["value"]
|
|
- green = property[1]["green"]["value"]
|
|
- blue = property[1]["blue"]["value"]
|
|
+ red = int(property[1]["red"]["value"])
|
|
+ green = int(property[1]["green"]["value"])
|
|
+ blue = int(property[1]["blue"]["value"])
|
|
col.setBackground(QColor(red, green, blue))
|
|
|
|
if readonly or type in ["color", "font", "caption"] or choices or label == "Track":
|
|
@@ -789,9 +789,9 @@ def set_property(self, property, filter, c, item_type, object_id=None):
|
|
|
|
if type == "color":
|
|
# Update the color based on the color curves
|
|
- red = property[1]["red"]["value"]
|
|
- green = property[1]["green"]["value"]
|
|
- blue = property[1]["blue"]["value"]
|
|
+ red = int(property[1]["red"]["value"])
|
|
+ green = int(property[1]["green"]["value"])
|
|
+ blue = int(property[1]["blue"]["value"])
|
|
col.setBackground(QColor(red, green, blue))
|
|
|
|
# Update helper dictionary
|
|
diff --git a/src/windows/process_effect.py b/src/windows/process_effect.py
|
|
index e4f3120c0..ea0c2946e 100644
|
|
--- a/src/windows/process_effect.py
|
|
+++ b/src/windows/process_effect.py
|
|
@@ -352,7 +352,7 @@ def accept(self):
|
|
while(not processing.IsDone() ):
|
|
# update progressbar
|
|
progressionStatus = processing.GetProgress()
|
|
- self.progressBar.setValue(progressionStatus)
|
|
+ self.progressBar.setValue(int(progressionStatus))
|
|
time.sleep(0.01)
|
|
|
|
# Process any queued events
|
|
diff --git a/src/windows/video_widget.py b/src/windows/video_widget.py
|
|
index d5c89a204..f33696c5c 100644
|
|
--- a/src/windows/video_widget.py
|
|
+++ b/src/windows/video_widget.py
|
|
@@ -25,8 +25,11 @@
|
|
along with OpenShot Library. If not, see <http://www.gnu.org/licenses/>.
|
|
"""
|
|
|
|
+import json
|
|
+
|
|
from PyQt5.QtCore import (
|
|
- Qt, QCoreApplication, QPointF, QPoint, QRect, QRectF, QSize, QMutex, QTimer
|
|
+ Qt, QCoreApplication, QMutex, QTimer,
|
|
+ QPoint, QPointF, QSize, QSizeF, QRect, QRectF,
|
|
)
|
|
from PyQt5.QtGui import (
|
|
QTransform, QPainter, QIcon, QColor, QPen, QBrush, QCursor, QImage, QRegion
|
|
@@ -41,8 +44,6 @@
|
|
from classes.app import get_app
|
|
from classes.query import Clip, Effect
|
|
|
|
-import json
|
|
-
|
|
|
|
class VideoWidget(QWidget, updates.UpdateInterface):
|
|
""" A QWidget used on the video display widget """
|
|
@@ -86,37 +87,68 @@ def changed(self, action):
|
|
self.pixel_ratio.ToFloat())
|
|
|
|
|
|
- def drawTransformHandler(self, painter, sx, sy, source_width, source_height, origin_x, origin_y,
|
|
- x1=None, y1=None, x2=None, y2=None, rotation = None):
|
|
+ def drawTransformHandler(
|
|
+ self, painter, sx, sy, source_width, source_height,
|
|
+ origin_x, origin_y,
|
|
+ x1=None, y1=None, x2=None, y2=None, rotation = None
|
|
+ ):
|
|
# Draw transform corners and center origin circle
|
|
# Corner size
|
|
cs = self.cs
|
|
os = 12.0
|
|
|
|
+ csx = cs / sx
|
|
+ csy = cs / sy
|
|
+
|
|
# Rotate the transform handler
|
|
if rotation:
|
|
- bbox_center_x = (((x1*source_width + x2*source_width) / 2.0) ) - ( (os/2) /sx)
|
|
- bbox_center_y = (((y1*source_height + y2*source_height) / 2.0) ) - ( (os/2) /sy)
|
|
+ bbox_center_x = ((x1*source_width + x2*source_width) / 2.0) - ((os / 2) / sx)
|
|
+ bbox_center_y = ((y1*source_height + y2*source_height) / 2.0) - ((os / 2) / sy)
|
|
painter.translate(bbox_center_x, bbox_center_y)
|
|
painter.rotate(rotation)
|
|
painter.translate(-bbox_center_x, -bbox_center_y)
|
|
|
|
- if(x1 and y1 and x2 and y2):
|
|
+ if all([x1, y1, x2, y2]):
|
|
# Calculate bounds of clip
|
|
- self.clipBounds = QRectF(QPointF(x1*source_width, y1*source_height), QPointF(x2*source_width, y2*source_height))
|
|
+ self.clipBounds = QRectF(
|
|
+ QPointF(x1 * source_width, y1 * source_height),
|
|
+ QPointF(x2 * source_width, y2 * source_height)
|
|
+ )
|
|
# Calculate 4 corners coordinates
|
|
- self.topLeftHandle = QRectF(x1*source_width -(cs/sx/2.0), y1*source_height-(cs/sy/2.0), cs/sx, cs/sy)
|
|
- self.topRightHandle = QRectF(x2*source_width-(cs/sx/2.0), y1*source_height-(cs/sy/2.0), cs/sx, cs/sy)
|
|
- self.bottomLeftHandle = QRectF(x1*source_width -(cs/sx/2.0), y2*source_height-(cs/sy/2.0), cs/sx, cs/sy)
|
|
- self.bottomRightHandle = QRectF(x2*source_width-(cs/sx/2.0), y2*source_height-(cs/sy/2.0), cs/sx, cs/sy)
|
|
+ self.topLeftHandle = QRectF(
|
|
+ x1 * source_width - (csx / 2.0),
|
|
+ y1 * source_height - (csy / 2.0),
|
|
+ csx,
|
|
+ csy)
|
|
+ self.topRightHandle = QRectF(
|
|
+ x2 * source_width - (csx / 2.0),
|
|
+ y1 * source_height - (csy / 2.0),
|
|
+ csx,
|
|
+ csy)
|
|
+ self.bottomLeftHandle = QRectF(
|
|
+ x1 * source_width - (csx / 2.0),
|
|
+ y2 * source_height - (csy / 2.0),
|
|
+ csx,
|
|
+ csy)
|
|
+ self.bottomRightHandle = QRectF(
|
|
+ x2 * source_width - (csx / 2.0),
|
|
+ y2 * source_height - (csy / 2.0),
|
|
+ csx,
|
|
+ csy)
|
|
else:
|
|
# Calculate bounds of clip
|
|
- self.clipBounds = QRectF(QPointF(0.0, 0.0), QPointF(source_width, source_height))
|
|
+ self.clipBounds = QRectF(
|
|
+ QPointF(0.0, 0.0),
|
|
+ QPointF(source_width, source_height))
|
|
# Calculate 4 corners coordinates
|
|
- self.topLeftHandle = QRectF(-cs/sx/2.0, -cs/sy/2.0, cs/sx, cs/sy)
|
|
- self.topRightHandle = QRectF(source_width - (cs/sx) + cs/sx/2.0, -cs/sy/2.0, cs/sx, cs/sy)
|
|
- self.bottomLeftHandle = QRectF(-cs/sx/2.0, source_height - (cs/sy) + cs/sy/2.0, cs/sx, cs/sy)
|
|
- self.bottomRightHandle = QRectF(source_width - (cs/sx) + cs/sx/2.0, source_height - (cs/sy) + cs/sy/2.0, cs/sx, cs/sy)
|
|
+ self.topLeftHandle = QRectF(
|
|
+ -csx / 2.0, -csy / 2.0, csx, csy)
|
|
+ self.topRightHandle = QRectF(
|
|
+ source_width - csx / 2.0, -csy / 2.0, csx, csy)
|
|
+ self.bottomLeftHandle = QRectF(
|
|
+ -csx / 2.0, source_height - csy / 2.0, csx, csy)
|
|
+ self.bottomRightHandle = QRectF(
|
|
+ source_width - csx / 2.0, source_height - csy / 2.0, csx, csy)
|
|
|
|
# Draw 4 corners
|
|
pen = QPen(QBrush(QColor("#53a0ed")), 1.5)
|
|
@@ -127,47 +159,110 @@ def drawTransformHandler(self, painter, sx, sy, source_width, source_height, ori
|
|
painter.drawRect(self.bottomLeftHandle)
|
|
painter.drawRect(self.bottomRightHandle)
|
|
|
|
- if(x1 and y1 and x2 and y2):
|
|
+ if all([x1, y1, x2, y2]):
|
|
# Calculate 4 side coordinates
|
|
- self.topHandle = QRectF(((x1*source_width+x2*source_width) / 2.0) - (cs/sx/2.0), (y1*source_height)-cs/sy/2.0, cs/sx, cs/sy)
|
|
- self.bottomHandle = QRectF(((x1*source_width+x2*source_width) / 2.0) - (cs/sx/2.0), (y2*source_height)-( cs/sy/2.0), cs/sx, cs/sy)
|
|
- self.leftHandle = QRectF((x1*source_width)-(cs/sx/2.0), ((y1*source_height+y2*source_height) / 2.0) - (cs/sy/2.0), cs/sx, cs/sy)
|
|
- self.rightHandle = QRectF((x2*source_width) - (cs/sx) + cs/sx/2.0, ((y1*source_height+y2*source_height) / 2.0) - (cs/sy/2.0), cs/sx, cs/sy)
|
|
+ self.topHandle = QRectF(
|
|
+ ((x1 + x2) * source_width - csx) / 2.0,
|
|
+ (y1 * source_height) - csy / 2.0,
|
|
+ csx,
|
|
+ csy)
|
|
+ self.bottomHandle = QRectF(
|
|
+ ((x1 + x2) * source_width - csx) / 2.0,
|
|
+ (y2 * source_height) - csy / 2.0,
|
|
+ csx,
|
|
+ csy)
|
|
+ self.leftHandle = QRectF(
|
|
+ (x1 * source_width) - csx / 2.0,
|
|
+ ((y1 + y2) * source_height - csy) / 2.0,
|
|
+ csx,
|
|
+ csy)
|
|
+ self.rightHandle = QRectF(
|
|
+ (x2 * source_width) - csx / 2.0,
|
|
+ ((y1 + y2) * source_height - csy) / 2.0,
|
|
+ csx, csy)
|
|
|
|
else:
|
|
# Calculate 4 side coordinates
|
|
- self.topHandle = QRectF((source_width / 2.0) - (cs/sx/2.0), -cs/sy/2.0, cs/sx, cs/sy)
|
|
- self.bottomHandle = QRectF((source_width / 2.0) - (cs/sx/2.0), source_height - (cs/sy) + cs/sy/2.0, cs/sx, cs/sy)
|
|
- self.leftHandle = QRectF(-cs/sx/2.0, (source_height / 2.0) - (cs/sy/2.0), cs/sx, cs/sy)
|
|
- self.rightHandle = QRectF(source_width - (cs/sx) + cs/sx/2.0, (source_height / 2.0) - (cs/sy/2.0), cs/sx, cs/sy)
|
|
+ self.topHandle = QRectF(
|
|
+ (source_width - csx) / 2.0,
|
|
+ -csy / 2.0,
|
|
+ csx,
|
|
+ csy)
|
|
+ self.bottomHandle = QRectF(
|
|
+ (source_width - csx) / 2.0,
|
|
+ source_height - (csy / 2.0),
|
|
+ csx,
|
|
+ csy)
|
|
+ self.leftHandle = QRectF(
|
|
+ -csx / 2.0,
|
|
+ (source_height - csy) / 2.0,
|
|
+ csx,
|
|
+ csy)
|
|
+ self.rightHandle = QRectF(
|
|
+ source_width - (csx / 2.0),
|
|
+ (source_height - csy) / 2.0,
|
|
+ csx,
|
|
+ csy)
|
|
|
|
# Calculate shear handles
|
|
- self.topShearHandle = QRectF(self.topLeftHandle.x(), self.topLeftHandle.y(), self.clipBounds.width(), self.topLeftHandle.height())
|
|
- self.leftShearHandle = QRectF(self.topLeftHandle.x(), self.topLeftHandle.y(), self.topLeftHandle.width(), self.clipBounds.height())
|
|
- self.rightShearHandle = QRectF(self.topRightHandle.x(), self.topRightHandle.y(), self.topRightHandle.width(), self.clipBounds.height())
|
|
- self.bottomShearHandle = QRectF(self.bottomLeftHandle.x(), self.bottomLeftHandle.y(), self.clipBounds.width(), self.topLeftHandle.height())
|
|
+ self.topShearHandle = QRectF(
|
|
+ self.topLeftHandle.x(),
|
|
+ self.topLeftHandle.y(),
|
|
+ self.clipBounds.width(),
|
|
+ self.topLeftHandle.height())
|
|
+ self.leftShearHandle = QRectF(
|
|
+ self.topLeftHandle.x(),
|
|
+ self.topLeftHandle.y(),
|
|
+ self.topLeftHandle.width(),
|
|
+ self.clipBounds.height())
|
|
+ self.rightShearHandle = QRectF(
|
|
+ self.topRightHandle.x(),
|
|
+ self.topRightHandle.y(),
|
|
+ self.topRightHandle.width(),
|
|
+ self.clipBounds.height())
|
|
+ self.bottomShearHandle = QRectF(
|
|
+ self.bottomLeftHandle.x(),
|
|
+ self.bottomLeftHandle.y(),
|
|
+ self.clipBounds.width(),
|
|
+ self.topLeftHandle.height())
|
|
|
|
# Draw 4 sides (centered)
|
|
- painter.drawRect(self.topHandle)
|
|
- painter.drawRect(self.bottomHandle)
|
|
- painter.drawRect(self.leftHandle)
|
|
- painter.drawRect(self.rightHandle)
|
|
- painter.drawRect(self.clipBounds)
|
|
+ painter.drawRects([
|
|
+ self.topHandle,
|
|
+ self.bottomHandle,
|
|
+ self.leftHandle,
|
|
+ self.rightHandle,
|
|
+ self.clipBounds,
|
|
+ ])
|
|
|
|
# Calculate center coordinate
|
|
- if(x1 and y1 and x2 and y2):
|
|
+ if all([x1, y1, x2, y2]):
|
|
cs = 5.0
|
|
os = 7.0
|
|
- self.centerHandle = QRectF( (((x1*source_width+x2*source_width) / 2.0) ) - (os/sx), (((y1*source_height+y2*source_height) / 2.0) ) - (os/sy), os/sx*2.0, os/sy*2.0)
|
|
+ self.centerHandle = QRectF(
|
|
+ ((x1 + x2) * source_width / 2.0) - (os / sx),
|
|
+ ((y1 + y2) * source_height / 2.0) - (os / sy),
|
|
+ os / sx * 2.0,
|
|
+ os / sy * 2.0
|
|
+ )
|
|
else:
|
|
- self.centerHandle = QRectF((source_width * origin_x) - (os/sx), (source_height * origin_y) - (os/sy), os/sx*2.0, os/sy*2.0)
|
|
+ self.centerHandle = QRectF(
|
|
+ source_width * origin_x - (os / sx),
|
|
+ source_height * origin_y - (os / sy),
|
|
+ os / sx * 2.0,
|
|
+ os / sy * 2.0)
|
|
|
|
# Draw origin
|
|
painter.drawEllipse(self.centerHandle)
|
|
- painter.drawLine(self.centerHandle.x() + (self.centerHandle.width()/2.0), self.centerHandle.y() + (self.centerHandle.height()/2.0) - self.centerHandle.height(),
|
|
- self.centerHandle.x() + (self.centerHandle.width()/2.0), self.centerHandle.y() + (self.centerHandle.height()/2.0) + self.centerHandle.height())
|
|
- painter.drawLine(self.centerHandle.x() + (self.centerHandle.width()/2.0) - self.centerHandle.width(), self.centerHandle.y() + (self.centerHandle.height()/2.0),
|
|
- self.centerHandle.x() + (self.centerHandle.width()/2.0) + self.centerHandle.width(), self.centerHandle.y() + (self.centerHandle.height()/2.0))
|
|
+
|
|
+ # Draw cross at origin center, extending beyond ellipse by 25%
|
|
+ center = self.centerHandle.center()
|
|
+ halfW = QPointF(self.centerHandle.width() * 0.75, 0)
|
|
+ halfH = QPointF(0, self.centerHandle.height() * 0.75)
|
|
+ painter.drawLines(
|
|
+ center - halfW, center + halfW,
|
|
+ center - halfH, center + halfH,
|
|
+ )
|
|
|
|
# Remove transform
|
|
painter.resetTransform()
|
|
@@ -179,7 +274,11 @@ def paintEvent(self, event, *args):
|
|
|
|
# Paint custom frame image on QWidget
|
|
painter = QPainter(self)
|
|
- painter.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform | QPainter.TextAntialiasing, True)
|
|
+ painter.setRenderHints(
|
|
+ QPainter.Antialiasing
|
|
+ | QPainter.SmoothPixmapTransform
|
|
+ | QPainter.TextAntialiasing,
|
|
+ True)
|
|
|
|
# Fill the whole widget with the solid color
|
|
painter.fillRect(event.rect(), QColor("#191919"))
|
|
@@ -191,7 +290,7 @@ def paintEvent(self, event, *args):
|
|
# DRAW FRAME
|
|
# Calculate new frame image size, maintaining aspect ratio
|
|
pixSize = self.current_image.size()
|
|
- pixSize.scale(event.rect().width(), event.rect().height(), Qt.KeepAspectRatio)
|
|
+ pixSize.scale(event.rect().size(), Qt.KeepAspectRatio)
|
|
self.curr_frame_size = pixSize
|
|
|
|
# Scale image (take into account display scaling for High DPI monitors)
|
|
@@ -223,13 +322,19 @@ def paintEvent(self, event, *args):
|
|
# Determine original size of clip's reader
|
|
source_width = self.transforming_clip.data['reader']['width']
|
|
source_height = self.transforming_clip.data['reader']['height']
|
|
- source_size = QSize(source_width, source_height * self.pixel_ratio.Reciprocal().ToDouble())
|
|
+ pixel_adjust = self.pixel_ratio.Reciprocal().ToDouble()
|
|
+ source_size = QSize(
|
|
+ int(source_width),
|
|
+ int(source_height * pixel_adjust))
|
|
|
|
# Determine scale of clip
|
|
scale = self.transforming_clip.data['scale']
|
|
|
|
# Set scale as STRETCH if the clip is attached to an object
|
|
- if (raw_properties.get('parentObjectId').get('memo') != 'None' and len(raw_properties.get('parentObjectId').get('memo')) > 0 ):
|
|
+ if (
|
|
+ raw_properties.get('parentObjectId').get('memo') != 'None'
|
|
+ and len(raw_properties.get('parentObjectId').get('memo')) > 0
|
|
+ ):
|
|
scale = openshot.SCALE_STRETCH
|
|
|
|
if scale == openshot.SCALE_FIT:
|
|
@@ -239,12 +344,7 @@ def paintEvent(self, event, *args):
|
|
source_size.scale(player_width, player_height, Qt.IgnoreAspectRatio)
|
|
|
|
elif scale == openshot.SCALE_CROP:
|
|
- width_size = QSize(player_width, round(player_width / (float(source_width) / float(source_height))))
|
|
- height_size = QSize(round(player_height / (float(source_height) / float(source_width))), player_height)
|
|
- if width_size.width() >= player_width and width_size.height() >= player_height:
|
|
- source_size.scale(width_size.width(), width_size.height(), Qt.KeepAspectRatio)
|
|
- else:
|
|
- source_size.scale(height_size.width(), height_size.height(), Qt.KeepAspectRatio)
|
|
+ source_size.scale(player_width, player_height, Qt.KeepAspectRatioByExpanding)
|
|
|
|
# Get new source width / height (after scaling mode applied)
|
|
source_width = source_size.width()
|
|
@@ -285,9 +385,6 @@ def paintEvent(self, event, *args):
|
|
x += player_width - scaled_source_width # right
|
|
y += (player_height - scaled_source_height) # bottom
|
|
|
|
- # Track gravity starting coordinate
|
|
- self.gravity_point = QPointF(x, y)
|
|
-
|
|
# Adjust x,y for location
|
|
x_offset = raw_properties.get('location_x').get('value')
|
|
y_offset = raw_properties.get('location_y').get('value')
|
|
@@ -329,7 +426,6 @@ def paintEvent(self, event, *args):
|
|
raw_properties_effect = json.loads(self.transforming_effect_object.PropertiesJSON(clip_frame_number))
|
|
# Get properties for the first object in dict. PropertiesJSON should return one object at the time
|
|
tmp = raw_properties_effect.get('objects')
|
|
- tmp2 = tmp.keys()
|
|
obj_id = list(tmp.keys())[0]
|
|
raw_properties_effect = raw_properties_effect.get('objects').get(obj_id)
|
|
|
|
@@ -342,10 +438,19 @@ def paintEvent(self, event, *args):
|
|
y1 = raw_properties_effect['y1']['value']
|
|
x2 = raw_properties_effect['x2']['value']
|
|
y2 = raw_properties_effect['y2']['value']
|
|
- self.drawTransformHandler(painter, sx, sy, source_width, source_height, origin_x, origin_y,
|
|
- x1, y1, x2, y2, rotation)
|
|
+ self.drawTransformHandler(
|
|
+ painter,
|
|
+ sx, sy,
|
|
+ source_width, source_height,
|
|
+ origin_x, origin_y,
|
|
+ x1, y1, x2, y2,
|
|
+ rotation)
|
|
else:
|
|
- self.drawTransformHandler(painter, sx, sy, source_width, source_height, origin_x, origin_y)
|
|
+ self.drawTransformHandler(
|
|
+ painter,
|
|
+ sx, sy,
|
|
+ source_width, source_height,
|
|
+ origin_x, origin_y)
|
|
|
|
if self.region_enabled:
|
|
# Paint region selector onto video preview
|
|
@@ -376,11 +481,21 @@ def paintEvent(self, event, *args):
|
|
pen = QPen(QBrush(QColor("#53a0ed")), 1.5)
|
|
pen.setCosmetic(True)
|
|
painter.setPen(pen)
|
|
- painter.drawRect(self.regionTopLeftHandle.x() - (cs/2.0/self.zoom), self.regionTopLeftHandle.y() - (cs/2.0/self.zoom), self.regionTopLeftHandle.width() / self.zoom, self.regionTopLeftHandle.height() / self.zoom)
|
|
- painter.drawRect(self.regionBottomRightHandle.x() - (cs/2.0/self.zoom), self.regionBottomRightHandle.y() - (cs/2.0/self.zoom), self.regionBottomRightHandle.width() / self.zoom, self.regionBottomRightHandle.height() / self.zoom)
|
|
- region_rect = QRectF(self.regionTopLeftHandle.x(), self.regionTopLeftHandle.y(),
|
|
- self.regionBottomRightHandle.x() - self.regionTopLeftHandle.x(),
|
|
- self.regionBottomRightHandle.y() - self.regionTopLeftHandle.y())
|
|
+ painter.drawRect(
|
|
+ self.regionTopLeftHandle.x() - (cs / 2.0 / self.zoom),
|
|
+ self.regionTopLeftHandle.y() - (cs / 2.0 / self.zoom),
|
|
+ self.regionTopLeftHandle.width() / self.zoom,
|
|
+ self.regionTopLeftHandle.height() / self.zoom)
|
|
+ painter.drawRect(
|
|
+ self.regionBottomRightHandle.x() - (cs / 2.0 / self.zoom),
|
|
+ self.regionBottomRightHandle.y() - (cs / 2.0 / self.zoom),
|
|
+ self.regionBottomRightHandle.width() / self.zoom,
|
|
+ self.regionBottomRightHandle.height() / self.zoom)
|
|
+ region_rect = QRectF(
|
|
+ self.regionTopLeftHandle.x(),
|
|
+ self.regionTopLeftHandle.y(),
|
|
+ self.regionBottomRightHandle.x() - self.regionTopLeftHandle.x(),
|
|
+ self.regionBottomRightHandle.y() - self.regionTopLeftHandle.y())
|
|
painter.drawRect(region_rect)
|
|
|
|
# Remove transform
|
|
@@ -394,23 +509,15 @@ def paintEvent(self, event, *args):
|
|
def centeredViewport(self, width, height):
|
|
""" Calculate size of viewport to maintain aspect ratio """
|
|
|
|
- # Calculate padding
|
|
- top_padding = (height - (height * self.zoom)) / 2.0
|
|
- left_padding = (width - (width * self.zoom)) / 2.0
|
|
+ window_size = QSizeF(width, height)
|
|
+ window_rect = QRectF(QPointF(0, 0), window_size)
|
|
|
|
- # Adjust parameters to zoom
|
|
- width = width * self.zoom
|
|
- height = height * self.zoom
|
|
+ aspectRatio = self.aspect_ratio.ToFloat() * self.pixel_ratio.ToFloat()
|
|
+ viewport_size = QSizeF(aspectRatio, 1).scaled(window_size, Qt.KeepAspectRatio)
|
|
+ viewport_rect = QRectF(QPointF(0, 0), viewport_size)
|
|
+ viewport_rect.moveCenter(window_rect.center())
|
|
|
|
- # Calculate which direction to scale (for perfect centering)
|
|
- aspectRatio = self.aspect_ratio.ToFloat()
|
|
- heightFromWidth = width / aspectRatio
|
|
- widthFromHeight = height * aspectRatio
|
|
-
|
|
- if heightFromWidth <= height:
|
|
- return QRect(left_padding, ((height - heightFromWidth) / 2) + top_padding, width, heightFromWidth)
|
|
- else:
|
|
- return QRect(((width - widthFromHeight) / 2.0) + left_padding, top_padding, widthFromHeight, height)
|
|
+ return viewport_rect.toRect()
|
|
|
|
def present(self, image, *args):
|
|
""" Present the current frame """
|
|
@@ -448,12 +555,16 @@ def mouseReleaseEvent(self, event):
|
|
# This can be used other widgets to display the selected region
|
|
if self.region_enabled:
|
|
# Get region coordinates
|
|
- region_rect = QRectF(self.regionTopLeftHandle.x(), self.regionTopLeftHandle.y(),
|
|
- self.regionBottomRightHandle.x() - self.regionTopLeftHandle.x(),
|
|
- self.regionBottomRightHandle.y() - self.regionTopLeftHandle.y()).normalized()
|
|
+ region_rect = QRectF(
|
|
+ self.regionTopLeftHandle.x(),
|
|
+ self.regionTopLeftHandle.y(),
|
|
+ self.regionBottomRightHandle.x() - self.regionTopLeftHandle.x(),
|
|
+ self.regionBottomRightHandle.y() - self.regionTopLeftHandle.y()
|
|
+ ).normalized()
|
|
|
|
# Map region (due to zooming)
|
|
- mapped_region_rect = self.region_transform.mapToPolygon(region_rect.toRect()).boundingRect()
|
|
+ mapped_region_rect = self.region_transform.mapToPolygon(
|
|
+ region_rect.toRect()).boundingRect()
|
|
|
|
# Render a scaled version of the region (as a QImage)
|
|
# TODO: Grab higher quality pixmap from the QWidget, as this method seems to be 1/2 resolution
|
|
@@ -461,14 +572,25 @@ def mouseReleaseEvent(self, event):
|
|
scale = 3.0
|
|
|
|
# Map rect to transform (for scaling video elements)
|
|
- mapped_region_rect = QRect(mapped_region_rect.x(), mapped_region_rect.y(), mapped_region_rect.width() * scale, mapped_region_rect.height() * scale)
|
|
+ mapped_region_rect = QRect(
|
|
+ mapped_region_rect.x(),
|
|
+ mapped_region_rect.y(),
|
|
+ int(mapped_region_rect.width() * scale),
|
|
+ int(mapped_region_rect.height() * scale))
|
|
|
|
# Render QWidget onto scaled QImage
|
|
- self.region_qimage = QImage(mapped_region_rect.width(), mapped_region_rect.height(), QImage.Format_RGBA8888)
|
|
+ self.region_qimage = QImage(
|
|
+ mapped_region_rect.size(), QImage.Format_RGBA8888)
|
|
region_painter = QPainter(self.region_qimage)
|
|
- region_painter.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform | QPainter.TextAntialiasing, True)
|
|
+ region_painter.setRenderHints(
|
|
+ QPainter.Antialiasing
|
|
+ | QPainter.SmoothPixmapTransform
|
|
+ | QPainter.TextAntialiasing,
|
|
+ True)
|
|
region_painter.scale(scale, scale)
|
|
- self.render(region_painter, QPoint(0,0), QRegion(mapped_region_rect, QRegion.Rectangle))
|
|
+ self.render(
|
|
+ region_painter, QPoint(0, 0),
|
|
+ QRegion(mapped_region_rect, QRegion.Rectangle))
|
|
region_painter.end()
|
|
|
|
# Inform UpdateManager to accept updates, and only store our final update
|
|
@@ -484,7 +606,8 @@ def mouseReleaseEvent(self, event):
|
|
def rotateCursor(self, pixmap, rotation, shear_x, shear_y):
|
|
"""Rotate cursor based on the current transform"""
|
|
rotated_pixmap = pixmap.transformed(
|
|
- QTransform().rotate(rotation).shear(shear_x, shear_y).scale(0.8, 0.8), Qt.SmoothTransformation)
|
|
+ QTransform().rotate(rotation).shear(shear_x, shear_y).scale(0.8, 0.8),
|
|
+ Qt.SmoothTransformation)
|
|
return QCursor(rotated_pixmap)
|
|
|
|
def getTransformMode(self, rotation, shear_x, shear_y, event):
|
|
@@ -627,6 +750,10 @@ def mouseMoveEvent(self, event):
|
|
|
|
# Transform clip object
|
|
if self.transform_mode:
|
|
+
|
|
+ x_motion = event.pos().x() - self.mouse_position.x()
|
|
+ y_motion = event.pos().y() - self.mouse_position.y()
|
|
+
|
|
if self.transform_mode == 'origin':
|
|
# Get current keyframe value
|
|
origin_x = raw_properties.get('origin_x').get('value')
|
|
@@ -635,8 +762,8 @@ def mouseMoveEvent(self, event):
|
|
scale_y = raw_properties.get('scale_y').get('value')
|
|
|
|
# Calculate new location coordinates
|
|
- origin_x += (event.pos().x() - self.mouse_position.x()) / (self.clipBounds.width() * scale_x)
|
|
- origin_y += (event.pos().y() - self.mouse_position.y()) / (self.clipBounds.height() * scale_y)
|
|
+ origin_x += x_motion / (self.clipBounds.width() * scale_x)
|
|
+ origin_y += y_motion / (self.clipBounds.height() * scale_y)
|
|
|
|
# Constrain to clip
|
|
if origin_x < 0.0:
|
|
@@ -648,8 +775,13 @@ def mouseMoveEvent(self, event):
|
|
if origin_y > 1.0:
|
|
origin_y = 1.0
|
|
# Update keyframe value (or create new one)
|
|
- self.updateClipProperty(self.transforming_clip.id, clip_frame_number, 'origin_x', origin_x, refresh=False)
|
|
- self.updateClipProperty(self.transforming_clip.id, clip_frame_number, 'origin_y', origin_y)
|
|
+ self.updateClipProperty(
|
|
+ self.transforming_clip.id, clip_frame_number,
|
|
+ 'origin_x', origin_x,
|
|
+ refresh=False)
|
|
+ self.updateClipProperty(
|
|
+ self.transforming_clip.id, clip_frame_number,
|
|
+ 'origin_y', origin_y)
|
|
|
|
elif self.transform_mode == 'location':
|
|
# Get current keyframe value
|
|
@@ -657,12 +789,17 @@ def mouseMoveEvent(self, event):
|
|
location_y = raw_properties.get('location_y').get('value')
|
|
|
|
# Calculate new location coordinates
|
|
- location_x += (event.pos().x() - self.mouse_position.x()) / viewport_rect.width()
|
|
- location_y += (event.pos().y() - self.mouse_position.y()) / viewport_rect.height()
|
|
+ location_x += x_motion / viewport_rect.width()
|
|
+ location_y += y_motion / viewport_rect.height()
|
|
|
|
# Update keyframe value (or create new one)
|
|
- self.updateClipProperty(self.transforming_clip.id, clip_frame_number, 'location_x', location_x, refresh=False)
|
|
- self.updateClipProperty(self.transforming_clip.id, clip_frame_number, 'location_y', location_y)
|
|
+ self.updateClipProperty(
|
|
+ self.transforming_clip.id, clip_frame_number,
|
|
+ 'location_x', location_x,
|
|
+ refresh=False)
|
|
+ self.updateClipProperty(
|
|
+ self.transforming_clip.id, clip_frame_number,
|
|
+ 'location_y', location_y)
|
|
|
|
elif self.transform_mode == 'shear_top':
|
|
# Get current keyframe shear value
|
|
@@ -672,11 +809,13 @@ def mouseMoveEvent(self, event):
|
|
# Calculate new location coordinates
|
|
aspect_ratio = (self.clipBounds.width() / self.clipBounds.height()) * 2.0
|
|
shear_x -= (
|
|
- event.pos().x() - self.mouse_position.x()) / (
|
|
+ x_motion) / (
|
|
(self.clipBounds.width() * scale_x) / aspect_ratio)
|
|
|
|
# Update keyframe value (or create new one)
|
|
- self.updateClipProperty(self.transforming_clip.id, clip_frame_number, 'shear_x', shear_x)
|
|
+ self.updateClipProperty(
|
|
+ self.transforming_clip.id, clip_frame_number,
|
|
+ 'shear_x', shear_x)
|
|
|
|
elif self.transform_mode == 'shear_bottom':
|
|
# Get current keyframe shear value
|
|
@@ -686,11 +825,13 @@ def mouseMoveEvent(self, event):
|
|
# Calculate new location coordinates
|
|
aspect_ratio = (self.clipBounds.width() / self.clipBounds.height()) * 2.0
|
|
shear_x += (
|
|
- event.pos().x() - self.mouse_position.x()) / (
|
|
+ x_motion) / (
|
|
(self.clipBounds.width() * scale_x) / aspect_ratio)
|
|
|
|
# Update keyframe value (or create new one)
|
|
- self.updateClipProperty(self.transforming_clip.id, clip_frame_number, 'shear_x', shear_x)
|
|
+ self.updateClipProperty(
|
|
+ self.transforming_clip.id, clip_frame_number,
|
|
+ 'shear_x', shear_x)
|
|
|
|
elif self.transform_mode == 'shear_left':
|
|
# Get current keyframe shear value
|
|
@@ -701,11 +842,13 @@ def mouseMoveEvent(self, event):
|
|
aspect_ratio = (
|
|
self.clipBounds.height() / self.clipBounds.width()) * 2.0
|
|
shear_y -= (
|
|
- event.pos().y() - self.mouse_position.y()) / (
|
|
+ y_motion) / (
|
|
self.clipBounds.height() * scale_y / aspect_ratio)
|
|
|
|
# Update keyframe value (or create new one)
|
|
- self.updateClipProperty(self.transforming_clip.id, clip_frame_number, 'shear_y', shear_y)
|
|
+ self.updateClipProperty(
|
|
+ self.transforming_clip.id, clip_frame_number,
|
|
+ 'shear_y', shear_y)
|
|
|
|
elif self.transform_mode == 'shear_right':
|
|
# Get current keyframe shear value
|
|
@@ -713,13 +856,16 @@ def mouseMoveEvent(self, event):
|
|
shear_y = raw_properties.get('shear_y').get('value')
|
|
|
|
# Calculate new location coordinates
|
|
- aspect_ratio = (self.clipBounds.height() / self.clipBounds.width()) * 2.0
|
|
+ aspect_ratio = (
|
|
+ self.clipBounds.height() / self.clipBounds.width()) * 2.0
|
|
shear_y += (
|
|
- event.pos().y() - self.mouse_position.y()) / (
|
|
+ y_motion) / (
|
|
self.clipBounds.height() * scale_y / aspect_ratio)
|
|
|
|
# Update keyframe value (or create new one)
|
|
- self.updateClipProperty(self.transforming_clip.id, clip_frame_number, 'shear_y', shear_y)
|
|
+ self.updateClipProperty(
|
|
+ self.transforming_clip.id, clip_frame_number,
|
|
+ 'shear_y', shear_y)
|
|
|
|
elif self.transform_mode == 'rotation':
|
|
# Get current rotation keyframe value
|
|
@@ -728,71 +874,68 @@ def mouseMoveEvent(self, event):
|
|
scale_y = max(float(raw_properties.get('scale_y').get('value')), 0.001)
|
|
|
|
# Calculate new location coordinates
|
|
- is_on_left = event.pos().x() < self.originHandle.x()
|
|
+ is_on_right = event.pos().x() > self.originHandle.x()
|
|
is_on_top = event.pos().y() < self.originHandle.y()
|
|
|
|
- if is_on_top:
|
|
- rotation += (
|
|
- event.pos().x() - self.mouse_position.x()) / (
|
|
- (self.clipBounds.width() * scale_x) / 90)
|
|
- else:
|
|
- rotation -= (
|
|
- event.pos().x() - self.mouse_position.x()) / (
|
|
- (self.clipBounds.width() * scale_x) / 90)
|
|
-
|
|
- if is_on_left:
|
|
- rotation -= (
|
|
- event.pos().y() - self.mouse_position.y()) / (
|
|
- (self.clipBounds.height() * scale_y) / 90)
|
|
- else:
|
|
- rotation += (
|
|
- event.pos().y() - self.mouse_position.y()) / (
|
|
- (self.clipBounds.height() * scale_y) / 90)
|
|
+ x_adjust = x_motion / ((self.clipBounds.width() * scale_x) / 90)
|
|
+ rotation += (x_adjust if is_on_top else -x_adjust)
|
|
+
|
|
+ y_adjust = y_motion / ((self.clipBounds.height() * scale_y) / 90)
|
|
+ rotation += (y_adjust if is_on_right else -y_adjust)
|
|
|
|
# Update keyframe value (or create new one)
|
|
- self.updateClipProperty(self.transforming_clip.id, clip_frame_number, 'rotation', rotation)
|
|
+ self.updateClipProperty(
|
|
+ self.transforming_clip.id,
|
|
+ clip_frame_number,
|
|
+ 'rotation', rotation)
|
|
|
|
elif self.transform_mode.startswith('scale_'):
|
|
# Get current scale keyframe value
|
|
scale_x = max(float(raw_properties.get('scale_x').get('value')), 0.001)
|
|
scale_y = max(float(raw_properties.get('scale_y').get('value')), 0.001)
|
|
|
|
+ half_w = self.clipBounds.width() / 2.0
|
|
+ half_h = self.clipBounds.height() / 2.0
|
|
+
|
|
if self.transform_mode == 'scale_top_right':
|
|
- scale_x += (event.pos().x() - self.mouse_position.x()) / (self.clipBounds.width() / 2.0)
|
|
- scale_y -= (event.pos().y() - self.mouse_position.y()) / (self.clipBounds.height() / 2.0)
|
|
+ scale_x += x_motion / half_w
|
|
+ scale_y -= y_motion / half_h
|
|
elif self.transform_mode == 'scale_bottom_right':
|
|
- scale_x += (event.pos().x() - self.mouse_position.x()) / (self.clipBounds.width() / 2.0)
|
|
- scale_y += (event.pos().y() - self.mouse_position.y()) / (self.clipBounds.height() / 2.0)
|
|
+ scale_x += x_motion / half_w
|
|
+ scale_y += y_motion / half_h
|
|
elif self.transform_mode == 'scale_top_left':
|
|
- scale_x -= (event.pos().x() - self.mouse_position.x()) / (self.clipBounds.width() / 2.0)
|
|
- scale_y -= (event.pos().y() - self.mouse_position.y()) / (self.clipBounds.height() / 2.0)
|
|
+ scale_x -= x_motion / half_w
|
|
+ scale_y -= y_motion / half_h
|
|
elif self.transform_mode == 'scale_bottom_left':
|
|
- scale_x -= (event.pos().x() - self.mouse_position.x()) / (self.clipBounds.width() / 2.0)
|
|
- scale_y += (event.pos().y() - self.mouse_position.y()) / (self.clipBounds.height() / 2.0)
|
|
+ scale_x -= x_motion / half_w
|
|
+ scale_y += y_motion / half_h
|
|
elif self.transform_mode == 'scale_top':
|
|
- scale_y -= (event.pos().y() - self.mouse_position.y()) / (self.clipBounds.height() / 2.0)
|
|
+ scale_y -= y_motion / half_h
|
|
elif self.transform_mode == 'scale_bottom':
|
|
- scale_y += (event.pos().y() - self.mouse_position.y()) / (self.clipBounds.height() / 2.0)
|
|
+ scale_y += y_motion / half_h
|
|
elif self.transform_mode == 'scale_left':
|
|
- scale_x -= (event.pos().x() - self.mouse_position.x()) / (self.clipBounds.width() / 2.0)
|
|
+ scale_x -= x_motion / half_w
|
|
elif self.transform_mode == 'scale_right':
|
|
- scale_x += (event.pos().x() - self.mouse_position.x()) / (self.clipBounds.width() / 2.0)
|
|
+ scale_x += x_motion / half_w
|
|
|
|
if int(QCoreApplication.instance().keyboardModifiers() & Qt.ControlModifier) > 0:
|
|
# If CTRL key is pressed, fix the scale_y to the correct aspect ration
|
|
- if scale_x and scale_y:
|
|
+ if scale_x:
|
|
scale_y = scale_x
|
|
elif scale_y:
|
|
scale_x = scale_y
|
|
- elif scale_x:
|
|
- scale_y = scale_x
|
|
|
|
# Update keyframe value (or create new one)
|
|
both_scaled = scale_x != 0.001 and scale_y != 0.001
|
|
if scale_x != 0.001:
|
|
- self.updateClipProperty(self.transforming_clip.id, clip_frame_number, 'scale_x', scale_x, refresh=(not both_scaled))
|
|
+ self.updateClipProperty(
|
|
+ self.transforming_clip.id, clip_frame_number,
|
|
+ 'scale_x', scale_x,
|
|
+ refresh=(not both_scaled))
|
|
if scale_y != 0.001:
|
|
- self.updateClipProperty(self.transforming_clip.id, clip_frame_number, 'scale_y', scale_y)
|
|
+ self.updateClipProperty(
|
|
+ self.transforming_clip.id, clip_frame_number,
|
|
+ 'scale_y', scale_y)
|
|
|
|
# Force re-paint
|
|
self.update()
|
|
@@ -803,16 +946,29 @@ def mouseMoveEvent(self, event):
|
|
cs = self.cs
|
|
|
|
# Adjust existing region coordinates (if any)
|
|
- if not self.mouse_dragging and self.resize_button.isVisible() and self.resize_button.rect().contains(event.pos()):
|
|
+ if (not self.mouse_dragging
|
|
+ and self.resize_button.isVisible()
|
|
+ and self.resize_button.rect().contains(event.pos())
|
|
+ ):
|
|
# Mouse over resize button (and not currently dragging)
|
|
self.setCursor(Qt.ArrowCursor)
|
|
- elif self.region_transform and self.regionTopLeftHandle and self.region_transform.mapToPolygon(self.regionTopLeftHandle.toRect()).containsPoint(event.pos(), Qt.OddEvenFill):
|
|
+ elif (
|
|
+ self.region_transform
|
|
+ and self.regionTopLeftHandle
|
|
+ and self.region_transform.mapToPolygon(
|
|
+ self.regionTopLeftHandle.toRect()).containsPoint(event.pos(), Qt.OddEvenFill)
|
|
+ ):
|
|
if not self.region_mode or self.region_mode == 'scale_top_left':
|
|
self.setCursor(self.rotateCursor(self.cursors.get('resize_fdiag'), 0, 0, 0))
|
|
# Set the region mode
|
|
if self.mouse_dragging and not self.region_mode:
|
|
self.region_mode = 'scale_top_left'
|
|
- elif self.region_transform and self.regionBottomRightHandle and self.region_transform.mapToPolygon(self.regionBottomRightHandle.toRect()).containsPoint(event.pos(), Qt.OddEvenFill):
|
|
+ elif (
|
|
+ self.region_transform
|
|
+ and self.regionBottomRightHandle
|
|
+ and self.region_transform.mapToPolygon(
|
|
+ self.regionBottomRightHandle.toRect()).containsPoint(event.pos(), Qt.OddEvenFill)
|
|
+ ):
|
|
if not self.region_mode or self.region_mode == 'scale_bottom_right':
|
|
self.setCursor(self.rotateCursor(self.cursors.get('resize_fdiag'), 0, 0, 0))
|
|
# Set the region mode
|
|
@@ -824,13 +980,25 @@ def mouseMoveEvent(self, event):
|
|
# Initialize new region coordinates at current event.pos()
|
|
if self.mouse_dragging and not self.region_mode:
|
|
self.region_mode = 'scale_bottom_right'
|
|
- self.regionTopLeftHandle = QRectF(self.region_transform_inverted.map(event.pos()).x(), self.region_transform_inverted.map(event.pos()).y(), cs, cs)
|
|
- self.regionBottomRightHandle = QRectF(self.region_transform_inverted.map(event.pos()).x(), self.region_transform_inverted.map(event.pos()).y(), cs, cs)
|
|
+ self.regionTopLeftHandle = QRectF(
|
|
+ self.region_transform_inverted.map(event.pos()).x(),
|
|
+ self.region_transform_inverted.map(event.pos()).y(),
|
|
+ cs, cs)
|
|
+ self.regionBottomRightHandle = QRectF(
|
|
+ self.region_transform_inverted.map(event.pos()).x(),
|
|
+ self.region_transform_inverted.map(event.pos()).y(),
|
|
+ cs, cs)
|
|
|
|
# Move existing region coordinates
|
|
if self.mouse_dragging:
|
|
- diff_x = self.region_transform_inverted.map(event.pos()).x() - self.region_transform_inverted.map(self.mouse_position).x()
|
|
- diff_y = self.region_transform_inverted.map(event.pos()).y() - self.region_transform_inverted.map(self.mouse_position).y()
|
|
+ diff_x = int(
|
|
+ self.region_transform_inverted.map(event.pos()).x()
|
|
+ - self.region_transform_inverted.map(self.mouse_position).x()
|
|
+ )
|
|
+ diff_y = int(
|
|
+ self.region_transform_inverted.map(event.pos()).y()
|
|
+ - self.region_transform_inverted.map(self.mouse_position).y()
|
|
+ )
|
|
if self.region_mode == 'scale_top_left':
|
|
self.regionTopLeftHandle.adjust(diff_x, diff_y, diff_x, diff_y)
|
|
elif self.region_mode == 'scale_bottom_right':
|
|
@@ -859,12 +1027,11 @@ def mouseMoveEvent(self, event):
|
|
if self.mouse_dragging and not self.transform_mode:
|
|
self.original_clip_data = self.transforming_clip.data
|
|
|
|
-
|
|
-
|
|
if self.transforming_effect_object.info.has_tracked_object:
|
|
# Get properties of effect at current frame
|
|
raw_properties = json.loads(self.transforming_effect_object.PropertiesJSON(clip_frame_number))
|
|
- # Get properties for the first object in dict. PropertiesJSON should return one object at the time
|
|
+ # Get properties for the first object in dict.
|
|
+ # PropertiesJSON should return one object at the time
|
|
obj_id = list(raw_properties.get('objects').keys())[0]
|
|
raw_properties = raw_properties.get('objects').get(obj_id)
|
|
|
|
@@ -878,18 +1045,28 @@ def mouseMoveEvent(self, event):
|
|
# Transform effect object
|
|
if self.transform_mode:
|
|
|
|
+ x_motion = event.pos().x() - self.mouse_position.x()
|
|
+ y_motion = event.pos().y() - self.mouse_position.y()
|
|
+
|
|
if self.transform_mode == 'location':
|
|
# Get current keyframe value
|
|
location_x = raw_properties.get('delta_x').get('value')
|
|
location_y = raw_properties.get('delta_y').get('value')
|
|
|
|
# Calculate new location coordinates
|
|
- location_x += (event.pos().x() - self.mouse_position.x()) / viewport_rect.width()
|
|
- location_y += (event.pos().y() - self.mouse_position.y()) / viewport_rect.height()
|
|
+ location_x += x_motion / viewport_rect.width()
|
|
+ location_y += y_motion / viewport_rect.height()
|
|
|
|
# Update keyframe value (or create new one)
|
|
- self.updateEffectProperty(self.transforming_effect.id, clip_frame_number, obj_id, 'delta_x', location_x, refresh=False)
|
|
- self.updateEffectProperty(self.transforming_effect.id, clip_frame_number, obj_id, 'delta_y', location_y)
|
|
+ self.updateEffectProperty(
|
|
+ self.transforming_effect.id, clip_frame_number,
|
|
+ obj_id,
|
|
+ 'delta_x', location_x,
|
|
+ refresh=False)
|
|
+ self.updateEffectProperty(
|
|
+ self.transforming_effect.id, clip_frame_number,
|
|
+ obj_id,
|
|
+ 'delta_y', location_y)
|
|
|
|
elif self.transform_mode == 'rotation':
|
|
# Get current rotation keyframe value
|
|
@@ -898,63 +1075,70 @@ def mouseMoveEvent(self, event):
|
|
scale_y = max(float(raw_properties.get('scale_y').get('value')), 0.001)
|
|
|
|
# Calculate new location coordinates
|
|
- is_on_left = event.pos().x() < self.originHandle.x()
|
|
+ is_on_right = event.pos().x() > self.originHandle.x()
|
|
is_on_top = event.pos().y() < self.originHandle.y()
|
|
|
|
- if is_on_top:
|
|
- rotation += (event.pos().x() - self.mouse_position.x()) / ((self.clipBounds.width() * scale_x) / 90)
|
|
- else:
|
|
- rotation -= (event.pos().x() - self.mouse_position.x()) / ((self.clipBounds.width() * scale_x) / 90)
|
|
+ x_adjust = x_motion / (self.clipBounds.width() * scale_x / 90)
|
|
+ rotation += (x_adjust if is_on_top else -x_adjust)
|
|
|
|
- if is_on_left:
|
|
- rotation -= (event.pos().y() - self.mouse_position.y()) / ((self.clipBounds.height() * scale_y) / 90)
|
|
- else:
|
|
- rotation += (event.pos().y() - self.mouse_position.y()) / ((self.clipBounds.height() * scale_y) / 90)
|
|
+ y_adjust = y_motion / (self.clipBounds.height() * scale_y / 90)
|
|
+ rotation += (y_adjust if is_on_right else -y_adjust)
|
|
|
|
# Update keyframe value (or create new one)
|
|
- self.updateEffectProperty(self.transforming_effect.id, clip_frame_number, obj_id, 'rotation', rotation)
|
|
+ self.updateEffectProperty(
|
|
+ self.transforming_effect.id,
|
|
+ clip_frame_number, obj_id,
|
|
+ 'rotation', rotation)
|
|
|
|
elif self.transform_mode.startswith('scale_'):
|
|
# Get current scale keyframe value
|
|
scale_x = max(float(raw_properties.get('scale_x').get('value')), 0.001)
|
|
scale_y = max(float(raw_properties.get('scale_y').get('value')), 0.001)
|
|
|
|
+ half_w = self.clipBounds.width() / 2.0
|
|
+ half_h = self.clipBounds.height() / 2.0
|
|
+
|
|
if self.transform_mode == 'scale_top_right':
|
|
- scale_x += (event.pos().x() - self.mouse_position.x()) / (self.clipBounds.width() / 2.0)
|
|
- scale_y -= (event.pos().y() - self.mouse_position.y()) / (self.clipBounds.height() / 2.0)
|
|
+ scale_x += x_motion / half_w
|
|
+ scale_y -= y_motion / half_h
|
|
elif self.transform_mode == 'scale_bottom_right':
|
|
- scale_x += (event.pos().x() - self.mouse_position.x()) / (self.clipBounds.width() / 2.0)
|
|
- scale_y += (event.pos().y() - self.mouse_position.y()) / (self.clipBounds.height() / 2.0)
|
|
+ scale_x += x_motion / half_w
|
|
+ scale_y += y_motion / half_h
|
|
elif self.transform_mode == 'scale_top_left':
|
|
- scale_x -= (event.pos().x() - self.mouse_position.x()) / (self.clipBounds.width() / 2.0)
|
|
- scale_y -= (event.pos().y() - self.mouse_position.y()) / (self.clipBounds.height() / 2.0)
|
|
+ scale_x -= x_motion / half_w
|
|
+ scale_y -= y_motion / half_h
|
|
elif self.transform_mode == 'scale_bottom_left':
|
|
- scale_x -= (event.pos().x() - self.mouse_position.x()) / (self.clipBounds.width() / 2.0)
|
|
- scale_y += (event.pos().y() - self.mouse_position.y()) / (self.clipBounds.height() / 2.0)
|
|
+ scale_x -= x_motion / half_w
|
|
+ scale_y += y_motion / half_h
|
|
elif self.transform_mode == 'scale_top':
|
|
- scale_y -= (event.pos().y() - self.mouse_position.y()) / (self.clipBounds.height() / 2.0)
|
|
+ scale_y -= y_motion / half_h
|
|
elif self.transform_mode == 'scale_bottom':
|
|
- scale_y += (event.pos().y() - self.mouse_position.y()) / (self.clipBounds.height() / 2.0)
|
|
+ scale_y += y_motion / half_h
|
|
elif self.transform_mode == 'scale_left':
|
|
- scale_x -= (event.pos().x() - self.mouse_position.x()) / (self.clipBounds.width() / 2.0)
|
|
+ scale_x -= x_motion / half_w
|
|
elif self.transform_mode == 'scale_right':
|
|
- scale_x += (event.pos().x() - self.mouse_position.x()) / (self.clipBounds.width() / 2.0)
|
|
+ scale_x += x_motion / half_w
|
|
|
|
if int(QCoreApplication.instance().keyboardModifiers() & Qt.ControlModifier) > 0:
|
|
- # If CTRL key is pressed, fix the scale_y to the correct aspect ration
|
|
- if scale_x and scale_y:
|
|
+ # If CTRL key is pressed, fix the scale_y to the correct aspect ratio
|
|
+ if scale_x:
|
|
scale_y = scale_x
|
|
elif scale_y:
|
|
scale_x = scale_y
|
|
- elif scale_x:
|
|
- scale_y = scale_x
|
|
|
|
# Update keyframe value (or create new one)
|
|
both_scaled = scale_x != 0.001 and scale_y != 0.001
|
|
if scale_x != 0.001:
|
|
- self.updateEffectProperty(self.transforming_effect.id, clip_frame_number, obj_id, 'scale_x', scale_x, refresh=(not both_scaled))
|
|
+ self.updateEffectProperty(
|
|
+ self.transforming_effect.id,
|
|
+ clip_frame_number, obj_id,
|
|
+ 'scale_x', scale_x,
|
|
+ refresh=(not both_scaled))
|
|
if scale_y != 0.001:
|
|
- self.updateEffectProperty(self.transforming_effect.id, clip_frame_number, obj_id, 'scale_y', scale_y)
|
|
+ self.updateEffectProperty(
|
|
+ self.transforming_effect.id,
|
|
+ clip_frame_number, obj_id,
|
|
+ 'scale_y', scale_y)
|
|
|
|
# Force re-paint
|
|
self.update()
|
|
@@ -1012,8 +1196,15 @@ def updateEffectProperty(self, effect_id, frame_number, obj_id, property_key, ne
|
|
# No clip found
|
|
return
|
|
|
|
- for point in c.data['objects'][obj_id][property_key]["Points"]:
|
|
- log.info("looping points: co.X = %s" % point["co"]["X"])
|
|
+ try:
|
|
+ props = c.data['objects'][obj_id]
|
|
+ points_list = props[property_key]["Points"]
|
|
+ except (TypeError, KeyError):
|
|
+ log.error("Corrupted project data!", exc_info=1)
|
|
+ return
|
|
+
|
|
+ for point in points_list:
|
|
+ log.info("looping points: co.X = %s", point["co"]["X"])
|
|
|
|
if point["co"]["X"] == frame_number:
|
|
found_point = True
|
|
@@ -1023,12 +1214,15 @@ def updateEffectProperty(self, effect_id, frame_number, obj_id, property_key, ne
|
|
|
|
if not found_point and new_value != None:
|
|
effect_updated = True
|
|
- log.info("Created new point at X=%s" % frame_number)
|
|
- c.data['objects'][obj_id][property_key]["Points"].append({'co': {'X': frame_number, 'Y': new_value}, 'interpolation': openshot.BEZIER})
|
|
+ log.info("Created new point at X=%s", frame_number)
|
|
+ points_list.append({
|
|
+ 'co': { 'X': frame_number, 'Y': new_value },
|
|
+ 'interpolation': openshot.BEZIER,
|
|
+ })
|
|
|
|
# Reduce # of clip properties we are saving (performance boost)
|
|
#TODO: This is too slow when draging transform handlers
|
|
- c.data = {'objects': {obj_id: c.data.get('objects').get(obj_id)}}
|
|
+ c.data = {'objects': {obj_id: c.data.get('objects', {}).get(obj_id)}}
|
|
|
|
if effect_updated:
|
|
c.save()
|
|
@@ -1040,10 +1234,10 @@ def refreshTriggered(self):
|
|
"""Signal to refresh viewport (i.e. a property might have changed that effects the preview)"""
|
|
|
|
# Update reference to clip
|
|
- if self and self.transforming_clip:
|
|
+ if self.transforming_clip:
|
|
self.transforming_clip = Clip.get(id=self.transforming_clip.id)
|
|
|
|
- if self and self.transforming_effect:
|
|
+ if self.transforming_effect:
|
|
self.transforming_effect = Effect.get(id=self.transforming_effect.id)
|
|
|
|
def transformTriggered(self, clip_id):
|
|
@@ -1053,7 +1247,7 @@ def transformTriggered(self, clip_id):
|
|
|
|
# Disable Transform UI
|
|
# Is this the same clip_id already being transformed?
|
|
- if self and self.transforming_clip and not clip_id:
|
|
+ if self.transforming_clip and not clip_id:
|
|
# Clear transform
|
|
self.transforming_clip = None
|
|
need_refresh = True
|
|
@@ -1078,7 +1272,7 @@ def keyFrameTransformTriggered(self, effect_id, clip_id):
|
|
|
|
# Disable Transform UI
|
|
# Is this the same clip_id already being transformed?
|
|
- if self and self.transforming_effect and not effect_id:
|
|
+ if self.transforming_effect and not effect_id:
|
|
# Clear transform
|
|
self.transforming_effect = None
|
|
self.transforming_clip = None
|
|
@@ -1102,12 +1296,8 @@ def keyFrameTransformTriggered(self, effect_id, clip_id):
|
|
|
|
def regionTriggered(self, clip_id):
|
|
"""Handle the 'select region' signal when it's emitted"""
|
|
- if self and not clip_id:
|
|
- # Clear transform
|
|
- self.region_enabled = False
|
|
- else:
|
|
- self.region_enabled = True
|
|
-
|
|
+ # Clear transform
|
|
+ self.region_enabled = bool(not clip_id)
|
|
get_app().window.refreshFrameSignal.emit()
|
|
|
|
def resizeEvent(self, event):
|
|
@@ -1135,7 +1325,7 @@ def delayed_resize_callback(self):
|
|
ratio = float(project_size.width()) / float(project_size.height())
|
|
even_width = round(project_size.width() / 2.0) * 2
|
|
even_height = round(round(even_width / ratio) / 2.0) * 2
|
|
- project_size = QSize(even_width, even_height)
|
|
+ project_size = QSize(int(even_width), int(even_height))
|
|
|
|
# Emit signal that video widget changed size
|
|
self.win.MaxSizeChanged.emit(project_size)
|
|
@@ -1199,7 +1389,6 @@ def __init__(self, watch_project=True, *args):
|
|
self.mouse_dragging = False
|
|
self.mouse_position = None
|
|
self.transform_mode = None
|
|
- self.gravity_point = None
|
|
self.original_clip_data = None
|
|
self.region_qimage = None
|
|
self.region_transform = None
|
|
@@ -1208,8 +1397,8 @@ def __init__(self, watch_project=True, *args):
|
|
self.regionTopLeftHandle = None
|
|
self.regionBottomRightHandle = None
|
|
self.curr_frame_size = None # Frame size
|
|
- self.zoom = 1.0 # Zoom of widget (does not affect video, only workspace)
|
|
- self.cs = 14.0 # Corner size of Transform Handler rectangles
|
|
+ self.zoom = 1.0 # Zoom of widget (does not affect video, only workspace)
|
|
+ self.cs = 14.0 # Corner size of Transform Handler rectangles
|
|
self.resize_button = QPushButton(_('Reset Zoom'), self)
|
|
self.resize_button.hide()
|
|
self.resize_button.setStyleSheet('QPushButton { margin: 10px; padding: 2px; }')
|
|
@@ -1251,7 +1440,6 @@ def __init__(self, watch_project=True, *args):
|
|
|
|
# Show Property timer
|
|
# Timer to use a delay before sending MaxSizeChanged signals (so we don't spam libopenshot)
|
|
- self.delayed_size = None
|
|
self.delayed_resize_timer = QTimer(self)
|
|
self.delayed_resize_timer.setInterval(200)
|
|
self.delayed_resize_timer.setSingleShot(True)
|
|
diff --git a/src/windows/views/effects_listview.py b/src/windows/views/effects_listview.py
|
|
index b7da28dc4..3ce3b4164 100644
|
|
--- a/src/windows/views/effects_listview.py
|
|
+++ b/src/windows/views/effects_listview.py
|
|
@@ -36,7 +36,8 @@
|
|
|
|
class EffectsListView(QListView):
|
|
""" A TreeView QWidget used on the main window """
|
|
- drag_item_size = 48
|
|
+ drag_item_size = QSize(48, 48)
|
|
+ drag_item_center = QPoint(24, 24)
|
|
|
|
def contextMenuEvent(self, event):
|
|
# Set context menu mode
|
|
@@ -69,8 +70,8 @@ def startDrag(self, event):
|
|
# Start drag operation
|
|
drag = QDrag(self)
|
|
drag.setMimeData(self.model().mimeData(selected))
|
|
- drag.setPixmap(icon.pixmap(QSize(self.drag_item_size, self.drag_item_size)))
|
|
- drag.setHotSpot(QPoint(self.drag_item_size / 2, self.drag_item_size / 2))
|
|
+ drag.setPixmap(icon.pixmap(self.drag_item_size))
|
|
+ drag.setHotSpot(self.drag_item_center)
|
|
drag.exec_()
|
|
|
|
def filter_changed(self):
|
|
diff --git a/src/windows/views/effects_treeview.py b/src/windows/views/effects_treeview.py
|
|
index 6a5ab79f4..910593524 100644
|
|
--- a/src/windows/views/effects_treeview.py
|
|
+++ b/src/windows/views/effects_treeview.py
|
|
@@ -36,7 +36,8 @@
|
|
|
|
class EffectsTreeView(QTreeView):
|
|
""" A TreeView QWidget used on the main window """
|
|
- drag_item_size = 48
|
|
+ drag_item_size = QSize(48, 48)
|
|
+ drag_item_center = QPoint(24, 24)
|
|
|
|
def contextMenuEvent(self, event):
|
|
# Set context menu mode
|
|
@@ -70,8 +71,8 @@ def startDrag(self, supportedActions):
|
|
# Start drag operation
|
|
drag = QDrag(self)
|
|
drag.setMimeData(self.model().mimeData(selected))
|
|
- drag.setPixmap(icon.pixmap(QSize(self.drag_item_size, self.drag_item_size)))
|
|
- drag.setHotSpot(QPoint(self.drag_item_size / 2, self.drag_item_size / 2))
|
|
+ drag.setPixmap(icon.pixmap(self.drag_item_size))
|
|
+ drag.setHotSpot(self.drag_item_center)
|
|
drag.exec_()
|
|
|
|
def refresh_columns(self):
|
|
diff --git a/src/windows/views/emojis_listview.py b/src/windows/views/emojis_listview.py
|
|
index 6f09bc562..cb13c35a7 100644
|
|
--- a/src/windows/views/emojis_listview.py
|
|
+++ b/src/windows/views/emojis_listview.py
|
|
@@ -39,7 +39,8 @@
|
|
|
|
class EmojisListView(QListView):
|
|
""" A QListView QWidget used on the main window """
|
|
- drag_item_size = 48
|
|
+ drag_item_size = QSize(48, 48)
|
|
+ drag_item_center = QPoint(24, 24)
|
|
|
|
def dragEnterEvent(self, event):
|
|
# If dragging urls onto widget, accept
|
|
@@ -57,8 +58,8 @@ def startDrag(self, event):
|
|
drag = QDrag(self)
|
|
drag.setMimeData(self.model.mimeData(selected))
|
|
icon = self.model.data(selected[0], Qt.DecorationRole)
|
|
- drag.setPixmap(icon.pixmap(QSize(self.drag_item_size, self.drag_item_size)))
|
|
- drag.setHotSpot(QPoint(self.drag_item_size / 2, self.drag_item_size / 2))
|
|
+ drag.setPixmap(icon.pixmap(self.drag_item_size))
|
|
+ drag.setHotSpot(self.drag_item_center)
|
|
|
|
# Create emoji file before drag starts
|
|
data = json.loads(drag.mimeData().text())
|
|
diff --git a/src/windows/views/files_listview.py b/src/windows/views/files_listview.py
|
|
index 83cdd0272..0e67306ae 100644
|
|
--- a/src/windows/views/files_listview.py
|
|
+++ b/src/windows/views/files_listview.py
|
|
@@ -38,7 +38,8 @@
|
|
|
|
class FilesListView(QListView):
|
|
""" A ListView QWidget used on the main window """
|
|
- drag_item_size = 48
|
|
+ drag_item_size = QSize(48, 48)
|
|
+ drag_item_center = QPoint(24, 24)
|
|
|
|
def contextMenuEvent(self, event):
|
|
event.accept()
|
|
@@ -113,8 +114,8 @@ def startDrag(self, supportedActions):
|
|
# Start drag operation
|
|
drag = QDrag(self)
|
|
drag.setMimeData(self.model().mimeData(selected))
|
|
- drag.setPixmap(icon.pixmap(QSize(self.drag_item_size, self.drag_item_size)))
|
|
- drag.setHotSpot(QPoint(self.drag_item_size / 2, self.drag_item_size / 2))
|
|
+ drag.setPixmap(icon.pixmap(self.drag_item_size))
|
|
+ drag.setHotSpot(self.drag_item_center)
|
|
drag.exec_()
|
|
|
|
# Without defining this method, the 'copy' action doesn't show with cursor
|
|
diff --git a/src/windows/views/files_treeview.py b/src/windows/views/files_treeview.py
|
|
index d3fe74d88..776b71cc2 100644
|
|
--- a/src/windows/views/files_treeview.py
|
|
+++ b/src/windows/views/files_treeview.py
|
|
@@ -41,7 +41,8 @@
|
|
|
|
class FilesTreeView(QTreeView):
|
|
""" A TreeView QWidget used on the main window """
|
|
- drag_item_size = 48
|
|
+ drag_item_size = QSize(48, 48)
|
|
+ drag_item_center = QPoint(24, 24)
|
|
|
|
def contextMenuEvent(self, event):
|
|
|
|
@@ -114,8 +115,8 @@ def startDrag(self, supportedActions):
|
|
# Start drag operation
|
|
drag = QDrag(self)
|
|
drag.setMimeData(self.model().mimeData(selected))
|
|
- drag.setPixmap(icon.pixmap(QSize(self.drag_item_size, self.drag_item_size)))
|
|
- drag.setHotSpot(QPoint(self.drag_item_size / 2, self.drag_item_size / 2))
|
|
+ drag.setPixmap(icon.pixmap(self.drag_item_size))
|
|
+ drag.setHotSpot(self.drag_item_center)
|
|
drag.exec_()
|
|
|
|
# Without defining this method, the 'copy' action doesn't show with cursor
|
|
diff --git a/src/windows/views/properties_tableview.py b/src/windows/views/properties_tableview.py
|
|
index e79b13644..fdaa7ee24 100644
|
|
--- a/src/windows/views/properties_tableview.py
|
|
+++ b/src/windows/views/properties_tableview.py
|
|
@@ -53,8 +53,13 @@
|
|
|
|
|
|
class PropertyDelegate(QItemDelegate):
|
|
- def __init__(self, parent=None, *args):
|
|
- QItemDelegate.__init__(self, parent, *args)
|
|
+ def __init__(self, parent=None, *args, **kwargs):
|
|
+
|
|
+ self.model = kwargs.pop("model", None)
|
|
+ if not self.model:
|
|
+ log.error("Cannot create delegate without data model!")
|
|
+
|
|
+ super().__init__(parent, *args, **kwargs)
|
|
|
|
# pixmaps for curve icons
|
|
self.curve_pixmaps = {
|
|
@@ -68,7 +73,7 @@ def paint(self, painter, option, index):
|
|
painter.setRenderHint(QPainter.Antialiasing)
|
|
|
|
# Get data model and selection
|
|
- model = get_app().window.propertyTableView.clip_properties_model.model
|
|
+ model = self.model
|
|
row = model.itemFromIndex(index).row()
|
|
selected_label = model.item(row, 0)
|
|
selected_value = model.item(row, 1)
|
|
@@ -104,16 +109,16 @@ def paint(self, painter, option, index):
|
|
painter.setPen(QPen(Qt.NoPen))
|
|
if property_type == "color":
|
|
# Color keyframe
|
|
- red = cur_property[1]["red"]["value"]
|
|
- green = cur_property[1]["green"]["value"]
|
|
- blue = cur_property[1]["blue"]["value"]
|
|
- painter.setBrush(QBrush(QColor(QColor(red, green, blue))))
|
|
+ red = int(cur_property[1]["red"]["value"])
|
|
+ green = int(cur_property[1]["green"]["value"])
|
|
+ blue = int(cur_property[1]["blue"]["value"])
|
|
+ painter.setBrush(QColor(red, green, blue))
|
|
else:
|
|
# Normal Keyframe
|
|
if option.state & QStyle.State_Selected:
|
|
- painter.setBrush(QBrush(QColor("#575757")))
|
|
+ painter.setBrush(QColor("#575757"))
|
|
else:
|
|
- painter.setBrush(QBrush(QColor("#3e3e3e")))
|
|
+ painter.setBrush(QColor("#3e3e3e"))
|
|
|
|
if readonly:
|
|
# Set text color for read only fields
|
|
@@ -146,7 +151,10 @@ def paint(self, painter, option, index):
|
|
|
|
if points > 1:
|
|
# Draw interpolation icon on top
|
|
- painter.drawPixmap(option.rect.x() + option.rect.width() - 30.0, option.rect.y() + 4, self.curve_pixmaps[interpolation])
|
|
+ painter.drawPixmap(
|
|
+ int(option.rect.x() + option.rect.width() - 30.0),
|
|
+ int(option.rect.y() + 4),
|
|
+ self.curve_pixmaps[interpolation])
|
|
|
|
# Set text color
|
|
painter.setPen(QPen(Qt.white))
|
|
@@ -818,9 +826,9 @@ def Color_Picker_Triggered(self, cur_property):
|
|
_ = get_app()._tr
|
|
|
|
# Get current value of color
|
|
- red = cur_property[1]["red"]["value"]
|
|
- green = cur_property[1]["green"]["value"]
|
|
- blue = cur_property[1]["blue"]["value"]
|
|
+ red = int(cur_property[1]["red"]["value"])
|
|
+ green = int(cur_property[1]["green"]["value"])
|
|
+ blue = int(cur_property[1]["blue"]["value"])
|
|
|
|
# Show color dialog
|
|
currentColor = QColor(red, green, blue)
|
|
@@ -865,7 +873,7 @@ def __init__(self, *args):
|
|
self.files_model = self.win.files_model.model
|
|
|
|
# Connect to update signals, so our menus stay current
|
|
- self.win.files_model.ModelRefreshed.connect(self.refresh_menu)
|
|
+ self.files_model.dataChanged.connect(self.refresh_menu)
|
|
self.win.transition_model.ModelRefreshed.connect(self.refresh_menu)
|
|
self.menu_reset = False
|
|
|
|
@@ -890,7 +898,7 @@ def __init__(self, *args):
|
|
self.setWordWrap(True)
|
|
|
|
# Set delegate
|
|
- delegate = PropertyDelegate()
|
|
+ delegate = PropertyDelegate(model=self.clip_properties_model.model)
|
|
self.setItemDelegateForColumn(1, delegate)
|
|
self.previous_x = -1
|
|
|
|
diff --git a/src/windows/views/transitions_listview.py b/src/windows/views/transitions_listview.py
|
|
index 09af86b2b..3ba3346f5 100644
|
|
--- a/src/windows/views/transitions_listview.py
|
|
+++ b/src/windows/views/transitions_listview.py
|
|
@@ -36,7 +36,8 @@
|
|
|
|
class TransitionsListView(QListView):
|
|
""" A QListView QWidget used on the main window """
|
|
- drag_item_size = 48
|
|
+ drag_item_size = QSize(48, 48)
|
|
+ drag_item_center = QPoint(24, 24)
|
|
|
|
def contextMenuEvent(self, event):
|
|
event.accept()
|
|
@@ -70,8 +71,8 @@ def startDrag(self, supportedActions):
|
|
# Start drag operation
|
|
drag = QDrag(self)
|
|
drag.setMimeData(self.model().mimeData(selected))
|
|
- drag.setPixmap(icon.pixmap(QSize(self.drag_item_size, self.drag_item_size)))
|
|
- drag.setHotSpot(QPoint(self.drag_item_size / 2, self.drag_item_size / 2))
|
|
+ drag.setPixmap(icon.pixmap(self.drag_item_size))
|
|
+ drag.setHotSpot(self.drag_item_center)
|
|
drag.exec_()
|
|
|
|
def filter_changed(self):
|
|
diff --git a/src/windows/views/transitions_treeview.py b/src/windows/views/transitions_treeview.py
|
|
index 6f903e913..7aa0cd481 100644
|
|
--- a/src/windows/views/transitions_treeview.py
|
|
+++ b/src/windows/views/transitions_treeview.py
|
|
@@ -36,7 +36,8 @@
|
|
|
|
class TransitionsTreeView(QTreeView):
|
|
""" A TreeView QWidget used on the main window """
|
|
- drag_item_size = 48
|
|
+ drag_item_size = QSize(48, 48)
|
|
+ drag_item_center = QPoint(24, 24)
|
|
|
|
def contextMenuEvent(self, event):
|
|
# Set context menu mode
|
|
@@ -68,8 +69,8 @@ def startDrag(self, event):
|
|
# Start drag operation
|
|
drag = QDrag(self)
|
|
drag.setMimeData(self.model().mimeData(selected))
|
|
- drag.setPixmap(icon.pixmap(QSize(self.drag_item_size, self.drag_item_size)))
|
|
- drag.setHotSpot(QPoint(self.drag_item_size / 2, self.drag_item_size / 2))
|
|
+ drag.setPixmap(icon.pixmap(self.drag_item_size))
|
|
+ drag.setHotSpot(self.drag_item_center)
|
|
drag.exec_()
|
|
|
|
def refresh_columns(self):
|
|
diff --git a/src/windows/views/tutorial.py b/src/windows/views/tutorial.py
|
|
index e2d7fb861..24124799f 100644
|
|
--- a/src/windows/views/tutorial.py
|
|
+++ b/src/windows/views/tutorial.py
|
|
@@ -53,7 +53,12 @@ def paintEvent(self, event, *args):
|
|
|
|
painter.setPen(QPen(frameColor, 2))
|
|
painter.setBrush(self.palette().color(QPalette.Window))
|
|
- painter.drawRoundedRect(QRectF(31, 0, self.width() - 31, self.height()), 10, 10)
|
|
+ painter.drawRoundedRect(
|
|
+ QRectF(31, 0,
|
|
+ self.width() - 31,
|
|
+ self.height()
|
|
+ ),
|
|
+ 10, 10)
|
|
|
|
# Paint blue triangle (if needed)
|
|
if self.arrow:
|
|
@@ -61,7 +66,8 @@ def paintEvent(self, event, *args):
|
|
path = QPainterPath()
|
|
path.moveTo(0, 35)
|
|
path.lineTo(31, 35 - arrow_height)
|
|
- path.lineTo(31, (35 - arrow_height) + (arrow_height * 2))
|
|
+ path.lineTo(
|
|
+ 31, int((35 - arrow_height) + (arrow_height * 2)))
|
|
path.lineTo(0, 35)
|
|
painter.fillPath(path, frameColor)
|
|
|
|
@@ -199,7 +205,9 @@ def process(self, parent_name=None):
|
|
|
|
# Create tutorial
|
|
self.position_widget = tutorial_object
|
|
- self.offset = QPoint(tutorial_details["x"], tutorial_details["y"])
|
|
+ self.offset = QPoint(
|
|
+ int(tutorial_details["x"]),
|
|
+ int(tutorial_details["y"]))
|
|
tutorial_dialog = TutorialDialog(tutorial_id, tutorial_details["text"], tutorial_details["arrow"], self)
|
|
|
|
# Connect signals
|
|
|
|
From 9fc55120f36c36b2b6b67e499128993c25e535cf Mon Sep 17 00:00:00 2001
|
|
From: "FeRD (Frank Dana)" <ferdnyc@gmail.com>
|
|
Date: Thu, 4 Nov 2021 21:02:56 -0400
|
|
Subject: [PATCH 3/6] VideoWidget: New checkTransformMode
|
|
|
|
Replacement for getTransformMode with less repetitious code
|
|
---
|
|
src/windows/video_widget.py | 160 ++++++++++++++----------------------
|
|
1 file changed, 61 insertions(+), 99 deletions(-)
|
|
|
|
diff --git a/src/windows/video_widget.py b/src/windows/video_widget.py
|
|
index f33696c5c..1b9c35b54 100644
|
|
--- a/src/windows/video_widget.py
|
|
+++ b/src/windows/video_widget.py
|
|
@@ -610,106 +610,68 @@ def rotateCursor(self, pixmap, rotation, shear_x, shear_y):
|
|
Qt.SmoothTransformation)
|
|
return QCursor(rotated_pixmap)
|
|
|
|
- def getTransformMode(self, rotation, shear_x, shear_y, event):
|
|
+ def checkTransformMode(self, rotation, shear_x, shear_y, event):
|
|
+ handle_uis = [
|
|
+ {"handle": self.centerHandle, "mode": 'origin', "cursor": 'hand'},
|
|
+ {"handle": self.topRightHandle, "mode": 'scale_top_right', "cursor": 'resize_bdiag'},
|
|
+ {"handle": self.topHandle, "mode": 'scale_top', "cursor": 'resize_y'},
|
|
+ {"handle": self.topLeftHandle, "mode": 'scale_top_left', "cursor": 'resize_fdiag'},
|
|
+ {"handle": self.leftHandle, "mode": 'scale_left', "cursor": 'resize_x'},
|
|
+ {"handle": self.rightHandle, "mode": 'scale_right', "cursor": 'resize_x'},
|
|
+ {"handle": self.bottomLeftHandle, "mode": 'scale_bottom_left', "cursor": 'resize_bdiag'},
|
|
+ {"handle": self.bottomHandle, "mode": 'scale_bottom', "cursor": 'resize_y'},
|
|
+ {"handle": self.bottomRightHandle, "mode": 'scale_bottom_right', "cursor": 'resize_fdiag'},
|
|
+ {"handle": self.topShearHandle, "mode": 'shear_top', "cursor": 'shear_x'},
|
|
+ {"handle": self.leftShearHandle, "mode": 'shear_left', "cursor": 'shear_y'},
|
|
+ {"handle": self.rightShearHandle, "mode": 'shear_right', "cursor": 'shear_y'},
|
|
+ {"handle": self.bottomShearHandle, "mode": 'shear_bottom', "cursor": 'shear_x'},
|
|
+ ]
|
|
+ non_handle_uis = {
|
|
+ "region": self.clipBounds,
|
|
+ "inside": {"mode": 'location', "cursor": 'move'},
|
|
+ "outside": {"mode": 'rotation', "cursor": "rotate"}
|
|
+ }
|
|
+
|
|
# Mouse over resize button (and not currently dragging)
|
|
- if not self.mouse_dragging and self.resize_button.isVisible() and self.resize_button.rect().contains(event.pos()):
|
|
+ if (not self.mouse_dragging
|
|
+ and self.resize_button.isVisible()
|
|
+ and self.resize_button.rect().contains(event.pos()
|
|
+ ):
|
|
self.setCursor(Qt.ArrowCursor)
|
|
- # Determine if cursor is over a handle
|
|
- elif self.transform.mapToPolygon(self.centerHandle.toRect()).containsPoint(event.pos(), Qt.OddEvenFill):
|
|
- if not self.transform_mode or self.transform_mode == 'origin':
|
|
- self.setCursor(self.rotateCursor(self.cursors.get('hand'), rotation, shear_x, shear_y))
|
|
- # Set the transform mode
|
|
- if self.mouse_dragging and not self.transform_mode:
|
|
- self.transform_mode = 'origin'
|
|
- elif self.transform.mapToPolygon(self.topRightHandle.toRect()).containsPoint(event.pos(), Qt.OddEvenFill):
|
|
- if not self.transform_mode or self.transform_mode == 'scale_top_right':
|
|
- self.setCursor(self.rotateCursor(self.cursors.get('resize_bdiag'), rotation, shear_x, shear_y))
|
|
- # Set the transform mode
|
|
- if self.mouse_dragging and not self.transform_mode:
|
|
- self.transform_mode = 'scale_top_right'
|
|
- elif self.transform.mapToPolygon(self.topHandle.toRect()).containsPoint(event.pos(), Qt.OddEvenFill):
|
|
- if not self.transform_mode or self.transform_mode == 'scale_top':
|
|
- self.setCursor(self.rotateCursor(self.cursors.get('resize_y'), rotation, shear_x, shear_y))
|
|
- # Set the transform mode
|
|
- if self.mouse_dragging and not self.transform_mode:
|
|
- self.transform_mode = 'scale_top'
|
|
- elif self.transform.mapToPolygon(self.topLeftHandle.toRect()).containsPoint(event.pos(), Qt.OddEvenFill):
|
|
- if not self.transform_mode or self.transform_mode == 'scale_top_left':
|
|
- self.setCursor(self.rotateCursor(self.cursors.get('resize_fdiag'), rotation, shear_x, shear_y))
|
|
- # Set the transform mode
|
|
- if self.mouse_dragging and not self.transform_mode:
|
|
- self.transform_mode = 'scale_top_left'
|
|
- elif self.transform.mapToPolygon(self.leftHandle.toRect()).containsPoint(event.pos(), Qt.OddEvenFill):
|
|
- if not self.transform_mode or self.transform_mode == 'scale_left':
|
|
- self.setCursor(self.rotateCursor(self.cursors.get('resize_x'), rotation, shear_x, shear_y))
|
|
- # Set the transform mode
|
|
- if self.mouse_dragging and not self.transform_mode:
|
|
- self.transform_mode = 'scale_left'
|
|
- elif self.transform.mapToPolygon(self.rightHandle.toRect()).containsPoint(event.pos(), Qt.OddEvenFill):
|
|
- if not self.transform_mode or self.transform_mode == 'scale_right':
|
|
- self.setCursor(self.rotateCursor(self.cursors.get('resize_x'), rotation, shear_x, shear_y))
|
|
- # Set the transform mode
|
|
- if self.mouse_dragging and not self.transform_mode:
|
|
- self.transform_mode = 'scale_right'
|
|
- elif self.transform.mapToPolygon(self.bottomLeftHandle.toRect()).containsPoint(event.pos(), Qt.OddEvenFill):
|
|
- if not self.transform_mode or self.transform_mode == 'scale_bottom_left':
|
|
- self.setCursor(self.rotateCursor(self.cursors.get('resize_bdiag'), rotation, shear_x, shear_y))
|
|
- # Set the transform mode
|
|
- if self.mouse_dragging and not self.transform_mode:
|
|
- self.transform_mode = 'scale_bottom_left'
|
|
- elif self.transform.mapToPolygon(self.bottomHandle.toRect()).containsPoint(event.pos(), Qt.OddEvenFill):
|
|
- if not self.transform_mode or self.transform_mode == 'scale_bottom':
|
|
- self.setCursor(self.rotateCursor(self.cursors.get('resize_y'), rotation, shear_x, shear_y))
|
|
- # Set the transform mode
|
|
- if self.mouse_dragging and not self.transform_mode:
|
|
- self.transform_mode = 'scale_bottom'
|
|
- elif self.transform.mapToPolygon(self.bottomRightHandle.toRect()).containsPoint(event.pos(), Qt.OddEvenFill):
|
|
- if not self.transform_mode or self.transform_mode == 'scale_bottom_right':
|
|
- self.setCursor(self.rotateCursor(self.cursors.get('resize_fdiag'), rotation, shear_x, shear_y))
|
|
- # Set the transform mode
|
|
- if self.mouse_dragging and not self.transform_mode:
|
|
- self.transform_mode = 'scale_bottom_right'
|
|
- elif self.transform.mapToPolygon(self.topShearHandle.toRect()).containsPoint(event.pos(), Qt.OddEvenFill):
|
|
- if not self.transform_mode or self.transform_mode == 'shear_top':
|
|
- self.setCursor(self.rotateCursor(self.cursors.get('shear_x'), rotation, shear_x, shear_y))
|
|
- # Set the transform mode
|
|
- if self.mouse_dragging and not self.transform_mode:
|
|
- self.transform_mode = 'shear_top'
|
|
- elif self.transform.mapToPolygon(self.leftShearHandle.toRect()).containsPoint(event.pos(), Qt.OddEvenFill):
|
|
- if not self.transform_mode or self.transform_mode == 'shear_left':
|
|
- self.setCursor(self.rotateCursor(self.cursors.get('shear_y'), rotation, shear_x, shear_y))
|
|
- # Set the transform mode
|
|
- if self.mouse_dragging and not self.transform_mode:
|
|
- self.transform_mode = 'shear_left'
|
|
- elif self.transform.mapToPolygon(self.rightShearHandle.toRect()).containsPoint(event.pos(), Qt.OddEvenFill):
|
|
- if not self.transform_mode or self.transform_mode == 'shear_right':
|
|
- self.setCursor(self.rotateCursor(self.cursors.get('shear_y'), rotation, shear_x, shear_y))
|
|
- # Set the transform mode
|
|
- if self.mouse_dragging and not self.transform_mode:
|
|
- self.transform_mode = 'shear_right'
|
|
- elif self.transform.mapToPolygon(self.bottomShearHandle.toRect()).containsPoint(event.pos(), Qt.OddEvenFill):
|
|
- if not self.transform_mode or self.transform_mode == 'shear_bottom':
|
|
- self.setCursor(self.rotateCursor(self.cursors.get('shear_x'), rotation, shear_x, shear_y))
|
|
- # Set the transform mode
|
|
- if self.mouse_dragging and not self.transform_mode:
|
|
- self.transform_mode = 'shear_bottom'
|
|
- elif self.transform.mapToPolygon(self.clipBounds.toRect()).containsPoint(event.pos(), Qt.OddEvenFill):
|
|
- if not self.transform_mode or self.transform_mode == 'location':
|
|
- self.setCursor(self.rotateCursor(self.cursors.get('move'), rotation, shear_x, shear_y))
|
|
- # Set the transform mode
|
|
- if self.mouse_dragging and not self.transform_mode:
|
|
- self.transform_mode = 'location'
|
|
- elif not self.transform.mapToPolygon(self.clipBounds.toRect()).containsPoint(event.pos(), Qt.OddEvenFill):
|
|
- if not self.transform_mode or self.transform_mode == 'rotation':
|
|
- self.setCursor(self.rotateCursor(self.cursors.get('rotate'), rotation, shear_x, shear_y))
|
|
- # Set the transform mode
|
|
- if self.mouse_dragging and not self.transform_mode:
|
|
- self.transform_mode = 'rotation'
|
|
- elif not self.transform_mode:
|
|
- # Reset cursor when not over a handle
|
|
- self.setCursor(QCursor(Qt.ArrowCursor))
|
|
+ self.transform_mode = None
|
|
+ return
|
|
+
|
|
+ # If mouse is over a handle, set corresponding pointer/mode
|
|
+ for h in handle_uis:
|
|
+ if self.transform.mapToPolygon(
|
|
+ h["handle"].toRect()
|
|
+ ).containsPoint(event.pos(), Qt.OddEvenFill):
|
|
+ # Handle contains cursor
|
|
+ if self.transform_mode and self.transform_mode != h["mode"]:
|
|
+ # We're in different xform mode, skip
|
|
+ continue
|
|
+ if self.mouse_dragging:
|
|
+ self.transform_mode = h["mode"]
|
|
+ self.setCursor(self.rotateCursor(
|
|
+ self.cursors.get(h["cursor"]), rotation, shear_x, shear_y))
|
|
+ return
|
|
+
|
|
+ # If not over any handles, determne inside/outside clip rectangle
|
|
+ r = non_handle_uis.get("region")
|
|
+ if self.transform.mapToPolygon(r.toRect()).containsPoint(event.pos(), Qt.OddEvenFill):
|
|
+ nh = non_handle_uis.get("inside", {})
|
|
+ else:
|
|
+ nh = non_handle_uis.get("outside", {})
|
|
+ if self.mouse_dragging and not self.transform_mode:
|
|
+ self.transform_mode = nh.get("mode")
|
|
+ if not self.transform_mode or self.transform_mode == nh.get("mode"):
|
|
+ self.setCursor(self.rotateCursor(
|
|
+ self.cursors.get(nh.get("cursor")), rotation, shear_x, shear_y))
|
|
|
|
- return True
|
|
+
|
|
+ # If we got this far and we don't have a transform mode, reset the cursor
|
|
+ if not self.transform_mode:
|
|
+ self.setCursor(QCursor(Qt.ArrowCursor))
|
|
|
|
def mouseMoveEvent(self, event):
|
|
"""Capture mouse events on video preview window """
|
|
@@ -746,7 +708,7 @@ def mouseMoveEvent(self, event):
|
|
if self.mouse_dragging and not self.transform_mode:
|
|
self.original_clip_data = self.transforming_clip.data
|
|
|
|
- _ = self.getTransformMode(rotation, shear_x, shear_y, event)
|
|
+ self.checkTransformMode(rotation, shear_x, shear_y, event)
|
|
|
|
# Transform clip object
|
|
if self.transform_mode:
|
|
@@ -1040,7 +1002,7 @@ def mouseMoveEvent(self, event):
|
|
self.mutex.unlock()
|
|
return
|
|
|
|
- _ = self.getTransformMode(0, 0, 0, event)
|
|
+ self.checkTransformMode(0, 0, 0, event)
|
|
|
|
# Transform effect object
|
|
if self.transform_mode:
|
|
|
|
From 1f058f730bb36068bce5c645ecea45b98279b614 Mon Sep 17 00:00:00 2001
|
|
From: "FeRD (Frank Dana)" <ferdnyc@gmail.com>
|
|
Date: Thu, 4 Nov 2021 21:42:48 -0400
|
|
Subject: [PATCH 4/6] VideoWidget: Protect property accesses
|
|
|
|
---
|
|
src/windows/video_widget.py | 61 +++++++++++++++++++++----------------
|
|
1 file changed, 34 insertions(+), 27 deletions(-)
|
|
|
|
diff --git a/src/windows/video_widget.py b/src/windows/video_widget.py
|
|
index 1b9c35b54..a4d42969f 100644
|
|
--- a/src/windows/video_widget.py
|
|
+++ b/src/windows/video_widget.py
|
|
@@ -635,7 +635,7 @@ def checkTransformMode(self, rotation, shear_x, shear_y, event):
|
|
# Mouse over resize button (and not currently dragging)
|
|
if (not self.mouse_dragging
|
|
and self.resize_button.isVisible()
|
|
- and self.resize_button.rect().contains(event.pos()
|
|
+ and self.resize_button.rect().contains(event.pos())
|
|
):
|
|
self.setCursor(Qt.ArrowCursor)
|
|
self.transform_mode = None
|
|
@@ -668,11 +668,6 @@ def checkTransformMode(self, rotation, shear_x, shear_y, event):
|
|
self.setCursor(self.rotateCursor(
|
|
self.cursors.get(nh.get("cursor")), rotation, shear_x, shear_y))
|
|
|
|
-
|
|
- # If we got this far and we don't have a transform mode, reset the cursor
|
|
- if not self.transform_mode:
|
|
- self.setCursor(QCursor(Qt.ArrowCursor))
|
|
-
|
|
def mouseMoveEvent(self, event):
|
|
"""Capture mouse events on video preview window """
|
|
self.mutex.lock()
|
|
@@ -1121,27 +1116,37 @@ def updateClipProperty(self, clip_id, frame_number, property_key, new_value, ref
|
|
# No clip found
|
|
return
|
|
|
|
- for point in c.data[property_key]["Points"]:
|
|
- log.info("looping points: co.X = %s" % point["co"]["X"])
|
|
+ # Property missing? Create it!
|
|
+ if property_key not in c.data:
|
|
+ c.data[property_key] = {"Points": []}
|
|
+ log.warning(
|
|
+ "%s: Added missing '%s' to property data",
|
|
+ clip_id, property_key)
|
|
|
|
- if point["co"]["X"] == frame_number:
|
|
+ points = c.data.get(property_key).get("Points")
|
|
+ for point in points:
|
|
+ co = point.get("co", {})
|
|
+ log.info("looping points: co.X = %s" % co.get("X"))
|
|
+
|
|
+ if co.get("X") == frame_number:
|
|
found_point = True
|
|
clip_updated = True
|
|
- point["interpolation"] = openshot.BEZIER
|
|
- point["co"]["Y"] = float(new_value)
|
|
+ point.update({
|
|
+ "co": {"X": frame_number, "Y": float(new_value)},
|
|
+ "interpolation": openshot.BEZIER,
|
|
+ })
|
|
|
|
if not found_point and new_value is not None:
|
|
clip_updated = True
|
|
- log.info("Created new point at X=%s", frame_number)
|
|
+ log.info("Creating new point at X=%s", frame_number)
|
|
c.data[property_key]["Points"].append({
|
|
- 'co': {'X': frame_number, 'Y': new_value},
|
|
+ 'co': {'X': frame_number, 'Y': float(new_value)},
|
|
'interpolation': openshot.BEZIER
|
|
})
|
|
|
|
- # Reduce # of clip properties we are saving (performance boost)
|
|
- c.data = {property_key: c.data.get(property_key)}
|
|
-
|
|
if clip_updated:
|
|
+ # Reduce # of clip properties we are saving (performance boost)
|
|
+ c.data = {property_key: c.data.get(property_key)}
|
|
c.save()
|
|
# Update the preview
|
|
if refresh:
|
|
@@ -1166,27 +1171,29 @@ def updateEffectProperty(self, effect_id, frame_number, obj_id, property_key, ne
|
|
return
|
|
|
|
for point in points_list:
|
|
- log.info("looping points: co.X = %s", point["co"]["X"])
|
|
+ co = point.get("co", {})
|
|
+ log.info("looping points: co.X = %s", co.get("X"))
|
|
|
|
- if point["co"]["X"] == frame_number:
|
|
+ if co.get("X") == frame_number:
|
|
found_point = True
|
|
effect_updated = True
|
|
- point["interpolation"] = openshot.BEZIER
|
|
- point["co"]["Y"] = float(new_value)
|
|
+ point.update({
|
|
+ "co": {"X": frame_number, "Y": float(new_value)},
|
|
+ "interpolation": openshot.BEZIER,
|
|
+ })
|
|
|
|
- if not found_point and new_value != None:
|
|
+ if not found_point and new_value is not None:
|
|
effect_updated = True
|
|
- log.info("Created new point at X=%s", frame_number)
|
|
+ log.info("Creating new point at X=%s", frame_number)
|
|
points_list.append({
|
|
- 'co': { 'X': frame_number, 'Y': new_value },
|
|
+ 'co': {'X': frame_number, 'Y': float(new_value)},
|
|
'interpolation': openshot.BEZIER,
|
|
})
|
|
|
|
- # Reduce # of clip properties we are saving (performance boost)
|
|
- #TODO: This is too slow when draging transform handlers
|
|
- c.data = {'objects': {obj_id: c.data.get('objects', {}).get(obj_id)}}
|
|
-
|
|
if effect_updated:
|
|
+ # Reduce # of clip properties we are saving (performance boost)
|
|
+ #TODO: This is too slow when draging transform handlers
|
|
+ c.data = {'objects': {obj_id: c.data.get('objects', {}).get(obj_id)}}
|
|
c.save()
|
|
# Update the preview
|
|
if refresh:
|
|
|
|
From 7df87ddc189c5e5031fbb19df13378428fab951e Mon Sep 17 00:00:00 2001
|
|
From: "FeRD (Frank Dana)" <ferdnyc@gmail.com>
|
|
Date: Thu, 4 Nov 2021 21:52:19 -0400
|
|
Subject: [PATCH 5/6] classes/thumbnail: Fix dangling filehandles
|
|
|
|
---
|
|
src/classes/thumbnail.py | 8 ++++----
|
|
1 file changed, 4 insertions(+), 4 deletions(-)
|
|
|
|
diff --git a/src/classes/thumbnail.py b/src/classes/thumbnail.py
|
|
index cca47d68f..dac7422a1 100644
|
|
--- a/src/classes/thumbnail.py
|
|
+++ b/src/classes/thumbnail.py
|
|
@@ -209,13 +209,13 @@ def do_GET(self):
|
|
|
|
# Send message back to client
|
|
if os.path.exists(thumb_path):
|
|
- if not only_path:
|
|
- self.wfile.write(open(thumb_path, 'rb').read())
|
|
- else:
|
|
+ if only_path:
|
|
self.wfile.write(bytes(thumb_path, "utf-8"))
|
|
+ else:
|
|
+ with open(thumb_path, 'rb') as f:
|
|
+ self.wfile.write(f.read())
|
|
|
|
# Pause processing of request (since we don't currently use thread pooling, this allows
|
|
# the threads to be processed without choking the CPU as much
|
|
# TODO: Make HTTPServer work with a limited thread pool and remove this sleep() hack.
|
|
time.sleep(0.01)
|
|
-
|
|
|
|
From 33cf68ca0b1ea57edd5dec3dbb8ba06d6a3f8fa4 Mon Sep 17 00:00:00 2001
|
|
From: "FeRD (Frank Dana)" <ferdnyc@gmail.com>
|
|
Date: Thu, 25 Nov 2021 02:18:32 -0500
|
|
Subject: [PATCH 6/6] properties_model: Fix bad logging call, Codacy flags
|
|
|
|
---
|
|
src/windows/models/properties_model.py | 10 +++++-----
|
|
1 file changed, 5 insertions(+), 5 deletions(-)
|
|
|
|
diff --git a/src/windows/models/properties_model.py b/src/windows/models/properties_model.py
|
|
index 40897f642..695e9f39c 100644
|
|
--- a/src/windows/models/properties_model.py
|
|
+++ b/src/windows/models/properties_model.py
|
|
@@ -444,7 +444,7 @@ def value_updated(self, item, interpolation=-1, value=None, interpolation_detail
|
|
log.debug("%s: update property %s. %s", log_id, property_key, clip_data.get(property_key))
|
|
|
|
# Check the type of property (some are keyframe, and some are not)
|
|
- if property_type != "reader" and type(clip_data[property_key]) == dict:
|
|
+ if property_type != "reader" and isinstance(clip_data[property_key], dict):
|
|
# Keyframe
|
|
# Loop through points, find a matching points on this frame
|
|
found_point = False
|
|
@@ -517,21 +517,21 @@ def value_updated(self, item, interpolation=-1, value=None, interpolation_detail
|
|
clip_updated = True
|
|
try:
|
|
clip_data[property_key] = int(new_value)
|
|
- except Exception as ex:
|
|
+ except Exception:
|
|
log.warn('Invalid Integer value passed to property', exc_info=1)
|
|
|
|
elif property_type == "float":
|
|
clip_updated = True
|
|
try:
|
|
clip_data[property_key] = float(new_value)
|
|
- except Exception as ex:
|
|
+ except Exception:
|
|
log.warn('Invalid Float value passed to property', exc_info=1)
|
|
|
|
elif property_type == "bool":
|
|
clip_updated = True
|
|
try:
|
|
clip_data[property_key] = bool(new_value)
|
|
- except Exception as ex:
|
|
+ except Exception:
|
|
log.warn('Invalid Boolean value passed to property', exc_info=1)
|
|
|
|
elif property_type == "string":
|
|
@@ -558,7 +558,7 @@ def value_updated(self, item, interpolation=-1, value=None, interpolation_detail
|
|
clip_object.Close()
|
|
clip_object = None
|
|
except Exception:
|
|
- log.warn('Invalid Reader value passed to property: %s (%s)', value, exc_info=1)
|
|
+ log.warn('Invalid Reader value passed to property: %s', value, exc_info=1)
|
|
|
|
# Reduce # of clip properties we are saving (performance boost)
|
|
clip_data = {property_key: clip_data.get(property_key)}
|