1
0
Fork 0
mirror of https://github.com/LadybirdBrowser/ladybird.git synced 2025-06-10 01:51:03 +09:00

CharacterMap: Add new Character Map application :^)

This commit is contained in:
Sam Atkins 2022-01-10 15:59:42 +00:00 committed by Andreas Kling
parent 1d79e8cb0f
commit 2327ea8970
Notes: sideshowbarker 2024-07-17 20:46:22 +09:00
7 changed files with 278 additions and 0 deletions

View file

@ -0,0 +1,4 @@
[App]
Name=Character Map
Executable=/bin/CharacterMap
Category=Utilities

View file

@ -6,6 +6,7 @@ add_subdirectory(Browser)
add_subdirectory(BrowserSettings)
add_subdirectory(Calculator)
add_subdirectory(Calendar)
add_subdirectory(CharacterMap)
add_subdirectory(CrashReporter)
add_subdirectory(Debugger)
add_subdirectory(DisplaySettings)

View file

@ -0,0 +1,17 @@
serenity_component(
CharacterMap
REQUIRED
TARGETS CharacterMap
)
compile_gml(CharacterMapWindow.gml CharacterMapWindowGML.h character_map_window_gml)
set(SOURCES
CharacterMapWindowGML.h
CharacterMapWidget.cpp
main.cpp
)
serenity_app(CharacterMap ICON app-keyboard-settings)
target_link_libraries(CharacterMap LibGUI LibMain)
link_with_unicode_data(CharacterMap)

View file

