1
0
mirror of https://github.com/qTox/qTox.git synced 2024-03-22 14:00:36 +08:00

WIP: KSnapshot-like screenshot grabber

WIP of a screenshot grabber accessible from the chat form to allow
users to easily send a part of a screenshot
This commit is contained in:
Stefan Merettig 2015-03-09 13:32:30 -04:00 committed by tux3
parent 4e1dd74269
commit c6d5b4cc55
14 changed files with 988 additions and 16 deletions

View File

@ -407,7 +407,6 @@ contains(ENABLE_SYSTRAY_GTK_BACKEND, NO) {
src/offlinemsgengine.cpp \
src/misc/qrwidget.cpp \
src/widget/genericchatroomwidget.cpp
}
SOURCES += \
@ -434,6 +433,11 @@ SOURCES += \
src/core/corestructs.cpp \
src/profilelocker.cpp \
src/avatarbroadcaster.cpp
src/widget/tool/screenshotgrabber.cpp \
src/widget/tool/screengrabberchooserrectitem.cpp \
src/widget/tool/screengrabberoverlayitem.cpp \
src/widget/tool/toolboxgraphicsitem.cpp
HEADERS += \
src/audio.h \
@ -458,4 +462,9 @@ HEADERS += \
src/widget/gui.h \
src/toxme.h \
src/profilelocker.h \
src/avatarbroadcaster.h
src/avatarbroadcaster.h \
src/widget/tool/screenshotgrabber.h \
src/widget/tool/screengrabberchooserrectitem.hpp \
src/widget/tool/screengrabberoverlayitem.hpp \
src/widget/tool/toolboxgraphicsitem.hpp

View File

