Add a font weight dropdown to the font selector

This commit is contained in:
Christian Kaiser 2025-08-04 18:52:58 -03:00
parent 286dd1c755
commit d8035135f9
4 changed files with 113 additions and 19 deletions

View File

@ -801,6 +801,17 @@ empty_fonts = No system fonts were found
antialias = Antialias antialias = Antialias
hinting = Hinting hinting = Hinting
ligatures = Ligatures ligatures = Ligatures
font_weight = Font Weight
font_weight_100 = Thin
font_weight_200 = Extra Light
font_weight_300 = Light
font_weight_400 = Normal
font_weight_500 = Medium
font_weight_600 = Semi Bold
font_weight_700 = Bold
font_weight_800 = Extra Bold
font_weight_900 = Black
font_weight_1000 = Extra Black
[frame_combo] [frame_combo]
all_frames = All frames all_frames = All frames

View File

@ -177,6 +177,7 @@ app::FontInfo convert_to(const std::string& from)
bool italic = false; bool italic = false;
app::FontInfo::Flags flags = app::FontInfo::Flags::None; app::FontInfo::Flags flags = app::FontInfo::Flags::None;
text::FontHinting hinting = text::FontHinting::Normal; text::FontHinting hinting = text::FontHinting::Normal;
text::FontStyle::Weight weight = text::FontStyle::Weight::Normal;
if (!parts.empty()) { if (!parts.empty()) {
if (parts[0].compare(0, 5, "file=") == 0) { if (parts[0].compare(0, 5, "file=") == 0) {
@ -214,16 +215,16 @@ app::FontInfo convert_to(const std::string& from)
else if (hintingStr == "full") else if (hintingStr == "full")
hinting = text::FontHinting::Full; hinting = text::FontHinting::Full;
} }
else if (parts[i].compare(0, 7, "weight=") == 0) {
std::string weightStr = parts[i].substr(7);
weight = static_cast<text::FontStyle::Weight>(std::atoi(weightStr.c_str()));
}
} }
} }
text::FontStyle style; text::FontStyle style(bold ? text::FontStyle::Weight::Bold : weight,
if (bold && italic) text::FontStyle::Width::Normal,
style = text::FontStyle::BoldItalic(); italic ? text::FontStyle::Slant::Italic : text::FontStyle::Slant::Upright);
else if (bold)
style = text::FontStyle::Bold();
else if (italic)
style = text::FontStyle::Italic();
return app::FontInfo(type, name, size, style, flags, hinting); return app::FontInfo(type, name, size, style, flags, hinting);
} }
@ -243,7 +244,7 @@ std::string convert_to(const app::FontInfo& from)
if (!result.empty()) { if (!result.empty()) {
if (from.size() > 0.0f) if (from.size() > 0.0f)
result += fmt::format(",size={}", from.size()); result += fmt::format(",size={}", from.size());
if (from.style().weight() >= text::FontStyle::Weight::SemiBold) if (from.style().weight() == text::FontStyle::Weight::Bold)
result += ",bold"; result += ",bold";
if (from.style().slant() != text::FontStyle::Slant::Upright) if (from.style().slant() != text::FontStyle::Slant::Upright)
result += ",italic"; result += ",italic";
@ -262,6 +263,8 @@ std::string convert_to(const app::FontInfo& from)
case text::FontHinting::Full: result += "full"; break; case text::FontHinting::Full: result += "full"; break;
} }
} }
if (from.style().weight() != text::FontStyle::Weight::Bold)
result += ",weight=" + std::to_string(static_cast<int>(from.style().weight()));
} }
return result; return result;
} }

View File

@ -20,9 +20,11 @@
#include "base/convert_to.h" #include "base/convert_to.h"
#include "base/scoped_value.h" #include "base/scoped_value.h"
#include "fmt/format.h" #include "fmt/format.h"
#include "text/font_style_set.h"
#include "ui/display.h" #include "ui/display.h"
#include "ui/fit_bounds.h" #include "ui/fit_bounds.h"
#include "ui/manager.h" #include "ui/manager.h"
#include "ui/menu.h"
#include "ui/message.h" #include "ui/message.h"
#include "ui/scale.h" #include "ui/scale.h"
@ -271,7 +273,7 @@ FontEntry::FontStyle::FontStyle(ui::TooltipManager* tooltips) : ButtonSet(3, tru
addItem("..."); addItem("...");
setMultiMode(MultiMode::Set); setMultiMode(MultiMode::Set);
tooltips->addTooltipFor(getItem(0), Strings::text_tool_bold(), BOTTOM); tooltips->addTooltipFor(getItem(0), Strings::font_style_font_weight(), BOTTOM);
tooltips->addTooltipFor(getItem(1), Strings::text_tool_italic(), BOTTOM); tooltips->addTooltipFor(getItem(1), Strings::text_tool_italic(), BOTTOM);
tooltips->addTooltipFor(getItem(2), Strings::text_tool_more_options(), BOTTOM); tooltips->addTooltipFor(getItem(2), Strings::text_tool_more_options(), BOTTOM);
} }
@ -384,16 +386,59 @@ void FontEntry::setInfo(const FontInfo& info, const From fromField)
{ {
m_info = info; m_info = info;
if (fromField != From::Face) auto family = theme()->fontMgr()->matchFamily(m_info.name());
bool hasBold = false;
m_availableWeights.clear();
if (family) {
auto checkWeight = [this, &family, &hasBold](text::FontStyle::Weight w) {
auto ref = family->matchStyle(
text::FontStyle(w, m_info.style().width(), m_info.style().slant()));
if (ref->fontStyle().weight() == w)
m_availableWeights.push_back(w);
if (ref->fontStyle().weight() == text::FontStyle::Weight::Bold)
hasBold = true;
};
checkWeight(text::FontStyle::Weight::Thin);
checkWeight(text::FontStyle::Weight::ExtraLight);
checkWeight(text::FontStyle::Weight::Light);
checkWeight(text::FontStyle::Weight::Normal);
checkWeight(text::FontStyle::Weight::Medium);
checkWeight(text::FontStyle::Weight::SemiBold);
checkWeight(text::FontStyle::Weight::Bold);
checkWeight(text::FontStyle::Weight::Black);
checkWeight(text::FontStyle::Weight::ExtraBlack);
}
else {
// Stick to only "normal" for fonts without a family.
m_availableWeights.push_back(text::FontStyle::Weight::Normal);
m_style.getItem(0)->setEnabled(false);
}
if (fromField != From::Face) {
m_face.setText(info.title()); m_face.setText(info.title());
}
if (fromField != From::Size) { if (fromField != From::Size) {
m_size.updateForFont(info); m_size.updateForFont(info);
m_size.setValue(fmt::format("{}", info.size())); m_size.setValue(fmt::format("{}", info.size()));
} }
m_style.getItem(0)->setEnabled(hasBold);
m_style.getItem(0)->setSelected(info.style().weight() != text::FontStyle::Weight::Normal);
m_style.getItem(0)->setText("B");
// Give some indication of what the weight is, if we have any variation
if (m_style.getItem(0)->isSelected() && m_availableWeights.size() > 1) {
if (info.style().weight() > text::FontStyle::Weight::Bold)
m_style.getItem(0)->setText("B+");
else if (info.style().weight() < text::FontStyle::Weight::Bold)
m_style.getItem(0)->setText("B-");
}
if (fromField != From::Style) { if (fromField != From::Style) {
m_style.getItem(0)->setSelected(info.style().weight() >= text::FontStyle::Weight::SemiBold);
m_style.getItem(1)->setSelected(info.style().slant() != text::FontStyle::Slant::Upright); m_style.getItem(1)->setSelected(info.style().slant() != text::FontStyle::Slant::Upright);
} }
@ -430,17 +475,51 @@ void FontEntry::onStyleItemClick(ButtonSet::Item* item)
switch (m_style.getItemIndex(item)) { switch (m_style.getItemIndex(item)) {
// Bold button changed // Bold button changed
case 0: { case 0: {
const bool bold = m_style.getItem(0)->isSelected(); if (m_availableWeights.size() > 2) {
style = text::FontStyle( // Ensure consistency, since the click also affects the "selected" highlighting.
bold ? text::FontStyle::Weight::Bold : text::FontStyle::Weight::Normal, item->setSelected(style.weight() != text::FontStyle::Weight::Normal);
style.width(),
style.slant());
setInfo(FontInfo(m_info, m_info.size(), style, m_info.flags(), m_info.hinting()), Menu weightMenu;
From::Style); auto currentWeight = m_info.style().weight();
auto weightChange = [this](text::FontStyle::Weight newWeight) {
text::FontStyle style(newWeight, m_info.style().width(), m_info.style().slant());
setInfo(FontInfo(m_info, m_info.size(), style, m_info.flags(), m_info.hinting()),
From::Style);
};
for (auto weight : m_availableWeights) {
auto* menuItem = new MenuItem(Strings::Translate(
("font_style.font_weight_" + std::to_string(static_cast<int>(weight))).c_str()));
menuItem->setSelected(weight == currentWeight);
if (!menuItem->isSelected())
menuItem->Click.connect([&weightChange, weight] { weightChange(weight); });
if (weight == text::FontStyle::Weight::Bold &&
currentWeight == text::FontStyle::Weight::Normal)
menuItem->setHighlighted(true);
weightMenu.addChild(menuItem);
}
weightMenu.initTheme();
const auto& bounds = m_style.getItem(0)->bounds();
weightMenu.showPopup(gfx::Point(bounds.x, bounds.y2()), display());
}
else {
const bool isBold = m_info.style().weight() == text::FontStyle::Weight::Bold;
style = text::FontStyle(
isBold ? text::FontStyle::Weight::Normal : text::FontStyle::Weight::Bold,
style.width(),
style.slant());
setInfo(FontInfo(m_info, m_info.size(), style, m_info.flags(), m_info.hinting()),
From::Style);
}
break; break;
} }
// Italic button changed // Italic button changed
case 1: { case 1: {
const bool italic = m_style.getItem(1)->isSelected(); const bool italic = m_style.getItem(1)->isSelected();
style = text::FontStyle( style = text::FontStyle(

View File

@ -115,6 +115,7 @@ private:
FontSize m_size; FontSize m_size;
FontStyle m_style; FontStyle m_style;
std::unique_ptr<FontStroke> m_stroke; std::unique_ptr<FontStroke> m_stroke;
std::vector<text::FontStyle::Weight> m_availableWeights;
bool m_lockFace = false; bool m_lockFace = false;
}; };