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)
159 model = self.clip_properties_model.model
160 row = self.indexAt(event.pos()).row()
161 column = self.indexAt(event.pos()).column()
162 if model.item(row, 0):
168 frame_number = self.clip_properties_model.frame_number
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)
177 property = self.selected_label.data()
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"]
190 item_id, item_type = self.selected_item.data()
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:
225 self.
new_value = QLocale().system().toDouble(self.selected_item.text())[0]
243 self.
new_value = property_min + (min_max_range * cursor_value_percent)
253 self.viewport().update()
257 get_app().updates.ignore_history =
False
266 model = self.clip_properties_model.model
267 row = self.indexAt(event.pos()).row()
268 column = self.indexAt(event.pos()).column()
269 if model.item(row, 0):
277 model = self.clip_properties_model.model
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)
298 self.clip_properties_model.color_update(self.
selected_item, newColor)
308 self.clip_properties_model.update_item(item_id, item_type)
315 self.clip_properties_model.update_frame(frame_number)
322 self.clip_properties_model.update_model(value)
326 model = self.clip_properties_model.model
327 row = self.indexAt(event.pos()).row()
328 selected_label = model.item(row, 0)
329 selected_value = model.item(row, 1)
331 frame_number = self.clip_properties_model.frame_number
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))
434 self.clip_properties_model.value_updated(self.
selected_item, interpolation=0, interpolation_details=preset)
437 self.clip_properties_model.color_update(self.
selected_item, QColor(
"#000"), interpolation=0, interpolation_details=preset)
440 log.info(
"Linear_Action_Triggered")
443 self.clip_properties_model.value_updated(self.
selected_item, interpolation=1)
446 self.clip_properties_model.color_update(self.
selected_item, QColor(
"#000"), interpolation=1, interpolation_details=[])
449 log.info(
"Constant_Action_Triggered")
452 self.clip_properties_model.value_updated(self.
selected_item, interpolation=2)
455 self.clip_properties_model.color_update(self.
selected_item, QColor(
"#000"), interpolation=2, interpolation_details=[])
458 log.info(
"Insert_Action_Triggered")
460 current_value = QLocale().system().toDouble(self.selected_item.text())[0]
461 self.clip_properties_model.value_updated(self.
selected_item, value=current_value)
464 log.info(
"Remove_Action_Triggered")
465 self.clip_properties_model.remove_keyframe(self.
selected_item)
468 log.info(
"Choice_Action_Triggered")
469 choice_value = self.sender().data()
472 self.clip_properties_model.value_updated(self.
selected_item, value=choice_value)
476 QTableView.__init__(self, *args)
492 self.setModel(self.clip_properties_model.model)
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)
509 self.clip_properties_model.update_model()
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:"))
641 self.btnSelectionName.setText(self.
item_name)
642 self.btnSelectionName.setVisible(
True)
644 self.btnSelectionName.setIcon(self.
item_icon)
646 self.lblSelection.setText(
"<strong>%s</strong>" % _(
"No Selection"))
647 self.btnSelectionName.setVisible(
False)
650 self.btnSelectionName.setMenu(self.
getMenu())
654 QFrame.__init__(self, *args)
663 self.lblSelection.setText(
"<strong>%s</strong>" % _(
"No Selection"))
665 self.btnSelectionName.setVisible(
False)
666 self.btnSelectionName.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
669 self.lblSelection.setTextFormat(Qt.RichText)
672 hbox.setContentsMargins(0,0,0,0)
def Constant_Action_Triggered
def Remove_Action_Triggered
def get_app
Returns the current QApplication instance of OpenShot.
def Choice_Action_Triggered
def Linear_Action_Triggered
def filter_changed
Filter the list of properties.
def select_item
Update the selected item in the properties window.
The label to display selections.
A Properties Table QWidget used on the main window.
def doubleClickedCB
Double click handler for the property table.
def Insert_Action_Triggered
def select_frame
Update the values of the selected clip, based on the current frame.
def Bezier_Action_Triggered