@ -23,6 +23,9 @@
#include <QFileInfo>
#include <QDragEnterEvent>
#include <QBitmap>
#include <QScreen>
#include <QTemporaryFile>
#include <QGuiApplication>
#include "chatform.h"
#include "src/core/core.h"
#include "src/friend.h"
@ -44,6 +47,7 @@
#include "src/chatlog/content/text.h"
#include "src/chatlog/chatlog.h"
#include "src/offlinemsgengine.h"
#include "src/widget/tool/screenshotgrabber.h"
ChatForm::ChatForm(Friend* chatFriend)
: f(chatFriend)
@ -81,6 +85,9 @@ ChatForm::ChatForm(Friend* chatFriend)
connect(Core::getInstance(), &Core::fileSendStarted, this, &ChatForm::startFileSend);
connect(sendButton, &QPushButton::clicked, this, &ChatForm::onSendTriggered);
connect(fileButton, &QPushButton::clicked, this, &ChatForm::onAttachClicked);
fileButton->setContextMenuPolicy(Qt::CustomContextMenu);
connect(fileButton, &QPushButton::customContextMenuRequested, this, &ChatForm::onAttachContext);
connect(screenshotAction, &QAction::triggered, this, &ChatForm::onScreenshotCreate);
connect(callButton, &QPushButton::clicked, this, &ChatForm::onCallTriggered);
connect(videoButton, &QPushButton::clicked, this, &ChatForm::onVideoCallTriggered);
connect(msgEdit, &ChatTextEdit::enterPressed, this, &ChatForm::onSendTriggered);
@ -858,6 +865,45 @@ void ChatForm::loadHistory(QDateTime since, bool processUndelivered)
chatWidget->verticalScrollBar()->setValue(savedSliderPos);
}
void ChatForm::onScreenshotCreate()
{
ScreenshotGrabber *screenshotGrabber = new ScreenshotGrabber (this);
connect(screenshotGrabber, &ScreenshotGrabber::screenshotTaken, this, &ChatForm::onScreenshotTaken);
// Try to not grab the context-menu
QTimer::singleShot(200, screenshotGrabber, &ScreenshotGrabber::showGrabber);
}
void ChatForm::onScreenshotTaken (const QPixmap &pixmap) {
QTemporaryFile file("qTox-Screenshot-XXXXXXXX.png");
if (!file.open())
{
QMessageBox::warning(this, tr("Failed to open temporary file", "Temporary file for screenshot"),
tr("qTox wasn't able to save the screenshot"));
return;
}
file.setAutoRemove(false);
pixmap.save(&file, "PNG");
long long filesize = file.size();
file.close();
QFileInfo fi(file);
emit sendFile(f->getFriendID(), fi.fileName(), fi.filePath(), filesize);
}
void ChatForm::onAttachContext(const QPoint &pos)
{
QMenu* context = new QMenu(fileButton);
context->addAction(screenshotAction);
context->exec(fileButton->mapToGlobal(pos));
}
void ChatForm::onLoadHistory()
{
LoadHistoryDialog dlg;

View File

@ -79,6 +79,7 @@ public slots:
void onVolMuteToggle();
void onAvatarChange(uint32_t FriendId, const QPixmap& pic);
void onAvatarRemoved(uint32_t FriendId);
void onAttachContext(const QPoint &pos);
private slots:
void onSendTriggered();
@ -94,6 +95,8 @@ private slots:
void onLoadHistory();
void onUpdateTime();
void onEnableCallButtons();
void onScreenshotCreate();
void onScreenshotTaken(const QPixmap &pixmap);
protected:
// drag & drop
@ -109,7 +112,7 @@ private:
int callId;
QLabel *callDuration;
QTimer *callDurationTimer;
QTimer typingTimer;
QTimer typingTimer;
QTimer *disableCallButtonsTimer;
QElapsedTimer timeElapsed;
OfflineMsgEngine *offlineEngine;

View File

@ -49,17 +49,17 @@ GenericChatForm::GenericChatForm(QWidget *parent)
nameLabel->setObjectName("nameLabel");
nameLabel->setMinimumHeight(Style::getFont(Style::Medium).pixelSize());
nameLabel->setEditable(true);
nameLabel->setTextFormat(Qt::PlainText);
nameLabel->setTextFormat(Qt::PlainText);
avatar = new MaskablePixmapWidget(this, QSize(40,40), ":/img/avatar_mask.svg");
QHBoxLayout *mainFootLayout = new QHBoxLayout(),
*headLayout = new QHBoxLayout();
QVBoxLayout *mainLayout = new QVBoxLayout(),
*footButtonsSmall = new QVBoxLayout(),
*micButtonsLayout = new QVBoxLayout();
headTextLayout = new QVBoxLayout();
headTextLayout = new QVBoxLayout();
QGridLayout *buttonsLayout = new QGridLayout();
chatWidget = new ChatLog(this);
@ -90,6 +90,8 @@ GenericChatForm::GenericChatForm(QWidget *parent)
// micButton->setFixedSize(25,20);
micButton->setToolTip("");
screenshotAction = new QAction(tr("Send screenshot"), nullptr);
footButtonsSmall->setSpacing(2);
msgEdit->setStyleSheet(Style::getStylesheet(":/ui/msgEdit/msgEdit.css"));
@ -127,29 +129,29 @@ GenericChatForm::GenericChatForm(QWidget *parent)
mainFootLayout->addSpacing(5);
mainFootLayout->addWidget(sendButton);
mainFootLayout->setSpacing(0);
headTextLayout->addStretch();
headTextLayout->addStretch();
headTextLayout->addWidget(nameLabel);
headTextLayout->addStretch();
micButtonsLayout->setSpacing(0);
micButtonsLayout->addWidget(micButton, Qt::AlignTop | Qt::AlignRight);
micButtonsLayout->addSpacing(4);
micButtonsLayout->addWidget(volButton, Qt::AlignTop | Qt::AlignRight);
buttonsLayout->addLayout(micButtonsLayout, 0, 0, 2, 1, Qt::AlignTop | Qt::AlignRight);
buttonsLayout->addWidget(callButton, 0, 1, 2, 1, Qt::AlignTop);
buttonsLayout->addWidget(videoButton, 0, 2, 2, 1, Qt::AlignTop);
buttonsLayout->setVerticalSpacing(0);
buttonsLayout->setHorizontalSpacing(4);
headLayout->addWidget(avatar);
headLayout->addSpacing(5);
headLayout->addLayout(headTextLayout);
headLayout->addLayout(buttonsLayout);
headWidget->setLayout(headLayout);
//Fix for incorrect layouts on OS X as per
//https://bugreports.qt-project.org/browse/QTBUG-14591
sendButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);

View File

@ -90,6 +90,7 @@ protected:
MaskablePixmapWidget *avatar;
QWidget *headWidget;
QPushButton *fileButton, *emoteButton, *callButton, *videoButton, *volButton, *micButton;
QAction *screenshotAction;
QVBoxLayout *headTextLayout;
ChatTextEdit *msgEdit;
QPushButton *sendButton;

View File

@ -0,0 +1,316 @@
/*
Copyright (C) 2014 by Project Tox <https://tox.im>
This file is part of qTox, a Qt-based graphical interface for Tox.
This program is libre 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 3 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 COPYING file for more details.
*/
#include "screengrabberchooserrectitem.hpp"
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsScene>
#include <QPainter>
#include <QCursor>
enum { HandleSize = 10 };
ScreenGrabberChooserRectItem::ScreenGrabberChooserRectItem(QGraphicsScene* scene)
{
scene->addItem(this);
setCursor(QCursor(Qt::OpenHandCursor));
this->mainRect = createHandleItem(scene);
this->topLeft = createHandleItem(scene);
this->topCenter = createHandleItem(scene);
this->topRight = createHandleItem(scene);
this->rightCenter = createHandleItem(scene);
this->bottomRight = createHandleItem(scene);
this->bottomCenter = createHandleItem(scene);
this->bottomLeft = createHandleItem(scene);
this->leftCenter = createHandleItem(scene);
this->topLeft->setCursor(QCursor(Qt::SizeFDiagCursor));
this->bottomRight->setCursor(QCursor(Qt::SizeFDiagCursor));
this->topRight->setCursor(QCursor(Qt::SizeBDiagCursor));
this->bottomLeft->setCursor(QCursor(Qt::SizeBDiagCursor));
this->leftCenter->setCursor(QCursor(Qt::SizeHorCursor));
this->rightCenter->setCursor(QCursor(Qt::SizeHorCursor));
this->topCenter->setCursor(QCursor(Qt::SizeVerCursor));
this->bottomCenter->setCursor(QCursor(Qt::SizeVerCursor));
this->mainRect->setRect(QRect());
hideHandles();
}
ScreenGrabberChooserRectItem::~ScreenGrabberChooserRectItem()
{
}
QRectF ScreenGrabberChooserRectItem::boundingRect() const
{
return QRectF(0, 0, this->rectWidth, this->rectHeight);
}
void ScreenGrabberChooserRectItem::beginResize()
{
this->rectWidth = this->rectHeight = 0;
this->state = Resizing;
setCursor(QCursor(Qt::CrossCursor));
hideHandles();
this->mainRect->grabMouse();
}
QRect ScreenGrabberChooserRectItem::chosenRect() const
{
QRect rect (x(), y(), this->rectWidth, this->rectHeight);
return rect.normalized();
}
void ScreenGrabberChooserRectItem::showHandles()
{
this->topLeft->show();
this->topCenter->show();
this->topRight->show();
this->rightCenter->show();
this->bottomRight->show();
this->bottomCenter->show();
this->bottomLeft->show();
this->leftCenter->show();
}
void ScreenGrabberChooserRectItem::hideHandles()
{
this->topLeft->hide();
this->topCenter->hide();
this->topRight->hide();
this->rightCenter->hide();
this->bottomRight->hide();
this->bottomCenter->hide();
this->bottomLeft->hide();
this->leftCenter->hide();
}
void ScreenGrabberChooserRectItem::mousePress(QGraphicsSceneMouseEvent* event)
{
if (event->button() == Qt::LeftButton)
{
this->state = Moving;
setCursor(QCursor(Qt::ClosedHandCursor));
}
}
void ScreenGrabberChooserRectItem::mouseMove(QGraphicsSceneMouseEvent* event)
{
if (this->state == Moving)
{
QPointF delta = event->scenePos() - event->lastScenePos();
moveBy (delta.x(), delta.y());
}
else if (this->state == Resizing)
{
prepareGeometryChange();
QPointF size = event->scenePos() - scenePos();
this->mainRect->setRect (0, 0, size.x(), size.y());
this->rectWidth = size.x();
this->rectHeight = size.y();
updateHandlePositions();
}
else
{
return;
}
emit regionChosen(chosenRect());
scene()->update();
}
void ScreenGrabberChooserRectItem::mouseRelease(QGraphicsSceneMouseEvent* event)
{
if (event->button() == Qt::LeftButton)
{
setCursor(QCursor(Qt::OpenHandCursor));
emit regionChosen(chosenRect());
this->state = None;
this->mainRect->ungrabMouse();
showHandles();
}
}
void ScreenGrabberChooserRectItem::mouseDoubleClick(QGraphicsSceneMouseEvent* event)
{
Q_UNUSED(event);
emit doubleClicked();
}
void ScreenGrabberChooserRectItem::mousePressHandle(int x, int y, QGraphicsSceneMouseEvent* event)
{
Q_UNUSED(x);
Q_UNUSED(y);
if(event->button() == Qt::LeftButton)
this->state = HandleResizing;
}
void ScreenGrabberChooserRectItem::mouseMoveHandle(int x, int y, QGraphicsSceneMouseEvent* event)
{
if (this->state != HandleResizing)
return;
QPointF delta = event->scenePos() - event->lastScenePos();
delta.rx() *= qreal(std::abs(x));
delta.ry() *= qreal(std::abs(y));
// We increase if the multiplier and the delta have the same sign
bool increaseX = ((x < 0) == (delta.x() < 0));
bool increaseY = ((y < 0) == (delta.y() < 0));
if((delta.x() < 0 && increaseX) || (delta.x() >= 0 && !increaseX))
{
moveBy(delta.x(), 0);
delta.rx() *= -1;
}
if((delta.y() < 0 && increaseY) || (delta.y() >= 0 && !increaseY))
{
moveBy(0, delta.y());
delta.ry() *= -1;
}
//
this->rectWidth += delta.x();
this->rectHeight += delta.y();
this->mainRect->setRect (0, 0, this->rectWidth, this->rectHeight);
updateHandlePositions();
emit regionChosen(chosenRect());
}
void ScreenGrabberChooserRectItem::mouseReleaseHandle(int x, int y, QGraphicsSceneMouseEvent* event)
{
Q_UNUSED(x);
Q_UNUSED(y);
if (event->button() == Qt::LeftButton)
this->state = None;
}
QPoint ScreenGrabberChooserRectItem::getHandleMultiplier(QGraphicsItem* handle)
{
if (handle == this->topLeft)
return QPoint(-1, -1);
if (handle == this->topCenter)
return QPoint(0, -1);
if (handle == this->topRight)
return QPoint(1, -1);
if (handle == this->rightCenter)
return QPoint(1, 0);
if (handle == this->bottomRight)
return QPoint(1, 1);
if (handle == this->bottomCenter)
return QPoint(0, 1);
if (handle == this->bottomLeft)
return QPoint(-1, 1);
if (handle == this->leftCenter)
return QPoint(-1, 0);
return QPoint();
}
void ScreenGrabberChooserRectItem::updateHandlePositions()
{
this->topLeft->setPos(-HandleSize, -HandleSize);
this->topCenter->setPos((this->rectWidth - HandleSize) / 2, -HandleSize);
this->topRight->setPos(this->rectWidth, -HandleSize);
this->rightCenter->setPos(this->rectWidth, (this->rectHeight - HandleSize) / 2);
this->bottomRight->setPos(this->rectWidth, this->rectHeight);
this->bottomCenter->setPos((this->rectWidth - HandleSize) / 2, this->rectHeight);
this->bottomLeft->setPos(-HandleSize, this->rectHeight);
this->leftCenter->setPos(-HandleSize, (this->rectHeight - HandleSize) / 2);
}
QGraphicsRectItem* ScreenGrabberChooserRectItem::createHandleItem(QGraphicsScene* scene)
{
QGraphicsRectItem* handle = new QGraphicsRectItem(0, 0, HandleSize, HandleSize);
handle->setPen(QPen(Qt::blue));
handle->setBrush(Qt::NoBrush);
scene->addItem(handle);
addToGroup(handle);
handle->installSceneEventFilter(this);
return handle;
}
bool ScreenGrabberChooserRectItem::sceneEventFilter(QGraphicsItem* watched, QEvent* event)
{
if (watched == this->mainRect)
forwardMainRectEvent(event);
else
forwardHandleEvent(watched, event);
return true;
}
void ScreenGrabberChooserRectItem::forwardMainRectEvent(QEvent* event)
{
QGraphicsSceneMouseEvent* mouseEvent = static_cast<QGraphicsSceneMouseEvent*>(event);
switch(event->type())
{
case QEvent::GraphicsSceneMousePress:
return mousePress(mouseEvent);
case QEvent::GraphicsSceneMouseMove:
return mouseMove(mouseEvent);
case QEvent::GraphicsSceneMouseRelease:
return mouseRelease(mouseEvent);
case QEvent::GraphicsSceneMouseDoubleClick:
return mouseDoubleClick(mouseEvent);
default:
return;
}
}
void ScreenGrabberChooserRectItem::forwardHandleEvent(QGraphicsItem* watched, QEvent* event)
{
QGraphicsSceneMouseEvent* mouseEvent = static_cast<QGraphicsSceneMouseEvent*>(event);
QPoint multiplier = getHandleMultiplier(watched);
if (multiplier.isNull())
return;
switch(event->type())
{
case QEvent::GraphicsSceneMousePress:
return mousePressHandle(multiplier.x(), multiplier.y(), mouseEvent);
case QEvent::GraphicsSceneMouseMove:
return mouseMoveHandle(multiplier.x(), multiplier.y(), mouseEvent);
case QEvent::GraphicsSceneMouseRelease:
return mouseReleaseHandle(multiplier.x(), multiplier.y(), mouseEvent);
default:
return;
}
}

