From 414867f13e129075d65987d7c6972baf2e6a05f8 Mon Sep 17 00:00:00 2001 From: Syping Date: Fri, 20 Jul 2018 15:58:51 +0200 Subject: [PATCH] imge cropping added --- ImportDialog.cpp | 44 +++ ImportDialog.h | 1 + ImportDialog.ui | 3 + anpro/imagecropper.cpp | 519 +++++++++++++++++++++++++++++ anpro/imagecropper.h | 103 ++++++ anpro/imagecropper_e.h | 36 ++ anpro/imagecropper_p.h | 76 +++++ gta5view.pro | 8 +- res/gta5sync.ts | 84 +++-- res/gta5sync_de.qm | Bin 45791 -> 46137 bytes res/gta5sync_de.ts | 84 +++-- res/gta5sync_en_US.ts | 84 +++-- res/gta5sync_fr.ts | 84 +++-- res/gta5sync_ru.ts | 84 +++-- res/gta5sync_uk.ts | 84 +++-- res/gta5sync_zh_TW.ts | 84 +++-- {anpro => uimod}/JSHighlighter.cpp | 0 {anpro => uimod}/JSHighlighter.h | 0 18 files changed, 1152 insertions(+), 226 deletions(-) create mode 100644 anpro/imagecropper.cpp create mode 100644 anpro/imagecropper.h create mode 100644 anpro/imagecropper_e.h create mode 100644 anpro/imagecropper_p.h rename {anpro => uimod}/JSHighlighter.cpp (100%) rename {anpro => uimod}/JSHighlighter.h (100%) diff --git a/ImportDialog.cpp b/ImportDialog.cpp index 9b876d0..ea8bf25 100644 --- a/ImportDialog.cpp +++ b/ImportDialog.cpp @@ -20,6 +20,7 @@ #include "ui_ImportDialog.h" #include "SidebarGenerator.h" #include "StandardPaths.h" +#include "imagecropper.h" #include "AppEnv.h" #include "config.h" #include @@ -108,6 +109,7 @@ ImportDialog::ImportDialog(QString profileName, QWidget *parent) : // Options menu optionsMenu = new QMenu(this); optionsMenu->addAction(tr("&Import new Picture..."), this, SLOT(importNewPicture())); + optionsMenu->addAction(tr("&Crop Picture..."), this, SLOT(cropPicture())); ui->cmdOptions->setMenu(optionsMenu); setMaximumSize(sizeHint()); @@ -255,6 +257,48 @@ void ImportDialog::processWatermark(QPainter *snapmaticPainter) snapmaticPainter->drawImage(0, 0, textWatermark); } +void ImportDialog::cropPicture() +{ + qreal screenRatio = AppEnv::screenRatio(); + + QDialog cropDialog(this); + cropDialog.setWindowTitle(tr("Crop Picture...")); + cropDialog.setWindowFlags(cropDialog.windowFlags()^Qt::WindowContextHelpButtonHint); + cropDialog.setModal(true); + + QVBoxLayout cropLayout; + cropLayout.setContentsMargins(0, 0, 0, 0); + cropLayout.setSpacing(0); + cropDialog.setLayout(&cropLayout); + + ImageCropper imageCropper(&cropDialog); + imageCropper.setBackgroundColor(Qt::black); + imageCropper.setCroppingRectBorderColor(QColor(255, 255, 255, 127)); + imageCropper.setImage(QPixmap::fromImage(workImage, Qt::AutoColor)); + imageCropper.setProportion(QSize(1, 1)); + imageCropper.setFixedSize(workImage.size()); + cropLayout.addWidget(&imageCropper); + + QHBoxLayout buttonLayout; + cropLayout.addLayout(&buttonLayout); + + QPushButton cropButton(&cropDialog); + cropButton.setMinimumSize(0, 40 * screenRatio); + cropButton.setText(tr("&Crop")); + cropButton.setToolTip(tr("Crop Picture")); + QObject::connect(&cropButton, SIGNAL(clicked(bool)), &cropDialog, SLOT(accept())); + + buttonLayout.addWidget(&cropButton); + + cropDialog.show(); + cropDialog.setFixedSize(cropDialog.sizeHint()); + if (cropDialog.exec() == true) + { + QImage *croppedImage = new QImage(imageCropper.cropImage().toImage()); + setImage(croppedImage); + } +} + void ImportDialog::importNewPicture() { QSettings settings(GTA5SYNC_APPVENDOR, GTA5SYNC_APPSTR); diff --git a/ImportDialog.h b/ImportDialog.h index a0f4568..7d35d49 100644 --- a/ImportDialog.h +++ b/ImportDialog.h @@ -40,6 +40,7 @@ public: private slots: void processImage(); + void cropPicture(); void importNewPicture(); void on_cbIgnore_toggled(bool checked); void on_cbAvatar_toggled(bool checked); diff --git a/ImportDialog.ui b/ImportDialog.ui index a6c31c4..c62dcd7 100644 --- a/ImportDialog.ui +++ b/ImportDialog.ui @@ -307,6 +307,9 @@ &Options + + false + diff --git a/anpro/imagecropper.cpp b/anpro/imagecropper.cpp new file mode 100644 index 0000000..f311116 --- /dev/null +++ b/anpro/imagecropper.cpp @@ -0,0 +1,519 @@ +/***************************************************************************** +* ImageCropper Qt Widget for cropping images +* Copyright (C) 2013 Dimka Novikov, to@dimkanovikov.pro +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or any later version. +* +* This library 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this program. If not, see . +*****************************************************************************/ + +#include "imagecropper.h" + +#include +#include + +namespace { + static const QSize WIDGET_MINIMUM_SIZE(470, 470); +} + +ImageCropper::ImageCropper(QWidget* parent) : + QWidget(parent), + pimpl(new ImageCropperPrivate) +{ + setMinimumSize(WIDGET_MINIMUM_SIZE); + setMouseTracking(true); +} + +ImageCropper::~ImageCropper() +{ + delete pimpl; +} + +void ImageCropper::setImage(const QPixmap& _image) +{ + pimpl->imageForCropping = _image; + update(); +} + +void ImageCropper::setBackgroundColor(const QColor& _backgroundColor) +{ + pimpl->backgroundColor = _backgroundColor; + update(); +} + +void ImageCropper::setCroppingRectBorderColor(const QColor& _borderColor) +{ + pimpl->croppingRectBorderColor = _borderColor; + update(); +} + +void ImageCropper::setProportion(const QSizeF& _proportion) +{ + // Пропорции хранятся в коэффициентах приращения сторон + // Таким образом, при изменении размера области выделения, + // размеры сторон изменяются на размер зависящий от + // коэффициентов приращения. + + // Сохраним пропорциональную зависимость области выделения в коэффициентах приращения сторон + if (pimpl->proportion != _proportion) { + pimpl->proportion = _proportion; + // ... расчитаем коэффициенты + float heightDelta = (float)_proportion.height() / _proportion.width(); + float widthDelta = (float)_proportion.width() / _proportion.height(); + // ... сохраним коэффициенты + pimpl->deltas.setHeight(heightDelta); + pimpl->deltas.setWidth(widthDelta); + } + + // Обновим пропорции области выделения + if ( pimpl->isProportionFixed ) { + float croppintRectSideRelation = + (float)pimpl->croppingRect.width() / pimpl->croppingRect.height(); + float proportionSideRelation = + (float)pimpl->proportion.width() / pimpl->proportion.height(); + // Если область выделения не соответствует необходимым пропорциям обновим её + if (croppintRectSideRelation != proportionSideRelation) { + bool widthShotrerThenHeight = + pimpl->croppingRect.width() < pimpl->croppingRect.height(); + // ... установим размер той стороны, что длиннее + if (widthShotrerThenHeight) { + pimpl->croppingRect.setHeight( + pimpl->croppingRect.width() * pimpl->deltas.height()); + } else { + pimpl->croppingRect.setWidth( + pimpl->croppingRect.height() * pimpl->deltas.width()); + } + // ... перерисуем виджет + update(); + } + } + +} + +void ImageCropper::setProportionFixed(const bool _isFixed) +{ + if (pimpl->isProportionFixed != _isFixed) { + pimpl->isProportionFixed = _isFixed; + setProportion(pimpl->proportion); + } +} + +const QPixmap ImageCropper::cropImage() +{ + // Получим размер отображаемого изображения + QSize scaledImageSize = + pimpl->imageForCropping.scaled( + this->size(), Qt::KeepAspectRatio, Qt::FastTransformation + ).size(); + // Определим расстояние от левого и верхнего краёв + float leftDelta = 0; + float topDelta = 0; + const float HALF_COUNT = 2; + if (this->size().height() == scaledImageSize.height()) { + leftDelta = (this->width() - scaledImageSize.width()) / HALF_COUNT; + } else { + topDelta = (this->height() - scaledImageSize.height()) / HALF_COUNT; + } + // Определим пропорцию области обрезки по отношению к исходному изображению + float xScale = (float)pimpl->imageForCropping.width() / scaledImageSize.width(); + float yScale = (float)pimpl->imageForCropping.height() / scaledImageSize.height(); + // Расчитаем область обрезки с учётом коррекции размеров исходного изображения + QRectF realSizeRect( + QPointF(pimpl->croppingRect.left() - leftDelta, pimpl->croppingRect.top() - topDelta), + pimpl->croppingRect.size()); + // ... корректируем левый и верхний края + realSizeRect.setLeft((pimpl->croppingRect.left() - leftDelta) * xScale); + realSizeRect.setTop ((pimpl->croppingRect.top() - topDelta) * yScale); + // ... корректируем размер + realSizeRect.setWidth(pimpl->croppingRect.width() * xScale); + realSizeRect.setHeight(pimpl->croppingRect.height() * yScale); + // Получаем обрезанное изображение + return pimpl->imageForCropping.copy(realSizeRect.toRect()); +} + +// ******** +// Protected section + +void ImageCropper::paintEvent(QPaintEvent* _event) +{ + QWidget::paintEvent( _event ); + // + QPainter widgetPainter(this); + // Рисуем изображение по центру виджета + { + // ... подгоним изображение для отображения по размеру виджета + QPixmap scaledImage = + pimpl->imageForCropping.scaled(this->size(), Qt::KeepAspectRatio, Qt::FastTransformation); + // ... заливаем фон + widgetPainter.fillRect( this->rect(), pimpl->backgroundColor ); + // ... рисуем изображение по центру виджета + if ( this->size().height() == scaledImage.height() ) { + widgetPainter.drawPixmap( ( this->width() - scaledImage.width() ) / 2, 0, scaledImage ); + } else { + widgetPainter.drawPixmap( 0, ( this->height() - scaledImage.height() ) / 2, scaledImage ); + } + } + // Рисуем область обрезки + { + // ... если это первое отображение после инициилизации, то центруем областо обрезки + if (pimpl->croppingRect.isNull()) { + const int width = WIDGET_MINIMUM_SIZE.width()/2; + const int height = WIDGET_MINIMUM_SIZE.height()/2; + pimpl->croppingRect.setSize(QSize(width, height)); + float x = (this->width() - pimpl->croppingRect.width())/2; + float y = (this->height() - pimpl->croppingRect.height())/2; + pimpl->croppingRect.moveTo(x, y); + } + + // ... рисуем затемненную область + QPainterPath p; + p.addRect(pimpl->croppingRect); + p.addRect(this->rect()); + widgetPainter.setBrush(QBrush(QColor(0,0,0,120))); + widgetPainter.setPen(Qt::transparent); + widgetPainter.drawPath(p); + // Рамка и контрольные точки + widgetPainter.setPen(pimpl->croppingRectBorderColor); + // ... рисуем прямоугольник области обрезки + { + widgetPainter.setBrush(QBrush(Qt::transparent)); + widgetPainter.drawRect(pimpl->croppingRect); + } + // ... рисуем контрольные точки + { + widgetPainter.setBrush(QBrush(pimpl->croppingRectBorderColor)); + // Вспомогательные X координаты + int leftXCoord = pimpl->croppingRect.left() - 2; + int centerXCoord = pimpl->croppingRect.center().x() - 3; + int rightXCoord = pimpl->croppingRect.right() - 2; + // Вспомогательные Y координаты + int topYCoord = pimpl->croppingRect.top() - 2; + int middleYCoord = pimpl->croppingRect.center().y() - 3; + int bottomYCoord = pimpl->croppingRect.bottom() - 2; + // + const QSize pointSize(6, 6); + // + QVector points; + points + // левая сторона + << QRect( QPoint(leftXCoord, topYCoord), pointSize ) + << QRect( QPoint(leftXCoord, middleYCoord), pointSize ) + << QRect( QPoint(leftXCoord, bottomYCoord), pointSize ) + // центр + << QRect( QPoint(centerXCoord, topYCoord), pointSize ) + << QRect( QPoint(centerXCoord, middleYCoord), pointSize ) + << QRect( QPoint(centerXCoord, bottomYCoord), pointSize ) + // правая сторона + << QRect( QPoint(rightXCoord, topYCoord), pointSize ) + << QRect( QPoint(rightXCoord, middleYCoord), pointSize ) + << QRect( QPoint(rightXCoord, bottomYCoord), pointSize ); + // + widgetPainter.drawRects( points ); + } + // ... рисуем пунктирные линии + { + QPen dashPen(pimpl->croppingRectBorderColor); + dashPen.setStyle(Qt::DashLine); + widgetPainter.setPen(dashPen); + // ... вертикальная + widgetPainter.drawLine( + QPoint(pimpl->croppingRect.center().x(), pimpl->croppingRect.top()), + QPoint(pimpl->croppingRect.center().x(), pimpl->croppingRect.bottom()) ); + // ... горизонтальная + widgetPainter.drawLine( + QPoint(pimpl->croppingRect.left(), pimpl->croppingRect.center().y()), + QPoint(pimpl->croppingRect.right(), pimpl->croppingRect.center().y()) ); + } + } + // + widgetPainter.end(); +} + +void ImageCropper::mousePressEvent(QMouseEvent* _event) +{ + if (_event->button() == Qt::LeftButton) { + pimpl->isMousePressed = true; + pimpl->startMousePos = _event->pos(); + pimpl->lastStaticCroppingRect = pimpl->croppingRect; + } + // + updateCursorIcon(_event->pos()); +} + +void ImageCropper::mouseMoveEvent(QMouseEvent* _event) +{ + QPointF mousePos = _event->pos(); // относительно себя (виджета) + // + if (!pimpl->isMousePressed) { + // Обработка обычного состояния, т.е. не изменяется размер + // области обрезки, и она не перемещается по виджету + pimpl->cursorPosition = cursorPosition(pimpl->croppingRect, mousePos); + updateCursorIcon(mousePos); + } else if (pimpl->cursorPosition != CursorPositionUndefined) { + // Обработка действий над областью обрезки + // ... определим смещение курсора мышки + QPointF mouseDelta; + mouseDelta.setX( mousePos.x() - pimpl->startMousePos.x() ); + mouseDelta.setY( mousePos.y() - pimpl->startMousePos.y() ); + // + if (pimpl->cursorPosition != CursorPositionMiddle) { + // ... изменяем размер области обрезки + QRectF newGeometry = + calculateGeometry( + pimpl->lastStaticCroppingRect, + pimpl->cursorPosition, + mouseDelta); + // ... пользователь пытается вывернуть область обрезки наизнанку + if (!newGeometry.isNull()) { + pimpl->croppingRect = newGeometry; + } + } else { + // ... перемещаем область обрезки + pimpl->croppingRect.moveTo( pimpl->lastStaticCroppingRect.topLeft() + mouseDelta ); + } + // Перерисуем виджет + update(); + } +} + +void ImageCropper::mouseReleaseEvent(QMouseEvent* _event) +{ + pimpl->isMousePressed = false; + updateCursorIcon(_event->pos()); +} + +// ******** +// Private section + +namespace { + // Находится ли точка рядом с координатой стороны + static bool isPointNearSide (const int _sideCoordinate, const int _pointCoordinate) + { + static const int indent = 10; + return (_sideCoordinate - indent) < _pointCoordinate && _pointCoordinate < (_sideCoordinate + indent); + } +} + +CursorPosition ImageCropper::cursorPosition(const QRectF& _cropRect, const QPointF& _mousePosition) +{ + CursorPosition cursorPosition = CursorPositionUndefined; + // + if ( _cropRect.contains( _mousePosition ) ) { + // Двухстороннее направление + if (isPointNearSide(_cropRect.top(), _mousePosition.y()) && + isPointNearSide(_cropRect.left(), _mousePosition.x())) { + cursorPosition = CursorPositionTopLeft; + } else if (isPointNearSide(_cropRect.bottom(), _mousePosition.y()) && + isPointNearSide(_cropRect.left(), _mousePosition.x())) { + cursorPosition = CursorPositionBottomLeft; + } else if (isPointNearSide(_cropRect.top(), _mousePosition.y()) && + isPointNearSide(_cropRect.right(), _mousePosition.x())) { + cursorPosition = CursorPositionTopRight; + } else if (isPointNearSide(_cropRect.bottom(), _mousePosition.y()) && + isPointNearSide(_cropRect.right(), _mousePosition.x())) { + cursorPosition = CursorPositionBottomRight; + // Одностороннее направление + } else if (isPointNearSide(_cropRect.left(), _mousePosition.x())) { + cursorPosition = CursorPositionLeft; + } else if (isPointNearSide(_cropRect.right(), _mousePosition.x())) { + cursorPosition = CursorPositionRight; + } else if (isPointNearSide(_cropRect.top(), _mousePosition.y())) { + cursorPosition = CursorPositionTop; + } else if (isPointNearSide(_cropRect.bottom(), _mousePosition.y())) { + cursorPosition = CursorPositionBottom; + // Без направления + } else { + cursorPosition = CursorPositionMiddle; + } + } + // + return cursorPosition; +} + +void ImageCropper::updateCursorIcon(const QPointF& _mousePosition) +{ + QCursor cursorIcon; + // + switch (cursorPosition(pimpl->croppingRect, _mousePosition)) + { + case CursorPositionTopRight: + case CursorPositionBottomLeft: + cursorIcon = QCursor(Qt::SizeBDiagCursor); + break; + case CursorPositionTopLeft: + case CursorPositionBottomRight: + cursorIcon = QCursor(Qt::SizeFDiagCursor); + break; + case CursorPositionTop: + case CursorPositionBottom: + cursorIcon = QCursor(Qt::SizeVerCursor); + break; + case CursorPositionLeft: + case CursorPositionRight: + cursorIcon = QCursor(Qt::SizeHorCursor); + break; + case CursorPositionMiddle: + cursorIcon = pimpl->isMousePressed ? + QCursor(Qt::ClosedHandCursor) : + QCursor(Qt::OpenHandCursor); + break; + case CursorPositionUndefined: + default: + cursorIcon = QCursor(Qt::ArrowCursor); + break; + } + // + this->setCursor(cursorIcon); +} + +const QRectF ImageCropper::calculateGeometry( + const QRectF& _sourceGeometry, + const CursorPosition _cursorPosition, + const QPointF& _mouseDelta + ) +{ + QRectF resultGeometry; + // + if ( pimpl->isProportionFixed ) { + resultGeometry = + calculateGeometryWithFixedProportions( + _sourceGeometry, _cursorPosition, _mouseDelta, pimpl->deltas); + } else { + resultGeometry = + calculateGeometryWithCustomProportions( + _sourceGeometry, _cursorPosition, _mouseDelta); + } + // Если пользователь пытается вывернуть область обрезки наизнанку, + // возвращаем null-прямоугольник + if ((resultGeometry.left() >= resultGeometry.right()) || + (resultGeometry.top() >= resultGeometry.bottom())) { + resultGeometry = QRect(); + } + // + return resultGeometry; +} + +const QRectF ImageCropper::calculateGeometryWithCustomProportions( + const QRectF& _sourceGeometry, + const CursorPosition _cursorPosition, + const QPointF& _mouseDelta + ) +{ + QRectF resultGeometry = _sourceGeometry; + // + switch ( _cursorPosition ) + { + case CursorPositionTopLeft: + resultGeometry.setLeft( _sourceGeometry.left() + _mouseDelta.x() ); + resultGeometry.setTop ( _sourceGeometry.top() + _mouseDelta.y() ); + break; + case CursorPositionTopRight: + resultGeometry.setTop ( _sourceGeometry.top() + _mouseDelta.y() ); + resultGeometry.setRight( _sourceGeometry.right() + _mouseDelta.x() ); + break; + case CursorPositionBottomLeft: + resultGeometry.setBottom( _sourceGeometry.bottom() + _mouseDelta.y() ); + resultGeometry.setLeft ( _sourceGeometry.left() + _mouseDelta.x() ); + break; + case CursorPositionBottomRight: + resultGeometry.setBottom( _sourceGeometry.bottom() + _mouseDelta.y() ); + resultGeometry.setRight ( _sourceGeometry.right() + _mouseDelta.x() ); + break; + case CursorPositionTop: + resultGeometry.setTop( _sourceGeometry.top() + _mouseDelta.y() ); + break; + case CursorPositionBottom: + resultGeometry.setBottom( _sourceGeometry.bottom() + _mouseDelta.y() ); + break; + case CursorPositionLeft: + resultGeometry.setLeft( _sourceGeometry.left() + _mouseDelta.x() ); + break; + case CursorPositionRight: + resultGeometry.setRight( _sourceGeometry.right() + _mouseDelta.x() ); + break; + default: + break; + } + // + return resultGeometry; +} + +const QRectF ImageCropper::calculateGeometryWithFixedProportions( + const QRectF& _sourceGeometry, + const CursorPosition _cursorPosition, + const QPointF& _mouseDelta, + const QSizeF& _deltas + ) +{ + QRectF resultGeometry = _sourceGeometry; + // + switch (_cursorPosition) + { + case CursorPositionLeft: + resultGeometry.setTop(_sourceGeometry.top() + _mouseDelta.x() * _deltas.height()); + resultGeometry.setLeft(_sourceGeometry.left() + _mouseDelta.x()); + break; + case CursorPositionRight: + resultGeometry.setTop(_sourceGeometry.top() - _mouseDelta.x() * _deltas.height()); + resultGeometry.setRight(_sourceGeometry.right() + _mouseDelta.x()); + break; + case CursorPositionTop: + resultGeometry.setTop(_sourceGeometry.top() + _mouseDelta.y()); + resultGeometry.setRight(_sourceGeometry.right() - _mouseDelta.y() * _deltas.width()); + break; + case CursorPositionBottom: + resultGeometry.setBottom(_sourceGeometry.bottom() + _mouseDelta.y()); + resultGeometry.setRight(_sourceGeometry.right() + _mouseDelta.y() * _deltas.width()); + break; + case CursorPositionTopLeft: + if ((_mouseDelta.x() * _deltas.height()) < (_mouseDelta.y())) { + resultGeometry.setTop(_sourceGeometry.top() + _mouseDelta.x() * _deltas.height()); + resultGeometry.setLeft(_sourceGeometry.left() + _mouseDelta.x()); + } else { + resultGeometry.setTop(_sourceGeometry.top() + _mouseDelta.y()); + resultGeometry.setLeft(_sourceGeometry.left() + _mouseDelta.y() * _deltas.width()); + } + break; + case CursorPositionTopRight: + if ((_mouseDelta.x() * _deltas.height() * -1) < (_mouseDelta.y())) { + resultGeometry.setTop(_sourceGeometry.top() - _mouseDelta.x() * _deltas.height()); + resultGeometry.setRight(_sourceGeometry.right() + _mouseDelta.x() ); + } else { + resultGeometry.setTop(_sourceGeometry.top() + _mouseDelta.y()); + resultGeometry.setRight(_sourceGeometry.right() - _mouseDelta.y() * _deltas.width()); + } + break; + case CursorPositionBottomLeft: + if ((_mouseDelta.x() * _deltas.height()) < (_mouseDelta.y() * -1)) { + resultGeometry.setBottom(_sourceGeometry.bottom() - _mouseDelta.x() * _deltas.height()); + resultGeometry.setLeft(_sourceGeometry.left() + _mouseDelta.x()); + } else { + resultGeometry.setBottom(_sourceGeometry.bottom() + _mouseDelta.y()); + resultGeometry.setLeft(_sourceGeometry.left() - _mouseDelta.y() * _deltas.width()); + } + break; + case CursorPositionBottomRight: + if ((_mouseDelta.x() * _deltas.height()) > (_mouseDelta.y())) { + resultGeometry.setBottom(_sourceGeometry.bottom() + _mouseDelta.x() * _deltas.height()); + resultGeometry.setRight(_sourceGeometry.right() + _mouseDelta.x()); + } else { + resultGeometry.setBottom(_sourceGeometry.bottom() + _mouseDelta.y()); + resultGeometry.setRight(_sourceGeometry.right() + _mouseDelta.y() * _deltas.width()); + } + break; + default: + break; + } + // + return resultGeometry; +} + diff --git a/anpro/imagecropper.h b/anpro/imagecropper.h new file mode 100644 index 0000000..a5a19a0 --- /dev/null +++ b/anpro/imagecropper.h @@ -0,0 +1,103 @@ +/***************************************************************************** +* ImageCropper Qt Widget for cropping images +* Copyright (C) 2013 Dimka Novikov, to@dimkanovikov.pro +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or any later version. +* +* This library 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this program. If not, see . +*****************************************************************************/ + +#ifndef IMAGECROPPER_H +#define IMAGECROPPER_H + +#include "imagecropper_p.h" +#include "imagecropper_e.h" + +#include + +class ImageCropper : public QWidget +{ + Q_OBJECT + +public: + ImageCropper(QWidget *parent = 0); + ~ImageCropper(); + +public slots: + // Установить изображение для обрезки + void setImage(const QPixmap& _image); + // Установить цвет фона виджета обрезки + void setBackgroundColor(const QColor& _backgroundColor); + // Установить цвет рамки области обрезки + void setCroppingRectBorderColor(const QColor& _borderColor); + // Установить пропорции области выделения + void setProportion(const QSizeF& _proportion); + // Использовать фиксированные пропорции области виделения + void setProportionFixed(const bool _isFixed); + +public: + // Обрезать изображение + const QPixmap cropImage(); + +protected: + virtual void paintEvent(QPaintEvent* _event); + virtual void mousePressEvent(QMouseEvent* _event); + virtual void mouseMoveEvent(QMouseEvent* _event); + virtual void mouseReleaseEvent(QMouseEvent* _event); + +private: + // Определение местоположения курсора над виджетом + CursorPosition cursorPosition(const QRectF& _cropRect, const QPointF& _mousePosition); + // Обновить иконку курсора соответствующую местоположению мыши + void updateCursorIcon(const QPointF& _mousePosition); + + // Получить размер виджета после его изменения мышью + // -------- + // Контракты: + // 1. Метод должен вызываться, только при зажатой кнопке мыши + // (т.е. при перемещении или изменении размера виджета) + // -------- + // В случае неудачи возвращает null-прямоугольник + const QRectF calculateGeometry( + const QRectF& _sourceGeometry, + const CursorPosition _cursorPosition, + const QPointF& _mouseDelta + ); + // Получить размер виджета после его изменения мышью + // Метод изменяет виджет не сохраняя начальных пропорций сторон + // ------ + // Контракты: + // 1. Метод должен вызываться, только при зажатой кнопке мыши + // (т.е. при перемещении или изменении размера виджета) + const QRectF calculateGeometryWithCustomProportions( + const QRectF& _sourceGeometry, + const CursorPosition _cursorPosition, + const QPointF& _mouseDelta + ); + // Получить размер виджета после его изменения мышью + // Метод изменяет виджет сохраняя начальные пропорции сторон + // ------ + // Контракты: + // 1. Метод должен вызываться, только при зажатой кнопке мыши + // (т.е. при перемещении или изменении размера виджета) + const QRectF calculateGeometryWithFixedProportions(const QRectF &_sourceGeometry, + const CursorPosition _cursorPosition, + const QPointF &_mouseDelta, + const QSizeF &_deltas + ); + +private: + // Private data implementation + ImageCropperPrivate* pimpl; +}; + +#endif // IMAGECROPPER_H diff --git a/anpro/imagecropper_e.h b/anpro/imagecropper_e.h new file mode 100644 index 0000000..a9ced6a --- /dev/null +++ b/anpro/imagecropper_e.h @@ -0,0 +1,36 @@ +/***************************************************************************** +* ImageCropper Qt Widget for cropping images +* Copyright (C) 2013 Dimka Novikov, to@dimkanovikov.pro +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or any later version. +* +* This library 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this program. If not, see . +*****************************************************************************/ + +#ifndef IMAGECROPPER_E_H +#define IMAGECROPPER_E_H + +enum CursorPosition +{ + CursorPositionUndefined, + CursorPositionMiddle, + CursorPositionTop, + CursorPositionBottom, + CursorPositionLeft, + CursorPositionRight, + CursorPositionTopLeft, + CursorPositionTopRight, + CursorPositionBottomLeft, + CursorPositionBottomRight +}; + +#endif // IMAGECROPPER_E_H diff --git a/anpro/imagecropper_p.h b/anpro/imagecropper_p.h new file mode 100644 index 0000000..bd09dbb --- /dev/null +++ b/anpro/imagecropper_p.h @@ -0,0 +1,76 @@ +/***************************************************************************** +* ImageCropper Qt Widget for cropping images +* Copyright (C) 2013 Dimka Novikov, to@dimkanovikov.pro +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or any later version. +* +* This library 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this program. If not, see . +*****************************************************************************/ + +#ifndef IMAGECROPPER_P_H +#define IMAGECROPPER_P_H + +#include "imagecropper_e.h" + +#include +#include +#include + +namespace { + const QRect INIT_CROPPING_RECT = QRect(); + const QSizeF INIT_PROPORTION = QSizeF(1.0, 1.0); +} + +class ImageCropperPrivate { +public: + ImageCropperPrivate() : + imageForCropping(QPixmap()), + croppingRect(INIT_CROPPING_RECT), + lastStaticCroppingRect(QRect()), + cursorPosition(CursorPositionUndefined), + isMousePressed(false), + isProportionFixed(false), + startMousePos(QPoint()), + proportion(INIT_PROPORTION), + deltas(INIT_PROPORTION), + backgroundColor(Qt::black), + croppingRectBorderColor(Qt::white) + {} + +public: + // Изображение для обрезки + QPixmap imageForCropping; + // Область обрезки + QRectF croppingRect; + // Последняя фиксированная область обрезки + QRectF lastStaticCroppingRect; + // Позиция курсора относительно области обрезки + CursorPosition cursorPosition; + // Зажата ли левая кнопка мыши + bool isMousePressed; + // Фиксировать пропорции области обрезки + bool isProportionFixed; + // Начальная позиция курсора при изменении размера области обрезки + QPointF startMousePos; + // Пропорции + QSizeF proportion; + // Приращения + // width - приращение по x + // height - приращение по y + QSizeF deltas; + // Цвет заливки фона под изображением + QColor backgroundColor; + // Цвет рамки области обрезки + QColor croppingRectBorderColor; +}; + +#endif // IMAGECROPPER_P_H diff --git a/gta5view.pro b/gta5view.pro index 6412937..d6a9cad 100644 --- a/gta5view.pro +++ b/gta5view.pro @@ -63,9 +63,10 @@ SOURCES += main.cpp \ TelemetryClass.cpp \ TranslationClass.cpp \ UserInterface.cpp \ - anpro/JSHighlighter.cpp \ + anpro/imagecropper.cpp \ pcg/pcg_basic.c \ tmext/TelemetryClassAuthenticator.cpp \ + uimod/JSHighlighter.cpp \ uimod/UiModLabel.cpp \ uimod/UiModWidget.cpp @@ -104,9 +105,12 @@ HEADERS += \ TelemetryClass.h \ TranslationClass.h \ UserInterface.h \ - anpro/JSHighlighter.h \ + anpro/imagecropper.h \ + anpro/imagecropper_e.h \ + anpro/imagecropper_p.h \ pcg/pcg_basic.h \ tmext/TelemetryClassAuthenticator.h \ + uimod/JSHighlighter.h \ uimod/UiModLabel.h \ uimod/UiModWidget.h diff --git a/res/gta5sync.ts b/res/gta5sync.ts index f522acb..4a8768a 100644 --- a/res/gta5sync.ts +++ b/res/gta5sync.ts @@ -252,8 +252,8 @@ Pictures and Savegames - - + + Background Colour: <span style="color: %1">%1</span> @@ -270,8 +270,8 @@ Pictures and Savegames - - + + Background Image: @@ -306,67 +306,87 @@ Pictures and Savegames - + Import picture - + &OK - + Discard picture - + &Cancel - + &Import new Picture... - + + &Crop Picture... + + + + Custom Avatar Custom Avatar Description in SC, don't use Special Character! - + Custom Picture Custom Picture Description in SC, don't use Special Character! - + + Crop Picture... + + + + + &Crop + + + + + Crop Picture + + + + Snapmatic Avatar Zone - + Are you sure to use a square image outside of the Avatar Zone? When you want to use it as Avatar the image will be detached! - + Select Colour... - + Background Image: %1 - + File Background Image: File @@ -1108,8 +1128,8 @@ Press 1 for Default View - - + + @@ -1120,12 +1140,12 @@ Press 1 for Default View - - - - - - + + + + + + @@ -1145,16 +1165,16 @@ Press 1 for Default View - - + + All image files (%1) - - + + All files (**) @@ -1162,16 +1182,16 @@ Press 1 for Default View - - + + Can't import %1 because file can't be open - - + + Can't import %1 because file can't be parsed properly diff --git a/res/gta5sync_de.qm b/res/gta5sync_de.qm index b56d18eaa80b8f1dc7f36432d0c204b9f7be91dd..f97f7350aa240cbb22702f9e6dbcab627ff21f4b 100644 GIT binary patch delta 3433 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 - - + + Background Colour: <span style="color: %1">%1</span> Hintergrundfarbe: <span style="color: %1">%1</span> @@ -289,7 +289,7 @@ Snapmatic Bilder und Spielständen Hintergrundbild entfernen - + Background Image: %1 Hintergrundbild: %1 @@ -314,70 +314,90 @@ Snapmatic Bilder und Spielständen &Optionen - + Import picture Bild importieren - + &OK &OK - + Discard picture Bild verwerfen - + &Cancel Abbre&chen - - + + Background Image: Hintergrundbild: - + &Import new Picture... Neues Bild &importieren... - + + &Crop Picture... + Bild zu&schneiden... + + + Custom Avatar Custom Avatar Description in SC, don't use Special Character! Eigener Avatar - + Custom Picture Custom Picture Description in SC, don't use Special Character! Eigenes Bild - + + Crop Picture... + Bild zuschneiden... + + + + &Crop + Zu&schneiden + + + + Crop Picture + Bild zuschneiden + + + Are you sure to use a square image outside of the Avatar Zone? When you want to use it as Avatar the image will be detached! Bist du sicher ein Quadrat Bild außerhalb der Avatar Zone zu verwenden? Wenn du es als Avatar verwenden möchtest wird es abgetrennt! - + Snapmatic Avatar Zone Snapmatic Avatar Zone - + Select Colour... Farbe auswählen... - + File Background Image: File Datei @@ -1135,8 +1155,8 @@ Drücke 1 für Standardmodus - - + + @@ -1147,12 +1167,12 @@ Drücke 1 für Standardmodus - - - - - - + + + + + + @@ -1189,16 +1209,16 @@ Drücke 1 für Standardmodus - - + + All image files (%1) Alle Bilddateien (%1) - - + + All files (**) @@ -1233,16 +1253,16 @@ Drücke 1 für Standardmodus - - + + Can't import %1 because file can't be open Kann %1 nicht importieren weil die Datei nicht geöffnet werden kann - - + + Can't import %1 because file can't be parsed properly Kann %1 nicht importieren weil die Datei nicht richtig gelesen werden kann diff --git a/res/gta5sync_en_US.ts b/res/gta5sync_en_US.ts index 349ee1e..d7c7694 100644 --- a/res/gta5sync_en_US.ts +++ b/res/gta5sync_en_US.ts @@ -226,8 +226,8 @@ Pictures and Savegames - - + + Background Colour: <span style="color: %1">%1</span> Background Color: <span style="color: %1">%1</span> @@ -269,7 +269,7 @@ Pictures and Savegames - + Background Image: %1 @@ -304,69 +304,89 @@ Pictures and Savegames - + Import picture - + &OK - + Discard picture - + &Cancel - - + + Background Image: - + &Import new Picture... - + + &Crop Picture... + + + + Custom Avatar Custom Avatar Description in SC, don't use Special Character! - + Custom Picture Custom Picture Description in SC, don't use Special Character! - + + Crop Picture... + + + + + &Crop + + + + + Crop Picture + + + + Snapmatic Avatar Zone - + Are you sure to use a square image outside of the Avatar Zone? When you want to use it as Avatar the image will be detached! - + Select Colour... Select Color... - + File Background Image: File @@ -1128,8 +1148,8 @@ Press 1 for Default View - - + + @@ -1140,12 +1160,12 @@ Press 1 for Default View - - - - - - + + + + + + @@ -1188,16 +1208,16 @@ Press 1 for Default View - - + + All image files (%1) - - + + All files (**) @@ -1237,16 +1257,16 @@ Press 1 for Default View - - + + Can't import %1 because file can't be open - - + + Can't import %1 because file can't be parsed properly diff --git a/res/gta5sync_fr.ts b/res/gta5sync_fr.ts index b562fc0..abf9beb 100644 --- a/res/gta5sync_fr.ts +++ b/res/gta5sync_fr.ts @@ -262,8 +262,8 @@ et les fichiers de sauvegarde de Grand Theft Auto V - - + + Background Colour: <span style="color: %1">%1</span> Couleur de fond : <span style="color: %1">%1</span> @@ -289,7 +289,7 @@ et les fichiers de sauvegarde de Grand Theft Auto V - + Background Image: %1 Image de fond : %1 @@ -314,70 +314,90 @@ et les fichiers de sauvegarde de Grand Theft Auto V - + Import picture Importer l'image - + &OK &OK - + Discard picture Supprimer l'image - + &Cancel A&nnuler - - + + Background Image: Image de fond : - + &Import new Picture... - + + &Crop Picture... + + + + Custom Avatar Custom Avatar Description in SC, don't use Special Character! Avatar personnalisé - + Custom Picture Custom Picture Description in SC, don't use Special Character! Image personnalisé - + + Crop Picture... + + + + + &Crop + + + + + Crop Picture + + + + Are you sure to use a square image outside of the Avatar Zone? When you want to use it as Avatar the image will be detached! Êtes-vous sûr d'utiliser une image carrée en dehors de la Zone d'Avatar ? Si vous l'utilisez comme Avatar, l'image sera détachée ! - + Snapmatic Avatar Zone Zone d'Avatar Snapmatic - + Select Colour... Choisir une couleur... - + File Background Image: File Fichier @@ -1146,8 +1166,8 @@ Appuyer sur 1 pour le mode par défaut - - + + @@ -1158,12 +1178,12 @@ Appuyer sur 1 pour le mode par défaut - - - - - - + + + + + + @@ -1195,16 +1215,16 @@ Appuyer sur 1 pour le mode par défaut - - + + All image files (%1) Toutes les images (%1) - - + + All files (**) @@ -1251,16 +1271,16 @@ Appuyer sur 1 pour le mode par défaut - - + + Can't import %1 because file can't be open Impossible d'importer %1, le fichier ne peut pas être ouvert - - + + Can't import %1 because file can't be parsed properly Impossible d'importer %1, le fichier ne peut pas être parsé correctement diff --git a/res/gta5sync_ru.ts b/res/gta5sync_ru.ts index 0b761a2..48d7957 100644 --- a/res/gta5sync_ru.ts +++ b/res/gta5sync_ru.ts @@ -264,8 +264,8 @@ Pictures and Savegames - - + + Background Colour: <span style="color: %1">%1</span> Цвет фона: <span style="color: %1">%1</span> @@ -291,7 +291,7 @@ Pictures and Savegames - + Background Image: %1 Фоновая картинка: %1 @@ -317,70 +317,90 @@ Pictures and Savegames - + Import picture Импортировать картинку - + &OK &ОК - + Discard picture Отклонить картинку - + &Cancel Я не уверен насчет горячих клавиш... От&мена - - + + Background Image: Фоновая картинка: - + &Import new Picture... - + + &Crop Picture... + + + + Custom Avatar Custom Avatar Description in SC, don't use Special Character! Свой Аватар - + Custom Picture Custom Picture Description in SC, don't use Special Character! Своя Картинка - + + Crop Picture... + + + + + &Crop + + + + + Crop Picture + + + + Are you sure to use a square image outside of the Avatar Zone? When you want to use it as Avatar the image will be detached! Ты точно хочешь использовать квадратное изображение вне зоны аватарки? Если это аватар, то изображение будет обрезано! - + Snapmatic Avatar Zone Зона Snapmatic Аватарки - + Select Colour... Выбрать цвет... - + File Background Image: File Файл @@ -1140,8 +1160,8 @@ Press 1 for Default View - - + + @@ -1152,12 +1172,12 @@ Press 1 for Default View - - - - - - + + + + + + @@ -1189,8 +1209,8 @@ Press 1 for Default View - - + + All files (**) @@ -1242,24 +1262,24 @@ Press 1 for Default View - - + + All image files (%1) Все файлы изображений (%1) - - + + Can't import %1 because file can't be open Не удалось открыть %1, файл не может быть открыт - - + + Can't import %1 because file can't be parsed properly Не получилось импортировать %1, файл не может быть правильно обработан diff --git a/res/gta5sync_uk.ts b/res/gta5sync_uk.ts index 4c095c1..7b18b5f 100644 --- a/res/gta5sync_uk.ts +++ b/res/gta5sync_uk.ts @@ -262,8 +262,8 @@ Pictures and Savegames - - + + Background Colour: <span style="color: %1">%1</span> Фоновий колір: <span style="color: %1">%1</span> @@ -280,8 +280,8 @@ Pictures and Savegames - - + + Background Image: Фонове зображення: @@ -316,68 +316,88 @@ Pictures and Savegames - + Import picture Імпортувати зображення - + &OK &OK - + Discard picture Відхилити зображення - + &Cancel &Скасувати - + &Import new Picture... - + + &Crop Picture... + + + + Custom Avatar Custom Avatar Description in SC, don't use Special Character! Користувацький Аватар - + Custom Picture Custom Picture Description in SC, don't use Special Character! Користувацьке Зображення - + + Crop Picture... + + + + + &Crop + + + + + Crop Picture + + + + Snapmatic Avatar Zone Зона Snapmatic Аватару - + Are you sure to use a square image outside of the Avatar Zone? When you want to use it as Avatar the image will be detached! Ви впевнені, що будете використовувати квадратне зображення поза зоною аватара? Якщо ви хочете використовувати його як Аватар, зображення буде відокремлено! - + Select Colour... Вибір кольору... - + Background Image: %1 Фонове зображення: %1 - + File Background Image: File Файл @@ -1126,8 +1146,8 @@ Press 1 for Default View - - + + @@ -1138,12 +1158,12 @@ Press 1 for Default View - - - - - - + + + + + + @@ -1163,16 +1183,16 @@ Press 1 for Default View - - + + All image files (%1) Файли зображень (%1) - - + + All files (**) @@ -1180,16 +1200,16 @@ Press 1 for Default View - - + + Can't import %1 because file can't be open Неможливо імпортувати %1, оскільки файл не може бути відкритий - - + + Can't import %1 because file can't be parsed properly Неможливо імпортувати %1, оскільки файл неможливо розібрати правильно diff --git a/res/gta5sync_zh_TW.ts b/res/gta5sync_zh_TW.ts index 3cccf8c..4dbd674 100644 --- a/res/gta5sync_zh_TW.ts +++ b/res/gta5sync_zh_TW.ts @@ -261,8 +261,8 @@ Pictures and Savegames - - + + Background Colour: <span style="color: %1">%1</span> 背景顏色: <span style="color: %1">%1</span> @@ -279,8 +279,8 @@ Pictures and Savegames - - + + Background Image: 背景圖片: @@ -315,67 +315,87 @@ Pictures and Savegames - + Import picture 匯入圖片 - + &OK 確定(&O) - + Discard picture 捨棄圖片 - + &Cancel 取消(&C) - + &Import new Picture... - + + &Crop Picture... + + + + Custom Avatar Custom Avatar Description in SC, don't use Special Character! 自訂大頭貼 - + Custom Picture Custom Picture Description in SC, don't use Special Character! 自訂圖片 - + + Crop Picture... + + + + + &Crop + + + + + Crop Picture + + + + Snapmatic Avatar Zone Snapmatic 大頭貼區域 - + Are you sure to use a square image outside of the Avatar Zone? When you want to use it as Avatar the image will be detached! 你確定要在大頭貼區域以外的地方使用方形圖片嗎? 作為大頭貼的圖片將被分離! - + Select Colour... 選擇顏色... - + Background Image: %1 背景圖片: %1 - + File Background Image: File 文件 @@ -1124,8 +1144,8 @@ Press 1 for Default View - - + + @@ -1136,12 +1156,12 @@ Press 1 for Default View - - - - - - + + + + + + @@ -1161,16 +1181,16 @@ Press 1 for Default View - - + + All image files (%1) 所有圖片 (%1) - - + + All files (**) @@ -1178,16 +1198,16 @@ Press 1 for Default View - - + + Can't import %1 because file can't be open 無法匯入 %1,因為檔案無法開啟 - - + + Can't import %1 because file can't be parsed properly 無法匯入 %1,因為檔案無法正確解析 diff --git a/anpro/JSHighlighter.cpp b/uimod/JSHighlighter.cpp similarity index 100% rename from anpro/JSHighlighter.cpp rename to uimod/JSHighlighter.cpp diff --git a/anpro/JSHighlighter.h b/uimod/JSHighlighter.h similarity index 100% rename from anpro/JSHighlighter.h rename to uimod/JSHighlighter.h