Skip to content

Commit 9f1fb74

Browse files
authored
Merge pull request #3815 from ferdnyc/color-allover
Use ColorPicker for all color dialogs
2 parents 544fda3 + ba3e5b2 commit 9f1fb74

File tree

5 files changed

+93
-95
lines changed

5 files changed

+93
-95
lines changed

src/windows/animated_title.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ class AnimatedTitle(QDialog):
4545
# Path to ui file
4646
ui_path = os.path.join(info.PATH, 'windows', 'ui', 'animated-title.ui')
4747

48-
def __init__(self):
49-
super().__init__()
48+
def __init__(self, *args, **kwargs):
49+
super().__init__(*args, **kwargs)
5050

5151
# Load UI from designer & init
5252
ui_util.load_ui(self, self.ui_path)

src/windows/export.py

Lines changed: 26 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -67,26 +67,19 @@ class Export(QDialog):
6767

6868
ExportStarted = pyqtSignal(str, int, int)
6969
ExportFrame = pyqtSignal(str, int, int, int, str)
70-
ExportEnded = pyqtSignal(str)
70+
ExportEnded = pyqtSignal(str)
7171

72-
def __init__(self):
72+
def __init__(self, *args, **kwargs):
73+
super().__init__(*args, **kwargs)
7374

74-
# Create dialog class
75-
QDialog.__init__(self)
76-
77-
# Load UI from designer
75+
# Load UI from designer & init
7876
ui_util.load_ui(self, self.ui_path)
79-
80-
# Init UI
8177
ui_util.init_ui(self)
8278

83-
# get translations
79+
# get translations & settings
8480
_ = get_app()._tr
85-
86-
# Get settings
8781
self.s = settings.get_settings()
8882

89-
# Track metrics
9083
track_metric_screen("export-screen")
9184

9285
# Dynamically load tabs from settings data
@@ -113,9 +106,6 @@ def __init__(self):
113106
# Pause playback (to prevent crash since we are fixing to change the timeline's max size)
114107
get_app().window.actionPlay_trigger(None, force="pause")
115108

116-
# Clear timeline preview cache (to get more available memory)
117-
get_app().window.timeline_sync.timeline.ClearAllCache()
118-
119109
# Hide audio channels
120110
self.lblChannels.setVisible(False)
121111
self.txtChannels.setVisible(False)
@@ -124,25 +114,31 @@ def __init__(self):
124114
openshot.Settings.Instance().WAIT_FOR_VIDEO_PROCESSING_TASK = True
125115
openshot.Settings.Instance().HIGH_QUALITY_SCALING = True
126116

117+
project_timeline = get_app().window.timeline_sync.timeline
118+
119+
# Clear timeline preview cache (to get more available memory)
120+
project_timeline.ClearAllCache()
121+
127122
# Get the original timeline settings
128-
width = get_app().window.timeline_sync.timeline.info.width
129-
height = get_app().window.timeline_sync.timeline.info.height
130-
fps = get_app().window.timeline_sync.timeline.info.fps
131-
sample_rate = get_app().window.timeline_sync.timeline.info.sample_rate
132-
channels = get_app().window.timeline_sync.timeline.info.channels
133-
channel_layout = get_app().window.timeline_sync.timeline.info.channel_layout
123+
width = project_timeline.info.width
124+
height = project_timeline.info.height
125+
fps = project_timeline.info.fps
126+
sample_rate = project_timeline.info.sample_rate
127+
channels = project_timeline.info.channels
128+
channel_layout = project_timeline.info.channel_layout
134129