View File

@ -0,0 +1,89 @@
/*
Copyright (C) 2014 by Project Tox <https://tox.im>
This file is part of qTox, a Qt-based graphical interface for Tox.
This program is libre 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 3 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 COPYING file for more details.
*/
#ifndef SCREENGRABBERCHOOSERRECTITEM_HPP
#define SCREENGRABBERCHOOSERRECTITEM_HPP
#include <QGraphicsItemGroup>
class ScreenGrabberChooserRectItem : public QObject, public QGraphicsItemGroup
{
Q_OBJECT
public:
ScreenGrabberChooserRectItem(QGraphicsScene* scene);
~ScreenGrabberChooserRectItem();
QRectF boundingRect() const;
void beginResize();
QRect chosenRect() const;
void showHandles();
void hideHandles();
signals:
void doubleClicked();
void regionChosen(QRect rect);
protected:
bool sceneEventFilter(QGraphicsItem* watched, QEvent* event);
private:
enum State {
None,
Resizing,
HandleResizing,
Moving,
};
State state = None;
int rectWidth = 0;
int rectHeight = 0;
void forwardMainRectEvent(QEvent* event);
void forwardHandleEvent(QGraphicsItem* watched, QEvent* event);
void mousePress(QGraphicsSceneMouseEvent* event);
void mouseMove(QGraphicsSceneMouseEvent* event);
void mouseRelease(QGraphicsSceneMouseEvent* event);
void mouseDoubleClick(QGraphicsSceneMouseEvent* event);
void mousePressHandle(int x, int y, QGraphicsSceneMouseEvent* event);
void mouseMoveHandle(int x, int y, QGraphicsSceneMouseEvent* event);
void mouseReleaseHandle(int x, int y, QGraphicsSceneMouseEvent* event);
QPoint getHandleMultiplier(QGraphicsItem* handle);
void updateHandlePositions();
QGraphicsRectItem* createHandleItem(QGraphicsScene* scene);
QGraphicsRectItem* mainRect;
QGraphicsRectItem* topLeft;
QGraphicsRectItem* topCenter;
QGraphicsRectItem* topRight;
QGraphicsRectItem* rightCenter;
QGraphicsRectItem* bottomRight;
QGraphicsRectItem* bottomCenter;
QGraphicsRectItem* bottomLeft;
QGraphicsRectItem* leftCenter;
};
#endif // SCREENGRABBERCHOOSERRECTITEM_HPP

