#include "cleanupswatch.h"
#include "trop.h"
#include "toonzqt/gutil.h"
#include <QHBoxLayout>
#include <QBrush>
#include <QPainter>
#include <QMouseEvent>
#include <QIcon>
#include <QPushButton>
#include <QActionGroup>
#include <QToolBar>
#include "toonz/tcleanupper.h"
#include "toonzqt/dvdialog.h"
CleanupSwatch::CleanupSwatch(QWidget *parent, int lx, int ly)
: QWidget(parent)
, m_lx(lx)
, m_ly(ly)
, m_enabled(false)
, m_viewAff()
//, m_lastRasCleanupped()
{
setStyleSheet("background: transparent");
QHBoxLayout *layout = new QHBoxLayout(this);
layout->setMargin(0);
layout->setSpacing(0);
m_leftSwatch = new CleanupSwatchArea(this, true);
layout->addWidget(m_leftSwatch);
DVGui::Separator *sep = new DVGui::Separator();
sep->setFixedWidth(1);
sep->setOrientation(false);
layout->addWidget(sep);
m_rightSwatch = new CleanupSwatchArea(this, false);
layout->addWidget(m_rightSwatch);
setLayout(layout);
}
//---------------------------------------------------------------------
void CleanupSwatch::enable(bool state) {
m_enabled = state;
if (!m_enabled) {
m_resampledRaster = TRasterP();
// m_lastRasCleanupped = TRasterP();
m_origRaster = TRasterP();
m_viewAff = TAffine();
m_resampleAff = TAffine();
m_leftSwatch->updateRaster();
m_rightSwatch->updateRaster();
}
}
//------------------------------------------------------------------------------
/*
void CleanupSwatch::hideEvent(QHideEvent* e)
{
m_enabledAct->setChecked(false);
}*/
//----------------------------------------------------------------
CleanupSwatch::CleanupSwatchArea::CleanupSwatchArea(CleanupSwatch *parent,
bool isLeft)
: QWidget(parent), m_isLeft(isLeft), m_sw(parent) {
setMinimumHeight(150);
// The following helps in re-establishing focus for wheel events
setFocusPolicy(Qt::WheelFocus);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
}
//----------------------------------------------------------------
void CleanupSwatch::CleanupSwatchArea::mousePressEvent(QMouseEvent *event) {
if (!m_sw->m_resampledRaster || m_sw->m_lx == 0 || m_sw->m_ly == 0) return;
// if (m_sw->m_lastRasCleanupped)
// TRop::addBackground(m_sw->m_lastRasCleanupped, TPixel::White);
m_pos = event->pos();
if (event->button() != Qt::MiddleButton || !m_sw->m_resampledRaster) {
event->ignore();
return;
m_panning = false;
} else
m_panning = true;
}
//-----------------------------------------------------------------------------
namespace {
#define ZOOMLEVELS 33
#define NOZOOMINDEX 20
double ZoomFactors[ZOOMLEVELS] = {
0.001, 0.002, 0.003, 0.004, 0.005, 0.007, 0.01, 0.015, 0.02, 0.03, 0.04,
0.05, 0.0625, 0.0833, 0.125, 0.167, 0.25, 0.333, 0.5, 0.667, 1, 2,
3, 4, 5, 6, 7, 8, 12, 16, 24, 32, 40};
double getQuantizedZoomFactor(double zf, bool forward) {
if (forward && (zf > ZoomFactors[ZOOMLEVELS - 1] ||
areAlmostEqual(zf, ZoomFactors[ZOOMLEVELS - 1], 1e-5)))
return zf;
else if (!forward &&
(zf < ZoomFactors[0] || areAlmostEqual(zf, ZoomFactors[0], 1e-5)))
return zf;
assert((!forward && zf > ZoomFactors[0]) ||
(forward && zf < ZoomFactors[ZOOMLEVELS - 1]));
int i = 0;
for (i = 0; i <= ZOOMLEVELS - 1; i++)
if (areAlmostEqual(zf, ZoomFactors[i], 1e-5)) zf = ZoomFactors[i];
if (forward && zf < ZoomFactors[0])
return ZoomFactors[0];
else if (!forward && zf > ZoomFactors[ZOOMLEVELS - 1])
return ZoomFactors[ZOOMLEVELS - 1];
for (i = 0; i < ZOOMLEVELS - 1; i++)
if (ZoomFactors[i + 1] - zf >= 0 && zf - ZoomFactors[i] >= 0) {
if (forward && ZoomFactors[i + 1] == zf)
return ZoomFactors[i + 2];
else if (!forward && ZoomFactors[i] == zf)
return ZoomFactors[i - 1];
else
return forward ? ZoomFactors[i + 1] : ZoomFactors[i];
}
return ZoomFactors[NOZOOMINDEX];
}
} // namespace
//-----------------------------------------------------------------------------
void CleanupSwatch::CleanupSwatchArea::keyPressEvent(QKeyEvent *event) {
if (!m_sw->m_resampledRaster || m_sw->m_lx == 0 || m_sw->m_ly == 0) return;
int key = event->key();
if (key != '+' && key != '-' && key != '0') return;
if (key == '0')
m_sw->m_viewAff = TAffine();
else {
bool forward = (key == '+');
double currZoomScale = sqrt(m_sw->m_viewAff.det());
double factor = getQuantizedZoomFactor(currZoomScale, forward);
double minZoom =
std::min((double)m_sw->m_lx / m_sw->m_resampledRaster->getLx(),
(double)m_sw->m_ly / m_sw->m_resampledRaster->getLy());
if ((!forward && factor < minZoom) || (forward && factor > 40.0)) return;
TPointD delta(0.5 * width(), 0.5 * height());
m_sw->m_viewAff = (TTranslation(delta) * TScale(factor / currZoomScale) *
TTranslation(-delta)) *
m_sw->m_viewAff;
}
m_sw->m_leftSwatch->updateRaster();
m_sw->m_rightSwatch->updateRaster();
}
//-----------------------------------------------------------------------------
void CleanupSwatch::CleanupSwatchArea::mouseReleaseEvent(QMouseEvent *event) {
m_sw->m_rightSwatch->updateRaster();
m_panning = false;
}
//----------------------------------------------------------------
void CleanupSwatch::CleanupSwatchArea::mouseMoveEvent(QMouseEvent *event) {
if (!m_panning) return;
TPoint curPos = TPoint(event->pos().x(), event->pos().y());
QPoint delta = event->pos() - m_pos;
if (delta == QPoint()) return;
TAffine oldAff = m_sw->m_viewAff;
m_sw->m_viewAff = TTranslation(delta.x(), -delta.y()) * m_sw->m_viewAff;
m_sw->m_leftSwatch->updateRaster();
m_sw->m_rightSwatch->updateRaster(true);
m_pos = event->pos();
}
//---------------------------------------------------------------
void CleanupSwatch::CleanupSwatchArea::wheelEvent(QWheelEvent *event) {
if (!m_sw->m_resampledRaster || m_sw->m_lx == 0 || m_sw->m_ly == 0) return;
int step = event->angleDelta().y() > 0 ? 120 : -120;
double factor = exp(0.001 * step);
if (factor == 1.0) return;
double scale = m_sw->m_viewAff.det();
double minZoom =
std::min((double)m_sw->m_lx / m_sw->m_resampledRaster->getLx(),
(double)m_sw->m_ly / m_sw->m_resampledRaster->getLy());
if ((factor < 1 && sqrt(scale) < minZoom) || (factor > 1 && scale > 1200.0))
return;
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
TPointD delta(event->position().x(), height() - event->position().y());
#else
TPointD delta(event->pos().x(), height() - event->pos().y());
#endif
m_sw->m_viewAff =
(TTranslation(delta) * TScale(factor) * TTranslation(-delta)) *
m_sw->m_viewAff;
m_sw->m_leftSwatch->updateRaster();
m_sw->m_rightSwatch->updateRaster();
}
//-------------------------------------------------------------------------------
void CleanupSwatch::resizeEvent(QResizeEvent *event) {
QSize s = m_leftSwatch->size();
m_lx = s.width();
m_ly = s.height();
// m_rightSwatch->resize(m_lx, m_ly);
m_leftSwatch->setMinimumHeight(0);
m_rightSwatch->setMinimumHeight(0);
m_leftSwatch->updateRaster();
m_rightSwatch->updateRaster();
// m_rightSwatch->updateRaster();
QWidget::resizeEvent(event);
// update();
}
/*
void CleanupSwatch::enableRightSwatch(bool state)
{
setVisible(state);
update();
}*/
//---------------------------------------------------
void CleanupSwatch::CleanupSwatchArea::updateCleanupped(bool dragging) {
TAffine aff = getFinalAff();
TRect rectToCompute = convert(aff.inv() * convert(m_r->getBounds()));
rectToCompute = rectToCompute.enlarge(
TCleanupper::instance()->getParameters()->m_despeckling);
TRect outRect = m_sw->m_resampledRaster->getBounds() * rectToCompute;
if (outRect.isEmpty()) return;
TRasterP rasCleanupped = TCleanupper::instance()->processColors(
m_sw->m_resampledRaster->extract(outRect));
TPointD cleanuppedPos = convert(outRect.getP00());
TRop::quickPut(m_r, rasCleanupped, aff * TTranslation(cleanuppedPos));
}
//---------------------------------------------------------------------------------
#ifdef LEVO
void CleanupSwatch::CleanupSwatchArea::updateCleanupped Versione ricalcolo Al
Release Del
mouse(bool dragging) {
TAffine aff = getFinalAff();
TRect rectToCompute = convert(aff.inv() * convert(m_r->getBounds()));
rectToCompute = rectToCompute.enlarge(
TCleanupper::instance()->getParameters()->m_despeckling);
TRect outRect = m_sw->m_resampledRaster->getBounds() * rectToCompute;
if (outRect.isEmpty()) return;
if (dragging && m_sw->m_lastRasCleanupped)
m_r->fill(TPixel(200, 200, 200));
else {
m_sw->m_lastRasCleanupped = TCleanupper::instance()->processColors(
m_sw->m_resampledRaster->extract(outRect));
m_sw->m_lastCleanuppedPos = convert(outRect.getP00());
}
TRop::quickPut(m_r, m_sw->m_lastRasCleanupped,
aff * TTranslation(m_sw->m_lastCleanuppedPos));
}
#endif
//---------------------------------------------------------------------------------
TAffine CleanupSwatch::CleanupSwatchArea::getFinalAff() {
return m_sw->m_viewAff *
TAffine().place(m_sw->m_resampledRaster->getCenterD(),
m_r->getCenterD());
}
//------------------------------------------------------------------------------
void CleanupSwatch::CleanupSwatchArea::updateRaster(bool dragging) {
if (isHidden() || m_sw->m_lx == 0 || m_sw->m_ly == 0) return;
if (!m_r || m_r->getLx() != m_sw->m_lx || m_r->getLy() != m_sw->m_ly)
m_r = TRaster32P(m_sw->m_lx, m_sw->m_ly);
if (!m_sw->m_resampledRaster)
m_r->fill(TPixel(200, 200, 200));
else {
m_r->fill(TPixel::White);
if (m_isLeft)
TRop::quickPut(m_r, m_sw->m_origRaster,
getFinalAff() * m_sw->m_resampleAff);
else
updateCleanupped(dragging);
}
if (dragging)
repaint();
else
update();
}
//----------------------------------------------------------------------------------
void CleanupSwatch::CleanupSwatchArea::paintEvent(QPaintEvent *event) {
QPainter p(this);
if (!m_r)
p.fillRect(rect(), QBrush(QColor(200, 200, 200)));
else
p.drawImage(rect(), rasterToQImage(m_r));
}
//-----------------------------------------------------------------
bool CleanupSwatch::isEnabled() { return isVisible() && m_enabled; }
//------------------------------------------------------------
void CleanupSwatch::setRaster(TRasterP rasLeft, const TAffine &aff,
TRasterP ras) {
if (!isVisible()) {
m_resampledRaster = TRasterP();
m_origRaster = TRasterP();
// m_lastRasCleanupped = TRasterP();
return;
}
m_resampledRaster = ras;
m_origRaster = rasLeft;
m_resampleAff = aff;
m_leftSwatch->updateRaster();
m_rightSwatch->updateRaster();
}
//--------------------------------------------------------------------
void CleanupSwatch::updateCleanupped() { m_rightSwatch->updateRaster(); }