mirror of https://github.com/cutefishos/settings
Add font other options
parent
48c175e483
commit
cf57053350
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (C) 2021 CutefishOS Team.
|
||||
*
|
||||
* Author: Reion Wong <reionwong@gmail.com>
|
||||
*
|
||||
* 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 3 of the License, or
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "fonts.h"
|
||||
|
||||
Fonts::Fonts(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_antiAliasing(false)
|
||||
, m_hintingModel(new QStandardItemModel(this))
|
||||
{
|
||||
KXftConfig xft;
|
||||
const auto aaState = xft.getAntiAliasing();
|
||||
m_antiAliasing = (aaState != KXftConfig::AntiAliasing::Disabled);
|
||||
|
||||
// Hinting options
|
||||
for (KXftConfig::Hint::Style s : {KXftConfig::Hint::None, KXftConfig::Hint::Slight, KXftConfig::Hint::Medium, KXftConfig::Hint::Full}) {
|
||||
auto item = new QStandardItem(KXftConfig::description(s));
|
||||
m_hintingModel->appendRow(item);
|
||||
}
|
||||
|
||||
// hinting
|
||||
KXftConfig::Hint::Style hStyle = KXftConfig::Hint::NotSet;
|
||||
xft.getHintStyle(hStyle);
|
||||
// if it is not set, we set it to slight hinting
|
||||
if (hStyle == KXftConfig::Hint::NotSet) {
|
||||
hStyle = KXftConfig::Hint::Slight;
|
||||
}
|
||||
m_hinting = hStyle;
|
||||
}
|
||||
|
||||
bool Fonts::antiAliasing() const
|
||||
{
|
||||
return m_antiAliasing;
|
||||
}
|
||||
|
||||
void Fonts::setAntiAliasing(bool antiAliasing)
|
||||
{
|
||||
if (m_antiAliasing != antiAliasing) {
|
||||
m_antiAliasing = antiAliasing;
|
||||
save();
|
||||
}
|
||||
}
|
||||
|
||||
int Fonts::hintingCurrentIndex() const
|
||||
{
|
||||
return hinting() - KXftConfig::Hint::None;
|
||||
}
|
||||
|
||||
void Fonts::setHintingCurrentIndex(int index)
|
||||
{
|
||||
setHinting(static_cast<KXftConfig::Hint::Style>(KXftConfig::Hint::None + index));
|
||||
}
|
||||
|
||||
KXftConfig::Hint::Style Fonts::hinting() const
|
||||
{
|
||||
return m_hinting;
|
||||
}
|
||||
|
||||
void Fonts::setHinting(KXftConfig::Hint::Style hinting)
|
||||
{
|
||||
if (m_hinting != hinting) {
|
||||
m_hinting = hinting;
|
||||
save();
|
||||
emit hintingChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QStandardItemModel *Fonts::hintingModel()
|
||||
{
|
||||
return m_hintingModel;
|
||||
}
|
||||
|
||||
void Fonts::save()
|
||||
{
|
||||
KXftConfig xft;
|
||||
KXftConfig::AntiAliasing::State aaState = KXftConfig::AntiAliasing::NotSet;
|
||||
if (xft.antiAliasingHasLocalConfig()) {
|
||||
aaState = m_antiAliasing ? KXftConfig::AntiAliasing::Enabled : KXftConfig::AntiAliasing::Disabled;
|
||||
}
|
||||
xft.setAntiAliasing(aaState);
|
||||
xft.setHintStyle(m_hinting);
|
||||
xft.apply();
|
||||
}
|
||||
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2021 CutefishOS Team.
|
||||
*
|
||||
* Author: Reion Wong <reionwong@gmail.com>
|
||||
*
|
||||
* 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 3 of the License, or
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FONTS_H
|
||||
#define FONTS_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QStandardItemModel>
|
||||
#include "kxftconfig.h"
|
||||
|
||||
class Fonts : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool antiAliasing READ antiAliasing WRITE setAntiAliasing NOTIFY antiAliasingChanged)
|
||||
Q_PROPERTY(QStandardItemModel * hintingModel READ hintingModel CONSTANT)
|
||||
Q_PROPERTY(int hintingCurrentIndex READ hintingCurrentIndex WRITE setHintingCurrentIndex NOTIFY hintingCurrentIndexChanged)
|
||||
|
||||
public:
|
||||
explicit Fonts(QObject *parent = nullptr);
|
||||
|
||||
bool antiAliasing() const;
|
||||
void setAntiAliasing(bool antiAliasing);
|
||||
|
||||
int hintingCurrentIndex() const;
|
||||
void setHintingCurrentIndex(int index);
|
||||
|
||||
KXftConfig::Hint::Style hinting() const;
|
||||
void setHinting(KXftConfig::Hint::Style hinting);
|
||||
|
||||
QStandardItemModel *hintingModel();
|
||||
|
||||
void save();
|
||||
|
||||
signals:
|
||||
void antiAliasingChanged();
|
||||
void hintingChanged();
|
||||
void hintingCurrentIndexChanged();
|
||||
|
||||
private:
|
||||
bool m_antiAliasing;
|
||||
QStandardItemModel *m_hintingModel;
|
||||
KXftConfig::Hint::Style m_hinting;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,893 @@
|
||||
/*
|
||||
Copyright (c) 2002 Craig Drummond <craig@kde.org>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "kxftconfig.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QStandardPaths>
|
||||
#include <QX11Info>
|
||||
|
||||
#include <fontconfig/fontconfig.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
static int point2Pixel(double point)
|
||||
{
|
||||
return (int)(((point * QX11Info::appDpiY()) / 72.0) + 0.5);
|
||||
}
|
||||
|
||||
static int pixel2Point(double pixel)
|
||||
{
|
||||
return (int)(((pixel * 72.0) / (double)QX11Info::appDpiY()) + 0.5);
|
||||
}
|
||||
|
||||
static bool equal(double d1, double d2)
|
||||
{
|
||||
return (fabs(d1 - d2) < 0.0001);
|
||||
}
|
||||
|
||||
static QString dirSyntax(const QString &d)
|
||||
{
|
||||
if (d.isNull()) {
|
||||
return d;
|
||||
}
|
||||
|
||||
QString ds(d);
|
||||
ds.replace(QLatin1String("//"), QLatin1String("/"));
|
||||
if (!ds.endsWith(QLatin1Char('/'))) {
|
||||
ds += QLatin1Char('/');
|
||||
}
|
||||
|
||||
return ds;
|
||||
}
|
||||
|
||||
inline bool fExists(const QString &p)
|
||||
{
|
||||
return QFileInfo(p).isFile();
|
||||
}
|
||||
|
||||
inline bool dWritable(const QString &p)
|
||||
{
|
||||
QFileInfo info(p);
|
||||
return info.isDir() && info.isWritable();
|
||||
}
|
||||
|
||||
static QString getDir(const QString &path)
|
||||
{
|
||||
QString str(path);
|
||||
|
||||
const int slashPos = str.lastIndexOf(QLatin1Char('/'));
|
||||
if (slashPos != -1) {
|
||||
str.truncate(slashPos + 1);
|
||||
}
|
||||
|
||||
return dirSyntax(str);
|
||||
}
|
||||
|
||||
static QDateTime getTimeStamp(const QString &item)
|
||||
{
|
||||
return QFileInfo(item).lastModified();
|
||||
}
|
||||
|
||||
static QString getEntry(QDomElement element, const char *type, unsigned int numAttributes, ...)
|
||||
{
|
||||
if (numAttributes == uint(element.attributes().length())) {
|
||||
va_list args;
|
||||
unsigned int arg;
|
||||
bool ok = true;
|
||||
|
||||
va_start(args, numAttributes);
|
||||
|
||||
for (arg = 0; arg < numAttributes && ok; ++arg) {
|
||||
const char *attr = va_arg(args, const char *);
|
||||
const char *val = va_arg(args, const char *);
|
||||
|
||||
if (!attr || !val || val != element.attribute(attr)) {
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
|
||||
if (ok) {
|
||||
QDomNode n = element.firstChild();
|
||||
|
||||
if (!n.isNull()) {
|
||||
QDomElement e = n.toElement();
|
||||
|
||||
if (!e.isNull() && type == e.tagName()) {
|
||||
return e.text();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
static KXftConfig::SubPixel::Type strToType(const char *str)
|
||||
{
|
||||
if (0 == strcmp(str, "rgb")) {
|
||||
return KXftConfig::SubPixel::Rgb;
|
||||
} else if (0 == strcmp(str, "bgr")) {
|
||||
return KXftConfig::SubPixel::Bgr;
|
||||
} else if (0 == strcmp(str, "vrgb")) {
|
||||
return KXftConfig::SubPixel::Vrgb;
|
||||
} else if (0 == strcmp(str, "vbgr")) {
|
||||
return KXftConfig::SubPixel::Vbgr;
|
||||
} else if (0 == strcmp(str, "none")) {
|
||||
return KXftConfig::SubPixel::None;
|
||||
} else {
|
||||
return KXftConfig::SubPixel::NotSet;
|
||||
}
|
||||
}
|
||||
|
||||
static KXftConfig::Hint::Style strToStyle(const char *str)
|
||||
{
|
||||
if (0 == strcmp(str, "hintslight")) {
|
||||
return KXftConfig::Hint::Slight;
|
||||
} else if (0 == strcmp(str, "hintmedium")) {
|
||||
return KXftConfig::Hint::Medium;
|
||||
} else if (0 == strcmp(str, "hintfull")) {
|
||||
return KXftConfig::Hint::Full;
|
||||
} else {
|
||||
return KXftConfig::Hint::None;
|
||||
}
|
||||
}
|
||||
|
||||
KXftConfig::KXftConfig()
|
||||
: m_doc("fontconfig")
|
||||
, m_file(getConfigFile())
|
||||
{
|
||||
qDebug() << "Using fontconfig file:" << m_file;
|
||||
reset();
|
||||
}
|
||||
|
||||
KXftConfig::~KXftConfig()
|
||||
{
|
||||
}
|
||||
|
||||
//
|
||||
// Obtain location of config file to use.
|
||||
QString KXftConfig::getConfigFile()
|
||||
{
|
||||
FcStrList *list = FcConfigGetConfigFiles(FcConfigGetCurrent());
|
||||
QStringList localFiles;
|
||||
FcChar8 *file;
|
||||
QString home(dirSyntax(QDir::homePath()));
|
||||
|
||||
m_globalFiles.clear();
|
||||
|
||||
while ((file = FcStrListNext(list))) {
|
||||
QString f((const char *)file);
|
||||
|
||||
if (fExists(f) && 0 == f.indexOf(home)) {
|
||||
localFiles.append(f);
|
||||
} else {
|
||||
m_globalFiles.append(f);
|
||||
}
|
||||
}
|
||||
FcStrListDone(list);
|
||||
|
||||
//
|
||||
// Go through list of localFiles, looking for the preferred one...
|
||||
if (!localFiles.isEmpty()) {
|
||||
for (const QString &file : qAsConst(localFiles)) {
|
||||
if (file.endsWith(QLatin1String("/fonts.conf")) || file.endsWith(QLatin1String("/.fonts.conf"))) {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
return localFiles.front(); // Just return the 1st one...
|
||||
} else { // Hmmm... no known localFiles?
|
||||
if (FcGetVersion() >= 21000) {
|
||||
const QString targetPath(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QLatin1Char('/') + QLatin1String("fontconfig"));
|
||||
QDir target(targetPath);
|
||||
if (!target.exists()) {
|
||||
target.mkpath(targetPath);
|
||||
}
|
||||
return targetPath + QLatin1String("/fonts.conf");
|
||||
} else {
|
||||
return home + QLatin1String("/.fonts.conf");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool KXftConfig::reset()
|
||||
{
|
||||
m_madeChanges = false;
|
||||
m_hint.reset();
|
||||
m_hinting.reset();
|
||||
m_excludeRange.reset();
|
||||
m_excludePixelRange.reset();
|
||||
m_subPixel.reset();
|
||||
m_antiAliasing.reset();
|
||||
m_antiAliasingHasLocalConfig = false;
|
||||
m_subPixelHasLocalConfig = false;
|
||||
m_hintHasLocalConfig = false;
|
||||
|
||||
bool ok = false;
|
||||
std::for_each(m_globalFiles.cbegin(), m_globalFiles.cend(), [this, &ok](const QString &file) {
|
||||
ok |= parseConfigFile(file);
|
||||
});
|
||||
|
||||
AntiAliasing globalAntialiasing;
|
||||
globalAntialiasing.state = m_antiAliasing.state;
|
||||
SubPixel globalSubPixel;
|
||||
globalSubPixel.type = m_subPixel.type;
|
||||
Hint globalHint;
|
||||
globalHint.style = m_hint.style;
|
||||
Exclude globalExcludeRange;
|
||||
globalExcludeRange.from = m_excludeRange.from;
|
||||
globalExcludeRange.to = m_excludePixelRange.to;
|
||||
Exclude globalExcludePixelRange;
|
||||
globalExcludePixelRange.from = m_excludePixelRange.from;
|
||||
globalExcludePixelRange.to = m_excludePixelRange.to;
|
||||
Hinting globalHinting;
|
||||
globalHinting.set = m_hinting.set;
|
||||
|
||||
m_antiAliasing.reset();
|
||||
m_subPixel.reset();
|
||||
m_hint.reset();
|
||||
m_hinting.reset();
|
||||
m_excludeRange.reset();
|
||||
m_excludePixelRange.reset();
|
||||
|
||||
ok |= parseConfigFile(m_file);
|
||||
|
||||
if (m_antiAliasing.node.isNull()) {
|
||||
m_antiAliasing = globalAntialiasing;
|
||||
} else {
|
||||
m_antiAliasingHasLocalConfig = true;
|
||||
}
|
||||
|
||||
if (m_subPixel.node.isNull()) {
|
||||
m_subPixel = globalSubPixel;
|
||||
} else {
|
||||
m_subPixelHasLocalConfig = true;
|
||||
}
|
||||
|
||||
if (m_hint.node.isNull()) {
|
||||
m_hint = globalHint;
|
||||
} else {
|
||||
m_hintHasLocalConfig = true;
|
||||
}
|
||||
|
||||
if (m_hinting.node.isNull()) {
|
||||
m_hinting = globalHinting;
|
||||
}
|
||||
if (m_excludeRange.node.isNull()) {
|
||||
m_excludeRange = globalExcludeRange;
|
||||
}
|
||||
if (m_excludePixelRange.node.isNull()) {
|
||||
m_excludePixelRange = globalExcludePixelRange;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool KXftConfig::apply()
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
if (m_madeChanges) {
|
||||
//
|
||||
// Check if file has been written since we last read it. If it has, then re-read and add any
|
||||
// of our changes...
|
||||
if (fExists(m_file) && getTimeStamp(m_file) != m_time) {
|
||||
KXftConfig newConfig;
|
||||
|
||||
newConfig.setExcludeRange(m_excludeRange.from, m_excludeRange.to);
|
||||
newConfig.setSubPixelType(m_subPixel.type);
|
||||
newConfig.setHintStyle(m_hint.style);
|
||||
newConfig.setAntiAliasing(m_antiAliasing.state);
|
||||
|
||||
ok = newConfig.changed() ? newConfig.apply() : true;
|
||||
if (ok) {
|
||||
reset();
|
||||
} else {
|
||||
m_time = getTimeStamp(m_file);
|
||||
}
|
||||
} else {
|
||||
// Ensure these are always equal...
|
||||
m_excludePixelRange.from = (int)point2Pixel(m_excludeRange.from);
|
||||
m_excludePixelRange.to = (int)point2Pixel(m_excludeRange.to);
|
||||
|
||||
FcAtomic *atomic = FcAtomicCreate((const unsigned char *)(QFile::encodeName(m_file).data()));
|
||||
|
||||
ok = false;
|
||||
if (atomic) {
|
||||
if (FcAtomicLock(atomic)) {
|
||||
FILE *f = fopen((char *)FcAtomicNewFile(atomic), "w");
|
||||
|
||||
if (f) {
|
||||
applySubPixelType();
|
||||
applyHintStyle();
|
||||
applyAntiAliasing();
|
||||
applyExcludeRange(false);
|
||||
applyExcludeRange(true);
|
||||
|
||||
//
|
||||
// Check document syntax...
|
||||
static const char qtXmlHeader[] = "<?xml version = '1.0'?>";
|
||||
static const char xmlHeader[] = "<?xml version=\"1.0\"?>";
|
||||
static const char qtDocTypeLine[] = "<!DOCTYPE fontconfig>";
|
||||
static const char docTypeLine[] =
|
||||
"<!DOCTYPE fontconfig SYSTEM "
|
||||
"\"fonts.dtd\">";
|
||||
|
||||
QString str(m_doc.toString());
|
||||
int idx;
|
||||
|
||||
if (0 != str.indexOf("<?xml")) {
|
||||
str.insert(0, xmlHeader);
|
||||
} else if (0 == str.indexOf(qtXmlHeader)) {
|
||||
str.replace(0, strlen(qtXmlHeader), xmlHeader);
|
||||
}
|
||||
|
||||
if (-1 != (idx = str.indexOf(qtDocTypeLine))) {
|
||||
str.replace(idx, strlen(qtDocTypeLine), docTypeLine);
|
||||
}
|
||||
|
||||
//
|
||||
// Write to file...
|
||||
fputs(str.toUtf8(), f);
|
||||
fclose(f);
|
||||
|
||||
if (FcAtomicReplaceOrig(atomic)) {
|
||||
ok = true;
|
||||
reset(); // Re-read contents..
|
||||
} else {
|
||||
FcAtomicDeleteNew(atomic);
|
||||
}
|
||||
}
|
||||
FcAtomicUnlock(atomic);
|
||||
}
|
||||
FcAtomicDestroy(atomic);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool KXftConfig::subPixelTypeHasLocalConfig() const
|
||||
{
|
||||
return m_subPixelHasLocalConfig;
|
||||
}
|
||||
|
||||
bool KXftConfig::getSubPixelType(SubPixel::Type &type)
|
||||
{
|
||||
type = m_subPixel.type;
|
||||
return SubPixel::None != m_subPixel.type;
|
||||
}
|
||||
|
||||
void KXftConfig::setSubPixelType(SubPixel::Type type)
|
||||
{
|
||||
if (type != m_subPixel.type) {
|
||||
m_subPixel.type = type;
|
||||
m_madeChanges = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool KXftConfig::hintStyleHasLocalConfig() const
|
||||
{
|
||||
return m_hintHasLocalConfig;
|
||||
}
|
||||
|
||||
bool KXftConfig::getHintStyle(Hint::Style &style)
|
||||
{
|
||||
if (Hint::NotSet != m_hint.style && !m_hint.toBeRemoved) {
|
||||
style = m_hint.style;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void KXftConfig::setHintStyle(Hint::Style style)
|
||||
{
|
||||
if ((Hint::NotSet == style && Hint::NotSet != m_hint.style && !m_hint.toBeRemoved)
|
||||
|| (Hint::NotSet != style && (style != m_hint.style || m_hint.toBeRemoved))) {
|
||||
m_hint.toBeRemoved = (Hint::NotSet == style);
|
||||
m_hint.style = style;
|
||||
m_madeChanges = true;
|
||||
}
|
||||
|
||||
if (Hint::NotSet != style) {
|
||||
setHinting(Hint::None != m_hint.style);
|
||||
}
|
||||
}
|
||||
|
||||
void KXftConfig::setHinting(bool set)
|
||||
{
|
||||
if (set != m_hinting.set) {
|
||||
m_hinting.set = set;
|
||||
m_madeChanges = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool KXftConfig::getExcludeRange(double &from, double &to)
|
||||
{
|
||||
if (!equal(0, m_excludeRange.from) || !equal(0, m_excludeRange.to)) {
|
||||
from = m_excludeRange.from;
|
||||
to = m_excludeRange.to;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void KXftConfig::setExcludeRange(double from, double to)
|
||||
{
|
||||
double f = from < to ? from : to, t = from < to ? to : from;
|
||||
|
||||
if (!equal(f, m_excludeRange.from) || !equal(t, m_excludeRange.to)) {
|
||||
m_excludeRange.from = f;
|
||||
m_excludeRange.to = t;
|
||||
m_madeChanges = true;
|
||||
}
|
||||
}
|
||||
|
||||
QString KXftConfig::description(SubPixel::Type t)
|
||||
{
|
||||
return QString();
|
||||
// switch (t) {
|
||||
// default:
|
||||
// case SubPixel::NotSet:
|
||||
// return QObject::tr("use system subpixel setting", "Vendor default");
|
||||
// case SubPixel::None:
|
||||
// return QObject::tr("no subpixel rendering", "None");
|
||||
// case SubPixel::Rgb:
|
||||
// return QObject::tr("RGB");
|
||||
// case SubPixel::Bgr:
|
||||
// return QObject::tr("BGR");
|
||||
// case SubPixel::Vrgb:
|
||||
// return QObject::tr("Vertical RGB");
|
||||
// case SubPixel::Vbgr:
|
||||
// return QObject::tr("Vertical BGR");
|
||||
// }
|
||||
}
|
||||
|
||||
const char *KXftConfig::toStr(SubPixel::Type t)
|
||||
{
|
||||
switch (t) {
|
||||
default:
|
||||
case SubPixel::NotSet:
|
||||
return "";
|
||||
case SubPixel::None:
|
||||
return "none";
|
||||
case SubPixel::Rgb:
|
||||
return "rgb";
|
||||
case SubPixel::Bgr:
|
||||
return "bgr";
|
||||
case SubPixel::Vrgb:
|
||||
return "vrgb";
|
||||
case SubPixel::Vbgr:
|
||||
return "vbgr";
|
||||
}
|
||||
}
|
||||
|
||||
QString KXftConfig::description(Hint::Style s)
|
||||
{
|
||||
switch (s) {
|
||||
default:
|
||||
case Hint::NotSet:
|
||||
return QObject::tr("Vendor default");
|
||||
case Hint::Medium:
|
||||
return QObject::tr("Medium");
|
||||
case Hint::None:
|
||||
return QObject::tr("None");
|
||||
case Hint::Slight:
|
||||
return QObject::tr("Slight");
|
||||
case Hint::Full:
|
||||
return QObject::tr("Full");
|
||||
}
|
||||
}
|
||||
|
||||
const char *KXftConfig::toStr(Hint::Style s)
|
||||
{
|
||||
switch (s) {
|
||||
default:
|
||||
case Hint::NotSet:
|
||||
return "";
|
||||
case Hint::Medium:
|
||||
return "hintmedium";
|
||||
case Hint::None:
|
||||
return "hintnone";
|
||||
case Hint::Slight:
|
||||
return "hintslight";
|
||||
case Hint::Full:
|
||||
return "hintfull";
|
||||
}
|
||||
}
|
||||
|
||||
bool KXftConfig::parseConfigFile(const QString &filename)
|
||||
{
|
||||
bool ok = false;
|
||||
|
||||
QFile f(filename);
|
||||
|
||||
if (f.open(QIODevice::ReadOnly)) {
|
||||
m_time = getTimeStamp(filename);
|
||||
ok = true;
|
||||
m_doc.clear();
|
||||
|
||||
if (m_doc.setContent(&f)) {
|
||||
readContents();
|
||||
}
|
||||
f.close();
|
||||
} else {
|
||||
ok = !fExists(filename) && dWritable(getDir(filename));
|
||||
}
|
||||
|
||||
if (m_doc.documentElement().isNull()) {
|
||||
m_doc.appendChild(m_doc.createElement("fontconfig"));
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
//
|
||||
// Check exclude range values - i.e. size and pixel size...
|
||||
// If "size" range is set, ensure "pixelsize" matches...
|
||||
if (!equal(0, m_excludeRange.from) || !equal(0, m_excludeRange.to)) {
|
||||
double pFrom = (double)point2Pixel(m_excludeRange.from), pTo = (double)point2Pixel(m_excludeRange.to);
|
||||
|
||||
if (!equal(pFrom, m_excludePixelRange.from) || !equal(pTo, m_excludePixelRange.to)) {
|
||||
m_excludePixelRange.from = pFrom;
|
||||
m_excludePixelRange.to = pTo;
|
||||
m_madeChanges = true;
|
||||
}
|
||||
} else if (!equal(0, m_excludePixelRange.from) || !equal(0, m_excludePixelRange.to)) {
|
||||
// "pixelsize" set, but not "size" !!!
|
||||
m_excludeRange.from = (int)pixel2Point(m_excludePixelRange.from);
|
||||
m_excludeRange.to = (int)pixel2Point(m_excludePixelRange.to);
|
||||
m_madeChanges = true;
|
||||
}
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
void KXftConfig::readContents()
|
||||
{
|
||||
QDomNode n = m_doc.documentElement().firstChild();
|
||||
|
||||
while (!n.isNull()) {
|
||||
QDomElement e = n.toElement();
|
||||
|
||||
if (!e.isNull()) {
|
||||
if ("match" == e.tagName()) {
|
||||
QString str;
|
||||
|
||||
int childNodesCount = e.childNodes().count();
|
||||
QDomNode en = e.firstChild();
|
||||
while (!en.isNull()) {
|
||||
if (en.isComment()) {
|
||||
childNodesCount--;
|
||||
}
|
||||
en = en.nextSibling();
|
||||
}
|
||||
|
||||
switch (childNodesCount) {
|
||||
case 1:
|
||||
if ("font" == e.attribute("target") || "pattern" == e.attribute("target")) {
|
||||
QDomNode en = e.firstChild();
|
||||
while (!en.isNull()) {
|
||||
QDomElement ene = en.toElement();
|
||||
|
||||
while (ene.isComment()) {
|
||||
ene = ene.nextSiblingElement();
|
||||
}
|
||||
|
||||
if (!ene.isNull() && "edit" == ene.tagName()) {
|
||||
if (!(str = getEntry(ene, "const", 2, "name", "rgba", "mode", "assign")).isNull()
|
||||
|| (m_subPixel.type == SubPixel::NotSet && !(str = getEntry(ene, "const", 2, "name", "rgba", "mode", "append")).isNull())) {
|
||||
m_subPixel.node = n;
|
||||
m_subPixel.type = strToType(str.toLatin1());
|
||||
} else if (!(str = getEntry(ene, "const", 2, "name", "hintstyle", "mode", "assign")).isNull()
|
||||
|| (m_hint.style == Hint::NotSet
|
||||
&& !(str = getEntry(ene, "const", 2, "name", "hintstyle", "mode", "append")).isNull())) {
|
||||
m_hint.node = n;
|
||||
m_hint.style = strToStyle(str.toLatin1());
|
||||
} else if (!(str = getEntry(ene, "bool", 2, "name", "hinting", "mode", "assign")).isNull()) {
|
||||
m_hinting.node = n;
|
||||
m_hinting.set = str.toLower() != "false";
|
||||
} else if (!(str = getEntry(ene, "bool", 2, "name", "antialias", "mode", "assign")).isNull()
|
||||
|| (m_antiAliasing.state == AntiAliasing::NotSet
|
||||
&& !(str = getEntry(ene, "bool", 2, "name", "antialias", "mode", "append")).isNull())) {
|
||||
m_antiAliasing.node = n;
|
||||
m_antiAliasing.state = str.toLower() != "false" ? AntiAliasing::Enabled : AntiAliasing::Disabled;
|
||||
}
|
||||
}
|
||||
en = en.nextSibling();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3: // CPD: Is target "font" or "pattern" ????
|
||||
if ("font" == e.attribute("target")) {
|
||||
bool foundFalse = false;
|
||||
QDomNode en = e.firstChild();
|
||||
while (en.isComment()) {
|
||||
en = en.nextSibling();
|
||||
}
|
||||
double from = -1.0, to = -1.0, pixelFrom = -1.0, pixelTo = -1.0;
|
||||
|
||||
while (!en.isNull()) {
|
||||
QDomElement ene = en.toElement();
|
||||
|
||||
if (!ene.isNull()) {
|
||||
if ("test" == ene.tagName()) {
|
||||
// kcmfonts used to write incorrectly more or less instead of
|
||||
// more_eq and less_eq, so read both,
|
||||
// first the old (wrong) one then the right one
|
||||
if (!(str = getEntry(ene, "double", 3, "qual", "any", "name", "size", "compare", "more")).isNull()) {
|
||||
from = str.toDouble();
|
||||
}
|
||||
if (!(str = getEntry(ene, "double", 3, "qual", "any", "name", "size", "compare", "more_eq")).isNull()) {
|
||||
from = str.toDouble();
|
||||
}
|
||||
if (!(str = getEntry(ene, "double", 3, "qual", "any", "name", "size", "compare", "less")).isNull()) {
|
||||
to = str.toDouble();
|
||||
}
|
||||
if (!(str = getEntry(ene, "double", 3, "qual", "any", "name", "size", "compare", "less_eq")).isNull()) {
|
||||
to = str.toDouble();
|
||||
}
|
||||
if (!(str = getEntry(ene, "double", 3, "qual", "any", "name", "pixelsize", "compare", "more")).isNull()) {
|
||||
pixelFrom = str.toDouble();
|
||||
}
|
||||
if (!(str = getEntry(ene, "double", 3, "qual", "any", "name", "pixelsize", "compare", "more_eq")).isNull()) {
|
||||
pixelFrom = str.toDouble();
|
||||
}
|
||||
if (!(str = getEntry(ene, "double", 3, "qual", "any", "name", "pixelsize", "compare", "less")).isNull()) {
|
||||
pixelTo = str.toDouble();
|
||||
}
|
||||
if (!(str = getEntry(ene, "double", 3, "qual", "any", "name", "pixelsize", "compare", "less_eq")).isNull()) {
|
||||
pixelTo = str.toDouble();
|
||||
}
|
||||
} else if ("edit" == ene.tagName() && "false" == getEntry(ene, "bool", 2, "name", "antialias", "mode", "assign")) {
|
||||
foundFalse = true;
|
||||
}
|
||||
}
|
||||
|
||||
en = en.nextSibling();
|
||||
}
|
||||
|
||||
if ((from >= 0 || to >= 0) && foundFalse) {
|
||||
m_excludeRange.from = from < to ? from : to;
|
||||
m_excludeRange.to = from < to ? to : from;
|
||||
m_excludeRange.node = n;
|
||||
} else if ((pixelFrom >= 0 || pixelTo >= 0) && foundFalse) {
|
||||
m_excludePixelRange.from = pixelFrom < pixelTo ? pixelFrom : pixelTo;
|
||||
m_excludePixelRange.to = pixelFrom < pixelTo ? pixelTo : pixelFrom;
|
||||
m_excludePixelRange.node = n;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
n = n.nextSibling();
|
||||
}
|
||||
}
|
||||
|
||||
void KXftConfig::applySubPixelType()
|
||||
{
|
||||
if (SubPixel::NotSet == m_subPixel.type) {
|
||||
if (!m_subPixel.node.isNull()) {
|
||||
m_doc.documentElement().removeChild(m_subPixel.node);
|
||||
m_subPixel.node.clear();
|
||||
}
|
||||
} else {
|
||||
QDomElement matchNode = m_doc.createElement("match");
|
||||
QDomElement typeNode = m_doc.createElement("const");
|
||||
QDomElement editNode = m_doc.createElement("edit");
|
||||
QDomText typeText = m_doc.createTextNode(toStr(m_subPixel.type));
|
||||
|
||||
matchNode.setAttribute("target", "font");
|
||||
editNode.setAttribute("mode", "assign");
|
||||
editNode.setAttribute("name", "rgba");
|
||||
editNode.appendChild(typeNode);
|
||||
typeNode.appendChild(typeText);
|
||||
matchNode.appendChild(editNode);
|
||||
if (m_subPixel.node.isNull()) {
|
||||
m_doc.documentElement().appendChild(matchNode);
|
||||
} else {
|
||||
m_doc.documentElement().replaceChild(matchNode, m_subPixel.node);
|
||||
}
|
||||
m_subPixel.node = matchNode;
|
||||
}
|
||||
}
|
||||
|
||||
void KXftConfig::applyHintStyle()
|
||||
{
|
||||
applyHinting();
|
||||
|
||||
if (Hint::NotSet == m_hint.style) {
|
||||
if (!m_hint.node.isNull()) {
|
||||
m_doc.documentElement().removeChild(m_hint.node);
|
||||
m_hint.node.clear();
|
||||
}
|
||||
if (!m_hinting.node.isNull()) {
|
||||
m_doc.documentElement().removeChild(m_hinting.node);
|
||||
m_hinting.node.clear();
|
||||
}
|
||||
} else {
|
||||
QDomElement matchNode = m_doc.createElement("match"), typeNode = m_doc.createElement("const"), editNode = m_doc.createElement("edit");
|
||||
QDomText typeText = m_doc.createTextNode(toStr(m_hint.style));
|
||||
|
||||
matchNode.setAttribute("target", "font");
|
||||
editNode.setAttribute("mode", "assign");
|
||||
editNode.setAttribute("name", "hintstyle");
|
||||
editNode.appendChild(typeNode);
|
||||
typeNode.appendChild(typeText);
|
||||
matchNode.appendChild(editNode);
|
||||
if (m_hint.node.isNull()) {
|
||||
m_doc.documentElement().appendChild(matchNode);
|
||||
} else {
|
||||
m_doc.documentElement().replaceChild(matchNode, m_hint.node);
|
||||
}
|
||||
m_hint.node = matchNode;
|
||||
}
|
||||
}
|
||||
|
||||
void KXftConfig::applyHinting()
|
||||
{
|
||||
QDomElement matchNode = m_doc.createElement("match"), typeNode = m_doc.createElement("bool"), editNode = m_doc.createElement("edit");
|
||||
QDomText typeText = m_doc.createTextNode(m_hinting.set ? "true" : "false");
|
||||
|
||||
matchNode.setAttribute("target", "font");
|
||||
editNode.setAttribute("mode", "assign");
|
||||
editNode.setAttribute("name", "hinting");
|
||||
editNode.appendChild(typeNode);
|
||||
typeNode.appendChild(typeText);
|
||||
matchNode.appendChild(editNode);
|
||||
if (m_hinting.node.isNull()) {
|
||||
m_doc.documentElement().appendChild(matchNode);
|
||||
} else {
|
||||
m_doc.documentElement().replaceChild(matchNode, m_hinting.node);
|
||||
}
|
||||
m_hinting.node = matchNode;
|
||||
}
|
||||
|
||||
void KXftConfig::applyExcludeRange(bool pixel)
|
||||
{
|
||||
Exclude &range = pixel ? m_excludePixelRange : m_excludeRange;
|
||||
|
||||
if (equal(range.from, 0) && equal(range.to, 0)) {
|
||||
if (!range.node.isNull()) {
|
||||
m_doc.documentElement().removeChild(range.node);
|
||||
range.node.clear();
|
||||
}
|
||||
} else {
|
||||
QString fromString, toString;
|
||||
|
||||
fromString.setNum(range.from);
|
||||
toString.setNum(range.to);
|
||||
|
||||
QDomElement matchNode = m_doc.createElement("match"), fromTestNode = m_doc.createElement("test"), fromNode = m_doc.createElement("double"),
|
||||
toTestNode = m_doc.createElement("test"), toNode = m_doc.createElement("double"), editNode = m_doc.createElement("edit"),
|
||||
boolNode = m_doc.createElement("bool");
|
||||
QDomText fromText = m_doc.createTextNode(fromString), toText = m_doc.createTextNode(toString), boolText = m_doc.createTextNode("false");
|
||||
|
||||
matchNode.setAttribute("target", "font"); // CPD: Is target "font" or "pattern" ????
|
||||
fromTestNode.setAttribute("qual", "any");
|
||||
fromTestNode.setAttribute("name", pixel ? "pixelsize" : "size");
|
||||
fromTestNode.setAttribute("compare", "more_eq");
|
||||
fromTestNode.appendChild(fromNode);
|
||||
fromNode.appendChild(fromText);
|
||||
toTestNode.setAttribute("qual", "any");
|
||||
toTestNode.setAttribute("name", pixel ? "pixelsize" : "size");
|
||||
toTestNode.setAttribute("compare", "less_eq");
|
||||
toTestNode.appendChild(toNode);
|
||||
toNode.appendChild(toText);
|
||||
editNode.setAttribute("mode", "assign");
|
||||
editNode.setAttribute("name", "antialias");
|
||||
editNode.appendChild(boolNode);
|
||||
boolNode.appendChild(boolText);
|
||||
matchNode.appendChild(fromTestNode);
|
||||
matchNode.appendChild(toTestNode);
|
||||
matchNode.appendChild(editNode);
|
||||
|
||||
if (!m_antiAliasing.node.isNull()) {
|
||||
m_doc.documentElement().removeChild(range.node);
|
||||
}
|
||||
if (range.node.isNull()) {
|
||||
m_doc.documentElement().appendChild(matchNode);
|
||||
} else {
|
||||
m_doc.documentElement().replaceChild(matchNode, range.node);
|
||||
}
|
||||
range.node = matchNode;
|
||||
}
|
||||
}
|
||||
|
||||
bool KXftConfig::antiAliasingHasLocalConfig() const
|
||||
{
|
||||
return m_antiAliasingHasLocalConfig;
|
||||
}
|
||||
|
||||
KXftConfig::AntiAliasing::State KXftConfig::getAntiAliasing() const
|
||||
{
|
||||
return m_antiAliasing.state;
|
||||
}
|
||||
|
||||
void KXftConfig::setAntiAliasing(AntiAliasing::State state)
|
||||
{
|
||||
if (state != m_antiAliasing.state) {
|
||||
m_antiAliasing.state = state;
|
||||
m_madeChanges = true;
|
||||
}
|
||||
}
|
||||
|
||||
void KXftConfig::applyAntiAliasing()
|
||||
{
|
||||
if (AntiAliasing::NotSet == m_antiAliasing.state) {
|
||||
if (!m_antiAliasing.node.isNull()) {
|
||||
m_doc.documentElement().removeChild(m_antiAliasing.node);
|
||||
m_antiAliasing.node.clear();
|
||||
}
|
||||
} else {
|
||||
QDomElement matchNode = m_doc.createElement("match");
|
||||
QDomElement typeNode = m_doc.createElement("bool");
|
||||
QDomElement editNode = m_doc.createElement("edit");
|
||||
QDomText typeText = m_doc.createTextNode(m_antiAliasing.state == AntiAliasing::Enabled ? "true" : "false");
|
||||
|
||||
matchNode.setAttribute("target", "font");
|
||||
editNode.setAttribute("mode", "assign");
|
||||
editNode.setAttribute("name", "antialias");
|
||||
editNode.appendChild(typeNode);
|
||||
typeNode.appendChild(typeText);
|
||||
matchNode.appendChild(editNode);
|
||||
if (!m_antiAliasing.node.isNull()) {
|
||||
m_doc.documentElement().removeChild(m_antiAliasing.node);
|
||||
}
|
||||
m_doc.documentElement().appendChild(matchNode);
|
||||
m_antiAliasing.node = matchNode;
|
||||
}
|
||||
}
|
||||
|
||||
// KXftConfig only parses one config file, user's .fonts.conf usually.
|
||||
// If that one doesn't exist, then KXftConfig doesn't know if antialiasing
|
||||
// is enabled or not. So try to find out the default value from the default font.
|
||||
// Maybe there's a better way *shrug*.
|
||||
bool KXftConfig::aliasingEnabled()
|
||||
{
|
||||
FcPattern *pattern = FcPatternCreate();
|
||||
FcConfigSubstitute(nullptr, pattern, FcMatchPattern);
|
||||
FcDefaultSubstitute(pattern);
|
||||
FcResult result;
|
||||
FcPattern *f = FcFontMatch(nullptr, pattern, &result);
|
||||
FcBool antialiased = FcTrue;
|
||||
FcPatternGetBool(f, FC_ANTIALIAS, 0, &antialiased);
|
||||
FcPatternDestroy(f);
|
||||
FcPatternDestroy(pattern);
|
||||
return antialiased == FcTrue;
|
||||
}
|
||||
@ -0,0 +1,242 @@
|
||||
#ifndef __KXFTCONFIG_H__
|
||||
#define __KXFTCONFIG_H__
|
||||
|
||||
/*
|
||||
Copyright (c) 2002 Craig Drummond <craig@kde.org>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QDomDocument>
|
||||
#include <QMetaType>
|
||||
#include <QStringList>
|
||||
|
||||
class KXftConfig
|
||||
{
|
||||
public:
|
||||
struct Item {
|
||||
Item(QDomNode &n)
|
||||
: node(n)
|
||||
, toBeRemoved(false)
|
||||
{
|
||||
}
|
||||
Item()
|
||||
: toBeRemoved(false)
|
||||
{
|
||||
}
|
||||
virtual void reset()
|
||||
{
|
||||
node.clear();
|
||||
toBeRemoved = false;
|
||||
}
|
||||
bool added()
|
||||
{
|
||||
return node.isNull();
|
||||
}
|
||||
|
||||
QDomNode node;
|
||||
|
||||
virtual ~Item()
|
||||
{
|
||||
}
|
||||
bool toBeRemoved;
|
||||
};
|
||||
|
||||
struct SubPixel : public Item {
|
||||
enum Type {
|
||||
NotSet,
|
||||
None,
|
||||
Rgb,
|
||||
Bgr,
|
||||
Vrgb,
|
||||
Vbgr,
|
||||
};
|
||||
|
||||
SubPixel(Type t, QDomNode &n)
|
||||
: Item(n)
|
||||
, type(t)
|
||||
{
|
||||
}
|
||||
SubPixel(Type t = NotSet)
|
||||
: type(t)
|
||||
{
|
||||
}
|
||||
|
||||
void reset() override
|
||||
{
|
||||
Item::reset();
|
||||
type = NotSet;
|
||||
}
|
||||
|
||||
Type type;
|
||||
};
|
||||
|
||||
struct Exclude : public Item {
|
||||
Exclude(double f, double t, QDomNode &n)
|
||||
: Item(n)
|
||||
, from(f)
|
||||
, to(t)
|
||||
{
|
||||
}
|
||||
Exclude(double f = 0, double t = 0)
|
||||
: from(f)
|
||||
, to(t)
|
||||
{
|
||||
}
|
||||
|
||||
void reset() override
|
||||
{
|
||||
Item::reset();
|
||||
from = to = 0;
|
||||
}
|
||||
|
||||
double from, to;
|
||||
};
|
||||
|
||||
struct Hint : public Item {
|
||||
enum Style {
|
||||
NotSet,
|
||||
None,
|
||||
Slight,
|
||||
Medium,
|
||||
Full,
|
||||
};
|
||||
|
||||
Hint(Style s, QDomNode &n)
|
||||
: Item(n)
|
||||
, style(s)
|
||||
{
|
||||
}
|
||||
Hint(Style s = NotSet)
|
||||
: style(s)
|
||||
{
|
||||
}
|
||||
|
||||
void reset() override
|
||||
{
|
||||
Item::reset();
|
||||
style = NotSet;
|
||||
}
|
||||
|
||||
Style style;
|
||||
};
|
||||
|
||||
struct Hinting : public Item {
|
||||
Hinting(bool s, QDomNode &n)
|
||||
: Item(n)
|
||||
, set(s)
|
||||
{
|
||||
}
|
||||
Hinting(bool s = true)
|
||||
: set(s)
|
||||
{
|
||||
}
|
||||
|
||||
void reset() override
|
||||
{
|
||||
Item::reset();
|
||||
set = true;
|
||||
}
|
||||
|
||||
bool set;
|
||||
};
|
||||
|
||||
struct AntiAliasing : public Item {
|
||||
enum State {
|
||||
NotSet,
|
||||
Enabled,
|
||||
Disabled,
|
||||
};
|
||||
|
||||
AntiAliasing(State s, QDomNode &n)
|
||||
: Item(n)
|
||||
, state(s)
|
||||
{
|
||||
}
|
||||
AntiAliasing(State s = NotSet)
|
||||
: state(s)
|
||||
{
|
||||
}
|
||||
|
||||
void reset() override
|
||||
{
|
||||
Item::reset();
|
||||
state = NotSet;
|
||||
}
|
||||
|
||||
enum State state;
|
||||
};
|
||||
|
||||
public:
|
||||
explicit KXftConfig();
|
||||
|
||||
virtual ~KXftConfig();
|
||||
|
||||
bool reset();
|
||||
bool apply();
|
||||
bool getSubPixelType(SubPixel::Type &type);
|
||||
void setSubPixelType(SubPixel::Type type); // SubPixel::None => turn off sub-pixel rendering
|
||||
bool getExcludeRange(double &from, double &to);
|
||||
void setExcludeRange(double from, double to); // from:0, to:0 => turn off exclude range
|
||||
bool getHintStyle(Hint::Style &style);
|
||||
void setHintStyle(Hint::Style style);
|
||||
void setAntiAliasing(AntiAliasing::State state);
|
||||
AntiAliasing::State getAntiAliasing() const;
|
||||
bool antiAliasingHasLocalConfig() const;
|
||||
bool subPixelTypeHasLocalConfig() const;
|
||||
bool hintStyleHasLocalConfig() const;
|
||||
bool changed()
|
||||
{
|
||||
return m_madeChanges;
|
||||
}
|
||||
static QString description(SubPixel::Type t);
|
||||
static const char *toStr(SubPixel::Type t);
|
||||
static QString description(Hint::Style s);
|
||||
static const char *toStr(Hint::Style s);
|
||||
bool aliasingEnabled();
|
||||
|
||||
private:
|
||||
bool parseConfigFile(const QString &filename);
|
||||
void readContents();
|
||||
void applySubPixelType();
|
||||
void applyHintStyle();
|
||||
void applyAntiAliasing();
|
||||
void setHinting(bool set);
|
||||
void applyHinting();
|
||||
void applyExcludeRange(bool pixel);
|
||||
QString getConfigFile();
|
||||
|
||||
private:
|
||||
QStringList m_globalFiles;
|
||||
|
||||
SubPixel m_subPixel;
|
||||
Exclude m_excludeRange, m_excludePixelRange;
|
||||
Hint m_hint;
|
||||
Hinting m_hinting;
|
||||
AntiAliasing m_antiAliasing;
|
||||
bool m_antiAliasingHasLocalConfig;
|
||||
bool m_subPixelHasLocalConfig;
|
||||
bool m_hintHasLocalConfig;
|
||||
QDomDocument m_doc;
|
||||
QString m_file;
|
||||
bool m_madeChanges;
|
||||
QDateTime m_time;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(KXftConfig::Hint::Style)
|
||||
Q_DECLARE_METATYPE(KXftConfig::SubPixel::Type)
|
||||
#endif
|
||||
@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 4.2333332 4.2333335"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="1.0.2 (e86c870879, 2021-01-15)"
|
||||
sodipodi:docname="language.svg">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="31.678384"
|
||||
inkscape:cx="9.2727919"
|
||||
inkscape:cy="5.3664169"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
inkscape:document-rotation="0"
|
||||
showgrid="false"
|
||||
units="px"
|
||||
inkscape:window-width="1770"
|
||||
inkscape:window-height="997"
|
||||
inkscape:window-x="128"
|
||||
inkscape:window-y="215"
|
||||
inkscape:window-maximized="0" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<g
|
||||
transform="matrix(0.11364409,0,0,0.09317682,-1.5119494,-0.87156054)"
|
||||
aria-label="A"
|
||||
id="g31"
|
||||
style="fill:#ffffff;fill-opacity:1">
|
||||
<path
|
||||
d="m 26.7,35.255 1.6735,-5.2065 c 1.2087,-3.8584 2.3243,-7.5309 3.3935,-11.529 h 0.18595 c 1.1157,3.9514 2.1849,7.6703 3.44,11.529 l 1.627,5.2065 z m 14.643,13.853 h 4.5557 L 34.3237,15.033 h -4.7881 l -11.575,34.075 h 4.3698 L 25.631,38.695 h 12.458 z"
|
||||
id="path29"
|
||||
style="fill:#ffffff;fill-opacity:1" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Copyright (C) 2021 CutefishOS Team.
|
||||
*
|
||||
* Author: Reion Wong <reionwong@gmail.com>
|
||||
*
|
||||
* 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 3 of the License, or
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import QtQuick 2.4
|
||||
import QtQuick.Controls 2.4
|
||||
import QtQuick.Layouts 1.3
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
import Cutefish.Settings 1.0
|
||||
import FishUI 1.0 as FishUI
|
||||
import "../"
|
||||
|
||||
ItemPage {
|
||||
id: control
|
||||
headerTitle: qsTr("Fonts")
|
||||
|
||||
Appearance {
|
||||
id: appearance
|
||||
}
|
||||
|
||||
FontsModel {
|
||||
id: fontsModel
|
||||
}
|
||||
|
||||
Fonts {
|
||||
id: fonts
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: fontsModel
|
||||
|
||||
function onLoadFinished() {
|
||||
for (var i in fontsModel.generalFonts) {
|
||||
if (fontsModel.systemGeneralFont === fontsModel.generalFonts[i]) {
|
||||
generalFontComboBox.currentIndex = i
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (i in fontsModel.fixedFonts) {
|
||||
if (fontsModel.systemFixedFont === fontsModel.fixedFonts[i]) {
|
||||
fixedFontComboBox.currentIndex = i
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
console.log("fonts load finished")
|
||||
}
|
||||
}
|
||||
|
||||
Scrollable {
|
||||
anchors.fill: parent
|
||||
contentHeight: layout.implicitHeight
|
||||
|
||||
ColumnLayout {
|
||||
id: layout
|
||||
anchors.fill: parent
|
||||
spacing: FishUI.Units.largeSpacing * 2
|
||||
|
||||
// Font
|
||||
RoundedItem {
|
||||
// Label {
|
||||
// text: qsTr("Font")
|
||||
// color: FishUI.Theme.disabledTextColor
|
||||
// bottomPadding: FishUI.Units.smallSpacing
|
||||
// }
|
||||
|
||||
GridLayout {
|
||||
rows: 3
|
||||
columns: 2
|
||||
|
||||
columnSpacing: FishUI.Units.largeSpacing * 1.5
|
||||
rowSpacing: FishUI.Units.largeSpacing
|
||||
|
||||
Label {
|
||||
text: qsTr("General Font")
|
||||
bottomPadding: FishUI.Units.smallSpacing
|
||||
}
|
||||
|
||||
ComboBox {
|
||||
id: generalFontComboBox
|
||||
model: fontsModel.generalFonts
|
||||
enabled: true
|
||||
Layout.fillWidth: true
|
||||
topInset: 0
|
||||
bottomInset: 0
|
||||
leftPadding: FishUI.Units.largeSpacing
|
||||
rightPadding: FishUI.Units.largeSpacing
|
||||
onActivated: appearance.setGenericFontFamily(currentText)
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("Fixed Font")
|
||||
bottomPadding: FishUI.Units.smallSpacing
|
||||
}
|
||||
|
||||
ComboBox {
|
||||
id: fixedFontComboBox
|
||||
model: fontsModel.fixedFonts
|
||||
enabled: true
|
||||
Layout.fillWidth: true
|
||||
topInset: 0
|
||||
bottomInset: 0
|
||||
leftPadding: FishUI.Units.largeSpacing
|
||||
rightPadding: FishUI.Units.largeSpacing
|
||||
onActivated: appearance.setFixedFontFamily(currentText)
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("Font Size")
|
||||
bottomPadding: FishUI.Units.smallSpacing
|
||||
}
|
||||
|
||||
TabBar {
|
||||
Layout.fillWidth: true
|
||||
|
||||
TabButton {
|
||||
text: qsTr("Small")
|
||||
}
|
||||
|
||||
TabButton {
|
||||
text: qsTr("Medium")
|
||||
}
|
||||
|
||||
TabButton {
|
||||
text: qsTr("Large")
|
||||
}
|
||||
|
||||
TabButton {
|
||||
text: qsTr("Huge")
|
||||
}
|
||||
|
||||
currentIndex: {
|
||||
var index = 0
|
||||
|
||||
if (appearance.fontPointSize <= 9)
|
||||
index = 0
|
||||
else if (appearance.fontPointSize <= 10)
|
||||
index = 1
|
||||
else if (appearance.fontPointSize <= 12)
|
||||
index = 2
|
||||
else if (appearance.fontPointSize <= 15)
|
||||
index = 3
|
||||
|
||||
return index
|
||||
}
|
||||
|
||||
onCurrentIndexChanged: {
|
||||
var fontSize = 0
|
||||
|
||||
switch (currentIndex) {
|
||||
case 0:
|
||||
fontSize = 9
|
||||
break;
|
||||
case 1:
|
||||
fontSize = 10
|
||||
break;
|
||||
case 2:
|
||||
fontSize = 12
|
||||
break;
|
||||
case 3:
|
||||
fontSize = 15
|
||||
break;
|
||||
}
|
||||
|
||||
appearance.setFontPointSize(fontSize)
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("Hinting")
|
||||
bottomPadding: FishUI.Units.smallSpacing
|
||||
}
|
||||
|
||||
ComboBox {
|
||||
model: fonts.hintingModel
|
||||
textRole: "display"
|
||||
Layout.fillWidth: true
|
||||
currentIndex: fonts.hintingCurrentIndex
|
||||
onCurrentIndexChanged: fonts.hintingCurrentIndex = currentIndex
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("Anti-Aliasing")
|
||||
bottomPadding: FishUI.Units.smallSpacing
|
||||
}
|
||||
|
||||
Switch {
|
||||
Layout.fillHeight: true
|
||||
Layout.alignment: Qt.AlignRight
|
||||
checked: fonts.antiAliasing
|
||||
onCheckedChanged: fonts.antiAliasing = checked
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue