Advance Wayland and KDE package bring-up
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -0,0 +1,495 @@
|
||||
/*
|
||||
This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2004 Antonio Larrosa <larrosa@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "kpixmapregionselectorwidget.h"
|
||||
#include <QAction>
|
||||
#include <QApplication>
|
||||
#include <QColor>
|
||||
#include <QCursor>
|
||||
#include <QHBoxLayout>
|
||||
#include <QImage>
|
||||
#include <QLabel>
|
||||
#include <QMenu>
|
||||
#include <QMouseEvent>
|
||||
#include <QPainter>
|
||||
#include <QRubberBand>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
class KPixmapRegionSelectorWidgetPrivate
|
||||
{
|
||||
public:
|
||||
KPixmapRegionSelectorWidgetPrivate(KPixmapRegionSelectorWidget *qq)
|
||||
: q(qq)
|
||||
{
|
||||
}
|
||||
|
||||
KPixmapRegionSelectorWidget *const q;
|
||||
|
||||
/**
|
||||
* Recalculates the pixmap that is shown based on the current selected area,
|
||||
* the original image, etc.
|
||||
*/
|
||||
void updatePixmap();
|
||||
|
||||
QRect calcSelectionRectangle(const QPoint &startPoint, const QPoint &endPoint);
|
||||
|
||||
enum CursorState { None = 0, Resizing, Moving };
|
||||
CursorState m_state;
|
||||
|
||||
QPixmap m_unzoomedPixmap;
|
||||
QPixmap m_originalPixmap;
|
||||
QPixmap m_linedPixmap;
|
||||
QRect m_selectedRegion;
|
||||
QLabel *m_label;
|
||||
|
||||
QPoint m_tempFirstClick;
|
||||
double m_forcedAspectRatio;
|
||||
|
||||
int m_maxWidth, m_maxHeight;
|
||||
double m_zoomFactor;
|
||||
|
||||
QRubberBand *m_rubberBand;
|
||||
};
|
||||
|
||||
KPixmapRegionSelectorWidget::KPixmapRegionSelectorWidget(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, d(new KPixmapRegionSelectorWidgetPrivate(this))
|
||||
{
|
||||
QHBoxLayout *hboxLayout = new QHBoxLayout(this);
|
||||
|
||||
hboxLayout->addStretch();
|
||||
QVBoxLayout *vboxLayout = new QVBoxLayout();
|
||||
hboxLayout->addItem(vboxLayout);
|
||||
|
||||
vboxLayout->addStretch();
|
||||
d->m_label = new QLabel(this);
|
||||
d->m_label->setAttribute(Qt::WA_NoSystemBackground, true); // setBackgroundMode( Qt::NoBackground );
|
||||
d->m_label->installEventFilter(this);
|
||||
|
||||
vboxLayout->addWidget(d->m_label);
|
||||
vboxLayout->addStretch();
|
||||
|
||||
hboxLayout->addStretch();
|
||||
|
||||
d->m_forcedAspectRatio = 0;
|
||||
|
||||
d->m_zoomFactor = 1.0;
|
||||
d->m_rubberBand = new QRubberBand(QRubberBand::Rectangle, d->m_label);
|
||||
d->m_rubberBand->hide();
|
||||
}
|
||||
|
||||
KPixmapRegionSelectorWidget::~KPixmapRegionSelectorWidget() = default;
|
||||
|
||||
QPixmap KPixmapRegionSelectorWidget::pixmap() const
|
||||
{
|
||||
return d->m_unzoomedPixmap;
|
||||
}
|
||||
|
||||
void KPixmapRegionSelectorWidget::setPixmap(const QPixmap &pixmap)
|
||||
{
|
||||
Q_ASSERT(!pixmap.isNull()); // This class isn't designed to deal with null pixmaps.
|
||||
d->m_originalPixmap = pixmap;
|
||||
d->m_unzoomedPixmap = pixmap;
|
||||
d->m_label->setPixmap(pixmap);
|
||||
resetSelection();
|
||||
}
|
||||
|
||||
void KPixmapRegionSelectorWidget::resetSelection()
|
||||
{
|
||||
d->m_selectedRegion = d->m_originalPixmap.rect();
|
||||
d->m_rubberBand->hide();
|
||||
d->updatePixmap();
|
||||
}
|
||||
|
||||
QRect KPixmapRegionSelectorWidget::selectedRegion() const
|
||||
{
|
||||
return d->m_selectedRegion;
|
||||
}
|
||||
|
||||
void KPixmapRegionSelectorWidget::setSelectedRegion(const QRect &rect)
|
||||
{
|
||||
if (!rect.isValid()) {
|
||||
resetSelection();
|
||||
} else {
|
||||
d->m_selectedRegion = rect;
|
||||
d->updatePixmap();
|
||||
}
|
||||
}
|
||||
|
||||
void KPixmapRegionSelectorWidgetPrivate::updatePixmap()
|
||||
{
|
||||
Q_ASSERT(!m_originalPixmap.isNull());
|
||||
if (m_originalPixmap.isNull()) {
|
||||
m_label->setPixmap(m_originalPixmap);
|
||||
return;
|
||||
}
|
||||
if (m_selectedRegion.width() > m_originalPixmap.width()) {
|
||||
m_selectedRegion.setWidth(m_originalPixmap.width());
|
||||
}
|
||||
if (m_selectedRegion.height() > m_originalPixmap.height()) {
|
||||
m_selectedRegion.setHeight(m_originalPixmap.height());
|
||||
}
|
||||
|
||||
QPainter painter;
|
||||
if (m_linedPixmap.isNull()) {
|
||||
m_linedPixmap = m_originalPixmap;
|
||||
QPainter p(&m_linedPixmap);
|
||||
p.setCompositionMode(QPainter::CompositionMode_SourceAtop);
|
||||
p.fillRect(m_linedPixmap.rect(), QColor(0, 0, 0, 100));
|
||||
}
|
||||
|
||||
QPixmap pixmap = m_linedPixmap;
|
||||
painter.begin(&pixmap);
|
||||
painter.drawPixmap(m_selectedRegion.topLeft(), m_originalPixmap, m_selectedRegion);
|
||||
|
||||
painter.end();
|
||||
|
||||
m_label->setPixmap(pixmap);
|
||||
|
||||
qApp->sendPostedEvents(nullptr, QEvent::LayoutRequest);
|
||||
|
||||
if (m_selectedRegion == m_originalPixmap.rect()) { // d->m_label->rect()) //### CHECK!
|
||||
m_rubberBand->hide();
|
||||
} else {
|
||||
m_rubberBand->setGeometry(QRect(m_selectedRegion.topLeft(), m_selectedRegion.size()));
|
||||
|
||||
/* m_rubberBand->setGeometry(QRect(m_label -> mapToGlobal(m_selectedRegion.topLeft()),
|
||||
m_selectedRegion.size()));
|
||||
*/
|
||||
if (m_state != None) {
|
||||
m_rubberBand->show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QMenu *KPixmapRegionSelectorWidget::createPopupMenu()
|
||||
{
|
||||
QMenu *popup = new QMenu(this);
|
||||
popup->setObjectName(QStringLiteral("PixmapRegionSelectorPopup"));
|
||||
popup->addSection(tr("Image Operations", "@title:menu"));
|
||||
|
||||
popup->addAction(QIcon::fromTheme(QStringLiteral("object-rotate-right")),
|
||||
tr("&Rotate Clockwise", "@action:inmenu"),
|
||||
this,
|
||||
&KPixmapRegionSelectorWidget::rotateClockwise);
|
||||
popup->addAction(QIcon::fromTheme(QStringLiteral("object-rotate-left")),
|
||||
tr("Rotate &Counterclockwise", "@action:inmenu"),
|
||||
this,
|
||||
&KPixmapRegionSelectorWidget::rotateCounterclockwise);
|
||||
|
||||
/*
|
||||
I wonder if it would be appropriate to have here an "Open with..." option to
|
||||
edit the image (antlarr)
|
||||
*/
|
||||
return popup;
|
||||
}
|
||||
|
||||
void KPixmapRegionSelectorWidget::rotate(RotateDirection direction)
|
||||
{
|
||||
int w = d->m_originalPixmap.width();
|
||||
int h = d->m_originalPixmap.height();
|
||||
QImage img = d->m_unzoomedPixmap.toImage();
|
||||
if (direction == Rotate90) {
|
||||
img = img.transformed(QTransform().rotate(90.0));
|
||||
} else if (direction == Rotate180) {
|
||||
img = img.transformed(QTransform().rotate(180.0));
|
||||
} else {
|
||||
img = img.transformed(QTransform().rotate(270.0));
|
||||
}
|
||||
|
||||
d->m_unzoomedPixmap = QPixmap::fromImage(img);
|
||||
|
||||
img = d->m_originalPixmap.toImage();
|
||||
if (direction == Rotate90) {
|
||||
img = img.transformed(QTransform().rotate(90.0));
|
||||
} else if (direction == Rotate180) {
|
||||
img = img.transformed(QTransform().rotate(180.0));
|
||||
} else {
|
||||
img = img.transformed(QTransform().rotate(270.0));
|
||||
}
|
||||
|
||||
d->m_originalPixmap = QPixmap::fromImage(img);
|
||||
|
||||
d->m_linedPixmap = QPixmap();
|
||||
|
||||
if (d->m_forcedAspectRatio > 0 && d->m_forcedAspectRatio != 1) {
|
||||
resetSelection();
|
||||
} else {
|
||||
switch (direction) {
|
||||
case (Rotate90): {
|
||||
int x = h - d->m_selectedRegion.y() - d->m_selectedRegion.height();
|
||||
int y = d->m_selectedRegion.x();
|
||||
d->m_selectedRegion.setRect(x, y, d->m_selectedRegion.height(), d->m_selectedRegion.width());
|
||||
d->updatePixmap();
|
||||
// qApp->sendPostedEvents(0,QEvent::LayoutRequest);
|
||||
// updatePixmap();
|
||||
|
||||
} break;
|
||||
case (Rotate270): {
|
||||
int x = d->m_selectedRegion.y();
|
||||
int y = w - d->m_selectedRegion.x() - d->m_selectedRegion.width();
|
||||
d->m_selectedRegion.setRect(x, y, d->m_selectedRegion.height(), d->m_selectedRegion.width());
|
||||
d->updatePixmap();
|
||||
// qApp->sendPostedEvents(0,QEvent::LayoutRequest);
|
||||
// updatePixmap();
|
||||
} break;
|
||||
default:
|
||||
resetSelection();
|
||||
}
|
||||
}
|
||||
|
||||
Q_EMIT pixmapRotated();
|
||||
}
|
||||
|
||||
void KPixmapRegionSelectorWidget::rotateClockwise()
|
||||
{
|
||||
rotate(Rotate90);
|
||||
}
|
||||
|
||||
void KPixmapRegionSelectorWidget::rotateCounterclockwise()
|
||||
{
|
||||
rotate(Rotate270);
|
||||
}
|
||||
|
||||
bool KPixmapRegionSelectorWidget::eventFilter(QObject *obj, QEvent *ev)
|
||||
{
|
||||
if (ev->type() == QEvent::MouseButtonPress) {
|
||||
QMouseEvent *mev = (QMouseEvent *)(ev);
|
||||
// qCDebug(KWidgetsAddonsLog) << QString("click at %1,%2").arg( mev->x() ).arg( mev->y() );
|
||||
|
||||
if (mev->button() == Qt::RightButton) {
|
||||
QMenu *popup = createPopupMenu();
|
||||
popup->exec(mev->globalPosition().toPoint());
|
||||
delete popup;
|
||||
return true;
|
||||
}
|
||||
|
||||
QCursor cursor;
|
||||
|
||||
if (d->m_selectedRegion.contains(mev->pos()) && d->m_selectedRegion != d->m_originalPixmap.rect()) {
|
||||
d->m_state = KPixmapRegionSelectorWidgetPrivate::Moving;
|
||||
cursor.setShape(Qt::SizeAllCursor);
|
||||
d->m_rubberBand->show();
|
||||
} else {
|
||||
d->m_state = KPixmapRegionSelectorWidgetPrivate::Resizing;
|
||||
cursor.setShape(Qt::CrossCursor);
|
||||
}
|
||||
QApplication::setOverrideCursor(cursor);
|
||||
|
||||
d->m_tempFirstClick = mev->pos();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ev->type() == QEvent::MouseMove) {
|
||||
QMouseEvent *mev = (QMouseEvent *)(ev);
|
||||
|
||||
// qCDebug(KWidgetsAddonsLog) << QString("move to %1,%2").arg( mev->x() ).arg( mev->y() );
|
||||
|
||||
if (d->m_state == KPixmapRegionSelectorWidgetPrivate::Resizing) {
|
||||
setSelectedRegion(d->calcSelectionRectangle(d->m_tempFirstClick, mev->pos()));
|
||||
} else if (d->m_state == KPixmapRegionSelectorWidgetPrivate::Moving) {
|
||||
int mevx = mev->position().x();
|
||||
int mevy = mev->position().y();
|
||||
bool mouseOutside = false;
|
||||
if (mevx < 0) {
|
||||
d->m_selectedRegion.translate(-d->m_selectedRegion.x(), 0);
|
||||
mouseOutside = true;
|
||||
} else if (mevx > d->m_originalPixmap.width()) {
|
||||
d->m_selectedRegion.translate(d->m_originalPixmap.width() - d->m_selectedRegion.width() - d->m_selectedRegion.x(), 0);
|
||||
mouseOutside = true;
|
||||
}
|
||||
if (mevy < 0) {
|
||||
d->m_selectedRegion.translate(0, -d->m_selectedRegion.y());
|
||||
mouseOutside = true;
|
||||
} else if (mevy > d->m_originalPixmap.height()) {
|
||||
d->m_selectedRegion.translate(0, d->m_originalPixmap.height() - d->m_selectedRegion.height() - d->m_selectedRegion.y());
|
||||
mouseOutside = true;
|
||||
}
|
||||
if (mouseOutside) {
|
||||
d->updatePixmap();
|
||||
return true;
|
||||
};
|
||||
|
||||
d->m_selectedRegion.translate(mev->position().x() - d->m_tempFirstClick.x(), //
|
||||
mev->position().y() - d->m_tempFirstClick.y());
|
||||
|
||||
// Check that the region has not fallen outside the image
|
||||
if (d->m_selectedRegion.x() < 0) {
|
||||
d->m_selectedRegion.translate(-d->m_selectedRegion.x(), 0);
|
||||
} else if (d->m_selectedRegion.right() > d->m_originalPixmap.width()) {
|
||||
d->m_selectedRegion.translate(-(d->m_selectedRegion.right() - d->m_originalPixmap.width()), 0);
|
||||
}
|
||||
|
||||
if (d->m_selectedRegion.y() < 0) {
|
||||
d->m_selectedRegion.translate(0, -d->m_selectedRegion.y());
|
||||
} else if (d->m_selectedRegion.bottom() > d->m_originalPixmap.height()) {
|
||||
d->m_selectedRegion.translate(0, -(d->m_selectedRegion.bottom() - d->m_originalPixmap.height()));
|
||||
}
|
||||
|
||||
d->m_tempFirstClick = mev->pos();
|
||||
d->updatePixmap();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ev->type() == QEvent::MouseButtonRelease) {
|
||||
QMouseEvent *mev = (QMouseEvent *)(ev);
|
||||
|
||||
if (d->m_state == KPixmapRegionSelectorWidgetPrivate::Resizing && mev->pos() == d->m_tempFirstClick) {
|
||||
resetSelection();
|
||||
}
|
||||
|
||||
d->m_state = KPixmapRegionSelectorWidgetPrivate::None;
|
||||
QApplication::restoreOverrideCursor();
|
||||
d->m_rubberBand->hide();
|
||||
return true;
|
||||
}
|
||||
|
||||
QWidget::eventFilter(obj, ev);
|
||||
return false;
|
||||
}
|
||||
|
||||
QRect KPixmapRegionSelectorWidgetPrivate::calcSelectionRectangle(const QPoint &startPoint, const QPoint &_endPoint)
|
||||
{
|
||||
QPoint endPoint = _endPoint;
|
||||
if (endPoint.x() < 0) {
|
||||
endPoint.setX(0);
|
||||
} else if (endPoint.x() > m_originalPixmap.width()) {
|
||||
endPoint.setX(m_originalPixmap.width());
|
||||
}
|
||||
if (endPoint.y() < 0) {
|
||||
endPoint.setY(0);
|
||||
} else if (endPoint.y() > m_originalPixmap.height()) {
|
||||
endPoint.setY(m_originalPixmap.height());
|
||||
}
|
||||
int w = abs(startPoint.x() - endPoint.x());
|
||||
int h = abs(startPoint.y() - endPoint.y());
|
||||
|
||||
if (m_forcedAspectRatio > 0) {
|
||||
double aspectRatio = w / double(h);
|
||||
|
||||
if (aspectRatio > m_forcedAspectRatio) {
|
||||
h = (int)(w / m_forcedAspectRatio);
|
||||
} else {
|
||||
w = (int)(h * m_forcedAspectRatio);
|
||||
}
|
||||
}
|
||||
|
||||
int x;
|
||||
int y;
|
||||
if (startPoint.x() < endPoint.x()) {
|
||||
x = startPoint.x();
|
||||
} else {
|
||||
x = startPoint.x() - w;
|
||||
}
|
||||
|
||||
if (startPoint.y() < endPoint.y()) {
|
||||
y = startPoint.y();
|
||||
} else {
|
||||
y = startPoint.y() - h;
|
||||
}
|
||||
|
||||
if (x < 0) {
|
||||
w += x;
|
||||
x = 0;
|
||||
h = (int)(w / m_forcedAspectRatio);
|
||||
|
||||
if (startPoint.y() > endPoint.y()) {
|
||||
y = startPoint.y() - h;
|
||||
}
|
||||
} else if (x + w > m_originalPixmap.width()) {
|
||||
w = m_originalPixmap.width() - x;
|
||||
h = (int)(w / m_forcedAspectRatio);
|
||||
|
||||
if (startPoint.y() > endPoint.y()) {
|
||||
y = startPoint.y() - h;
|
||||
}
|
||||
}
|
||||
|
||||
if (y < 0) {
|
||||
h += y;
|
||||
y = 0;
|
||||
w = (int)(h * m_forcedAspectRatio);
|
||||
|
||||
if (startPoint.x() > endPoint.x()) {
|
||||
x = startPoint.x() - w;
|
||||
}
|
||||
} else if (y + h > m_originalPixmap.height()) {
|
||||
h = m_originalPixmap.height() - y;
|
||||
w = (int)(h * m_forcedAspectRatio);
|
||||
|
||||
if (startPoint.x() > endPoint.x()) {
|
||||
x = startPoint.x() - w;
|
||||
}
|
||||
}
|
||||
|
||||
return QRect(x, y, w, h);
|
||||
}
|
||||
|
||||
QRect KPixmapRegionSelectorWidget::unzoomedSelectedRegion() const
|
||||
{
|
||||
return QRect((int)(d->m_selectedRegion.x() / d->m_zoomFactor),
|
||||
(int)(d->m_selectedRegion.y() / d->m_zoomFactor),
|
||||
(int)(d->m_selectedRegion.width() / d->m_zoomFactor),
|
||||
(int)(d->m_selectedRegion.height() / d->m_zoomFactor));
|
||||
}
|
||||
|
||||
QImage KPixmapRegionSelectorWidget::selectedImage() const
|
||||
{
|
||||
QImage origImage = d->m_unzoomedPixmap.toImage();
|
||||
return origImage.copy(unzoomedSelectedRegion());
|
||||
}
|
||||
|
||||
void KPixmapRegionSelectorWidget::setSelectionAspectRatio(int width, int height)
|
||||
{
|
||||
d->m_forcedAspectRatio = width / double(height);
|
||||
}
|
||||
|
||||
void KPixmapRegionSelectorWidget::setFreeSelectionAspectRatio()
|
||||
{
|
||||
d->m_forcedAspectRatio = 0;
|
||||
}
|
||||
|
||||
void KPixmapRegionSelectorWidget::setMaximumWidgetSize(int width, int height)
|
||||
{
|
||||
d->m_maxWidth = width;
|
||||
d->m_maxHeight = height;
|
||||
|
||||
if (d->m_selectedRegion == d->m_originalPixmap.rect()) {
|
||||
d->m_selectedRegion = QRect();
|
||||
}
|
||||
d->m_originalPixmap = d->m_unzoomedPixmap;
|
||||
|
||||
// qCDebug(KWidgetsAddonsLog) << QString(" original Pixmap :") << d->m_originalPixmap.rect();
|
||||
// qCDebug(KWidgetsAddonsLog) << QString(" unzoomed Pixmap : %1 x %2 ").arg(d->m_unzoomedPixmap.width()).arg(d->m_unzoomedPixmap.height());
|
||||
|
||||
if (!d->m_originalPixmap.isNull() && (d->m_originalPixmap.width() > d->m_maxWidth || d->m_originalPixmap.height() > d->m_maxHeight)) {
|
||||
/* We have to resize the pixmap to get it complete on the screen */
|
||||
QImage image = d->m_originalPixmap.toImage();
|
||||
d->m_originalPixmap = QPixmap::fromImage(image.scaled(width, height, Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
||||
double oldZoomFactor = d->m_zoomFactor;
|
||||
d->m_zoomFactor = d->m_originalPixmap.width() / (double)d->m_unzoomedPixmap.width();
|
||||
|
||||
if (d->m_selectedRegion.isValid()) {
|
||||
d->m_selectedRegion = QRect((int)(d->m_selectedRegion.x() * d->m_zoomFactor / oldZoomFactor),
|
||||
(int)(d->m_selectedRegion.y() * d->m_zoomFactor / oldZoomFactor),
|
||||
(int)(d->m_selectedRegion.width() * d->m_zoomFactor / oldZoomFactor),
|
||||
(int)(d->m_selectedRegion.height() * d->m_zoomFactor / oldZoomFactor));
|
||||
}
|
||||
}
|
||||
|
||||
if (!d->m_selectedRegion.isValid()) {
|
||||
d->m_selectedRegion = d->m_originalPixmap.rect();
|
||||
}
|
||||
|
||||
d->m_linedPixmap = QPixmap();
|
||||
d->updatePixmap();
|
||||
resize(d->m_label->width(), d->m_label->height());
|
||||
}
|
||||
|
||||
#include "moc_kpixmapregionselectorwidget.cpp"
|
||||
Reference in New Issue
Block a user