View File

@ -0,0 +1,81 @@
/*
Copyright (C) 2014 by Project Tox <https://tox.im>
This file is part of qTox, a Qt-based graphical interface for Tox.
This program is libre 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 3 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 COPYING file for more details.
*/
#include "screengrabberoverlayitem.hpp"
#include <QGraphicsSceneMouseEvent>
#include <QPainter>
#include <QPen>
#include "screenshotgrabber.h"
ScreenGrabberOverlayItem::ScreenGrabberOverlayItem(ScreenshotGrabber* grabber)
: screnshootGrabber(grabber)
{
QBrush overlayBrush(QColor(0x00, 0x00, 0x00, 0x70)); // Translucent black
setCursor(QCursor(Qt::CrossCursor));
setBrush(overlayBrush);
setPen(QPen(Qt::NoPen));
}
ScreenGrabberOverlayItem::~ScreenGrabberOverlayItem()
{
}
void ScreenGrabberOverlayItem::setChosenRect(QRect rect)
{
this->chosenRect = rect;
update();
}
void ScreenGrabberOverlayItem::mousePressEvent(QGraphicsSceneMouseEvent* event)
{
if (event->button() == Qt::LeftButton)
this->screnshootGrabber->beginRectChooser(event);
}
void ScreenGrabberOverlayItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
if (!this->chosenRect.isValid())
{
QGraphicsRectItem::paint(painter, option, widget);
return;
}
//
painter->save();
painter->setBrush(brush());
painter->setPen(pen());
QRectF self = rect();
qreal leftX = chosenRect.x();
qreal rightX = chosenRect.x() + chosenRect.width();
qreal topY = chosenRect.y();
qreal bottomY = chosenRect.y() + chosenRect.height();
painter->drawRect(0, 0, leftX, self.height()); // Left of chosen
painter->drawRect(rightX, 0, self.width() - rightX, self.height()); // Right of chosen
painter->drawRect(leftX, 0, chosenRect.width(), topY); // Top of chosen
painter->drawRect(leftX, bottomY, chosenRect.width(), self.height() - bottomY); // Bottom of chosen
painter->restore();
}

