Commit 01fd7108 authored by Dmitry Kazakov's avatar Dmitry Kazakov

Implement a proper Onion Skin configuration dialog

parent 1de937d5
......@@ -255,6 +255,16 @@ void KisImageConfig::setOnionSkinOpacity(int offset, int value)
m_config.writeEntry("onionSkinOpacity_" + QString::number(offset), value);
}
bool KisImageConfig::onionSkinState(int offset) const
{
return m_config.readEntry("onionSkinState_" + QString::number(offset), false);
}
void KisImageConfig::setOnionSkinState(int offset, bool value)
{
m_config.writeEntry("onionSkinState_" + QString::number(offset), value);
}
QColor KisImageConfig::onionSkinTintColorBackward() const
{
return m_config.readEntry("onionSkinTintColorBackward", QColor(Qt::red));
......@@ -359,3 +369,14 @@ int KisImageConfig::totalRAM()
return totalMemory;
}
bool KisImageConfig::showAdditionalOnionSkinsSettings(bool requestDefault) const
{
return !requestDefault ?
m_config.readEntry("showAdditionalOnionSkinsSettings", true) : true;
}
void KisImageConfig::setShowAdditionalOnionSkinsSettings(bool value)
{
m_config.writeEntry("showAdditionalOnionSkinsSettings", value);
}
......@@ -86,6 +86,9 @@ public:
int onionSkinOpacity(int offset) const;
void setOnionSkinOpacity(int offset, int value);
bool onionSkinState(int offset) const;
void setOnionSkinState(int offset, bool value);
QColor onionSkinTintColorBackward() const;
void setOnionSkinTintColorBackward(const QColor &value);
......@@ -95,6 +98,9 @@ public:
bool lazyFrameCreationEnabled(bool requestDefault = false) const;
void setLazyFrameCreationEnabled(bool value);
bool showAdditionalOnionSkinsSettings(bool requestDefault = false) const;
void setShowAdditionalOnionSkinsSettings(bool value);
private:
Q_DISABLE_COPY(KisImageConfig)
......
......@@ -81,9 +81,14 @@ struct KisOnionSkinCompositor::Private
backwardOpacities.resize(numberOfSkins);
forwardOpacities.resize(numberOfSkins);
const qreal scaleFactor = config.onionSkinOpacity(0) / 255.0;
for (int i = 0; i < numberOfSkins; i++) {
backwardOpacities[i] = config.onionSkinOpacity(-(i + 1));
forwardOpacities[i] = config.onionSkinOpacity(i + 1);
int backwardState = (int) config.onionSkinState(-(i + 1));
int forwardState = (int) config.onionSkinState(i + 1);
backwardOpacities[i] = scaleFactor * backwardState * config.onionSkinOpacity(-(i + 1));
forwardOpacities[i] = scaleFactor * forwardState * config.onionSkinOpacity(i + 1);
}
}
};
......
......@@ -21,6 +21,11 @@ set(KRITA_ANIMATIONDOCKER_PART_SRCS
kis_draggable_tool_button.cpp
kis_animation_utils.cpp
kis_custom_modifiers_catcher.cpp
kis_equalizer_column.cpp
kis_equalizer_slider.cpp
kis_equalizer_button.cpp
kis_equalizer_widget.cpp
)
ki18n_wrap_ui(KRITA_ANIMATIONDOCKER_PART_SRCS
......
/*
* Copyright (c) 2015 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_equalizer_button.h"
#include <QStyle>
#include <QPainter>
#include <QStyleOption>
#include <QApplication>
#include "timeline_color_scheme.h"
#include "kis_global.h"
#include "kis_debug.h"
struct KisEqualizerButton::Private
{
Private(KisEqualizerButton *_q)
: q(_q),
isRightmost(false),
isHovering(false) {}
QRect boundingRect() const;
QRect fillingRect() const;
KisEqualizerButton *q;
bool isRightmost;
bool isHovering;
};
KisEqualizerButton::KisEqualizerButton(QWidget *parent)
: QAbstractButton(parent),
m_d(new Private(this))
{
setFocusPolicy(Qt::WheelFocus);
setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
}
KisEqualizerButton::~KisEqualizerButton()
{
}
void KisEqualizerButton::setRightmost(bool value)
{
m_d->isRightmost = value;
}
QRect KisEqualizerButton::Private::boundingRect() const
{
QRect bounds = q->rect().adjusted(0, 0, -isRightmost, 0);
return bounds;
}
QRect KisEqualizerButton::Private::fillingRect() const
{
const int offset = 3;
QRect filling = boundingRect().adjusted(offset + 1, offset + 1,
-offset, -offset);
return filling;
}
void KisEqualizerButton::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event);
const QRect bounds = m_d->boundingRect();
const QRect filling = m_d->fillingRect();
const QColor backgroundColor = palette().color(QPalette::Base);
QPainter p(this);
{ // draw border
QStyleOptionViewItemV4 option; // empty!
const int gridHint = style()->styleHint(QStyle::SH_Table_GridLineColor, &option, this);
const QColor gridColor = static_cast<QRgb>(gridHint);
const QPen gridPen(gridColor);
p.setPen(gridPen);
p.setBrush(backgroundColor);
p.drawRect(bounds);
}
{
QColor fillColor = TimelineColorScheme::instance()->onionSkinsButtonColor();
QColor frameColor = TimelineColorScheme::instance()-> onionSkinsSliderColor();
if (isChecked() || hasFocus() || m_d->isHovering) {
p.setPen(hasFocus() || m_d->isHovering ? frameColor : Qt::transparent);
p.setBrush(isChecked() ? fillColor : Qt::transparent);
p.drawRect(filling);
}
}
QString textValue = text();
{ // draw text
QPalette::ColorRole textRole = QPalette::Text;
//Draw text shadow, This will increase readability when the background of same color
QRect shadowRect(bounds);
shadowRect.translate(1,1);
QColor textColor = palette().color(textRole);
QColor shadowColor = (textColor.value() <= 128)
? QColor(255,255,255,160) : QColor(0,0,0,160);
int flags = Qt::AlignCenter | Qt::TextHideMnemonic;
p.setPen(shadowColor);
p.drawText(shadowRect, flags, textValue);
p.setPen(textColor);
p.drawText(bounds, flags, textValue);
}
}
QSize KisEqualizerButton::sizeHint() const
{
QFontMetrics metrics(this->font());
const int minHeight = metrics.height() + 10;
return QSize(15, minHeight);
}
void KisEqualizerButton::enterEvent(QEvent *event)
{
Q_UNUSED(event);
m_d->isHovering = true;
update();
}
void KisEqualizerButton::leaveEvent(QEvent *event)
{
Q_UNUSED(event);
m_d->isHovering = false;
update();
}
/*
* Copyright (c) 2015 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __KIS_EQUALIZER_BUTTON_H
#define __KIS_EQUALIZER_BUTTON_H
#include <QScopedPointer>
#include <QAbstractButton>
class KisEqualizerButton : public QAbstractButton
{
public:
KisEqualizerButton(QWidget *parent);
~KisEqualizerButton();
void paintEvent(QPaintEvent *event);
void setRightmost(bool value);
QSize sizeHint() const;
void enterEvent(QEvent *event);
void leaveEvent(QEvent *event);
private:
struct Private;
const QScopedPointer<Private> m_d;
};
#endif /* __KIS_EQUALIZER_BUTTON_H */
/*
* Copyright (c) 2015 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_equalizer_column.h"
#include <QVBoxLayout>
#include <QFontMetrics>
#include <QApplication>
#include "kis_debug.h"
#include "kis_equalizer_slider.h"
#include "kis_equalizer_button.h"
#include "kis_signals_blocker.h"
struct KisEqualizerColumn::Private
{
KisEqualizerButton *stateButton;
KisEqualizerSlider *mainSlider;
int id;
};
KisEqualizerColumn::KisEqualizerColumn(QWidget *parent, int id, const QString &title)
: QWidget(parent),
m_d(new Private)
{
setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
m_d->id = id;
m_d->stateButton = new KisEqualizerButton(this);
m_d->stateButton->setText(title);
m_d->stateButton->setCheckable(true);
m_d->stateButton->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
m_d->mainSlider = new KisEqualizerSlider(this);
m_d->mainSlider->setRange(0, 100);
m_d->mainSlider->setSingleStep(5);
m_d->mainSlider->setPageStep(10);
m_d->mainSlider->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
QVBoxLayout *vbox = new QVBoxLayout(this);
vbox->setSpacing(0);
vbox->setContentsMargins(0,0,0,0);
vbox->addWidget(m_d->stateButton, 0);
vbox->addWidget(m_d->mainSlider, 1);
setLayout(vbox);
connect(m_d->stateButton, SIGNAL(toggled(bool)),
SLOT(slotButtonChanged(bool)));
connect(m_d->mainSlider, SIGNAL(valueChanged(int)),
SLOT(slotSliderChanged(int)));
}
KisEqualizerColumn::~KisEqualizerColumn()
{
}
void KisEqualizerColumn::setRightmost(bool value)
{
m_d->stateButton->setRightmost(value);
m_d->mainSlider->setRightmost(value);
}
void KisEqualizerColumn::slotSliderChanged(int value)
{
KisSignalsBlocker b(m_d->stateButton);
m_d->stateButton->setChecked(value > 0);
emit sigColumnChanged(m_d->id, m_d->stateButton->isChecked(), m_d->mainSlider->value());
}
void KisEqualizerColumn::slotButtonChanged(bool value)
{
Q_UNUSED(value);
emit sigColumnChanged(m_d->id, m_d->stateButton->isChecked(), m_d->mainSlider->value());
}
int KisEqualizerColumn::value() const
{
return m_d->mainSlider->value();
}
void KisEqualizerColumn::setValue(int value)
{
m_d->mainSlider->setValue(value);
}
bool KisEqualizerColumn::state() const
{
return m_d->stateButton->isChecked();
}
void KisEqualizerColumn::setState(bool value)
{
m_d->stateButton->setChecked(value);
}
/*
* Copyright (c) 2015 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __KIS_EQUALIZER_COLUMN_H
#define __KIS_EQUALIZER_COLUMN_H
#include <QWidget>
#include <QScopedPointer>
#include <QSlider>
#include "kritaanimationdocker_export.h"
class KRITAANIMATIONDOCKER_EXPORT KisEqualizerColumn : public QWidget
{
Q_OBJECT
public:
KisEqualizerColumn(QWidget *parent, int id, const QString &title);
~KisEqualizerColumn();
void setRightmost(bool value);
int value() const;
void setValue(int value);
bool state() const;
void setState(bool value);
Q_SIGNALS:
void sigColumnChanged(int id, bool state, int value);
private Q_SLOTS:
void slotSliderChanged(int value);
void slotButtonChanged(bool value);
private:
struct Private;
const QScopedPointer<Private> m_d;
};
#endif /* __KIS_EQUALIZER_COLUMN_H */
/*
* Copyright (c) 2015 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_equalizer_slider.h"
#include <QStyle>
#include <QPainter>
#include <QMouseEvent>
#include <QApplication>
#include <QStyleOptionSlider>
#include "kis_global.h"
#include "kis_debug.h"
#include "timeline_color_scheme.h"
struct KisEqualizerSlider::Private
{
Private(KisEqualizerSlider *_q) : q(_q), isRightmost(false) {}
KisEqualizerSlider *q;
bool isRightmost;
QRect boundingRect() const;
QRect sliderRect() const;
int mousePosToValue(const QPoint &pt, bool round) const;
};
KisEqualizerSlider::KisEqualizerSlider(QWidget *parent)
: QAbstractSlider(parent),
m_d(new Private(this))
{
setOrientation(Qt::Vertical);
setFocusPolicy(Qt::WheelFocus);
setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
}
KisEqualizerSlider::~KisEqualizerSlider()
{
}
void KisEqualizerSlider::setRightmost(bool value)
{
m_d->isRightmost = value;
}
QRect KisEqualizerSlider::Private::boundingRect() const
{
QRect bounds = q->rect().adjusted(0, 0, -isRightmost, -1);
return bounds;
}
QRect KisEqualizerSlider::Private::sliderRect() const
{
const int offset = 3;
QRect filling = boundingRect().adjusted(offset + 1, offset + 1,
-offset, -offset);
return filling;
}
int KisEqualizerSlider::Private::mousePosToValue(const QPoint &pt, bool round) const
{
const QRect areaRect = sliderRect();
int rawValue = -pt.y() + (areaRect.top() + areaRect.height());
int maxRawValue = areaRect.height();
int value = QStyle::sliderValueFromPosition(q->minimum(), q->maximum(), rawValue, maxRawValue);
if (round) {
const int singleStep = q->singleStep();
value = ((value + singleStep / 2) / singleStep) * singleStep;
}
return value;
}
void KisEqualizerSlider::mousePressEvent(QMouseEvent *ev)
{
if (maximum() == minimum() || (ev->buttons() ^ ev->button())) {
ev->ignore();
return;
}
const bool precise = ev->modifiers() & Qt::ControlModifier ||
ev->button() == Qt::RightButton;
int value = m_d->mousePosToValue(ev->pos(), !precise);
setSliderPosition(value);
triggerAction(SliderMove);
setRepeatAction(SliderNoAction);
}
void KisEqualizerSlider::mouseMoveEvent(QMouseEvent *ev)
{
const bool precise = ev->modifiers() & Qt::ControlModifier ||
ev->buttons() & Qt::RightButton;
int value = m_d->mousePosToValue(ev->pos(), !precise);
setSliderPosition(value);
triggerAction(SliderMove);
setRepeatAction(SliderNoAction);
}
void KisEqualizerSlider::mouseReleaseEvent(QMouseEvent *ev)
{
Q_UNUSED(ev);
}
QSize KisEqualizerSlider::sizeHint() const
{
return QSize(15, 100);
}
void KisEqualizerSlider::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event);
const QRect bounds = m_d->boundingRect();
const QColor backgroundColor = palette().color(QPalette::Base);
QPainter p(this);
{ // draw border
QStyleOptionViewItemV4 option; // empty!
const int gridHint = style()->styleHint(QStyle::SH_Table_GridLineColor, &option, this);
const QColor gridColor = static_cast<QRgb>(gridHint);
const QPen gridPen(gridColor);