~verzegnassi-stefano/+junk/pdf-viewer

« back to all changes in this revision

Viewing changes to src/plugin/libreofficetoolkit-qml-plugin/ucunits.cpp

  • Committer: Stefano Verzegnassi
  • Date: 2016-04-15 10:51:55 UTC
  • Revision ID: stefano92.100@gmail.com-20160415105155-swsdn420t6n85b2i
 * Removed all the not necessary stuff, including the LibreOffice Viewer and the Plain Text Viewer
* 2014 WelcomePage is back again

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright 2012 Canonical Ltd.
3
 
 *
4
 
 * This program is free software; you can redistribute it and/or modify
5
 
 * it under the terms of the GNU Lesser General Public License as published by
6
 
 * the Free Software Foundation; version 3.
7
 
 *
8
 
 * This program is distributed in the hope that it will be useful,
9
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
 
 * GNU Lesser General Public License for more details.
12
 
 *
13
 
 * You should have received a copy of the GNU Lesser General Public License
14
 
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
15
 
 *
16
 
 * Author: Florian Boucault <florian.boucault@canonical.com>
17
 
 */
18
 
 
19
 
#include "ucunits.h"
20
 
 
21
 
#include <QtQml/QQmlContext>
22
 
#include <QtQml/QQmlFile>
23
 
#include <QtCore/QFileInfo>
24
 
#include <QtCore/QDir>
25
 
#include <QtCore/QRegularExpression>
26
 
#include <QtCore/qmath.h>
27
 
#include <QtGui/QGuiApplication>
28
 
#include <QtGui/QScreen>
29
 
 
30
 
#define ENV_GRID_UNIT_PX "GRID_UNIT_PX"
31
 
#define DEFAULT_GRID_UNIT_PX 8
32
 
 
33
 
static float getenvFloat(const char* name, float defaultValue)
34
 
{
35
 
    QByteArray stringValue = qgetenv(name);
36
 
    bool ok;
37
 
    float value = stringValue.toFloat(&ok);
38
 
    return ok ? value : defaultValue;
39
 
}
40
 
 
41
 
 
42
 
/*!
43
 
    \qmltype Units
44
 
    \instantiates UCUnits
45
 
    \inqmlmodule Ubuntu.Components 1.1
46
 
    \ingroup resolution-independence
47
 
    \brief Units of measurement for sizes, spacing, margin, etc.
48
 
 
49
 
    Units provides facilities for measuring UI elements in a variety
50
 
    of units other than just pixels.
51
 
 
52
 
    A global instance of Units is exposed as the \b{units} context property.
53
 
    Example usage:
54
 
 
55
 
    \qml
56
 
    import QtQuick 2.4
57
 
    import Ubuntu.Components 1.2
58
 
 
59
 
    Item {
60
 
        width: units.gu(2)
61
 
        height: units.gu(5)
62
 
    }
63
 
    \endqml
64
 
 
65
 
    \sa {Resolution Independence}
66
 
*/
67
 
 
68
 
/*
69
 
 * Note on the interaction between GRID_UNIT_PX and QT_DEVICE_PIXEL_RATIO
70
 
 *
71
 
 * In Qt5.4 there is a single means to scale the UI: the QT_DEVICE_PIXEL_RATIO environment
72
 
 * variable. This accepts only integer values, thus allowing a x2 or x3 scaling of any
73
 
 * Qt-based UI, that includes QWidget as well as any QML UI.
74
 
 *
75
 
 * Setting QT_DEVICE_PIXEL_RATIO=2 implies one density-independent pixel corresponds to 2
76
 
 * physical pixels. Developers describe their UI in terms of density-independent pixels.
77
 
 * Qt scales accordingly.
78
 
 *
79
 
 * The Ubuntu UI Toolkit has solved the scaling problem with the GRID_UNIT_PX variable.
80
 
 * It offers more flexibility, but only scales QML applications written to use the UITK
81
 
 * (since it uses this Units class) as it is built on top of QML.
82
 
 *
83
 
 * There are additional areas in Qt where QT_DEVICE_PIXEL_RATIO causes correct scaling which
84
 
 * GRID_UNIT_PX cannot, for example:
85
 
 *   1. cacheBuffer for ListView/GridViews - specified in density-independent pixels
86
 
 *   2. gesture recognition  matches what is on screen better, as it is density-independent
87
 
 *      pixel aware
88
 
 *
89
 
 * In order to get the best of both worlds, Ubuntu will set both GRID_UNIT_PX and
90
 
 * QT_DEVICE_PIXEL_RATIO. Thus all Qt apps will scale reasonably well, with UITK-based apps
91
 
 * scaling perfectly for any desired scale (i.e. non-integer scales).
92
 
 *
93
 
 * However UITK developers can just use this Units class as usual, and will be almost totally
94
 
 * isolated from Qt's own scaling concept.
95
 
 */
96
 
 
97
 
UCUnits::UCUnits(QObject *parent) :
98
 
    QObject(parent),
99
 
    m_devicePixelRatio(qGuiApp->devicePixelRatio())
100
 
{
101
 
    // If GRID_UNIT_PX set, always use it. If not, 1GU := DEFAULT_GRID_UNIT_PX * m_devicePixelRatio
102
 
    if (qEnvironmentVariableIsSet(ENV_GRID_UNIT_PX)) {
103
 
        m_gridUnit = getenvFloat(ENV_GRID_UNIT_PX, DEFAULT_GRID_UNIT_PX);
104
 
    } else {
105
 
        m_gridUnit = DEFAULT_GRID_UNIT_PX * m_devicePixelRatio;
106
 
    }
107
 
}
108
 
 
109
 
/*!
110
 
    \qmlproperty real Units::gridUnit
111
 
 
112
 
    The number of pixels 1 grid unit corresponds to.
113
 
*/
114
 