@ -0,0 +1,90 @@
/*
* Copyright (c) 2022, Sam Atkins <atkinssj@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "CharacterMapWidget.h"
#include <Applications/CharacterMap/CharacterMapWindowGML.h>
#include <LibConfig/Client.h>
#include <LibGUI/Action.h>
#include <LibGUI/Application.h>
#include <LibGUI/Clipboard.h>
#include <LibGUI/FontPicker.h>
#include <LibGUI/Icon.h>
#include <LibGUI/Label.h>
#include <LibGUI/Menu.h>
#include <LibGUI/Toolbar.h>
#include <LibUnicode/CharacterTypes.h>
CharacterMapWidget::CharacterMapWidget()
{
load_from_gml(character_map_window_gml);
m_toolbar = find_descendant_of_type_named<GUI::Toolbar>("toolbar");
m_font_name_label = find_descendant_of_type_named<GUI::Label>("font_name");
m_glyph_map = find_descendant_of_type_named<GUI::GlyphMapWidget>("glyph_map");
m_statusbar = find_descendant_of_type_named<GUI::Statusbar>("statusbar");
m_choose_font_action = GUI::Action::create("Choose Font...", Gfx::Bitmap::try_load_from_file("/res/icons/16x16/app-font-editor.png").release_value_but_fixme_should_propagate_errors(), [&](auto&) {
auto font_picker = GUI::FontPicker::construct(window(), &font(), false);
if (font_picker->exec() == GUI::Dialog::ExecOK) {
auto& font = *font_picker->font();
Config::write_string("CharacterMap", "History", "Font", font.qualified_name());
set_font(font);
}
});
m_copy_selection_action = GUI::CommonActions::make_copy_action([&](GUI::Action&) {
auto selection = m_glyph_map->selection();
StringBuilder builder;
for (auto code_point = selection.start(); code_point < selection.start() + selection.size(); ++code_point) {
if (!m_glyph_map->font().contains_glyph(code_point))
continue;
builder.append_code_point(code_point);
}
GUI::Clipboard::the().set_plain_text(builder.to_string());
});
m_toolbar->add_action(*m_choose_font_action);
m_toolbar->add_separator();
m_toolbar->add_action(*m_copy_selection_action);
m_glyph_map->on_active_glyph_changed = [&](int) {
update_statusbar();
};
did_change_font();
update_statusbar();
}
CharacterMapWidget::~CharacterMapWidget()
{
}
void CharacterMapWidget::initialize_menubar(GUI::Window& window)
{
auto& file_menu = window.add_menu("&File");
file_menu.add_action(GUI::CommonActions::make_quit_action([](GUI::Action&) {
GUI::Application::the()->quit();
}));
auto& help_menu = window.add_menu("&Help");
help_menu.add_action(GUI::CommonActions::make_about_action("Character Map", GUI::Icon::default_icon("app-keyboard-settings"), &window));
}
void CharacterMapWidget::did_change_font()
{
m_glyph_map->set_font(font());
m_font_name_label->set_text(font().qualified_name());
}
void CharacterMapWidget::update_statusbar()
{
auto code_point = m_glyph_map->active_glyph();
StringBuilder builder;
builder.appendff("U+{:04X}", code_point);
if (auto display_name = Unicode::code_point_display_name(code_point); display_name.has_value())
builder.appendff(" - {}", display_name.value());
m_statusbar->set_text(builder.to_string());
}

View file

@ -0,0 +1,34 @@
/*
* Copyright (c) 2022, Sam Atkins <atkinssj@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibGUI/Button.h>
#include <LibGUI/GlyphMapWidget.h>
#include <LibGUI/Statusbar.h>
class CharacterMapWidget final : public GUI::Widget {
C_OBJECT(CharacterMapWidget);
public:
virtual ~CharacterMapWidget() override;
void initialize_menubar(GUI::Window& window);
private:
CharacterMapWidget();
virtual void did_change_font() override;
void update_statusbar();
RefPtr<GUI::Toolbar> m_toolbar;
RefPtr<GUI::Label> m_font_name_label;
RefPtr<GUI::GlyphMapWidget> m_glyph_map;
RefPtr<GUI::Statusbar> m_statusbar;
RefPtr<GUI::Action> m_choose_font_action;
RefPtr<GUI::Action> m_copy_selection_action;
};

View file

@ -0,0 +1,44 @@
@GUI::Frame {
fill_with_background_color: true
layout: @GUI::VerticalBoxLayout {
}
@GUI::ToolbarContainer {
@GUI::Toolbar {
layout: @GUI::HorizontalBoxLayout {
spacing: 4
margins: [0, 0, 0, 4]
}
name: "toolbar"
@GUI::Label {
text: "Font: "
autosize: true
}
@GUI::Frame {
background_role: "Base"
fill_with_background_color: true
fixed_height: 20
layout: @GUI::VerticalBoxLayout {
}
@GUI::Label {
name: "font_name"
text: "Cool Font 16 400"
}
}
}
}
@GUI::GlyphMapWidget {
name: "glyph_map"
}
@GUI::Statusbar {
name: "statusbar"
}
}

View file

@ -0,0 +1,88 @@
/*
* Copyright (c) 2022, Sam Atkins <atkinssj@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "CharacterMapWidget.h"
#include <LibConfig/Client.h>
#include <LibCore/ArgsParser.h>
#include <LibCore/System.h>
#include <LibGUI/Application.h>
#include <LibGUI/Icon.h>
#include <LibGUI/Window.h>
#include <LibGfx/FontDatabase.h>
#include <LibMain/Main.h>
#include <LibUnicode/CharacterTypes.h>
static void search_and_print_results(String const& query)
{
outln("Searching for '{}'", query);
String uppercase_query = query.to_uppercase();
StringView uppercase_query_view = uppercase_query.view();
// FIXME: At time of writing there are 144,697 code points in Unicode. I've added some breathing room,
// but ideally this would be defined in LibUnicode somewhere.
constexpr u32 unicode_character_count = 150000;
// FIXME: There's probably a better way to do this than just looping, but it still only takes ~150ms to run for me!
u32 result_count = 0;
for (u32 i = 1; i < unicode_character_count; ++i) {
if (auto maybe_display_name = Unicode::code_point_display_name(i); maybe_display_name.has_value()) {
auto& display_name = maybe_display_name.value();
// FIXME: This should be a case-sensitive search, since we already converted the query to uppercase
// and the unicode names are all in uppercase. But, that makes it run slower!
// Sensitive: ~175ms, Insensitive: ~140ms
if (display_name.contains(uppercase_query_view, AK::CaseSensitivity::CaseInsensitive)) {
StringBuilder builder;
builder.append_code_point(i);
builder.append(" - ");
builder.append(display_name);
outln(builder.string_view());
result_count++;
}
}
}
if (result_count == 0)
outln("No results found.");
else if (result_count == 1)
outln("1 result found.");
else
outln("{} results found.", result_count);
}
ErrorOr<int> serenity_main(Main::Arguments arguments)
{
TRY(Core::System::pledge("stdio recvfd sendfd rpath unix"));
auto app = TRY(GUI::Application::try_create(arguments));
Config::pledge_domains("CharacterMap");
TRY(Core::System::pledge("stdio recvfd sendfd rpath"));
TRY(Core::System::unveil("/res", "r"));
TRY(Core::System::unveil(nullptr, nullptr));
String query;
Core::ArgsParser args_parser;
args_parser.add_option(query, "Search character names using this query, and print them as a list.", "search", 's', "query");
args_parser.parse(arguments);
if (!query.is_empty()) {
search_and_print_results(query);
return 0;
}
auto app_icon = TRY(GUI::Icon::try_create_default_icon("app-keyboard-settings"));
auto window = TRY(GUI::Window::try_create());
window->set_title("Character Map");
window->set_icon(app_icon.bitmap_for_size(16));
window->resize(400, 400);
auto character_map_widget = TRY(window->try_set_main_widget<CharacterMapWidget>());
character_map_widget->initialize_menubar(*window);
auto font_query = Config::read_string("CharacterMap", "History", "Font", Gfx::FontDatabase::the().default_font_query());
character_map_widget->set_font(Gfx::FontDatabase::the().get_by_name(font_query));
window->show();
return app->exec();
}