OpenShot Video Editor  2.0.0
properties_tableview.py
Go to the documentation of this file.
1 ##
2 #
3 # @file
4 # @brief This file contains the properties tableview, used by the main window
5 # @author Jonathan Thomas <jonathan@openshot.org>
6 #
7 # @section LICENSE
8 #
9 # Copyright (c) 2008-2018 OpenShot Studios, LLC
10 # (http://www.openshotstudios.com). This file is part of
11 # OpenShot Video Editor (http://www.openshot.org), an open-source project
12 # dedicated to delivering high quality video editing and animation solutions
13 # to the world.
14 #
15 # OpenShot Video Editor is free software: you can redistribute it and/or modify
16 # it under the terms of the GNU General Public License as published by
17 # the Free Software Foundation, either version 3 of the License, or
18 # (at your option) any later version.
19 #
20 # OpenShot Video Editor is distributed in the hope that it will be useful,
21 # but WITHOUT ANY WARRANTY; without even the implied warranty of
22 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 # GNU General Public License for more details.
24 #
25 # You should have received a copy of the GNU General Public License
26 # along with OpenShot Library. If not, see <http://www.gnu.org/licenses/>.
27 #
28 
29 import os
30 from functools import partial
31 from PyQt5.QtCore import Qt, QRectF, QLocale, pyqtSignal, Qt, QObject, QTimer
32 from PyQt5.QtGui import *
33 from PyQt5.QtWidgets import QTableView, QAbstractItemView, QMenu, QSizePolicy, QHeaderView, QColorDialog, QItemDelegate, QStyle, QLabel, QPushButton, QHBoxLayout, QFrame
34 
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
40 
41 import openshot
42 
43 try:
44  import json
45 except ImportError:
46  import simplejson as json
47 
48 
49 class PropertyDelegate(QItemDelegate):
50  def __init__(self, parent=None, *args):
51  QItemDelegate.__init__(self, parent, *args)
52 
53  # pixmaps for curve icons
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))
57  }
58 
59  def paint(self, painter, option, index):
60  painter.save()
61  painter.setRenderHint(QPainter.Antialiasing)
62 
63  # Get data model and selection
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()
69 
70  # Get min/max values for this property
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"]
79 
80  # Calculate percentage value
81  if property_type in ["float", "int"]:
82  # Get the current value
83  current_value = QLocale().system().toDouble(selected_value.text())[0]
84 
85  # Shift my range to be positive
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
91 
92  # Calculate current value as % of min/max range
93  min_max_range = float(property_max) - float(property_min)
94  value_percent = current_value / min_max_range
95  else:
96  value_percent = 0.0
97 
98  # set background color
99  painter.setPen(QPen(Qt.NoPen))
100  if property_type == "color":
101  # Color keyframe
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))))
106  else:
107  # Normal Keyframe
108  if option.state & QStyle.State_Selected:
109  painter.setBrush(QBrush(QColor("#575757")))
110  else:
111  painter.setBrush(QBrush(QColor("#3e3e3e")))
112 
113  if not readonly:
114  path = QPainterPath()
115  path.addRoundedRect(QRectF(option.rect), 15, 15)
116  painter.fillPath(path, QColor("#3e3e3e"))
117  painter.drawPath(path)
118 
119  # Render mask rectangle
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)
124 
125  # gradient for value box
126  gradient = QLinearGradient(option.rect.topLeft(), option.rect.topRight())
127  gradient.setColorAt(0, QColor("#828282"))
128  gradient.setColorAt(1, QColor("#828282"))
129 
130  # Render progress
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)
138 
139  if points > 1:
140  # Draw interpolation icon on top
141  painter.drawPixmap(option.rect.x() + option.rect.width() - 30.0, option.rect.y() + 4, self.curve_pixmaps[interpolation])
142 
143  # set text color
144  painter.setPen(QPen(Qt.white))
145  value = index.data(Qt.DisplayRole)
146  if value:
147  painter.drawText(option.rect, Qt.AlignCenter, value)
148 
149  painter.restore()
150 
151 
152 ##
153 # A Properties Table QWidget used on the main window
154 class PropertiesTableView(QTableView):
155  loadProperties = pyqtSignal(str, str)
156 
157  def mouseMoveEvent(self, event):
158  # Get data model and selection
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):
163  self.selected_label = model.item(row, 0)
164  self.selected_item = model.item(row, 1)
165 
166  # Is the user dragging on the value column
167  if self.selected_label and self.selected_item:
168  frame_number = self.clip_properties_model.frame_number
169 
170  # Get the position of the cursor and % value
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)
175 
176  try:
177  property = self.selected_label.data()
178  except Exception as ex:
179  # If item is deleted during this drag... an exception can occur
180  # Just ignore, since this is harmless
181  return
182 
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()
191 
192  # Bail if readonly
193  if readonly:
194  return
195 
196  # Get the original data of this item (prior to any updates, for the undo/redo system)
197  if not self.original_data:
198  # Ignore undo/redo history temporarily (to avoid a huge pile of undo/redo history)
199  get_app().updates.ignore_history = True
200 
201  # Find this clip
202  c = None
203  if item_type == "clip":
204  # Get clip object
205  c = Clip.get(id=item_id)
206  elif item_type == "transition":
207  # Get transition object
208  c = Transition.get(id=item_id)
209  elif item_type == "effect":
210  # Get effect object
211  c = Effect.get(id=item_id)
212 
213  if c:
214  if property_key in c.data:
215  # Grab the original data for this item/property
216  self.original_data = c.data
217 
218  # Calculate percentage value
219  if property_type in ["float", "int"]:
220  min_max_range = float(property_max) - float(property_min)
221 
222  # Determine if range is unreasonably long (such as position, start, end, etc.... which can be huge #'s)
223  if min_max_range > 1000.0:
224  # Get the current value
225  self.new_value = QLocale().system().toDouble(self.selected_item.text())[0]
226 
227  # Huge range - increment / decrement slowly
228  if self.previous_x == -1:
229  # init previous_x for the first time
230  self.previous_x = event.x()
231  # calculate # of pixels dragged
232  drag_diff = self.previous_x - event.x()
233  if drag_diff > 0:
234  # Move to the left by a small amount
235  self.new_value -= 0.50
236  elif drag_diff < 0:
237  # Move to the right by a small amount
238  self.new_value += 0.50
239  # update previous x
240  self.previous_x = event.x()
241  else:
242  # Small range - use cursor % to calculate new value
243  self.new_value = property_min + (min_max_range * cursor_value_percent)
244 
245  # Clamp value between min and max (just incase user drags too big)
246  self.new_value = max(property_min, self.new_value)
247  self.new_value = min(property_max, self.new_value)
248 
249  # Update value of this property
250  self.clip_properties_model.value_updated(self.selected_item, -1, self.new_value)
251 
252  # Repaint
253  self.viewport().update()
254 
255  def mouseReleaseEvent(self, event):
256  # Inform UpdateManager to accept updates, and only store our final update
257  get_app().updates.ignore_history = False
258 
259  # Add final update to undo/redo history
260  get_app().updates.apply_last_action_to_history(self.original_data)
261 
262  # Clear original data
263  self.original_data = None
264 
265  # Get data model and selection
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):
270  self.selected_label = model.item(row, 0)
271  self.selected_item = model.item(row, 1)
272 
273  ##
274  # Double click handler for the property table
275  def doubleClickedCB(self, model_index):
276  # Get data model and selection
277  model = self.clip_properties_model.model
278 
279  row = model_index.row()
280  selected_label = model.item(row, 0)
281  self.selected_item = model.item(row, 1)
282 
283  if selected_label:
284  property = selected_label.data()
285  property_type = property[1]["type"]
286 
287  if property_type == "color":
288  # Get current value of color
289  red = property[1]["red"]["value"]
290  green = property[1]["green"]["value"]
291  blue = property[1]["blue"]["value"]
292 
293  # Show color dialog
294  currentColor = QColor(red, green, blue)
295  newColor = QColorDialog.getColor(currentColor)
296 
297  # Set the new color keyframe
298  self.clip_properties_model.color_update(self.selected_item, newColor)
299 
300  ##
301  # Update the selected item in the properties window
302  def select_item(self, item_id, item_type):
303 
304  # Get translation object
305  _ = get_app()._tr
306 
307  # Update item
308  self.clip_properties_model.update_item(item_id, item_type)
309 
310  ##
311  # Update the values of the selected clip, based on the current frame
312  def select_frame(self, frame_number):
313 
314  # Update item
315  self.clip_properties_model.update_frame(frame_number)
316 
317  ##
318  # Filter the list of properties
319  def filter_changed(self, value=None):
320 
321  # Update model
322  self.clip_properties_model.update_model(value)
323 
324  def contextMenuEvent(self, event):
325  # Get data model and selection
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)
330  self.selected_item = selected_value
331  frame_number = self.clip_properties_model.frame_number
332 
333  # Get translation object
334  _ = get_app()._tr
335 
336  # If item selected
337  if selected_label:
338  # Get data from selected item
339  property = selected_label.data()
340  property_name = property[1]["name"]
341  self.property_type = property[1]["type"]
342  points = property[1]["points"]
343  self.choices = property[1]["choices"]
344  property_key = property[0]
345  clip_id, item_type = selected_value.data()
346 
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))
351 
352  # Define bezier presets
353  bezier_presets = [
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")),
358 
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)")),
367 
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)")),
376 
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)"))
385  ]
386 
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)))
390 
391  # Add menu options for keyframes
392  menu = QMenu(self)
393  if points > 1:
394  # Menu for more than 1 point
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])
399  preset_action.triggered.connect(partial(self.Bezier_Action_Triggered, bezier_preset))
400  menu.addMenu(Bezier_Menu)
401  Linear_Action = menu.addAction(_("Linear"))
402  Linear_Action.setIcon(linear_icon)
403  Linear_Action.triggered.connect(self.Linear_Action_Triggered)
404  Constant_Action = menu.addAction(_("Constant"))
405  Constant_Action.setIcon(constant_icon)
406  Constant_Action.triggered.connect(self.Constant_Action_Triggered)
407  menu.addSeparator()
408  Insert_Action = menu.addAction(_("Insert Keyframe"))
409  Insert_Action.triggered.connect(self.Insert_Action_Triggered)
410  Remove_Action = menu.addAction(_("Remove Keyframe"))
411  Remove_Action.triggered.connect(self.Remove_Action_Triggered)
412  menu.popup(QCursor.pos())
413  elif points == 1:
414  # Menu for a single point
415  Insert_Action = menu.addAction(_("Insert Keyframe"))
416  Insert_Action.triggered.connect(self.Insert_Action_Triggered)
417  Remove_Action = menu.addAction(_("Remove Keyframe"))
418  Remove_Action.triggered.connect(self.Remove_Action_Triggered)
419  menu.popup(QCursor.pos())
420 
421  if self.choices:
422  # Menu for choices
423  for choice in self.choices:
424  Choice_Action = menu.addAction(_(choice["name"]))
425  Choice_Action.setData(choice["value"])
426  Choice_Action.triggered.connect(self.Choice_Action_Triggered)
427  # Show choice menu
428  menu.popup(QCursor.pos())
429 
430  def Bezier_Action_Triggered(self, preset=[]):
431  log.info("Bezier_Action_Triggered: %s" % str(preset))
432  if self.property_type != "color":
433  # Update keyframe interpolation mode
434  self.clip_properties_model.value_updated(self.selected_item, interpolation=0, interpolation_details=preset)
435  else:
436  # Update colors interpolation mode
437  self.clip_properties_model.color_update(self.selected_item, QColor("#000"), interpolation=0, interpolation_details=preset)
438 
439  def Linear_Action_Triggered(self, event):
440  log.info("Linear_Action_Triggered")
441  if self.property_type != "color":
442  # Update keyframe interpolation mode
443  self.clip_properties_model.value_updated(self.selected_item, interpolation=1)
444  else:
445  # Update colors interpolation mode
446  self.clip_properties_model.color_update(self.selected_item, QColor("#000"), interpolation=1, interpolation_details=[])
447 
448  def Constant_Action_Triggered(self, event):
449  log.info("Constant_Action_Triggered")
450  if self.property_type != "color":
451  # Update keyframe interpolation mode
452  self.clip_properties_model.value_updated(self.selected_item, interpolation=2)
453  else:
454  # Update colors interpolation mode
455  self.clip_properties_model.color_update(self.selected_item, QColor("#000"), interpolation=2, interpolation_details=[])
456 
457  def Insert_Action_Triggered(self, event):
458  log.info("Insert_Action_Triggered")
459  if self.selected_item:
460  current_value = QLocale().system().toDouble(self.selected_item.text())[0]
461  self.clip_properties_model.value_updated(self.selected_item, value=current_value)
462 
463  def Remove_Action_Triggered(self, event):
464  log.info("Remove_Action_Triggered")
465  self.clip_properties_model.remove_keyframe(self.selected_item)
466 
467  def Choice_Action_Triggered(self, event):
468  log.info("Choice_Action_Triggered")
469  choice_value = self.sender().data()
470 
471  # Update value of dropdown item
472  self.clip_properties_model.value_updated(self.selected_item, value=choice_value)
473 
474  def __init__(self, *args):
475  # Invoke parent init
476  QTableView.__init__(self, *args)
477 
478  # Get a reference to the window object
479  self.win = get_app().window
480 
481  # Get Model data
482  self.clip_properties_model = PropertiesModel(self)
483 
484  # Keep track of mouse press start position to determine when to start drag
485  self.selected = []
486  self.selected_label = None
487  self.selected_item = None
488  self.new_value = None
489  self.original_data = None
490 
491  # Setup header columns
492  self.setModel(self.clip_properties_model.model)
493  self.setSelectionBehavior(QAbstractItemView.SelectRows)
494  self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
495  self.setWordWrap(True)
496 
497  # Set delegate
498  delegate = PropertyDelegate()
499  self.setItemDelegateForColumn(1, delegate)
500  self.previous_x = -1
501 
502  # Get table header
503  horizontal_header = self.horizontalHeader()
504  horizontal_header.setSectionResizeMode(QHeaderView.Stretch)
505  vertical_header = self.verticalHeader()
506  vertical_header.setVisible(False)
507 
508  # Refresh view
509  self.clip_properties_model.update_model()
510 
511  # Resize columns
512  self.resizeColumnToContents(0)
513  self.resizeColumnToContents(1)
514 
515  # Connect filter signals
516  get_app().window.txtPropertyFilter.textChanged.connect(self.filter_changed)
517  get_app().window.InsertKeyframe.connect(self.Insert_Action_Triggered)
518  self.doubleClicked.connect(self.doubleClickedCB)
519  self.loadProperties.connect(self.select_item)
520 
521 
522 ##
523 # The label to display selections
524 class SelectionLabel(QFrame):
525 
526  def getMenu(self):
527  # Build menu for selection button
528  menu = QMenu(self)
529 
530  # Get translation object
531  _ = get_app()._tr
532 
533  # Look up item for more info
534  if self.item_type == "clip":
535  item = Clip.get(id=self.item_id)
536  if item:
537  self.item_name = item.title()
538  elif self.item_type == "transition":
539  item = Transition.get(id=self.item_id)
540  if item:
541  self.item_name = item.title()
542  elif self.item_type == "effect":
543  item = Effect.get(id=self.item_id)
544  if item:
545  self.item_name = item.title()
546 
547  # Bail if no item name was found
548  if not self.item_name:
549  return
550 
551  # Add selected clips
552  for item_id in get_app().window.selected_clips:
553  clip = Clip.get(id=item_id)
554  if clip:
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'})
560  action.triggered.connect(self.Action_Triggered)
561 
562  # Add effects for these clips (if any)
563  for effect in clip.data.get('effects'):
564  effect = Effect.get(id=effect.get('id'))
565  if effect:
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'})
571  action.triggered.connect(self.Action_Triggered)
572 
573  # Add selected transitions
574  for item_id in get_app().window.selected_transitions:
575  trans = Transition.get(id=item_id)
576  if trans:
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'})
582  action.triggered.connect(self.Action_Triggered)
583 
584  # Add selected effects
585  for item_id in get_app().window.selected_effects:
586  effect = Effect.get(id=item_id)
587  if effect:
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'})
593  action.triggered.connect(self.Action_Triggered)
594 
595  # Return the menu object
596  return menu
597 
598  def Action_Triggered(self, event):
599  # Switch selection
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))
603 
604  # Set the property tableview to the new item
605  get_app().window.propertyTableView.loadProperties.emit(item_id, item_type)
606 
607  # Update selected item label
608  def select_item(self, item_id, item_type):
609  self.item_name = None
610  self.item_icon = None
611  self.item_type = item_type
612  self.item_id = item_id
613 
614  # Get translation object
615  _ = get_app()._tr
616 
617  # Look up item for more info
618  if self.item_type == "clip":
619  clip = Clip.get(id=self.item_id)
620  if clip:
621  self.item_name = clip.title()
622  self.item_icon = QIcon(QPixmap(clip.data.get('image')))
623  elif self.item_type == "transition":
624  trans = Transition.get(id=self.item_id)
625  if trans:
626  self.item_name = _(trans.title())
627  self.item_icon = QIcon(QPixmap(trans.data.get('reader', {}).get('path')))
628  elif self.item_type == "effect":
629  effect = Effect.get(id=self.item_id)
630  if effect:
631  self.item_name = _(effect.title())
632  self.item_icon = QIcon(QPixmap(os.path.join(info.PATH, "effects", "icons", "%s.png" % effect.data.get('class_name').lower())))
633 
634  # Truncate long text
635  if self.item_name and len(self.item_name) > 25:
636  self.item_name = "%s..." % self.item_name[:22]
637 
638  # Set label
639  if self.item_id:
640  self.lblSelection.setText("<strong>%s</strong>" % _("Selection:"))
641  self.btnSelectionName.setText(self.item_name)
642  self.btnSelectionName.setVisible(True)
643  if self.item_icon:
644  self.btnSelectionName.setIcon(self.item_icon)
645  else:
646  self.lblSelection.setText("<strong>%s</strong>" % _("No Selection"))
647  self.btnSelectionName.setVisible(False)
648 
649  # Set the menu on the button
650  self.btnSelectionName.setMenu(self.getMenu())
651 
652  def __init__(self, *args):
653  # Invoke parent init
654  QFrame.__init__(self, *args)
655  self.item_id = None
656  self.item_type = None
657 
658  # Get translation object
659  _ = get_app()._tr
660 
661  # Widgets
662  self.lblSelection = QLabel()
663  self.lblSelection.setText("<strong>%s</strong>" % _("No Selection"))
664  self.btnSelectionName = QPushButton()
665  self.btnSelectionName.setVisible(False)
666  self.btnSelectionName.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
667 
668  # Support rich text
669  self.lblSelection.setTextFormat(Qt.RichText)
670 
671  hbox = QHBoxLayout()
672  hbox.setContentsMargins(0,0,0,0)
673  hbox.addWidget(self.lblSelection)
674  hbox.addWidget(self.btnSelectionName)
675  self.setLayout(hbox)
676 
677  # Connect signals
678  get_app().window.propertyTableView.loadProperties.connect(self.select_item)
def get_app
Returns the current QApplication instance of OpenShot.
Definition: app.py:55
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 select_frame
Update the values of the selected clip, based on the current frame.