30 from functools
import partial
31 from PyQt5.QtCore import Qt, QRectF, QLocale, pyqtSignal, Qt, QObject, QTimer
33 from PyQt5.QtWidgets import QTableView, QAbstractItemView, QMenu, QSizePolicy, QHeaderView, QColorDialog, QItemDelegate, QStyle, QLabel, QPushButton, QHBoxLayout, QFrame
35 from classes.logger
import log
36 from classes.app
import get_app
37 from classes
import info
38 from classes.query
import Clip, Effect, Transition
39 from windows.models.properties_model
import PropertiesModel
46 import simplejson
as json
51 QItemDelegate.__init__(self, parent, *args)
54 self.
curve_pixmaps = { openshot.BEZIER: QPixmap(os.path.join(info.IMAGES_PATH,
"keyframe-%s.png" % openshot.BEZIER)),
55 openshot.LINEAR: QPixmap(os.path.join(info.IMAGES_PATH,
"keyframe-%s.png" % openshot.LINEAR)),
56 openshot.CONSTANT: QPixmap(os.path.join(info.IMAGES_PATH,
"keyframe-%s.png" % openshot.CONSTANT))
59 def paint(self, painter, option, index):
61 painter.setRenderHint(QPainter.Antialiasing)
64 model =
get_app().window.propertyTableView.clip_properties_model.model
65 row = model.itemFromIndex(index).row()
66 selected_label = model.item(row, 0)
67 selected_value = model.item(row, 1)
68 property = selected_label.data()
71 property_name = property[1][
"name"]
72 property_type = property[1][
"type"]
73 property_max = property[1][
"max"]
74 property_min = property[1][
"min"]
75 readonly = property[1][
"readonly"]
76 keyframe = property[1][
"keyframe"]
77 points = property[1][
"points"]
78 interpolation = property[1][
"interpolation"]
81 if property_type
in [
"float",
"int"]:
83 current_value = QLocale().system().toDouble(selected_value.text())[0]
86 if property_min < 0.0:
87 property_shift = 0.0 - property_min
88 property_min += property_shift
89 property_max += property_shift
90 current_value += property_shift
93 min_max_range = float(property_max) - float(property_min)
94 value_percent = current_value / min_max_range
99 painter.setPen(QPen(Qt.NoPen))
100 if property_type ==
"color":
102 red = property[1][
"red"][
"value"]
103 green = property[1][
"green"][
"value"]
104 blue = property[1][
"blue"][
"value"]
105 painter.setBrush(QBrush(QColor(QColor(red, green, blue))))
108 if option.state & QStyle.State_Selected:
109 painter.setBrush(QBrush(QColor(
"#575757")))
111 painter.setBrush(QBrush(QColor(
"#3e3e3e")))
114 path = QPainterPath()
115 path.addRoundedRect(QRectF(option.rect), 15, 15)
116 painter.fillPath(path, QColor(
"#3e3e3e"))
117 painter.drawPath(path)
120 painter.setBrush(QBrush(QColor(
"#000000")))
121 mask_rect = QRectF(option.rect)
122 mask_rect.setWidth(option.rect.width() * value_percent)
123 painter.setClipRect(mask_rect, Qt.IntersectClip)
126 gradient = QLinearGradient(option.rect.topLeft(), option.rect.topRight())
127 gradient.setColorAt(0, QColor(
"#828282"))
128 gradient.setColorAt(1, QColor(
"#828282"))
131 painter.setBrush(gradient)
132 path = QPainterPath()
133 value_rect = QRectF(option.rect)
134 path.addRoundedRect(value_rect, 15, 15);
135 painter.fillPath(path, gradient)
136 painter.drawPath(path);
137 painter.setClipping(
False)
141 painter.drawPixmap(option.rect.x() + option.rect.width() - 30.0, option.rect.y() + 4, self.
curve_pixmaps[interpolation])
144 painter.setPen(QPen(Qt.white))
145 value = index.data(Qt.DisplayRole)
147 painter.drawText(option.rect, Qt.AlignCenter, value)
155 loadProperties = pyqtSignal(str, str)
160 row = self.indexAt(event.pos()).row()
161 column = self.indexAt(event.pos()).column()
162 if model.item(row, 0):
171 value_column_x = self.columnViewportPosition(1)
172 value_column_y = value_column_x + self.columnWidth(1)
173 cursor_value = event.x() - value_column_x
174 cursor_value_percent = cursor_value / self.columnWidth(1)
178 except Exception
as ex:
183 property_key = property[0]
184 property_name = property[1][
"name"]
185 property_type = property[1][
"type"]
186 property_max = property[1][
"max"]
187 property_min = property[1][
"min"]
188 property_value = property[1][
"value"]
189 readonly = property[1][
"readonly"]
199 get_app().updates.ignore_history =
True 203 if item_type ==
"clip":
205 c = Clip.get(id=item_id)
206 elif item_type ==
"transition":
208 c = Transition.get(id=item_id)
209 elif item_type ==
"effect":
211 c = Effect.get(id=item_id)
214 if property_key
in c.data:
219 if property_type
in [
"float",
"int"]:
220 min_max_range = float(property_max) - float(property_min)
223 if min_max_range > 1000.0:
243 self.
new_value = property_min + (min_max_range * cursor_value_percent)
253 self.viewport().update()
257 get_app().updates.ignore_history =
False 267 row = self.indexAt(event.pos()).row()
268 column = self.indexAt(event.pos()).column()
269 if model.item(row, 0):
279 row = model_index.row()
280 selected_label = model.item(row, 0)
284 property = selected_label.data()
285 property_type = property[1][
"type"]
287 if property_type ==
"color":
289 red = property[1][
"red"][
"value"]
290 green = property[1][
"green"][
"value"]
291 blue = property[1][
"blue"][
"value"]
294 currentColor = QColor(red, green, blue)
295 newColor = QColorDialog.getColor(currentColor)
327 row = self.indexAt(event.pos()).row()
328 selected_label = model.item(row, 0)
329 selected_value = model.item(row, 1)
339 property = selected_label.data()
340 property_name = property[1][
"name"]
342 points = property[1][
"points"]
344 property_key = property[0]
345 clip_id, item_type = selected_value.data()
347 log.info(
"Context menu shown for %s (%s) for clip %s on frame %s" % (
348 property_name, property_key, clip_id, frame_number))
349 log.info(
"Points: %s" % points)
350 log.info(
"Property: %s" % str(property))
354 (0.250, 0.100, 0.250, 1.000, _(
"Ease (Default)")),
355 (0.420, 0.000, 1.000, 1.000, _(
"Ease In")),
356 (0.000, 0.000, 0.580, 1.000, _(
"Ease Out")),
357 (0.420, 0.000, 0.580, 1.000, _(
"Ease In/Out")),
359 (0.550, 0.085, 0.680, 0.530, _(
"Ease In (Quad)")),
360 (0.550, 0.055, 0.675, 0.190, _(
"Ease In (Cubic)")),
361 (0.895, 0.030, 0.685, 0.220, _(
"Ease In (Quart)")),
362 (0.755, 0.050, 0.855, 0.060, _(
"Ease In (Quint)")),
363 (0.470, 0.000, 0.745, 0.715, _(
"Ease In (Sine)")),
364 (0.950, 0.050, 0.795, 0.035, _(
"Ease In (Expo)")),
365 (0.600, 0.040, 0.980, 0.335, _(
"Ease In (Circ)")),
366 (0.600, -0.280, 0.735, 0.045, _(
"Ease In (Back)")),
368 (0.250, 0.460, 0.450, 0.940, _(
"Ease Out (Quad)")),
369 (0.215, 0.610, 0.355, 1.000, _(
"Ease Out (Cubic)")),
370 (0.165, 0.840, 0.440, 1.000, _(
"Ease Out (Quart)")),
371 (0.230, 1.000, 0.320, 1.000, _(
"Ease Out (Quint)")),
372 (0.390, 0.575, 0.565, 1.000, _(
"Ease Out (Sine)")),
373 (0.190, 1.000, 0.220, 1.000, _(
"Ease Out (Expo)")),
374 (0.075, 0.820, 0.165, 1.000, _(
"Ease Out (Circ)")),
375 (0.175, 0.885, 0.320, 1.275, _(
"Ease Out (Back)")),
377 (0.455, 0.030, 0.515, 0.955, _(
"Ease In/Out (Quad)")),
378 (0.645, 0.045, 0.355, 1.000, _(
"Ease In/Out (Cubic)")),
379 (0.770, 0.000, 0.175, 1.000, _(
"Ease In/Out (Quart)")),
380 (0.860, 0.000, 0.070, 1.000, _(
"Ease In/Out (Quint)")),
381 (0.445, 0.050, 0.550, 0.950, _(
"Ease In/Out (Sine)")),
382 (1.000, 0.000, 0.000, 1.000, _(
"Ease In/Out (Expo)")),
383 (0.785, 0.135, 0.150, 0.860, _(
"Ease In/Out (Circ)")),
384 (0.680, -0.550, 0.265, 1.550, _(
"Ease In/Out (Back)"))
387 bezier_icon = QIcon(QPixmap(os.path.join(info.IMAGES_PATH,
"keyframe-%s.png" % openshot.BEZIER)))
388 linear_icon = QIcon(QPixmap(os.path.join(info.IMAGES_PATH,
"keyframe-%s.png" % openshot.LINEAR)))
389 constant_icon = QIcon(QPixmap(os.path.join(info.IMAGES_PATH,
"keyframe-%s.png" % openshot.CONSTANT)))
395 Bezier_Menu = QMenu(_(
"Bezier"), self)
396 Bezier_Menu.setIcon(bezier_icon)
397 for bezier_preset
in bezier_presets:
398 preset_action = Bezier_Menu.addAction(bezier_preset[4])
400 menu.addMenu(Bezier_Menu)
401 Linear_Action = menu.addAction(_(
"Linear"))
402 Linear_Action.setIcon(linear_icon)
404 Constant_Action = menu.addAction(_(
"Constant"))
405 Constant_Action.setIcon(constant_icon)
408 Insert_Action = menu.addAction(_(
"Insert Keyframe"))
410 Remove_Action = menu.addAction(_(
"Remove Keyframe"))
412 menu.popup(QCursor.pos())
415 Insert_Action = menu.addAction(_(
"Insert Keyframe"))
417 Remove_Action = menu.addAction(_(
"Remove Keyframe"))
419 menu.popup(QCursor.pos())
424 Choice_Action = menu.addAction(_(choice[
"name"]))
425 Choice_Action.setData(choice[
"value"])
428 menu.popup(QCursor.pos())
431 log.info(
"Bezier_Action_Triggered: %s" % str(preset))
440 log.info(
"Linear_Action_Triggered")
449 log.info(
"Constant_Action_Triggered")
458 log.info(
"Insert_Action_Triggered")
460 current_value = QLocale().system().toDouble(self.
selected_item.text())[0]
464 log.info(
"Remove_Action_Triggered")
468 log.info(
"Choice_Action_Triggered")
469 choice_value = self.sender().data()
476 QTableView.__init__(self, *args)
493 self.setSelectionBehavior(QAbstractItemView.SelectRows)
494 self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
495 self.setWordWrap(
True)
499 self.setItemDelegateForColumn(1, delegate)
503 horizontal_header = self.horizontalHeader()
504 horizontal_header.setSectionResizeMode(QHeaderView.Stretch)
505 vertical_header = self.verticalHeader()
506 vertical_header.setVisible(
False)
512 self.resizeColumnToContents(0)
513 self.resizeColumnToContents(1)
535 item = Clip.get(id=self.
item_id)
539 item = Transition.get(id=self.
item_id)
543 item = Effect.get(id=self.
item_id)
552 for item_id
in get_app().window.selected_clips:
553 clip = Clip.get(id=item_id)
555 item_name = clip.title()
556 item_icon = QIcon(QPixmap(clip.data.get(
'image')))
557 action = menu.addAction(item_name)
558 action.setIcon(item_icon)
559 action.setData({
'item_id':item_id,
'item_type':
'clip'})
563 for effect
in clip.data.get(
'effects'):
564 effect = Effect.get(id=effect.get(
'id'))
566 item_name = effect.title()
567 item_icon = QIcon(QPixmap(os.path.join(info.PATH,
"effects",
"icons",
"%s.png" % effect.data.get(
'class_name').lower())))
568 action = menu.addAction(
' > %s' % _(item_name))
569 action.setIcon(item_icon)
570 action.setData({
'item_id': effect.id,
'item_type':
'effect'})
574 for item_id
in get_app().window.selected_transitions:
575 trans = Transition.get(id=item_id)
577 item_name = _(trans.title())
578 item_icon = QIcon(QPixmap(trans.data.get(
'reader',{}).get(
'path')))
579 action = menu.addAction(_(item_name))
580 action.setIcon(item_icon)
581 action.setData({
'item_id': item_id,
'item_type':
'transition'})
585 for item_id
in get_app().window.selected_effects:
586 effect = Effect.get(id=item_id)
588 item_name = _(effect.title())
589 item_icon = QIcon(QPixmap(os.path.join(info.PATH,
"effects",
"icons",
"%s.png" % effect.data.get(
'class_name').lower())))
590 action = menu.addAction(_(item_name))
591 action.setIcon(item_icon)
592 action.setData({
'item_id': item_id,
'item_type':
'effect'})
600 item_id = self.sender().data()[
'item_id']
601 item_type = self.sender().data()[
'item_type']
602 log.info(
'switch selection to %s:%s' % (item_id, item_type))
605 get_app().window.propertyTableView.loadProperties.emit(item_id, item_type)
619 clip = Clip.get(id=self.
item_id)
622 self.
item_icon = QIcon(QPixmap(clip.data.get(
'image')))
624 trans = Transition.get(id=self.
item_id)
627 self.
item_icon = QIcon(QPixmap(trans.data.get(
'reader', {}).get(
'path')))
629 effect = Effect.get(id=self.
item_id)
632 self.
item_icon = QIcon(QPixmap(os.path.join(info.PATH,
"effects",
"icons",
"%s.png" % effect.data.get(
'class_name').lower())))
640 self.
lblSelection.setText(
"<strong>%s</strong>" % _(
"Selection:"))
646 self.
lblSelection.setText(
"<strong>%s</strong>" % _(
"No Selection"))
654 QFrame.__init__(self, *args)
663 self.
lblSelection.setText(
"<strong>%s</strong>" % _(
"No Selection"))
666 self.
btnSelectionName.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
672 hbox.setContentsMargins(0,0,0,0)
def __init__(self, parent=None, args)
def get_app()
Returns the current QApplication instance of OpenShot.
def mouseReleaseEvent(self, event)
def paint(self, painter, option, index)
def Bezier_Action_Triggered(self, preset=[])
def select_item(self, item_id, item_type)
Update the selected item in the properties window.
def mouseMoveEvent(self, event)
def doubleClickedCB(self, model_index)
Double click handler for the property table.
def filter_changed(self, value=None)
Filter the list of properties.
def contextMenuEvent(self, event)
def Choice_Action_Triggered(self, event)
def Linear_Action_Triggered(self, event)
def Insert_Action_Triggered(self, event)
The label to display selections.
def select_frame(self, frame_number)
Update the values of the selected clip, based on the current frame.
A Properties Table QWidget used on the main window.
def select_item(self, item_id, item_type)
def Action_Triggered(self, event)
def Constant_Action_Triggered(self, event)
def Remove_Action_Triggered(self, event)