From 542796f74e080bb15235752e372534cc5c1932eb Mon Sep 17 00:00:00 2001 From: Darby Johnston Date: Sat, 29 Jun 2024 17:30:58 -0700 Subject: [PATCH] Add a color picker --- lib/tlPlayApp/CMakeLists.txt | 2 + lib/tlPlayApp/ColorPickerTool.cpp | 115 ++++++++++++++++++++++++++ lib/tlPlayApp/ColorPickerTool.h | 47 +++++++++++ lib/tlPlayApp/MainWindow.cpp | 14 ++-- lib/tlPlayApp/Tools.cpp | 7 +- lib/tlPlayApp/Tools.h | 2 +- lib/tlPlayApp/ToolsActions.cpp | 3 + lib/tlPlayApp/ToolsWidget.cpp | 12 ++- lib/tlPlayApp/ToolsWidget.h | 3 + lib/tlPlayQtApp/AudioTool.cpp | 2 +- lib/tlPlayQtApp/CMakeLists.txt | 2 + lib/tlPlayQtApp/ColorPickerTool.cpp | 110 ++++++++++++++++++++++++ lib/tlPlayQtApp/ColorPickerTool.h | 42 ++++++++++ lib/tlPlayQtApp/DevicesTool.cpp | 2 +- lib/tlPlayQtApp/InfoTool.cpp | 2 +- lib/tlPlayQtApp/MainWindow.cpp | 9 ++ lib/tlPlayQtApp/MessagesTool.cpp | 2 +- lib/tlPlayQtApp/SystemLogTool.cpp | 2 +- lib/tlPlayQtApp/ViewTool.cpp | 2 +- lib/tlQtWidget/TimelineViewport.cpp | 28 ++++++- lib/tlQtWidget/TimelineViewport.h | 3 + lib/tlTimelineUI/TimelineViewport.cpp | 43 +++++++++- lib/tlTimelineUI/TimelineViewport.h | 3 + 23 files changed, 437 insertions(+), 20 deletions(-) create mode 100644 lib/tlPlayApp/ColorPickerTool.cpp create mode 100644 lib/tlPlayApp/ColorPickerTool.h create mode 100644 lib/tlPlayQtApp/ColorPickerTool.cpp create mode 100644 lib/tlPlayQtApp/ColorPickerTool.h diff --git a/lib/tlPlayApp/CMakeLists.txt b/lib/tlPlayApp/CMakeLists.txt index a65cd54f0..50e8cd278 100644 --- a/lib/tlPlayApp/CMakeLists.txt +++ b/lib/tlPlayApp/CMakeLists.txt @@ -4,6 +4,7 @@ set(HEADERS AudioMenu.h AudioPopup.h AudioTool.h + ColorPickerTool.h ColorTool.h CompareActions.h CompareMenu.h @@ -57,6 +58,7 @@ set(SOURCE AudioMenu.cpp AudioPopup.cpp AudioTool.cpp + ColorPickerTool.cpp ColorTool.cpp CompareActions.cpp CompareMenu.cpp diff --git a/lib/tlPlayApp/ColorPickerTool.cpp b/lib/tlPlayApp/ColorPickerTool.cpp new file mode 100644 index 000000000..97b9dc58f --- /dev/null +++ b/lib/tlPlayApp/ColorPickerTool.cpp @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2021-2024 Darby Johnston +// All rights reserved. + +#include + +#include +#include + +#include +#include +#include +#include + +#include + +namespace tl +{ + namespace play_app + { + struct ColorPickerTool::Private + { + image::Color4f color; + std::shared_ptr swatch; + std::vector > labels; + std::shared_ptr layout; + std::shared_ptr > colorPickerObserver; + }; + + void ColorPickerTool::_init( + const std::shared_ptr& mainWindow, + const std::shared_ptr& app, + const std::shared_ptr& context, + const std::shared_ptr& parent) + { + IToolWidget::_init( + Tool::ColorPicker, + "tl::play_app::ColorPickerTool", + app, + context, + parent); + TLRENDER_P(); + + p.swatch = ui::ColorSwatch::create(context); + p.swatch->setSizeRole(ui::SizeRole::SwatchLarge); + + p.labels.push_back(ui::Label::create(context)); + p.labels.push_back(ui::Label::create(context)); + p.labels.push_back(ui::Label::create(context)); + p.labels.push_back(ui::Label::create(context)); + + p.layout = ui::VerticalLayout::create(context); + p.layout->setMarginRole(ui::SizeRole::MarginSmall); + p.layout->setSpacingRole(ui::SizeRole::SpacingSmall); + p.swatch->setParent(p.layout); + auto gridLayout = ui::GridLayout::create(context, p.layout); + gridLayout->setSpacingRole(ui::SizeRole::SpacingSmall); + auto label = ui::Label::create("Red:", context, gridLayout); + gridLayout->setGridPos(label, 0, 0); + p.labels[0]->setParent(gridLayout); + gridLayout->setGridPos(p.labels[0], 0, 1); + label = ui::Label::create("Green:", context, gridLayout); + gridLayout->setGridPos(label, 1, 0); + p.labels[1]->setParent(gridLayout); + gridLayout->setGridPos(p.labels[1], 1, 1); + label = ui::Label::create("Blue:", context, gridLayout); + gridLayout->setGridPos(label, 2, 0); + p.labels[2]->setParent(gridLayout); + gridLayout->setGridPos(p.labels[2], 2, 1); + label = ui::Label::create("Alpha:", context, gridLayout); + gridLayout->setGridPos(label, 3, 0); + p.labels[3]->setParent(gridLayout); + gridLayout->setGridPos(p.labels[3], 3, 1); + _setWidget(p.layout); + + _widgetUpdate(); + + p.colorPickerObserver = observer::ValueObserver::create( + mainWindow->getViewport()->observeColorPicker(), + [this](const image::Color4f& value) + { + _p->color = value; + _widgetUpdate(); + }); + } + + ColorPickerTool::ColorPickerTool() : + _p(new Private) + {} + + ColorPickerTool::~ColorPickerTool() + {} + + std::shared_ptr ColorPickerTool::create( + const std::shared_ptr& mainWindow, + const std::shared_ptr& app, + const std::shared_ptr& context, + const std::shared_ptr& parent) + { + auto out = std::shared_ptr(new ColorPickerTool); + out->_init(mainWindow, app, context, parent); + return out; + } + + void ColorPickerTool::_widgetUpdate() + { + TLRENDER_P(); + p.swatch->setColor(p.color); + p.labels[0]->setText(string::Format("{0}").arg(p.color.r)); + p.labels[1]->setText(string::Format("{0}").arg(p.color.g)); + p.labels[2]->setText(string::Format("{0}").arg(p.color.b)); + p.labels[3]->setText(string::Format("{0}").arg(p.color.a)); + } + } +} diff --git a/lib/tlPlayApp/ColorPickerTool.h b/lib/tlPlayApp/ColorPickerTool.h new file mode 100644 index 000000000..293440bae --- /dev/null +++ b/lib/tlPlayApp/ColorPickerTool.h @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2021-2024 Darby Johnston +// All rights reserved. + +#pragma once + +#include + +#include + +namespace tl +{ + namespace play_app + { + class App; + class MainWindow; + + //! Color picker tool. + class ColorPickerTool : public IToolWidget + { + TLRENDER_NON_COPYABLE(ColorPickerTool); + + protected: + void _init( + const std::shared_ptr&, + const std::shared_ptr&, + const std::shared_ptr&, + const std::shared_ptr& parent); + + ColorPickerTool(); + + public: + virtual ~ColorPickerTool(); + + static std::shared_ptr create( + const std::shared_ptr&, + const std::shared_ptr&, + const std::shared_ptr&, + const std::shared_ptr& parent = nullptr); + + private: + void _widgetUpdate(); + + TLRENDER_PRIVATE(); + }; + } +} diff --git a/lib/tlPlayApp/MainWindow.cpp b/lib/tlPlayApp/MainWindow.cpp index e28049d1d..604bff13c 100644 --- a/lib/tlPlayApp/MainWindow.cpp +++ b/lib/tlPlayApp/MainWindow.cpp @@ -413,7 +413,10 @@ namespace tl p.infoLabel->setHAlign(ui::HAlign::Right); p.infoLabel->setMarginRole(ui::SizeRole::MarginInside); - p.toolsWidget = ToolsWidget::create(app, context); + p.toolsWidget = ToolsWidget::create( + std::dynamic_pointer_cast(shared_from_this()), + app, + context); p.toolsWidget->hide(); p.layout = ui::VerticalLayout::create(context, shared_from_this()); @@ -459,11 +462,12 @@ namespace tl hLayout->setSpacingRole(ui::SizeRole::SpacingTool); p.speedEdit->setParent(hLayout); p.speedButton->setParent(hLayout); - auto spacer = ui::Spacer::create(ui::Orientation::Horizontal, context); + auto spacer = ui::Spacer::create(ui::Orientation::Horizontal, context, p.bottomLayout); spacer->setHStretch(ui::Stretch::Expanding); - spacer->setParent(p.bottomLayout); - p.audioButton->setParent(p.bottomLayout); - p.muteButton->setParent(p.bottomLayout); + hLayout = ui::HorizontalLayout::create(context, p.bottomLayout); + hLayout->setSpacingRole(ui::SizeRole::SpacingTool); + p.audioButton->setParent(hLayout); + p.muteButton->setParent(hLayout); p.dividers["Status"] = ui::Divider::create(ui::Orientation::Vertical, context, p.layout); p.statusLayout = ui::HorizontalLayout::create(context, p.layout); p.statusLayout->setSpacingRole(ui::SizeRole::None); diff --git a/lib/tlPlayApp/Tools.cpp b/lib/tlPlayApp/Tools.cpp index a0a97b075..9b8a3570e 100644 --- a/lib/tlPlayApp/Tools.cpp +++ b/lib/tlPlayApp/Tools.cpp @@ -19,6 +19,7 @@ namespace tl "Files", "View", "Color", + "ColorPicker", "Info", "Audio", "Devices", @@ -34,6 +35,7 @@ namespace tl "Files", "View", "Color", + "Color Picker", "Information", "Audio", "Devices", @@ -51,6 +53,7 @@ namespace tl "Files", "View", "Color", + "ColorPicker", "Info", "Audio", "Devices", @@ -73,7 +76,8 @@ namespace tl ui::Key::F6, ui::Key::F7, ui::Key::F8, - ui::Key::F9 + ui::Key::F9, + ui::Key::F10 }; return data[static_cast(value)]; } @@ -85,6 +89,7 @@ namespace tl Tool::Files, Tool::View, Tool::Color, + Tool::ColorPicker, Tool::Info, Tool::Audio, Tool::Devices, diff --git a/lib/tlPlayApp/Tools.h b/lib/tlPlayApp/Tools.h index f103fcda2..dee0c4f84 100644 --- a/lib/tlPlayApp/Tools.h +++ b/lib/tlPlayApp/Tools.h @@ -14,13 +14,13 @@ namespace tl { //! Tools. //! - //! \todo Add a color picker. //! \todo Add a magnifier. enum class Tool { Files, View, Color, + ColorPicker, Info, Audio, Devices, diff --git a/lib/tlPlayApp/ToolsActions.cpp b/lib/tlPlayApp/ToolsActions.cpp index 95e2ab126..88b85959f 100644 --- a/lib/tlPlayApp/ToolsActions.cpp +++ b/lib/tlPlayApp/ToolsActions.cpp @@ -35,6 +35,9 @@ namespace tl "Show the color tool\n" "\n" "Shortcut: {0}", + "Show the color picker tool\n" + "\n" + "Shortcut: {0}", "Show the information tool\n" "\n" "Shortcut: {0}", diff --git a/lib/tlPlayApp/ToolsWidget.cpp b/lib/tlPlayApp/ToolsWidget.cpp index a46e940aa..387042b53 100644 --- a/lib/tlPlayApp/ToolsWidget.cpp +++ b/lib/tlPlayApp/ToolsWidget.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -30,6 +31,7 @@ namespace tl }; void ToolsWidget::_init( + const std::shared_ptr& mainWindow, const std::shared_ptr& app, const std::shared_ptr& context, const std::shared_ptr& parent) @@ -42,6 +44,7 @@ namespace tl p.toolWidgets[Tool::Audio] = AudioTool::create(app, context); p.toolWidgets[Tool::Color] = ColorTool::create(app, context); + p.toolWidgets[Tool::ColorPicker] = ColorPickerTool::create(mainWindow, app, context); p.toolWidgets[Tool::Devices] = DevicesTool::create(app, context); p.toolWidgets[Tool::Files] = FilesTool::create(app, context); p.toolWidgets[Tool::Info] = InfoTool::create(app, context); @@ -73,12 +76,13 @@ namespace tl {} std::shared_ptr ToolsWidget::create( - const std::shared_ptr&app, - const std::shared_ptr&context, - const std::shared_ptr&parent) + const std::shared_ptr& mainWindow, + const std::shared_ptr& app, + const std::shared_ptr& context, + const std::shared_ptr& parent) { auto out = std::shared_ptr(new ToolsWidget); - out->_init(app, context, parent); + out->_init(mainWindow, app, context, parent); return out; } diff --git a/lib/tlPlayApp/ToolsWidget.h b/lib/tlPlayApp/ToolsWidget.h index 79fe4f225..4212359d2 100644 --- a/lib/tlPlayApp/ToolsWidget.h +++ b/lib/tlPlayApp/ToolsWidget.h @@ -13,6 +13,7 @@ namespace tl namespace play_app { class App; + class MainWindow; //! Tools widget. class ToolsWidget : public ui::IWidget @@ -21,6 +22,7 @@ namespace tl protected: void _init( + const std::shared_ptr&, const std::shared_ptr&, const std::shared_ptr&, const std::shared_ptr& parent); @@ -32,6 +34,7 @@ namespace tl //! Create a new widget. static std::shared_ptr create( + const std::shared_ptr&, const std::shared_ptr&, const std::shared_ptr&, const std::shared_ptr& parent = nullptr); diff --git a/lib/tlPlayQtApp/AudioTool.cpp b/lib/tlPlayQtApp/AudioTool.cpp index d2393e6a3..758ff3010 100644 --- a/lib/tlPlayQtApp/AudioTool.cpp +++ b/lib/tlPlayQtApp/AudioTool.cpp @@ -97,7 +97,7 @@ namespace tl setWidget(audioTool); toggleViewAction()->setIcon(QIcon(":/Icons/Audio.svg")); - toggleViewAction()->setShortcut(QKeySequence(Qt::Key_F5)); + toggleViewAction()->setShortcut(QKeySequence(Qt::Key_F6)); toggleViewAction()->setToolTip(tr("Show audio controls")); } } diff --git a/lib/tlPlayQtApp/CMakeLists.txt b/lib/tlPlayQtApp/CMakeLists.txt index a7d3bb34a..88e16731b 100644 --- a/lib/tlPlayQtApp/CMakeLists.txt +++ b/lib/tlPlayQtApp/CMakeLists.txt @@ -2,6 +2,7 @@ set(HEADERS App.h AudioActions.h AudioTool.h + ColorPickerTool.h ColorTool.h CompareActions.h DevicesTool.h @@ -33,6 +34,7 @@ set(SOURCE App.cpp AudioActions.cpp AudioTool.cpp + ColorPickerTool.cpp ColorTool.cpp CompareActions.cpp DevicesTool.cpp diff --git a/lib/tlPlayQtApp/ColorPickerTool.cpp b/lib/tlPlayQtApp/ColorPickerTool.cpp new file mode 100644 index 000000000..6c530ac55 --- /dev/null +++ b/lib/tlPlayQtApp/ColorPickerTool.cpp @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2021-2024 Darby Johnston +// All rights reserved. + +#include + +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include + +namespace tl +{ + namespace play_qt + { + struct ColorPickerTool::Private + { + image::Color4f color; + qtwidget::ColorSwatch* colorSwatch = nullptr; + std::vector labels; + }; + + ColorPickerTool::ColorPickerTool(MainWindow* mainWindow, App* app, QWidget* parent) : + IToolWidget(app, parent), + _p(new Private) + { + TLRENDER_P(); + + p.colorSwatch = new qtwidget::ColorSwatch; + p.colorSwatch->setSwatchSize(40); + + p.labels.push_back(new QLabel); + p.labels.push_back(new QLabel); + p.labels.push_back(new QLabel); + p.labels.push_back(new QLabel); + + auto widget = new QWidget; + auto layout = new QVBoxLayout; + layout->setContentsMargins(0, 0, 0, 0); + layout->addWidget(p.colorSwatch); + auto formLayout = new QFormLayout; + layout->addLayout(formLayout); + formLayout->addRow("Red:", p.labels[0]); + formLayout->addRow("Green:", p.labels[1]); + formLayout->addRow("Blue:", p.labels[2]); + formLayout->addRow("Alpha:", p.labels[3]); + widget->setLayout(layout); + addWidget(widget); + + addStretch(); + + _widgetUpdate(); + + connect( + mainWindow->viewport(), + &Viewport::colorPickerChanged, + [this](const image::Color4f& value) + { + _p->color = value; + _widgetUpdate(); + }); + } + + ColorPickerTool::~ColorPickerTool() + {} + + void ColorPickerTool::_widgetUpdate() + { + TLRENDER_P(); + p.colorSwatch->setColor(p.color); + p.labels[0]->setText(QString::fromUtf8( + std::string(string::Format("{0}").arg(p.color.r)).c_str())); + p.labels[1]->setText(QString::fromUtf8( + std::string(string::Format("{0}").arg(p.color.g)).c_str())); + p.labels[2]->setText(QString::fromUtf8( + std::string(string::Format("{0}").arg(p.color.b)).c_str())); + p.labels[3]->setText(QString::fromUtf8( + std::string(string::Format("{0}").arg(p.color.a)).c_str())); + } + + ColorPickerDockWidget::ColorPickerDockWidget( + ColorPickerTool* colorPickerTool, + QWidget* parent) + { + setObjectName("ColorPickerTool"); + setWindowTitle(tr("Color Picker")); + setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); + + auto dockTitleBar = new DockTitleBar; + dockTitleBar->setText(tr("Color Picker")); + dockTitleBar->setIcon(QIcon(":/Icons/ColorPicker.svg")); + auto dockWidget = new QDockWidget; + setTitleBarWidget(dockTitleBar); + + setWidget(colorPickerTool); + + toggleViewAction()->setIcon(QIcon(":/Icons/ColorPicker.svg")); + toggleViewAction()->setShortcut(QKeySequence(Qt::Key_F4)); + toggleViewAction()->setToolTip(tr("Show color picker")); + } + } +} diff --git a/lib/tlPlayQtApp/ColorPickerTool.h b/lib/tlPlayQtApp/ColorPickerTool.h new file mode 100644 index 000000000..f75aac943 --- /dev/null +++ b/lib/tlPlayQtApp/ColorPickerTool.h @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2021-2024 Darby Johnston +// All rights reserved. + +#pragma once + +#include + +#include + +namespace tl +{ + namespace play_qt + { + class MainWindow; + + //! Color picker tool. + class ColorPickerTool : public IToolWidget + { + Q_OBJECT + + public: + ColorPickerTool(MainWindow*, App*, QWidget* parent = nullptr); + + virtual ~ColorPickerTool(); + + private: + void _widgetUpdate(); + + TLRENDER_PRIVATE(); + }; + + //! Color picker tool dock widget. + class ColorPickerDockWidget : public QDockWidget + { + Q_OBJECT + + public: + ColorPickerDockWidget(ColorPickerTool*, QWidget* parent = nullptr); + }; + } +} diff --git a/lib/tlPlayQtApp/DevicesTool.cpp b/lib/tlPlayQtApp/DevicesTool.cpp index 00142f540..190a81eef 100644 --- a/lib/tlPlayQtApp/DevicesTool.cpp +++ b/lib/tlPlayQtApp/DevicesTool.cpp @@ -368,7 +368,7 @@ namespace tl setWidget(devicesTool); toggleViewAction()->setIcon(QIcon(":/Icons/Devices.svg")); - toggleViewAction()->setShortcut(QKeySequence(Qt::Key_F6)); + toggleViewAction()->setShortcut(QKeySequence(Qt::Key_F7)); toggleViewAction()->setToolTip(tr("Show devices")); } } diff --git a/lib/tlPlayQtApp/InfoTool.cpp b/lib/tlPlayQtApp/InfoTool.cpp index 61a467f8c..c0f1b6be9 100644 --- a/lib/tlPlayQtApp/InfoTool.cpp +++ b/lib/tlPlayQtApp/InfoTool.cpp @@ -99,7 +99,7 @@ namespace tl setWidget(infoTool); toggleViewAction()->setIcon(QIcon(":/Icons/Info.svg")); - toggleViewAction()->setShortcut(QKeySequence(Qt::Key_F4)); + toggleViewAction()->setShortcut(QKeySequence(Qt::Key_F5)); toggleViewAction()->setToolTip(tr("Show information")); } } diff --git a/lib/tlPlayQtApp/MainWindow.cpp b/lib/tlPlayQtApp/MainWindow.cpp index 97d4ee722..de50aca99 100644 --- a/lib/tlPlayQtApp/MainWindow.cpp +++ b/lib/tlPlayQtApp/MainWindow.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -104,6 +105,7 @@ namespace tl FilesTool* filesTool = nullptr; ViewTool* viewTool = nullptr; ColorTool* colorTool = nullptr; + ColorPickerTool* colorPickerTool = nullptr; InfoTool* infoTool = nullptr; AudioTool* audioTool = nullptr; DevicesTool* devicesTool = nullptr; @@ -370,6 +372,13 @@ namespace tl toolsToolBar->addAction(colorDockWidget->toggleViewAction()); addDockWidget(Qt::RightDockWidgetArea, colorDockWidget); + p.colorPickerTool = new ColorPickerTool(this, app); + auto colorPickerDockWidget = new ColorPickerDockWidget(p.colorPickerTool); + colorPickerDockWidget->hide(); + p.toolActions->menu()->addAction(colorPickerDockWidget->toggleViewAction()); + toolsToolBar->addAction(colorPickerDockWidget->toggleViewAction()); + addDockWidget(Qt::RightDockWidgetArea, colorPickerDockWidget); + p.infoTool = new InfoTool(app); auto infoDockWidget = new InfoDockWidget(p.infoTool); infoDockWidget->hide(); diff --git a/lib/tlPlayQtApp/MessagesTool.cpp b/lib/tlPlayQtApp/MessagesTool.cpp index f2499e983..358e3f800 100644 --- a/lib/tlPlayQtApp/MessagesTool.cpp +++ b/lib/tlPlayQtApp/MessagesTool.cpp @@ -126,7 +126,7 @@ namespace tl setWidget(messagesTool); toggleViewAction()->setIcon(QIcon(":/Icons/Messages.svg")); - toggleViewAction()->setShortcut(QKeySequence(Qt::Key_F8)); + toggleViewAction()->setShortcut(QKeySequence(Qt::Key_F9)); toggleViewAction()->setToolTip(tr("Show messages")); } } diff --git a/lib/tlPlayQtApp/SystemLogTool.cpp b/lib/tlPlayQtApp/SystemLogTool.cpp index 9253d5930..f10d756a8 100644 --- a/lib/tlPlayQtApp/SystemLogTool.cpp +++ b/lib/tlPlayQtApp/SystemLogTool.cpp @@ -125,7 +125,7 @@ namespace tl setWidget(systemLogTool); - toggleViewAction()->setShortcut(QKeySequence(Qt::Key_F9)); + toggleViewAction()->setShortcut(QKeySequence(Qt::Key_F10)); toggleViewAction()->setToolTip(tr("Show system log")); } } diff --git a/lib/tlPlayQtApp/ViewTool.cpp b/lib/tlPlayQtApp/ViewTool.cpp index f0cd39522..08ef59df9 100644 --- a/lib/tlPlayQtApp/ViewTool.cpp +++ b/lib/tlPlayQtApp/ViewTool.cpp @@ -156,7 +156,7 @@ namespace tl setWidget(viewTool); toggleViewAction()->setIcon(QIcon(":/Icons/View.svg")); - toggleViewAction()->setShortcut(QKeySequence(Qt::Key_F5)); + toggleViewAction()->setShortcut(QKeySequence(Qt::Key_F2)); toggleViewAction()->setToolTip(tr("Show view controls")); } } diff --git a/lib/tlQtWidget/TimelineViewport.cpp b/lib/tlQtWidget/TimelineViewport.cpp index 2bdf1522a..459704a48 100644 --- a/lib/tlQtWidget/TimelineViewport.cpp +++ b/lib/tlQtWidget/TimelineViewport.cpp @@ -58,7 +58,8 @@ namespace tl { None, View, - Wipe + Wipe, + ColorPicker }; MouseMode mouseMode = MouseMode::None; math::Vector2i mousePos; @@ -522,6 +523,23 @@ namespace tl p.vao->draw(GL_TRIANGLES, 0, p.vbo->getSize()); } } + + if (p.buffer && Private::MouseMode::ColorPicker == p.mouseMode) + { + gl::OffscreenBufferBinding binding(p.buffer); + std::vector sample(4); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glReadPixels( + p.mousePos.x, + p.mousePos.y, + 1, + 1, + GL_RGBA, + GL_FLOAT, + sample.data()); + const image::Color4f color(sample[0], sample[1], sample[2], sample[3]); + Q_EMIT colorPickerChanged(color); + } } #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) @@ -560,6 +578,11 @@ namespace tl p.mousePress.x = event->x() * devicePixelRatio; p.mousePress.y = event->y() * devicePixelRatio; } + else if (Qt::LeftButton == event->button() && event->modifiers() & Qt::ShiftModifier) + { + p.mouseMode = Private::MouseMode::ColorPicker; + update(); + } } void TimelineViewport::mouseReleaseEvent(QMouseEvent*) @@ -601,6 +624,9 @@ namespace tl } } break; + case Private::MouseMode::ColorPicker: + update(); + break; default: break; } } diff --git a/lib/tlQtWidget/TimelineViewport.h b/lib/tlQtWidget/TimelineViewport.h index 14b03a248..757e12d39 100644 --- a/lib/tlQtWidget/TimelineViewport.h +++ b/lib/tlQtWidget/TimelineViewport.h @@ -112,6 +112,9 @@ namespace tl //! This signal is emitted when the dropped frames count is changed. void droppedFramesChanged(size_t); + //! This signal is emitted when the color picker is changed. + void colorPickerChanged(const tl::image::Color4f&); + private Q_SLOTS: void _playbackUpdate(timeline::Playback); void _videoDataUpdate(const std::vector&); diff --git a/lib/tlTimelineUI/TimelineViewport.cpp b/lib/tlTimelineUI/TimelineViewport.cpp index f851a8342..bff5046f7 100644 --- a/lib/tlTimelineUI/TimelineViewport.cpp +++ b/lib/tlTimelineUI/TimelineViewport.cpp @@ -8,7 +8,9 @@ #include +#include #include +#include #include #include @@ -48,7 +50,8 @@ namespace tl double frame = 0.0; }; DroppedFramesData droppedFramesData; - + std::shared_ptr > colorPicker; + bool doRender = false; std::shared_ptr buffer; @@ -56,7 +59,8 @@ namespace tl { None, View, - Wipe + Wipe, + ColorPicker }; struct MouseData { @@ -85,6 +89,7 @@ namespace tl p.frameView = observer::Value::create(true); p.fps = observer::Value::create(0.0); p.droppedFrames = observer::Value::create(0); + p.colorPicker = observer::Value::create(); } TimelineViewport::TimelineViewport() : @@ -352,6 +357,11 @@ namespace tl return _p->droppedFrames; } + std::shared_ptr > TimelineViewport::observeColorPicker() const + { + return _p->colorPicker; + } + void TimelineViewport::setGeometry(const math::Box2i& value) { const bool changed = value != _geometry; @@ -451,6 +461,26 @@ namespace tl const unsigned int id = p.buffer->getColorID(); event.render->drawTexture(id, g); } + + if (p.buffer && Private::MouseMode::ColorPicker == p.mouse.mode) + { + gl::OffscreenBufferBinding binding(p.buffer); + const math::Vector2i samplePos( + _mouse.pos.x - _geometry.min.x, + _mouse.pos.y - _geometry.min.y); + std::vector sample(4); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glReadPixels( + samplePos.x, + samplePos.y, + 1, + 1, + GL_RGBA, + GL_FLOAT, + sample.data()); + const image::Color4f color(sample[0], sample[1], sample[2], sample[3]); + p.colorPicker->setIfChanged(color); + } } void TimelineViewport::mouseMoveEvent(ui::MouseMoveEvent& event) @@ -492,6 +522,9 @@ namespace tl } break; } + case Private::MouseMode::ColorPicker: + _updates |= ui::Update::Draw; + break; default: break; } } @@ -512,6 +545,12 @@ namespace tl { p.mouse.mode = Private::MouseMode::Wipe; } + else if (0 == event.button && + event.modifiers & static_cast(ui::KeyModifier::Shift)) + { + p.mouse.mode = Private::MouseMode::ColorPicker; + _updates |= ui::Update::Draw; + } } void TimelineViewport::mouseReleaseEvent(ui::MouseClickEvent& event) diff --git a/lib/tlTimelineUI/TimelineViewport.h b/lib/tlTimelineUI/TimelineViewport.h index 8fb24b136..a98563f97 100644 --- a/lib/tlTimelineUI/TimelineViewport.h +++ b/lib/tlTimelineUI/TimelineViewport.h @@ -111,6 +111,9 @@ namespace tl //! Observe the number of dropped frames during playback.. std::shared_ptr > observeDroppedFrames() const; + + //! Observe the color picker. + std::shared_ptr > observeColorPicker() const; void setGeometry(const math::Box2i&) override; void sizeHintEvent(const ui::SizeHintEvent&) override;