float UCUnits::gridUnit()
115
 
{
116
 
    return m_gridUnit;
117
 
}
118
 
 
119
 
void UCUnits::setGridUnit(float gridUnit)
120
 
{
121
 
    m_gridUnit = gridUnit;
122
 
    Q_EMIT gridUnitChanged();
123
 
}
124
 
 
125
 
/*!
126
 
    \qmlmethod real Units::dp(real value)
127
 
 
128
 
    Returns the number of pixels \a value density independent pixels correspond to.
129
 
*/
130
 
// Density-independent pixels (and not physical pixels) because Qt sizes in terms of density-independent pixels.
131
 
float UCUnits::dp(float value)
132
 
{
133
 
    const float ratio = m_gridUnit / DEFAULT_GRID_UNIT_PX;
134
 
    if (value <= 2.0) {
135
 
        // for values under 2dp, return only multiples of the value
136
 
        return qRound(value * qFloor(ratio)) / m_devicePixelRatio;
137
 
    } else {
138
 
        return qRound(value * ratio) / m_devicePixelRatio;
139
 
    }
140
 
}
141
 
 
142
 
/*!
143
 
    \qmlmethod real Units::gu(real value)
144
 
 
145
 
    Returns the number of pixels \a value grid units correspond to.
146
 
*/
147
 
// Density-independent pixels (and not physical pixels) because Qt sizes in terms of density-independent pixels.
148
 
 
149
 
float UCUnits::gu(float value)
150
 
{
151
 
    return qRound(value * m_gridUnit) / m_devicePixelRatio;
152
 
}
153
 
 
154
 
QString UCUnits::resolveResource(const QUrl& url)
155
 
{
156
 
    if (url.isEmpty()) {
157
 
        return QString();
158
 
    }
159
 
 
160
 
    QString path = QQmlFile::urlToLocalFileOrQrc(url);
161
 
 
162
 
    if (path.isEmpty()) {
163
 
        return QString();
164
 
    }
165
 
 
166
 
    QFileInfo fileInfo(path);
167
 
    if (fileInfo.exists() && !fileInfo.isFile()) {
168
 
        return QString();
169
 
    }
170
 
 
171
 
    QString prefix = fileInfo.dir().absolutePath() + QDir::separator() + fileInfo.baseName();
172
 
    QString suffix = "." + fileInfo.completeSuffix();
173
 
 
174
 
    /* Use file with expected grid unit suffix if it exists.
175
 
       For example, if m_gridUnit = 10, look for resource@10.png.
176
 
    */
177
 
 
178
 
    path = prefix + suffixForGridUnit(m_gridUnit) + suffix;
179
 
    if (QFile::exists(path)) {
180
 
        return QString("1") + "/" + path;
181
 
    }
182
 
 
183
 
    /* No file with expected grid unit suffix exists.
184
 
       List all the files of the form fileBaseName@[0-9]*.fileSuffix and select
185
 
       the most appropriate one privileging downscaling high resolution assets
186
 
       over upscaling low resolution assets.
187
 
 
188
 
       The most appropriate file has a grid unit suffix greater than the target
189
 
       grid unit (m_gridUnit) yet as small as possible.
190
 
       If no file with a grid unit suffix greater than the target grid unit
191
 
       exists, then select one with a grid unit suffix as close as possible to
192
 
       the target grid unit.
193
 
 
194
 
       For example, if m_gridUnit = 10 and the available files are
195
 
       resource@9.png, resource@14.png and resource@18.png, the most appropriate
196
 
       file would be resource@14.png since it is above 10 and smaller
197
 
       than resource@18.png.
198
 
    */
199
 
    QStringList nameFilters;
200
 
    nameFilters << fileInfo.baseName() + "@[0-9]*" + suffix;
201
 
    QStringList files = fileInfo.dir().entryList(nameFilters, QDir::Files);
202
 
 
203
 
    if (!files.empty()) {
204
 
        float selectedGridUnitSuffix = gridUnitSuffixFromFileName(files.first());
205
 
 
206
 
        Q_FOREACH (const QString& fileName, files) {
207
 
            float gridUnitSuffix = gridUnitSuffixFromFileName(fileName);
208
 
            if ((selectedGridUnitSuffix >= m_gridUnit && gridUnitSuffix >= m_gridUnit && gridUnitSuffix < selectedGridUnitSuffix)
209
 
                || (selectedGridUnitSuffix < m_gridUnit && gridUnitSuffix > selectedGridUnitSuffix)) {
210
 
                selectedGridUnitSuffix = gridUnitSuffix;
211
 
            }
212
 
        }
213
 
 
214
 
        path = prefix + suffixForGridUnit(selectedGridUnitSuffix) + suffix;
215
 
        float scaleFactor = m_gridUnit / selectedGridUnitSuffix;
216
 
        return QString::number(scaleFactor) + "/" + path;
217
 
    }
218
 
 
219
 
    path = prefix + suffix;
220
 
    if (QFile::exists(path)) {
221
 
        return QString("1") + "/" + path;
222
 
    }
223
 
 
224
 
    return QString();
225
 
}
226
 
 
227
 
QString UCUnits::suffixForGridUnit(float gridUnit)
228
 
{
229
 
    return "@" + QString::number(gridUnit);
230
 
}
231
 
 
232
 
float UCUnits::gridUnitSuffixFromFileName(const QString& fileName)
233
 
{
234
 
    QRegularExpression re("^.*@([0-9]*).*$");
235
 
    QRegularExpressionMatch match = re.match(fileName);
236
 
    if (match.hasMatch()) {
237
 
        return match.captured(1).toFloat();
238
 
    } else {
239
 
        return 0;
240
 
    }
241
 
}