135130
# Create new "export" openshot.Timeline object
136-
self.timeline = openshot.Timeline(width, height, openshot.Fraction(fps.num, fps.den),
137-
sample_rate, channels, channel_layout)
131+
self.timeline = openshot.Timeline(
132+
width, height, openshot.Fraction(fps.num, fps.den),
133+
sample_rate, channels, channel_layout)
138134
# Init various properties
139-
self.timeline.info.channel_layout = get_app().window.timeline_sync.timeline.info.channel_layout
140-
self.timeline.info.has_audio = get_app().window.timeline_sync.timeline.info.has_audio
141-
self.timeline.info.has_video = get_app().window.timeline_sync.timeline.info.has_video
142-
self.timeline.info.video_length = get_app().window.timeline_sync.timeline.info.video_length
143-
self.timeline.info.duration = get_app().window.timeline_sync.timeline.info.duration
144-
self.timeline.info.sample_rate = get_app().window.timeline_sync.timeline.info.sample_rate
145-
self.timeline.info.channels = get_app().window.timeline_sync.timeline.info.channels
135+
self.timeline.info.sample_rate = sample_rate
136+
self.timeline.info.channels = channels
137+
self.timeline.info.channel_layout = channel_layout
138+
self.timeline.info.has_audio = project_timeline.info.has_audio
139+
self.timeline.info.has_video = project_timeline.info.has_video
140+
self.timeline.info.video_length = project_timeline.info.video_length
141+
self.timeline.info.duration = project_timeline.info.duration
146142

147143
# Load the "export" Timeline reader with the JSON from the real timeline
148144
json_timeline = json.dumps(get_app().project._data)

src/windows/title_editor.py

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
# Is one even necessary, or is it safe to use xml.dom.minidom for that?
3838
from xml.dom import minidom
3939

40-
from PyQt5.QtCore import Qt, QTimer
40+
from PyQt5.QtCore import Qt, pyqtSlot, QTimer
4141
from PyQt5 import QtGui
4242
from PyQt5.QtWidgets import (
4343
QWidget, QGraphicsScene,
@@ -51,8 +51,9 @@
5151
from classes.logger import log
5252
from classes.app import get_app
5353
from classes.metrics import track_metric_screen
54+
from windows.views.titles_listview import TitlesListView
55+
from windows.color_picker import ColorPicker
5456
from classes.style_tools import style_to_dict, dict_to_style, set_if_existing
55-
5657
from windows.views.titles_listview import TitlesListView
5758

5859

@@ -368,6 +369,15 @@ def save_and_reload(self):
368369
self.writeToFile(self.xmldoc)
369370
self.display_svg()
370371

372+
@pyqtSlot(QtGui.QColor)
373+
def color_callback(self, save_fn, refresh_fn, color):
374+
"""Update SVG color after user selection"""
375+
if not color or not color.isValid():
376+
return
377+
save_fn(color.name(), color.alphaF())
378+
refresh_fn()
379+
self.save_and_reload()
380+
371381
@staticmethod
372382
def best_contrast(bg: QtGui.QColor) -> QtGui.QColor:
373383
"""Choose text color for best contrast against a background"""
@@ -382,39 +392,33 @@ def btnFontColor_clicked(self):
382392
app = get_app()
383393
_ = app._tr
384394

395+
callback_func = functools.partial(
396+
self.color_callback,
397+
self.set_font_color_elements,
398+
self.update_font_color_button)
385399
# Get color from user
386-
col = QColorDialog.getColor(self.font_color_code, self, _("Select a Color"),
387-
QColorDialog.DontUseNativeDialog | QColorDialog.ShowAlphaChannel)
388-
389-
# Update SVG colors
390-
if col.isValid():
391-
self.set_font_color_elements(col.name(), col.alphaF())
392-
self.update_font_color_button()
393-
394-
# Something changed, so update temp SVG
395-
self.writeToFile(self.xmldoc)
396-
397-
# Display SVG again
398-
self.display_svg()
400+
log.debug("Launching color picker for %s", self.font_color_code.name())
401+
ColorPicker(
402+
self.font_color_code, parent=self,
403+
title=_("Select a Color"),
404+
extra_options=QColorDialog.ShowAlphaChannel,
405+
callback=callback_func)
399406

400407
def btnBackgroundColor_clicked(self):
401408
app = get_app()
402409
_ = app._tr
403410

411+
callback_func = functools.partial(
412+
self.color_callback,
413+
self.set_bg_style,
414+
self.update_background_color_button)
404415
# Get color from user
405-
col = QColorDialog.getColor(self.bg_color_code, self, _("Select a Color"),
406-
QColorDialog.DontUseNativeDialog | QColorDialog.ShowAlphaChannel)
407-
408-
# Update SVG colors
409-
if col.isValid():
410-
self.set_bg_style(col.name(), col.alphaF())
411-
self.update_background_color_button()
412-
413-
# Something changed, so update temp SVG
414-
self.writeToFile(self.xmldoc)
415-
416-
# Display SVG again
417-
self.display_svg()
416+
log.debug("Launching color picker for %s", self.bg_color_code.name())
417+
ColorPicker(
418+
self.bg_color_code, parent=self,
419+
title=_("Select a Color"),
420+
extra_options=QColorDialog.ShowAlphaChannel,
421+
callback=callback_func)
418422

419423
def btnFont_clicked(self):
420424
app = get_app()

src/windows/views/blender_listview.py

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
Qt, QObject, pyqtSlot, pyqtSignal, QThread, QTimer, QSize,
4545
)
4646
from PyQt5.QtWidgets import (
47-
QApplication, QListView, QMessageBox, QColorDialog,
47+
QApplication, QListView, QMessageBox,
4848
QComboBox, QDoubleSpinBox, QLabel, QPushButton, QLineEdit, QPlainTextEdit,
4949
)
5050
from PyQt5.QtGui import QColor, QImage, QPixmap
@@ -54,7 +54,9 @@
5454
from classes import settings
5555
from classes.query import File
5656
from classes.app import get_app
57+
5758
from windows.models.blender_model import BlenderModel
59+
from windows.color_picker import ColorPicker
5860

