rewrote snore backend with qml

This commit is contained in:
Patrick von Reth 2014-07-02 18:54:05 +02:00
parent 064a93ff9f
commit 790c6e39b6
10 changed files with 163 additions and 542 deletions

View File

@ -41,6 +41,7 @@ else()
find_package(Qt5Widgets REQUIRED)
find_package(Qt5Network REQUIRED)
find_package(Qt5DBus QUIET)
find_package(Qt5Declarative QUIET)
include(ECMQt4To5Porting)
set(SNORE_SUFFIX "-qt5")
set(SNORE_CamelCase_SUFFIX "Qt5")

View File

@ -1,16 +1,14 @@
QT4_ADD_RESOURCES(SNORE_RCS ${CMAKE_CURRENT_SOURCE_DIR}/snore.qrc)
set( SNORE_SRC
snorenotifier.cpp
notifywidget.cpp
DpiScaler.cpp
${SNORE_RCS}
)
set( SNORE_FORMS
notifywidget.ui)
qt4_wrap_ui(SNORE_UI ${SNORE_FORMS})
add_library(libsnore_backend_snore MODULE ${SNORE_SRC} ${SNORE_UI} )
target_link_libraries(libsnore_backend_snore snorecore ${QT_QTCORE_LIBRARY} )
add_library(libsnore_backend_snore MODULE ${SNORE_SRC} )
target_link_libraries(libsnore_backend_snore snorecore ${QT_QTCORE_LIBRARY} ${QT_QTDECLARATIVE_LIBRARY})
install(TARGETS libsnore_backend_snore ${SNORE_PLUGIN_INSTALL_PATH})

View File

@ -1,200 +0,0 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2013, Teo Mrnjavac <teo@kde.org>
*
* Tomahawk 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 3 of the License, or
* (at your option) any later version.
*
* Tomahawk 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 Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#include "DpiScaler.h"
#include <QFont>
#include <QFontMetrics>
namespace TomahawkUtils
{
int DpiScaler::s_fontSize = 0;
#ifdef Q_OS_MAC
const qreal DpiScaler::s_baseDpi = 72.;
#else
const qreal DpiScaler::s_baseDpi = 96.;
#endif
DpiScaler::DpiScaler( const QPaintDevice* that )
: that( that )
{
m_ratioX = ratioX( that );
m_ratioY = ratioY( that );
}
QSize
DpiScaler::scaled( int w, int h ) const
{
return QSize( scaledX( w ), scaledY( h ) );
}
QSize
DpiScaler::scaled( const QSize& size ) const
{
return scaled( size.width(), size.height() );
}
QMargins
DpiScaler::scaled( int left, int top, int right, int bottom ) const
{
return QMargins( scaledX( left ),
scaledY( top ),
scaledX( right ),
scaledY( bottom ) );
}
QMargins
DpiScaler::scaled( const QMargins& margins ) const
{
return scaled( margins.left(),
margins.top(),
margins.right(),
margins.bottom() );
}
int
DpiScaler::scaledX( int x ) const
{
return qRound( x * m_ratioX );
}
int
DpiScaler::scaledY( int y ) const
{
return qRound( y * m_ratioY );
}
// static methods start here
QSize
DpiScaler::scaled( const QPaintDevice* pd, int w, int h )
{
return QSize( scaledX( pd, w ), scaledY( pd, h ) );
}
QSize
DpiScaler::scaled( const QPaintDevice* pd, const QSize& size )
{
return scaled( pd, size.width(), size.height() );
}
QMargins
DpiScaler::scaled( const QPaintDevice* pd, int left, int top, int right, int bottom )
{
return QMargins( scaledX( pd, left ),
scaledY( pd, top ),
scaledX( pd, right ),
scaledY( pd, bottom ) );
}
QMargins
DpiScaler::scaled( const QPaintDevice* pd, const QMargins& margins )
{
return scaled( pd,
margins.left(),
margins.top(),
margins.right(),
margins.bottom() );
}
int
DpiScaler::scaledX( const QPaintDevice* pd, int x )
{
return qRound( x * ratioX( pd ) );
}
int
DpiScaler::scaledY( const QPaintDevice* pd, int y )
{
return qRound( y * ratioY( pd ) );
}
int DpiScaler::getFontSize()
{
return s_fontSize;
}
void DpiScaler::setFontSize(int value)
{
s_fontSize = value;
}
qreal
DpiScaler::ratioX( const QPaintDevice* pd )
{
qreal ratioFromFH = ratioFromFontHeight();
qreal ratioYFromDpi = pd->logicalDpiY() / s_baseDpi; //using Y because we compare with height
//if the error is less than 1%, we trust that the logical DPI setting has the best value
if ( qAbs( ratioFromFH / ratioYFromDpi - 1 ) < 0.01 )
return pd->logicalDpiX() / s_baseDpi;
else
return ratioFromFH;
}
qreal
DpiScaler::ratioY( const QPaintDevice* pd )
{
qreal ratioFromFH = ratioFromFontHeight();
qreal ratioYFromDpi = pd->logicalDpiY() / s_baseDpi; //using Y because we compare with height
//if the error is less than 1%, we trust that the logical DPI setting has the best value
if ( qAbs( ratioFromFH / ratioYFromDpi - 1 ) < 0.01 )
return ratioYFromDpi;
else
return ratioFromFH;
}
qreal
DpiScaler::ratioFromFontHeight()
{
int fS = s_fontSize;
QFont f;
f.setPointSize( fS );
int fH = QFontMetrics( f ).ascent() + 1; //a font's em-height should be ascent + 1px (baseline)
qreal basePpp = s_baseDpi / 72.; //72*(1.333)=96 dpi
#ifdef Q_OS_MAC
const int baseFontSize = 13;
#else
const int baseFontSize = 8;
#endif
qreal baseFontHeight = baseFontSize * basePpp; //we assume a minimum font size of 7pt
qreal ratioFromFontHeights = qMax( fH / baseFontHeight, 1. );
return ratioFromFontHeights;
}
}

View File

@ -1,75 +0,0 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2013, Teo Mrnjavac <teo@kde.org>
*
* Tomahawk 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 3 of the License, or
* (at your option) any later version.
*
* Tomahawk 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 Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DPISCALER_H
#define DPISCALER_H
#include <QPaintDevice>
#include <QMargins>
#include <QSize>
namespace TomahawkUtils
{
/**
* @brief The DpiScaler class provides some convenience methods to recompute fixed pixel sizes
* into values suitable for different environment DPI settings.
* Usage:
* class Foo : public QWidget, private TomahawkUtils::DpiScaler {...};
*/
class DpiScaler
{
public:
DpiScaler( const QPaintDevice* that );
QSize scaled( int w, int h ) const;
QSize scaled( const QSize& size ) const;
QMargins scaled( int left, int top, int right, int bottom ) const;
QMargins scaled( const QMargins& margins ) const;
int scaledX( int x ) const;
int scaledY( int y ) const;
// convenience one-shot methods, usable without composing or private-inheriting DpiScaler
static QSize scaled( const QPaintDevice* pd, int w, int h );
static QSize scaled( const QPaintDevice* pd, const QSize& size );
static QMargins scaled( const QPaintDevice* pd, int left, int top, int right, int bottom );
static QMargins scaled( const QPaintDevice* pd, const QMargins& margins );
static int scaledX( const QPaintDevice* pd, int x );
static int scaledY( const QPaintDevice* pd, int y );
static int getFontSize();
static void setFontSize(int value);
private:
static int s_fontSize;
inline static qreal ratioX( const QPaintDevice* pd );
inline static qreal ratioY( const QPaintDevice* pd );
inline static qreal ratioFromFontHeight();
qreal m_ratioX;
qreal m_ratioY;
const QPaintDevice* that;
static const qreal s_baseDpi;
};
}
#endif // DPISCALER_H

View File

@ -0,0 +1,109 @@
import QtQuick 1.1
Rectangle {
objectName: "qmlNotification"
id: root
width: 365
height: 100
clip: true
signal dismissed()
signal linkClicked(string link)
signal invoked()
function update(nTitle, bBody, nImage, nAppIcon, color)
{
title.text = nTitle
body.text = bBody
appIcon.source = nAppIcon
image.source = nImage
root.color = color
}
MouseArea {
id: mouseArea2
anchors.fill: parent
z: -1
onClicked: root.invoked()
}
Text {
id: title
x: 106
y: 3
width: 217
height: 14
color: "#ffffff"
text: qsTr("Title")
wrapMode: Text.WordWrap
font.pixelSize: 12
}
Text {
id: body
x: 106
y: 23
width: 217
height: 69
color: "#ffffff"
text: qsTr("Body")
wrapMode: Text.WordWrap
font.pixelSize: 12
onLinkActivated: root.linkClicked(link)
}
Image {
id: image
width: 100
height: 100
z: 4
fillMode: Image.PreserveAspectFit
source: "qrc:/root/images/freedesktop-dbus.png"
}
Image {
id: appIcon
x: 329
y: 62
width: 30
height: 30
fillMode: Image.PreserveAspectFit
source: "qrc:/root/snore.png"
}
Image {
id: closeButton
x: 345
y: 0
width: 20
height: 20
fillMode: Image.PreserveAspectFit
z: 3
source: "qrc:/resources/close.png"
MouseArea {
id: mouseArea1
anchors.fill: parent
onClicked: root.dismissed()
}
}
}

View File

@ -18,28 +18,31 @@
*/
#include "notifywidget.h"
#include "ui_notifywidget.h"
#include "core/log.h"
#include <QDesktopWidget>
#include <QDesktopServices>
#include <QPicture>
#include <QtDeclarative/QDeclarativeView>
#include <QLayout>
#include <QSize>
using namespace Snore;
NotifyWidget::NotifyWidget(int pos,QWidget *parent) :
QWidget(parent, Qt::ToolTip | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
| Qt::WindowDoesNotAcceptFocus
#endif
),
ui(new Ui::NotifyWidget),
QDeclarativeView(QUrl("qrc:/notification.qml"), parent),
m_moveTimer(new QTimer(this)),
m_desktop(QDesktopWidget().availableGeometry()),
m_id(pos),
m_mem(QString("SnoreNotifyWidget%1").arg(QString::number(m_id))),
m_ready(true)
{
ui->setupUi(this);
qmlNotification = rootObject();
this->setWindowFlags(Qt::ToolTip | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
| Qt::WindowDoesNotAcceptFocus
#endif
);
if(m_mem.create(sizeof(SHARED_MEM_TYPE)))
{
m_mem.lock();
@ -59,24 +62,26 @@ NotifyWidget::NotifyWidget(int pos,QWidget *parent) :
snoreDebug( SNORE_DEBUG ) << "Status" << *data;
}
TomahawkUtils::DpiScaler::setFontSize(10);
m_scaler = new TomahawkUtils::DpiScaler(this);
ui->closeButton->setMaximumWidth(ui->closeButton->height());
setFixedSize( m_scaler->scaled(300, 80));
m_dest = QPoint(m_desktop.topRight().x() - width(), m_desktop.topRight().y() + m_scaler->scaledY(10) + (m_scaler->scaledY(10) + height()) * pos);
m_dest = QPoint(m_desktop.topRight().x() - width(), m_desktop.topRight().y() + 10 + 10 + height() * pos);
m_start = QPoint(m_desktop.topRight().x(), m_dest.y());
snoreDebug( SNORE_DEBUG ) << m_dest << m_start << size();
m_moveTimer->setInterval(1);
connect( m_moveTimer, SIGNAL(timeout()), this, SLOT(slotMove()));
connect(qmlNotification, SIGNAL(invoked()),this, SLOT(slotInvoked()));
connect(qmlNotification, SIGNAL(dismissed()),this, SLOT(slotDismissed()));
connect(qmlNotification, SIGNAL(linkClicked(QString)),this, SLOT(slotLinkClicked(QString)));
}
NotifyWidget::~NotifyWidget()
{
delete m_scaler;
delete ui;
}
void NotifyWidget::display(const Notification &notification)
@ -92,17 +97,14 @@ void NotifyWidget::display(const Notification &notification)
void NotifyWidget::update(const Notification &notification)
{
m_notification = notification;
ui->titel->setText(notification.title());
ui->body->setText(notification.text());
ui->body->setFixedHeight((m_scaler->scaledY(40) / ui->body->fontInfo().pointSize()) * ui->body->fontInfo().pointSize());//round it by line height
QMetaObject::invokeMethod(qmlNotification, "update", Qt::QueuedConnection,
Q_ARG( QVariant, notification.title()),
Q_ARG( QVariant, notification.text()),
Q_ARG( QVariant, QUrl::fromLocalFile(notification.icon().localUrl())),
Q_ARG( QVariant, QUrl::fromLocalFile(notification.application().icon().localUrl())),
Q_ARG( QVariant, computeBackgrondColor(notification.application().icon().image())));
QSize iconSize = m_scaler->scaled(65,65);
ui->icon->setPixmap(QPixmap::fromImage(notification.icon().image().scaled(iconSize, Qt::KeepAspectRatio, Qt::SmoothTransformation)));
iconSize = m_scaler->scaled(20,20);
QImage img = notification.application().icon().image().scaled(iconSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
ui->appIcon->setPixmap(QPixmap::fromImage(img));
setPalette(img);
}
bool NotifyWidget::acquire()
@ -164,17 +166,17 @@ void NotifyWidget::slotMove()
}
}
void NotifyWidget::on_closeButton_clicked()
void NotifyWidget::slotDismissed()
{
emit dismissed();
}
void NotifyWidget::mousePressEvent(QMouseEvent *)
void NotifyWidget::slotInvoked()
{
emit invoked();
}
void NotifyWidget::setPalette(const QImage &img)
QColor NotifyWidget::computeBackgrondColor(const QImage &img)
{
qulonglong r = 0;
qulonglong g = 0;
@ -191,22 +193,11 @@ void NotifyWidget::setPalette(const QImage &img)
}
int s = img.width()*img.height();
QPalette p = palette();
QColor bg = QColor(r/s, g/s, b/s);
p.setColor(QPalette::All, QPalette::Window, bg);
p.setColor(QPalette::All, QPalette::Background, bg);
p.setColor(QPalette::All, QPalette::Base, bg);
p.setColor(QPalette::All, QPalette::Text, Qt::white);
p.setColor(QPalette::All, QPalette::BrightText, Qt::white);
p.setColor(QPalette::All, QPalette::ButtonText, Qt::white);
p.setColor(QPalette::All, QPalette::WindowText, Qt::white);
QWidget::setPalette(p);
ui->closeButton->setPalette(p);
ui->body->setPalette(p);
ui->titel->setPalette(p);
return QColor(r/s, g/s, b/s);
}
void NotifyWidget::on_body_linkActivated(const QString &link)
void NotifyWidget::slotLinkClicked(QString link)
{
snoreDebug( SNORE_DEBUG ) << link;
QDesktopServices::openUrl( QUrl(link));
}

View File

@ -24,14 +24,12 @@
#include <QTimer>
#include <QSharedMemory>
#include "core/notification/notification.h"
#include "DpiScaler.h"
namespace Ui {
class NotifyWidget;
}
#include <QtDeclarative>
typedef bool SHARED_MEM_TYPE;
class NotifyWidget : public QWidget
class NotifyWidget : public QDeclarativeView
{
Q_OBJECT
@ -58,27 +56,26 @@ signals:
private slots:
void slotMove();
void on_closeButton_clicked();
void slotDismissed();
void on_body_linkActivated(const QString &link);
void slotInvoked();
protected:
void mousePressEvent(QMouseEvent *e);
void slotLinkClicked(QString link);
private:
void setPalette(const QImage &img);
Ui::NotifyWidget *ui;
QColor computeBackgrondColor(const QImage &img);
QTimer *m_moveTimer;
QPoint m_dest;
QPoint m_start;
int m_dist;
QRect m_desktop;
TomahawkUtils::DpiScaler *m_scaler;
Snore::Notification m_notification;
QObject *qmlNotification;
int m_id;
QSharedMemory m_mem;
bool m_ready;

View File

@ -1,206 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>NotifyWidget</class>
<widget class="QWidget" name="NotifyWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>359</width>
<height>175</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="mouseTracking">
<bool>true</bool>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<property name="windowIcon">
<iconset resource="../../../../data/snore.qrc">
<normaloff>:/root/snore.png</normaloff>:/root/snore.png</iconset>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="appIcon">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>appIcon</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="icon">
<property name="text">
<string>Icon</string>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="spacing">
<number>0</number>
</property>
<property name="sizeConstraint">
<enum>QLayout::SetFixedSize</enum>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="spacing">
<number>0</number>
</property>
<property name="sizeConstraint">
<enum>QLayout::SetMinimumSize</enum>
</property>
<item>
<widget class="QLabel" name="titel">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
<weight>75</weight>
<bold>true</bold>
<kerning>true</kerning>
</font>
</property>
<property name="text">
<string>TextLabel</string>
</property>
<property name="scaledContents">
<bool>false</bool>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="indent">
<number>0</number>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="closeButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string notr="true">X</string>
</property>
<property name="shortcut">
<string notr="true"/>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="body">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string notr="true">&lt;i&gt;This is Snore&lt;/i&gt;&lt;br&gt;&lt;a href=&quot;https://github.com/TheOneRing/Snorenotify&quot;&gt;Project Website&lt;/a&gt;&lt;br&gt;1&lt;br&gt;2&lt;br&gt;3&lt;br&gt;4&lt;br&gt;5&lt;br&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="scaledContents">
<bool>false</bool>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="margin">
<number>0</number>
</property>
<property name="indent">
<number>0</number>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
<resources>
<include location="../../../../data/snore.qrc"/>
</resources>
<connections/>
</ui>

Binary file not shown.

After

Width:  |  Height:  |  Size: 725 B

View File

@ -0,0 +1,6 @@
<RCC>
<qresource prefix="/">
<file>notification.qml</file>
<file>resources/close.png</file>
</qresource>
</RCC>