LibGfx+FontEditor+Fonts: Add family, size and weight metadata to fonts
This makes finding fonts from the same family much less difficult. :^)
This commit is contained in:
parent
5abc03db0d
commit
80b77cec38
Notes:
sideshowbarker
2024-07-19 01:45:52 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/80b77cec384
22 changed files with 106 additions and 34 deletions
|
@ -121,7 +121,7 @@ FontEditorWidget::FontEditorWidget(const String& path, RefPtr<Gfx::Font>&& edite
|
|||
font_metadata_group_box.set_layout<GUI::VerticalBoxLayout>();
|
||||
font_metadata_group_box.layout()->set_margins({ 5, 15, 5, 5 });
|
||||
font_metadata_group_box.set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fixed);
|
||||
font_metadata_group_box.set_preferred_size(0, 195);
|
||||
font_metadata_group_box.set_preferred_size(0, 275);
|
||||
font_metadata_group_box.set_title("Font metadata");
|
||||
|
||||
//// Name Row
|
||||
|
@ -143,6 +143,61 @@ FontEditorWidget::FontEditorWidget(const String& path, RefPtr<Gfx::Font>&& edite
|
|||
m_edited_font->set_name(name_textbox.text());
|
||||
};
|
||||
|
||||
//// Family Row
|
||||
auto& family_container = font_metadata_group_box.add<GUI::Widget>();
|
||||
family_container.set_layout<GUI::HorizontalBoxLayout>();
|
||||
family_container.set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fixed);
|
||||
family_container.set_preferred_size(0, 22);
|
||||
|
||||
auto& family_label = family_container.add<GUI::Label>();
|
||||
family_label.set_size_policy(GUI::SizePolicy::Fixed, GUI::SizePolicy::Fill);
|
||||
family_label.set_preferred_size(100, 0);
|
||||
family_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
|
||||
family_label.set_text("Family:");
|
||||
|
||||
auto& family_textbox = family_container.add<GUI::TextBox>();
|
||||
family_textbox.set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fill);
|
||||
family_textbox.set_text(m_edited_font->family());
|
||||
family_textbox.on_change = [&] {
|
||||
m_edited_font->set_family(family_textbox.text());
|
||||
};
|
||||
|
||||
//// Presentation size Row
|
||||
auto& presentation_size_container = font_metadata_group_box.add<GUI::Widget>();
|
||||
presentation_size_container.set_layout<GUI::HorizontalBoxLayout>();
|
||||
presentation_size_container.set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fixed);
|
||||
presentation_size_container.set_preferred_size(0, 22);
|
||||
|
||||
auto& presentation_size_label = presentation_size_container.add<GUI::Label>();
|
||||
presentation_size_label.set_size_policy(GUI::SizePolicy::Fixed, GUI::SizePolicy::Fill);
|
||||
presentation_size_label.set_preferred_size(100, 0);
|
||||
presentation_size_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
|
||||
presentation_size_label.set_text("Presentation size:");
|
||||
|
||||
auto& presentation_size_spinbox = presentation_size_container.add<GUI::SpinBox>();
|
||||
presentation_size_spinbox.set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fill);
|
||||
presentation_size_spinbox.set_min(0);
|
||||
presentation_size_spinbox.set_max(255);
|
||||
presentation_size_spinbox.set_value(m_edited_font->presentation_size());
|
||||
|
||||
//// Weight Row
|
||||
auto& weight_container = font_metadata_group_box.add<GUI::Widget>();
|
||||
weight_container.set_layout<GUI::HorizontalBoxLayout>();
|
||||
weight_container.set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fixed);
|
||||
weight_container.set_preferred_size(0, 22);
|
||||
|
||||
auto& weight_label = weight_container.add<GUI::Label>();
|
||||
weight_label.set_size_policy(GUI::SizePolicy::Fixed, GUI::SizePolicy::Fill);
|
||||
weight_label.set_preferred_size(100, 0);
|
||||
weight_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
|
||||
weight_label.set_text("Weight:");
|
||||
|
||||
auto& weight_spinbox = weight_container.add<GUI::SpinBox>();
|
||||
weight_spinbox.set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fill);
|
||||
weight_spinbox.set_min(0);
|
||||
weight_spinbox.set_max(65535);
|
||||
weight_spinbox.set_value(m_edited_font->weight());
|
||||
|
||||
//// Glyph spacing Row
|
||||
auto& glyph_spacing_container = font_metadata_group_box.add<GUI::Widget>();
|
||||
glyph_spacing_container.set_layout<GUI::HorizontalBoxLayout>();
|
||||
|
@ -278,7 +333,7 @@ FontEditorWidget::FontEditorWidget(const String& path, RefPtr<Gfx::Font>&& edite
|
|||
right_site_width = max(right_site_width, m_glyph_map_widget->preferred_width());
|
||||
|
||||
m_preferred_width = m_glyph_editor_widget->width() + right_site_width + 20;
|
||||
m_preferred_height = m_glyph_map_widget->relative_rect().height() + 2 * m_edited_font->glyph_height() + 300;
|
||||
m_preferred_height = m_glyph_map_widget->relative_rect().height() + 2 * m_edited_font->glyph_height() + 380;
|
||||
};
|
||||
|
||||
m_glyph_editor_widget->on_glyph_altered = [this, update_demo](u8 glyph) {
|
||||
|
@ -316,6 +371,16 @@ FontEditorWidget::FontEditorWidget(const String& path, RefPtr<Gfx::Font>&& edite
|
|||
update_demo();
|
||||
};
|
||||
|
||||
weight_spinbox.on_change = [this, update_demo](int value) {
|
||||
m_edited_font->set_weight(value);
|
||||
update_demo();
|
||||
};
|
||||
|
||||
presentation_size_spinbox.on_change = [this, update_demo](int value) {
|
||||
m_edited_font->set_presentation_size(value);
|
||||
update_demo();
|
||||
};
|
||||
|
||||
spacing_spinbox.on_change = [this, update_demo](int value) {
|
||||
m_edited_font->set_glyph_spacing(value);
|
||||
update_demo();
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -53,8 +53,10 @@ struct [[gnu::packed]] FontFileHeader
|
|||
u8 glyph_spacing;
|
||||
u8 baseline;
|
||||
u8 mean_line;
|
||||
u8 unused[3];
|
||||
char name[64];
|
||||
u8 presentation_size;
|
||||
u16 weight;
|
||||
char name[32];
|
||||
char family[32];
|
||||
};
|
||||
|
||||
Font& Font::default_font()
|
||||
|
@ -112,7 +114,7 @@ NonnullRefPtr<Font> Font::clone() const
|
|||
memcpy(new_widths, m_glyph_widths, m_glyph_count);
|
||||
else
|
||||
memset(new_widths, m_glyph_width, m_glyph_count);
|
||||
return adopt(*new Font(m_name, new_rows, new_widths, m_fixed_width, m_glyph_width, m_glyph_height, m_glyph_spacing, m_type, m_baseline, m_mean_line));
|
||||
return adopt(*new Font(m_name, m_family, new_rows, new_widths, m_fixed_width, m_glyph_width, m_glyph_height, m_glyph_spacing, m_type, m_baseline, m_mean_line, m_presentation_size, m_weight));
|
||||
}
|
||||
|
||||
NonnullRefPtr<Font> Font::create(u8 glyph_height, u8 glyph_width, bool fixed, FontTypes type)
|
||||
|
@ -124,11 +126,12 @@ NonnullRefPtr<Font> Font::create(u8 glyph_height, u8 glyph_width, bool fixed, Fo
|
|||
memset(new_rows, 0, bytes_per_glyph * count);
|
||||
auto* new_widths = static_cast<u8*>(malloc(count));
|
||||
memset(new_widths, glyph_width, count);
|
||||
return adopt(*new Font("Untitled", new_rows, new_widths, fixed, glyph_width, glyph_height, 1, type, 0, 0));
|
||||
return adopt(*new Font("Untitled", "Untitled", new_rows, new_widths, fixed, glyph_width, glyph_height, 1, type, 0, 0, 0, 400));
|
||||
}
|
||||
|
||||
Font::Font(const StringView& name, unsigned* rows, u8* widths, bool is_fixed_width, u8 glyph_width, u8 glyph_height, u8 glyph_spacing, FontTypes type, u8 baseline, u8 mean_line)
|
||||
Font::Font(String name, String family, unsigned* rows, u8* widths, bool is_fixed_width, u8 glyph_width, u8 glyph_height, u8 glyph_spacing, FontTypes type, u8 baseline, u8 mean_line, u8 presentation_size, u16 weight)
|
||||
: m_name(name)
|
||||
, m_family(family)
|
||||
, m_type(type)
|
||||
, m_rows(rows)
|
||||
, m_glyph_widths(widths)
|
||||
|
@ -139,6 +142,8 @@ Font::Font(const StringView& name, unsigned* rows, u8* widths, bool is_fixed_wid
|
|||
, m_glyph_spacing(glyph_spacing)
|
||||
, m_baseline(baseline)
|
||||
, m_mean_line(mean_line)
|
||||
, m_presentation_size(presentation_size)
|
||||
, m_weight(weight)
|
||||
, m_fixed_width(is_fixed_width)
|
||||
{
|
||||
update_x_height();
|
||||
|
@ -170,11 +175,16 @@ RefPtr<Font> Font::load_from_memory(const u8* data)
|
|||
dbgprintf("header.magic != '!Fnt', instead it's '%c%c%c%c'\n", header.magic[0], header.magic[1], header.magic[2], header.magic[3]);
|
||||
return nullptr;
|
||||
}
|
||||
if (header.name[63] != '\0') {
|
||||
if (header.name[sizeof(header.name) - 1] != '\0') {
|
||||
dbgprintf("Font name not fully null-terminated\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (header.family[sizeof(header.family) - 1] != '\0') {
|
||||
dbgprintf("Font family not fully null-terminated\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FontTypes type;
|
||||
if (header.type == 0)
|
||||
type = FontTypes::Default;
|
||||
|
@ -190,7 +200,7 @@ RefPtr<Font> Font::load_from_memory(const u8* data)
|
|||
u8* widths = nullptr;
|
||||
if (header.is_variable_width)
|
||||
widths = (u8*)(rows) + count * bytes_per_glyph;
|
||||
return adopt(*new Font(String(header.name), rows, widths, !header.is_variable_width, header.glyph_width, header.glyph_height, header.glyph_spacing, type, header.baseline, header.mean_line));
|
||||
return adopt(*new Font(String(header.name), String(header.family), rows, widths, !header.is_variable_width, header.glyph_width, header.glyph_height, header.glyph_spacing, type, header.baseline, header.mean_line, header.presentation_size, header.weight));
|
||||
}
|
||||
|
||||
size_t Font::glyph_count_by_type(FontTypes type)
|
||||
|
@ -231,7 +241,10 @@ bool Font::write_to_file(const StringView& path)
|
|||
header.mean_line = m_mean_line;
|
||||
header.is_variable_width = !m_fixed_width;
|
||||
header.glyph_spacing = m_glyph_spacing;
|
||||
memcpy(header.name, m_name.characters(), min(m_name.length(), (size_t)63));
|
||||
header.presentation_size = m_presentation_size;
|
||||
header.weight = m_weight;
|
||||
memcpy(header.name, m_name.characters(), min(m_name.length(), sizeof(header.name) - 1));
|
||||
memcpy(header.family, m_family.characters(), min(m_family.length(), sizeof(header.family) - 1));
|
||||
|
||||
size_t bytes_per_glyph = sizeof(unsigned) * m_glyph_height;
|
||||
size_t count = glyph_count_by_type(m_type);
|
||||
|
@ -339,32 +352,14 @@ void Font::set_type(FontTypes type)
|
|||
|
||||
void Font::set_family_fonts()
|
||||
{
|
||||
String typeface;
|
||||
String weight;
|
||||
StringBuilder size;
|
||||
|
||||
auto parts = this->name().split(' ');
|
||||
if (parts.size() < 2) {
|
||||
typeface = this->name();
|
||||
} else {
|
||||
typeface = parts[0];
|
||||
weight = parts[1];
|
||||
}
|
||||
|
||||
if (this->is_fixed_width()) {
|
||||
size.appendf("%d", this->m_max_glyph_width);
|
||||
size.append("x");
|
||||
}
|
||||
size.appendf("%d", this->m_glyph_height);
|
||||
|
||||
StringBuilder path;
|
||||
|
||||
if (weight != "Bold") {
|
||||
path.appendf("/res/fonts/%sBold%s.font", &typeface[0], &size.to_string()[0]);
|
||||
if (weight() != 700) {
|
||||
path.appendff("/res/fonts/{}Bold{}.font", family(), presentation_size());
|
||||
auto spath = path.to_string();
|
||||
m_bold_family_font = Font::load_from_file(path.to_string());
|
||||
if (m_bold_family_font)
|
||||
set_boldface(true);
|
||||
path.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -89,6 +89,12 @@ public:
|
|||
|
||||
~Font();
|
||||
|
||||
u8 presentation_size() const { return m_presentation_size; }
|
||||
void set_presentation_size(u8 size) { m_presentation_size = size; }
|
||||
|
||||
u16 weight() const { return m_weight; }
|
||||
void set_weight(u16 weight) { m_weight = weight; }
|
||||
|
||||
GlyphBitmap glyph_bitmap(u32 code_point) const;
|
||||
|
||||
u8 glyph_width(size_t ch) const { return m_fixed_width ? m_glyph_width : m_glyph_widths[ch]; }
|
||||
|
@ -118,8 +124,8 @@ public:
|
|||
int width(const Utf8View&) const;
|
||||
int width(const Utf32View&) const;
|
||||
|
||||
String name() const { return m_name; }
|
||||
void set_name(const StringView& name) { m_name = name; }
|
||||
const String& name() const { return m_name; }
|
||||
void set_name(String name) { m_name = move(name); }
|
||||
|
||||
bool is_fixed_width() const { return m_fixed_width; }
|
||||
void set_fixed_width(bool b) { m_fixed_width = b; }
|
||||
|
@ -142,8 +148,11 @@ public:
|
|||
FontTypes type() { return m_type; }
|
||||
void set_type(FontTypes type);
|
||||
|
||||
const String& family() const { return m_family; }
|
||||
void set_family(String family) { m_family = move(family); }
|
||||
|
||||
private:
|
||||
Font(const StringView& name, unsigned* rows, u8* widths, bool is_fixed_width, u8 glyph_width, u8 glyph_height, u8 glyph_spacing, FontTypes type, u8 baseline, u8 mean_line);
|
||||
Font(String name, String family, unsigned* rows, u8* widths, bool is_fixed_width, u8 glyph_width, u8 glyph_height, u8 glyph_spacing, FontTypes type, u8 baseline, u8 mean_line, u8 presentation_size, u16 weight);
|
||||
|
||||
static RefPtr<Font> load_from_memory(const u8*);
|
||||
static size_t glyph_count_by_type(FontTypes type);
|
||||
|
@ -154,6 +163,7 @@ private:
|
|||
RefPtr<Font> m_bold_family_font;
|
||||
|
||||
String m_name;
|
||||
String m_family;
|
||||
FontTypes m_type;
|
||||
size_t m_glyph_count { 256 };
|
||||
|
||||
|
@ -169,6 +179,8 @@ private:
|
|||
u8 m_glyph_spacing { 0 };
|
||||
u8 m_baseline { 0 };
|
||||
u8 m_mean_line { 0 };
|
||||
u8 m_presentation_size { 0 };
|
||||
u16 m_weight { 0 };
|
||||
|
||||
bool m_fixed_width { false };
|
||||
bool m_boldface { false };
|
||||
|
|
Loading…
Add table
Reference in a new issue