From de6640508be1b1205111d70253e3ac24f67dda7f Mon Sep 17 00:00:00 2001 From: zhouhang95 <765229842@qq.com> Date: Thu, 10 Aug 2023 16:48:32 +0800 Subject: [PATCH 01/32] abc fps --- projects/Alembic/WriteAlembic.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/projects/Alembic/WriteAlembic.cpp b/projects/Alembic/WriteAlembic.cpp index cfc3592c7c..24e0c00374 100644 --- a/projects/Alembic/WriteAlembic.cpp +++ b/projects/Alembic/WriteAlembic.cpp @@ -302,6 +302,7 @@ struct WriteAlembic2 : INode { virtual void apply() override { auto prim = get_input("prim"); bool flipFrontBack = get_input2("flipFrontBack"); + float fps = get_input2("fps"); int frameid; if (has_input("frameid")) { frameid = get_input2("frameid"); @@ -313,7 +314,7 @@ struct WriteAlembic2 : INode { if (frameid == frame_start) { std::string path = get_input2("path"); archive = {Alembic::AbcCoreOgawa::WriteArchive(), path}; - archive.addTimeSampling(TimeSampling(1.0/24, frame_start / 24.0)); + archive.addTimeSampling(TimeSampling(1.0/fps, frame_start / fps)); if (prim->polys.size() || prim->tris.size()) { meshyObj = OPolyMesh( OObject( archive, 1 ), "mesh" ); } @@ -492,6 +493,7 @@ ZENDEFNODE(WriteAlembic2, { {"writepath", "path", ""}, {"int", "frame_start", "0"}, {"int", "frame_end", "100"}, + {"float", "fps", "24"}, {"bool", "flipFrontBack", "1"}, }, {}, From 8ca33564a355e86e70a6b07ec6f946df889b7319 Mon Sep 17 00:00:00 2001 From: zhouhang95 <765229842@qq.com> Date: Fri, 11 Aug 2023 12:04:11 +0800 Subject: [PATCH 02/32] WriteAlembic --- projects/Alembic/WriteAlembic.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/Alembic/WriteAlembic.cpp b/projects/Alembic/WriteAlembic.cpp index 24e0c00374..662145c593 100644 --- a/projects/Alembic/WriteAlembic.cpp +++ b/projects/Alembic/WriteAlembic.cpp @@ -302,7 +302,7 @@ struct WriteAlembic2 : INode { virtual void apply() override { auto prim = get_input("prim"); bool flipFrontBack = get_input2("flipFrontBack"); - float fps = get_input2("fps"); + float fps = has_input("fps")? get_input2("fps") : 24.0f; int frameid; if (has_input("frameid")) { frameid = get_input2("frameid"); @@ -493,7 +493,7 @@ ZENDEFNODE(WriteAlembic2, { {"writepath", "path", ""}, {"int", "frame_start", "0"}, {"int", "frame_end", "100"}, - {"float", "fps", "24"}, + {"fps"}, {"bool", "flipFrontBack", "1"}, }, {}, From e4a7f79c9b3ca5e9df0d320288366f63d3a029cf Mon Sep 17 00:00:00 2001 From: miyanyan <1138989048@qq.com> Date: Thu, 7 Sep 2023 21:48:44 +0800 Subject: [PATCH 03/32] add ColorEditor --- ui/zenoedit/viewport/displaywidget.cpp | 3 +- ui/zenoplayer/zenoplayer.cpp | 3 +- ui/zenoui/ColorEditor/ColorEditor.cpp | 1445 ++++++++++++++++++++++++ ui/zenoui/ColorEditor/ColorEditor.h | 313 +++++ ui/zenoui/comctrl/gv/zitemfactory.cpp | 3 +- ui/zenoui/comctrl/zwidgetfactory.cpp | 3 +- 6 files changed, 1766 insertions(+), 4 deletions(-) create mode 100644 ui/zenoui/ColorEditor/ColorEditor.cpp create mode 100644 ui/zenoui/ColorEditor/ColorEditor.h diff --git a/ui/zenoedit/viewport/displaywidget.cpp b/ui/zenoedit/viewport/displaywidget.cpp index 30bc553b6a..6d07ed0edf 100644 --- a/ui/zenoedit/viewport/displaywidget.cpp +++ b/ui/zenoedit/viewport/displaywidget.cpp @@ -11,6 +11,7 @@ #include "zenomainwindow.h" #include "camerakeyframe.h" #include +#include #include #include "timeline/ztimeline.h" #include "dialog/zrecorddlg.h" @@ -360,7 +361,7 @@ void DisplayWidget::onCommandDispatched(int actionType, bool bChecked) { auto [r, g, b] = m_glView->getSession()->get_background_color(); auto c = QColor::fromRgbF(r, g, b); - c = QColorDialog::getColor(c); + c = ColorEditor::getColor(c); if (c.isValid()) { m_glView->getSession()->set_background_color(c.redF(), c.greenF(), c.blueF()); updateFrame(); diff --git a/ui/zenoplayer/zenoplayer.cpp b/ui/zenoplayer/zenoplayer.cpp index 6e30db369a..6c644c82f6 100644 --- a/ui/zenoplayer/zenoplayer.cpp +++ b/ui/zenoplayer/zenoplayer.cpp @@ -18,6 +18,7 @@ #include #include #include +#include ZenoPlayer::ZenoPlayer(ZENO_PLAYER_INIT_PARAM param, QWidget *parent) @@ -109,7 +110,7 @@ QMenuBar *ZenoPlayer::initMenu() connect(pAction, &QAction::triggered, this, [=]() { auto [r, g, b] = Zenovis::GetInstance().getSession()->get_background_color(); auto c = QColor::fromRgbF(r, g, b); - c = QColorDialog::getColor(c); + c = ColorEditor::getColor(c); if (c.isValid()) { Zenovis::GetInstance().getSession()->set_background_color(c.redF(), c.greenF(), c.blueF()); ((ZenoPlayer *)zenoApp->getWindow("ZenoPlayer"))->updateFrame(); diff --git a/ui/zenoui/ColorEditor/ColorEditor.cpp b/ui/zenoui/ColorEditor/ColorEditor.cpp new file mode 100644 index 0000000000..9303525d44 --- /dev/null +++ b/ui/zenoui/ColorEditor/ColorEditor.cpp @@ -0,0 +1,1445 @@ +#include "ColorEditor.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//--------------------------------------------------------- color wheel ------------------------------------------------ +class ColorWheel::Private +{ +public: + static constexpr int selectorRadius = 4; + static constexpr int comboSelectorRadius = 3; + int radius = 0; + QColor selectedColor = QColor(Qt::white); + QImage colorBuffer; + colorcombo::ICombination* colorCombination = nullptr; + + void renderWheel(const QRect& rect) + { + auto center = rect.center(); + auto size = rect.size(); + + radius = std::min(rect.width(), rect.height()) / 2 - selectorRadius; + + // init buffer + colorBuffer = QImage(size, QImage::Format_ARGB32); + colorBuffer.fill(Qt::transparent); + + // create gradient + QConicalGradient hsvGradient(center, 0); + for (int deg = 0; deg < 360; deg += 60) { + hsvGradient.setColorAt(deg / 360.0, QColor::fromHsvF(deg / 360.0, 1.0, selectedColor.valueF())); + } + hsvGradient.setColorAt(1.0, QColor::fromHsvF(0.0, 1.0, selectedColor.valueF())); + + QRadialGradient valueGradient(center, radius); + valueGradient.setColorAt(0.0, QColor::fromHsvF(0.0, 0.0, selectedColor.valueF())); + valueGradient.setColorAt(1.0, Qt::transparent); + + QPainter painter(&colorBuffer); + painter.setRenderHint(QPainter::Antialiasing, true); + // draw color wheel + painter.setPen(Qt::transparent); + painter.setBrush(hsvGradient); + painter.drawEllipse(center, radius, radius); + painter.setBrush(valueGradient); + painter.drawEllipse(center, radius, radius); + } +}; + +ColorWheel::ColorWheel(QWidget* parent) + : QWidget(parent) + , p(new Private) +{ + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); +} + +void ColorWheel::setColorCombination(colorcombo::ICombination* combination) +{ + p->colorCombination = combination; + repaint(); +} + +void ColorWheel::setSelectedColor(const QColor& color) +{ + if (!isEnabled()) return; + + if (color.value() != p->selectedColor.value()) { + p->selectedColor = color; + p->renderWheel(this->rect()); + } + else { + p->selectedColor = color; + } + update(); +} + +QColor ColorWheel::getSelectedColor() const +{ + return p->selectedColor; +} + +QColor ColorWheel::getColor(int x, int y) const +{ + if (p->radius <= 0) return QColor(); + + auto line = QLineF(this->rect().center(), QPointF(x, y)); + auto h = line.angle() / 360.0; + auto s = std::min(1.0, line.length() / p->radius); + auto v = p->selectedColor.valueF(); + return QColor::fromHsvF(h, s, v); +} + +void ColorWheel::paintEvent(QPaintEvent* e) +{ + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing, true); + // draw wheel + painter.drawImage(0, 0, p->colorBuffer); + // draw selected color circle + painter.setPen(Qt::black); + painter.setBrush(Qt::white); + drawSelector(&painter, p->selectedColor, p->selectorRadius); + // draw color combination circle + if (p->colorCombination) { + auto colors = p->colorCombination->genColors(p->selectedColor); + for (const auto& color : colors) { + drawSelector(&painter, color, p->comboSelectorRadius); + } + // add selected color, so the user can switch between this + colors.push_back(p->selectedColor); + emit combinationColorChanged(colors); + } +} + +void ColorWheel::mousePressEvent(QMouseEvent* e) +{ + processMouseEvent(e); +} + +void ColorWheel::mouseMoveEvent(QMouseEvent* e) +{ + processMouseEvent(e); +} + +void ColorWheel::resizeEvent(QResizeEvent* e) +{ + p->renderWheel(this->rect()); +} + +void ColorWheel::processMouseEvent(QMouseEvent* e) +{ + if (e->buttons() & Qt::LeftButton) { + p->selectedColor = getColor(e->x(), e->y()); + emit colorSelected(p->selectedColor); + update(); + } +} + +void ColorWheel::drawSelector(QPainter* painter, const QColor& color, int radius) +{ + auto line = QLineF::fromPolar(color.hsvSaturationF() * p->radius, color.hsvHueF() * 360.0); + line.translate(this->rect().center()); + painter->drawEllipse(line.p2(), radius, radius); +} + +//-------------------------------------------------- color combination -------------------------------------------- +namespace colorcombo +{ +ICombination::ICombination(QObject* parent) + : QObject(parent) + , m_min(0) + , m_max(1) + , m_value(0) + , m_rangeEnabled(false) +{ +} + +ICombination::ICombination(double min, double max, double value, bool rangeEnabled, QObject* parent) + : QObject(parent) + , m_min(min) + , m_max(max) + , m_value(value) + , m_rangeEnabled(rangeEnabled) +{ +} + +QString ICombination::name() +{ + return tr("None"); +} + +QVector ICombination::genColors(const QColor& color) +{ + return {}; +} + +void ICombination::setRange(double min, double max) +{ + m_min = min; + m_max = max; +} + +void ICombination::serValue(double value) +{ + m_value = value; +} + +double ICombination::min() const +{ + return m_min; +} + +double ICombination::max() const +{ + return m_max; +} + +double ICombination::getValue() const +{ + return m_value; +} + +bool ICombination::rangeEnabled() const +{ + return m_rangeEnabled; +} + +Complementary::Complementary(QObject* parent) + : ICombination(parent) +{ +} + +QString Complementary::name() +{ + return tr("Complementary"); +} + +QVector Complementary::genColors(const QColor& color) +{ + return {QColor::fromHsv((color.hsvHue() + 180) % 360, color.hsvSaturation(), color.value())}; +} + +Monochromatic::Monochromatic(QObject* parent) + : ICombination(0, 1, 0.5, true, parent) +{ +} + +QString Monochromatic::name() +{ + return tr("Monochromatic"); +} + +QVector Monochromatic::genColors(const QColor& color) +{ + return {QColor::fromHsvF(color.hsvHueF(), color.hsvSaturationF(), color.valueF() * getValue())}; +} + +Analogous::Analogous(QObject* parent) + : ICombination(0, 180, 30, true, parent) +{ +} + +QString Analogous::name() +{ + return tr("Analogous"); +} + +QVector Analogous::genColors(const QColor& color) +{ + int add = getValue(); + return {QColor::fromHsv((color.hsvHue() + add) % 360, color.hsvSaturation(), color.value()), + QColor::fromHsv((color.hsvHue() - add + 360) % 360, color.hsvSaturation(), color.value())}; +} + +Triadic::Triadic(QObject* parent) + : ICombination(0, 180, 120, true, parent) +{ +} + +QString Triadic::name() +{ + return tr("Triadic"); +} + +QVector Triadic::genColors(const QColor& color) +{ + int add = getValue(); + return {QColor::fromHsv((color.hsvHue() + add) % 360, color.hsvSaturation(), color.value()), + QColor::fromHsv((color.hsvHue() - add + 360) % 360, color.hsvSaturation(), color.value())}; +} + +Tetradic::Tetradic(QObject* parent) + : ICombination(-90, 90, 90, true, parent) +{ +} + +QString Tetradic::name() +{ + return tr("Tetradic"); +} + +QVector Tetradic::genColors(const QColor& color) +{ + /* + * A--------B + * | | + * D--------C + * + * A : H, S, V + * B : H - 90 + factor * 180, S, V + * C : H + 180, S, V + * D : H + 90 + factor * 180, S, V + */ + int add = getValue(); + return {QColor::fromHsv((color.hsvHue() + add + 360) % 360, color.hsvSaturation(), color.value()), + QColor::fromHsv((color.hsvHue() + 180) % 360, color.hsvSaturation(), color.value()), + QColor::fromHsv((color.hsvHue() + add + 180 + 360) % 360, color.hsvSaturation(), color.value())}; +} +} // namespace colorcombo + +//--------------------------------------------------- color slider ------------------------------------------- +void JumpableSlider::mousePressEvent(QMouseEvent* e) +{ + if (e->button() == Qt::LeftButton) { + e->accept(); + setSliderDown(true); + handleMouseEvent(e); + } + else { + QSlider::mousePressEvent(e); + } +} + +void JumpableSlider::mouseMoveEvent(QMouseEvent* e) +{ + if (e->buttons() & Qt::LeftButton) { + e->accept(); + handleMouseEvent(e); + } + else { + QSlider::mouseMoveEvent(e); + } +} + +void JumpableSlider::mouseReleaseEvent(QMouseEvent* e) +{ + QSlider::mouseReleaseEvent(e); +} + +void JumpableSlider::handleMouseEvent(QMouseEvent* e) +{ + int newVal; + if (orientation() == Qt::Horizontal) { + newVal = minimum() + ((maximum() - minimum() + 1) * e->x()) / width(); + } + else { + newVal = minimum() + ((maximum() - minimum() + 1) * (height() - e->y())) / height(); + } + setValue(!invertedAppearance() ? newVal : maximum() - newVal); +} + +class GradientSlider::Private +{ +public: + QVector> colors; +}; + +GradientSlider::GradientSlider(QWidget* parent) + : JumpableSlider(Qt::Horizontal, parent) + , p(new Private) +{ +} + +void GradientSlider::setGradient(const QColor& startColor, const QColor& stopColor) +{ + setGradient({{0, startColor}, {1, stopColor}}); +} + +void GradientSlider::setGradient(const QVector>& colors) +{ + if (colors.size() <= 1) { + qWarning() << "ColorSlider::setGradient: colors size should >= 2"; + return; + } + + p->colors = colors; + + QString ori; + float x1, y1, x2, y2; + if (orientation() == Qt::Horizontal) { + ori = "horizontal"; + x1 = 0; + y1 = 0; + x2 = 1; + y2 = 0; + } + else { + ori = "vertical"; + x1 = 0; + y1 = 0; + x2 = 0; + y2 = 1; + } + + QString gradientStyle; + for (const auto& color : colors) { + gradientStyle += QString(",stop:%1 %2").arg(color.first).arg(color.second.name()); + } + + auto style = QString("QSlider::groove:%1{background:qlineargradient(x1:%2,y1:%3,x2:%4,y2:%5 %6);}" + "QSlider::handle:%1{background:#5C5C5C;border:1px solid;width:6px}") + .arg(ori) + .arg(x1) + .arg(y1) + .arg(x2) + .arg(y2) + .arg(gradientStyle); + + setStyleSheet(style); +} + +QVector> GradientSlider::gradientColor() const +{ + return p->colors; +} + +class ColorSpinHSlider::Private +{ +public: + QSpinBox* spinbox; + GradientSlider* slider; + + Private(const QString& name, QWidget* parent) + { + QLabel* text = new QLabel(name, parent); + text->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + spinbox = new QSpinBox(parent); + spinbox->setButtonSymbols(QAbstractSpinBox::NoButtons); + slider = new GradientSlider(parent); + slider->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + auto layout = new QHBoxLayout(parent); + layout->setAlignment(Qt::AlignLeft); + layout->setMargin(0); + layout->addWidget(text, 1); + layout->addWidget(spinbox, 1); + layout->addWidget(slider, 8); + + connect(slider, &QSlider::valueChanged, spinbox, &QSpinBox::setValue); + connect(spinbox, QOverload::of(&QSpinBox::valueChanged), slider, &GradientSlider::setValue); + } +}; +ColorSpinHSlider::ColorSpinHSlider(const QString& name, QWidget* parent) + : QWidget(parent) + , p(new Private(name, this)) +{ + connect(p->slider, &QSlider::valueChanged, this, &ColorSpinHSlider::valueChanged); +} + +void ColorSpinHSlider::setGradient(const QColor& startColor, const QColor& stopColor) +{ + p->slider->setGradient(startColor, stopColor); +} + +void ColorSpinHSlider::setGradient(const QVector>& colors) +{ + p->slider->setGradient(colors); +} + +void ColorSpinHSlider::setValue(double value) +{ + p->spinbox->setValue(value); +} + +void ColorSpinHSlider::setRange(double min, double max) +{ + p->slider->setRange(min, max); + p->spinbox->setRange(min, max); +} + +QVector> ColorSpinHSlider::gradientColor() const +{ + return p->slider->gradientColor(); +} + +//--------------------------------------------- color button ------------------------------------------------------- +class ColorButton::Private +{ +public: + QPoint pressPos; + QColor color; + int bolderWidth = 0; + + void updateStyle(QPushButton* btn) + { + auto style = QString("QPushButton{min-width:30px;min-height:30px;background-color:%1;border:%2px solid;}" + "QPushButton:pressed{border: 1px solid #ffd700;}") + .arg(color.name()) + .arg(bolderWidth); + btn->setStyleSheet(style); + } +}; + +ColorButton::ColorButton(QWidget* parent) + : QPushButton(parent) + , p(new Private) +{ + setAcceptDrops(true); + connect(this, &QPushButton::clicked, this, [this]() { emit colorClicked(p->color); }); +} + +void ColorButton::setColor(const QColor& color) +{ + p->color = color; + p->updateStyle(this); +} + +void ColorButton::setBolderWidth(int width) +{ + p->bolderWidth = width; + p->updateStyle(this); +} + +QColor ColorButton::color() const +{ + return p->color; +} + +void ColorButton::mousePressEvent(QMouseEvent* e) +{ + p->pressPos = e->pos(); + QPushButton::mousePressEvent(e); +} + +void ColorButton::mouseMoveEvent(QMouseEvent* e) +{ + if (e->buttons() & Qt::LeftButton) { + if ((p->pressPos - e->pos()).manhattanLength() > QApplication::startDragDistance()) { + QMimeData* mime = new QMimeData; + mime->setColorData(p->color); + QPixmap pix(width(), height()); + pix.fill(p->color); + QDrag* drg = new QDrag(this); + drg->setMimeData(mime); + drg->setPixmap(pix); + drg->exec(Qt::CopyAction); + // need let pushbutton release + QMouseEvent event(QEvent::MouseButtonRelease, e->pos(), Qt::LeftButton, Qt::LeftButton, 0); + QApplication::sendEvent(this, &event); + } + } +} + +void ColorButton::dragEnterEvent(QDragEnterEvent* e) +{ + if (qvariant_cast(e->mimeData()->colorData()).isValid()) + e->accept(); + else + e->ignore(); +} + +void ColorButton::dragLeaveEvent(QDragLeaveEvent*) +{ + if (hasFocus()) parentWidget()->setFocus(); +} + +void ColorButton::dropEvent(QDropEvent* e) +{ + auto color = qvariant_cast(e->mimeData()->colorData()); + if (color.isValid()) { + setColor(color); + emit colorDroped(color); + e->accept(); + } + else { + e->ignore(); + } +} + +//--------------------------------------------- color palette ------------------------------------------------------ +class ColorPalette::Private +{ +public: + int columnCount = 0; + QGridLayout* layout = nullptr; + QVector colors; + + Private(int column, QScrollArea* parent) + { + columnCount = column; + + auto scrollWidget = new QWidget(parent); + layout = new QGridLayout(scrollWidget); + layout->setAlignment(Qt::AlignTop); + layout->setSpacing(0); + layout->setMargin(0); + + parent->setWidget(scrollWidget); + } + + std::pair getLayoutIndex(int index) { return {index / columnCount, index % columnCount}; } + + void updateLayout(int begin, int end) + { + for (int i = begin; i < end; ++i) { + int row = i / columnCount; + int col = i % columnCount; + auto btn = qobject_cast(layout->itemAtPosition(row, col)->widget()); + btn->setColor(colors[i]); + } + } +}; + +ColorPalette::ColorPalette(int column, QWidget* parent) + : QScrollArea(parent) + , p(new Private(column, this)) +{ + setWidgetResizable(true); + setAcceptDrops(true); +} + +void ColorPalette::addColor(const QColor& color) +{ + int index = p->colors.size(); + p->colors.push_back(color); + + auto btn = new ColorButton(this); + btn->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + btn->setBolderWidth(1); + btn->setToolTip(tr("Ctrl + click to remove color")); + connect(btn, &ColorButton::colorClicked, this, [this, index](const QColor& color) { + if (QApplication::keyboardModifiers() == Qt::ControlModifier) { + auto layoutIndex = p->getLayoutIndex(index); + removeColor(layoutIndex.first, layoutIndex.second); + } + else { + emit colorClicked(color); + } + }); + connect(btn, &ColorButton::colorDroped, this, [this, index](const QColor& color) { + // update color at index + p->colors[index] = color; + }); + + auto layoutIndex = p->getLayoutIndex(index); + p->layout->addWidget(btn, layoutIndex.first, layoutIndex.second); + + p->updateLayout(index, index + 1); +} + +void ColorPalette::setColor(const QColor& color, int row, int column) +{ + int index = row * p->columnCount + column; + p->colors[index] = color; + p->updateLayout(index, index + 1); +} + +void ColorPalette::removeColor(int row, int column) +{ + int size = p->colors.size(); + auto item = p->layout->takeAt(size - 1); + if (item->widget()) { + delete item->widget(); + } + delete item; + + int index = row * p->columnCount + column; + p->colors.remove(index); + p->updateLayout(index, p->colors.size()); +} + +QColor ColorPalette::colorAt(int row, int column) const +{ + if (column >= p->columnCount) { + return QColor(); + } + int index = row * p->columnCount + column; + if (index >= p->colors.size()) { + return QColor(); + } + return p->colors[index]; +} + +QVector ColorPalette::colors() const +{ + return p->colors; +} + +void ColorPalette::dragEnterEvent(QDragEnterEvent* e) +{ + if (qvariant_cast(e->mimeData()->colorData()).isValid()) + e->accept(); + else + e->ignore(); +} + +void ColorPalette::dropEvent(QDropEvent* e) +{ + auto color = qvariant_cast(e->mimeData()->colorData()); + if (color.isValid()) { + addColor(color); + e->accept(); + } + else { + e->ignore(); + } +} + +//--------------------------------------------- color preview ------------------------------------------------------- +class ColorPreview::Private +{ +public: + ColorButton* pbtnCurrent; + ColorButton* pbtnPrevious; + + Private(const QColor& color, QWidget* parent) + : pbtnCurrent(new ColorButton(parent)) + , pbtnPrevious(new ColorButton(parent)) + { + // pbtnCurrent->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + // pbtnPrevious->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + + pbtnCurrent->setBolderWidth(1); + pbtnPrevious->setBolderWidth(1); + + pbtnCurrent->setColor(color); + pbtnPrevious->setColor(color); + + auto layout = new QHBoxLayout(parent); + layout->setSpacing(0); + layout->setMargin(0); + layout->addWidget(pbtnPrevious); + layout->addWidget(pbtnCurrent); + } + + void setCurrent(const QColor& color) { pbtnCurrent->setColor(color); } +}; + +ColorPreview::ColorPreview(const QColor& color, QWidget* parent) + : QWidget(parent) + , p(new Private(color, this)) +{ + // only emit when current color changed + connect(p->pbtnCurrent, &ColorButton::colorDroped, this, &ColorPreview::currentColorChanged); +} + +void ColorPreview::setCurrentColor(const QColor& color) +{ + p->setCurrent(color); +} + +QColor ColorPreview::currentColor() const +{ + return p->pbtnCurrent->color(); +} + +QColor ColorPreview::previousColor() const +{ + return p->pbtnPrevious->color(); +} + +//------------------------------------------- color combo widget --------------------------- +class ColorComboWidget::Private +{ +public: + static constexpr int factor = 360; + std::queue combs; + QHBoxLayout* hlayout = nullptr; + QPushButton* switchBtn = nullptr; + JumpableSlider* factorSlider = nullptr; + QDoubleSpinBox* factorSpinbox = nullptr; + + Private(QWidget* parent) + { + factorSpinbox = new QDoubleSpinBox(parent); + factorSlider = new JumpableSlider(Qt::Horizontal, parent); + switchBtn = new QPushButton(parent); + switchBtn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + factorSpinbox->setButtonSymbols(QAbstractSpinBox::NoButtons); + + auto layout = new QGridLayout(parent); + layout->setMargin(0); + hlayout = new QHBoxLayout(); + hlayout->setMargin(0); + hlayout->setSpacing(0); + layout->addLayout(hlayout, 0, 0, 1, 3); + layout->addWidget(switchBtn, 0, 3, 1, 1); + layout->addWidget(factorSpinbox, 1, 0, 1, 1); + layout->addWidget(factorSlider, 1, 1, 1, 3); + + connect(factorSlider, &QSlider::valueChanged, factorSpinbox, [this](int value) { factorSpinbox->setValue(1.0 * value / factor); }); + connect(factorSpinbox, QOverload::of(&QDoubleSpinBox::valueChanged), factorSlider, + [this](double value) { factorSlider->setValue(value * factor); }); + } +}; + +ColorComboWidget::ColorComboWidget(QWidget* parent) + : QWidget(parent) + , p(new Private(this)) +{ + // dummy + addCombination(new colorcombo::ICombination(this)); + switchCombination(); + + connect(p->switchBtn, &QPushButton::clicked, this, &ColorComboWidget::switchCombination); + connect(p->factorSpinbox, QOverload::of(&QDoubleSpinBox::valueChanged), this, [this](double value) { + auto comb = p->combs.front(); + comb->serValue(value); + emit combinationChanged(comb); + }); +} + +void ColorComboWidget::addCombination(colorcombo::ICombination* combo) +{ + p->combs.push(combo); +} + +void ColorComboWidget::clearCombination() +{ + while (!p->combs.empty()) { + p->combs.pop(); + } + // dummy + addCombination(new colorcombo::ICombination(this)); + switchCombination(); +} + +colorcombo::ICombination* ColorComboWidget::currentCombination() const +{ + return p->combs.front(); +} + +void ColorComboWidget::setColors(const QVector& colors) +{ + for (int i = 0; i < colors.size(); ++i) { + auto btn = qobject_cast(p->hlayout->itemAt(i)->widget()); + btn->setColor(colors[i]); + } +} + +void ColorComboWidget::switchCombination() +{ + if (p->combs.empty()) return; + + auto front = p->combs.front(); + p->combs.pop(); + p->combs.push(front); + + auto currentComb = p->combs.front(); + + // clear + QLayoutItem* item; + while (item = p->hlayout->takeAt(0)) { + if (item->widget()) { + delete item->widget(); + } + delete item; + } + // add + auto colors = currentComb->genColors(Qt::white); + int size = colors.size() + 1; + for (int i = 0; i < size; ++i) { + auto btn = new ColorButton(this); + btn->setBolderWidth(1); + btn->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + btn->setAcceptDrops(false); // color can't be changed by drop + connect(btn, &ColorButton::colorClicked, this, &ColorComboWidget::colorClicked); + p->hlayout->addWidget(btn); + } + + // make slider looks like double slider + p->factorSlider->setRange(currentComb->min() * p->factor, currentComb->max() * p->factor); + p->factorSpinbox->setRange(currentComb->min(), currentComb->max()); + p->factorSpinbox->setSingleStep((currentComb->max() - currentComb->min()) / p->factor); + p->factorSpinbox->setValue(currentComb->getValue()); + p->factorSlider->setEnabled(currentComb->rangeEnabled()); + p->factorSpinbox->setEnabled(currentComb->rangeEnabled()); + + emit combinationChanged(currentComb); +} + +//------------------------------------------ color lineedit -------------------------------- + +ColorLineEdit::ColorLineEdit(QWidget* parent) + : QLineEdit(parent) +{ + connect(this, &ColorLineEdit::editingFinished, this, [this]() { + setText(text().toUpper()); + emit currentColorChanged(QColor(text())); + }); +} +void ColorLineEdit::setColor(const QColor& color) +{ + setText(color.name().toUpper()); +} + +//------------------------------------------ color picker ---------------------------------- +class ColorPicker::Private +{ +public: + int rectLength = 20; + int scaleSize = 10; + QPoint cursorPos; + QImage fullScreenImg; + + void grabFullScreen() + { + const QDesktopWidget* desktop = QApplication::desktop(); + const QPixmap pixmap = QApplication::primaryScreen()->grabWindow(desktop->winId(), desktop->pos().x(), desktop->pos().y(), + desktop->width(), desktop->height()); + fullScreenImg = pixmap.toImage(); + } + + QRect getScreenRect() const + { + const QDesktopWidget* desktop = QApplication::desktop(); + return QRect(desktop->pos(), desktop->size()); + } + + QColor getColorAt(QPoint p) const { return fullScreenImg.pixelColor(p); } + + QImage getScaledImage(QPoint p) const + { + int rectHalfLength = rectLength / 2; + QImage img = fullScreenImg.copy(p.x() - rectHalfLength, p.y() - rectHalfLength, rectLength, rectLength); + return img.scaled(scaleSize * rectLength, scaleSize * rectLength); + } + + QScreen* getScreenAt(QPoint p) const + { +#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) + QScreen* screen = QApplication::screenAt(p); +#else + int screenNum = QApplication::desktop()->screenNumber(p); + QScreen* screen = QApplication::screens().at(screenNum); +#endif + return screen; + } +}; + +ColorPicker::ColorPicker(QWidget* parent) + : QWidget(parent) + , p(new Private) +{ + setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint); + setMouseTracking(true); + setCursor(Qt::CrossCursor); +} + +QColor ColorPicker::grabScreenColor(QPoint p) const +{ + // not use now, just make screenshot and get color from it + const QDesktopWidget* desktop = QApplication::desktop(); + const QPixmap pixmap = QApplication::primaryScreen()->grabWindow(desktop->winId(), p.x(), p.y(), 1, 1); + QImage i = pixmap.toImage(); + return i.pixel(0, 0); +} + +void ColorPicker::startColorPicking() +{ + p->cursorPos = QCursor::pos(); + p->grabFullScreen(); + setGeometry(p->getScreenRect()); + showFullScreen(); + setFocus(); +} + +void ColorPicker::releaseColorPicking() +{ + hide(); +} + +void ColorPicker::paintEvent(QPaintEvent* e) +{ + QPainter painter(this); + // background + painter.drawImage(0, 0, p->fullScreenImg); + // scaled img + auto img = p->getScaledImage(p->cursorPos); + auto currentColor = p->getColorAt(p->cursorPos); + auto screen = p->getScreenAt(p->cursorPos); + auto rect = screen->geometry(); + // calculate img pos + int dx = 20, dy = 20; + int x, y; + if (rect.right() - p->cursorPos.x() < img.width() + dx) { + x = p->cursorPos.x() - img.width() - dx; + } + else { + x = p->cursorPos.x() + dx; + } + if (rect.height() - p->cursorPos.y() < img.height() + dy) { + y = p->cursorPos.y() - img.height() + dy; + } + else { + y = p->cursorPos.y() + dy; + } + + painter.translate(x, y); + painter.drawImage(0, 0, img); + + int rectWidth = 10; + int halfRectWidth = rectWidth / 2; + int halfH = img.height() / 2; + int halfW = img.width() / 2; + // cross + painter.setPen(QPen(QColor("#aadafa7f"), rectWidth)); + painter.drawLine(halfW, halfRectWidth, halfW, halfH - rectWidth); + painter.drawLine(halfW, rectWidth + halfH, halfW, img.height() - halfRectWidth); + painter.drawLine(halfRectWidth, halfH, halfW - rectWidth, halfH); + painter.drawLine(rectWidth + halfW, halfH, img.width() - halfRectWidth, halfH); + // bolder + painter.setPen(QPen(qGray(currentColor.rgb()) > 127 ? Qt::black : Qt::white, 1)); + painter.drawRect(0, 0, img.width(), img.height()); + painter.drawRect(halfW - halfRectWidth, halfH - halfRectWidth, rectWidth, rectWidth); +} + +void ColorPicker::mouseMoveEvent(QMouseEvent* e) +{ + p->cursorPos = e->pos(); + update(); +} + +void ColorPicker::mouseReleaseEvent(QMouseEvent* e) +{ + if (e->button() == Qt::LeftButton) { + emit colorSelected(p->getColorAt(QCursor::pos())); + releaseColorPicking(); + } + else if (e->button() == Qt::RightButton) { + releaseColorPicking(); + } +} + +void ColorPicker::keyPressEvent(QKeyEvent* e) +{ + switch (e->key()) { + case Qt::Key_Escape: + releaseColorPicking(); + break; + case Qt::Key_Return: + case Qt::Key_Enter: + emit colorSelected(p->getColorAt(QCursor::pos())); + releaseColorPicking(); + break; + case Qt::Key_Up: + QCursor::setPos(p->cursorPos.x(), p->cursorPos.y() - 1); + break; + case Qt::Key_Down: + QCursor::setPos(p->cursorPos.x(), p->cursorPos.y() + 1); + break; + case Qt::Key_Left: + QCursor::setPos(p->cursorPos.x() - 1, p->cursorPos.y()); + break; + case Qt::Key_Right: + QCursor::setPos(p->cursorPos.x() + 1, p->cursorPos.y()); + break; + default: + break; + } +} + +void ColorPicker::focusOutEvent(QFocusEvent* e) +{ + releaseColorPicking(); +} + +//------------------------------------------------------- color data -------------------------------------------- +struct ColorEditorData +{ + static constexpr int rowCount = 4; + static constexpr int colCount = 12; + QColor standardColor[rowCount * colCount]; + + ColorEditorData() + { + // standard + int i = 0; + for (int s = 0; s < rowCount; ++s) { + for (int h = 0; h < colCount; ++h) { + standardColor[i++] = QColor::fromHsvF(1.0 * h / colCount, 1.0 - 1.0 * s / rowCount, 1.0); + } + } + } + + QVector readSettings() + { + const QSettings settings(QSettings::UserScope, QStringLiteral("__ColorEditor_4x12")); + int count = settings.value(QLatin1String("customCount")).toInt(); + QVector customColor(count); + // if zero, init with standard + if (count == 0) { + for (const auto& color : standardColor) { + customColor.append(color); + } + } + // otherwise, init with settings + else { + for (int i = 0; i < count; ++i) { + const QVariant v = settings.value(QLatin1String("customColors/") + QString::number(i)); + if (v.isValid()) { + customColor[i] = v.toUInt(); + } + } + } + + return customColor; + } + void writeSettings(const QVector& colors) + { + QSettings settings(QSettings::UserScope, QStringLiteral("__ColorEditor_4x12")); + int count = colors.size(); + settings.setValue(QLatin1String("customCount"), count); + for (int i = 0; i < count; ++i) { + settings.setValue(QLatin1String("customColors/") + QString::number(i), colors[i].rgb()); + } + } +}; + +//------------------------------------------ color editor ---------------------------------- +class ColorEditor::Private +{ +public: + ColorWheel* wheel; + ColorLineEdit* colorText; + ColorPreview* preview; + ColorPicker* picker; + QPushButton* pickerBtn; + ColorComboWidget* combo; + QGroupBox* previewGroup; + QGroupBox* comboGroup; + ColorPalette* palette; + ColorSpinHSlider* rSlider; + ColorSpinHSlider* gSlider; + ColorSpinHSlider* bSlider; + ColorSpinHSlider* hSlider; + ColorSpinHSlider* sSlider; + ColorSpinHSlider* vSlider; + + QColor initialColor; + QColor curColor; + ColorEditorData colorData; + + Private(const QColor& color, QDialog* parent) + { + initialColor = color; + // left + picker = new ColorPicker(parent); + pickerBtn = new QPushButton(parent); + wheel = new ColorWheel(parent); + colorText = new ColorLineEdit(parent); + preview = new ColorPreview(color, parent); + combo = new ColorComboWidget(parent); + previewGroup = new QGroupBox(tr("Previous/Current Colors"), parent); + comboGroup = new QGroupBox(tr("Color Combination"), parent); + + colorText->setMaximumWidth(80); + colorText->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + pickerBtn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + + auto previewWidget = new QWidget(parent); + auto previewLayout = new QHBoxLayout(previewWidget); + previewLayout->setMargin(0); + previewLayout->addWidget(preview); + previewLayout->addWidget(pickerBtn); + + auto previewGroupLayout = new QHBoxLayout(previewGroup); + previewGroupLayout->addWidget(previewWidget); + + auto comboGroupLayout = new QHBoxLayout(comboGroup); + comboGroupLayout->addWidget(combo); + + auto leftWidget = new QWidget(parent); + auto leftLayout = new QGridLayout(leftWidget); + // leftLayout->setMargin(0); + leftLayout->setSpacing(0); + leftLayout->addWidget(wheel, 0, 0); + leftLayout->addWidget(colorText, 1, 0, Qt::AlignRight); + leftLayout->addWidget(previewGroup, 2, 0); + leftLayout->addWidget(comboGroup, 3, 0); + + // right + palette = new ColorPalette(colorData.colCount, parent); + rSlider = new ColorSpinHSlider("R", parent); + gSlider = new ColorSpinHSlider("G", parent); + bSlider = new ColorSpinHSlider("B", parent); + hSlider = new ColorSpinHSlider("H", parent); + sSlider = new ColorSpinHSlider("S", parent); + vSlider = new ColorSpinHSlider("V", parent); + + auto rgbSlider = new QWidget(parent); + auto rgbSliderLayout = new QVBoxLayout(rgbSlider); + rgbSliderLayout->setMargin(0); + rgbSliderLayout->setSpacing(2); + rgbSliderLayout->addWidget(rSlider); + rgbSliderLayout->addWidget(gSlider); + rgbSliderLayout->addWidget(bSlider); + + auto hsvSlider = new QWidget(parent); + auto hsvSliderLayout = new QVBoxLayout(hsvSlider); + hsvSliderLayout->setMargin(0); + hsvSliderLayout->setSpacing(2); + hsvSliderLayout->addWidget(hSlider); + hsvSliderLayout->addWidget(sSlider); + hsvSliderLayout->addWidget(vSlider); + + rSlider->setRange(0, 255); + gSlider->setRange(0, 255); + bSlider->setRange(0, 255); + hSlider->setRange(0, 359); + sSlider->setRange(0, 255); + vSlider->setRange(0, 255); + + setGradientR(color); + setGradientG(color); + setGradientB(color); + setGradientH(color); + setGradientS(color); + setGradientV(color); + + auto rightWidget = new QWidget(parent); + auto rightLayout = new QVBoxLayout(rightWidget); + // rightLayout->setMargin(0); + rightLayout->addWidget(palette); + rightLayout->addWidget(rgbSlider); + rightLayout->addWidget(hsvSlider); + // splitter + auto splitter = new QSplitter(parent); + splitter->addWidget(leftWidget); + splitter->addWidget(rightWidget); + splitter->setStretchFactor(0, 3); + splitter->setStretchFactor(1, 7); + splitter->setCollapsible(0, false); + splitter->setCollapsible(1, false); + + auto layout = new QVBoxLayout(parent); + layout->setMargin(0); + layout->addWidget(splitter); + } + + void blockColorSignals(bool block) + { + wheel->blockSignals(block); + colorText->blockSignals(block); + preview->blockSignals(block); + combo->blockSignals(block); + palette->blockSignals(block); + rSlider->blockSignals(block); + gSlider->blockSignals(block); + bSlider->blockSignals(block); + hSlider->blockSignals(block); + sSlider->blockSignals(block); + vSlider->blockSignals(block); + } + + void setGradient(const QColor& color) + { + bool rChanged = color.red() != curColor.red(); + bool gChanged = color.green() != curColor.green(); + bool bChanged = color.blue() != curColor.blue(); + bool hChanged = color.hsvHue() != curColor.hsvHue(); + bool sChanged = color.hsvSaturation() != curColor.hsvSaturation(); + bool vChanged = color.value() != curColor.value(); + + if (gChanged || bChanged) { + setGradientR(color); + } + if (rChanged || bChanged) { + setGradientG(color); + } + if (rChanged || gChanged) { + setGradientB(color); + } + if (sChanged || vChanged) { + setGradientH(color); + } + if (hChanged || vChanged) { + setGradientS(color); + } + if (hChanged || sChanged) { + setGradientV(color); + } + } + + void setGradientR(const QColor& color) + { + rSlider->setGradient(QColor(0, color.green(), color.blue()), QColor(255, color.green(), color.blue())); + } + void setGradientG(const QColor& color) + { + gSlider->setGradient(QColor(color.red(), 0, color.blue()), QColor(color.red(), 255, color.blue())); + } + void setGradientB(const QColor& color) + { + bSlider->setGradient(QColor(color.red(), color.green(), 0), QColor(color.red(), color.green(), 255)); + } + void setGradientH(const QColor& color) + { + // hSlider is unique + static QVector> hColors(7); + for (int i = 0; i < hColors.size(); ++i) { + float f = 1.0 * i / (hColors.size() - 1); + hColors[i] = {f, QColor::fromHsvF(f, color.hsvSaturationF(), color.valueF())}; + } + hSlider->setGradient(hColors); + } + void setGradientS(const QColor& color) + { + sSlider->setGradient(QColor::fromHsvF(color.hsvHueF(), 0, color.valueF()), QColor::fromHsvF(color.hsvHueF(), 1, color.valueF())); + } + void setGradientV(const QColor& color) + { + vSlider->setGradient(QColor::fromHsvF(color.hsvHueF(), color.hsvSaturationF(), 0), + QColor::fromHsvF(color.hsvHueF(), color.hsvSaturationF(), 1)); + } +}; + +ColorEditor::ColorEditor(QWidget* parent) + : ColorEditor(Qt::white, parent) +{ +} + +ColorEditor::ColorEditor(const QColor& initial, QWidget* parent) + : QDialog(parent) + , p(new Private(initial, this)) +{ + setWindowFlag(Qt::WindowContextHelpButtonHint, false); + setWindowTitle(tr("ColorEditor")); + setMinimumSize(700, 500); + initSlots(); + // init combinations + p->combo->addCombination(new colorcombo::Analogous(this)); + p->combo->addCombination(new colorcombo::Complementary(this)); + p->combo->addCombination(new colorcombo::Monochromatic(this)); + p->combo->addCombination(new colorcombo::Triadic(this)); + p->combo->addCombination(new colorcombo::Tetradic(this)); + // init colors for palette + auto paletteColors = p->colorData.readSettings(); + for (const auto& color : paletteColors) { + p->palette->addColor(color); + } + // current combination + p->wheel->setColorCombination(p->combo->currentCombination()); + // current color + setCurrentColor(initial); +} + +void ColorEditor::setCurrentColor(const QColor& color) +{ + p->blockColorSignals(true); + { + p->wheel->setSelectedColor(color); + p->colorText->setColor(color); + p->preview->setCurrentColor(color); + p->setGradient(color); + p->rSlider->setValue(color.red()); + p->gSlider->setValue(color.green()); + p->bSlider->setValue(color.blue()); + p->hSlider->setValue(color.hsvHue()); + p->sSlider->setValue(color.hsvSaturation()); + p->vSlider->setValue(color.value()); + } + p->blockColorSignals(false); + + p->curColor = color; +} + +QColor ColorEditor::currentColor() const +{ + return p->preview->currentColor(); +} + +ColorEditor::~ColorEditor() {} + +void ColorEditor::setColorCombinations(const QVector combinations) +{ + p->combo->clearCombination(); + for (const auto& combination : combinations) { + p->combo->addCombination(combination); + } +} + +void ColorEditor::closeEvent(QCloseEvent* e) +{ + // save colors on close + p->colorData.writeSettings(p->palette->colors()); + QDialog::closeEvent(e); +} + +void ColorEditor::initSlots() +{ + // picker + connect(p->pickerBtn, &QPushButton::clicked, p->picker, &ColorPicker::startColorPicking); + connect(p->picker, &ColorPicker::colorSelected, this, &ColorEditor::setCurrentColor); + // color combination + connect(p->wheel, &ColorWheel::combinationColorChanged, p->combo, &ColorComboWidget::setColors); + connect(p->combo, &ColorComboWidget::combinationChanged, this, [this](colorcombo::ICombination* combination) { + p->wheel->setColorCombination(combination); + p->comboGroup->setTitle(combination->name()); + }); + // color wheel/text/preview/combo + connect(p->wheel, &ColorWheel::colorSelected, this, &ColorEditor::setCurrentColor); + connect(p->colorText, &ColorLineEdit::currentColorChanged, this, &ColorEditor::setCurrentColor); + connect(p->preview, &ColorPreview::currentColorChanged, this, &ColorEditor::setCurrentColor); + connect(p->palette, &ColorPalette::colorClicked, this, &ColorEditor::setCurrentColor); + connect(p->combo, &ColorComboWidget::colorClicked, this, [this](const QColor& color) { + // don't change wheel color + p->wheel->setEnabled(false); + setCurrentColor(color); + p->wheel->setEnabled(true); + }); + // color slider + connect(p->rSlider, &ColorSpinHSlider::valueChanged, this, [this](int value) { + auto color = QColor(value, p->curColor.green(), p->curColor.blue()); + setCurrentColor(color); + }); + connect(p->gSlider, &ColorSpinHSlider::valueChanged, this, [this](int value) { + auto color = QColor(p->curColor.red(), value, p->curColor.blue()); + setCurrentColor(color); + }); + connect(p->bSlider, &ColorSpinHSlider::valueChanged, this, [this](int value) { + auto color = QColor(p->curColor.red(), p->curColor.green(), value); + setCurrentColor(color); + }); + connect(p->hSlider, &ColorSpinHSlider::valueChanged, this, [this](int value) { + auto color = QColor::fromHsv(value, p->curColor.hsvSaturation(), p->curColor.value()); + setCurrentColor(color); + }); + connect(p->sSlider, &ColorSpinHSlider::valueChanged, this, [this](int value) { + auto color = QColor::fromHsv(p->curColor.hsvHue(), value, p->curColor.value()); + setCurrentColor(color); + }); + connect(p->vSlider, &ColorSpinHSlider::valueChanged, this, [this](int value) { + auto color = QColor::fromHsv(p->curColor.hsvHue(), p->curColor.hsvSaturation(), value); + setCurrentColor(color); + }); +} + +QColor ColorEditor::getColor(const QColor& initial, QWidget* parent, const QString& title) +{ + ColorEditor dlg(initial, parent); + if (!title.isEmpty()) dlg.setWindowTitle(title); + dlg.exec(); + return dlg.currentColor(); +} diff --git a/ui/zenoui/ColorEditor/ColorEditor.h b/ui/zenoui/ColorEditor/ColorEditor.h new file mode 100644 index 0000000000..d9cf774849 --- /dev/null +++ b/ui/zenoui/ColorEditor/ColorEditor.h @@ -0,0 +1,313 @@ +#pragma once + +#include + +#include +#include +#include +#include +#include +#include + +//------------------------------------------- color combination ---------------------------------------------- +namespace colorcombo +{ +class ICombination : public QObject +{ + Q_OBJECT +public: + explicit ICombination(QObject* parent = nullptr); + explicit ICombination(double min, double max, double value, bool rangeEnabled, QObject* parent = nullptr); + virtual ~ICombination() = default; + virtual QString name(); + virtual QVector genColors(const QColor& color); + void setRange(double min, double max); + void serValue(double value); + double min() const; + double max() const; + double getValue() const; + bool rangeEnabled() const; + +private: + double m_min; + double m_max; + double m_value; + bool m_rangeEnabled; +}; + +class Complementary : public ICombination +{ +public: + explicit Complementary(QObject* parent = nullptr); + virtual QString name() override; + virtual QVector genColors(const QColor& color) override; +}; + +class Monochromatic : public ICombination +{ +public: + explicit Monochromatic(QObject* parent = nullptr); + virtual QString name() override; + virtual QVector genColors(const QColor& color) override; +}; + +class Analogous : public ICombination +{ +public: + explicit Analogous(QObject* parent = nullptr); + virtual QString name() override; + virtual QVector genColors(const QColor& color) override; +}; + +class Triadic : public ICombination +{ +public: + explicit Triadic(QObject* parent = nullptr); + virtual QString name() override; + virtual QVector genColors(const QColor& color) override; +}; + +class Tetradic : public ICombination +{ +public: + explicit Tetradic(QObject* parent = nullptr); + virtual QString name() override; + virtual QVector genColors(const QColor& color) override; +}; +} // namespace colorcombo + +//-------------------------------------------------- color wheel -------------------------------------------------- +class ColorWheel : public QWidget +{ + Q_OBJECT +public: + explicit ColorWheel(QWidget* parent = nullptr); + + void setColorCombination(colorcombo::ICombination* combination); + void setSelectedColor(const QColor& color); + QColor getSelectedColor() const; + QColor getColor(int x, int y) const; + +signals: + void colorSelected(const QColor& color); + void combinationColorChanged(const QVector& colors); + +protected: + void paintEvent(QPaintEvent* e) override; + void mousePressEvent(QMouseEvent* e) override; + void mouseMoveEvent(QMouseEvent* e) override; + void resizeEvent(QResizeEvent* e) override; + +private: + void processMouseEvent(QMouseEvent* e); + void drawSelector(QPainter* painter, const QColor& color, int radius); + + class Private; + std::unique_ptr p; +}; + +//---------------------------------------------- color slider ------------------------------------------------------- +class JumpableSlider : public QSlider +{ + Q_OBJECT +public: + using QSlider::QSlider; + +protected: + void mousePressEvent(QMouseEvent* e) override; + void mouseMoveEvent(QMouseEvent* e) override; + void mouseReleaseEvent(QMouseEvent* e) override; + +private: + void handleMouseEvent(QMouseEvent* e); +}; + +class GradientSlider : public JumpableSlider +{ + Q_OBJECT +public: + explicit GradientSlider(QWidget* parent = nullptr); + void setGradient(const QColor& startColor, const QColor& stopColor); + void setGradient(const QVector>& colors); + QVector> gradientColor() const; + +private: + class Private; + std::unique_ptr p; +}; + +class ColorSpinHSlider : public QWidget +{ + Q_OBJECT +public: + explicit ColorSpinHSlider(const QString& name, QWidget* parent = nullptr); + void setGradient(const QColor& startColor, const QColor& stopColor); + void setGradient(const QVector>& colors); + void setValue(double value); + void setRange(double min, double max); + QVector> gradientColor() const; + +signals: + void valueChanged(int value); + +private: + class Private; + std::unique_ptr p; +}; + +//--------------------------------------------- color button ------------------------------------------------------- +class ColorButton : public QPushButton +{ + Q_OBJECT +public: + explicit ColorButton(QWidget* parent); + void setColor(const QColor& color); + void setBolderWidth(int width); + QColor color() const; + +signals: + void colorClicked(const QColor& color); + void colorDroped(const QColor& color); + +protected: + void mousePressEvent(QMouseEvent* e) override; + void mouseMoveEvent(QMouseEvent* e) override; + void dragEnterEvent(QDragEnterEvent* e) override; + void dragLeaveEvent(QDragLeaveEvent*) override; + void dropEvent(QDropEvent* e) override; + +private: + class Private; + std::unique_ptr p; +}; + +//--------------------------------------------- color palette ------------------------------------------------------ +class ColorPalette : public QScrollArea +{ + Q_OBJECT +public: + explicit ColorPalette(int column, QWidget* parent = nullptr); + void addColor(const QColor& color); + void setColor(const QColor& color, int row, int column); + void removeColor(int row, int column); + QColor colorAt(int row, int column) const; + QVector colors() const; + +signals: + void colorClicked(const QColor& color); + +protected: + void dragEnterEvent(QDragEnterEvent* e) override; + void dropEvent(QDropEvent* e) override; + +private: + class Private; + std::unique_ptr p; +}; + +//--------------------------------------------- color preview ------------------------------------------------------- +class ColorPreview : public QWidget +{ + Q_OBJECT +public: + explicit ColorPreview(const QColor& color, QWidget* parent = nullptr); + void setCurrentColor(const QColor& color); + QColor currentColor() const; + QColor previousColor() const; + +signals: + void currentColorChanged(const QColor& color); + +private: + class Private; + std::unique_ptr p; +}; + +//------------------------------------------- color combo widget --------------------------- +class ColorComboWidget : public QWidget +{ + Q_OBJECT +public: + explicit ColorComboWidget(QWidget* parent = nullptr); + + void addCombination(colorcombo::ICombination* combo); + void clearCombination(); + void switchCombination(); + void setColors(const QVector& colors); + colorcombo::ICombination* currentCombination() const; + +signals: + void colorClicked(const QColor& color); + void combinationChanged(colorcombo::ICombination* combo); + +private: + class Private; + std::unique_ptr p; +}; + +//------------------------------------------ color lineedit -------------------------------- +class ColorLineEdit : public QLineEdit +{ + Q_OBJECT +public: + explicit ColorLineEdit(QWidget* parent = nullptr); + void setColor(const QColor& color); + +signals: + void currentColorChanged(const QColor& color); +}; + +//------------------------------------------ color picker ---------------------------------- +class ColorPicker : public QWidget +{ + Q_OBJECT +public: + explicit ColorPicker(QWidget* parent = nullptr); + + QColor grabScreenColor(QPoint p) const; + void startColorPicking(); + void releaseColorPicking(); + +signals: + void colorSelected(const QColor& color); + +protected: + void paintEvent(QPaintEvent* e) override; + void mouseMoveEvent(QMouseEvent* e) override; + void mouseReleaseEvent(QMouseEvent* e) override; + void keyPressEvent(QKeyEvent* e) override; + void focusOutEvent(QFocusEvent* e) override; + +private: + class Private; + std::unique_ptr p; +}; + +//------------------------------------------ color editor ---------------------------------- +class ColorEditor : public QDialog +{ + Q_OBJECT +public: + explicit ColorEditor(QWidget* parent = nullptr); + explicit ColorEditor(const QColor& initial, QWidget* parent = nullptr); + ~ColorEditor(); + + static QColor getColor(const QColor& initial, QWidget* parent = nullptr, const QString& title = ""); + + void setCurrentColor(const QColor& color); + QColor currentColor() const; + + void setColorCombinations(const QVector combinations); + +signals: + void currentColorChanged(const QColor& color); + +protected: + void closeEvent(QCloseEvent* e) override; + +private: + void initSlots(); + + class Private; + std::unique_ptr p; +}; \ No newline at end of file diff --git a/ui/zenoui/comctrl/gv/zitemfactory.cpp b/ui/zenoui/comctrl/gv/zitemfactory.cpp index ace70e4e9c..2c716cc69c 100644 --- a/ui/zenoui/comctrl/gv/zitemfactory.cpp +++ b/ui/zenoui/comctrl/gv/zitemfactory.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include "zveceditoritem.h" #include "style/zenostyle.h" @@ -208,7 +209,7 @@ namespace zenoui pEditBtn->setProperty("color", value.value().name()); QObject::connect(pEditBtn, &ZenoParamPushButton::clicked, [=]() { - QColor color = QColorDialog::getColor(QColor(pEditBtn->property("color").toString())); + QColor color = ColorEditor::getColor(QColor(pEditBtn->property("color").toString())); if (color.isValid()) { pEditBtn->setProperty("color", color.name()); diff --git a/ui/zenoui/comctrl/zwidgetfactory.cpp b/ui/zenoui/comctrl/zwidgetfactory.cpp index ac022b5b6d..15ba512968 100644 --- a/ui/zenoui/comctrl/zwidgetfactory.cpp +++ b/ui/zenoui/comctrl/zwidgetfactory.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -113,7 +114,7 @@ namespace zenoui pBtn->setFixedSize(ZenoStyle::dpiScaled(100), ZenoStyle::dpiScaled(30)); pBtn->setStyleSheet(QString("background-color:%1; border:0;").arg(value.value().name())); QObject::connect(pBtn, &QPushButton::clicked, [=]() { - QColor color = QColorDialog::getColor(pBtn->palette().window().color()); + QColor color = ColorEditor::getColor(pBtn->palette().window().color()); if (color.isValid()) { pBtn->setStyleSheet(QString("background-color:%1; border:0;").arg(color.name())); From 379b96c28749b3521290e1d8291e499b38c22fab Mon Sep 17 00:00:00 2001 From: miyanyan <1138989048@qq.com> Date: Fri, 8 Sep 2023 22:54:29 +0800 Subject: [PATCH 04/32] add dialog buttons for ColorEditor --- ui/zenoui/ColorEditor/ColorEditor.cpp | 116 ++++++++++++++------------ ui/zenoui/ColorEditor/ColorEditor.h | 2 +- 2 files changed, 65 insertions(+), 53 deletions(-) diff --git a/ui/zenoui/ColorEditor/ColorEditor.cpp b/ui/zenoui/ColorEditor/ColorEditor.cpp index 9303525d44..606b1c1983 100644 --- a/ui/zenoui/ColorEditor/ColorEditor.cpp +++ b/ui/zenoui/ColorEditor/ColorEditor.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -1137,13 +1138,13 @@ class ColorEditor::Private ColorSpinHSlider* sSlider; ColorSpinHSlider* vSlider; - QColor initialColor; - QColor curColor; + QColor currentColor; + QColor selectedColor; ColorEditorData colorData; Private(const QColor& color, QDialog* parent) { - initialColor = color; + selectedColor = color; // left picker = new ColorPicker(parent); pickerBtn = new QPushButton(parent); @@ -1172,7 +1173,7 @@ class ColorEditor::Private auto leftWidget = new QWidget(parent); auto leftLayout = new QGridLayout(leftWidget); - // leftLayout->setMargin(0); + leftLayout->setContentsMargins(0, 0, 5, 0); leftLayout->setSpacing(0); leftLayout->addWidget(wheel, 0, 0); leftLayout->addWidget(colorText, 1, 0, Qt::AlignRight); @@ -1188,21 +1189,17 @@ class ColorEditor::Private sSlider = new ColorSpinHSlider("S", parent); vSlider = new ColorSpinHSlider("V", parent); - auto rgbSlider = new QWidget(parent); - auto rgbSliderLayout = new QVBoxLayout(rgbSlider); - rgbSliderLayout->setMargin(0); - rgbSliderLayout->setSpacing(2); - rgbSliderLayout->addWidget(rSlider); - rgbSliderLayout->addWidget(gSlider); - rgbSliderLayout->addWidget(bSlider); - - auto hsvSlider = new QWidget(parent); - auto hsvSliderLayout = new QVBoxLayout(hsvSlider); - hsvSliderLayout->setMargin(0); - hsvSliderLayout->setSpacing(2); - hsvSliderLayout->addWidget(hSlider); - hsvSliderLayout->addWidget(sSlider); - hsvSliderLayout->addWidget(vSlider); + auto colorSlider = new QWidget(parent); + auto colorSliderLayout = new QVBoxLayout(colorSlider); + colorSliderLayout->setMargin(0); + colorSliderLayout->setSpacing(2); + colorSliderLayout->addWidget(rSlider); + colorSliderLayout->addWidget(gSlider); + colorSliderLayout->addWidget(bSlider); + colorSliderLayout->addSpacing(5); + colorSliderLayout->addWidget(hSlider); + colorSliderLayout->addWidget(sSlider); + colorSliderLayout->addWidget(vSlider); rSlider->setRange(0, 255); gSlider->setRange(0, 255); @@ -1218,24 +1215,35 @@ class ColorEditor::Private setGradientS(color); setGradientV(color); - auto rightWidget = new QWidget(parent); - auto rightLayout = new QVBoxLayout(rightWidget); - // rightLayout->setMargin(0); - rightLayout->addWidget(palette); - rightLayout->addWidget(rgbSlider); - rightLayout->addWidget(hsvSlider); - // splitter - auto splitter = new QSplitter(parent); - splitter->addWidget(leftWidget); - splitter->addWidget(rightWidget); - splitter->setStretchFactor(0, 3); - splitter->setStretchFactor(1, 7); - splitter->setCollapsible(0, false); - splitter->setCollapsible(1, false); + auto rightSplitter = new QSplitter(Qt::Vertical, parent); + rightSplitter->addWidget(palette); + rightSplitter->addWidget(colorSlider); + rightSplitter->setCollapsible(0, false); + rightSplitter->setCollapsible(1, false); + auto equalH = std::max(palette->minimumSizeHint().height(), colorSlider->minimumSizeHint().height()); + rightSplitter->setSizes({equalH * 2, equalH * 1}); // setStretchFactor not always work well + + auto mainSplitter = new QSplitter(parent); + mainSplitter->addWidget(leftWidget); + mainSplitter->addWidget(rightSplitter); + mainSplitter->setStretchFactor(0, 3); + mainSplitter->setStretchFactor(1, 7); + mainSplitter->setCollapsible(0, false); + mainSplitter->setCollapsible(1, false); + // buttons + auto buttons = new QDialogButtonBox(parent); + auto okBtn = buttons->addButton(QDialogButtonBox::Ok); + auto cancleBtn = buttons->addButton(QDialogButtonBox::Cancel); + connect(okBtn, &QPushButton::clicked, parent, [this, parent]() { + selectedColor = currentColor; + parent->accept(); + }); + connect(cancleBtn, &QPushButton::clicked, parent, &QDialog::reject); auto layout = new QVBoxLayout(parent); - layout->setMargin(0); - layout->addWidget(splitter); + layout->setMargin(5); + layout->addWidget(mainSplitter); + layout->addWidget(buttons); } void blockColorSignals(bool block) @@ -1255,12 +1263,12 @@ class ColorEditor::Private void setGradient(const QColor& color) { - bool rChanged = color.red() != curColor.red(); - bool gChanged = color.green() != curColor.green(); - bool bChanged = color.blue() != curColor.blue(); - bool hChanged = color.hsvHue() != curColor.hsvHue(); - bool sChanged = color.hsvSaturation() != curColor.hsvSaturation(); - bool vChanged = color.value() != curColor.value(); + bool rChanged = color.red() != currentColor.red(); + bool gChanged = color.green() != currentColor.green(); + bool bChanged = color.blue() != currentColor.blue(); + bool hChanged = color.hsvHue() != currentColor.hsvHue(); + bool sChanged = color.hsvSaturation() != currentColor.hsvSaturation(); + bool vChanged = color.value() != currentColor.value(); if (gChanged || bChanged) { setGradientR(color); @@ -1324,9 +1332,10 @@ ColorEditor::ColorEditor(const QColor& initial, QWidget* parent) : QDialog(parent) , p(new Private(initial, this)) { + //setProperty("cssClass", "coloreditor"); setWindowFlag(Qt::WindowContextHelpButtonHint, false); setWindowTitle(tr("ColorEditor")); - setMinimumSize(700, 500); + setMinimumSize(700, 550); initSlots(); // init combinations p->combo->addCombination(new colorcombo::Analogous(this)); @@ -1362,15 +1371,18 @@ void ColorEditor::setCurrentColor(const QColor& color) } p->blockColorSignals(false); - p->curColor = color; + p->currentColor = color; } QColor ColorEditor::currentColor() const { - return p->preview->currentColor(); + return p->currentColor; } -ColorEditor::~ColorEditor() {} +QColor ColorEditor::selectedColor() const +{ + return p->selectedColor; +} void ColorEditor::setColorCombinations(const QVector combinations) { @@ -1411,27 +1423,27 @@ void ColorEditor::initSlots() }); // color slider connect(p->rSlider, &ColorSpinHSlider::valueChanged, this, [this](int value) { - auto color = QColor(value, p->curColor.green(), p->curColor.blue()); + auto color = QColor(value, p->currentColor.green(), p->currentColor.blue()); setCurrentColor(color); }); connect(p->gSlider, &ColorSpinHSlider::valueChanged, this, [this](int value) { - auto color = QColor(p->curColor.red(), value, p->curColor.blue()); + auto color = QColor(p->currentColor.red(), value, p->currentColor.blue()); setCurrentColor(color); }); connect(p->bSlider, &ColorSpinHSlider::valueChanged, this, [this](int value) { - auto color = QColor(p->curColor.red(), p->curColor.green(), value); + auto color = QColor(p->currentColor.red(), p->currentColor.green(), value); setCurrentColor(color); }); connect(p->hSlider, &ColorSpinHSlider::valueChanged, this, [this](int value) { - auto color = QColor::fromHsv(value, p->curColor.hsvSaturation(), p->curColor.value()); + auto color = QColor::fromHsv(value, p->currentColor.hsvSaturation(), p->currentColor.value()); setCurrentColor(color); }); connect(p->sSlider, &ColorSpinHSlider::valueChanged, this, [this](int value) { - auto color = QColor::fromHsv(p->curColor.hsvHue(), value, p->curColor.value()); + auto color = QColor::fromHsv(p->currentColor.hsvHue(), value, p->currentColor.value()); setCurrentColor(color); }); connect(p->vSlider, &ColorSpinHSlider::valueChanged, this, [this](int value) { - auto color = QColor::fromHsv(p->curColor.hsvHue(), p->curColor.hsvSaturation(), value); + auto color = QColor::fromHsv(p->currentColor.hsvHue(), p->currentColor.hsvSaturation(), value); setCurrentColor(color); }); } @@ -1441,5 +1453,5 @@ QColor ColorEditor::getColor(const QColor& initial, QWidget* parent, const QStri ColorEditor dlg(initial, parent); if (!title.isEmpty()) dlg.setWindowTitle(title); dlg.exec(); - return dlg.currentColor(); + return dlg.selectedColor(); } diff --git a/ui/zenoui/ColorEditor/ColorEditor.h b/ui/zenoui/ColorEditor/ColorEditor.h index d9cf774849..6f032982cf 100644 --- a/ui/zenoui/ColorEditor/ColorEditor.h +++ b/ui/zenoui/ColorEditor/ColorEditor.h @@ -290,12 +290,12 @@ class ColorEditor : public QDialog public: explicit ColorEditor(QWidget* parent = nullptr); explicit ColorEditor(const QColor& initial, QWidget* parent = nullptr); - ~ColorEditor(); static QColor getColor(const QColor& initial, QWidget* parent = nullptr, const QString& title = ""); void setCurrentColor(const QColor& color); QColor currentColor() const; + QColor selectedColor() const; void setColorCombinations(const QVector combinations); From 93e44a25f747faca5a9d3449b378c3429cc56109 Mon Sep 17 00:00:00 2001 From: miyanyan <1138989048@qq.com> Date: Sat, 9 Sep 2023 22:08:11 +0800 Subject: [PATCH 05/32] QDialog: Matches instances of QPushButton, but not of its subclasses --- ui/zenoedit/res/stylesheet/qwidget.qss | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ui/zenoedit/res/stylesheet/qwidget.qss b/ui/zenoedit/res/stylesheet/qwidget.qss index 8b1f6e2eb8..18a911478c 100644 --- a/ui/zenoedit/res/stylesheet/qwidget.qss +++ b/ui/zenoedit/res/stylesheet/qwidget.qss @@ -8,7 +8,7 @@ QDialog background: rgb(45,50,57); } -QDialog QPushButton +QDialog .QPushButton { background: #596270; color:#C3D2DF; @@ -17,19 +17,19 @@ QDialog QPushButton font-weight: 600; } -QDialog QPushButton:hover +QDialog .QPushButton:hover { background: #6A93BC; color:#CFDBE5; } -QDialog QPushButton:default +QDialog .QPushButton:default { background: #4578AC; color:#C3D2DF; } -QDialog QPushButton:disabled +QDialog .QPushButton:disabled { background: #8A919A; color:#9BAAB4; From 0e499e7ecf2acdc3aced32278f4e50f34c81415f Mon Sep 17 00:00:00 2001 From: miyanyan <1138989048@qq.com> Date: Mon, 11 Sep 2023 21:24:22 +0800 Subject: [PATCH 06/32] update color editor style --- ui/zenoedit/res/stylesheet/qwidget.qss | 11 +++- ui/zenoui/ColorEditor/ColorEditor.cpp | 91 ++++++++++++++++++-------- ui/zenoui/ColorEditor/ColorEditor.h | 4 +- 3 files changed, 74 insertions(+), 32 deletions(-) diff --git a/ui/zenoedit/res/stylesheet/qwidget.qss b/ui/zenoedit/res/stylesheet/qwidget.qss index 18a911478c..1151c31d18 100644 --- a/ui/zenoedit/res/stylesheet/qwidget.qss +++ b/ui/zenoedit/res/stylesheet/qwidget.qss @@ -68,6 +68,11 @@ QDialog QLineEdit:disabled { color: #8f9ba8; } +QDialog QGroupBox { + font-size: 8pt; + font-weight: 500; + color: #A3B1C0; +} QDialog QCheckBox{ font-size: 9pt; @@ -98,6 +103,10 @@ QDialog QSpinBox::down-button border: none; } +QDialog QSpinBox:disabled { + background-color: #2F2F2F; +} + QDialog QTableWidget { background-color: #191D21; @@ -208,4 +217,4 @@ QWidget[cssClass = "welcomepage_link"] border-radius: 8px; border:1px solid #24282E; padding-left: 20px; -} \ No newline at end of file +} diff --git a/ui/zenoui/ColorEditor/ColorEditor.cpp b/ui/zenoui/ColorEditor/ColorEditor.cpp index 606b1c1983..ebe0f86129 100644 --- a/ui/zenoui/ColorEditor/ColorEditor.cpp +++ b/ui/zenoui/ColorEditor/ColorEditor.cpp @@ -25,6 +25,8 @@ #include #include +#include "zenoui/style/zenostyle.h" + //--------------------------------------------------------- color wheel ------------------------------------------------ class ColorWheel::Private { @@ -202,7 +204,7 @@ void ICombination::setRange(double min, double max) m_max = max; } -void ICombination::serValue(double value) +void ICombination::setValue(double value) { m_value = value; } @@ -243,7 +245,7 @@ QVector Complementary::genColors(const QColor& color) } Monochromatic::Monochromatic(QObject* parent) - : ICombination(0, 1, 0.5, true, parent) + : ICombination(0, 100, 50, true, parent) { } @@ -254,7 +256,8 @@ QString Monochromatic::name() QVector Monochromatic::genColors(const QColor& color) { - return {QColor::fromHsvF(color.hsvHueF(), color.hsvSaturationF(), color.valueF() * getValue())}; + double rate = getValue() / (max() - min()); + return {QColor::fromHsvF(color.hsvHueF(), color.hsvSaturationF(), color.valueF() * rate)}; } Analogous::Analogous(QObject* parent) @@ -490,14 +493,26 @@ class ColorButton::Private public: QPoint pressPos; QColor color; - int bolderWidth = 0; + int bolderTopWidth = 0; + int bolderBottomWidth = 0; + int bolderLeftWidth = 0; + int bolderRightWidth = 0; void updateStyle(QPushButton* btn) { - auto style = QString("QPushButton{min-width:30px;min-height:30px;background-color:%1;border:%2px solid;}" + int minWidth = ZenoStyle::dpiScaled(20); + int minHeight = ZenoStyle::dpiScaled(20); + auto style = QString("QPushButton{min-width:%1px;min-height:%2px;background-color:%3;" + "border-top:%4px solid;border-bottom:%5px solid;" + "border-left:%6px solid;border-right:%7px solid;}" "QPushButton:pressed{border: 1px solid #ffd700;}") - .arg(color.name()) - .arg(bolderWidth); + .arg(minWidth) + .arg(minHeight) + .arg(color.name()) + .arg(bolderTopWidth) + .arg(bolderBottomWidth) + .arg(bolderLeftWidth) + .arg(bolderRightWidth); btn->setStyleSheet(style); } }; @@ -516,9 +531,12 @@ void ColorButton::setColor(const QColor& color) p->updateStyle(this); } -void ColorButton::setBolderWidth(int width) +void ColorButton::setBolderWidth(int top, int bottom, int left, int right) { - p->bolderWidth = width; + p->bolderTopWidth = top; + p->bolderBottomWidth = bottom; + p->bolderLeftWidth = left; + p->bolderRightWidth = right; p->updateStyle(this); } @@ -610,6 +628,19 @@ class ColorPalette::Private btn->setColor(colors[i]); } } + + void updateBolder(int begin, int end) + { + int size = colors.size(); + for (int i = begin; i < end; ++i) { + int row = i / columnCount; + int col = i % columnCount; + auto btn = qobject_cast(layout->itemAtPosition(row, col)->widget()); + int bolderLeftWidth = col == 0 ? 1 : 0; + int bolderTopWidth = row == 0 ? 1 : 0; + btn->setBolderWidth(bolderTopWidth, 1, bolderLeftWidth, 1); + } + } }; ColorPalette::ColorPalette(int column, QWidget* parent) @@ -627,7 +658,6 @@ void ColorPalette::addColor(const QColor& color) auto btn = new ColorButton(this); btn->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); - btn->setBolderWidth(1); btn->setToolTip(tr("Ctrl + click to remove color")); connect(btn, &ColorButton::colorClicked, this, [this, index](const QColor& color) { if (QApplication::keyboardModifiers() == Qt::ControlModifier) { @@ -646,7 +676,8 @@ void ColorPalette::addColor(const QColor& color) auto layoutIndex = p->getLayoutIndex(index); p->layout->addWidget(btn, layoutIndex.first, layoutIndex.second); - p->updateLayout(index, index + 1); + p->updateLayout(index, p->colors.size()); + p->updateBolder(index, p->colors.size()); } void ColorPalette::setColor(const QColor& color, int row, int column) @@ -668,6 +699,7 @@ void ColorPalette::removeColor(int row, int column) int index = row * p->columnCount + column; p->colors.remove(index); p->updateLayout(index, p->colors.size()); + p->updateBolder(index, p->colors.size()); } QColor ColorPalette::colorAt(int row, int column) const @@ -721,8 +753,8 @@ class ColorPreview::Private // pbtnCurrent->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); // pbtnPrevious->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); - pbtnCurrent->setBolderWidth(1); - pbtnPrevious->setBolderWidth(1); + pbtnCurrent->setBolderWidth(1, 1, 0, 1); + pbtnPrevious->setBolderWidth(1, 1, 1, 1); pbtnCurrent->setColor(color); pbtnPrevious->setColor(color); @@ -764,16 +796,15 @@ QColor ColorPreview::previousColor() const class ColorComboWidget::Private { public: - static constexpr int factor = 360; std::queue combs; QHBoxLayout* hlayout = nullptr; QPushButton* switchBtn = nullptr; JumpableSlider* factorSlider = nullptr; - QDoubleSpinBox* factorSpinbox = nullptr; + QSpinBox* factorSpinbox = nullptr; Private(QWidget* parent) { - factorSpinbox = new QDoubleSpinBox(parent); + factorSpinbox = new QSpinBox(parent); factorSlider = new JumpableSlider(Qt::Horizontal, parent); switchBtn = new QPushButton(parent); switchBtn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); @@ -789,9 +820,8 @@ class ColorComboWidget::Private layout->addWidget(factorSpinbox, 1, 0, 1, 1); layout->addWidget(factorSlider, 1, 1, 1, 3); - connect(factorSlider, &QSlider::valueChanged, factorSpinbox, [this](int value) { factorSpinbox->setValue(1.0 * value / factor); }); - connect(factorSpinbox, QOverload::of(&QDoubleSpinBox::valueChanged), factorSlider, - [this](double value) { factorSlider->setValue(value * factor); }); + connect(factorSlider, &QSlider::valueChanged, factorSpinbox, &QSpinBox::setValue); + connect(factorSpinbox, QOverload::of(&QSpinBox::valueChanged), factorSlider, &QSlider::setValue); } }; @@ -804,9 +834,9 @@ ColorComboWidget::ColorComboWidget(QWidget* parent) switchCombination(); connect(p->switchBtn, &QPushButton::clicked, this, &ColorComboWidget::switchCombination); - connect(p->factorSpinbox, QOverload::of(&QDoubleSpinBox::valueChanged), this, [this](double value) { + connect(p->factorSpinbox, QOverload::of(&QSpinBox::valueChanged), this, [this](int value) { auto comb = p->combs.front(); - comb->serValue(value); + comb->setValue(value); emit combinationChanged(comb); }); } @@ -862,20 +892,24 @@ void ColorComboWidget::switchCombination() int size = colors.size() + 1; for (int i = 0; i < size; ++i) { auto btn = new ColorButton(this); - btn->setBolderWidth(1); + int bolderRightWidth = i < size - 1 ? 0 : 1; + btn->setBolderWidth(1, 1, 1, bolderRightWidth); btn->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); btn->setAcceptDrops(false); // color can't be changed by drop connect(btn, &ColorButton::colorClicked, this, &ColorComboWidget::colorClicked); p->hlayout->addWidget(btn); } - // make slider looks like double slider - p->factorSlider->setRange(currentComb->min() * p->factor, currentComb->max() * p->factor); + p->factorSlider->blockSignals(true); + p->factorSpinbox->blockSignals(true); + p->factorSlider->setRange(currentComb->min(), currentComb->max()); p->factorSpinbox->setRange(currentComb->min(), currentComb->max()); - p->factorSpinbox->setSingleStep((currentComb->max() - currentComb->min()) / p->factor); + p->factorSlider->setValue(currentComb->getValue()); p->factorSpinbox->setValue(currentComb->getValue()); p->factorSlider->setEnabled(currentComb->rangeEnabled()); p->factorSpinbox->setEnabled(currentComb->rangeEnabled()); + p->factorSlider->blockSignals(false); + p->factorSpinbox->blockSignals(false); emit combinationChanged(currentComb); } @@ -1155,7 +1189,7 @@ class ColorEditor::Private previewGroup = new QGroupBox(tr("Previous/Current Colors"), parent); comboGroup = new QGroupBox(tr("Color Combination"), parent); - colorText->setMaximumWidth(80); + colorText->setMaximumWidth(ZenoStyle::dpiScaled(60)); colorText->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); pickerBtn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); @@ -1191,7 +1225,7 @@ class ColorEditor::Private auto colorSlider = new QWidget(parent); auto colorSliderLayout = new QVBoxLayout(colorSlider); - colorSliderLayout->setMargin(0); + colorSliderLayout->setContentsMargins(5, 0, 0, 0); colorSliderLayout->setSpacing(2); colorSliderLayout->addWidget(rSlider); colorSliderLayout->addWidget(gSlider); @@ -1332,10 +1366,9 @@ ColorEditor::ColorEditor(const QColor& initial, QWidget* parent) : QDialog(parent) , p(new Private(initial, this)) { - //setProperty("cssClass", "coloreditor"); setWindowFlag(Qt::WindowContextHelpButtonHint, false); setWindowTitle(tr("ColorEditor")); - setMinimumSize(700, 550); + setMinimumSize(ZenoStyle::dpiScaled(500), ZenoStyle::dpiScaled(350)); initSlots(); // init combinations p->combo->addCombination(new colorcombo::Analogous(this)); diff --git a/ui/zenoui/ColorEditor/ColorEditor.h b/ui/zenoui/ColorEditor/ColorEditor.h index 6f032982cf..fb5d673c09 100644 --- a/ui/zenoui/ColorEditor/ColorEditor.h +++ b/ui/zenoui/ColorEditor/ColorEditor.h @@ -22,7 +22,7 @@ class ICombination : public QObject virtual QString name(); virtual QVector genColors(const QColor& color); void setRange(double min, double max); - void serValue(double value); + void setValue(double value); double min() const; double max() const; double getValue() const; @@ -162,7 +162,7 @@ class ColorButton : public QPushButton public: explicit ColorButton(QWidget* parent); void setColor(const QColor& color); - void setBolderWidth(int width); + void setBolderWidth(int top, int bottom, int left, int right); QColor color() const; signals: From a8534f9624f782eeb066da486786033dafc90034 Mon Sep 17 00:00:00 2001 From: miyanyan <1138989048@qq.com> Date: Thu, 21 Sep 2023 12:50:14 +0800 Subject: [PATCH 07/32] ColorEditor: do not handle key_return and key_enter --- ui/zenoui/ColorEditor/ColorEditor.cpp | 8 ++++++++ ui/zenoui/ColorEditor/ColorEditor.h | 1 + 2 files changed, 9 insertions(+) diff --git a/ui/zenoui/ColorEditor/ColorEditor.cpp b/ui/zenoui/ColorEditor/ColorEditor.cpp index ebe0f86129..ae2acff481 100644 --- a/ui/zenoui/ColorEditor/ColorEditor.cpp +++ b/ui/zenoui/ColorEditor/ColorEditor.cpp @@ -1432,6 +1432,14 @@ void ColorEditor::closeEvent(QCloseEvent* e) QDialog::closeEvent(e); } +void ColorEditor::keyPressEvent(QKeyEvent* e) +{ + if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) { + return; + } + QDialog::keyPressEvent(e); +} + void ColorEditor::initSlots() { // picker diff --git a/ui/zenoui/ColorEditor/ColorEditor.h b/ui/zenoui/ColorEditor/ColorEditor.h index fb5d673c09..120e30a2f5 100644 --- a/ui/zenoui/ColorEditor/ColorEditor.h +++ b/ui/zenoui/ColorEditor/ColorEditor.h @@ -304,6 +304,7 @@ class ColorEditor : public QDialog protected: void closeEvent(QCloseEvent* e) override; + void keyPressEvent(QKeyEvent* e) override; private: void initSlots(); From 30e485bd56cf1d77a21f7df702f0f0bc5cec28e5 Mon Sep 17 00:00:00 2001 From: miyanyan <1138989048@qq.com> Date: Sun, 24 Sep 2023 22:55:37 +0800 Subject: [PATCH 08/32] add MixedSpinBox --- ui/zenoedit/res/stylesheet/spinbox.qss | 35 +++++++++++++++++++++++++- ui/zenoui/ColorEditor/ColorEditor.cpp | 16 ++++++++++++ ui/zenoui/ColorEditor/ColorEditor.h | 8 ++++++ 3 files changed, 58 insertions(+), 1 deletion(-) diff --git a/ui/zenoedit/res/stylesheet/spinbox.qss b/ui/zenoedit/res/stylesheet/spinbox.qss index 06d26840b1..f46440bbf6 100644 --- a/ui/zenoedit/res/stylesheet/spinbox.qss +++ b/ui/zenoedit/res/stylesheet/spinbox.qss @@ -72,7 +72,7 @@ QSpinBox[cssClass = "control"]::up-button:hover { image: url(:/icons/rightArrow-on.svg); } - + QDoubleSpinBox { background: #191D21; @@ -117,4 +117,37 @@ QDoubleSpinBox::up-button QDoubleSpinBox::up-button:hover { image: url(:/icons/rightArrow-on.svg); +} + +/* ^^^ the upper style is too large... */ +QDoubleSpinBox#MixedSpinBox +{ + height: 20px; + font-size: 9pt; + font-weight: 400; + border: 0; + color: #FFFFFF; + background-color: #191D21; +} + +QDoubleSpinBox#MixedSpinBox:focus +{ + border: 2px solid #4B9EF4; +} + +QDoubleSpinBox#MixedSpinBox:disabled +{ + background-color: #2F2F2F; +} + +QDoubleSpinBox#MixedSpinBox::up-button +{ + height: 0px; + width: 0px; +} + +QDoubleSpinBox#MixedSpinBox::down-button +{ + height: 0px; + width: 0px; } \ No newline at end of file diff --git a/ui/zenoui/ColorEditor/ColorEditor.cpp b/ui/zenoui/ColorEditor/ColorEditor.cpp index ae2acff481..a22a01793a 100644 --- a/ui/zenoui/ColorEditor/ColorEditor.cpp +++ b/ui/zenoui/ColorEditor/ColorEditor.cpp @@ -324,6 +324,22 @@ QVector Tetradic::genColors(const QColor& color) } // namespace colorcombo //--------------------------------------------------- color slider ------------------------------------------- +MixedSpinBox::MixedSpinBox(QWidget* parent) + : QDoubleSpinBox(parent) +{ + setObjectName("MixedSpinBox"); + setDecimals(4); + setSingleStep(0.0001); + setFocusPolicy(Qt::ClickFocus); +} + +QString MixedSpinBox::textFromValue(double value) const +{ + QString shortestNum = QLocale().toString(value, 'f', QLocale::FloatingPointShortest); + QString decimalNum = QLocale().toString(value, 'f', decimals()); + return shortestNum.size() <= decimalNum.size() ? shortestNum : decimalNum; +} + void JumpableSlider::mousePressEvent(QMouseEvent* e) { if (e->button() == Qt::LeftButton) { diff --git a/ui/zenoui/ColorEditor/ColorEditor.h b/ui/zenoui/ColorEditor/ColorEditor.h index 120e30a2f5..0ba30b9ae4 100644 --- a/ui/zenoui/ColorEditor/ColorEditor.h +++ b/ui/zenoui/ColorEditor/ColorEditor.h @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -107,6 +108,13 @@ class ColorWheel : public QWidget }; //---------------------------------------------- color slider ------------------------------------------------------- +class MixedSpinBox : public QDoubleSpinBox +{ +public: + explicit MixedSpinBox(QWidget* parent = nullptr); + virtual QString textFromValue(double value) const override; +}; + class JumpableSlider : public QSlider { Q_OBJECT From fcb7f9070fea6b2e167ae4674d60d888dd243fef Mon Sep 17 00:00:00 2001 From: miyanyan <1138989048@qq.com> Date: Sun, 24 Sep 2023 23:03:57 +0800 Subject: [PATCH 09/32] ColorEditor: color values [0, 255] -> [0.0, 1.0] --- ui/zenoui/ColorEditor/ColorEditor.cpp | 207 +++++++++++++++++++------- ui/zenoui/ColorEditor/ColorEditor.h | 27 +++- 2 files changed, 179 insertions(+), 55 deletions(-) diff --git a/ui/zenoui/ColorEditor/ColorEditor.cpp b/ui/zenoui/ColorEditor/ColorEditor.cpp index a22a01793a..1fe1a0808d 100644 --- a/ui/zenoui/ColorEditor/ColorEditor.cpp +++ b/ui/zenoui/ColorEditor/ColorEditor.cpp @@ -175,15 +175,17 @@ ICombination::ICombination(QObject* parent) , m_min(0) , m_max(1) , m_value(0) + , m_decimals(0) , m_rangeEnabled(false) { } -ICombination::ICombination(double min, double max, double value, bool rangeEnabled, QObject* parent) +ICombination::ICombination(double min, double max, double value, int decimals, bool rangeEnabled, QObject* parent) : QObject(parent) , m_min(min) , m_max(max) , m_value(value) + , m_decimals(decimals) , m_rangeEnabled(rangeEnabled) { } @@ -209,6 +211,11 @@ void ICombination::setValue(double value) m_value = value; } +void ICombination::setDecimals(int decimals) +{ + m_decimals = decimals; +} + double ICombination::min() const { return m_min; @@ -229,6 +236,11 @@ bool ICombination::rangeEnabled() const return m_rangeEnabled; } +int ICombination::decimals() const +{ + return m_decimals; +} + Complementary::Complementary(QObject* parent) : ICombination(parent) { @@ -245,7 +257,7 @@ QVector Complementary::genColors(const QColor& color) } Monochromatic::Monochromatic(QObject* parent) - : ICombination(0, 100, 50, true, parent) + : ICombination(0, 1, 0.5, 4, true, parent) { } @@ -261,7 +273,7 @@ QVector Monochromatic::genColors(const QColor& color) } Analogous::Analogous(QObject* parent) - : ICombination(0, 180, 30, true, parent) + : ICombination(0, 180, 30, 0, true, parent) { } @@ -278,7 +290,7 @@ QVector Analogous::genColors(const QColor& color) } Triadic::Triadic(QObject* parent) - : ICombination(0, 180, 120, true, parent) + : ICombination(0, 180, 120, 0, true, parent) { } @@ -295,7 +307,7 @@ QVector Triadic::genColors(const QColor& color) } Tetradic::Tetradic(QObject* parent) - : ICombination(-90, 90, 90, true, parent) + : ICombination(-90, 90, 90, 0, true, parent) { } @@ -340,6 +352,86 @@ QString MixedSpinBox::textFromValue(double value) const return shortestNum.size() <= decimalNum.size() ? shortestNum : decimalNum; } +class JumpableSlider::Private +{ +public: + double minValue = 0.0; + double maxValue = 1.0; + double singleStep = 0.0001; +}; + +JumpableSlider::JumpableSlider(QWidget* parent) + : JumpableSlider(Qt::Horizontal, parent) +{ +} + +JumpableSlider::JumpableSlider(Qt::Orientation orientation, QWidget* parent) + : QSlider(orientation, parent) + , p(new Private) +{ + connect(this, &QSlider::valueChanged, this, [this](int value) {emit valueChanged(value * p->singleStep); }); +} + +void JumpableSlider::setValue(double value) +{ + // need round + // 0.179999 * 1000 need be 180 + // int(0.179999 * 1000) = 179 + QSlider::setValue(std::round(value / p->singleStep)); +} + +void JumpableSlider::setMinimum(double value) +{ + QSlider::setMinimum(value / p->singleStep); + p->minValue = value; +} + +void JumpableSlider::setMaximum(double value) +{ + if (value < p->minValue) { + return; + } + QSlider::setMaximum(value / p->singleStep); + p->maxValue = value; +} + +void JumpableSlider::setRange(double minValue, double maxValue) +{ + setMinimum(minValue); + setMaximum(maxValue); +} + +void JumpableSlider::setSingleStep(double value) +{ + if (value == 0.0) { + return; + } + p->singleStep = value; + setMinimum(p->minValue); + setMaximum(p->maxValue); + setValue(this->value()); +} + +double JumpableSlider::value() const +{ + return QSlider::value() * p->singleStep; +} + +double JumpableSlider::minimum() const +{ + return p->minValue; +} + +double JumpableSlider::maximum() const +{ + return p->maxValue; +} + +double JumpableSlider::singleStep() const +{ + return p->singleStep; +} + void JumpableSlider::mousePressEvent(QMouseEvent* e) { if (e->button() == Qt::LeftButton) { @@ -370,14 +462,16 @@ void JumpableSlider::mouseReleaseEvent(QMouseEvent* e) void JumpableSlider::handleMouseEvent(QMouseEvent* e) { - int newVal; + double newVal; + double maxValue = maximum(); + double minValue = minimum(); if (orientation() == Qt::Horizontal) { - newVal = minimum() + ((maximum() - minimum() + 1) * e->x()) / width(); + newVal = minValue + ((maxValue - minValue) * e->x()) / width(); } else { - newVal = minimum() + ((maximum() - minimum() + 1) * (height() - e->y())) / height(); + newVal = minValue + ((maxValue - minValue) * (height() - e->y())) / height(); } - setValue(!invertedAppearance() ? newVal : maximum() - newVal); + setValue(!invertedAppearance() ? newVal : maxValue - newVal); } class GradientSlider::Private @@ -448,14 +542,14 @@ QVector> GradientSlider::gradientColor() const class ColorSpinHSlider::Private { public: - QSpinBox* spinbox; + MixedSpinBox* spinbox; GradientSlider* slider; Private(const QString& name, QWidget* parent) { QLabel* text = new QLabel(name, parent); text->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - spinbox = new QSpinBox(parent); + spinbox = new MixedSpinBox(parent); spinbox->setButtonSymbols(QAbstractSpinBox::NoButtons); slider = new GradientSlider(parent); slider->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); @@ -463,18 +557,17 @@ class ColorSpinHSlider::Private layout->setAlignment(Qt::AlignLeft); layout->setMargin(0); layout->addWidget(text, 1); - layout->addWidget(spinbox, 1); - layout->addWidget(slider, 8); - - connect(slider, &QSlider::valueChanged, spinbox, &QSpinBox::setValue); - connect(spinbox, QOverload::of(&QSpinBox::valueChanged), slider, &GradientSlider::setValue); + layout->addWidget(spinbox, 2); + layout->addWidget(slider, 7); } }; ColorSpinHSlider::ColorSpinHSlider(const QString& name, QWidget* parent) : QWidget(parent) , p(new Private(name, this)) { - connect(p->slider, &QSlider::valueChanged, this, &ColorSpinHSlider::valueChanged); + connect(p->slider, &GradientSlider::valueChanged, this, &ColorSpinHSlider::valueChanged); + connect(p->slider, &GradientSlider::valueChanged, p->spinbox, &MixedSpinBox::setValue); + connect(p->spinbox, &MixedSpinBox::editingFinished, this, [this]() { p->slider->setValue(p->spinbox->value()); }); } void ColorSpinHSlider::setGradient(const QColor& startColor, const QColor& stopColor) @@ -490,6 +583,7 @@ void ColorSpinHSlider::setGradient(const QVector>& colors) void ColorSpinHSlider::setValue(double value) { p->spinbox->setValue(value); + p->slider->setValue(value); } void ColorSpinHSlider::setRange(double min, double max) @@ -503,6 +597,11 @@ QVector> ColorSpinHSlider::gradientColor() const return p->slider->gradientColor(); } +double ColorSpinHSlider::value() const +{ + return p->slider->value(); +} + //--------------------------------------------- color button ------------------------------------------------------- class ColorButton::Private { @@ -816,11 +915,11 @@ class ColorComboWidget::Private QHBoxLayout* hlayout = nullptr; QPushButton* switchBtn = nullptr; JumpableSlider* factorSlider = nullptr; - QSpinBox* factorSpinbox = nullptr; + MixedSpinBox* factorSpinbox = nullptr; Private(QWidget* parent) { - factorSpinbox = new QSpinBox(parent); + factorSpinbox = new MixedSpinBox(parent); factorSlider = new JumpableSlider(Qt::Horizontal, parent); switchBtn = new QPushButton(parent); switchBtn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); @@ -831,13 +930,10 @@ class ColorComboWidget::Private hlayout = new QHBoxLayout(); hlayout->setMargin(0); hlayout->setSpacing(0); - layout->addLayout(hlayout, 0, 0, 1, 3); - layout->addWidget(switchBtn, 0, 3, 1, 1); - layout->addWidget(factorSpinbox, 1, 0, 1, 1); - layout->addWidget(factorSlider, 1, 1, 1, 3); - - connect(factorSlider, &QSlider::valueChanged, factorSpinbox, &QSpinBox::setValue); - connect(factorSpinbox, QOverload::of(&QSpinBox::valueChanged), factorSlider, &QSlider::setValue); + layout->addLayout(hlayout, 0, 0, 1, 9); + layout->addWidget(switchBtn, 0, 9, 1, 1); + layout->addWidget(factorSpinbox, 1, 0, 1, 4); + layout->addWidget(factorSlider, 1, 4, 1, 6); } }; @@ -850,7 +946,12 @@ ColorComboWidget::ColorComboWidget(QWidget* parent) switchCombination(); connect(p->switchBtn, &QPushButton::clicked, this, &ColorComboWidget::switchCombination); - connect(p->factorSpinbox, QOverload::of(&QSpinBox::valueChanged), this, [this](int value) { + connect(p->factorSpinbox, &MixedSpinBox::editingFinished, this, [this]() { + double value = p->factorSpinbox->value(); + p->factorSlider->setValue(value); + }); + connect(p->factorSlider, &JumpableSlider::valueChanged, this, [this](double value) { + p->factorSpinbox->setValue(value); auto comb = p->combs.front(); comb->setValue(value); emit combinationChanged(comb); @@ -918,6 +1019,7 @@ void ColorComboWidget::switchCombination() p->factorSlider->blockSignals(true); p->factorSpinbox->blockSignals(true); + p->factorSpinbox->setDecimals(currentComb->decimals()); // need set decimals first p->factorSlider->setRange(currentComb->min(), currentComb->max()); p->factorSpinbox->setRange(currentComb->min(), currentComb->max()); p->factorSlider->setValue(currentComb->getValue()); @@ -1251,12 +1353,12 @@ class ColorEditor::Private colorSliderLayout->addWidget(sSlider); colorSliderLayout->addWidget(vSlider); - rSlider->setRange(0, 255); - gSlider->setRange(0, 255); - bSlider->setRange(0, 255); - hSlider->setRange(0, 359); - sSlider->setRange(0, 255); - vSlider->setRange(0, 255); + rSlider->setRange(0, 1); + gSlider->setRange(0, 1); + bSlider->setRange(0, 1); + hSlider->setRange(0, 1); + sSlider->setRange(0, 1); + vSlider->setRange(0, 1); setGradientR(color); setGradientG(color); @@ -1387,8 +1489,8 @@ ColorEditor::ColorEditor(const QColor& initial, QWidget* parent) setMinimumSize(ZenoStyle::dpiScaled(500), ZenoStyle::dpiScaled(350)); initSlots(); // init combinations - p->combo->addCombination(new colorcombo::Analogous(this)); p->combo->addCombination(new colorcombo::Complementary(this)); + p->combo->addCombination(new colorcombo::Analogous(this)); p->combo->addCombination(new colorcombo::Monochromatic(this)); p->combo->addCombination(new colorcombo::Triadic(this)); p->combo->addCombination(new colorcombo::Tetradic(this)); @@ -1411,12 +1513,12 @@ void ColorEditor::setCurrentColor(const QColor& color) p->colorText->setColor(color); p->preview->setCurrentColor(color); p->setGradient(color); - p->rSlider->setValue(color.red()); - p->gSlider->setValue(color.green()); - p->bSlider->setValue(color.blue()); - p->hSlider->setValue(color.hsvHue()); - p->sSlider->setValue(color.hsvSaturation()); - p->vSlider->setValue(color.value()); + p->rSlider->setValue(color.redF()); + p->gSlider->setValue(color.greenF()); + p->bSlider->setValue(color.blueF()); + p->hSlider->setValue(color.hsvHueF()); + p->sSlider->setValue(color.hsvSaturationF()); + p->vSlider->setValue(color.valueF()); } p->blockColorSignals(false); @@ -1479,28 +1581,28 @@ void ColorEditor::initSlots() p->wheel->setEnabled(true); }); // color slider - connect(p->rSlider, &ColorSpinHSlider::valueChanged, this, [this](int value) { - auto color = QColor(value, p->currentColor.green(), p->currentColor.blue()); + connect(p->rSlider, &ColorSpinHSlider::valueChanged, this, [this](double value) { + auto color = QColor::fromRgbF(value, p->currentColor.greenF(), p->currentColor.blueF()); setCurrentColor(color); }); - connect(p->gSlider, &ColorSpinHSlider::valueChanged, this, [this](int value) { - auto color = QColor(p->currentColor.red(), value, p->currentColor.blue()); + connect(p->gSlider, &ColorSpinHSlider::valueChanged, this, [this](double value) { + auto color = QColor::fromRgbF(p->currentColor.redF(), value, p->currentColor.blueF()); setCurrentColor(color); }); - connect(p->bSlider, &ColorSpinHSlider::valueChanged, this, [this](int value) { - auto color = QColor(p->currentColor.red(), p->currentColor.green(), value); + connect(p->bSlider, &ColorSpinHSlider::valueChanged, this, [this](double value) { + auto color = QColor::fromRgbF(p->currentColor.redF(), p->currentColor.greenF(), value); setCurrentColor(color); }); - connect(p->hSlider, &ColorSpinHSlider::valueChanged, this, [this](int value) { - auto color = QColor::fromHsv(value, p->currentColor.hsvSaturation(), p->currentColor.value()); + connect(p->hSlider, &ColorSpinHSlider::valueChanged, this, [this](double value) { + auto color = QColor::fromHsvF(value, p->currentColor.hsvSaturationF(), p->currentColor.valueF()); setCurrentColor(color); }); - connect(p->sSlider, &ColorSpinHSlider::valueChanged, this, [this](int value) { - auto color = QColor::fromHsv(p->currentColor.hsvHue(), value, p->currentColor.value()); + connect(p->sSlider, &ColorSpinHSlider::valueChanged, this, [this](double value) { + auto color = QColor::fromHsvF(p->currentColor.hsvHueF(), value, p->currentColor.valueF()); setCurrentColor(color); }); - connect(p->vSlider, &ColorSpinHSlider::valueChanged, this, [this](int value) { - auto color = QColor::fromHsv(p->currentColor.hsvHue(), p->currentColor.hsvSaturation(), value); + connect(p->vSlider, &ColorSpinHSlider::valueChanged, this, [this](double value) { + auto color = QColor::fromHsvF(p->currentColor.hsvHueF(), p->currentColor.hsvSaturationF(), value); setCurrentColor(color); }); } @@ -1512,3 +1614,4 @@ QColor ColorEditor::getColor(const QColor& initial, QWidget* parent, const QStri dlg.exec(); return dlg.selectedColor(); } + diff --git a/ui/zenoui/ColorEditor/ColorEditor.h b/ui/zenoui/ColorEditor/ColorEditor.h index 0ba30b9ae4..30dca6213a 100644 --- a/ui/zenoui/ColorEditor/ColorEditor.h +++ b/ui/zenoui/ColorEditor/ColorEditor.h @@ -18,21 +18,24 @@ class ICombination : public QObject Q_OBJECT public: explicit ICombination(QObject* parent = nullptr); - explicit ICombination(double min, double max, double value, bool rangeEnabled, QObject* parent = nullptr); + explicit ICombination(double min, double max, double value, int decimals, bool rangeEnabled, QObject* parent = nullptr); virtual ~ICombination() = default; virtual QString name(); virtual QVector genColors(const QColor& color); void setRange(double min, double max); void setValue(double value); + void setDecimals(int decimals); double min() const; double max() const; double getValue() const; bool rangeEnabled() const; + int decimals() const; private: double m_min; double m_max; double m_value; + int m_decimals; bool m_rangeEnabled; }; @@ -119,7 +122,21 @@ class JumpableSlider : public QSlider { Q_OBJECT public: - using QSlider::QSlider; + explicit JumpableSlider(QWidget* parent); + explicit JumpableSlider(Qt::Orientation orientation, QWidget* parent = nullptr); + void setValue(double value); + void setMinimum(double value); + void setMaximum(double value); + void setRange(double minValue, double maxValue); + void setSingleStep(double value); + + double value() const; + double minimum() const; + double maximum() const; + double singleStep() const; + +signals: + void valueChanged(double value); protected: void mousePressEvent(QMouseEvent* e) override; @@ -128,6 +145,9 @@ class JumpableSlider : public QSlider private: void handleMouseEvent(QMouseEvent* e); + + class Private; + std::unique_ptr p; }; class GradientSlider : public JumpableSlider @@ -154,9 +174,10 @@ class ColorSpinHSlider : public QWidget void setValue(double value); void setRange(double min, double max); QVector> gradientColor() const; + double value() const; signals: - void valueChanged(int value); + void valueChanged(double value); private: class Private; From 58ffd458f33a0c3077fba5630c66f66152206e56 Mon Sep 17 00:00:00 2001 From: luzh Date: Wed, 27 Sep 2023 15:05:17 +0800 Subject: [PATCH 10/32] [fix] dispatch log from optix thread to main thread. --- ui/zenoedit/zenoapplication.cpp | 8 ++++++++ ui/zenoedit/zenoapplication.h | 3 +++ ui/zenoedit/zwidgetostream.cpp | 7 +++++++ ui/zenoedit/zwidgetostream.h | 14 ++++++++++++++ 4 files changed, 32 insertions(+) diff --git a/ui/zenoedit/zenoapplication.cpp b/ui/zenoedit/zenoapplication.cpp index c635dc103b..b6194f3538 100644 --- a/ui/zenoedit/zenoapplication.cpp +++ b/ui/zenoedit/zenoapplication.cpp @@ -24,6 +24,9 @@ ZenoApplication::ZenoApplication(int &argc, char **argv) m_errSteam.registerMsgHandler(); verifyVersion(); + //register optix log proxy + bool ret = connect(m_errSteam.optixLogProxy().get(), SIGNAL(optixlogReady(const QString&)), this, SLOT(onOptixlogReady(const QString&)), Qt::QueuedConnection); + QStringList locations; locations = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation); #ifdef Q_OS_WIN @@ -39,6 +42,11 @@ ZenoApplication::~ZenoApplication() { } +void ZenoApplication::onOptixlogReady(const QString& msg) +{ + qDebug() << msg; +} + QString ZenoApplication::readQss(const QString& qssPath) { bool ret = false; diff --git a/ui/zenoedit/zenoapplication.h b/ui/zenoedit/zenoapplication.h index 0217169ced..98e8e35364 100644 --- a/ui/zenoedit/zenoapplication.h +++ b/ui/zenoedit/zenoapplication.h @@ -31,6 +31,9 @@ class ZenoApplication : public QApplication #endif QStandardItemModel* logModel() const; +private slots: + void onOptixlogReady(const QString& msg); + private: QString readQss(const QString& qssPath); void initMetaTypes(); diff --git a/ui/zenoedit/zwidgetostream.cpp b/ui/zenoedit/zwidgetostream.cpp index 34201858b6..2da4557266 100644 --- a/ui/zenoedit/zwidgetostream.cpp +++ b/ui/zenoedit/zwidgetostream.cpp @@ -10,6 +10,7 @@ ZWidgetErrStream::ZWidgetErrStream(std::ostream &stream) , m_stream(stream) { m_old_buf = m_stream.rdbuf(); + m_spProxyOptixLog = std::make_shared(); m_stream.rdbuf(this); } @@ -18,6 +19,11 @@ ZWidgetErrStream::~ZWidgetErrStream() m_stream.rdbuf(m_old_buf); } +std::shared_ptr ZWidgetErrStream::optixLogProxy() const +{ + return m_spProxyOptixLog; +} + bool ZWidgetErrStream::isGUIThread() { //return true; @@ -27,6 +33,7 @@ bool ZWidgetErrStream::isGUIThread() std::streamsize ZWidgetErrStream::xsputn(const char* p, std::streamsize n) { if (!isGUIThread()) { + emit m_spProxyOptixLog->optixlogReady(QString::fromUtf8(p, n)); return _base::xsputn(p, n); } diff --git a/ui/zenoedit/zwidgetostream.h b/ui/zenoedit/zwidgetostream.h index 8c9f71a351..7d18421feb 100644 --- a/ui/zenoedit/zwidgetostream.h +++ b/ui/zenoedit/zwidgetostream.h @@ -6,6 +6,17 @@ #include #include +class ProxySendOptixLog : public QObject +{ + Q_OBJECT +public: + ProxySendOptixLog() {} + +signals: + void optixlogReady(const QString& msg); +}; + + class ZWidgetErrStream : public std::basic_streambuf { typedef std::basic_streambuf _base; @@ -14,6 +25,7 @@ class ZWidgetErrStream : public std::basic_streambuf virtual ~ZWidgetErrStream(); static void registerMsgHandler(); static void appendFormatMsg(std::string const& str); + std::shared_ptr optixLogProxy() const; protected: virtual std::streamsize xsputn(const char* p, std::streamsize n) override; @@ -29,6 +41,8 @@ class ZWidgetErrStream : public std::basic_streambuf std::ostream &m_stream; std::streambuf *m_old_buf; std::string m_linebuffer; + + std::shared_ptr m_spProxyOptixLog; }; #endif From d579cb74bae47b056fd8d8f78560b67caddffd8a Mon Sep 17 00:00:00 2001 From: miyanyan <1138989048@qq.com> Date: Thu, 28 Sep 2023 20:34:22 +0800 Subject: [PATCH 11/32] ColorEditor: add gamma correction --- ui/zenoui/ColorEditor/ColorEditor.cpp | 247 +++++++++++++++++++++----- ui/zenoui/ColorEditor/ColorEditor.h | 33 +++- 2 files changed, 227 insertions(+), 53 deletions(-) diff --git a/ui/zenoui/ColorEditor/ColorEditor.cpp b/ui/zenoui/ColorEditor/ColorEditor.cpp index 1fe1a0808d..76262ad9ed 100644 --- a/ui/zenoui/ColorEditor/ColorEditor.cpp +++ b/ui/zenoui/ColorEditor/ColorEditor.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -27,6 +28,28 @@ #include "zenoui/style/zenostyle.h" +//------------------------------------------- color correction ----------------------------------------------- +void ColorCorrection::correct(QColor& color) +{ + double r = color.redF(); + double g = color.greenF(); + double b = color.blueF(); + color.setRedF(std::pow(r, 1 / gamma)); + color.setGreenF(std::pow(g, 1 / gamma)); + color.setBlueF(std::pow(b, 1 / gamma)); +} + +void ColorCorrection::correct(QImage& image) +{ + for (int x = 0; x < image.width(); ++x) { + for (int y = 0; y < image.height(); ++y) { + QColor color = image.pixelColor(x, y); + correct(color); + image.setPixelColor(x, y, color); + } + } +} + //--------------------------------------------------------- color wheel ------------------------------------------------ class ColorWheel::Private { @@ -37,6 +60,7 @@ class ColorWheel::Private QColor selectedColor = QColor(Qt::white); QImage colorBuffer; colorcombo::ICombination* colorCombination = nullptr; + ColorCorrection* colorCorrection = nullptr; void renderWheel(const QRect& rect) { @@ -68,6 +92,11 @@ class ColorWheel::Private painter.drawEllipse(center, radius, radius); painter.setBrush(valueGradient); painter.drawEllipse(center, radius, radius); + + // color correction + if (colorCorrection) { + colorCorrection->correct(colorBuffer); + } } }; @@ -98,6 +127,13 @@ void ColorWheel::setSelectedColor(const QColor& color) update(); } +void ColorWheel::setColorCorrection(ColorCorrection* colorCorrection) +{ + p->colorCorrection = colorCorrection; + p->renderWheel(this->rect()); + update(); +} + QColor ColorWheel::getSelectedColor() const { return p->selectedColor; @@ -352,6 +388,16 @@ QString MixedSpinBox::textFromValue(double value) const return shortestNum.size() <= decimalNum.size() ? shortestNum : decimalNum; } +void MixedSpinBox::keyPressEvent(QKeyEvent* e) +{ + if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) { + clearFocus(); + } + else { + QDoubleSpinBox::keyPressEvent(e); + } +} + class JumpableSlider::Private { public: @@ -369,7 +415,7 @@ JumpableSlider::JumpableSlider(Qt::Orientation orientation, QWidget* parent) : QSlider(orientation, parent) , p(new Private) { - connect(this, &QSlider::valueChanged, this, [this](int value) {emit valueChanged(value * p->singleStep); }); + connect(this, &QSlider::valueChanged, this, [this](int value) { emit valueChanged(value * p->singleStep); }); } void JumpableSlider::setValue(double value) @@ -477,7 +523,34 @@ void JumpableSlider::handleMouseEvent(QMouseEvent* e) class GradientSlider::Private { public: - QVector> colors; + ColorCorrection* colorCorrection = nullptr; + QLinearGradient gradient; + QImage colorBuffer; + + Private() { gradient.setCoordinateMode(QGradient::StretchToDeviceMode); } + + void render(const QRect& rect, Qt::Orientation orientation, bool invertedAppearance) + { + QSize size = rect.size(); + colorBuffer = QImage(size, QImage::Format_ARGB32); + // update gradient final stop + double dir = invertedAppearance ? -1 : 1; + if (orientation == Qt::Horizontal) { + gradient.setFinalStop(dir, 0); + } + else { + gradient.setFinalStop(0, -dir); + } + + QPainter painter(&colorBuffer); + // draw gradient + painter.setBrush(gradient); + painter.drawRect(0, 0, colorBuffer.width(), colorBuffer.height()); + // color correction + if (colorCorrection) { + colorCorrection->correct(colorBuffer); + } + } }; GradientSlider::GradientSlider(QWidget* parent) @@ -491,52 +564,55 @@ void GradientSlider::setGradient(const QColor& startColor, const QColor& stopCol setGradient({{0, startColor}, {1, stopColor}}); } -void GradientSlider::setGradient(const QVector>& colors) +void GradientSlider::setGradient(const QGradientStops& colors) { if (colors.size() <= 1) { qWarning() << "ColorSlider::setGradient: colors size should >= 2"; return; } - p->colors = colors; + p->gradient.setStops(colors); + p->render(this->rect(), orientation(), invertedAppearance()); + update(); +} + +void GradientSlider::setColorCorrection(ColorCorrection* colorCorrection) +{ + p->colorCorrection = colorCorrection; + p->render(this->rect(), orientation(), invertedAppearance()); + update(); +} + +QGradientStops GradientSlider::gradientColor() const +{ + return p->gradient.stops(); +} + +void GradientSlider::paintEvent(QPaintEvent* e) +{ + QPainter painter(this); + // draw groove + painter.drawImage(0, 0, p->colorBuffer); - QString ori; - float x1, y1, x2, y2; + QPointF p1, p2; if (orientation() == Qt::Horizontal) { - ori = "horizontal"; - x1 = 0; - y1 = 0; - x2 = 1; - y2 = 0; + double pos = (value() - minimum()) / (maximum() - minimum()) * width(); + p1 = QPointF(pos, 0); + p2 = QPointF(pos, height()); } else { - ori = "vertical"; - x1 = 0; - y1 = 0; - x2 = 0; - y2 = 1; + double pos = height() - (value() - minimum()) / (maximum() - minimum()) * height(); + p1 = QPointF(0, pos); + p2 = QPointF(height(), pos); } - - QString gradientStyle; - for (const auto& color : colors) { - gradientStyle += QString(",stop:%1 %2").arg(color.first).arg(color.second.name()); - } - - auto style = QString("QSlider::groove:%1{background:qlineargradient(x1:%2,y1:%3,x2:%4,y2:%5 %6);}" - "QSlider::handle:%1{background:#5C5C5C;border:1px solid;width:6px}") - .arg(ori) - .arg(x1) - .arg(y1) - .arg(x2) - .arg(y2) - .arg(gradientStyle); - - setStyleSheet(style); + // draw handle + painter.setPen(QPen(QColor("#5C5C5C"), 6)); + painter.drawLine(p1, p2); } -QVector> GradientSlider::gradientColor() const +void GradientSlider::resizeEvent(QResizeEvent* e) { - return p->colors; + p->render(this->rect(), orientation(), invertedAppearance()); } class ColorSpinHSlider::Private @@ -575,11 +651,16 @@ void ColorSpinHSlider::setGradient(const QColor& startColor, const QColor& stopC p->slider->setGradient(startColor, stopColor); } -void ColorSpinHSlider::setGradient(const QVector>& colors) +void ColorSpinHSlider::setGradient(const QGradientStops& colors) { p->slider->setGradient(colors); } +void ColorSpinHSlider::setColorCorrection(ColorCorrection* colorCorrection) +{ + p->slider->setColorCorrection(colorCorrection); +} + void ColorSpinHSlider::setValue(double value) { p->spinbox->setValue(value); @@ -592,7 +673,7 @@ void ColorSpinHSlider::setRange(double min, double max) p->spinbox->setRange(min, max); } -QVector> ColorSpinHSlider::gradientColor() const +QGradientStops ColorSpinHSlider::gradientColor() const { return p->slider->gradientColor(); } @@ -608,6 +689,7 @@ class ColorButton::Private public: QPoint pressPos; QColor color; + ColorCorrection* colorCorrection = nullptr; int bolderTopWidth = 0; int bolderBottomWidth = 0; int bolderLeftWidth = 0; @@ -615,19 +697,24 @@ class ColorButton::Private void updateStyle(QPushButton* btn) { + QColor showColor = color; + if (colorCorrection) { + colorCorrection->correct(showColor); + } + int minWidth = ZenoStyle::dpiScaled(20); int minHeight = ZenoStyle::dpiScaled(20); auto style = QString("QPushButton{min-width:%1px;min-height:%2px;background-color:%3;" "border-top:%4px solid;border-bottom:%5px solid;" "border-left:%6px solid;border-right:%7px solid;}" "QPushButton:pressed{border: 1px solid #ffd700;}") - .arg(minWidth) - .arg(minHeight) - .arg(color.name()) - .arg(bolderTopWidth) - .arg(bolderBottomWidth) - .arg(bolderLeftWidth) - .arg(bolderRightWidth); + .arg(minWidth) + .arg(minHeight) + .arg(showColor.name()) + .arg(bolderTopWidth) + .arg(bolderBottomWidth) + .arg(bolderLeftWidth) + .arg(bolderRightWidth); btn->setStyleSheet(style); } }; @@ -646,6 +733,12 @@ void ColorButton::setColor(const QColor& color) p->updateStyle(this); } +void ColorButton::setColorCorrection(ColorCorrection* colorCorrection) +{ + p->colorCorrection = colorCorrection; + p->updateStyle(this); +} + void ColorButton::setBolderWidth(int top, int bottom, int left, int right) { p->bolderTopWidth = top; @@ -717,6 +810,7 @@ class ColorPalette::Private public: int columnCount = 0; QGridLayout* layout = nullptr; + ColorCorrection* colorCorrection = nullptr; QVector colors; Private(int column, QScrollArea* parent) @@ -774,6 +868,7 @@ void ColorPalette::addColor(const QColor& color) auto btn = new ColorButton(this); btn->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); btn->setToolTip(tr("Ctrl + click to remove color")); + btn->setColorCorrection(p->colorCorrection); connect(btn, &ColorButton::colorClicked, this, [this, index](const QColor& color) { if (QApplication::keyboardModifiers() == Qt::ControlModifier) { auto layoutIndex = p->getLayoutIndex(index); @@ -817,6 +912,15 @@ void ColorPalette::removeColor(int row, int column) p->updateBolder(index, p->colors.size()); } +void ColorPalette::setColorCorrection(ColorCorrection* colorCorrection) +{ + p->colorCorrection = colorCorrection; + for (int i = 0; i < p->layout->count(); ++i) { + auto btn = qobject_cast(p->layout->itemAt(i)->widget()); + btn->setColorCorrection(colorCorrection); + } +} + QColor ColorPalette::colorAt(int row, int column) const { if (column >= p->columnCount) { @@ -897,6 +1001,12 @@ void ColorPreview::setCurrentColor(const QColor& color) p->setCurrent(color); } +void ColorPreview::setColorCorrection(ColorCorrection* colorCorrection) +{ + p->pbtnCurrent->setColorCorrection(colorCorrection); + p->pbtnPrevious->setColorCorrection(colorCorrection); +} + QColor ColorPreview::currentColor() const { return p->pbtnCurrent->color(); @@ -916,6 +1026,7 @@ class ColorComboWidget::Private QPushButton* switchBtn = nullptr; JumpableSlider* factorSlider = nullptr; MixedSpinBox* factorSpinbox = nullptr; + ColorCorrection* colorCorrection = nullptr; Private(QWidget* parent) { @@ -986,6 +1097,15 @@ void ColorComboWidget::setColors(const QVector& colors) } } +void ColorComboWidget::setColorCorrection(ColorCorrection* colorCorrection) +{ + p->colorCorrection = colorCorrection; + for (int i = 0; i < p->hlayout->count(); ++i) { + auto btn = qobject_cast(p->hlayout->itemAt(i)->widget()); + btn->setColorCorrection(colorCorrection); + } +} + void ColorComboWidget::switchCombination() { if (p->combs.empty()) return; @@ -1013,6 +1133,7 @@ void ColorComboWidget::switchCombination() btn->setBolderWidth(1, 1, 1, bolderRightWidth); btn->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); btn->setAcceptDrops(false); // color can't be changed by drop + btn->setColorCorrection(p->colorCorrection); connect(btn, &ColorButton::colorClicked, this, &ColorComboWidget::colorClicked); p->hlayout->addWidget(btn); } @@ -1047,6 +1168,14 @@ void ColorLineEdit::setColor(const QColor& color) setText(color.name().toUpper()); } +void ColorLineEdit::keyPressEvent(QKeyEvent* e) +{ + if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) { + clearFocus(); + } + QLineEdit::keyPressEvent(e); +} + //------------------------------------------ color picker ---------------------------------- class ColorPicker::Private { @@ -1275,6 +1404,7 @@ class ColorEditor::Private { public: ColorWheel* wheel; + QCheckBox* showInSRGB; ColorLineEdit* colorText; ColorPreview* preview; ColorPicker* picker; @@ -1293,14 +1423,17 @@ class ColorEditor::Private QColor currentColor; QColor selectedColor; ColorEditorData colorData; + std::unique_ptr colorCorrection; Private(const QColor& color, QDialog* parent) { + colorCorrection = std::unique_ptr(new ColorCorrection); selectedColor = color; // left picker = new ColorPicker(parent); pickerBtn = new QPushButton(parent); wheel = new ColorWheel(parent); + showInSRGB = new QCheckBox(tr("show in srgb"), parent); colorText = new ColorLineEdit(parent); preview = new ColorPreview(color, parent); combo = new ColorComboWidget(parent); @@ -1327,10 +1460,11 @@ class ColorEditor::Private auto leftLayout = new QGridLayout(leftWidget); leftLayout->setContentsMargins(0, 0, 5, 0); leftLayout->setSpacing(0); - leftLayout->addWidget(wheel, 0, 0); - leftLayout->addWidget(colorText, 1, 0, Qt::AlignRight); - leftLayout->addWidget(previewGroup, 2, 0); - leftLayout->addWidget(comboGroup, 3, 0); + leftLayout->addWidget(wheel, 0, 0, 1, 10); + leftLayout->addWidget(showInSRGB, 1, 0, 1, 5, Qt::AlignLeft); + leftLayout->addWidget(colorText, 1, 5, 1, 5, Qt::AlignRight); + leftLayout->addWidget(previewGroup, 2, 0, 1, 10); + leftLayout->addWidget(comboGroup, 3, 0, 1, 10); // right palette = new ColorPalette(colorData.colCount, parent); @@ -1457,7 +1591,7 @@ class ColorEditor::Private void setGradientH(const QColor& color) { // hSlider is unique - static QVector> hColors(7); + static QGradientStops hColors(7); for (int i = 0; i < hColors.size(); ++i) { float f = 1.0 * i / (hColors.size() - 1); hColors[i] = {f, QColor::fromHsvF(f, color.hsvSaturationF(), color.valueF())}; @@ -1503,6 +1637,8 @@ ColorEditor::ColorEditor(const QColor& initial, QWidget* parent) p->wheel->setColorCombination(p->combo->currentCombination()); // current color setCurrentColor(initial); + // show in srgb + p->showInSRGB->setChecked(true); } void ColorEditor::setCurrentColor(const QColor& color) @@ -1560,6 +1696,20 @@ void ColorEditor::keyPressEvent(QKeyEvent* e) void ColorEditor::initSlots() { + // color correction + connect(p->showInSRGB, &QCheckBox::toggled, this, [this](bool checked) { + auto colorCorrection = checked ? p->colorCorrection.get() : nullptr; + p->wheel->setColorCorrection(colorCorrection); + p->palette->setColorCorrection(colorCorrection); + p->preview->setColorCorrection(colorCorrection); + p->combo->setColorCorrection(colorCorrection); + p->rSlider->setColorCorrection(colorCorrection); + p->gSlider->setColorCorrection(colorCorrection); + p->bSlider->setColorCorrection(colorCorrection); + p->hSlider->setColorCorrection(colorCorrection); + p->sSlider->setColorCorrection(colorCorrection); + p->vSlider->setColorCorrection(colorCorrection); + }); // picker connect(p->pickerBtn, &QPushButton::clicked, p->picker, &ColorPicker::startColorPicking); connect(p->picker, &ColorPicker::colorSelected, this, &ColorEditor::setCurrentColor); @@ -1614,4 +1764,3 @@ QColor ColorEditor::getColor(const QColor& initial, QWidget* parent, const QStri dlg.exec(); return dlg.selectedColor(); } - diff --git a/ui/zenoui/ColorEditor/ColorEditor.h b/ui/zenoui/ColorEditor/ColorEditor.h index 30dca6213a..eab22ce4c6 100644 --- a/ui/zenoui/ColorEditor/ColorEditor.h +++ b/ui/zenoui/ColorEditor/ColorEditor.h @@ -10,6 +10,14 @@ #include #include +//------------------------------------------- color correction ----------------------------------------------- +struct ColorCorrection +{ + float gamma = 2.2f; + void correct(QColor& color); + void correct(QImage& image); +}; + //------------------------------------------- color combination ---------------------------------------------- namespace colorcombo { @@ -89,6 +97,7 @@ class ColorWheel : public QWidget void setColorCombination(colorcombo::ICombination* combination); void setSelectedColor(const QColor& color); + void setColorCorrection(ColorCorrection* colorCorrection); QColor getSelectedColor() const; QColor getColor(int x, int y) const; @@ -116,6 +125,9 @@ class MixedSpinBox : public QDoubleSpinBox public: explicit MixedSpinBox(QWidget* parent = nullptr); virtual QString textFromValue(double value) const override; + +protected: + void keyPressEvent(QKeyEvent* e) override; }; class JumpableSlider : public QSlider @@ -156,8 +168,13 @@ class GradientSlider : public JumpableSlider public: explicit GradientSlider(QWidget* parent = nullptr); void setGradient(const QColor& startColor, const QColor& stopColor); - void setGradient(const QVector>& colors); - QVector> gradientColor() const; + void setGradient(const QGradientStops& colors); + void setColorCorrection(ColorCorrection* colorCorrection); + QGradientStops gradientColor() const; + +protected: + void paintEvent(QPaintEvent* e) override; + void resizeEvent(QResizeEvent* e) override; private: class Private; @@ -170,10 +187,11 @@ class ColorSpinHSlider : public QWidget public: explicit ColorSpinHSlider(const QString& name, QWidget* parent = nullptr); void setGradient(const QColor& startColor, const QColor& stopColor); - void setGradient(const QVector>& colors); + void setGradient(const QGradientStops& colors); + void setColorCorrection(ColorCorrection* colorCorrection); void setValue(double value); void setRange(double min, double max); - QVector> gradientColor() const; + QGradientStops gradientColor() const; double value() const; signals: @@ -191,6 +209,7 @@ class ColorButton : public QPushButton public: explicit ColorButton(QWidget* parent); void setColor(const QColor& color); + void setColorCorrection(ColorCorrection* colorCorrection); void setBolderWidth(int top, int bottom, int left, int right); QColor color() const; @@ -219,6 +238,7 @@ class ColorPalette : public QScrollArea void addColor(const QColor& color); void setColor(const QColor& color, int row, int column); void removeColor(int row, int column); + void setColorCorrection(ColorCorrection* colorCorrection); QColor colorAt(int row, int column) const; QVector colors() const; @@ -241,6 +261,7 @@ class ColorPreview : public QWidget public: explicit ColorPreview(const QColor& color, QWidget* parent = nullptr); void setCurrentColor(const QColor& color); + void setColorCorrection(ColorCorrection* colorCorrection); QColor currentColor() const; QColor previousColor() const; @@ -263,6 +284,7 @@ class ColorComboWidget : public QWidget void clearCombination(); void switchCombination(); void setColors(const QVector& colors); + void setColorCorrection(ColorCorrection* colorCorrection); colorcombo::ICombination* currentCombination() const; signals: @@ -284,6 +306,9 @@ class ColorLineEdit : public QLineEdit signals: void currentColorChanged(const QColor& color); + +protected: + void keyPressEvent(QKeyEvent* e) override; }; //------------------------------------------ color picker ---------------------------------- From d22e6af1283ccb698692a12881c0c63bcb813f3c Mon Sep 17 00:00:00 2001 From: miyanyan <1138989048@qq.com> Date: Fri, 6 Oct 2023 20:04:27 +0800 Subject: [PATCH 12/32] add MakeColor --- ui/zenomodel/src/uihelper.cpp | 3 +++ ui/zenoui/ColorEditor/ColorEditor.h | 2 +- zeno/src/nodes/color/MakeColor.cpp | 38 +++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 zeno/src/nodes/color/MakeColor.cpp diff --git a/ui/zenomodel/src/uihelper.cpp b/ui/zenomodel/src/uihelper.cpp index 0c465ca964..862d9afb43 100644 --- a/ui/zenomodel/src/uihelper.cpp +++ b/ui/zenomodel/src/uihelper.cpp @@ -609,6 +609,8 @@ PARAM_CONTROL UiHelper::getControlByType(const QString &type) return CONTROL_MULTILINE_STRING; } else if (type == "color") { //color is more general than heatmap. return CONTROL_COLOR; + } else if (type == "purecolor") { //purecolor is coloreditor, color is heatmap? ^^^^ + return CONTROL_PURE_COLOR; } else if (type == "curve") { return CONTROL_CURVE; } else if (type.startsWith("enum ")) { @@ -655,6 +657,7 @@ QString UiHelper::getTypeByControl(PARAM_CONTROL ctrl) case CONTROL_WRITEPATH: return "string"; case CONTROL_READPATH: return "string"; case CONTROL_COLOR: return "color"; //todo: is vec3? + case CONTROL_PURE_COLOR: return "purecolor"; case CONTROL_CURVE: return "curve"; case CONTROL_ENUM: return "string"; case CONTROL_HSLIDER: diff --git a/ui/zenoui/ColorEditor/ColorEditor.h b/ui/zenoui/ColorEditor/ColorEditor.h index eab22ce4c6..add4606900 100644 --- a/ui/zenoui/ColorEditor/ColorEditor.h +++ b/ui/zenoui/ColorEditor/ColorEditor.h @@ -207,7 +207,7 @@ class ColorButton : public QPushButton { Q_OBJECT public: - explicit ColorButton(QWidget* parent); + explicit ColorButton(QWidget* parent = nullptr); void setColor(const QColor& color); void setColorCorrection(ColorCorrection* colorCorrection); void setBolderWidth(int top, int bottom, int left, int right); diff --git a/zeno/src/nodes/color/MakeColor.cpp b/zeno/src/nodes/color/MakeColor.cpp new file mode 100644 index 0000000000..046c23cf72 --- /dev/null +++ b/zeno/src/nodes/color/MakeColor.cpp @@ -0,0 +1,38 @@ +#include + +#include +#include + +namespace zeno { + +struct MakeColor : zeno::INode { + virtual void apply() override { + auto colorstr = get_input2("color:"); // get param + vec3f color{ 1, 1, 1 }; + if (colorstr.size() == 7) { + colorstr = colorstr.substr(1); + std::stringstream ss(colorstr); + unsigned int hexColor; + ss >> std::hex >> hexColor; + float r = (hexColor >> 16 & 0xFF) / 255.0f; + float g = (hexColor >> 8 & 0xFF) / 255.0f; + float b = (hexColor & 0xFF) / 255.0f; + color = { r, g, b }; + } + set_output2("color", std::move(color)); + } +}; + +ZENO_DEFNODE(MakeColor)({ + { + }, + { + {"vec3f", "color"}, + }, + { + {"purecolor", "color", "#FFFFFF"}, + }, + {"color"}, +}); + +} // namespace zeno From d29a40e73c34a600e29712980375d2d091f0ec12 Mon Sep 17 00:00:00 2001 From: miyanyan <1138989048@qq.com> Date: Sat, 7 Oct 2023 20:28:00 +0800 Subject: [PATCH 13/32] DisplayWidget: use QColorDialog to edit color --- ui/zenoedit/viewport/displaywidget.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ui/zenoedit/viewport/displaywidget.cpp b/ui/zenoedit/viewport/displaywidget.cpp index 6d07ed0edf..30bc553b6a 100644 --- a/ui/zenoedit/viewport/displaywidget.cpp +++ b/ui/zenoedit/viewport/displaywidget.cpp @@ -11,7 +11,6 @@ #include "zenomainwindow.h" #include "camerakeyframe.h" #include -#include #include #include "timeline/ztimeline.h" #include "dialog/zrecorddlg.h" @@ -361,7 +360,7 @@ void DisplayWidget::onCommandDispatched(int actionType, bool bChecked) { auto [r, g, b] = m_glView->getSession()->get_background_color(); auto c = QColor::fromRgbF(r, g, b); - c = ColorEditor::getColor(c); + c = QColorDialog::getColor(c); if (c.isValid()) { m_glView->getSession()->set_background_color(c.redF(), c.greenF(), c.blueF()); updateFrame(); From d770c8a7e32b763c0465f2dafc4c622e777d16fd Mon Sep 17 00:00:00 2001 From: miyanyan <1138989048@qq.com> Date: Sat, 7 Oct 2023 20:32:25 +0800 Subject: [PATCH 14/32] add button text for color picker and color combination switch --- ui/zenoui/ColorEditor/ColorEditor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/zenoui/ColorEditor/ColorEditor.cpp b/ui/zenoui/ColorEditor/ColorEditor.cpp index 76262ad9ed..f72bdf059b 100644 --- a/ui/zenoui/ColorEditor/ColorEditor.cpp +++ b/ui/zenoui/ColorEditor/ColorEditor.cpp @@ -1032,7 +1032,7 @@ class ColorComboWidget::Private { factorSpinbox = new MixedSpinBox(parent); factorSlider = new JumpableSlider(Qt::Horizontal, parent); - switchBtn = new QPushButton(parent); + switchBtn = new QPushButton(tr("switch"), parent); switchBtn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); factorSpinbox->setButtonSymbols(QAbstractSpinBox::NoButtons); @@ -1431,7 +1431,7 @@ class ColorEditor::Private selectedColor = color; // left picker = new ColorPicker(parent); - pickerBtn = new QPushButton(parent); + pickerBtn = new QPushButton(tr("pick"), parent); wheel = new ColorWheel(parent); showInSRGB = new QCheckBox(tr("show in srgb"), parent); colorText = new ColorLineEdit(parent); From 79612be946c9075bb7f834b353f0d85bb6104f22 Mon Sep 17 00:00:00 2001 From: miyanyan <1138989048@qq.com> Date: Sun, 8 Oct 2023 20:39:40 +0800 Subject: [PATCH 15/32] add colorvec3f --- ui/zenoedit/dialog/zeditparamlayoutdlg.cpp | 1 + ui/zenoedit/nodesys/zenonode.cpp | 1 + ui/zenomodel/include/modeldata.h | 1 + ui/zenomodel/src/jsonhelper.cpp | 5 +++++ ui/zenomodel/src/uihelper.cpp | 16 ++++++++++++--- ui/zenoui/comctrl/gv/zitemfactory.cpp | 24 +++++++++++++++++++--- ui/zenoui/comctrl/zwidgetfactory.cpp | 23 ++++++++++++++++++--- zeno/src/nodes/color/MakeColor.cpp | 17 +++------------ 8 files changed, 65 insertions(+), 23 deletions(-) diff --git a/ui/zenoedit/dialog/zeditparamlayoutdlg.cpp b/ui/zenoedit/dialog/zeditparamlayoutdlg.cpp index 0f63a54df3..1555a4eae1 100644 --- a/ui/zenoedit/dialog/zeditparamlayoutdlg.cpp +++ b/ui/zenoedit/dialog/zeditparamlayoutdlg.cpp @@ -36,6 +36,7 @@ static CONTROL_ITEM_INFO controlList[] = { {"Integer Vector 2", CONTROL_VEC2_INT, "vec2i", ":/icons/parameter_control_integerVector2.svg"}, {"Color", CONTROL_COLOR, "color", ":/icons/parameter_control_color.svg"}, {"Pure Color", CONTROL_PURE_COLOR, "color", ":/icons/parameter_control_color.svg"}, + {"Color Vec3f", CONTROL_COLOR_VEC3F, "color", ":/icons/parameter_control_color.svg"}, {"Curve", CONTROL_CURVE, "curve", ":/icons/parameter_control_curve.svg"}, {"SpinBox", CONTROL_HSPINBOX, "int", ":/icons/parameter_control_spinbox.svg"}, {"DoubleSpinBox", CONTROL_HDOUBLESPINBOX, "float", ":/icons/parameter_control_spinbox.svg"}, diff --git a/ui/zenoedit/nodesys/zenonode.cpp b/ui/zenoedit/nodesys/zenonode.cpp index c9036c31e0..bc685808aa 100644 --- a/ui/zenoedit/nodesys/zenonode.cpp +++ b/ui/zenoedit/nodesys/zenonode.cpp @@ -921,6 +921,7 @@ ZGraphicsLayout* ZenoNode::addParam(const QModelIndex& viewparamIdx, ZenoSubGrap case CONTROL_WRITEPATH: case CONTROL_MULTILINE_STRING: case CONTROL_PURE_COLOR: + case CONTROL_COLOR_VEC3F: case CONTROL_CURVE: case CONTROL_HSLIDER: case CONTROL_HSPINBOX: diff --git a/ui/zenomodel/include/modeldata.h b/ui/zenomodel/include/modeldata.h index c42d6f9cf4..ae8a4923a9 100644 --- a/ui/zenomodel/include/modeldata.h +++ b/ui/zenomodel/include/modeldata.h @@ -17,6 +17,7 @@ enum PARAM_CONTROL { CONTROL_MULTILINE_STRING, CONTROL_COLOR, CONTROL_PURE_COLOR, + CONTROL_COLOR_VEC3F, CONTROL_CURVE, CONTROL_HSLIDER, CONTROL_HSPINBOX, diff --git a/ui/zenomodel/src/jsonhelper.cpp b/ui/zenomodel/src/jsonhelper.cpp index 1a8ea18a81..73dd2325a7 100644 --- a/ui/zenomodel/src/jsonhelper.cpp +++ b/ui/zenomodel/src/jsonhelper.cpp @@ -168,6 +168,11 @@ namespace JsonHelper int dim = -1; bool bFloat = false; UiHelper::parseVecType(type, dim, bFloat); + // ^^^ use regexp, but not include colorvec3f + // vvv so specify here + if (type == "colorvec3f") { + bFloat = true; + } for (int i = 0; i < vec.size(); i++) { if (!bFloat) diff --git a/ui/zenomodel/src/uihelper.cpp b/ui/zenomodel/src/uihelper.cpp index 862d9afb43..252fdf2225 100644 --- a/ui/zenomodel/src/uihelper.cpp +++ b/ui/zenomodel/src/uihelper.cpp @@ -159,6 +159,7 @@ bool UiHelper::validateVariant(const QVariant& var, const QString& type) { return (varType == QMetaType::User); } + case CONTROL_COLOR_VEC3F: case CONTROL_VEC2_FLOAT: case CONTROL_VEC2_INT: case CONTROL_VEC3_FLOAT: @@ -252,6 +253,7 @@ QVariant UiHelper::parseStringByType(const QString &defaultValue, const QString case CONTROL_COLOR: case CONTROL_ENUM: return defaultValue; + case CONTROL_COLOR_VEC3F: case CONTROL_VEC2_FLOAT: case CONTROL_VEC2_INT: case CONTROL_VEC3_FLOAT: @@ -387,7 +389,8 @@ QString UiHelper::getControlDesc(PARAM_CONTROL ctrl) case CONTROL_VEC3_INT: return "Integer Vector 3"; case CONTROL_VEC2_INT: return "Integer Vector 2"; case CONTROL_COLOR: return "Color"; - case CONTROL_PURE_COLOR: return "Pure Color"; + case CONTROL_PURE_COLOR: return "Pure Color"; + case CONTROL_COLOR_VEC3F: return "Color Vec3f"; case CONTROL_CURVE: return "Curve"; case CONTROL_HSPINBOX: return "SpinBox"; case CONTROL_HDOUBLESPINBOX: return "DoubleSpinBox"; @@ -466,6 +469,10 @@ PARAM_CONTROL UiHelper::getControlByDesc(const QString& descName) { return CONTROL_PURE_COLOR; } + else if (descName == "Color Vec3f") + { + return CONTROL_COLOR_VEC3F; + } else if (descName == "Curve") { return CONTROL_CURVE; @@ -554,7 +561,7 @@ QStringList UiHelper::getControlLists(const QString& type, bool isNodeUI) else if (type == "readpath") { ctrls = { CONTROL_READPATH }; } else if (type == "multiline_string") { ctrls = { CONTROL_STRING, CONTROL_MULTILINE_STRING }; } else if (type == "color") { //color is more general than heatmap. - ctrls = {CONTROL_COLOR, CONTROL_PURE_COLOR}; + ctrls = {CONTROL_COLOR, CONTROL_PURE_COLOR, CONTROL_COLOR_VEC3F}; } else if (type == "curve") { ctrls = { CONTROL_CURVE }; } else if (type.startsWith("enum ")) { @@ -609,8 +616,10 @@ PARAM_CONTROL UiHelper::getControlByType(const QString &type) return CONTROL_MULTILINE_STRING; } else if (type == "color") { //color is more general than heatmap. return CONTROL_COLOR; - } else if (type == "purecolor") { //purecolor is coloreditor, color is heatmap? ^^^^ + } else if (type == "purecolor") { return CONTROL_PURE_COLOR; + } else if (type == "colorvec3f") { //colorvec3f is for coloreditor, color is heatmap? ^^^^ + return CONTROL_COLOR_VEC3F; } else if (type == "curve") { return CONTROL_CURVE; } else if (type.startsWith("enum ")) { @@ -658,6 +667,7 @@ QString UiHelper::getTypeByControl(PARAM_CONTROL ctrl) case CONTROL_READPATH: return "string"; case CONTROL_COLOR: return "color"; //todo: is vec3? case CONTROL_PURE_COLOR: return "purecolor"; + case CONTROL_COLOR_VEC3F: return "colorvec3f"; // ^^^ color vec is here case CONTROL_CURVE: return "curve"; case CONTROL_ENUM: return "string"; case CONTROL_HSLIDER: diff --git a/ui/zenoui/comctrl/gv/zitemfactory.cpp b/ui/zenoui/comctrl/gv/zitemfactory.cpp index 2c716cc69c..bbc9a483b9 100644 --- a/ui/zenoui/comctrl/gv/zitemfactory.cpp +++ b/ui/zenoui/comctrl/gv/zitemfactory.cpp @@ -201,19 +201,37 @@ namespace zenoui pItemWidget = pEditBtn; break; } - case CONTROL_PURE_COLOR: { + case CONTROL_PURE_COLOR: + case CONTROL_COLOR_VEC3F: + { + QColor currentColor; + if (ctrl == CONTROL_PURE_COLOR) { + currentColor = value.value(); + } + else if (ctrl == CONTROL_COLOR_VEC3F) { + auto colorVec = value.value(); + currentColor = QColor::fromRgbF(colorVec[0], colorVec[1], colorVec[2]); + } + ZenoParamPushButton *pEditBtn = new ZenoParamPushButton("", -1, QSizePolicy::Expanding); pEditBtn->setData(GVKEY_SIZEHINT, ZenoStyle::dpiScaledSize(QSizeF(100, zenoui::g_ctrlHeight))); pEditBtn->setData(GVKEY_SIZEPOLICY, QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); pEditBtn->setData(GVKEY_TYPE, type); - pEditBtn->setProperty("color", value.value().name()); + pEditBtn->setProperty("color", currentColor.name()); QObject::connect(pEditBtn, &ZenoParamPushButton::clicked, [=]() { QColor color = ColorEditor::getColor(QColor(pEditBtn->property("color").toString())); if (color.isValid()) { pEditBtn->setProperty("color", color.name()); - cbSet.cbEditFinished(QVariant::fromValue(color)); + if (ctrl == CONTROL_PURE_COLOR) { + cbSet.cbEditFinished(QVariant::fromValue(color)); + } + else if (ctrl == CONTROL_COLOR_VEC3F) { + UI_VECTYPE colorVec(3); + color.getRgbF(&colorVec[0], &colorVec[1], &colorVec[2]); + cbSet.cbEditFinished(QVariant::fromValue(colorVec)); + } } }); pItemWidget = pEditBtn; diff --git a/ui/zenoui/comctrl/zwidgetfactory.cpp b/ui/zenoui/comctrl/zwidgetfactory.cpp index 15ba512968..3d1a0ccc62 100644 --- a/ui/zenoui/comctrl/zwidgetfactory.cpp +++ b/ui/zenoui/comctrl/zwidgetfactory.cpp @@ -109,16 +109,33 @@ namespace zenoui }); return pBtn; } - case CONTROL_PURE_COLOR: { + case CONTROL_PURE_COLOR: + case CONTROL_COLOR_VEC3F: + { + QColor currentColor; + if (ctrl == CONTROL_PURE_COLOR) { + currentColor = value.value(); + } + else if (ctrl == CONTROL_COLOR_VEC3F) { + auto colorVec = value.value(); + currentColor = QColor::fromRgbF(colorVec[0], colorVec[1], colorVec[2]); + } QPushButton *pBtn = new QPushButton; pBtn->setFixedSize(ZenoStyle::dpiScaled(100), ZenoStyle::dpiScaled(30)); - pBtn->setStyleSheet(QString("background-color:%1; border:0;").arg(value.value().name())); + pBtn->setStyleSheet(QString("background-color:%1; border:0;").arg(currentColor.name())); QObject::connect(pBtn, &QPushButton::clicked, [=]() { QColor color = ColorEditor::getColor(pBtn->palette().window().color()); if (color.isValid()) { pBtn->setStyleSheet(QString("background-color:%1; border:0;").arg(color.name())); - cbSet.cbEditFinished(QVariant::fromValue(color)); + if (ctrl == CONTROL_PURE_COLOR) { + cbSet.cbEditFinished(QVariant::fromValue(color)); + } + else if (ctrl == CONTROL_COLOR_VEC3F) { + UI_VECTYPE colorVec(3); + color.getRgbF(&colorVec[0], &colorVec[1], &colorVec[2]); + cbSet.cbEditFinished(QVariant::fromValue(colorVec)); + } } }); return pBtn; diff --git a/zeno/src/nodes/color/MakeColor.cpp b/zeno/src/nodes/color/MakeColor.cpp index 046c23cf72..9871d79139 100644 --- a/zeno/src/nodes/color/MakeColor.cpp +++ b/zeno/src/nodes/color/MakeColor.cpp @@ -7,30 +7,19 @@ namespace zeno { struct MakeColor : zeno::INode { virtual void apply() override { - auto colorstr = get_input2("color:"); // get param - vec3f color{ 1, 1, 1 }; - if (colorstr.size() == 7) { - colorstr = colorstr.substr(1); - std::stringstream ss(colorstr); - unsigned int hexColor; - ss >> std::hex >> hexColor; - float r = (hexColor >> 16 & 0xFF) / 255.0f; - float g = (hexColor >> 8 & 0xFF) / 255.0f; - float b = (hexColor & 0xFF) / 255.0f; - color = { r, g, b }; - } + auto color = get_input2("color"); set_output2("color", std::move(color)); } }; ZENO_DEFNODE(MakeColor)({ { + {"colorvec3f", "color", "1, 1, 1"}, }, { {"vec3f", "color"}, }, - { - {"purecolor", "color", "#FFFFFF"}, + { }, {"color"}, }); From ae67e1e65d1b3077a11fc74c557a568ad788d2b1 Mon Sep 17 00:00:00 2001 From: miyanyan <1138989048@qq.com> Date: Sun, 8 Oct 2023 21:24:52 +0800 Subject: [PATCH 16/32] sync color between ZenoParamPushButton and QPushButton when type is colorvec3f --- ui/zenoedit/panel/zenoproppanel.cpp | 12 +++++++++++- ui/zenoui/comctrl/gv/zenogvhelper.cpp | 9 +++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/ui/zenoedit/panel/zenoproppanel.cpp b/ui/zenoedit/panel/zenoproppanel.cpp index ecb064b5e8..781d63194d 100644 --- a/ui/zenoedit/panel/zenoproppanel.cpp +++ b/ui/zenoedit/panel/zenoproppanel.cpp @@ -636,8 +636,18 @@ void ZenoPropPanel::onViewParamDataChanged(const QModelIndex& topLeft, const QMo } else if (QPushButton *pBtn = qobject_cast(ctrl.pControl)) { - if (value.canConvert()) + // purecolor + if (value.canConvert()) { pBtn->setStyleSheet(QString("background-color:%1; border:0;").arg(value.value().name())); + } + // colorvec3f + else if (value.canConvert()) { + UI_VECTYPE vec = value.value(); + if (vec.size() == 3) { + auto color = QColor::fromRgbF(vec[0], vec[1], vec[2]); + pBtn->setStyleSheet(QString("background-color:%1; border:0;").arg(color.name())); + } + } } //... } diff --git a/ui/zenoui/comctrl/gv/zenogvhelper.cpp b/ui/zenoui/comctrl/gv/zenogvhelper.cpp index 0ca640d2ad..b65f62bc9c 100644 --- a/ui/zenoui/comctrl/gv/zenogvhelper.cpp +++ b/ui/zenoui/comctrl/gv/zenogvhelper.cpp @@ -90,9 +90,18 @@ void ZenoGvHelper::setValue(QGraphicsItem* item, PARAM_CONTROL ctrl, const QVari else if (ZenoParamPushButton* pBtn = qobject_cast(pItem)) { //nothing need to be done. + // purecolor if (value.canConvert()) { pBtn->setProperty("color", value.value().name()); } + // colorvec3f + else if (value.canConvert()) { + UI_VECTYPE vec = value.value(); + if (vec.size() == 3) { + auto color = QColor::fromRgbF(vec[0], vec[1], vec[2]); + pBtn->setProperty("color", color.name()); + } + } } else if (ZenoVecEditItem* pBtn = qobject_cast(pItem)) { From 982fab79fb119f593723bcd8ee9c1c76f8e5881b Mon Sep 17 00:00:00 2001 From: miyanyan <40262194+miyanyan@users.noreply.github.com> Date: Wed, 11 Oct 2023 17:57:54 +0800 Subject: [PATCH 17/32] use QColorDialog in zenoplayer --- ui/zenoplayer/zenoplayer.cpp | 3 +-- zeno/src/nodes/color/MakeColor.cpp | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/ui/zenoplayer/zenoplayer.cpp b/ui/zenoplayer/zenoplayer.cpp index 6c644c82f6..6e30db369a 100644 --- a/ui/zenoplayer/zenoplayer.cpp +++ b/ui/zenoplayer/zenoplayer.cpp @@ -18,7 +18,6 @@ #include #include #include -#include ZenoPlayer::ZenoPlayer(ZENO_PLAYER_INIT_PARAM param, QWidget *parent) @@ -110,7 +109,7 @@ QMenuBar *ZenoPlayer::initMenu() connect(pAction, &QAction::triggered, this, [=]() { auto [r, g, b] = Zenovis::GetInstance().getSession()->get_background_color(); auto c = QColor::fromRgbF(r, g, b); - c = ColorEditor::getColor(c); + c = QColorDialog::getColor(c); if (c.isValid()) { Zenovis::GetInstance().getSession()->set_background_color(c.redF(), c.greenF(), c.blueF()); ((ZenoPlayer *)zenoApp->getWindow("ZenoPlayer"))->updateFrame(); diff --git a/zeno/src/nodes/color/MakeColor.cpp b/zeno/src/nodes/color/MakeColor.cpp index 9871d79139..63c03a3399 100644 --- a/zeno/src/nodes/color/MakeColor.cpp +++ b/zeno/src/nodes/color/MakeColor.cpp @@ -1,5 +1,3 @@ -#include - #include #include From 8d10924fa27bba1e50f0427b9c239da7be87afc0 Mon Sep 17 00:00:00 2001 From: YingQ Date: Thu, 12 Oct 2023 15:45:47 +0800 Subject: [PATCH 18/32] autolevelimage fastblur --- projects/ImgCV/ImageComposite.cpp | 124 ++------ projects/ImgCV/ImageProcessing.cpp | 473 +++++++++++++---------------- 2 files changed, 229 insertions(+), 368 deletions(-) diff --git a/projects/ImgCV/ImageComposite.cpp b/projects/ImgCV/ImageComposite.cpp index 5667ee8feb..775c3ef889 100644 --- a/projects/ImgCV/ImageComposite.cpp +++ b/projects/ImgCV/ImageComposite.cpp @@ -1,17 +1,16 @@ -#include #include #include #include #include #include +#include +#include #include #include #include #include -#include -using namespace cv; namespace zeno { @@ -863,87 +862,8 @@ ZENDEFNODE(CompBlur, { {"image"} }, {}, - { "comp" }, -}); - -/*struct CompExtractChanel_gray: INode { - virtual void apply() override { - auto image = get_input("image"); - auto RGB = get_input2("RGB"); - auto R = get_input2("R"); - auto G = get_input2("G"); - auto B = get_input2("B"); - auto A = get_input2("A"); - auto &ud1 = image->userData(); - int w = ud1.get2("w"); - int h = ud1.get2("h"); - auto image2 = std::make_shared(); - image2->userData().set2("isImage", 1); - image2->userData().set2("w", w); - image2->userData().set2("h", h); - image2->verts.resize(image->size()); - - if(RGB){ - for (auto i = 0; i < image->verts.size(); i++) { - float avr = (image->verts[i][0] + image->verts[i][1] + image->verts[i][2])/3; - image2->verts[i] = {avr,avr,avr}; - } - } - if(R && !RGB) { - for (auto i = 0; i < image->verts.size(); i++) { - float R = image->verts[i][0]; - zeno::clamp(image2->verts[i][0] += R,0,1); - zeno::clamp(image2->verts[i][1] += R,0,1); - zeno::clamp(image2->verts[i][2] += R,0,1); - } - } - if(G && !RGB) { - for (auto i = 0; i < image->verts.size(); i++) { - float G = image->verts[i][1]; - zeno::clamp(image2->verts[i][0] += G,0,1); - zeno::clamp(image2->verts[i][1] += G,0,1); - zeno::clamp(image2->verts[i][2] += G,0,1); - } - } - if(B && !RGB) { - for (auto i = 0; i < image->verts.size(); i++) { - float B = image->verts[i][2]; - zeno::clamp(image2->verts[i][0] += B,0,1); - zeno::clamp(image2->verts[i][1] += B,0,1); - zeno::clamp(image2->verts[i][2] += B,0,1); - } - } - if(A) { - if (image->verts.has_attr("alpha")) { - auto &Alpha = image->verts.attr("alpha"); - image2->verts.add_attr("alpha"); - image2->verts.attr("alpha")=image->verts.attr("alpha"); - } - else{ - image2->verts.add_attr("alpha"); - for(int i = 0;i < w * h;i++){ - image2->verts.attr("alpha")[i] = 1.0; - } - } - } - set_output("image", image2); - } -}; -ZENDEFNODE(CompExtractChanel_gray, { - { - {"image"}, - {"bool", "RGB", "0"}, - {"bool", "R", "0"}, - {"bool", "G", "0"}, - {"bool", "B", "0"}, - {"bool", "A", "0"}, - }, - { - {"image"} - }, - {}, { "deprecated" }, -});*/ +}); struct ImageExtractChannel : INode { virtual void apply() override { @@ -1013,39 +933,40 @@ struct CompImport : INode { auto remapRange = get_input2("RemapRange"); auto remap = get_input2("Remap"); auto image = std::make_shared(); + auto attributesType = get_input2("AttributesType"); + image->resize(nx * ny); image->userData().set2("isImage", 1); image->userData().set2("w", nx); image->userData().set2("h", ny); - if (prim->verts.attr_is(attrName)) { - auto &attr = prim->verts.attr(attrName); - //calculate max and min attr value and remap it to 0-1 - float minresult = zeno::parallel_reduce_array(attr.size(), attr[0], [&] (size_t i) -> float { return attr[i]; }, - [&] (float i, float j) -> float { return zeno::min(i, j); }); - float maxresult = zeno::parallel_reduce_array(attr.size(), attr[0], [&] (size_t i) -> float { return attr[i]; }, - [&] (float i, float j) -> float { return zeno::max(i, j); }); + std::visit([&](auto attrty) { + using T = decltype(attrty); + if (!prim->verts.has_attr(attrName)) { + zeno::log_error("No such attribute '{}' in prim", attrName); + return; + } + auto &attr = prim->verts.attr(attrName); + auto minresult = zeno::parallel_reduce_array(attr.size(), attr[0], [&] (size_t i) -> T { return attr[i]; }, + [&] (T i, T j) -> T { return zeno::min(i, j); }); + auto maxresult = zeno::parallel_reduce_array(attr.size(), attr[0], [&] (size_t i) -> T { return attr[i]; }, + [&] (T i, T j) -> T { return zeno::max(i, j); }); + if (remap) { for (auto i = 0; i < nx * ny; i++) { - float v = attr[i]; + auto v = attr[i]; v = (v - minresult) / (maxresult - minresult);//remap to 0-1 v = v * (remapRange[1] - remapRange[0]) + remapRange[0]; - image->verts[i] = {v, v, v}; + image->verts[i] = vec3f(v); } } else { for (auto i = 0; i < nx * ny; i++) { - float v = attr[i]; - image->verts[i] = {v, v, v}; + const auto v = attr[i]; + image->verts[i] = vec3f(v); } } - } - else if (prim->verts.attr_is(attrName)) {//todo::add remap - auto &attr = prim->attr(attrName); - for (auto i = 0; i < nx * ny; i++) { - image->verts[i] = attr[i]; - } - } + }, enum_variant>(array_index({"float", "vec3f"}, attributesType))); set_output("image", image); } }; @@ -1056,6 +977,7 @@ ZENDEFNODE(CompImport, { {"string", "attrName", ""}, {"bool", "Remap", "0"}, {"vec2f", "RemapRange", "0, 1"}, + {"enum float vec3f", "AttributesType", "float"}, }, { {"image"}, diff --git a/projects/ImgCV/ImageProcessing.cpp b/projects/ImgCV/ImageProcessing.cpp index e52cf97a3d..f8e1a00e6a 100644 --- a/projects/ImgCV/ImageProcessing.cpp +++ b/projects/ImgCV/ImageProcessing.cpp @@ -386,93 +386,6 @@ ZENDEFNODE(ImageHSV2RGB, { { "image" }, }); -struct ImageEditRGB : INode { - virtual void apply() override { - auto image = get_input("image"); - auto RGB = get_input2("RGB"); - auto Gray = get_input2("Gray"); - auto Invert = get_input2("Invert"); - float R = get_input2("R"); - float G = get_input2("G"); - float B = get_input2("B"); - - if(RGB == "RGB") { - for (auto i = 0; i < image->verts.size(); i++) { - float R1 = R * image->verts[i][0]; - float G1 = G * image->verts[i][1]; - float B1 = B * image->verts[i][2]; - image->verts[i][0] = R1 ; - image->verts[i][1] = G1 ; - image->verts[i][2] = B1 ; - } - } - if(RGB == "R") { - for (auto i = 0; i < image->verts.size(); i++) { - float R1 = R * image->verts[i][0]; - float G1 = 0; - float B1 = 0; - image->verts[i][0] = R1 ; - image->verts[i][1] = G1 ; - image->verts[i][2] = B1 ; - } - } - if(RGB == "G") { - for (auto i = 0; i < image->verts.size(); i++) { - float R1 = 0; - float G1 = G * image->verts[i][1]; - float B1 = 0; - image->verts[i][0] = R1 ; - image->verts[i][1] = G1 ; - image->verts[i][2] = B1 ; - } - } - if(RGB == "B") { - for (auto i = 0; i < image->verts.size(); i++) { - float R1 = 0; - float G1 = 0; - float B1 = B * image->verts[i][2]; - image->verts[i][0] = R1; - image->verts[i][1] = G1; - image->verts[i][2] = B1; - } - } - if(Gray){ - for (auto i = 0; i < image->verts.size(); i++) { - float R = image->verts[i][0]; - float G = image->verts[i][1]; - float B = image->verts[i][2]; - float avr = (R + G + B)/3; - image->verts[i][0] = avr ; - image->verts[i][1] = avr ; - image->verts[i][2] = avr ; - } - } - if(Invert){ - for (auto i = 0; i < image->verts.size(); i++) { - image->verts[i] = 1 - image->verts[i]; - } - } - set_output("image", image); - } -}; - -ZENDEFNODE(ImageEditRGB, { - { - {"image"}, - {"enum RGB R G B", "RGB", "RGB"}, - {"float", "R", "1"}, - {"float", "G", "1"}, - {"float", "B", "1"}, - {"bool", "Gray", "0"}, - {"bool", "Invert", "0"}, - }, - { - {"image"} - }, - {}, - { "image" }, -}); - struct ImageEditHSV : INode { virtual void apply() override { auto image = get_input("image"); @@ -1058,123 +971,137 @@ void bilateralFilter(std::shared_ptr &image, std::shared_ptr("image"); - auto xsize = get_input2("xsize"); - auto ysize = get_input2("ysize"); - auto &ud = image->userData(); - int w = ud.get2("w"); - int h = ud.get2("h"); - - cv::Mat imagecvin(h, w, CV_32FC3); - cv::Mat imagecvout(h, w, CV_32FC3); - for (auto a = 0; a < image->verts.size(); a++){ - int i = a / w; - int j = a % w; - vec3f rgb = image->verts[i * w + j]; - imagecvin.at(i, j) = {rgb[0], rgb[1], rgb[2]}; - } - cv::blur(imagecvin,imagecvout,cv::Size(xsize,ysize),cv::Point(-1,-1)); - for (auto a = 0; a < image->verts.size(); a++){ - int i = a / w; - int j = a % w; - cv::Vec3f rgb = imagecvout.at(i, j); - image->verts[i * w + j] = {rgb[0], rgb[1], rgb[2]}; - } - set_output("image", image); - } -}; - -ZENDEFNODE(ImageBlur, { - { - {"image"}, - {"float", "xsize", "10"}, - {"float", "ysize", "10"}, - }, - { - {"image"} - }, - {}, - { "image" }, -}); -struct ImageGaussianBlur : INode { - virtual void apply() override { - auto image = get_input("image"); - auto kernelsize = get_input2("kernelsize"); - auto sigmaX = get_input2("sigmaX"); - auto &ud = image->userData(); - int w = ud.get2("w"); - int h = ud.get2("h"); - cv::Mat imagecvin(h, w, CV_32FC3); - cv::Mat imagecvout(h, w, CV_32FC3); - for (auto a = 0; a < image->verts.size(); a++){ - int i = a / w; - int j = a % w; - vec3f rgb = image->verts[i * w + j]; - imagecvin.at(i, j) = {rgb[0], rgb[1], rgb[2]}; - } - if(kernelsize%2==0){ - kernelsize += 1; - } - cv::GaussianBlur(imagecvin,imagecvout,cv::Size(kernelsize,kernelsize),sigmaX); - for (auto a = 0; a < image->verts.size(); a++){ - int i = a / w; - int j = a % w; - cv::Vec3f rgb = imagecvout.at(i, j); - image->verts[i * w + j] = {rgb[0], rgb[1], rgb[2]}; - } - set_output("image", image); - } -}; +/////////////////////////// +std::vector boxesForGauss(float sigma, int n) // standard deviation, number of boxes +{ + auto wIdeal = sqrt((12 * sigma*sigma / n) + 1); // Ideal averaging filter width + int wl = floor(wIdeal); + if (wl % 2 == 0) + wl--; + int wu = wl + 2; + + float mIdeal = (12 * sigma*sigma - n * wl*wl - 4 * n*wl - 3 * n) / (-4 * wl - 4); + int m = round(mIdeal); + // var sigmaActual = Math.sqrt( (m*wl*wl + (n-m)*wu*wu - n)/12 ); + + std::vector sizes(n); + for (auto i = 0; i < n; i++) + sizes[i] = i < m ? wl : wu; + return sizes; +} -ZENDEFNODE(ImageGaussianBlur, { - { - {"image"}, - {"int", "kernelsize", "5"}, - {"float", "sigmaX", "2.0"}, - }, - { - {"image"} - }, - {}, - { "image" }, -}); +void boxBlurH(std::vector& scl, std::vector& tcl, int w, int h, int r) { + float iarr = 1.f / (r + r + 1); + #pragma omp parallel for + for (int i = 0; i < h; i++) { + int ti = i * w, li = ti, ri = ti + r; + auto fv = scl[ti], lv = scl[ti + w - 1]; + auto val = (r + 1)*fv; + for (int j = 0; j < r; j++) val += scl[ti + j]; + for (int j = 0; j <= r; j++, ri++, ti++) { val += scl[ri] - fv; tcl[ti] = val*iarr; } + for (int j = r + 1; j < w - r; j++, ri++, ti++, li++) { val += scl[ri] - scl[li]; tcl[ti] = val*iarr; } + for (int j = w - r; j < w; j++, ti++, li++) { val += lv - scl[li]; tcl[ti] = val*iarr; }//border? + } +} +void boxBlurT(std::vector& scl, std::vector& tcl, int w, int h, int r) { + float iarr = 1.f / (r + r + 1);// radius range on either side of a pixel + the pixel itself + #pragma omp parallel for + for (auto i = 0; i < w; i++) { + int ti = i, li = ti, ri = ti + r * w; + auto fv = scl[ti], lv = scl[ti + w * (h - 1)]; + auto val = (r + 1)*fv; + for (int j = 0; j < r; j++) val += scl[ti + j * w]; + for (int j = 0; j <= r; j++, ri+=w, ti+=w) { val += scl[ri] - fv; tcl[ti] = val*iarr; } + for (int j = r + 1; j < h - r; j++, ri+=w, ti+=w, li+=w) { val += scl[ri] - scl[li]; tcl[ti] = val*iarr; } + for (int j = h - r; j < h; j++, ti+=w, li+=w) { val += lv - scl[li]; tcl[ti] = val*iarr; } + } +} +void boxBlur(std::vector& scl, std::vector& tcl, int w, int h, int r) { + std::swap(scl, tcl); + boxBlurH(tcl, scl, w, h, r); + boxBlurT(scl, tcl, w, h, r); +} +void gaussBlur(std::vector scl, std::vector& tcl, int w, int h, float sigma, int blurNumber) { + auto bxs = boxesForGauss(sigma, blurNumber); + boxBlur(scl, tcl, w, h, (bxs[0] - 1) / 2); + boxBlur(tcl, scl, w, h, (bxs[1] - 1) / 2); + boxBlur(scl, tcl, w, h, (bxs[2] - 1) / 2); + /*for (auto i = 0; i < blurNumber; i++) { + boxBlur(scl, tcl, w, h, (bxs[i] - 1) / 2); + }*/ +} -struct ImageMedianBlur : INode { +struct ImageBlur : INode { virtual void apply() override { auto image = get_input("image"); auto kernelSize = get_input2("kernelSize"); + auto type = get_input2("type"); + auto fastgaussian = get_input2("Fast Blur(Gaussian)"); + auto sigmaX = get_input2("GaussianSigma"); + auto sigmaColor = get_input2("BilateralSigma")[0]; + auto sigmaSpace = get_input2("BilateralSigma")[1]; auto &ud = image->userData(); int w = ud.get2("w"); int h = ud.get2("h"); - cv::Mat imagecvin(h, w, CV_32FC3); - cv::Mat imagecvout(h, w, CV_32FC3); - for (auto a = 0; a < image->verts.size(); a++){ - int i = a / w; - int j = a % w; - vec3f rgb = image->verts[i * w + j]; - imagecvin.at(i, j) = {rgb[0], rgb[1], rgb[2]}; - } - if(kernelSize%2==0){ - kernelSize += 1; - } - cv::medianBlur(imagecvin,imagecvout,kernelSize); - for (auto a = 0; a < image->verts.size(); a++){ - int i = a / w; - int j = a % w; - cv::Vec3f rgb = imagecvout.at(i, j); - image->verts[i * w + j] = {rgb[0], rgb[1], rgb[2]}; + auto img_out = std::make_shared(); + img_out->resize(w * h); + img_out->userData().set2("w", w); + img_out->userData().set2("h", h); + img_out->userData().set2("isImage", 1); + + if(type == "Gaussian" && fastgaussian){ + gaussBlur(image->verts, img_out->verts, w, h, sigmaX, 3); + } + else{//CV BLUR + cv::Mat imagecvin(h, w, CV_32FC3); + cv::Mat imagecvout(h, w, CV_32FC3); + for (auto a = 0; a < image->verts.size(); a++){ + int i = a / w; + int j = a % w; + vec3f rgb = image->verts[i * w + j]; + imagecvin.at(i, j) = {rgb[0], rgb[1], rgb[2]}; + } + if(kernelSize%2==0){ + kernelSize += 1; + } + if(type == "Box"){ + cv::boxFilter(imagecvin,imagecvout,-1,cv::Size(kernelSize,kernelSize)); + } + else if(type == "Gaussian"){ + cv::GaussianBlur(imagecvin,imagecvout,cv::Size(kernelSize,kernelSize),sigmaX); + } + else if(type == "Median"){ + cv::medianBlur(imagecvin,imagecvout,kernelSize); + } + else if(type == "Bilateral"){ + cv::bilateralFilter(imagecvin,imagecvout, kernelSize, sigmaColor, sigmaSpace); + } + else if(type == "Stack"){ + cv::stackBlur(imagecvin,imagecvout,cv::Size(kernelSize, kernelSize)); + } + else{ + zeno::log_error("ImageBlur: Blur type does not exist"); + } + for (auto a = 0; a < image->verts.size(); a++){ + int i = a / w; + int j = a % w; + cv::Vec3f rgb = imagecvout.at(i, j); + img_out->verts[i * w + j] = {rgb[0], rgb[1], rgb[2]}; + } } - set_output("image", image); + set_output("image", img_out); } }; -ZENDEFNODE(ImageMedianBlur, { +ZENDEFNODE(ImageBlur, { { {"image"}, {"int", "kernelSize", "5"}, + {"enum Gaussian Box Median Bilateral Stack", "type", "Gaussian"}, + {"float", "GaussianSigma", "1"},//fast gaussian only effect by sigma + {"vec2f", "BilateralSigma", "50,50"},//等参数分开显示再移开 + {"bool", "Fast Blur(Gaussian)", "1"}, }, { {"image"} @@ -1183,49 +1110,6 @@ ZENDEFNODE(ImageMedianBlur, { { "image" }, }); -struct ImageBilateralBlur : INode { - virtual void apply() override { - auto image = get_input("image"); - auto diameter = get_input2("diameter"); - auto sigmaColor = get_input2("sigmaColor"); - auto sigmaSpace = get_input2("sigmaSpace"); - auto &ud = image->userData(); - int w = ud.get2("w"); - int h = ud.get2("h"); - cv::Mat imagecvin(h, w, CV_32FC3); - cv::Mat imagecvout(h, w, CV_32FC3); - for (auto a = 0; a < image->verts.size(); a++){ - int i = a / w; - int j = a % w; - vec3f rgb = image->verts[i * w + j]; - imagecvin.at(i, j) = {rgb[0], rgb[1], rgb[2]}; - } - cv::bilateralFilter(imagecvin,imagecvout, diameter, sigmaColor, sigmaSpace); - for (auto a = 0; a < image->verts.size(); a++){ - int i = a / w; - int j = a % w; - cv::Vec3f rgb = imagecvout.at(i, j); - image->verts[i * w + j] = {rgb[0], rgb[1], rgb[2]}; - } - set_output("image", image); - } -}; - -ZENDEFNODE(ImageBilateralBlur, { - { - {"image"}, - {"int", "diameter", "10"}, - {"float", "sigmaColor", "75"}, - {"float", "sigmaSpace", "75"}, - }, - { - {"image"} - }, - {}, - { "image" }, -}); - - struct ImageEditContrast : INode { virtual void apply() override { auto image = get_input("image"); @@ -1252,35 +1136,6 @@ ZENDEFNODE(ImageEditContrast, { { "image" }, }); -struct ImageEditSaturation : INode { - virtual void apply() override { - auto image = get_input("image"); - float Si = get_input2("Saturation"); - float H = 0, S = 0, V = 0; - for (auto i = 0; i < image->verts.size(); i++) { - float R = image->verts[i][0]; - float G = image->verts[i][1]; - float B = image->verts[i][2]; - zeno::RGBtoHSV(R, G, B, H, S, V); - S = S + (S - 0.5)*(Si-1); - zeno::HSVtoRGB(H, S, V, R, G, B); - image->verts[i][0] = R; - image->verts[i][1] = G; - image->verts[i][2] = B; - } - set_output("image", image); - } -}; - -ZENDEFNODE(ImageEditSaturation, { - { - {"image"}, - {"float", "Saturation", "1"}, - }, - {"image"}, - {}, - { "image" }, -}); struct ImageEditInvert : INode{ virtual void apply() override { @@ -1302,7 +1157,7 @@ ZENDEFNODE(ImageEditInvert, { "image", }, {}, - {"image"}, + {"deprecated"}, }); @@ -2238,6 +2093,7 @@ struct ImageLevels: INode { auto gamma = get_input2("gamma");//range 0.01 - 9.99 auto channel = get_input2("channel"); auto clamp = get_input2("Clamp Output"); + auto autolevel = get_input2("Auto Level"); UserData &ud = image->userData(); int w = ud.get2("w"); int h = ud.get2("h"); @@ -2246,8 +2102,91 @@ struct ImageLevels: INode { float inputMin = inputLevels[0]; float outputMin = outputLevels[0]; float gammaCorrection = 1.0f / gamma; + float MinBlue, MaxBlue, MinRed, MaxRed, MinGreen, MaxGreen = 0.0f; + //calculate histogram + if (autolevel) { + std::vector histogramred(256, 0); + std::vector histogramgreen(256, 0); + std::vector histogramblue(256, 0); + for (int i = 0; i < w * h; i++) { + histogramred[zeno::clamp(int(image->verts[i][0] * 255.99), 0, 255)]++; + histogramgreen[zeno::clamp(int(image->verts[i][1] * 255.99), 0, 255)]++; + histogramblue[zeno::clamp(int(image->verts[i][2] * 255.99), 0, 255)]++; + } + int total = w * h; + int sum = 0; + //Red channel + for (int i = 0; i < 256; i++) { + sum += histogramred[i]; + if (sum >= total * 0.001f) { + MinRed = i; + break; + } + } + sum = 0; + for (int i = 255; i >= 0; i--) { + sum += histogramred[i]; + if (sum >= total * 0.001f) { + MaxRed = i; + break; + } + } + //Green channel + sum = 0; + for (int i = 0; i < 256; i++) { + sum += histogramgreen[i]; + if (sum >= total * 0.001f) { + MinGreen = i; + break; + } + } + sum = 0; + for (int i = 255; i >= 0; i--) { + sum += histogramgreen[i]; + if (sum >= total * 0.001f) { + MaxGreen = i; + break; + } + } + //Blue channel + sum = 0; + for (int i = 0; i < 256; i++) { + sum += histogramblue[i]; + if (sum >= total * 0.001f) { + MinBlue = i; + break; + } + } + sum = 0; + for (int i = 255; i >= 0; i--) { + sum += histogramblue[i]; + if (sum >= total * 0.001f) { + MaxBlue = i; + break; + } + } + //inputMin = std::min(std::min(MinRed, MinGreen), MinBlue) / 255.0f;//auto contrast? 对于灰度图像,由于只有一个通道,自动对比度和自动色阶实际上算法相同? + //inputRange = (std::max(std::max(MaxRed, MaxGreen), MaxBlue) - inputMin) / 255.0f; + /*// 根据计算的值影响level参数 + inputMin = min / 255.0f; + inputRange = (max - min) / 255.0f;*/ + } + MinRed /= 255.0f, MinGreen /= 255.0f, MinBlue /= 255.0f, MaxRed /= 255.0f, MaxGreen /= 255.0f, MaxBlue /= 255.0f; - if (channel == "All") { + if(autolevel){ +#pragma omp parallel for + for (int i = 0; i < w * h; i++) { + vec3f &v = image->verts[i]; + v[0] = (v[0] < MinRed) ? MinRed : v[0]; + v[1] = (v[1] < MinGreen) ? MinGreen : v[1]; + v[2] = (v[2] < MinBlue) ? MinBlue : v[2]; + v[0] = (v[0] - MinRed) / (MaxRed - MinRed); + v[1] = (v[1] - MinGreen) / (MaxGreen - MinGreen); + v[2] = (v[2] - MinBlue) / (MaxBlue - MinBlue); + v = clamp ? zeno::clamp((v * outputRange + outputMin), 0, 1) : (v * outputRange + outputMin); + } + } + else if (channel == "All") { #pragma omp parallel for for (int i = 0; i < w * h; i++) { vec3f &v = image->verts[i]; @@ -2269,10 +2208,9 @@ struct ImageLevels: INode { } } } - else if (channel == "R") { #pragma omp parallel for - for (int i = 0; i < w; i++) { + for (int i = 0; i < w * h; i++) { float &v = image->verts[i][0]; if (v < inputMin) v = inputMin; v = (v - inputMin) / inputRange; @@ -2283,7 +2221,7 @@ struct ImageLevels: INode { else if (channel == "G") { #pragma omp parallel for - for (int i = 0; i < w; i++) { + for (int i = 0; i < w * h; i++) { float &v = image->verts[i][1]; if (v < inputMin) v = inputMin; v = (v - inputMin) / inputRange; @@ -2294,7 +2232,7 @@ struct ImageLevels: INode { else if (channel == "B") { #pragma omp parallel for - for (int i = 0; i < w; i++) { + for (int i = 0; i < w * h; i++) { float &v = image->verts[i][2]; if (v < inputMin) v = inputMin; v = (v - inputMin) / inputRange; @@ -2318,6 +2256,7 @@ struct ImageLevels: INode { zeno::log_error("no alpha channel"); } } + set_output("image", image); } }; @@ -2327,8 +2266,8 @@ ZENDEFNODE(ImageLevels, { {"vec2f", "Input Levels", "0, 1"}, {"float", "gamma", "1"}, {"vec2f", "Output Levels", "0, 1"}, - //{"bool", "auto level", "false"}, //auto level {"enum All R G B A", "channel", "RGB"}, + {"bool", "Auto Level", "0"}, {"bool", "Clamp Output", "1"}, }, { From d2a109e2b9008fc8fd329db572ccb949807257c0 Mon Sep 17 00:00:00 2001 From: YingQ Date: Thu, 12 Oct 2023 16:48:08 +0800 Subject: [PATCH 19/32] Update ImageProcessing.cpp --- projects/ImgCV/ImageProcessing.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/projects/ImgCV/ImageProcessing.cpp b/projects/ImgCV/ImageProcessing.cpp index f8e1a00e6a..070496175f 100644 --- a/projects/ImgCV/ImageProcessing.cpp +++ b/projects/ImgCV/ImageProcessing.cpp @@ -1072,7 +1072,7 @@ struct ImageBlur : INode { cv::GaussianBlur(imagecvin,imagecvout,cv::Size(kernelSize,kernelSize),sigmaX); } else if(type == "Median"){ - cv::medianBlur(imagecvin,imagecvout,kernelSize); + cv::medianBlur(imagecvin,imagecvout,kernelSize);//kernel size can only be 3/5 when use CV_32FC3 } else if(type == "Bilateral"){ cv::bilateralFilter(imagecvin,imagecvout, kernelSize, sigmaColor, sigmaSpace); @@ -1099,8 +1099,8 @@ ZENDEFNODE(ImageBlur, { {"image"}, {"int", "kernelSize", "5"}, {"enum Gaussian Box Median Bilateral Stack", "type", "Gaussian"}, - {"float", "GaussianSigma", "1"},//fast gaussian only effect by sigma - {"vec2f", "BilateralSigma", "50,50"},//等参数分开显示再移开 + {"float", "GaussianSigma", "1"},//fast gaussian only effect by sigma 等参数分开显示再移开 + {"vec2f", "BilateralSigma", "50,50"}, {"bool", "Fast Blur(Gaussian)", "1"}, }, { @@ -1160,7 +1160,6 @@ ZENDEFNODE(ImageEditInvert, { {"deprecated"}, }); - /* 将灰度图像转换为法线贴图 */ struct ImageToNormalMap : INode { virtual void apply() override { From 13b70b7b3c84cb5fe563ee91b6fc46bf5b0d26f2 Mon Sep 17 00:00:00 2001 From: miyanyan <1138989048@qq.com> Date: Fri, 13 Oct 2023 12:46:42 +0800 Subject: [PATCH 20/32] ColorPicker: support multi screen --- ui/zenoui/ColorEditor/ColorEditor.cpp | 31 ++++++++++++++++++--------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/ui/zenoui/ColorEditor/ColorEditor.cpp b/ui/zenoui/ColorEditor/ColorEditor.cpp index f72bdf059b..ac69f1b18e 100644 --- a/ui/zenoui/ColorEditor/ColorEditor.cpp +++ b/ui/zenoui/ColorEditor/ColorEditor.cpp @@ -1199,7 +1199,12 @@ class ColorPicker::Private return QRect(desktop->pos(), desktop->size()); } - QColor getColorAt(QPoint p) const { return fullScreenImg.pixelColor(p); } + QColor getColorAt(QPoint p) const + { + // p need in local coordinate + // e.g. if use QCursor::pos(), it's global pos, need mapFromGlobal(QCursor::pos()) + return fullScreenImg.pixelColor(p); + } QImage getScaledImage(QPoint p) const { @@ -1240,11 +1245,12 @@ QColor ColorPicker::grabScreenColor(QPoint p) const void ColorPicker::startColorPicking() { - p->cursorPos = QCursor::pos(); p->grabFullScreen(); - setGeometry(p->getScreenRect()); - showFullScreen(); + showFullScreen(); // show fullscreen only covers one screen + QRect fullRect = p->getScreenRect(); + setGeometry(fullRect); // force reszie setFocus(); + p->cursorPos = this->mapFromGlobal(QCursor::pos()); } void ColorPicker::releaseColorPicking() @@ -1257,21 +1263,26 @@ void ColorPicker::paintEvent(QPaintEvent* e) QPainter painter(this); // background painter.drawImage(0, 0, p->fullScreenImg); + + // get screen info + QPoint globalPos = this->mapToGlobal(p->cursorPos); + auto screen = p->getScreenAt(globalPos); + auto rect = screen->geometry(); + QPoint bottomRight = this->mapFromGlobal(rect.bottomRight()); + // scaled img auto img = p->getScaledImage(p->cursorPos); auto currentColor = p->getColorAt(p->cursorPos); - auto screen = p->getScreenAt(p->cursorPos); - auto rect = screen->geometry(); // calculate img pos int dx = 20, dy = 20; int x, y; - if (rect.right() - p->cursorPos.x() < img.width() + dx) { + if (bottomRight.x() - p->cursorPos.x() < img.width() + dx) { x = p->cursorPos.x() - img.width() - dx; } else { x = p->cursorPos.x() + dx; } - if (rect.height() - p->cursorPos.y() < img.height() + dy) { + if (bottomRight.y() - p->cursorPos.y() < img.height() + dy) { y = p->cursorPos.y() - img.height() + dy; } else { @@ -1306,7 +1317,7 @@ void ColorPicker::mouseMoveEvent(QMouseEvent* e) void ColorPicker::mouseReleaseEvent(QMouseEvent* e) { if (e->button() == Qt::LeftButton) { - emit colorSelected(p->getColorAt(QCursor::pos())); + emit colorSelected(p->getColorAt(this->mapFromGlobal(QCursor::pos()))); releaseColorPicking(); } else if (e->button() == Qt::RightButton) { @@ -1322,7 +1333,7 @@ void ColorPicker::keyPressEvent(QKeyEvent* e) break; case Qt::Key_Return: case Qt::Key_Enter: - emit colorSelected(p->getColorAt(QCursor::pos())); + emit colorSelected(p->getColorAt(this->mapFromGlobal(QCursor::pos()))); releaseColorPicking(); break; case Qt::Key_Up: From 944474acd3861be40152243567fae6a36d36166b Mon Sep 17 00:00:00 2001 From: luzh Date: Fri, 13 Oct 2023 14:58:50 +0800 Subject: [PATCH 21/32] [fix] log classify and font style. --- ui/zenoedit/res/stylesheet/qlineedit.qss | 2 +- ui/zenoedit/zenoapplication.cpp | 26 +++++++++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/ui/zenoedit/res/stylesheet/qlineedit.qss b/ui/zenoedit/res/stylesheet/qlineedit.qss index 974ccaacf2..cd12cbf976 100644 --- a/ui/zenoedit/res/stylesheet/qlineedit.qss +++ b/ui/zenoedit/res/stylesheet/qlineedit.qss @@ -142,7 +142,7 @@ QPlainTextEdit[cssClass="logpanel"] color: #A3B1C0; background-color: rgb(24,29,33); border: 1px solid rgb(18,20,22); - font-weight: 500; + font-family:'Arial' 9pt; } QLineEdit[cssClass = "blackboard_title"] diff --git a/ui/zenoedit/zenoapplication.cpp b/ui/zenoedit/zenoapplication.cpp index b6194f3538..692c6d9fc6 100644 --- a/ui/zenoedit/zenoapplication.cpp +++ b/ui/zenoedit/zenoapplication.cpp @@ -44,7 +44,31 @@ ZenoApplication::~ZenoApplication() void ZenoApplication::onOptixlogReady(const QString& msg) { - qDebug() << msg; + if (msg.startsWith("[")) + { + QMessageLogger logger("zeno", 0, 0); + QChar tip = msg.at(1); + + auto& mgr = GraphsManagment::instance(); + if (tip == 'T') { + mgr.appendLog(QtDebugMsg, "zeno", 0, msg); + } + else if (tip == 'D') { + mgr.appendLog(QtDebugMsg, "zeno", 0, msg); + } + else if (tip == 'I') { + mgr.appendLog(QtInfoMsg, "zeno", 0, msg); + } + else if (tip == 'C') { + mgr.appendLog(QtCriticalMsg, "zeno", 0, msg); + } + else if (tip == 'W') { + mgr.appendLog(QtWarningMsg, "zeno", 0, msg); + } + else if (tip == 'E') { + mgr.appendLog(QtFatalMsg, "zeno", 0, msg); + } + } } QString ZenoApplication::readQss(const QString& qssPath) From af819d7466878bd7662342e3ad467ac7d0eec6d7 Mon Sep 17 00:00:00 2001 From: zhouhang95 <765229842@qq.com> Date: Fri, 13 Oct 2023 17:46:55 +0800 Subject: [PATCH 22/32] write 32 exr & ImageColor2 --- projects/ImgCV/ImageProcessing.cpp | 41 ++++++++++++++++++++++ zeno/src/nodes/prim/UVProjectFromPlane.cpp | 2 +- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/projects/ImgCV/ImageProcessing.cpp b/projects/ImgCV/ImageProcessing.cpp index 070496175f..55c96c7357 100644 --- a/projects/ImgCV/ImageProcessing.cpp +++ b/projects/ImgCV/ImageProcessing.cpp @@ -1570,6 +1570,47 @@ ZENDEFNODE(ImageColor, { {"image"}, }, {}, + { "deprecated" }, +}); +struct ImageColor2 : INode { + virtual void apply() override { + auto image = std::make_shared(); + auto color = get_input2("Color"); + auto alpha = get_input2("Alpha"); + auto size = get_input2("Size"); + auto balpha = get_input2("alpha"); + auto vertsize = size[0] * size[1]; + image->verts.resize(vertsize); + image->userData().set2("isImage", 1); + image->userData().set2("w", size[0]); + image->userData().set2("h", size[1]); + if(balpha){ + auto &alphaAttr = image->verts.add_attr("alpha"); + for (int i = 0; i < vertsize ; i++) { + image->verts[i] = {zeno::clamp(color[0], 0.0f, 1.0f), zeno::clamp(color[1], 0.0f, 1.0f), zeno::clamp(color[2], 0.0f, 1.0f)}; + alphaAttr[i] = zeno::clamp(alpha, 0.0f, 1.0f); + } + } + else{ + for (int i = 0; i < vertsize ; i++) { + image->verts[i] = {zeno::clamp(color[0], 0.0f, 1.0f), zeno::clamp(color[1], 0.0f, 1.0f), zeno::clamp(color[2], 0.0f, 1.0f)}; + } + } + set_output("image", image); + } +}; + +ZENDEFNODE(ImageColor2, { + { + {"vec3f", "Color", "1,1,1"}, + {"float", "Alpha", "1"}, + {"vec2i", "Size", "1024,1024"}, + {"bool", "alpha", "1"}, + }, + { + {"image"}, + }, + {}, { "image" }, }); diff --git a/zeno/src/nodes/prim/UVProjectFromPlane.cpp b/zeno/src/nodes/prim/UVProjectFromPlane.cpp index 3ccf4e1a99..37d5424bcd 100644 --- a/zeno/src/nodes/prim/UVProjectFromPlane.cpp +++ b/zeno/src/nodes/prim/UVProjectFromPlane.cpp @@ -585,7 +585,7 @@ struct WriteImageFile : INode { const char* err; path += ".exr"; std::string native_path = std::filesystem::u8path(path).string(); - int ret = SaveEXR(data2.data(),w,h,n,1,native_path.c_str(),&err); + int ret = SaveEXR(data2.data(),w,h,n,0,native_path.c_str(),&err); if (ret != TINYEXR_SUCCESS) { zeno::log_error("Error saving EXR file: {}\n", err); From 1e8f3f87231cd1abe219a1885151fcb91e6e2918 Mon Sep 17 00:00:00 2001 From: littlemine Date: Fri, 13 Oct 2023 18:35:54 +0800 Subject: [PATCH 23/32] upd zpc --- projects/CUDA/zpc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/CUDA/zpc b/projects/CUDA/zpc index efd865f356..b2d979ff65 160000 --- a/projects/CUDA/zpc +++ b/projects/CUDA/zpc @@ -1 +1 @@ -Subproject commit efd865f35618a56f03277a3cc65bb848f7664b4a +Subproject commit b2d979ff655ea371ccb3311a049955a8f59255d7 From a02cd58a96673040738412b1ac3f92709ba226d4 Mon Sep 17 00:00:00 2001 From: YingQ Date: Mon, 16 Oct 2023 11:18:01 +0800 Subject: [PATCH 24/32] Delete blend clamp --- projects/ImgCV/ImageComposite.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/ImgCV/ImageComposite.cpp b/projects/ImgCV/ImageComposite.cpp index 775c3ef889..489ba4ece7 100644 --- a/projects/ImgCV/ImageComposite.cpp +++ b/projects/ImgCV/ImageComposite.cpp @@ -729,8 +729,8 @@ struct Blend: INode { //todo: rgb1和rgb2大小不同的情况 #pragma omp parallel for for (int i = 0; i < imagesize; i++) { - vec3f rgb1 = zeno::clamp(blend->verts[i], 0, 1) * opacity1; - vec3f rgb2 = zeno::clamp(base->verts[i], 0, 1) * opacity2; + vec3f rgb1 = blend->verts[i] * opacity1; + vec3f rgb2 = base->verts[i] * opacity2; vec3f opacity = zeno::clamp(mask->verts[i], 0, 1) * maskopacity; if(compmode == "Overlay" || compmode == "SoftLight" || compmode == "Divide"){ vec3f c = BlendModeV(blendalpha[i], basealpha[i], rgb1, rgb2, opacity, compmode); From 808b0ec99efc6615b38516d2bde1af3587bd6cfa Mon Sep 17 00:00:00 2001 From: zhouhang95 <765229842@qq.com> Date: Mon, 16 Oct 2023 15:20:04 +0800 Subject: [PATCH 25/32] select_mode_normal_append_remove --- ui/zenoedit/viewport/cameracontrol.cpp | 28 +++++++++++++++++++++- ui/zenoedit/viewport/cameracontrol.h | 3 +++ ui/zenoedit/viewport/displaywidget.cpp | 2 +- ui/zenoedit/viewport/viewportwidget.cpp | 5 ++++ ui/zenoedit/viewportinteraction/picker.cpp | 17 +++++++------ ui/zenoedit/viewportinteraction/picker.h | 10 ++++++-- 6 files changed, 52 insertions(+), 13 deletions(-) diff --git a/ui/zenoedit/viewport/cameracontrol.cpp b/ui/zenoedit/viewport/cameracontrol.cpp index 5a84adf49a..149c3810c7 100644 --- a/ui/zenoedit/viewport/cameracontrol.cpp +++ b/ui/zenoedit/viewport/cameracontrol.cpp @@ -586,7 +586,18 @@ void CameraControl::fakeMouseReleaseEvent(QMouseEvent *event) { int y0 = m_boundRectStartPos.y(); int x1 = releasePos.x(); int y1 = releasePos.y(); - m_picker->pick(x0, y0, x1, y1); + zeno::SELECTION_MODE mode = zeno::SELECTION_MODE::NORMAL; + if (shift_pressed == false && ctrl_pressed == false) { + mode = zeno::SELECTION_MODE::NORMAL; + } + else if (shift_pressed == true && ctrl_pressed == false) { + mode = zeno::SELECTION_MODE::APPEND; + } + else if (shift_pressed == false && ctrl_pressed == true) { + mode = zeno::SELECTION_MODE::REMOVE; + } + + m_picker->pick(x0, y0, x1, y1, mode); m_picker->sync_to_scene(); if (scene->select_mode == zenovis::PICK_MODE::PICK_OBJECT) onPrimSelected(); @@ -637,6 +648,12 @@ void CameraControl::fakeMouseReleaseEvent(QMouseEvent *event) { } bool CameraControl::fakeKeyPressEvent(int uKey) { + if (uKey & Qt::SHIFT) { + shift_pressed = true; + } + if (uKey & Qt::CTRL) { + ctrl_pressed = true; + } if (!middle_button_pressed) { return false; } @@ -684,6 +701,15 @@ bool CameraControl::fakeKeyPressEvent(int uKey) { } } +bool CameraControl::fakeKeyReleaseEvent(int uKey) { + if (uKey == Qt::Key_Shift) { + shift_pressed = false; + } + if (uKey == Qt::Key_Control) { + ctrl_pressed = false; + } + return false; +} //void CameraControl::createPointNode(QPointF pnt) { //auto pModel = zenoApp->graphsManagment()->currentModel(); //ZASSERT_EXIT(pModel); diff --git a/ui/zenoedit/viewport/cameracontrol.h b/ui/zenoedit/viewport/cameracontrol.h index db3f10b544..da7798a816 100644 --- a/ui/zenoedit/viewport/cameracontrol.h +++ b/ui/zenoedit/viewport/cameracontrol.h @@ -39,6 +39,7 @@ class CameraControl : public QObject void setKeyFrame(); bool fakeKeyPressEvent(int uKey); + bool fakeKeyReleaseEvent(int uKey); void fakeMousePressEvent(QMouseEvent* event); void fakeMouseReleaseEvent(QMouseEvent* event); void fakeMouseMoveEvent(QMouseEvent* event); @@ -66,6 +67,8 @@ class CameraControl : public QObject Zenovis* m_zenovis; bool middle_button_pressed = false; + bool shift_pressed = false; + bool ctrl_pressed = false; }; diff --git a/ui/zenoedit/viewport/displaywidget.cpp b/ui/zenoedit/viewport/displaywidget.cpp index 6bdac8b03b..8c59fbbbcd 100644 --- a/ui/zenoedit/viewport/displaywidget.cpp +++ b/ui/zenoedit/viewport/displaywidget.cpp @@ -1217,7 +1217,7 @@ void DisplayWidget::onNodeSelected(const QModelIndex &subgIdx, const QModelIndex node_context += prim_name + ":" + e.toStdString() + " "; if (picker) - picker->load_from_str(node_context, scene->select_mode); + picker->load_from_str(node_context, scene->select_mode, zeno::SELECTION_MODE::NORMAL); } if (picker) { picker->sync_to_scene(); diff --git a/ui/zenoedit/viewport/viewportwidget.cpp b/ui/zenoedit/viewport/viewportwidget.cpp index 3aa0670736..ba4c758fb7 100644 --- a/ui/zenoedit/viewport/viewportwidget.cpp +++ b/ui/zenoedit/viewport/viewportwidget.cpp @@ -396,4 +396,9 @@ void ViewportWidget::keyPressEvent(QKeyEvent *event) void ViewportWidget::keyReleaseEvent(QKeyEvent *event) { _base::keyReleaseEvent(event); + int uKey = event->key(); + if (m_camera->fakeKeyReleaseEvent(uKey)) { + zenoApp->getMainWindow()->updateViewport(); + return; + } } diff --git a/ui/zenoedit/viewportinteraction/picker.cpp b/ui/zenoedit/viewportinteraction/picker.cpp index 481ec91965..2f9714d141 100644 --- a/ui/zenoedit/viewportinteraction/picker.cpp +++ b/ui/zenoedit/viewportinteraction/picker.cpp @@ -145,7 +145,7 @@ void Picker::pick(int x, int y) { // onPrimitiveSelected(); } -void Picker::pick(int x0, int y0, int x1, int y1) { +void Picker::pick(int x0, int y0, int x1, int y1, SELECTION_MODE mode) { auto scene = this->scene(); ZASSERT_EXIT(scene); auto selected = picker->getPicked(x0, y0, x1, y1); @@ -155,14 +155,10 @@ void Picker::pick(int x0, int y0, int x1, int y1) { selected_prims.clear(); return; } - load_from_str(selected, zenovis::PICK_MODE::PICK_OBJECT); + load_from_str(selected, zenovis::PICK_MODE::PICK_OBJECT, SELECTION_MODE::NORMAL); } else { - if (selected.empty()) { - selected_elements.clear(); - return; - } - load_from_str(selected, scene->select_mode); + load_from_str(selected, scene->select_mode, mode); if (picked_elems_callback) picked_elems_callback(selected_elements); } } @@ -201,7 +197,7 @@ void Picker::sync_to_scene() { } -void Picker::load_from_str(const string& str, zenovis::PICK_MODE mode) { +void Picker::load_from_str(const string& str, zenovis::PICK_MODE mode, SELECTION_MODE sel_mode) { if (str.empty()) return; // parse selected string std::regex reg(" "); @@ -215,6 +211,9 @@ void Picker::load_from_str(const string& str, zenovis::PICK_MODE mode) { } } else { + if (sel_mode == SELECTION_MODE::NORMAL) { + selected_elements.clear(); + } while (p != end) { string result = *p++; // qDebug() << result.c_str(); @@ -225,7 +224,7 @@ void Picker::load_from_str(const string& str, zenovis::PICK_MODE mode) { int elem_id; ss >> elem_id; if (selected_elements.find(obj_id) != selected_elements.end()) { auto &elements = selected_elements[obj_id]; - if (elements.count(elem_id) > 0) + if (sel_mode == SELECTION_MODE::REMOVE) elements.erase(elem_id); else elements.insert(elem_id); diff --git a/ui/zenoedit/viewportinteraction/picker.h b/ui/zenoedit/viewportinteraction/picker.h index ca60719185..3cf7bd4d26 100644 --- a/ui/zenoedit/viewportinteraction/picker.h +++ b/ui/zenoedit/viewportinteraction/picker.h @@ -16,6 +16,12 @@ class ViewportWidget; namespace zeno { +enum class SELECTION_MODE { + NORMAL, + APPEND, + REMOVE, +}; + std::optional ray_box_intersect( zeno::vec3f const &bmin, zeno::vec3f const &bmax, @@ -38,14 +44,14 @@ class Picker Picker(ViewportWidget* pViewport); void initialize(); void pick(int x, int y); - void pick(int x0, int y0, int x1, int y1); + void pick(int x0, int y0, int x1, int y1, SELECTION_MODE mode = SELECTION_MODE::NORMAL); void pick_depth(int x, int y); void add(const std::string& prim_name); std::string just_pick_prim(int x, int y); const std::unordered_set& get_picked_prims(); const std::unordered_map>& get_picked_elems(); void sync_to_scene(); - void load_from_str(const std::string& str, zenovis::PICK_MODE mode); + void load_from_str(const std::string& str, zenovis::PICK_MODE mode, SELECTION_MODE sel_mode); std::string save_to_str(zenovis::PICK_MODE mode); void save_context(); void load_context(); From ce06ca2cd248d6ed18385dba1109cc43630bcdc7 Mon Sep 17 00:00:00 2001 From: YingQ Date: Mon, 16 Oct 2023 17:27:01 +0800 Subject: [PATCH 26/32] clampfkalpha --- projects/ImgCV/ImageComposite.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/projects/ImgCV/ImageComposite.cpp b/projects/ImgCV/ImageComposite.cpp index 489ba4ece7..da65547234 100644 --- a/projects/ImgCV/ImageComposite.cpp +++ b/projects/ImgCV/ImageComposite.cpp @@ -575,7 +575,7 @@ ZENDEFNODE(Composite, { template static T BlendMode(const float &alpha1, const float &alpha2, const T& rgb1, const T& rgb2, const vec3f opacity, std::string compmode) { - if(compmode == std::string("Copy")) {//copy and over is different!!! + if(compmode == std::string("Copy")) {//copy and over is different! T value = rgb1 * opacity[0] + rgb2 * (1 - opacity[0]); return value; } @@ -732,13 +732,15 @@ struct Blend: INode { vec3f rgb1 = blend->verts[i] * opacity1; vec3f rgb2 = base->verts[i] * opacity2; vec3f opacity = zeno::clamp(mask->verts[i], 0, 1) * maskopacity; + float alpha1 = zeno::clamp(blendalpha[i], 0, 1); + float alpha2 = zeno::clamp(basealpha[i], 0, 1); if(compmode == "Overlay" || compmode == "SoftLight" || compmode == "Divide"){ - vec3f c = BlendModeV(blendalpha[i], basealpha[i], rgb1, rgb2, opacity, compmode); - image2->verts[i] = zeno::clamp(c, 0, 1); + vec3f c = BlendModeV(alpha1, alpha2, rgb1, rgb2, opacity, compmode); + image2->verts[i] = c; } else{ - vec3f c = BlendMode(blendalpha[i], basealpha[i], rgb1, rgb2, opacity, compmode); - image2->verts[i] = zeno::clamp(c, 0, 1); + vec3f c = BlendMode(alpha1, alpha2, rgb1, rgb2, opacity, compmode); + image2->verts[i] = c; } } if(alphaoutput) {//如果两个输入 其中一个没有alpha 对于rgb和alpha alpha的默认值不一样 前者为1 后者为0? @@ -748,8 +750,8 @@ struct Blend: INode { #pragma omp parallel for for (int i = 0; i < imagesize; i++) { vec3f opacity = zeno::clamp(mask->verts[i], 0, 1) * maskopacity; - float alpha = BlendMode(blendalpha[i], basealpha[i], blendalpha[i], basealpha[i], opacity, alphamode); - image2alpha[i] = zeno::clamp(alpha, 0, 1); + float alpha = BlendMode(zeno::clamp(blendalpha[i], 0, 1), zeno::clamp(basealpha[i], 0, 1), zeno::clamp(blendalpha[i], 0, 1), zeno::clamp(basealpha[i], 0, 1), opacity, alphamode); + image2alpha[i] = alpha; } } From 0a1ff3ba644ceb3caacfd1553e8724d5d86db737 Mon Sep 17 00:00:00 2001 From: miyanyan <1138989048@qq.com> Date: Mon, 16 Oct 2023 20:13:11 +0800 Subject: [PATCH 27/32] [fix] std::unique_ptr build error --- ui/zenoui/ColorEditor/ColorEditor.cpp | 20 ++++++++++++++++++++ ui/zenoui/ColorEditor/ColorEditor.h | 16 ++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/ui/zenoui/ColorEditor/ColorEditor.cpp b/ui/zenoui/ColorEditor/ColorEditor.cpp index ac69f1b18e..e9c3fd6cca 100644 --- a/ui/zenoui/ColorEditor/ColorEditor.cpp +++ b/ui/zenoui/ColorEditor/ColorEditor.cpp @@ -107,6 +107,8 @@ ColorWheel::ColorWheel(QWidget* parent) setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); } +ColorWheel::~ColorWheel() = default; + void ColorWheel::setColorCombination(colorcombo::ICombination* combination) { p->colorCombination = combination; @@ -418,6 +420,8 @@ JumpableSlider::JumpableSlider(Qt::Orientation orientation, QWidget* parent) connect(this, &QSlider::valueChanged, this, [this](int value) { emit valueChanged(value * p->singleStep); }); } +JumpableSlider::~JumpableSlider() = default; + void JumpableSlider::setValue(double value) { // need round @@ -559,6 +563,8 @@ GradientSlider::GradientSlider(QWidget* parent) { } +GradientSlider::~GradientSlider() = default; + void GradientSlider::setGradient(const QColor& startColor, const QColor& stopColor) { setGradient({{0, startColor}, {1, stopColor}}); @@ -646,6 +652,8 @@ ColorSpinHSlider::ColorSpinHSlider(const QString& name, QWidget* parent) connect(p->spinbox, &MixedSpinBox::editingFinished, this, [this]() { p->slider->setValue(p->spinbox->value()); }); } +ColorSpinHSlider::~ColorSpinHSlider() = default; + void ColorSpinHSlider::setGradient(const QColor& startColor, const QColor& stopColor) { p->slider->setGradient(startColor, stopColor); @@ -727,6 +735,8 @@ ColorButton::ColorButton(QWidget* parent) connect(this, &QPushButton::clicked, this, [this]() { emit colorClicked(p->color); }); } +ColorButton::~ColorButton() = default; + void ColorButton::setColor(const QColor& color) { p->color = color; @@ -860,6 +870,8 @@ ColorPalette::ColorPalette(int column, QWidget* parent) setAcceptDrops(true); } +ColorPalette::~ColorPalette() = default; + void ColorPalette::addColor(const QColor& color) { int index = p->colors.size(); @@ -996,6 +1008,8 @@ ColorPreview::ColorPreview(const QColor& color, QWidget* parent) connect(p->pbtnCurrent, &ColorButton::colorDroped, this, &ColorPreview::currentColorChanged); } +ColorPreview::~ColorPreview() = default; + void ColorPreview::setCurrentColor(const QColor& color) { p->setCurrent(color); @@ -1069,6 +1083,8 @@ ColorComboWidget::ColorComboWidget(QWidget* parent) }); } +ColorComboWidget::~ColorComboWidget() = default; + void ColorComboWidget::addCombination(colorcombo::ICombination* combo) { p->combs.push(combo); @@ -1234,6 +1250,8 @@ ColorPicker::ColorPicker(QWidget* parent) setCursor(Qt::CrossCursor); } +ColorPicker::~ColorPicker() = default; + QColor ColorPicker::grabScreenColor(QPoint p) const { // not use now, just make screenshot and get color from it @@ -1652,6 +1670,8 @@ ColorEditor::ColorEditor(const QColor& initial, QWidget* parent) p->showInSRGB->setChecked(true); } +ColorEditor::~ColorEditor() = default; + void ColorEditor::setCurrentColor(const QColor& color) { p->blockColorSignals(true); diff --git a/ui/zenoui/ColorEditor/ColorEditor.h b/ui/zenoui/ColorEditor/ColorEditor.h index add4606900..684536f0a3 100644 --- a/ui/zenoui/ColorEditor/ColorEditor.h +++ b/ui/zenoui/ColorEditor/ColorEditor.h @@ -94,6 +94,7 @@ class ColorWheel : public QWidget Q_OBJECT public: explicit ColorWheel(QWidget* parent = nullptr); + ~ColorWheel(); void setColorCombination(colorcombo::ICombination* combination); void setSelectedColor(const QColor& color); @@ -136,6 +137,8 @@ class JumpableSlider : public QSlider public: explicit JumpableSlider(QWidget* parent); explicit JumpableSlider(Qt::Orientation orientation, QWidget* parent = nullptr); + ~JumpableSlider(); + void setValue(double value); void setMinimum(double value); void setMaximum(double value); @@ -167,6 +170,8 @@ class GradientSlider : public JumpableSlider Q_OBJECT public: explicit GradientSlider(QWidget* parent = nullptr); + ~GradientSlider(); + void setGradient(const QColor& startColor, const QColor& stopColor); void setGradient(const QGradientStops& colors); void setColorCorrection(ColorCorrection* colorCorrection); @@ -186,6 +191,8 @@ class ColorSpinHSlider : public QWidget Q_OBJECT public: explicit ColorSpinHSlider(const QString& name, QWidget* parent = nullptr); + ~ColorSpinHSlider(); + void setGradient(const QColor& startColor, const QColor& stopColor); void setGradient(const QGradientStops& colors); void setColorCorrection(ColorCorrection* colorCorrection); @@ -208,6 +215,8 @@ class ColorButton : public QPushButton Q_OBJECT public: explicit ColorButton(QWidget* parent = nullptr); + ~ColorButton(); + void setColor(const QColor& color); void setColorCorrection(ColorCorrection* colorCorrection); void setBolderWidth(int top, int bottom, int left, int right); @@ -235,6 +244,8 @@ class ColorPalette : public QScrollArea Q_OBJECT public: explicit ColorPalette(int column, QWidget* parent = nullptr); + ~ColorPalette(); + void addColor(const QColor& color); void setColor(const QColor& color, int row, int column); void removeColor(int row, int column); @@ -260,6 +271,8 @@ class ColorPreview : public QWidget Q_OBJECT public: explicit ColorPreview(const QColor& color, QWidget* parent = nullptr); + ~ColorPreview(); + void setCurrentColor(const QColor& color); void setColorCorrection(ColorCorrection* colorCorrection); QColor currentColor() const; @@ -279,6 +292,7 @@ class ColorComboWidget : public QWidget Q_OBJECT public: explicit ColorComboWidget(QWidget* parent = nullptr); + ~ColorComboWidget(); void addCombination(colorcombo::ICombination* combo); void clearCombination(); @@ -317,6 +331,7 @@ class ColorPicker : public QWidget Q_OBJECT public: explicit ColorPicker(QWidget* parent = nullptr); + ~ColorPicker(); QColor grabScreenColor(QPoint p) const; void startColorPicking(); @@ -344,6 +359,7 @@ class ColorEditor : public QDialog public: explicit ColorEditor(QWidget* parent = nullptr); explicit ColorEditor(const QColor& initial, QWidget* parent = nullptr); + ~ColorEditor(); static QColor getColor(const QColor& initial, QWidget* parent = nullptr, const QString& title = ""); From 0ba2dac459ecf1e1be4f897efd9e736ab1c170c7 Mon Sep 17 00:00:00 2001 From: Nick-keyboardwarrior Date: Tue, 17 Oct 2023 15:46:13 +0800 Subject: [PATCH 28/32] small fix for noise sign --- zeno/src/nodes/prim/WBNoise.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/zeno/src/nodes/prim/WBNoise.cpp b/zeno/src/nodes/prim/WBNoise.cpp index 6a6642e09f..8a684d6dd5 100644 --- a/zeno/src/nodes/prim/WBNoise.cpp +++ b/zeno/src/nodes/prim/WBNoise.cpp @@ -896,6 +896,12 @@ float scnoise(float x, float y, float z, int pulsenum, int griddist) { //} struct NoiseImageGen : INode { + // quick tofix source: + // https://stackoverflow.com/questions/1903954/is-there-a-standard-sign-function-signum-sgn-in-c-c + template int sgn(T val) { + return (T(0) < val) - (val < T(0)); + } + virtual void apply() override { auto perC = get_input2("noise per component"); auto image_size = get_input2("image size"); @@ -944,10 +950,15 @@ struct NoiseImageGen : INode { } if (perC) { - image->verts[i] = pow(vec3f(r, g, b), exponent); - alpha[i] = r+g+b; // tofix: proper expression? as well as amplitude related + image->verts[i] = vec3f( + sgn(r) * pow(abs(r), exponent), + sgn(g) * pow(abs(g), exponent), + sgn(b) * pow(abs(b), exponent) + ); + alpha[i] = r+g+b; // tofix: proper expression? is amplitude itrelated? } else { - image->verts[i] = pow(vec3f(r, r, r), exponent); + float er = sgn(r) * pow(abs(r), exponent); + image->verts[i] = vec3f(er, er, er); alpha[i] = r; } } From a2c0e3daf7ec2faf913c5ac42bc829d604b70680 Mon Sep 17 00:00:00 2001 From: YingQ Date: Tue, 17 Oct 2023 16:38:26 +0800 Subject: [PATCH 29/32] fkmagicblend --- projects/ImgCV/ImageComposite.cpp | 59 ++++++++++++++++--------------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/projects/ImgCV/ImageComposite.cpp b/projects/ImgCV/ImageComposite.cpp index da65547234..13df6ed641 100644 --- a/projects/ImgCV/ImageComposite.cpp +++ b/projects/ImgCV/ImageComposite.cpp @@ -573,22 +573,22 @@ ZENDEFNODE(Composite, { template -static T BlendMode(const float &alpha1, const float &alpha2, const T& rgb1, const T& rgb2, const vec3f opacity, std::string compmode) +static T BlendMode(const float &alpha1, const float &alpha2, const T& rgb1, const T& rgb2, const T& background, const vec3f opacity, std::string compmode) { if(compmode == std::string("Copy")) {//copy and over is different! T value = rgb1 * opacity[0] + rgb2 * (1 - opacity[0]); return value; } else if(compmode == std::string("Over")) { - T value = (rgb1 + rgb2 * (1 - alpha1)) * opacity[0] + rgb2 * (1 - opacity[0]); + T value = (rgb1 + background * (1 - alpha1)) * opacity[0] + rgb2 * (1 - opacity[0]); return value; } else if(compmode == std::string("Under")) { - T value = (rgb2 + rgb1 * (1 - alpha2)) * opacity[0] + rgb2 * (1 - opacity[0]); + T value = (background + rgb1 * (1 - alpha2)) * opacity[0] + rgb2 * (1 - opacity[0]); return value; } else if(compmode == std::string("Atop")) { - T value = (rgb1 * alpha2 + rgb2 * (1 - alpha1)) * opacity[0] + rgb2 * (1 - opacity[0]); + T value = (rgb1 * alpha2 + background * (1 - alpha1)) * opacity[0] + rgb2 * (1 - opacity[0]); return value; } else if(compmode == std::string("In")) { @@ -600,53 +600,53 @@ static T BlendMode(const float &alpha1, const float &alpha2, const T& rgb1, cons return value; } else if(compmode == std::string("Xor")) { - T value = (rgb1 * (1 - alpha2) + rgb2 * (1 - alpha1)) * opacity[0] + rgb2 * (1 - opacity[0]); + T value = (rgb1 * (1 - alpha2) + background * (1 - alpha1)) * opacity[0] + rgb2 * (1 - opacity[0]); return value; } else if(compmode == std::string("Add")) { - T value = (rgb1 + rgb2) * opacity[0] + rgb2 * (1 - opacity[0]);//clamp? + T value = (rgb1 + background) * opacity[0] + rgb2 * (1 - opacity[0]);//clamp? return value; } else if(compmode == std::string("Subtract")) { - T value = (rgb2 - rgb1) * opacity[0] + rgb2 * (1 - opacity[0]); + T value = (background - rgb1) * opacity[0] + rgb2 * (1 - opacity[0]); return value; } else if(compmode == std::string("Multiply")) { - T value = rgb1 * rgb2 * opacity[0] + rgb2 * (1 - opacity[0]); + T value = rgb1 * background * opacity[0] + rgb2 * (1 - opacity[0]); return value; } else if(compmode == std::string("Max(Lighten)")) { - T value = zeno::max(rgb1, rgb2) * opacity[0] + rgb2 * (1 - opacity[0]); + T value = zeno::max(rgb1, background) * opacity[0] + rgb2 * (1 - opacity[0]); return value; } else if(compmode == std::string("Min(Darken)")) { - T value = zeno::min(rgb1, rgb2) * opacity[0] + rgb2 * (1 - opacity[0]); + T value = zeno::min(rgb1, background) * opacity[0] + rgb2 * (1 - opacity[0]); return value; } else if(compmode == std::string("Screen")) {//A+B-AB if A and B between 0-1, else A if A>B else B - T value = (1 - (1 - rgb2) * (1 - rgb1)) * opacity[0] + rgb2 * (1 - opacity[0]);//only care 0-1! + T value = (1 - (1 - background) * (1 - rgb1)) * opacity[0] + rgb2 * (1 - opacity[0]);//only care 0-1! return value; } else if(compmode == std::string("Difference")) { - T value = zeno::abs(rgb1 - rgb2) * opacity[0] + rgb2 * (1 - opacity[0]); + T value = zeno::abs(rgb1 - background) * opacity[0] + rgb2 * (1 - opacity[0]); return value; } else if(compmode == std::string("Average")) { - T value = (rgb1 + rgb2) / 2 * opacity[0] + rgb2 * (1 - opacity[0]); + T value = (rgb1 + background) / 2 * opacity[0] + rgb2 * (1 - opacity[0]); return value; } return T(0); } -static zeno::vec3f BlendModeV(const float &alpha1, const float &alpha2, const vec3f& rgb1, const vec3f& rgb2, const vec3f opacity, std::string compmode) +static zeno::vec3f BlendModeV(const float &alpha1, const float &alpha2, const vec3f& rgb1, const vec3f& rgb2, const vec3f& background, const vec3f opacity, std::string compmode) { if(compmode == std::string("Overlay")) { vec3f value; for (int k = 0; k < 3; k++) { if (rgb2[k] < 0.5) { - value[k] = 2 * rgb1[k] * rgb2[k]; + value[k] = 2 * rgb1[k] * background[k]; } else { - value[k] = 1 - 2 * (1 - rgb1[k]) * (1 - rgb2[k]);//screen + value[k] = 1 - 2 * (1 - rgb1[k]) * (1 - background[k]);//screen } } value = value * opacity[0] + rgb2 * (1 - opacity[0]); @@ -656,9 +656,9 @@ static zeno::vec3f BlendModeV(const float &alpha1, const float &alpha2, const ve vec3f value; for (int k = 0; k < 3; k++) { if (rgb1[k] < 0.5) { - value[k] = 2 * rgb1[k] * rgb2[k] + rgb2[k] * rgb2[k] * (1 - 2 * rgb1[k]); + value[k] = 2 * rgb1[k] * background[k] + background[k] * background[k] * (1 - 2 * rgb1[k]); } else { - value[k] = 2 * rgb2[k] * (1 - rgb1[k]) + sqrt(rgb2[k]) * (2 * rgb1[k] - 1); + value[k] = 2 * background[k] * (1 - rgb1[k]) + sqrt(background[k]) * (2 * rgb1[k] - 1); } } /*for (int k = 0; k < 3; k++) { Nuke method @@ -677,7 +677,7 @@ static zeno::vec3f BlendModeV(const float &alpha1, const float &alpha2, const ve if (rgb1[k] == 0) { value[k] = 1; } else { - value[k] = rgb2[k] / rgb1[k]; + value[k] = background[k] / rgb1[k]; } } value = value * opacity[0] + rgb2 * (1 - opacity[0]); @@ -686,7 +686,7 @@ static zeno::vec3f BlendModeV(const float &alpha1, const float &alpha2, const ve return zeno::vec3f(0); } -struct Blend: INode { +struct Blend: INode {//optimize virtual void apply() override {//todo:: add blend scope RGBA and Premultiplied / Alpha Blending(https://github.com/jamieowen/glsl-blend/issues/6) auto blend = get_input("Foreground"); auto base = get_input("Background"); @@ -726,20 +726,20 @@ struct Blend: INode { auto &blendalpha = blend->has_attr("alpha")?blend->attr("alpha"):std::vector(imagesize, 1.0f); auto &basealpha = base->has_attr("alpha")?base->attr("alpha"):std::vector(imagesize, 1.0f); -//todo: rgb1和rgb2大小不同的情况 #pragma omp parallel for for (int i = 0; i < imagesize; i++) { vec3f rgb1 = blend->verts[i] * opacity1; - vec3f rgb2 = base->verts[i] * opacity2; - vec3f opacity = zeno::clamp(mask->verts[i], 0, 1) * maskopacity; - float alpha1 = zeno::clamp(blendalpha[i], 0, 1); - float alpha2 = zeno::clamp(basealpha[i], 0, 1); + vec3f rgb2 = base->verts[i]; + vec3f background = rgb2 * opacity2; + vec3f opacity = zeno::clamp(mask->verts[i] * maskopacity, 0, 1); + float alpha1 = zeno::clamp(blendalpha[i] * opacity1, 0, 1); + float alpha2 = zeno::clamp(basealpha[i] * opacity2, 0, 1); if(compmode == "Overlay" || compmode == "SoftLight" || compmode == "Divide"){ - vec3f c = BlendModeV(alpha1, alpha2, rgb1, rgb2, opacity, compmode); + vec3f c = BlendModeV(alpha1, alpha2, rgb1, rgb2, background, opacity, compmode); image2->verts[i] = c; } else{ - vec3f c = BlendMode(alpha1, alpha2, rgb1, rgb2, opacity, compmode); + vec3f c = BlendMode(alpha1, alpha2, rgb1, rgb2, background, opacity, compmode); image2->verts[i] = c; } } @@ -749,8 +749,9 @@ struct Blend: INode { //std::string alphablendmode = alphamode == "SameWithBlend" ? compmode : alphamode; #pragma omp parallel for for (int i = 0; i < imagesize; i++) { - vec3f opacity = zeno::clamp(mask->verts[i], 0, 1) * maskopacity; - float alpha = BlendMode(zeno::clamp(blendalpha[i], 0, 1), zeno::clamp(basealpha[i], 0, 1), zeno::clamp(blendalpha[i], 0, 1), zeno::clamp(basealpha[i], 0, 1), opacity, alphamode); + vec3f opacity = zeno::clamp(mask->verts[i] * maskopacity, 0, 1); + float alpha = BlendMode(zeno::clamp(blendalpha[i] * opacity1, 0, 1), zeno::clamp(basealpha[i], 0, 1), + zeno::clamp(blendalpha[i] * opacity1, 0, 1), zeno::clamp(basealpha[i], 0, 1), zeno::clamp(basealpha[i] * opacity2, 0, 1), opacity, alphamode); image2alpha[i] = alpha; } } From bc21a5fa0ab4b014569185504f4fa3fb8c2322d7 Mon Sep 17 00:00:00 2001 From: YingQ Date: Tue, 17 Oct 2023 16:38:46 +0800 Subject: [PATCH 30/32] sobel1 --- projects/ImgCV/ObjectRecog.cpp | 146 ++++----------------------------- 1 file changed, 15 insertions(+), 131 deletions(-) diff --git a/projects/ImgCV/ObjectRecog.cpp b/projects/ImgCV/ObjectRecog.cpp index 33c12547af..c0f3574c25 100644 --- a/projects/ImgCV/ObjectRecog.cpp +++ b/projects/ImgCV/ObjectRecog.cpp @@ -96,6 +96,9 @@ struct ImageEdgeDetect : INode { int threshold = get_input2("threshold"); int maxThreshold = get_input2("maxThreshold"); float kernelSize = get_input2("kernelSize"); + //float scale = get_input2("scale"); + //float delta = get_input2("delta"); + //int borderType = get_input2("borderType"); auto &ud = image->userData(); int w = ud.get2("w"); int h = ud.get2("h"); @@ -130,61 +133,26 @@ struct ImageEdgeDetect : INode { } set_output("image", image); } - if (mode == "sobel_gray") { + if (mode == "sobel") {//todo:: cv::Mat imagecvin(h, w, CV_32F); - cv::Mat imagecvout(h, w, CV_32F); - int var = 1; + float grayvalue = 1; +#pragma omp parallel for for (int i = 0; i < h; i++) { for (int j = 0; j < w; j++) { vec3f rgb = image->verts[i * w + j]; - var = 255 * (rgb[0] * 0.299 + rgb[1] * 0.587 + rgb[2] *0.114) ;//average convert to gray - imagecvin.at(i, j) = var; + grayvalue = rgb[0] * 0.299 + rgb[1] * 0.587 + rgb[2] *0.114;//todo detect rgb three channel? + imagecvin.at(i, j) = grayvalue; } } - cv::Mat gradX, gradY; + //cv::Sobel(imagecvin, gradX, CV_32F, 1, 0, kernelSize,scale,delta,borderType); cv::Sobel(imagecvin, gradX, CV_32F, 1, 0, kernelSize); cv::Sobel(imagecvin, gradY, CV_32F, 0, 1, kernelSize); - cv::convertScaleAbs(gradX, gradX); - cv::convertScaleAbs(gradY, gradY); - - for (int i = 0; i < h; i++) { - for (int j = 0; j < w; j++) { - float xg = gradX.at(i, j); - float yg = gradY.at(i, j); - float xy = xg + yg; - xy = xy / 255.f; - image->verts[i * w + j] = {xy, xy, xy}; - } - } - set_output("image", image); - } - - if (mode == "sobel_threshold") { - cv::Mat imagecvin(h, w, CV_32F); - cv::Mat imagecvout(h, w, CV_32F); - int var = 1; - for (int i = 0; i < h; i++) { - for (int j = 0; j < w; j++) { - vec3f rgb = image->verts[i * w + j]; - var = 255 * (rgb[0] * 0.299 + rgb[1] * 0.587 + rgb[2] *0.114); - imagecvin.at(i, j) = var; - } - } - - cv::Mat gradX, gradY; - cv::Sobel(imagecvin, gradX, CV_32F, 1, 0); - cv::Sobel(imagecvin, gradY, CV_32F, 0, 1); - - cv::Mat gradientMagnitude, gradientDirection; - cv::cartToPolar(gradX, gradY, gradientMagnitude, gradientDirection, true); - - cv::threshold(gradientMagnitude, imagecvout, threshold, maxThreshold, cv::THRESH_BINARY); +#pragma omp parallel for for (int i = 0; i < h; i++) { - for (int j = 0; j < w; j++) { - float r = float(imagecvout.at(i, j)) / 255.f; - image->verts[i * w + j] = {r, r, r}; + float magnitude = abs(gradX.at(i, j)) + abs(gradY.at(i, j));//manhattan distance? not euclidean distance + image->verts[i * w + j] = {magnitude, magnitude, magnitude}; } } set_output("image", image); @@ -359,7 +327,7 @@ struct ImageEdgeDetect : INode { ZENDEFNODE(ImageEdgeDetect, { { { "image" }, - { "enum zeno_gray zeno_threshold sobel_gray sobel_threshold roberts_gray roberts_threshold prewitt_gray prewitt_threshold canny_gray canny_threshold", "mode", "sobel_gray" }, + { "enum zeno_gray zeno_threshold sobel roberts_gray roberts_threshold prewitt_gray prewitt_threshold canny_gray canny_threshold", "mode", "sobel" }, { "float", "threshold", "50" }, { "float", "maxThreshold", "9999" }, { "float", "kernelSize", "3"} @@ -472,91 +440,7 @@ ZENDEFNODE(ImageEdgeDetectDIY, { { "deprecated" }, }); -struct ImageEdgeDetectSobel : INode { - void apply() override { - std::shared_ptr image = get_input2("image"); - auto mode = get_input2("mode"); - int threshold = get_input2("threshold"); - int maxThreshold = get_input2("maxThreshold"); - float kernelSize = get_input2("kernelSize"); - auto &ud = image->userData(); - int w = ud.get2("w"); - int h = ud.get2("h"); - - if (mode == "sobel_gray") { - cv::Mat imagecvin(h, w, CV_32F); - cv::Mat imagecvout(h, w, CV_32F); - int var = 1; - for (int i = 0; i < h; i++) { - for (int j = 0; j < w; j++) { - vec3f rgb = image->verts[i * w + j]; - var = 255 * (rgb[0] * 0.299 + rgb[1] * 0.587 + rgb[2] *0.114) ;//average convert to gray - imagecvin.at(i, j) = var; - } - } - - cv::Mat gradX, gradY; - cv::Sobel(imagecvin, gradX, CV_32F, 1, 0, kernelSize); - cv::Sobel(imagecvin, gradY, CV_32F, 0, 1, kernelSize); - cv::convertScaleAbs(gradX, gradX); - cv::convertScaleAbs(gradY, gradY); - - for (int i = 0; i < h; i++) { - for (int j = 0; j < w; j++) { - float xg = gradX.at(i, j); - float yg = gradY.at(i, j); - float xy = xg + yg; - xy = xy / 255.f; - image->verts[i * w + j] = {xy, xy, xy}; - } - } - set_output("image", image); - } - - if (mode == "sobel_threshold") { - cv::Mat imagecvin(h, w, CV_32F); - cv::Mat imagecvout(h, w, CV_32F); - int var = 1; - for (int i = 0; i < h; i++) { - for (int j = 0; j < w; j++) { - vec3f rgb = image->verts[i * w + j]; - var = 255 * (rgb[0] * 0.299 + rgb[1] * 0.587 + rgb[2] *0.114); - imagecvin.at(i, j) = var; - } - } - cv::Mat gradX, gradY; - cv::Sobel(imagecvin, gradX, CV_32F, 1, 0); - cv::Sobel(imagecvin, gradY, CV_32F, 0, 1); - cv::Mat gradientMagnitude, gradientDirection; - cv::cartToPolar(gradX, gradY, gradientMagnitude, gradientDirection, true); - cv::threshold(gradientMagnitude, imagecvout, threshold, maxThreshold, cv::THRESH_BINARY); - for (int i = 0; i < h; i++) { - for (int j = 0; j < w; j++) { - float r = float(imagecvout.at(i, j)) / 255.f; - image->verts[i * w + j] = {r, r, r}; - } - } - set_output("image", image); - } - } -}; - -ZENDEFNODE(ImageEdgeDetectSobel, { - { - { "image" }, - { "enum sobel_gray sobel_threshold", "mode", "sobel_gray" }, - { "float", "threshold", "50" }, - { "float", "maxThreshold", "9999" }, - { "float", "kernelSize", "3"}, - }, - { - { "image" } - }, - {}, - { "image" }, -}); - -struct ImageEdgeDetectMarr : INode { +struct ImageEdgeDetectMarr : INode { //need to gray? void apply() override { std::shared_ptr image = get_input2("image"); auto kerneldiameter = get_input2("kernelDiameter"); @@ -589,7 +473,7 @@ struct ImageEdgeDetectMarr : INode { if (kernelX >= 0 && kernelX < w && kernelY >= 0 && kernelY < h) { - sum += (image->verts[kernelY * w + kernelX][0]) * 255 * kernel[i][j]; + sum += (image->verts[kernelY * w + kernelX][0]) * 255.99 * kernel[i][j];//maybe this cause problem } } } From 2660f710cc9aba0299b46b64a046d6ae83876331 Mon Sep 17 00:00:00 2001 From: zhouhang95 <765229842@qq.com> Date: Tue, 17 Oct 2023 16:57:49 +0800 Subject: [PATCH 31/32] wasd-in-optix --- ui/zenoedit/viewport/optixviewport.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ui/zenoedit/viewport/optixviewport.cpp b/ui/zenoedit/viewport/optixviewport.cpp index fa6ba8d7d5..c0b3cad70e 100644 --- a/ui/zenoedit/viewport/optixviewport.cpp +++ b/ui/zenoedit/viewport/optixviewport.cpp @@ -590,6 +590,10 @@ void ZOptixViewport::keyPressEvent(QKeyEvent* event) if (modifiers & Qt::AltModifier) { uKey += Qt::ALT; } + if (m_camera->fakeKeyPressEvent(uKey)) { + zenoApp->getMainWindow()->updateViewport(); + return; + } /* if (uKey == key) this->changeTransformOperation(0); From d4c92a51b395d02c84a9f734ab6ca1c40355813e Mon Sep 17 00:00:00 2001 From: Nick-keyboardwarrior Date: Wed, 18 Oct 2023 18:17:50 +0800 Subject: [PATCH 32/32] another fix for testing exponent with amplitude (check tofix comment I0 feel so weird) --- zeno/src/nodes/prim/WBNoise.cpp | 69 +++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 29 deletions(-) diff --git a/zeno/src/nodes/prim/WBNoise.cpp b/zeno/src/nodes/prim/WBNoise.cpp index 8a684d6dd5..703c44b802 100644 --- a/zeno/src/nodes/prim/WBNoise.cpp +++ b/zeno/src/nodes/prim/WBNoise.cpp @@ -906,7 +906,7 @@ struct NoiseImageGen : INode { auto perC = get_input2("noise per component"); auto image_size = get_input2("image size"); auto seed = get_input2("seed"); - auto turbulence = get_input2("turbulence"); + auto turbulence = get_input2("turbulence")+1; // tofix: think the case that turbulence = 0 auto roughness = get_input2("roughness"); auto exponent = get_input2("exponent"); auto frequency = get_input2("spatial frequency") * 0.001f; // tofix: mysterious scale? @@ -918,48 +918,59 @@ struct NoiseImageGen : INode { // tofix: how to lock engine seed // try a dumb way -// std::default_random_engine new_engine; engine = new_engine; -// engine.seed(seed); g_seed = seed; #pragma omp parallel for for (int i = 0; i < image_size[0] * image_size[1]; i++) { vec2f p = vec2f(i % image_size[0], i / image_size[0]); - float r = 0; - float g = 0; - float b = 0; vec2f freq = frequency; vec4f amp = amplitude; float rough = roughness; + + float r = 0; + float g = 0; + float b = 0; + float nval = 0; + vec4f max_possible_amp = vec4f(0); for (int j = 0; j < turbulence; j++) { - r += scnoise(p[0] * freq[0], - p[1] * freq[1], - p[0] * freq[0], - 3, 2) * amp[0]; - g += scnoise(p[0] * freq[0], - p[0] * freq[0], - p[1] * freq[1], - 3, 2) * amp[1]; - b += scnoise(p[1] * freq[1], - p[0] * freq[0], - p[0] * freq[0], - 3, 2) * amp[2]; + max_possible_amp += amp; + + if(perC) { + nval = scnoise(p[0] * freq[0], p[1] * freq[1], p[0] * freq[0], 3, 2); + r += nval * amp[0]; + nval = scnoise(p[0] * freq[0], p[0] * freq[0], p[1] * freq[1], 3, 2); + g += nval * amp[1]; + nval = scnoise(p[1] * freq[1], p[0] * freq[0], p[0] * freq[0], 3, 2); + b += nval * amp[2]; + } + else{ + nval = scnoise(p[0] * freq[0], p[1] * freq[1], p[0] * freq[0], 3, 2); + r += nval * amp[0]; + g += nval * amp[1]; + b += nval * amp[2]; + } + freq *= 2.0f; amp *= rough; } - if (perC) { - image->verts[i] = vec3f( - sgn(r) * pow(abs(r), exponent), - sgn(g) * pow(abs(g), exponent), - sgn(b) * pow(abs(b), exponent) - ); - alpha[i] = r+g+b; // tofix: proper expression? is amplitude itrelated? - } else { - float er = sgn(r) * pow(abs(r), exponent); - image->verts[i] = vec3f(er, er, er); - alpha[i] = r; + r /= max_possible_amp[0]; + g /= max_possible_amp[1]; + b /= max_possible_amp[2]; + image->verts[i] = vec3f( + sgn(r) * pow(abs(r), exponent) * amplitude[0], + sgn(g) * pow(abs(g), exponent) * amplitude[1], + sgn(b) * pow(abs(b), exponent) * amplitude[2] + ); + if(perC) { + // tofix: ??? blackbox, is isolated from rgb, + // value does not change with rgb amplitude, + // Some random thought: maybe it has some relationship with rgb value when rgb amlitude set to 1; + alpha[i] = r+g+b * amplitude[3]; // r+g+b for placeholder + } + else{ + alpha[i] = image->verts[i][0]; } } image->userData().set2("isImage", 1);