View File

@ -0,0 +1,46 @@
/*
Copyright (C) 2014 by Project Tox <https://tox.im>
This file is part of qTox, a Qt-based graphical interface for Tox.
This program is libre 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 3 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 COPYING file for more details.
*/
#ifndef SCREENGRABBEROVERLAYITEM_HPP
#define SCREENGRABBEROVERLAYITEM_HPP
#include <QGraphicsRectItem>
class ScreenshotGrabber;
class ScreenGrabberOverlayItem : public QObject, public QGraphicsRectItem
{
Q_OBJECT
public:
ScreenGrabberOverlayItem(ScreenshotGrabber* grabber);
~ScreenGrabberOverlayItem();
void setChosenRect(QRect rect);
void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget);
protected:
void mousePressEvent(QGraphicsSceneMouseEvent* event);
private:
ScreenshotGrabber* screnshootGrabber;
QRect chosenRect;
};
#endif // SCREENGRABBEROVERLAYITEM_HPP

View File

@ -0,0 +1,183 @@
/*
Copyright (C) 2015 by Project Tox <https://tox.im>
This file is part of qTox, a Qt-based graphical interface for Tox.
This program is libre 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 3 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 COPYING file for more details.
*/
#include "screenshotgrabber.h"
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsPixmapItem>
#include <QGraphicsRectItem>
#include <QDesktopWidget>
#include <QGraphicsView>
#include <QApplication>
#include <QMouseEvent>
#include <QScreen>
#include <QDebug>
#include "screengrabberchooserrectitem.hpp"
#include "screengrabberoverlayitem.hpp"
#include "toolboxgraphicsitem.hpp"
ScreenshotGrabber::ScreenshotGrabber(QWidget* parent)
: QWidget(parent)
{
QGraphicsScene* scene = new QGraphicsScene;
this->window = new QGraphicsView (scene); // Top-level widget
setupWindow();
setupScene(scene);
installEventFilter(this);
}
ScreenshotGrabber::~ScreenshotGrabber()
{
}
bool ScreenshotGrabber::eventFilter(QObject* object, QEvent* event)
{
if (event->type() == QEvent::KeyPress)
return handleKeyPress(static_cast<QKeyEvent*>(event));
return QWidget::eventFilter(object, event);
}
void ScreenshotGrabber::showGrabber()
{
this->screenGrab = grabScreen();
this->screenGrabDisplay->setPixmap(this->screenGrab);
this->window->show();
this->window->setFocus();
this->window->grabKeyboard();
adjustWindowSize();
adjustTooltipPosition();
}
bool ScreenshotGrabber::handleKeyPress(QKeyEvent* event)
{
if (event->key() == Qt::Key_Escape)
reject();
else if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)
acceptRegion();
else
return false;
return true;
}
void ScreenshotGrabber::acceptRegion()
{
QRect rect = this->chooserRect->chosenRect();
if (rect.width() < 1 || rect.height() < 1)
return;
//
qDebug() << "Screenshot accepted, chosen region" << rect;
emit screenshotTaken(this->screenGrab.copy(rect));
this->window->close();
}
void ScreenshotGrabber::setupWindow()
{
this->window->setWindowFlags(Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint);
this->window->setAttribute(Qt::WA_DeleteOnClose);
this->window->setContentsMargins(0, 0, 0, 0);
this->window->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
this->window->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
this->window->setFrameShape(QFrame::NoFrame);
connect(this->window, &QObject::destroyed, this, &QObject::deleteLater);
this->window->installEventFilter(this);
}
void ScreenshotGrabber::setupScene(QGraphicsScene* scene)
{
this->overlay = new ScreenGrabberOverlayItem(this);
this->helperToolbox = new ToolBoxGraphicsItem;
this->screenGrabDisplay = scene->addPixmap(this->screenGrab);
this->helperTooltip = scene->addText(QString());
scene->addItem(this->overlay);
this->chooserRect = new ScreenGrabberChooserRectItem(scene);
scene->addItem(this->helperToolbox);
this->helperToolbox->addToGroup(this->helperTooltip);
this->helperTooltip->setDefaultTextColor(Qt::black);
useNothingSelectedTooltip();
connect(this->chooserRect, &ScreenGrabberChooserRectItem::doubleClicked, this, &ScreenshotGrabber::acceptRegion);
connect(this->chooserRect, &ScreenGrabberChooserRectItem::regionChosen, this, &ScreenshotGrabber::useRegionSelectedTooltip);
connect(this->chooserRect, &ScreenGrabberChooserRectItem::regionChosen, this->overlay, &ScreenGrabberOverlayItem::setChosenRect);
}
void ScreenshotGrabber::useNothingSelectedTooltip()
{
this->helperTooltip->setHtml(tr("Click and drag to select a region to select it. Press <b>ESC</b> to cancel.",
"Help text shown when no region has been selected yet"));
adjustTooltipPosition();
}
void ScreenshotGrabber::useRegionSelectedTooltip()
{
this->helperTooltip->setHtml(tr("Press <b>Return</b> to accept, or move and resize the selected region.",
"Help text shown when a region has been selected"));
adjustTooltipPosition();
}
void ScreenshotGrabber::adjustTooltipPosition()
{
QRectF size = this->helperToolbox->childrenBoundingRect();
QRect screenRect = QApplication::desktop()->screen()->rect();
// Align the toolbox center-top.
this->helperToolbox->setX(screenRect.x() + (screenRect.width() - size.width() + size.x()) / 2);
this->helperToolbox->setY(screenRect.y());
}
void ScreenshotGrabber::reject()
{
qDebug() << "Rejected screenshot";
this->window->close();
}
QRect ScreenshotGrabber::getSystemScreenRect()
{
return QApplication::primaryScreen()->virtualGeometry();
}
void ScreenshotGrabber::adjustWindowSize()
{
QRect systemScreenRect = getSystemScreenRect();
qDebug() << "adjusting grabber size to" << systemScreenRect;
this->window->setGeometry(systemScreenRect);
this->window->scene()->setSceneRect(systemScreenRect);
this->overlay->setRect(systemScreenRect);
}
QPixmap ScreenshotGrabber::grabScreen() {
return QApplication::primaryScreen()->grabWindow(QApplication::desktop()->winId());
}
void ScreenshotGrabber::beginRectChooser(QGraphicsSceneMouseEvent* event)
{
QPointF pos = event->scenePos();
this->chooserRect->setX(pos.x());
this->chooserRect->setY(pos.y());
this->chooserRect->beginResize();
}

View File

@ -0,0 +1,84 @@
/*
Copyright (C) 2015 by Project Tox <https://tox.im>
This file is part of qTox, a Qt-based graphical interface for Tox.
This program is libre 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 3 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 COPYING file for more details.
*/
#ifndef SCREENSHOTGRABBER_H
#define SCREENSHOTGRABBER_H
#include <QWidget>
#include <QPixmap>
#include <QPoint>
class ScreenGrabberChooserRectItem;
class QGraphicsSceneMouseEvent;
class ScreenGrabberOverlayItem;
class QGraphicsPixmapItem;
class ToolBoxGraphicsItem;
class QGraphicsRectItem;
class QGraphicsTextItem;
class QGraphicsScene;
class QGraphicsView;
class ScreenshotGrabber : public QWidget
{
Q_OBJECT
public:
ScreenshotGrabber(QWidget* parent);
~ScreenshotGrabber() override;
bool eventFilter(QObject* object, QEvent* event);
public slots:
void showGrabber();
void acceptRegion();
signals:
void screenshotTaken(const QPixmap &pixmap);
void rejected();
private:
friend class ScreenGrabberOverlayItem;
void setupWindow();
void setupScene(QGraphicsScene* scene);
void useNothingSelectedTooltip();
void useRegionSelectedTooltip();
void adjustTooltipPosition();
bool handleKeyPress(QKeyEvent* event);
void reject();
QRect getSystemScreenRect();
void adjustWindowSize();
QPixmap grabScreen();
void beginRectChooser(QGraphicsSceneMouseEvent* event);
QPixmap screenGrab;
QGraphicsView* window;
QGraphicsPixmapItem* screenGrabDisplay;
ScreenGrabberOverlayItem* overlay;
ScreenGrabberChooserRectItem* chooserRect;
ToolBoxGraphicsItem* helperToolbox;
QGraphicsTextItem* helperTooltip;
};
#endif // SCREENSHOTGRABBER_H