5961

6062
class BlenderListView(QListView):
@@ -228,24 +230,13 @@ def color_button_clicked(self, widget, param, index):
228230
currentColor.setRgbF(color_value[0], color_value[1], color_value[2])
229231
# Store our arguments for the callback to pick up again
230232
self._color_scratchpad = (widget, param)
231-
232-
# Set up non-modal color dialog (to avoid blocking the eyedropper)
233-
self.newColorDialog = QColorDialog(currentColor, self.win)
234-
self.newColorDialog.setWindowTitle(_("Select a Color"))
235-
self.newColorDialog.setWindowFlags(Qt.Tool)
236-
self.newColorDialog.setOptions(QColorDialog.DontUseNativeDialog)
237-
# Avoid signal loops
238-
self.newColorDialog.blockSignals(True)
239-
self.newColorDialog.colorSelected.connect(self.color_selected)
240-
self.newColorDialog.finished.connect(self.newColorDialog.deleteLater)
241-
self.newColorDialog.blockSignals(False)
242-
self.newColorDialog.open()
233+
ColorPicker(currentColor, callback=self.color_selected, parent=self.win)
243234

244235
@pyqtSlot(QColor)
245236
def color_selected(self, newColor):
246-
"""QColorDialog callback when the user chooses a color"""
237+
"""Callback when the user chooses a color in the dialog"""
247238
if not self._color_scratchpad:
248-
log.warning("QColorDialog callback called without parameter to set")
239+
log.warning("ColorPicker callback called without parameter to set")
249240
return
250241
(widget, param) = self._color_scratchpad
251242
if not newColor or not newColor.isValid():
@@ -673,7 +664,6 @@ def __init__(self, parent, *args):
673664
self.selected = None
674665
self.deselected = None
675666
self._color_scratchpad = None
676-
self.newColorDialog = None
677667
self.selected_template = ""
678668
self.final_render = False
679669

