mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 07:48:11 +00:00
FileManager: Add "Font" tab to File Properties window
We now keep the MappedFile around when inspecting a font, so that we can use that font to display a preview.
This commit is contained in:
parent
98eaa4b044
commit
8ec691057f
4 changed files with 228 additions and 0 deletions
|
@ -8,6 +8,7 @@ serenity_component(
|
||||||
compile_gml(FileManagerWindow.gml FileManagerWindowGML.h file_manager_window_gml)
|
compile_gml(FileManagerWindow.gml FileManagerWindowGML.h file_manager_window_gml)
|
||||||
compile_gml(FileOperationProgress.gml FileOperationProgressGML.h file_operation_progress_gml)
|
compile_gml(FileOperationProgress.gml FileOperationProgressGML.h file_operation_progress_gml)
|
||||||
compile_gml(PropertiesWindowAudioTab.gml PropertiesWindowAudioTabGML.h properties_window_audio_tab_gml)
|
compile_gml(PropertiesWindowAudioTab.gml PropertiesWindowAudioTabGML.h properties_window_audio_tab_gml)
|
||||||
|
compile_gml(PropertiesWindowFontTab.gml PropertiesWindowFontTabGML.h properties_window_font_tab_gml)
|
||||||
compile_gml(PropertiesWindowGeneralTab.gml PropertiesWindowGeneralTabGML.h properties_window_general_tab_gml)
|
compile_gml(PropertiesWindowGeneralTab.gml PropertiesWindowGeneralTabGML.h properties_window_general_tab_gml)
|
||||||
compile_gml(PropertiesWindowImageTab.gml PropertiesWindowImageTabGML.h properties_window_image_tab_gml)
|
compile_gml(PropertiesWindowImageTab.gml PropertiesWindowImageTabGML.h properties_window_image_tab_gml)
|
||||||
|
|
||||||
|
@ -24,6 +25,7 @@ set(GENERATED_SOURCES
|
||||||
FileManagerWindowGML.h
|
FileManagerWindowGML.h
|
||||||
FileOperationProgressGML.h
|
FileOperationProgressGML.h
|
||||||
PropertiesWindowAudioTabGML.h
|
PropertiesWindowAudioTabGML.h
|
||||||
|
PropertiesWindowFontTabGML.h
|
||||||
PropertiesWindowGeneralTabGML.h
|
PropertiesWindowGeneralTabGML.h
|
||||||
PropertiesWindowImageTabGML.h
|
PropertiesWindowImageTabGML.h
|
||||||
)
|
)
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <AK/NumberFormat.h>
|
#include <AK/NumberFormat.h>
|
||||||
#include <Applications/FileManager/DirectoryView.h>
|
#include <Applications/FileManager/DirectoryView.h>
|
||||||
#include <Applications/FileManager/PropertiesWindowAudioTabGML.h>
|
#include <Applications/FileManager/PropertiesWindowAudioTabGML.h>
|
||||||
|
#include <Applications/FileManager/PropertiesWindowFontTabGML.h>
|
||||||
#include <Applications/FileManager/PropertiesWindowGeneralTabGML.h>
|
#include <Applications/FileManager/PropertiesWindowGeneralTabGML.h>
|
||||||
#include <Applications/FileManager/PropertiesWindowImageTabGML.h>
|
#include <Applications/FileManager/PropertiesWindowImageTabGML.h>
|
||||||
#include <LibAudio/Loader.h>
|
#include <LibAudio/Loader.h>
|
||||||
|
@ -27,6 +28,12 @@
|
||||||
#include <LibGUI/MessageBox.h>
|
#include <LibGUI/MessageBox.h>
|
||||||
#include <LibGUI/SeparatorWidget.h>
|
#include <LibGUI/SeparatorWidget.h>
|
||||||
#include <LibGUI/TabWidget.h>
|
#include <LibGUI/TabWidget.h>
|
||||||
|
#include <LibGfx/Font/BitmapFont.h>
|
||||||
|
#include <LibGfx/Font/FontDatabase.h>
|
||||||
|
#include <LibGfx/Font/FontStyleMapping.h>
|
||||||
|
#include <LibGfx/Font/OpenType/Font.h>
|
||||||
|
#include <LibGfx/Font/Typeface.h>
|
||||||
|
#include <LibGfx/Font/WOFF/Font.h>
|
||||||
#include <LibGfx/ICC/Profile.h>
|
#include <LibGfx/ICC/Profile.h>
|
||||||
#include <LibGfx/ICC/Tags.h>
|
#include <LibGfx/ICC/Tags.h>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
|
@ -218,6 +225,9 @@ ErrorOr<void> PropertiesWindow::create_file_type_specific_tabs(GUI::TabWidget& t
|
||||||
if (mime_type.starts_with("audio/"sv))
|
if (mime_type.starts_with("audio/"sv))
|
||||||
return create_audio_tab(tab_widget, move(mapped_file));
|
return create_audio_tab(tab_widget, move(mapped_file));
|
||||||
|
|
||||||
|
if (mime_type.starts_with("font/"sv) || m_path.ends_with(".font"sv))
|
||||||
|
return create_font_tab(tab_widget, move(mapped_file), mime_type);
|
||||||
|
|
||||||
if (mime_type.starts_with("image/"sv))
|
if (mime_type.starts_with("image/"sv))
|
||||||
return create_image_tab(tab_widget, move(mapped_file), mime_type);
|
return create_image_tab(tab_widget, move(mapped_file), mime_type);
|
||||||
|
|
||||||
|
@ -262,6 +272,98 @@ ErrorOr<void> PropertiesWindow::create_audio_tab(GUI::TabWidget& tab_widget, Non
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct FontInfo {
|
||||||
|
enum class Format {
|
||||||
|
BitmapFont,
|
||||||
|
OpenType,
|
||||||
|
TrueType,
|
||||||
|
WOFF,
|
||||||
|
WOFF2,
|
||||||
|
};
|
||||||
|
Format format;
|
||||||
|
NonnullRefPtr<Gfx::Typeface> typeface;
|
||||||
|
};
|
||||||
|
static ErrorOr<FontInfo> load_font(StringView path, StringView mime_type, NonnullRefPtr<Core::MappedFile> mapped_file)
|
||||||
|
{
|
||||||
|
if (path.ends_with(".font"sv)) {
|
||||||
|
auto font = TRY(Gfx::BitmapFont::try_load_from_mapped_file(mapped_file));
|
||||||
|
auto typeface = TRY(try_make_ref_counted<Gfx::Typeface>(font->family(), font->variant()));
|
||||||
|
typeface->add_bitmap_font(move(font));
|
||||||
|
return FontInfo { FontInfo::Format::BitmapFont, move(typeface) };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mime_type == "font/otf" || mime_type == "font/ttf") {
|
||||||
|
auto font = TRY(OpenType::Font::try_load_from_externally_owned_memory(mapped_file->bytes()));
|
||||||
|
auto typeface = TRY(try_make_ref_counted<Gfx::Typeface>(font->family(), font->variant()));
|
||||||
|
typeface->set_vector_font(move(font));
|
||||||
|
return FontInfo {
|
||||||
|
mime_type == "font/otf" ? FontInfo::Format::OpenType : FontInfo::Format::TrueType,
|
||||||
|
move(typeface)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mime_type == "font/woff" || mime_type == "font/woff2") {
|
||||||
|
auto font = TRY(WOFF::Font::try_load_from_externally_owned_memory(mapped_file->bytes()));
|
||||||
|
auto typeface = TRY(try_make_ref_counted<Gfx::Typeface>(font->family(), font->variant()));
|
||||||
|
typeface->set_vector_font(move(font));
|
||||||
|
return FontInfo {
|
||||||
|
mime_type == "font/woff" ? FontInfo::Format::WOFF : FontInfo::Format::WOFF2,
|
||||||
|
move(typeface)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return Error::from_string_view("Unrecognized font format."sv);
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> PropertiesWindow::create_font_tab(GUI::TabWidget& tab_widget, NonnullRefPtr<Core::MappedFile> mapped_file, StringView mime_type)
|
||||||
|
{
|
||||||
|
auto font_info_or_error = load_font(m_path, mime_type, mapped_file);
|
||||||
|
if (font_info_or_error.is_error()) {
|
||||||
|
warnln("Failed to open '{}': {}", m_path, font_info_or_error.release_error());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
auto font_info = font_info_or_error.release_value();
|
||||||
|
auto& typeface = font_info.typeface;
|
||||||
|
|
||||||
|
auto tab = TRY(tab_widget.try_add_tab<GUI::Widget>("Font"_short_string));
|
||||||
|
TRY(tab->load_from_gml(properties_window_font_tab_gml));
|
||||||
|
|
||||||
|
String format_name;
|
||||||
|
switch (font_info.format) {
|
||||||
|
case FontInfo::Format::BitmapFont:
|
||||||
|
format_name = TRY("Bitmap Font"_string);
|
||||||
|
break;
|
||||||
|
case FontInfo::Format::OpenType:
|
||||||
|
format_name = TRY("OpenType"_string);
|
||||||
|
break;
|
||||||
|
case FontInfo::Format::TrueType:
|
||||||
|
format_name = TRY("TrueType"_string);
|
||||||
|
break;
|
||||||
|
case FontInfo::Format::WOFF:
|
||||||
|
format_name = TRY("WOFF"_string);
|
||||||
|
break;
|
||||||
|
case FontInfo::Format::WOFF2:
|
||||||
|
format_name = TRY("WOFF2"_string);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tab->find_descendant_of_type_named<GUI::Label>("font_format")->set_text(format_name);
|
||||||
|
tab->find_descendant_of_type_named<GUI::Label>("font_family")->set_text(TRY(String::from_deprecated_string(typeface->family())));
|
||||||
|
tab->find_descendant_of_type_named<GUI::Label>("font_fixed_width")->set_text(typeface->is_fixed_width() ? "Yes"_short_string : "No"_short_string);
|
||||||
|
tab->find_descendant_of_type_named<GUI::Label>("font_width")->set_text(TRY(String::from_utf8(Gfx::width_to_name(static_cast<Gfx::FontWidth>(typeface->width())))));
|
||||||
|
|
||||||
|
auto nearest_weight_class_name = [](unsigned weight) {
|
||||||
|
if (weight > 925)
|
||||||
|
return Gfx::weight_to_name(Gfx::FontWeight::ExtraBlack);
|
||||||
|
unsigned weight_class = clamp(round_to<unsigned>(weight / 100.0) * 100, Gfx::FontWeight::Thin, Gfx::FontWeight::Black);
|
||||||
|
return Gfx::weight_to_name(weight_class);
|
||||||
|
};
|
||||||
|
auto weight = typeface->weight();
|
||||||
|
tab->find_descendant_of_type_named<GUI::Label>("font_weight")->set_text(TRY(String::formatted("{} ({})", weight, nearest_weight_class_name(weight))));
|
||||||
|
tab->find_descendant_of_type_named<GUI::Label>("font_slope")->set_text(TRY(String::from_utf8(Gfx::slope_to_name(typeface->slope()))));
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
ErrorOr<void> PropertiesWindow::create_image_tab(GUI::TabWidget& tab_widget, NonnullRefPtr<Core::MappedFile> mapped_file, StringView mime_type)
|
ErrorOr<void> PropertiesWindow::create_image_tab(GUI::TabWidget& tab_widget, NonnullRefPtr<Core::MappedFile> mapped_file, StringView mime_type)
|
||||||
{
|
{
|
||||||
auto image_decoder = Gfx::ImageDecoder::try_create_for_raw_bytes(mapped_file->bytes(), mime_type);
|
auto image_decoder = Gfx::ImageDecoder::try_create_for_raw_bytes(mapped_file->bytes(), mime_type);
|
||||||
|
|
|
@ -31,6 +31,7 @@ private:
|
||||||
ErrorOr<void> create_general_tab(GUI::TabWidget&, bool disable_rename);
|
ErrorOr<void> create_general_tab(GUI::TabWidget&, bool disable_rename);
|
||||||
ErrorOr<void> create_file_type_specific_tabs(GUI::TabWidget&);
|
ErrorOr<void> create_file_type_specific_tabs(GUI::TabWidget&);
|
||||||
ErrorOr<void> create_audio_tab(GUI::TabWidget&, NonnullRefPtr<Core::MappedFile>);
|
ErrorOr<void> create_audio_tab(GUI::TabWidget&, NonnullRefPtr<Core::MappedFile>);
|
||||||
|
ErrorOr<void> create_font_tab(GUI::TabWidget&, NonnullRefPtr<Core::MappedFile>, StringView mime_type);
|
||||||
ErrorOr<void> create_image_tab(GUI::TabWidget&, NonnullRefPtr<Core::MappedFile>, StringView mime_type);
|
ErrorOr<void> create_image_tab(GUI::TabWidget&, NonnullRefPtr<Core::MappedFile>, StringView mime_type);
|
||||||
|
|
||||||
struct PermissionMasks {
|
struct PermissionMasks {
|
||||||
|
|
123
Userland/Applications/FileManager/PropertiesWindowFontTab.gml
Normal file
123
Userland/Applications/FileManager/PropertiesWindowFontTab.gml
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
@GUI::Widget {
|
||||||
|
layout: @GUI::VerticalBoxLayout {
|
||||||
|
margins: [8]
|
||||||
|
spacing: 12
|
||||||
|
}
|
||||||
|
|
||||||
|
@GUI::GroupBox {
|
||||||
|
title: "Font"
|
||||||
|
preferred_height: "shrink"
|
||||||
|
layout: @GUI::VerticalBoxLayout {
|
||||||
|
margins: [12, 8, 0]
|
||||||
|
spacing: 2
|
||||||
|
}
|
||||||
|
|
||||||
|
@GUI::Widget {
|
||||||
|
layout: @GUI::HorizontalBoxLayout {
|
||||||
|
spacing: 12
|
||||||
|
}
|
||||||
|
|
||||||
|
@GUI::Label {
|
||||||
|
text: "Format:"
|
||||||
|
text_alignment: "TopLeft"
|
||||||
|
fixed_width: 80
|
||||||
|
}
|
||||||
|
|
||||||
|
@GUI::Label {
|
||||||
|
name: "font_format"
|
||||||
|
text: "TrueType"
|
||||||
|
text_alignment: "TopLeft"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GUI::Widget {
|
||||||
|
layout: @GUI::HorizontalBoxLayout {
|
||||||
|
spacing: 12
|
||||||
|
}
|
||||||
|
|
||||||
|
@GUI::Label {
|
||||||
|
text: "Family:"
|
||||||
|
text_alignment: "TopLeft"
|
||||||
|
fixed_width: 80
|
||||||
|
}
|
||||||
|
|
||||||
|
@GUI::Label {
|
||||||
|
name: "font_family"
|
||||||
|
text: "SerenitySans"
|
||||||
|
text_alignment: "TopLeft"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GUI::Widget {
|
||||||
|
layout: @GUI::HorizontalBoxLayout {
|
||||||
|
spacing: 12
|
||||||
|
}
|
||||||
|
|
||||||
|
@GUI::Label {
|
||||||
|
text: "Fixed width:"
|
||||||
|
text_alignment: "TopLeft"
|
||||||
|
fixed_width: 80
|
||||||
|
}
|
||||||
|
|
||||||
|
@GUI::Label {
|
||||||
|
name: "font_fixed_width"
|
||||||
|
text: "No"
|
||||||
|
text_alignment: "TopLeft"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GUI::Widget {
|
||||||
|
layout: @GUI::HorizontalBoxLayout {
|
||||||
|
spacing: 12
|
||||||
|
}
|
||||||
|
|
||||||
|
@GUI::Label {
|
||||||
|
text: "Width:"
|
||||||
|
text_alignment: "TopLeft"
|
||||||
|
fixed_width: 80
|
||||||
|
}
|
||||||
|
|
||||||
|
@GUI::Label {
|
||||||
|
name: "font_width"
|
||||||
|
text: "Normal"
|
||||||
|
text_alignment: "TopLeft"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GUI::Widget {
|
||||||
|
layout: @GUI::HorizontalBoxLayout {
|
||||||
|
spacing: 12
|
||||||
|
}
|
||||||
|
|
||||||
|
@GUI::Label {
|
||||||
|
text: "Weight:"
|
||||||
|
text_alignment: "TopLeft"
|
||||||
|
fixed_width: 80
|
||||||
|
}
|
||||||
|
|
||||||
|
@GUI::Label {
|
||||||
|
name: "font_weight"
|
||||||
|
text: "500 (Medium)"
|
||||||
|
text_alignment: "TopLeft"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GUI::Widget {
|
||||||
|
layout: @GUI::HorizontalBoxLayout {
|
||||||
|
spacing: 12
|
||||||
|
}
|
||||||
|
|
||||||
|
@GUI::Label {
|
||||||
|
text: "Slope:"
|
||||||
|
text_alignment: "TopLeft"
|
||||||
|
fixed_width: 80
|
||||||
|
}
|
||||||
|
|
||||||
|
@GUI::Label {
|
||||||
|
name: "font_slope"
|
||||||
|
text: "Regular"
|
||||||
|
text_alignment: "TopLeft"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue