Files
GoldenCheetah/src/GcOverlayWidget.cpp
2015-11-08 23:45:00 +01:00

464 lines
15 KiB
C++

/*
* Copyright (c) 2014 Mark Liversedge (liversedge@gmail.com)
* (c) Aleksey Osipov (aliks-os@yandex.ru)
*
* Some of the code pinched from http://qt-project.org/wiki/Widget-moveable-and-resizeable
* coz it was simpler than starting from scratch.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "GcOverlayWidget.h"
#include "GcScopeBar.h"
#include "DiaryWindow.h"
#include "DiarySidebar.h"
#include "Context.h"
#include "QtMacButton.h"
GcOverlayWidget::GcOverlayWidget(Context *context, QWidget *parent) : QWidget(parent), context(context)
{
// left / right scroller icon
static QIcon leftIcon = iconFromPNG(":images/mac/left.png");
static QIcon rightIcon = iconFromPNG(":images/mac/right.png");
setContentsMargins(4,0,4,4);
setAutoFillBackground(false);
setAttribute(Qt::WA_TranslucentBackground);
setMouseTracking(true);
setFocusPolicy(Qt::ClickFocus);
#ifdef GC_HAVE_MUMODEL
setMinimumSize(400,200); //XX temp for MU model...
#else
setMinimumSize(250,200);
#endif
setFocus();
mode = none;
initial = true;
// main layout
QVBoxLayout *mlayout = new QVBoxLayout(this);
mlayout->setSpacing(0);
mlayout->setContentsMargins(1,0,1,1);
QHBoxLayout *titleLayout = new QHBoxLayout;
titleLayout->setSpacing(0);
titleLayout->setContentsMargins(0,0,0,0);
mlayout->addLayout(titleLayout);
// scroller buttons
left = new QToolButton(this);
left->setStyleSheet("QToolButton { border: none; padding: 0px; }");
left->setAutoFillBackground(false);
left->setFixedSize(23,23);
left->setIcon(leftIcon);
left->setIconSize(QSize(23,23));
left->setFocusPolicy(Qt::NoFocus);
left->hide(); // don't show until we have >1 widgets
titleLayout->addWidget(left);
connect(left, SIGNAL(clicked()), this, SLOT(scrollLeft()));
titleLabel = new GcLabel("No Title Set");
titleLabel->setAutoFillBackground(false);
titleLabel->setFixedHeight(23);
// menu bar in the middle of the buttons
titleLayout->addStretch();
titleLayout->addWidget(titleLabel);
titleLayout->addStretch();
right = new QToolButton(this);
right->setStyleSheet("QToolButton { border: none; padding: 0px; }");
right->setAutoFillBackground(false);
right->setFixedSize(20,20);
right->setIcon(rightIcon);
right->setIconSize(QSize(20,20));
right->setFocusPolicy(Qt::NoFocus);
right->hide();
titleLayout->addWidget(right);
connect(right, SIGNAL(clicked()), this, SLOT(scrollRight()));
stack = new QStackedWidget(this);
stack->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
mlayout->addWidget(stack);
// trap resize / mouse events
m_infocus = true;
m_showMenu = false;
m_isEditing = true;
installEventFilter(parent);
connect(context, SIGNAL(configChanged(qint32)), this, SLOT(configChanged(qint32)));
// setup colors
configChanged(CONFIG_APPEARANCE);
}
void
GcOverlayWidget::configChanged(qint32)
{
if (GCColor::isFlat()) {
titleLabel->setStyleSheet(QString("color: %1;").arg(GCColor::invertColor(GColor(CCHROME)).name()));
} else {
titleLabel->setStyleSheet("color: black;");
}
}
void
GcOverlayWidget::addWidget(QString title, QWidget *widget)
{
// we want this one
//widget->setParent(this);
//widget->releaseMouse();
//widget->setAttribute(Qt::WA_TransparentForMouseEvents, true);
// add to list
items << GcOverlayWidgetItem(title, widget);
stack->addWidget(widget);
// but don't select it
// unless its the first one
if (items.count() == 1) setCurrentIndex(0);
// set cursors visible/hidden if needed
setCursors();
}
void
GcOverlayWidget::setCurrentIndex(int index)
{
if (initial || index != stack->currentIndex()) {
titleLabel->setText(items.at(index).name);
stack->setCurrentIndex(index);
// tell everyone we changed
emit currentIndexChanged(index);
initial = false;
}
}
int
GcOverlayWidget::currentIndex() const
{
return stack->currentIndex();
}
void
GcOverlayWidget::setCursors()
{
if (items.count() > 1) {
left->show();
right->show();
} else {
left->hide();
right->hide();
}
}
void
GcOverlayWidget::scrollRight()
{
int rightIndex = stack->currentIndex() + 1;
if (stack->count() > rightIndex) setCurrentIndex(rightIndex);
else setCurrentIndex(0);
}
void
GcOverlayWidget::scrollLeft()
{
if (stack->currentIndex() > 0) setCurrentIndex(stack->currentIndex() -1);
else setCurrentIndex(stack->count() -1);
}
GcOverlayWidget::~GcOverlayWidget() {}
void
GcOverlayWidget::paintEvent (QPaintEvent *event)
{
// paint the darn thing!
paintBackground(event);
QWidget::paintEvent(event);
}
// paint is the same as sidebar
void
GcOverlayWidget::paintBackground(QPaintEvent *)
{
// setup a painter and the area to paint
QPainter painter(this);
painter.save();
QRect all(0,0,width(),height());
QRect boundary(0,0,width()-1,height()-1);
painter.fillRect(all, GColor(CPLOTBACKGROUND));
painter.setPen(QPen(Qt::darkGray));
painter.drawRect(boundary);
// linear gradients
QLinearGradient active = GCColor::linearGradient(23, true);
QLinearGradient inactive = GCColor::linearGradient(23, false);
// title
QRect title(1,1,width()-2,22);
painter.fillRect(title, QColor(Qt::white));
painter.fillRect(title, isActiveWindow() ? active : inactive);
if (!GCColor::isFlat()) {
QPen black(QColor(100,100,100,200));
painter.setPen(black);
painter.drawLine(0,22, width()-1, 22);
//QPen gray(QColor(230,230,230));
//painter.setPen(gray);
//painter.drawLine(0,0, width()-1, 0);
}
painter.restore();
}
void GcOverlayWidget::focusInEvent(QFocusEvent *)
{
m_infocus = true;
parentWidget()->installEventFilter(this);
parentWidget()->repaint();
emit inFocus(true);
}
void GcOverlayWidget::focusOutEvent(QFocusEvent *)
{
if (!m_isEditing) return;
if (m_showMenu) return;
mode = none;
emit outFocus(false);
m_infocus = false;
}
bool GcOverlayWidget::eventFilter( QObject *obj, QEvent *evt )
{
//return QWidget::eventFilter(obj, evt);
if (m_infocus) {
QWidget *w = parentWidget();
if (w == obj && evt->type()==QEvent::Paint) {
#if 0
QPainter painter(w);
QPoint p = this->mapTo(w,QPoint(-3,-3));
QPoint LT = w->mapFrom(w,p);
QPoint LB = w->mapFrom(w,QPoint(p.x(),p.y()+this->height()));
QPoint RB = w->mapFrom(w,QPoint(p.x()+this->width(),p.y()+this->height()));
QPoint RT = w->mapFrom(w,QPoint(p.x()+this->width(),p.y()));
painter.fillRect(LT.x(),LT.y(),6,6,QColor("black"));
painter.fillRect(LB.x(),LB.y(),6,6,QColor("black"));
painter.fillRect(RB.x(),RB.y(),6,6,QColor("black"));
painter.fillRect(RT.x(),RT.y(),6,6,QColor("black"));
#endif
return QWidget::eventFilter(obj,evt);
}
}
return QWidget::eventFilter(obj, evt);
}
void GcOverlayWidget::mousePressEvent(QMouseEvent *e)
{
position = QPoint(e->globalX()-geometry().x(), e->globalY()-geometry().y());
if (!m_isEditing) return;
if (!m_infocus) return;
//QWidget::mouseMoveEvent(e);
if (!(e->buttons() & Qt::LeftButton)) {
setCursorShape(e->pos());
return;
}
if(e->button()==Qt::RightButton) {
//e->accept();
}
}
void GcOverlayWidget::keyPressEvent(QKeyEvent *e)
{
if (!m_isEditing) return;
if (e->key() == Qt::Key_Delete) {
//this->deleteLater();
}
if (QApplication::keyboardModifiers() == Qt::ControlModifier) {
QPoint newPos(x(),y());
if (e->key() == Qt::Key_Up) newPos.setY(newPos.y()-1);
if (e->key() == Qt::Key_Down) newPos.setY(newPos.y()+1);
if (e->key() == Qt::Key_Left) newPos.setX(newPos.x()-1);
if (e->key() == Qt::Key_Right) newPos.setX(newPos.x()+1);
move(newPos);
}
if (QApplication::keyboardModifiers() == Qt::ShiftModifier) {
if (e->key() == Qt::Key_Up) resize(width(),height()-1);
if (e->key() == Qt::Key_Down) resize(width(),height()+1);
if (e->key() == Qt::Key_Left) resize(width()-1,height());
if (e->key() == Qt::Key_Right) resize(width()+1,height());
}
emit newGeometry(geometry());
}
void GcOverlayWidget::setCursorShape(const QPoint &e_pos)
{
const int diff = 6;
if (
//Left-Bottom
((e_pos.y() > y() + height() - diff) && //Bottom
(e_pos.x() < x()+diff)) || //Left
//Right-Bottom
((e_pos.y() > y() + height() - diff) && //Bottom
(e_pos.x() > x() + width() - diff)) || //Right
//Left-Top
((e_pos.y() < y() + diff) && //Top
(e_pos.x() < x() + diff)) || //Left
//Right-Top
((e_pos.y() < y() + diff) && //Top
(e_pos.x() > x() + width() - diff)) //Right
)
{
//Left-Bottom
if ((e_pos.y() > y() + height() - diff) && //Bottom
(e_pos.x() < x() + diff)) { //Left
mode = resizebl;
setCursor(QCursor(Qt::SizeBDiagCursor));
}
//Right-Bottom
if ((e_pos.y() > y() + height() - diff) && //Bottom
(e_pos.x() > x() + width() - diff)) { //Right
mode = resizebr;
setCursor(QCursor(Qt::SizeFDiagCursor));
}
//Left-Top
if ((e_pos.y() < y() + diff) && //Top
(e_pos.x() < x() + diff)) { //Left
mode = resizetl;
setCursor(QCursor(Qt::SizeFDiagCursor));
}
//Right-Top
if ((e_pos.y() < y() + diff) && //Top
(e_pos.x() > x() + width() - diff)) { //Right
mode = resizetr;
setCursor(QCursor(Qt::SizeBDiagCursor));
}
}
// проверка положения курсора по горизонтали
else if ((e_pos.x() < x() + diff) || //Left
((e_pos.x() > x() + width() - diff))) { //Right
if (e_pos.x() < x() + diff) { //Left
setCursor(QCursor(Qt::SizeHorCursor));
mode = resizel;
} else { //Right
setCursor(QCursor(Qt::SizeHorCursor));
mode = resizer;
}
}
// проверка положения курсора по вертикали
else if (((e_pos.y() > y() + height() - diff)) || //Bottom
(e_pos.y() < y() + diff)) { //Top
if (e_pos.y() < y() + diff) { //Top
setCursor(QCursor(Qt::SizeVerCursor));
mode = resizet;
} else { //Bottom
setCursor(QCursor(Qt::SizeVerCursor));
mode = resizeb;
}
} else if (e_pos.y() <= y() + 23 ) {
setCursor(QCursor(Qt::ArrowCursor));
mode = moving;
}
}
void GcOverlayWidget::mouseReleaseEvent(QMouseEvent *e)
{
QWidget::mouseReleaseEvent(e);
}
void GcOverlayWidget::mouseMoveEvent(QMouseEvent *e)
{
QWidget::mouseMoveEvent(e);
if (!m_isEditing) return;
if (!m_infocus) return;
if (!(e->buttons() & Qt::LeftButton)) {
QPoint p = QPoint(e->x()+geometry().x(), e->y()+geometry().y());
setCursorShape(p);
return;
}
if (mode == moving && (e->buttons() & Qt::LeftButton)) {
QPoint toMove = e->globalPos() - position;
if (toMove.x() < 0) return;
if (toMove.y() < 0) return;
if (toMove.x() > parentWidget()->width()-width()) return;
move(toMove);
emit newGeometry(geometry());
parentWidget()->repaint();
return;
}
if ((mode != moving) && (e->buttons() & Qt::LeftButton)) {
switch (mode){
case resizetl: { //Left-Top
int newwidth = e->globalX() - position.x() - geometry().x();
int newheight = e->globalY() - position.y() - geometry().y();
QPoint toMove = e->globalPos() - position;
resize(geometry().width()-newwidth,geometry().height()-newheight);
move(toMove.x(),toMove.y());
break;
}
case resizetr: { //Right-Top
int newheight = e->globalY() - position.y() - geometry().y();
QPoint toMove = e->globalPos() - position;
resize(e->x(),geometry().height()-newheight);
move(x(),toMove.y());
break;
}
case resizebl: { //Left-Bottom
int newwidth = e->globalX() - position.x() - geometry().x();
QPoint toMove = e->globalPos() - position;
resize(geometry().width()-newwidth,e->y());
move(toMove.x(),y());
break;
}
case resizeb: { //Bottom
resize(width(),e->y()); break;}
case resizel: { //Left
int newwidth = e->globalX() - position.x() - geometry().x();
QPoint toMove = e->globalPos() - position;
resize(geometry().width()-newwidth,height());
move(toMove.x(),y());
break;
}
case resizet: { //Top
int newheight = e->globalY() - position.y() - geometry().y();
QPoint toMove = e->globalPos() - position;
resize(width(),geometry().height()-newheight);
move(x(),toMove.y());
break;
}
case resizer: { //Right
resize(e->x(),height()); break;}
case resizebr: { //Right-Bottom
resize(e->x(),e->y()); break;}
}
parentWidget()->repaint();
}
emit newGeometry(geometry());
//QWidget::mouseMoveEvent(e);
}