src/windows/views/properties_tableview.py

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -26,24 +26,27 @@
2626
"""
2727

2828
import os
29-
from functools import partial
29+
import functools
3030
from operator import itemgetter
31-
from PyQt5.QtCore import Qt, QRectF, QLocale, pyqtSignal, QTimer
31+
32+
from PyQt5.QtCore import Qt, QRectF, QLocale, pyqtSignal, pyqtSlot
3233
from PyQt5.QtGui import (
3334
QCursor, QIcon, QColor, QBrush, QPen, QPalette, QPixmap,
3435
QPainter, QPainterPath, QLinearGradient, QFont, QFontInfo,
3536
)
3637
from PyQt5.QtWidgets import (
3738
QTableView, QAbstractItemView, QMenu, QSizePolicy,
38-
QHeaderView, QColorDialog, QItemDelegate, QStyle, QLabel,
39+
QHeaderView, QItemDelegate, QStyle, QLabel,
3940
QPushButton, QHBoxLayout, QFrame, QFontDialog
4041
)
4142

4243
from classes.logger import log
4344
from classes.app import get_app
4445
from classes import info
4546
from classes.query import Clip, Effect, Transition
47+
4648
from windows.models.properties_model import PropertiesModel
49+
from windows.color_picker import ColorPicker
4750

4851
import openshot
4952

@@ -297,6 +300,13 @@ def mouseReleaseEvent(self, event):
297300
self.lock_selection = False
298301
self.previous_x = -1
299302

303+
@pyqtSlot(QColor)
304+
def color_callback(self, newColor: QColor):
305+
# Set the new color keyframe
306+
if newColor.isValid():
307+
self.clip_properties_model.color_update(
308+
self.selected_item, newColor)
309+
300310
def doubleClickedCB(self, model_index):
301311
"""Double click handler for the property table"""
302312

@@ -322,12 +332,11 @@ def doubleClickedCB(self, model_index):
322332

323333
# Show color dialog
324334
currentColor = QColor(red, green, blue)
325-
newColor = QColorDialog.getColor(currentColor, self, _("Select a Color"),
326-
QColorDialog.DontUseNativeDialog)
327-
328-
# Set the new color keyframe
329-
if newColor.isValid():
330-
self.clip_properties_model.color_update(self.selected_item, newColor)
335+
log.debug("Launching ColorPicker for %s", currentColor.name())
336+
ColorPicker(
337+
currentColor, parent=self, title=_("Select a Color"),
338+
callback=self.color_callback)
339+
return
331340

332341
elif property_type == "font":
333342
# Get font from user
@@ -381,7 +390,7 @@ def filter_changed(self, value=None):
381390
self.clip_properties_model.update_model(value)
382391

383392
def contextMenuEvent(self, event):
384-
""" Display context menu, or release lock when menu displays """
393+
""" Display context menu """
385394
# Get property being acted on
386395
index = self.indexAt(event.pos())
387396
if not index.isValid():
@@ -469,6 +478,7 @@ def contextMenuEvent(self, event):
469478
track_name = track.get("label") or _("Track %s") % display_count
470479
self.choices.append({"name": track_name, "value": track.get("number"), "selected": False, "icon": None})
471480
display_count -= 1
481+
return
472482

473483
elif self.property_type == "font":
474484
# Get font from user
@@ -480,7 +490,6 @@ def contextMenuEvent(self, event):
480490
if ok and font:
481491
fontinfo = QFontInfo(font)
482492
self.clip_properties_model.value_updated(self.selected_item, value=fontinfo.family())
483-
return self.contextMenuEvent(event, release=True)
484493

485494
elif self.property_type == "color":
486495
# Get current value of color
@@ -490,13 +499,11 @@ def contextMenuEvent(self, event):
490499

491500
# Show color dialog
492501
currentColor = QColor(red, green, blue)
493-
newColor = QColorDialog.getColor(currentColor, self, _("Select a Color"),
494-
QColorDialog.DontUseNativeDialog)
495-
496-
# Set the new color keyframe
497-
if newColor.isValid():
498-
self.clip_properties_model.color_update(self.selected_item, newColor)
499-
return self.contextMenuEvent(event, release=True)
502+
log.debug("Launching ColorPicker for %s", currentColor.name())
503+
ColorPicker(
504+
currentColor, parent=self, title=_("Select a Color"),
505+
callback=self.color_callback)
506+
return
500507

501508
# Define bezier presets
502509
bezier_presets = [
@@ -540,7 +547,8 @@ def contextMenuEvent(self, event):
540547
Bezier_Menu = menu.addMenu(self.bezier_icon, _("Bezier"))
541548
for bezier_preset in bezier_presets:
542549
preset_action = Bezier_Menu.addAction(bezier_preset[4])
543-
preset_action.triggered.connect(partial(self.Bezier_Action_Triggered, bezier_preset))
550+
preset_action.triggered.connect(functools.partial(
551+
self.Bezier_Action_Triggered, bezier_preset))
544552
Linear_Action = menu.addAction(self.linear_icon, _("Linear"))
545553
Linear_Action.triggered.connect(self.Linear_Action_Triggered)
546554
Constant_Action = menu.addAction(self.constant_icon, _("Constant"))

0 commit comments

Comments
 (0)