Use custom-adjusted font metrics.
This commit is contained in:
parent
4ddff63a9b
commit
86dc01e9bc
16 changed files with 362 additions and 202 deletions
|
|
@ -23,12 +23,16 @@ public:
|
|||
void drawTextLeft(int x, int y, int outerw, const QString &text, int textWidth = -1) {
|
||||
QFontMetrics m(fontMetrics());
|
||||
if (style::RightToLeft() && textWidth < 0) textWidth = m.horizontalAdvance(text);
|
||||
drawText(style::RightToLeft() ? (outerw - x - textWidth) : x, y + m.ascent(), text);
|
||||
const auto result = style::FindAdjustResult(font());
|
||||
const auto ascent = result ? result->iascent : m.ascent();
|
||||
drawText(style::RightToLeft() ? (outerw - x - textWidth) : x, y + ascent, text);
|
||||
}
|
||||
void drawTextRight(int x, int y, int outerw, const QString &text, int textWidth = -1) {
|
||||
QFontMetrics m(fontMetrics());
|
||||
if (!style::RightToLeft() && textWidth < 0) textWidth = m.horizontalAdvance(text);
|
||||
drawText(style::RightToLeft() ? x : (outerw - x - textWidth), y + m.ascent(), text);
|
||||
const auto result = style::FindAdjustResult(font());
|
||||
const auto ascent = result ? result->iascent : m.ascent();
|
||||
drawText(style::RightToLeft() ? x : (outerw - x - textWidth), y + ascent, text);
|
||||
}
|
||||
void drawPixmapLeft(int x, int y, int outerw, const QPixmap &pix, const QRect &from) {
|
||||
drawPixmap(QPoint(style::RightToLeft() ? (outerw - x - (from.width() / pix.devicePixelRatio())) : x, y), pix, from);
|
||||
|
|
|
|||
|
|
@ -107,13 +107,13 @@ void TitleWidget::init(int height) {
|
|||
const auto apple = (family == u".AppleSystemUIFont"_q);
|
||||
setFromFont(style::font(
|
||||
apple ? 13 : (height * 15) / 24,
|
||||
apple ? style::internal::FontBold : 0,
|
||||
apple ? style::FontFlag::Bold : 0,
|
||||
family));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!_textStyle) {
|
||||
setFromFont(style::font(13, style::internal::FontSemibold, 0));
|
||||
setFromFont(style::font(13, style::FontFlag::Semibold, 0));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,12 +29,12 @@ auto PaletteVersion = 0;
|
|||
auto ShortAnimationRunning = rpl::variable<bool>(false);
|
||||
auto RunningShortAnimations = 0;
|
||||
|
||||
std::vector<internal::ModuleBase*> &StyleModules() {
|
||||
[[nodiscard]] std::vector<internal::ModuleBase*> &StyleModules() {
|
||||
static auto result = std::vector<internal::ModuleBase*>();
|
||||
return result;
|
||||
}
|
||||
|
||||
void startModules(int scale) {
|
||||
void StartModules(int scale) {
|
||||
for (const auto module : StyleModules()) {
|
||||
module->start(scale);
|
||||
}
|
||||
|
|
@ -60,14 +60,14 @@ void StopShortAnimation() {
|
|||
|
||||
} // namespace internal
|
||||
|
||||
void startManager(int scale) {
|
||||
internal::registerFontFamily("Open Sans");
|
||||
internal::startModules(scale);
|
||||
void StartManager(int scale) {
|
||||
internal::RegisterFontFamily("Open Sans");
|
||||
internal::StartModules(scale);
|
||||
}
|
||||
|
||||
void stopManager() {
|
||||
internal::destroyFonts();
|
||||
internal::destroyIcons();
|
||||
void StopManager() {
|
||||
internal::DestroyFonts();
|
||||
internal::DestroyIcons();
|
||||
}
|
||||
|
||||
rpl::producer<> PaletteChanged() {
|
||||
|
|
|
|||
|
|
@ -35,8 +35,8 @@ void StopShortAnimation();
|
|||
|
||||
} // namespace internal
|
||||
|
||||
void startManager(int scale);
|
||||
void stopManager();
|
||||
void StartManager(int scale);
|
||||
void StopManager();
|
||||
|
||||
[[nodiscard]] rpl::producer<> PaletteChanged();
|
||||
[[nodiscard]] int PaletteVersion();
|
||||
|
|
|
|||
|
|
@ -57,27 +57,28 @@ public:
|
|||
_data->set(r, g, b, a);
|
||||
}
|
||||
|
||||
operator const QBrush &() const {
|
||||
[[nodiscard]] operator const QBrush &() const {
|
||||
return _data->b;
|
||||
}
|
||||
|
||||
operator const QPen &() const {
|
||||
[[nodiscard]] operator const QPen &() const {
|
||||
return _data->p;
|
||||
}
|
||||
|
||||
ColorData *operator->() const {
|
||||
[[nodiscard]] ColorData *operator->() const {
|
||||
return _data;
|
||||
}
|
||||
ColorData *v() const {
|
||||
[[nodiscard]] ColorData *get() const {
|
||||
return _data;
|
||||
}
|
||||
|
||||
explicit operator bool() const {
|
||||
[[nodiscard]] explicit operator bool() const {
|
||||
return !!_data;
|
||||
}
|
||||
|
||||
class Proxy;
|
||||
Proxy operator[](const style::palette &paletteOverride) const;
|
||||
[[nodiscard]] Proxy operator[](
|
||||
const style::palette &paletteOverride) const;
|
||||
|
||||
private:
|
||||
friend class OwnedColor;
|
||||
|
|
@ -164,12 +165,12 @@ public:
|
|||
}
|
||||
Proxy(const Proxy &other) = default;
|
||||
|
||||
operator const QBrush &() const { return _color; }
|
||||
operator const QPen &() const { return _color; }
|
||||
ColorData *operator->() const { return _color.v(); }
|
||||
ColorData *v() const { return _color.v(); }
|
||||
explicit operator bool() const { return _color ? true : false; }
|
||||
Color clone() const { return _color; }
|
||||
[[nodiscard]] operator const QBrush &() const { return _color; }
|
||||
[[nodiscard]] operator const QPen &() const { return _color; }
|
||||
[[nodiscard]] ColorData *operator->() const { return _color.get(); }
|
||||
[[nodiscard]] ColorData *get() const { return _color.get(); }
|
||||
[[nodiscard]] explicit operator bool() const { return !!_color; }
|
||||
[[nodiscard]] Color clone() const { return _color; }
|
||||
|
||||
private:
|
||||
Color _color;
|
||||
|
|
|
|||
|
|
@ -52,6 +52,19 @@ void SetCustomFont(const QString &font) {
|
|||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
struct ResolvedFont {
|
||||
ResolvedFont(FontResolveResult result, FontVariants *modified);
|
||||
|
||||
FontResolveResult result;
|
||||
FontData data;
|
||||
};
|
||||
|
||||
ResolvedFont::ResolvedFont(FontResolveResult result, FontVariants *modified)
|
||||
: result(std::move(result))
|
||||
, data(this->result, modified) {
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
#ifndef LIB_UI_USE_PACKAGED_FONTS
|
||||
|
|
@ -69,12 +82,33 @@ const auto PersianFontTypes = std::array{
|
|||
|
||||
bool Started = false;
|
||||
|
||||
QMap<QString, int> fontFamilyMap;
|
||||
QVector<QString> fontFamilies;
|
||||
QMap<uint32, FontData*> fontsMap;
|
||||
base::flat_map<QString, int> FontFamilyIndices;
|
||||
std::vector<QString> FontFamilies;
|
||||
base::flat_map<uint32, std::unique_ptr<ResolvedFont>> FontsByKey;
|
||||
base::flat_map<uint64, uint32> QtFontsKeys;
|
||||
|
||||
uint32 fontKey(int size, uint32 flags, int family) {
|
||||
return (((uint32(family) << 12) | uint32(size)) << 6) | flags;
|
||||
[[nodiscard]] uint32 FontKey(int size, FontFlags flags, int family) {
|
||||
return (uint32(family) << 18)
|
||||
| (uint32(size) << 6)
|
||||
| uint32(flags.value());
|
||||
}
|
||||
|
||||
[[nodiscard]] uint64 QtFontKey(const QFont &font) {
|
||||
static auto Families = base::flat_map<QString, int>();
|
||||
|
||||
const auto pixelSize = font.pixelSize();
|
||||
const auto family = font.family();
|
||||
auto i = Families.find(family);
|
||||
if (i == end(Families)) {
|
||||
i = Families.emplace(family, Families.size()).first;
|
||||
}
|
||||
return (uint64(i->second) << 24)
|
||||
| (uint64(font.weight()) << 16)
|
||||
| (uint64(font.bold() ? 1 : 0) << 15)
|
||||
| (uint64(font.italic() ? 1 : 0) << 14)
|
||||
| (uint64(font.underline() ? 1 : 0) << 13)
|
||||
| (uint64(font.strikeOut() ? 1 : 0) << 12)
|
||||
| (uint64(font.pixelSize()));
|
||||
}
|
||||
|
||||
#ifndef LIB_UI_USE_PACKAGED_FONTS
|
||||
|
|
@ -135,106 +169,161 @@ bool LoadCustomFont(const QString &filePath) {
|
|||
return family;
|
||||
}
|
||||
|
||||
[[nodiscard]] int ComputePixelSize(QFont font, uint32 flags, int size) {
|
||||
struct Metrics {
|
||||
int pixelSize = 0;
|
||||
float64 ascent = 0.;
|
||||
float64 height = 0.;
|
||||
};
|
||||
[[nodiscard]] Metrics ComputeMetrics(QFont font, bool adjust) {
|
||||
constexpr auto kMaxSizeShift = 8;
|
||||
|
||||
const auto startSize = font.pixelSize();
|
||||
const auto metrics = QFontMetricsF(font);
|
||||
const auto simple = [&] {
|
||||
return Metrics{
|
||||
.pixelSize = startSize,
|
||||
.ascent = metrics.ascent(),
|
||||
.height = metrics.height(),
|
||||
};
|
||||
};
|
||||
|
||||
const auto family = font.family();
|
||||
const auto basic = u"Open Sans"_q;
|
||||
if (family == basic) {
|
||||
return size;
|
||||
return simple();
|
||||
}
|
||||
font.setPixelSize(size);
|
||||
|
||||
auto copy = font;
|
||||
copy.setFamily(basic);
|
||||
const auto basicMetrics = QFontMetricsF(copy);
|
||||
|
||||
//static const auto Test = u"bdfghijklpqtyBDFGHIJKLPQTY1234567890[]{}()"_q;
|
||||
static const auto Full = u"bdfghijklpqtyBDFGHIJKLPQTY1234567890[]{}()"_q;
|
||||
static const auto Test = u"acemnorsuvwxz"_q;
|
||||
|
||||
const auto desired = basicMetrics.tightBoundingRect(Test).height();
|
||||
//const auto tightAscent = -tightRect.y();
|
||||
//const auto tightDescent = tightRect.y() + tightRect.height();
|
||||
|
||||
if (desired < 1.) {
|
||||
return size;
|
||||
const auto desiredFull = basicMetrics.tightBoundingRect(Full);
|
||||
if (desired < 1. || desiredFull.height() < desired) {
|
||||
return simple();
|
||||
}
|
||||
const auto currentMetrics = QFontMetricsF(font);
|
||||
|
||||
auto current = currentMetrics.tightBoundingRect(Test).height();
|
||||
//const auto tightAscent = -tightRect.y();
|
||||
//const auto tightDescent = tightRect.y() + tightRect.height();
|
||||
const auto adjusted = [&](int size, const QFontMetricsF &metrics) {
|
||||
const auto full = metrics.tightBoundingRect(Full);
|
||||
const auto desiredTightAscent = -desiredFull.y();
|
||||
const auto desiredTightHeight = desiredFull.height();
|
||||
const auto ascentAdd = basicMetrics.ascent() - desiredTightAscent;
|
||||
const auto heightAdd = basicMetrics.height() - desiredTightHeight;
|
||||
const auto tightAscent = -full.y();
|
||||
const auto tightHeight = full.height();
|
||||
return Metrics{
|
||||
.pixelSize = size,
|
||||
.ascent = tightAscent + ascentAdd,
|
||||
.height = tightHeight + heightAdd,
|
||||
};
|
||||
};
|
||||
|
||||
const auto max = std::min(kMaxSizeShift, size - 1);
|
||||
if (current < 1. || std::abs(current - desired) < 0.2) {
|
||||
return size;
|
||||
} else if (current < desired) {
|
||||
auto current = metrics.tightBoundingRect(Test).height();
|
||||
if (current < 1.) {
|
||||
return simple();
|
||||
} else if (std::abs(current - desired) < 0.2) {
|
||||
return adjusted(startSize, metrics);
|
||||
}
|
||||
|
||||
const auto adjustedByFont = [&](const QFont &font) {
|
||||
return adjusted(font.pixelSize(), QFontMetricsF(font));
|
||||
};
|
||||
const auto max = std::min(kMaxSizeShift, startSize - 1);
|
||||
if (current < desired) {
|
||||
for (auto i = 0; i != max; ++i) {
|
||||
const auto shift = i + 1;
|
||||
font.setPixelSize(size + shift);
|
||||
font.setPixelSize(startSize + shift);
|
||||
const auto metrics = QFontMetricsF(font);
|
||||
const auto now = metrics.tightBoundingRect(Test).height();
|
||||
if (now > desired) {
|
||||
const auto better = (now - desired) < (desired - current);
|
||||
return better ? (size + shift) : (size + shift - 1);
|
||||
if (better) {
|
||||
return adjusted(startSize + shift, metrics);
|
||||
}
|
||||
font.setPixelSize(startSize + shift - 1);
|
||||
return adjustedByFont(font);
|
||||
}
|
||||
current = now;
|
||||
}
|
||||
return size + max;
|
||||
font.setPixelSize(startSize + max);
|
||||
return adjustedByFont(font);
|
||||
} else {
|
||||
for (auto i = 0; i != max; ++i) {
|
||||
const auto shift = i + 1;
|
||||
font.setPixelSize(size - shift);
|
||||
font.setPixelSize(startSize - shift);
|
||||
const auto metrics = QFontMetricsF(font);
|
||||
const auto now = metrics.tightBoundingRect(Test).height();
|
||||
if (now < desired) {
|
||||
const auto better = (desired - now) < (current - desired);
|
||||
return better ? (size - shift) : (size - shift + 1);
|
||||
if (better) {
|
||||
return adjusted(startSize - shift, metrics);
|
||||
}
|
||||
font.setPixelSize(startSize - shift + 1);
|
||||
return adjustedByFont(font);
|
||||
}
|
||||
current = now;
|
||||
}
|
||||
return size - max;
|
||||
font.setPixelSize(startSize - max);
|
||||
return adjustedByFont(font);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] QFont ResolveFont(
|
||||
[[nodiscard]] FontResolveResult ResolveFont(
|
||||
const QString &family,
|
||||
uint32 flags,
|
||||
FontFlags flags,
|
||||
int size,
|
||||
bool skipSizeAdjustment) {
|
||||
auto result = QFont();
|
||||
const auto monospace = (flags & FontMonospace) != 0;
|
||||
auto font = QFont();
|
||||
|
||||
const auto monospace = (flags & FontFlag::Monospace) != 0;
|
||||
const auto system = !monospace && (family == SystemFontTag());
|
||||
const auto overriden = !monospace && !system && !family.isEmpty();
|
||||
if (monospace) {
|
||||
result.setFamily(MonospaceFont());
|
||||
font.setFamily(MonospaceFont());
|
||||
} else if (system) {
|
||||
} else if (overriden) {
|
||||
result.setFamily(family);
|
||||
font.setFamily(family);
|
||||
} else {
|
||||
result.setFamily("Open Sans"_q);
|
||||
font.setFamily("Open Sans"_q);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0)
|
||||
result.setFeature("ss03", true);
|
||||
font.setFeature("ss03", true);
|
||||
#endif // Qt >= 6.7.0
|
||||
}
|
||||
result.setWeight(((flags & FontBold) || (flags & FontSemibold))
|
||||
font.setPixelSize(size);
|
||||
|
||||
font.setWeight((flags & (FontFlag::Bold | FontFlag::Semibold))
|
||||
? QFont::DemiBold
|
||||
: QFont::Normal);
|
||||
if (result.bold()) {
|
||||
const auto style = QFontInfo(result).styleName();
|
||||
if (font.bold()) {
|
||||
const auto style = QFontInfo(font).styleName();
|
||||
if (!style.isEmpty() && !style.startsWith(
|
||||
"Semibold",
|
||||
Qt::CaseInsensitive)) {
|
||||
result.setBold(true);
|
||||
font.setBold(true);
|
||||
}
|
||||
}
|
||||
result.setItalic(flags & FontItalic);
|
||||
result.setUnderline(flags & FontUnderline);
|
||||
result.setStrikeOut(flags & FontStrikeOut);
|
||||
result.setPixelSize((monospace || !overriden || skipSizeAdjustment)
|
||||
? size
|
||||
: ComputePixelSize(result, flags, size));
|
||||
return result;
|
||||
|
||||
font.setItalic(flags & FontFlag::Italic);
|
||||
font.setUnderline(flags & FontFlag::Underline);
|
||||
font.setStrikeOut(flags & FontFlag::StrikeOut);
|
||||
|
||||
const auto adjust = (overriden && !skipSizeAdjustment);
|
||||
const auto metrics = ComputeMetrics(font, adjust);
|
||||
font.setPixelSize(metrics.pixelSize);
|
||||
|
||||
return {
|
||||
.font = font,
|
||||
.ascent = metrics.ascent,
|
||||
.height = metrics.height,
|
||||
.iascent = int(base::SafeRound(metrics.ascent)),
|
||||
.iheight = int(base::SafeRound(metrics.height)),
|
||||
.requestedFamily = RegisterFontFamily(family),
|
||||
.requestedSize = size,
|
||||
.requestedFlags = flags,
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
@ -276,74 +365,66 @@ void StartFonts() {
|
|||
QApplication::setFont(appFont);
|
||||
}
|
||||
|
||||
void destroyFonts() {
|
||||
for (auto fontData : std::as_const(fontsMap)) {
|
||||
delete fontData;
|
||||
}
|
||||
fontsMap.clear();
|
||||
void DestroyFonts() {
|
||||
base::take(FontsByKey);
|
||||
}
|
||||
|
||||
int registerFontFamily(const QString &family) {
|
||||
auto result = fontFamilyMap.value(family, -1);
|
||||
if (result < 0) {
|
||||
result = fontFamilies.size();
|
||||
fontFamilyMap.insert(family, result);
|
||||
fontFamilies.push_back(family);
|
||||
int RegisterFontFamily(const QString &family) {
|
||||
auto i = FontFamilyIndices.find(family);
|
||||
if (i == end(FontFamilyIndices)) {
|
||||
i = FontFamilyIndices.emplace(family, FontFamilies.size()).first;
|
||||
FontFamilies.push_back(family);
|
||||
}
|
||||
return result;
|
||||
return i->second;
|
||||
}
|
||||
|
||||
FontData::FontData(int size, uint32 flags, int family, Font *other)
|
||||
: f(ResolveFont(
|
||||
family ? fontFamilies[family] : Custom,
|
||||
flags,
|
||||
size,
|
||||
family != 0))
|
||||
FontData::FontData(const FontResolveResult &result, FontVariants *modified)
|
||||
: f(result.font)
|
||||
, _m(f)
|
||||
, _size(size)
|
||||
, _flags(flags)
|
||||
, _family(family) {
|
||||
if (other) {
|
||||
memcpy(_modified, other, sizeof(_modified));
|
||||
, _size(result.requestedSize)
|
||||
, _family(result.requestedFamily)
|
||||
, _flags(result.requestedFlags) {
|
||||
if (modified) {
|
||||
memcpy(&_modified, modified, sizeof(_modified));
|
||||
}
|
||||
_modified[_flags] = Font(this);
|
||||
_modified[int(_flags)] = Font(this);
|
||||
|
||||
height = int(base::SafeRound(_m.height()));
|
||||
ascent = int(base::SafeRound(_m.ascent()));
|
||||
descent = int(base::SafeRound(_m.descent()));
|
||||
height = int(base::SafeRound(result.height));
|
||||
ascent = int(base::SafeRound(result.ascent));
|
||||
descent = height - ascent;
|
||||
spacew = width(QLatin1Char(' '));
|
||||
elidew = width(u"..."_q);
|
||||
}
|
||||
|
||||
Font FontData::bold(bool set) const {
|
||||
return otherFlagsFont(FontBold, set);
|
||||
return otherFlagsFont(FontFlag::Bold, set);
|
||||
}
|
||||
|
||||
Font FontData::italic(bool set) const {
|
||||
return otherFlagsFont(FontItalic, set);
|
||||
return otherFlagsFont(FontFlag::Italic, set);
|
||||
}
|
||||
|
||||
Font FontData::underline(bool set) const {
|
||||
return otherFlagsFont(FontUnderline, set);
|
||||
return otherFlagsFont(FontFlag::Underline, set);
|
||||
}
|
||||
|
||||
Font FontData::strikeout(bool set) const {
|
||||
return otherFlagsFont(FontStrikeOut, set);
|
||||
return otherFlagsFont(FontFlag::StrikeOut, set);
|
||||
}
|
||||
|
||||
Font FontData::semibold(bool set) const {
|
||||
return otherFlagsFont(FontSemibold, set);
|
||||
return otherFlagsFont(FontFlag::Semibold, set);
|
||||
}
|
||||
|
||||
Font FontData::monospace(bool set) const {
|
||||
return otherFlagsFont(FontMonospace, set);
|
||||
return otherFlagsFont(FontFlag::Monospace, set);
|
||||
}
|
||||
|
||||
int FontData::size() const {
|
||||
return _size;
|
||||
}
|
||||
|
||||
uint32 FontData::flags() const {
|
||||
FontFlags FontData::flags() const {
|
||||
return _flags;
|
||||
}
|
||||
|
||||
|
|
@ -351,50 +432,61 @@ int FontData::family() const {
|
|||
return _family;
|
||||
}
|
||||
|
||||
Font FontData::otherFlagsFont(uint32 flag, bool set) const {
|
||||
int32 newFlags = set ? (_flags | flag) : (_flags & ~flag);
|
||||
if (!_modified[newFlags].v()) {
|
||||
_modified[newFlags] = Font(_size, newFlags, _family, _modified);
|
||||
Font FontData::otherFlagsFont(FontFlag flag, bool set) const {
|
||||
const auto newFlags = set ? (_flags | flag) : (_flags & ~flag);
|
||||
if (!_modified[newFlags]) {
|
||||
_modified[newFlags] = Font(_size, newFlags, _family, &_modified);
|
||||
}
|
||||
return _modified[newFlags];
|
||||
}
|
||||
|
||||
Font::Font(int size, uint32 flags, const QString &family) {
|
||||
if (fontFamilyMap.isEmpty()) {
|
||||
for (uint32 i = 0, s = fontFamilies.size(); i != s; ++i) {
|
||||
fontFamilyMap.insert(fontFamilies.at(i), i);
|
||||
}
|
||||
}
|
||||
|
||||
auto i = fontFamilyMap.constFind(family);
|
||||
if (i == fontFamilyMap.cend()) {
|
||||
fontFamilies.push_back(family);
|
||||
i = fontFamilyMap.insert(family, fontFamilies.size() - 1);
|
||||
}
|
||||
init(size, flags, i.value(), 0);
|
||||
Font::Font(int size, FontFlags flags, const QString &family) {
|
||||
init(size, flags, RegisterFontFamily(family), 0);
|
||||
}
|
||||
|
||||
Font::Font(int size, uint32 flags, int family) {
|
||||
Font::Font(int size, FontFlags flags, int family) {
|
||||
init(size, flags, family, 0);
|
||||
}
|
||||
|
||||
Font::Font(int size, uint32 flags, int family, Font *modified) {
|
||||
Font::Font(int size, FontFlags flags, int family, FontVariants *modified) {
|
||||
init(size, flags, family, modified);
|
||||
}
|
||||
|
||||
void Font::init(int size, uint32 flags, int family, Font *modified) {
|
||||
uint32 key = fontKey(size, flags, family);
|
||||
auto i = fontsMap.constFind(key);
|
||||
if (i == fontsMap.cend()) {
|
||||
i = fontsMap.insert(key, new FontData(size, flags, family, modified));
|
||||
void Font::init(
|
||||
int size,
|
||||
FontFlags flags,
|
||||
int family,
|
||||
FontVariants *modified) {
|
||||
const auto key = FontKey(size, flags, family);
|
||||
auto i = FontsByKey.find(key);
|
||||
if (i == end(FontsByKey)) {
|
||||
i = FontsByKey.emplace(
|
||||
key,
|
||||
std::make_unique<ResolvedFont>(
|
||||
ResolveFont(
|
||||
family ? FontFamilies[family] : Custom,
|
||||
flags,
|
||||
size,
|
||||
family != 0),
|
||||
modified)).first;
|
||||
QtFontsKeys.emplace(QtFontKey(i->second->data.f), key);
|
||||
}
|
||||
ptr = i.value();
|
||||
_data = &i->second->data;
|
||||
}
|
||||
|
||||
OwnedFont::OwnedFont(const QString &custom, FontFlags flags, int size)
|
||||
: _data(ResolveFont(custom, flags, size, false), nullptr) {
|
||||
_font._data = &_data;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
QFont ResolveFont(const QString &custom, uint32 flags, int size) {
|
||||
return internal::ResolveFont(custom, flags, size, false);
|
||||
const FontResolveResult *FindAdjustResult(const QFont &font) {
|
||||
const auto key = internal::QtFontKey(font);
|
||||
const auto i = internal::QtFontsKeys.find(key);
|
||||
return (i != end(internal::QtFontsKeys))
|
||||
? &internal::FontsByKey[i->second]->result
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
} // namespace style
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "base/basic_types.h"
|
||||
#include "base/flags.h"
|
||||
|
||||
#include <QtGui/QFont>
|
||||
#include <QtGui/QFontMetrics>
|
||||
|
|
@ -18,61 +19,75 @@ namespace style {
|
|||
[[nodiscard]] const QString &SystemFontTag();
|
||||
void SetCustomFont(const QString &font);
|
||||
|
||||
[[nodiscard]] QFont ResolveFont(
|
||||
const QString &custom,
|
||||
uint32 flags,
|
||||
int size);
|
||||
enum class FontFlag : uchar {
|
||||
Bold = 0x01,
|
||||
Italic = 0x02,
|
||||
Underline = 0x04,
|
||||
StrikeOut = 0x08,
|
||||
Semibold = 0x10,
|
||||
Monospace = 0x20,
|
||||
};
|
||||
inline constexpr bool is_flag_type(FontFlag) { return true; }
|
||||
using FontFlags = base::flags<FontFlag>;
|
||||
|
||||
struct FontResolveResult {
|
||||
QFont font;
|
||||
float64 ascent = 0.;
|
||||
float64 height = 0.;
|
||||
int iascent = 0;
|
||||
int iheight = 0;
|
||||
int requestedFamily = 0;
|
||||
int requestedSize = 0;
|
||||
FontFlags requestedFlags;
|
||||
};
|
||||
[[nodiscard]] const FontResolveResult *FindAdjustResult(const QFont &font);
|
||||
|
||||
namespace internal {
|
||||
|
||||
void StartFonts();
|
||||
|
||||
void destroyFonts();
|
||||
int registerFontFamily(const QString &family);
|
||||
void DestroyFonts();
|
||||
int RegisterFontFamily(const QString &family);
|
||||
|
||||
inline constexpr auto kFontVariants = 0x40;
|
||||
|
||||
class Font;
|
||||
using FontVariants = std::array<Font, kFontVariants>;
|
||||
|
||||
class FontData;
|
||||
class Font {
|
||||
class Font final {
|
||||
public:
|
||||
Font(Qt::Initialization = Qt::Uninitialized) {
|
||||
}
|
||||
Font(int size, uint32 flags, const QString &family);
|
||||
Font(int size, uint32 flags, int family);
|
||||
Font(int size, FontFlags flags, const QString &family);
|
||||
Font(int size, FontFlags flags, int family);
|
||||
|
||||
FontData *operator->() const {
|
||||
return ptr;
|
||||
[[nodiscard]] FontData *operator->() const {
|
||||
return _data;
|
||||
}
|
||||
FontData *v() const {
|
||||
return ptr;
|
||||
[[nodiscard]] FontData *get() const {
|
||||
return _data;
|
||||
}
|
||||
|
||||
operator bool() const {
|
||||
return !!ptr;
|
||||
[[nodiscard]] operator bool() const {
|
||||
return _data != nullptr;
|
||||
}
|
||||
|
||||
operator const QFont &() const;
|
||||
[[nodiscard]] operator const QFont &() const;
|
||||
|
||||
private:
|
||||
FontData *ptr = nullptr;
|
||||
|
||||
void init(int size, uint32 flags, int family, Font *modified);
|
||||
friend void startManager();
|
||||
|
||||
Font(FontData *p) : ptr(p) {
|
||||
}
|
||||
Font(int size, uint32 flags, int family, Font *modified);
|
||||
friend class FontData;
|
||||
friend class OwnedFont;
|
||||
|
||||
};
|
||||
FontData *_data = nullptr;
|
||||
|
||||
enum FontFlags {
|
||||
FontBold = 0x01,
|
||||
FontItalic = 0x02,
|
||||
FontUnderline = 0x04,
|
||||
FontStrikeOut = 0x08,
|
||||
FontSemibold = 0x10,
|
||||
FontMonospace = 0x20,
|
||||
void init(int size, FontFlags flags, int family, FontVariants *modified);
|
||||
friend void StartManager();
|
||||
|
||||
explicit Font(FontData *data) : _data(data) {
|
||||
}
|
||||
Font(int size, FontFlags flags, int family, FontVariants *modified);
|
||||
|
||||
FontDifferentFlags = 0x40,
|
||||
};
|
||||
|
||||
class FontData {
|
||||
|
|
@ -100,37 +115,74 @@ public:
|
|||
[[nodiscard]] Font semibold(bool set = true) const;
|
||||
[[nodiscard]] Font monospace(bool set = true) const;
|
||||
|
||||
int size() const;
|
||||
uint32 flags() const;
|
||||
int family() const;
|
||||
[[nodiscard]] int size() const;
|
||||
[[nodiscard]] FontFlags flags() const;
|
||||
[[nodiscard]] int family() const;
|
||||
|
||||
QFont f;
|
||||
int32 height, ascent, descent, spacew, elidew;
|
||||
int height = 0;
|
||||
int ascent = 0;
|
||||
int descent = 0;
|
||||
int spacew = 0;
|
||||
int elidew = 0;
|
||||
|
||||
private:
|
||||
mutable Font _modified[FontDifferentFlags];
|
||||
friend class OwnedFont;
|
||||
friend struct ResolvedFont;
|
||||
|
||||
Font otherFlagsFont(uint32 flag, bool set) const;
|
||||
FontData(int size, uint32 flags, int family, Font *other);
|
||||
mutable FontVariants _modified;
|
||||
|
||||
[[nodiscard]] Font otherFlagsFont(FontFlag flag, bool set) const;
|
||||
FontData(const FontResolveResult &data, FontVariants *modified);
|
||||
|
||||
friend class Font;
|
||||
QFontMetricsF _m;
|
||||
int _size;
|
||||
uint32 _flags;
|
||||
int _family;
|
||||
int _size = 0;
|
||||
int _family = 0;
|
||||
FontFlags _flags = 0;
|
||||
|
||||
};
|
||||
|
||||
inline bool operator==(const Font &a, const Font &b) {
|
||||
return a.v() == b.v();
|
||||
return a.get() == b.get();
|
||||
}
|
||||
inline bool operator!=(const Font &a, const Font &b) {
|
||||
return a.v() != b.v();
|
||||
return a.get() != b.get();
|
||||
}
|
||||
|
||||
inline Font::operator const QFont &() const {
|
||||
return ptr->f;
|
||||
Expects(_data != nullptr);
|
||||
|
||||
return _data->f;
|
||||
}
|
||||
|
||||
class OwnedFont final {
|
||||
public:
|
||||
OwnedFont(const QString &custom, FontFlags flags, int size);
|
||||
OwnedFont(const OwnedFont &other)
|
||||
: _data(other._data) {
|
||||
_font._data = &_data;
|
||||
}
|
||||
|
||||
OwnedFont &operator=(const OwnedFont &other) {
|
||||
_data = other._data;
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] const Font &font() const {
|
||||
return _font;
|
||||
}
|
||||
[[nodiscard]] FontData *operator->() const {
|
||||
return _font.get();
|
||||
}
|
||||
[[nodiscard]] FontData *get() const {
|
||||
return _font.get();
|
||||
}
|
||||
|
||||
private:
|
||||
FontData _data;
|
||||
Font _font;
|
||||
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace style
|
||||
|
|
|
|||
|
|
@ -393,14 +393,14 @@ Icon Icon::withPalette(const style::palette &palette) const {
|
|||
return result;
|
||||
}
|
||||
|
||||
void resetIcons() {
|
||||
void ResetIcons() {
|
||||
iconPixmaps.clear();
|
||||
for (const auto data : iconData) {
|
||||
data->reset();
|
||||
}
|
||||
}
|
||||
|
||||
void destroyIcons() {
|
||||
void DestroyIcons() {
|
||||
iconData.clear();
|
||||
iconPixmaps.clear();
|
||||
|
||||
|
|
|
|||
|
|
@ -295,8 +295,8 @@ private:
|
|||
|
||||
};
|
||||
|
||||
void resetIcons();
|
||||
void destroyIcons();
|
||||
void ResetIcons();
|
||||
void DestroyIcons();
|
||||
|
||||
} // namespace internal
|
||||
} // namespace style
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@ QByteArray save() {
|
|||
|
||||
bool load(const QByteArray &cache) {
|
||||
if (GetMutable().load(cache)) {
|
||||
style::internal::resetIcons();
|
||||
style::internal::ResetIcons();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -242,17 +242,17 @@ palette::SetResult setColor(QLatin1String name, QLatin1String from) {
|
|||
|
||||
void apply(const palette &other) {
|
||||
GetMutable() = other;
|
||||
style::internal::resetIcons();
|
||||
style::internal::ResetIcons();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
GetMutable().reset();
|
||||
style::internal::resetIcons();
|
||||
style::internal::ResetIcons();
|
||||
}
|
||||
|
||||
void reset(const colorizer &with) {
|
||||
GetMutable().reset(with);
|
||||
style::internal::resetIcons();
|
||||
style::internal::ResetIcons();
|
||||
}
|
||||
|
||||
int indexOfColor(color c) {
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ using cursor = Qt::CursorShape;
|
|||
using align = Qt::Alignment;
|
||||
using margins = QMargins;
|
||||
using font = internal::Font;
|
||||
using owned_font = internal::OwnedFont;
|
||||
using color = internal::Color;
|
||||
using owned_color = internal::OwnedColor;
|
||||
using complex_color = internal::ComplexColor;
|
||||
|
|
|
|||
|
|
@ -373,28 +373,31 @@ bool BlockParser::isSpaceBreak(
|
|||
style::font WithFlags(
|
||||
const style::font &font,
|
||||
TextBlockFlags flags,
|
||||
uint32 fontFlags) {
|
||||
style::FontFlags fontFlags) {
|
||||
using namespace style::internal;
|
||||
|
||||
using Flag = style::FontFlag;
|
||||
if (!flags && !fontFlags) {
|
||||
return font;
|
||||
} else if (IsMono(flags) || (fontFlags & FontMonospace)) {
|
||||
} else if (IsMono(flags) || (fontFlags & Flag::Monospace)) {
|
||||
return font->monospace();
|
||||
}
|
||||
auto result = font;
|
||||
if ((flags & TextBlockFlag::Bold) || (fontFlags & FontBold)) {
|
||||
if ((flags & TextBlockFlag::Bold) || (fontFlags & Flag::Bold)) {
|
||||
result = result->bold();
|
||||
} else if ((flags & TextBlockFlag::Semibold)
|
||||
|| (fontFlags & FontSemibold)) {
|
||||
|| (fontFlags & Flag::Semibold)) {
|
||||
result = result->semibold();
|
||||
}
|
||||
if ((flags & TextBlockFlag::Italic) || (fontFlags & FontItalic)) {
|
||||
if ((flags & TextBlockFlag::Italic) || (fontFlags & Flag::Italic)) {
|
||||
result = result->italic();
|
||||
}
|
||||
if ((flags & TextBlockFlag::Underline) || (fontFlags & FontUnderline)) {
|
||||
if ((flags & TextBlockFlag::Underline)
|
||||
|| (fontFlags & Flag::Underline)) {
|
||||
result = result->underline();
|
||||
}
|
||||
if ((flags & TextBlockFlag::StrikeOut) || (fontFlags & FontStrikeOut)) {
|
||||
if ((flags & TextBlockFlag::StrikeOut)
|
||||
|| (fontFlags & Flag::StrikeOut)) {
|
||||
result = result->strikeout();
|
||||
}
|
||||
if (flags & TextBlockFlag::Tilde) { // Tilde fix in OpenSans.
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ using TextBlockFlags = base::flags<TextBlockFlag>;
|
|||
[[nodiscard]] style::font WithFlags(
|
||||
const style::font &font,
|
||||
TextBlockFlags flags,
|
||||
uint32 fontFlags = 0);
|
||||
style::FontFlags fontFlags = 0);
|
||||
|
||||
[[nodiscard]] Qt::LayoutDirection UnpackParagraphDirection(
|
||||
bool ltr,
|
||||
|
|
|
|||
|
|
@ -3912,7 +3912,9 @@ void InputField::refreshPlaceholder(const QString &text) {
|
|||
_placeholder = metrics.elidedText(text, Qt::ElideRight, availableWidth);
|
||||
_placeholderPath = QPainterPath();
|
||||
if (!_placeholder.isEmpty()) {
|
||||
_placeholderPath.addText(0, QFontMetrics(placeholderFont).ascent(), placeholderFont, _placeholder);
|
||||
const auto result = style::FindAdjustResult(placeholderFont);
|
||||
const auto ascent = result ? result->iascent : metrics.ascent();
|
||||
_placeholderPath.addText(0, ascent, placeholderFont, _placeholder);
|
||||
}
|
||||
} else {
|
||||
_placeholder = _st.placeholderFont->elided(text, availableWidth);
|
||||
|
|
|
|||
|
|
@ -390,7 +390,9 @@ void MaskedInputField::refreshPlaceholder(const QString &text) {
|
|||
_placeholder = metrics.elidedText(text, Qt::ElideRight, availableWidth);
|
||||
_placeholderPath = QPainterPath();
|
||||
if (!_placeholder.isEmpty()) {
|
||||
_placeholderPath.addText(0, QFontMetrics(placeholderFont).ascent(), placeholderFont, _placeholder);
|
||||
const auto result = style::FindAdjustResult(placeholderFont);
|
||||
const auto ascent = result ? result->iascent : metrics.ascent();
|
||||
_placeholderPath.addText(0, ascent, placeholderFont, _placeholder);
|
||||
}
|
||||
} else {
|
||||
_placeholder = _st.placeholderFont->elided(text, availableWidth);
|
||||
|
|
|
|||
|
|
@ -20,10 +20,13 @@ namespace Ui {
|
|||
|
||||
// flick scroll taken from http://qt-project.org/doc/qt-4.8/demos-embedded-anomaly-src-flickcharm-cpp.html
|
||||
|
||||
ScrollShadow::ScrollShadow(ScrollArea *parent, const style::ScrollArea *st) : QWidget(parent), _st(st) {
|
||||
ScrollShadow::ScrollShadow(ScrollArea *parent, const style::ScrollArea *st)
|
||||
: QWidget(parent)
|
||||
, _st(st) {
|
||||
Expects(_st != nullptr);
|
||||
Expects(_st->shColor.get() != nullptr);
|
||||
|
||||
setVisible(false);
|
||||
Assert(_st != nullptr);
|
||||
Assert(_st->shColor.v() != nullptr);
|
||||
}
|
||||
|
||||
void ScrollShadow::paintEvent(QPaintEvent *e) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue