mirror of
https://github.com/GoldenCheetah/GoldenCheetah.git
synced 2026-02-16 01:19:57 +00:00
... change storage format to .INI files (which is QTs cross-system format) ... differentiate between System, Global and Athlete specific settings ... store the Global Settings in the AthleteDirectory (root) ... store the Athlete specific Settings in the Athletes Names subdir /config ... migrate existing Settings from current location into new formats "on-the-fly"
481 lines
14 KiB
C++
481 lines
14 KiB
C++
/*
|
|
* Copyright (c) 2013 Damien Grauser (Damien.Grauser@pev-geneve.ch)
|
|
*
|
|
* 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 "GcSideBarItem.h"
|
|
#include "DiaryWindow.h"
|
|
#include "DiarySidebar.h"
|
|
|
|
// creates an icon in the apple style of gray emboss
|
|
QIcon iconFromPNG(QString filename, bool emboss)
|
|
{
|
|
QImage pngImage;
|
|
pngImage.load(filename);
|
|
|
|
// use muted dark gray color
|
|
QImage gray8 = pngImage.convertToFormat(QImage::Format_Indexed8);
|
|
gray8.setColor(0, QColor(80,80,80, 170).rgb());
|
|
|
|
if (GCColor::isFlat()) return QIcon(QPixmap::fromImage(gray8));
|
|
|
|
QImage white8 = pngImage.convertToFormat(QImage::Format_Indexed8);
|
|
white8.setColor(0, QColor(255,255,255, 255).rgb());
|
|
|
|
// now convert to a format we can paint with!
|
|
QImage white = white8.convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
|
QImage gray = gray8.convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
|
|
|
QPainter painter;
|
|
painter.begin(&white);
|
|
painter.setBackgroundMode(Qt::TransparentMode);
|
|
if (emboss) painter.drawImage(0,-1, gray);
|
|
else painter.drawImage(0,0, gray);
|
|
painter.end();
|
|
|
|
return QIcon(QPixmap::fromImage(white));
|
|
}
|
|
|
|
//
|
|
// GcSplitter -- The sidebar is largely comprised of this which contains a splitter (GcSubSplitter)
|
|
// and a control (GcSplitterControl) at the bottom with icons to show/hide items.
|
|
// The GcSplitter contains 2 or more such items (GcSplitterItem) and each of those will
|
|
// have a special handle (GcSplitterHandle).
|
|
//
|
|
GcSplitter::GcSplitter(Qt::Orientation orientation, QWidget *parent) : QWidget(parent)
|
|
{
|
|
|
|
setContentsMargins(0,0,0,0);
|
|
|
|
control = new GcSplitterControl(this);
|
|
|
|
splitter = new GcSubSplitter(orientation, control, this);
|
|
splitter->setHandleWidth(23);
|
|
splitter->setFrameStyle(QFrame::NoFrame);
|
|
splitter->setContentsMargins(0,0,0,0);
|
|
splitter->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
|
|
|
|
QVBoxLayout *layout = new QVBoxLayout(this);
|
|
layout->setSpacing(0);
|
|
layout->setAlignment(Qt::AlignBottom|Qt::AlignHCenter);
|
|
layout->setContentsMargins(0,0,0,0);
|
|
layout->addWidget(splitter);
|
|
layout->addWidget(control);
|
|
|
|
connect(splitter,SIGNAL(splitterMoved(int,int)), this, SLOT(subSplitterMoved(int,int)));
|
|
}
|
|
|
|
void
|
|
GcSplitter::prepare(QString cyclist, QString name)
|
|
{
|
|
this->name = name;
|
|
this->cyclist = cyclist;
|
|
|
|
QWidget *spacer = new QWidget(this);
|
|
spacer->setAutoFillBackground(false);
|
|
spacer->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
|
|
control->addWidget(spacer);
|
|
|
|
// get saved state
|
|
QString statesetting = GC_QSETTINGS_ATHLETE_LAYOUT+QString("splitter/%1/sizes").arg(name);
|
|
QVariant sizes = appsettings->cvalue(cyclist, statesetting);
|
|
if (sizes != QVariant()) {
|
|
splitter->restoreState(sizes.toByteArray());
|
|
splitter->setOpaqueResize(true); // redraw when released, snappier UI
|
|
}
|
|
|
|
// should we hide / show each widget?
|
|
for(int i=0; i<splitter->count(); i++) {
|
|
QString hidesetting = GC_QSETTINGS_ATHLETE_LAYOUT+QString("splitter/%1/hide/%2").arg(name).arg(i);
|
|
QVariant hidden = appsettings->cvalue(cyclist, hidesetting);
|
|
if (i && hidden != QVariant()) {
|
|
if (hidden.toBool() == true) {
|
|
splitter->widget(i)->hide();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
GcSplitter::saveSettings()
|
|
{
|
|
// get saved state
|
|
QString statesetting = GC_QSETTINGS_ATHLETE_LAYOUT+QString("splitter/%1/sizes").arg(name);
|
|
appsettings->setCValue(cyclist, statesetting, splitter->saveState());
|
|
|
|
// should we hide / show each widget?
|
|
for(int i=0; i<splitter->count(); i++) {
|
|
QString hidesetting = GC_QSETTINGS_ATHLETE_LAYOUT+QString("splitter/%1/hide/%2").arg(name).arg(i);
|
|
appsettings->setCValue(cyclist, hidesetting, QVariant(splitter->widget(i)->isHidden()));
|
|
}
|
|
}
|
|
|
|
void
|
|
GcSplitter::setOpaqueResize(bool opaque)
|
|
{
|
|
return splitter->setOpaqueResize(opaque);
|
|
}
|
|
|
|
QList<int>
|
|
GcSplitter::sizes() const
|
|
{
|
|
return splitter->sizes();
|
|
}
|
|
|
|
void
|
|
GcSplitter::setSizes(const QList<int> &list)
|
|
{
|
|
return splitter->setSizes(list);
|
|
}
|
|
|
|
QByteArray
|
|
GcSplitter::saveState() const
|
|
{
|
|
return splitter->saveState();
|
|
}
|
|
|
|
bool
|
|
GcSplitter::restoreState(const QByteArray &state)
|
|
{
|
|
return splitter->restoreState(state);
|
|
}
|
|
|
|
void
|
|
GcSplitter::subSplitterMoved(int pos, int index)
|
|
{
|
|
saveSettings();
|
|
emit splitterMoved(pos, index);
|
|
}
|
|
|
|
void
|
|
GcSplitter::addWidget(QWidget *widget)
|
|
{
|
|
splitter->addWidget(widget);
|
|
}
|
|
|
|
void
|
|
GcSplitter::insertWidget(int index, QWidget *widget)
|
|
{
|
|
splitter->insertWidget(index, widget);
|
|
}
|
|
|
|
//
|
|
// GcSubSplitter -- the actual QSplitter widget but needs to have a handle at the top even if there is
|
|
// only one item shown, hence making it a special widget
|
|
//
|
|
|
|
GcSubSplitter::GcSubSplitter(Qt::Orientation orientation, GcSplitterControl *control, GcSplitter *parent, bool plainstyle) : QSplitter(orientation, parent), control(control), gcSplitter (parent), plainstyle(plainstyle)
|
|
{
|
|
_insertedWidget = NULL;
|
|
|
|
// we add a fake widget to ensure the first real widget
|
|
// that is added has a handle (even though it cannot be moved)
|
|
if (!plainstyle) {
|
|
QLabel *fake = new QLabel("fake");
|
|
fake->setFixedHeight(0);
|
|
setHandleWidth(0);
|
|
QSplitter::addWidget(fake);
|
|
//setStretchFactor(0,0);
|
|
} else {
|
|
QSplitter::addWidget((QWidget*)control);
|
|
}
|
|
}
|
|
|
|
void
|
|
GcSubSplitter::addWidget(QWidget *widget)
|
|
{
|
|
_insertedWidget = widget;
|
|
QSplitter::addWidget(widget);
|
|
//setStretchFactor(indexOf(widget), 1);
|
|
}
|
|
|
|
void
|
|
GcSubSplitter::insertWidget(int index, QWidget *widget)
|
|
{
|
|
_insertedWidget = widget;
|
|
QSplitter::insertWidget(index, widget);
|
|
}
|
|
GcSplitterItem *
|
|
GcSubSplitter::removeItem(QString text)
|
|
{
|
|
for(int i=1; i<= count(); i++) {
|
|
const GcSplitterHandle *h = static_cast<GcSplitterHandle*>(handle(i));
|
|
if (h && h->title() == text) {
|
|
return static_cast<GcSplitterItem*>(widget(i));
|
|
}
|
|
}
|
|
return NULL; // didn't find it!
|
|
}
|
|
|
|
|
|
QSplitterHandle*
|
|
GcSubSplitter::createHandle()
|
|
{
|
|
if(_insertedWidget != 0) {
|
|
GcSplitterItem* _item = dynamic_cast<GcSplitterItem*>(_insertedWidget);
|
|
if(_item != 0) {
|
|
_item->splitterHandle = new GcSplitterHandle(_item->title, orientation(), this, !plainstyle);
|
|
|
|
if (!plainstyle) {
|
|
_item->splitterHandle->addActions(_item->actions());
|
|
_item->controlAction = new QAction(_item->icon, _item->title, this);
|
|
_item->controlAction->setStatusTip(_item->title);
|
|
control->addAction(_item->controlAction);
|
|
|
|
connect(_item->controlAction, SIGNAL(triggered(void)), _item, SLOT(selectHandle(void)));
|
|
connect(_item->controlAction, SIGNAL(triggered(void)), gcSplitter, SLOT(saveSettings()));
|
|
}
|
|
return _item->splitterHandle;
|
|
}
|
|
}
|
|
|
|
return QSplitter::createHandle();
|
|
}
|
|
|
|
//
|
|
// GcSplitterHandle -- the handle shown at the top of a sidebar item with a title and a menu button
|
|
// the user drags this to resize the sidebar contents up and down.
|
|
//
|
|
|
|
GcSplitterHandle::GcSplitterHandle(QString title, Qt::Orientation orientation, QSplitter *parent, bool metal) : QSplitterHandle(orientation, parent), _title(title), metal(metal)
|
|
{
|
|
|
|
init(title, orientation, NULL, NULL, NULL, parent, metal);
|
|
}
|
|
|
|
GcSplitterHandle::GcSplitterHandle(QString title, Qt::Orientation orientation,
|
|
QWidget *left, QWidget *mid, QWidget *right,
|
|
QSplitter *parent, bool metal) : QSplitterHandle(orientation, parent), _title(title), metal(metal)
|
|
{
|
|
init(title, orientation, left, mid, right, parent, metal);
|
|
}
|
|
|
|
void
|
|
GcSplitterHandle::init(QString title, Qt::Orientation orientation,
|
|
QWidget *left, QWidget *mid, QWidget *right, QSplitter *parent, bool metal)
|
|
{
|
|
Q_UNUSED(orientation);
|
|
|
|
setContentsMargins(0,0,0,0);
|
|
if (metal)
|
|
setFixedHeight(23);
|
|
else
|
|
setFixedHeight(18);
|
|
|
|
gcSplitter = (GcSubSplitter*)parent;
|
|
|
|
titleLayout = new QHBoxLayout(this);
|
|
titleLayout->setContentsMargins(0,0,0,0);
|
|
titleLayout->setSpacing(2);
|
|
|
|
titleLabel = new GcLabel(title, this);
|
|
titleLabel->setXOff(0);
|
|
titleLabel->setChrome(true);
|
|
|
|
QFont font;
|
|
#ifdef Q_OS_MAC
|
|
titleLabel->setFixedHeight(16);
|
|
titleLabel->setYOff(1);
|
|
font.setPointSize(11);
|
|
#else
|
|
titleLabel->setYOff(1);
|
|
font.setPointSize(10);
|
|
#endif
|
|
font.setWeight(QFont::Black);
|
|
titleLabel->setFont(font);
|
|
|
|
titleLayout->addSpacing(10);
|
|
titleLayout->addWidget(titleLabel);
|
|
|
|
// widgets
|
|
if (left) titleLayout->addWidget(left);
|
|
titleLayout->addStretch();
|
|
|
|
if (mid) titleLayout->addWidget(mid);
|
|
//titleLayout->addStretch();
|
|
|
|
if (right) titleLayout->addWidget(right);
|
|
setCursor(Qt::ArrowCursor);
|
|
}
|
|
|
|
QSize
|
|
GcSplitterHandle::sizeHint() const
|
|
{
|
|
return QSize(200, metal ? 23 :18);
|
|
}
|
|
|
|
GcSubSplitter*
|
|
GcSplitterHandle::splitter() const
|
|
{
|
|
return gcSplitter;
|
|
}
|
|
|
|
void
|
|
GcSplitterHandle::addAction(QAction *)
|
|
{
|
|
//not used anyway titleToolbar->addAction(action);
|
|
}
|
|
|
|
void
|
|
GcSplitterHandle::addActions(QList<QAction*> actions)
|
|
{
|
|
foreach(QAction *action, actions) {
|
|
QToolButton *p = new QToolButton(this);
|
|
p->setStyleSheet("QToolButton { border: none; padding: 0px; }");
|
|
p->setAutoFillBackground(false);
|
|
p->setFixedSize(20,20);
|
|
p->setIcon(action->icon());
|
|
p->setIconSize(QSize(10,10));
|
|
p->setFocusPolicy(Qt::NoFocus);
|
|
titleLayout->addWidget(p);
|
|
connect(p, SIGNAL(clicked()), action, SLOT(trigger()));
|
|
}
|
|
}
|
|
|
|
void
|
|
GcSplitterHandle::paintEvent(QPaintEvent *event)
|
|
{
|
|
// paint the darn thing!
|
|
paintBackground(event);
|
|
QWidget::paintEvent(event);
|
|
}
|
|
|
|
void
|
|
GcSplitterHandle::paintBackground(QPaintEvent *)
|
|
{
|
|
// setup a painter and the area to paint
|
|
QPainter painter(this);
|
|
|
|
painter.save();
|
|
QRect all(0,0,width(),height());
|
|
|
|
// fill with a linear gradient
|
|
painter.setPen(Qt::NoPen);
|
|
painter.fillRect(all, QColor(Qt::white));
|
|
|
|
QLinearGradient active = GCColor::linearGradient(metal ? 23 : 18, true, !metal);
|
|
QLinearGradient inactive = GCColor::linearGradient(metal ? 23 : 18, false, !metal);
|
|
|
|
painter.fillRect(all, isActiveWindow() ? active : inactive);
|
|
|
|
if (!GCColor::isFlat()) {
|
|
QPen black(QColor(100,100,100,200));
|
|
painter.setPen(black);
|
|
painter.drawLine(0,height()-1, width()-1, height()-1);
|
|
|
|
QPen gray(QColor(230,230,230));
|
|
painter.setPen(gray);
|
|
painter.drawLine(0,0, width()-1, 0);
|
|
}
|
|
|
|
painter.restore();
|
|
}
|
|
|
|
//
|
|
// GcSplitterControl - the icon bar at the bottom of the left sidebar
|
|
//
|
|
|
|
GcSplitterControl::GcSplitterControl(QWidget *parent) : QToolBar(parent)
|
|
{
|
|
setContentsMargins(0,0,0,0);
|
|
setFixedHeight(20);
|
|
setIconSize(QSize(14,14));
|
|
setToolButtonStyle(Qt::ToolButtonIconOnly);
|
|
setAutoFillBackground(false);
|
|
|
|
QWidget *spacer = new QWidget(this);
|
|
spacer->setAutoFillBackground(false);
|
|
spacer->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
|
|
addWidget(spacer);
|
|
}
|
|
|
|
void
|
|
GcSplitterControl::paintEvent(QPaintEvent *event)
|
|
{
|
|
// paint the darn thing!
|
|
paintBackground(event);
|
|
//QToolBar::paintEvent(event);
|
|
}
|
|
|
|
void
|
|
GcSplitterControl::paintBackground(QPaintEvent *)
|
|
{
|
|
QRect all(0,0,width(),height());
|
|
|
|
// setup a painter and the area to paint
|
|
QPainter painter(this);
|
|
|
|
QLinearGradient active = GCColor::linearGradient(20, true);
|
|
QLinearGradient inactive = GCColor::linearGradient(20, false);
|
|
|
|
// fill with a linear gradient
|
|
painter.setPen(Qt::NoPen);
|
|
painter.fillRect(all, isActiveWindow() ? active : inactive);
|
|
|
|
if (!GCColor::isFlat()) {
|
|
QPen gray(QColor(230,230,230));
|
|
painter.setPen(gray);
|
|
painter.drawLine(0,0, width()-1, 0);
|
|
}
|
|
}
|
|
|
|
void
|
|
GcSplitterControl::selectAction()
|
|
{
|
|
this->setVisible(!this->isVisible());
|
|
|
|
/*this->setBaseSize(width(), parentWidget()->height());
|
|
this->setMaximumSize(QWIDGETSIZE_MAX,QWIDGETSIZE_MAX);*/
|
|
}
|
|
|
|
//
|
|
// GcSplitterItem -- the selectable content in the sidebar; has a name, an icon and a widget to show
|
|
//
|
|
|
|
GcSplitterItem::GcSplitterItem(QString title, QIcon icon, QWidget *parent) : QWidget(parent), title(title), icon(icon)
|
|
{
|
|
setContentsMargins(0,0,0,0);
|
|
layout = new QVBoxLayout(this);
|
|
layout->setContentsMargins(0,0,0,0);
|
|
layout->setSpacing(0);
|
|
content = NULL;
|
|
//titleBar = new GcSideBarTitle(title, this);
|
|
//layout->addWidget(titleBar);
|
|
}
|
|
|
|
void
|
|
GcSplitterItem::addWidget(QWidget *p)
|
|
{
|
|
content = p;
|
|
//p->setContentsMargins(0,0,0,0);
|
|
layout->addWidget(p);
|
|
}
|
|
|
|
void
|
|
GcSplitterItem::selectHandle()
|
|
{
|
|
//splitterHandle->gcSplitter->setStretchFactor(splitterHandle->index, this->isVisible() ? 0 : 1);
|
|
this->setVisible(!this->isVisible());
|
|
controlAction->setChecked(this->isVisible());
|
|
/*this->setBaseSize(width(), parentWidget()->height());
|
|
this->setMaximumSize(QWIDGETSIZE_MAX,QWIDGETSIZE_MAX);*/
|
|
}
|
|
|
|
GcSplitterItem::~GcSplitterItem()
|
|
{
|
|
}
|
|
|