View File

@ -0,0 +1,64 @@
/*
Copyright (C) 2014 by Project Tox <https://tox.im>
This file is part of qTox, a Qt-based graphical interface for Tox.
This program is libre 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 3 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 COPYING file for more details.
*/
#include "toolboxgraphicsitem.hpp"
#include <QPainter>
ToolBoxGraphicsItem::ToolBoxGraphicsItem()
{
this->opacityAnimation = new QPropertyAnimation(this, QByteArrayLiteral("opacity"), this);
this->opacityAnimation->setKeyValueAt(0, this->idleOpacity);
this->opacityAnimation->setKeyValueAt(1, this->activeOpacity);
this->opacityAnimation->setDuration(this->fadeTimeMs);
setOpacity(this->idleOpacity);
}
ToolBoxGraphicsItem::~ToolBoxGraphicsItem()
{
}
void ToolBoxGraphicsItem::hoverEnterEvent(QGraphicsSceneHoverEvent* event)
{
startAnimation(QAbstractAnimation::Forward);
QGraphicsItemGroup::hoverEnterEvent(event);
}
void ToolBoxGraphicsItem::hoverLeaveEvent(QGraphicsSceneHoverEvent* event)
{
startAnimation(QAbstractAnimation::Backward);
QGraphicsItemGroup::hoverLeaveEvent(event);
}
void ToolBoxGraphicsItem::startAnimation(QAbstractAnimation::Direction direction)
{
this->opacityAnimation->setDirection(direction);
this->opacityAnimation->start();
}
void ToolBoxGraphicsItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
painter->save();
painter->setPen(Qt::NoPen);
painter->setBrush(QBrush(QColor(0xFF, 0xE2, 0x82)));
painter->drawRect(childrenBoundingRect());
painter->restore();
QGraphicsItemGroup::paint(painter, option, widget);
}

View File

@ -0,0 +1,49 @@
/*
Copyright (C) 2014 by Project Tox <https://tox.im>
This file is part of qTox, a Qt-based graphical interface for Tox.
This program is libre 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 3 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 COPYING file for more details.
*/
#ifndef TOOLBOXGRAPHICSITEM_HPP
#define TOOLBOXGRAPHICSITEM_HPP
#include <QGraphicsItemGroup>
#include <QPropertyAnimation>
#include <QObject>
class ToolBoxGraphicsItem : public QObject, public QGraphicsItemGroup
{
Q_OBJECT
Q_PROPERTY(qreal opacity READ opacity WRITE setOpacity)
public:
ToolBoxGraphicsItem();
~ToolBoxGraphicsItem();
void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget);
protected:
void hoverEnterEvent(QGraphicsSceneHoverEvent* event);
void hoverLeaveEvent(QGraphicsSceneHoverEvent* event);
private:
void startAnimation(QAbstractAnimation::Direction direction);
QPropertyAnimation* opacityAnimation;
qreal idleOpacity = 0.7f;
qreal activeOpacity = 1.0f;
int fadeTimeMs = 300;
};
#endif // TOOLBOXGRAPHICSITEM_HPP

View File

@ -10,7 +10,7 @@ QPushButton
height: 24px;
}
QPushButton:hover
QAbstractButton:hover
{
background-color: #79c76f;
}
@ -25,7 +25,6 @@ QPushButton[enabled="false"]
background-color: #919191;
}
QPushButton:focus
{
QPushButton:focus {
outline: none;
}