2020-01-18 05:38:21 -03:00
/*
* Copyright ( c ) 2018 - 2020 , Andreas Kling < kling @ serenityos . org >
2022-02-10 16:28:48 -03:00
* Copyright ( c ) 2022 , the SerenityOS developers .
2020-01-18 05:38:21 -03:00
*
2021-04-22 05:24:48 -03:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-01-18 05:38:21 -03:00
*/
2022-07-05 07:37:06 -03:00
# include "MainWidget.h"
2019-04-03 10:23:13 -03:00
# include "GlyphEditorWidget.h"
2021-04-10 14:47:23 -03:00
# include "NewFontDialog.h"
2022-02-09 21:45:15 -03:00
# include <AK/Array.h>
2019-09-04 17:50:40 -03:00
# include <AK/StringBuilder.h>
2022-02-13 17:18:39 -03:00
# include <AK/StringUtils.h>
2021-04-06 13:04:21 -03:00
# include <Applications/FontEditor/FontEditorWindowGML.h>
2022-07-04 23:41:05 -03:00
# include <Applications/FontEditor/FontPreviewWindowGML.h>
2021-11-14 10:26:10 -03:00
# include <LibConfig/Client.h>
2021-04-10 14:40:59 -03:00
# include <LibDesktop/Launcher.h>
2021-04-06 13:04:21 -03:00
# include <LibGUI/Action.h>
2021-04-10 14:40:59 -03:00
# include <LibGUI/Application.h>
2020-02-06 16:33:02 -03:00
# include <LibGUI/Button.h>
# include <LibGUI/CheckBox.h>
2021-04-10 14:40:59 -03:00
# include <LibGUI/Clipboard.h>
# include <LibGUI/ComboBox.h>
2021-04-06 13:04:21 -03:00
# include <LibGUI/FilePicker.h>
2022-07-05 06:32:22 -03:00
# include <LibGUI/GlyphMapWidget.h>
2020-02-06 16:33:02 -03:00
# include <LibGUI/GroupBox.h>
2021-09-09 08:43:19 -03:00
# include <LibGUI/InputBox.h>
2021-09-23 21:07:34 -03:00
# include <LibGUI/ItemListModel.h>
2020-02-06 16:33:02 -03:00
# include <LibGUI/Label.h>
2022-02-13 17:18:39 -03:00
# include <LibGUI/ListView.h>
2021-04-10 14:40:59 -03:00
# include <LibGUI/Menu.h>
2021-04-13 11:18:20 -03:00
# include <LibGUI/Menubar.h>
2020-05-08 19:06:56 -03:00
# include <LibGUI/MessageBox.h>
2020-02-06 16:33:02 -03:00
# include <LibGUI/SpinBox.h>
2021-04-13 11:18:20 -03:00
# include <LibGUI/Statusbar.h>
2020-02-06 16:33:02 -03:00
# include <LibGUI/TextBox.h>
2021-04-13 11:18:20 -03:00
# include <LibGUI/ToolbarContainer.h>
2020-05-08 19:06:56 -03:00
# include <LibGUI/Window.h>
2022-04-09 04:28:38 -03:00
# include <LibGfx/Font/BitmapFont.h>
# include <LibGfx/Font/Emoji.h>
# include <LibGfx/Font/FontStyleMapping.h>
2021-05-20 08:00:04 -03:00
# include <LibGfx/TextDirection.h>
2021-11-18 19:39:54 -03:00
# include <LibUnicode/CharacterTypes.h>
2019-02-02 05:05:14 -02:00
2022-07-05 06:32:22 -03:00
namespace FontEditor {
2022-03-02 21:55:14 -03:00
static constexpr Array pangrams = {
2022-07-11 14:32:29 -03:00
" quick fox jumps nightly above wizard " sv ,
" five quacking zephyrs jolt my wax bed " sv ,
" pack my box with five dozen liquor jugs " sv ,
" quick brown fox jumps over the lazy dog " sv ,
" waxy and quivering jocks fumble the pizza " sv ,
" ~#:[@_1%]*{$2.3}/4^(5'6 \" sv)-&|7+8!=<9,0 \\ >?; " sv ,
" byxfjärmat föl gick på duvshowen " sv ,
" " sv ,
" float Fox.quick(h){ is_brown && it_jumps_over(doges.lazy) } " sv ,
" <fox color= \" brown \" speed= \" quick \" jumps= \" over \" >lazy dog</fox> " sv
2022-03-02 21:55:14 -03:00
} ;
2022-07-05 07:37:06 -03:00
ErrorOr < RefPtr < GUI : : Window > > MainWidget : : create_preview_window ( )
2019-02-02 05:05:14 -02:00
{
2022-07-04 23:41:05 -03:00
auto window = TRY ( GUI : : Window : : try_create ( this ) ) ;
2022-08-22 13:52:21 -03:00
window - > set_window_mode ( GUI : : WindowMode : : RenderAbove ) ;
2021-09-22 10:25:25 -03:00
window - > set_title ( " Preview " ) ;
2021-04-06 13:04:21 -03:00
window - > resize ( 400 , 150 ) ;
2022-07-04 23:41:05 -03:00
window - > center_within ( * this - > window ( ) ) ;
2021-04-06 13:04:21 -03:00
2022-07-04 23:41:05 -03:00
auto main_widget = TRY ( window - > try_set_main_widget < GUI : : Widget > ( ) ) ;
main_widget - > load_from_gml ( font_preview_window_gml ) ;
2021-04-06 13:04:21 -03:00
2022-07-04 23:41:05 -03:00
m_preview_label = find_descendant_of_type_named < GUI : : Label > ( " preview_label " ) ;
m_preview_label - > set_font ( edited_font ( ) ) ;
2021-04-06 13:04:21 -03:00
2022-07-04 23:41:05 -03:00
m_preview_textbox = find_descendant_of_type_named < GUI : : TextBox > ( " preview_textbox " ) ;
m_preview_textbox - > on_change = [ & ] {
auto preview = String : : formatted ( " {} \n {} " , m_preview_textbox - > text ( ) , Unicode : : to_unicode_uppercase_full ( m_preview_textbox - > text ( ) ) ) ;
m_preview_label - > set_text ( preview ) ;
2020-10-24 12:03:39 -03:00
} ;
2022-07-04 23:41:05 -03:00
m_preview_textbox - > set_text ( pangrams [ 0 ] ) ;
2020-10-24 12:03:39 -03:00
2022-07-04 23:41:05 -03:00
auto & reload_button = * find_descendant_of_type_named < GUI : : Button > ( " reload_button " ) ;
AK+Everywhere: Disallow constructing Functions from incompatible types
Previously, AK::Function would accept _any_ callable type, and try to
call it when called, first with the given set of arguments, then with
zero arguments, and if all of those failed, it would simply not call the
function and **return a value-constructed Out type**.
This lead to many, many, many hard to debug situations when someone
forgot a `const` in their lambda argument types, and many cases of
people taking zero arguments in their lambdas to ignore them.
This commit reworks the Function interface to not include any such
surprising behaviour, if your function instance is not callable with
the declared argument set of the Function, it can simply not be
assigned to that Function instance, end of story.
2021-06-05 15:34:31 -03:00
reload_button . on_click = [ & ] ( auto ) {
2022-02-09 21:45:15 -03:00
static size_t i = 1 ;
if ( i > = pangrams . size ( ) )
2021-04-22 14:41:43 -03:00
i = 0 ;
2022-07-04 23:41:05 -03:00
m_preview_textbox - > set_text ( pangrams [ i ] ) ;
2021-04-22 14:41:43 -03:00
i + + ;
} ;
2021-04-06 13:04:21 -03:00
return window ;
}
2022-07-05 07:37:06 -03:00
ErrorOr < void > MainWidget : : create_actions ( )
2021-04-06 13:04:21 -03:00
{
2022-07-11 14:32:29 -03:00
m_new_action = GUI : : Action : : create ( " &New Font... " , { Mod_Ctrl , Key_N } , TRY ( Gfx : : Bitmap : : try_load_from_file ( " /res/icons/16x16/filetype-font.png " sv ) ) , [ & ] ( auto & ) {
2021-11-29 11:44:26 -03:00
if ( ! request_close ( ) )
return ;
2021-04-10 14:47:23 -03:00
auto new_font_wizard = NewFontDialog : : construct ( window ( ) ) ;
2022-07-30 08:34:04 -03:00
if ( new_font_wizard - > exec ( ) ! = GUI : : Dialog : : ExecResult : : OK )
return ;
new_font_wizard - > hide ( ) ;
auto maybe_font = new_font_wizard - > create_font ( ) ;
if ( maybe_font . is_error ( ) )
return show_error ( " Failed to create new font " sv , maybe_font . error ( ) ) ;
if ( auto result = initialize ( { } , move ( maybe_font . value ( ) ) ) ; result . is_error ( ) )
show_error ( " Failed to initialize font " sv , result . error ( ) ) ;
2021-04-10 14:47:23 -03:00
} ) ;
2021-04-22 14:53:17 -03:00
m_new_action - > set_status_tip ( " Create a new font " ) ;
2022-07-04 23:22:06 -03:00
2021-04-10 14:47:23 -03:00
m_open_action = GUI : : CommonActions : : make_open_action ( [ & ] ( auto & ) {
2021-10-13 17:09:38 -03:00
if ( ! request_close ( ) )
return ;
2022-07-11 14:32:29 -03:00
Optional < String > open_path = GUI : : FilePicker : : get_open_filepath ( window ( ) , { } , " /res/fonts/ " sv ) ;
2021-04-06 13:04:21 -03:00
if ( ! open_path . has_value ( ) )
return ;
2022-07-30 08:30:30 -03:00
if ( auto result = open_file ( open_path . value ( ) ) ; result . is_error ( ) )
show_error ( " Failed to open font " sv , result . error ( ) ) ;
2021-04-06 13:04:21 -03:00
} ) ;
2022-07-04 23:22:06 -03:00
2021-04-10 14:40:59 -03:00
m_save_action = GUI : : CommonActions : : make_save_action ( [ & ] ( auto & ) {
2021-08-26 18:25:02 -03:00
if ( m_path . is_empty ( ) )
2022-07-30 08:30:30 -03:00
return m_save_as_action - > activate ( ) ;
if ( auto result = save_file ( m_path ) ; result . is_error ( ) )
show_error ( " Failed to save font " sv , result . error ( ) ) ;
2021-04-06 13:04:21 -03:00
} ) ;
2022-07-04 23:22:06 -03:00
2021-04-10 14:40:59 -03:00
m_save_as_action = GUI : : CommonActions : : make_save_as_action ( [ & ] ( auto & ) {
2021-08-26 18:25:02 -03:00
LexicalPath lexical_path ( m_path . is_empty ( ) ? " Untitled.font " : m_path ) ;
2021-04-10 14:40:59 -03:00
Optional < String > save_path = GUI : : FilePicker : : get_save_filepath ( window ( ) , lexical_path . title ( ) , lexical_path . extension ( ) ) ;
if ( ! save_path . has_value ( ) )
return ;
2022-07-30 08:30:30 -03:00
if ( auto result = save_file ( save_path . value ( ) ) ; result . is_error ( ) )
show_error ( " Failed to save font " sv , result . error ( ) ) ;
2021-04-10 14:40:59 -03:00
} ) ;
2022-07-04 23:22:06 -03:00
2021-04-10 14:40:59 -03:00
m_cut_action = GUI : : CommonActions : : make_cut_action ( [ & ] ( auto & ) {
2022-07-30 08:30:30 -03:00
if ( auto result = cut_selected_glyphs ( ) ; result . is_error ( ) )
show_error ( " Failed to cut selection " sv , result . error ( ) ) ;
2021-04-06 13:04:21 -03:00
} ) ;
2022-07-04 23:22:06 -03:00
2021-04-10 14:40:59 -03:00
m_copy_action = GUI : : CommonActions : : make_copy_action ( [ & ] ( auto & ) {
2022-07-30 08:30:30 -03:00
if ( auto result = copy_selected_glyphs ( ) ; result . is_error ( ) )
show_error ( " Failed to copy selection " sv , result . error ( ) ) ;
2021-04-06 13:04:21 -03:00
} ) ;
2022-07-04 23:22:06 -03:00
2021-04-10 14:40:59 -03:00
m_paste_action = GUI : : CommonActions : : make_paste_action ( [ & ] ( auto & ) {
2022-01-04 14:24:06 -03:00
paste_glyphs ( ) ;
2021-04-06 13:04:21 -03:00
} ) ;
2021-11-20 11:22:01 -03:00
m_paste_action - > set_enabled ( GUI : : Clipboard : : the ( ) . fetch_mime_type ( ) = = " glyph/x-fonteditor " ) ;
2022-07-04 23:22:06 -03:00
GUI : : Clipboard : : the ( ) . on_change = [ & ] ( String const & data_type ) {
m_paste_action - > set_enabled ( data_type = = " glyph/x-fonteditor " ) ;
} ;
2021-09-22 10:25:25 -03:00
m_delete_action = GUI : : CommonActions : : make_delete_action ( [ this ] ( auto & ) {
2022-01-04 14:24:06 -03:00
delete_selected_glyphs ( ) ;
2021-04-06 13:04:21 -03:00
} ) ;
2022-07-04 23:22:06 -03:00
2021-04-22 15:12:53 -03:00
m_undo_action = GUI : : CommonActions : : make_undo_action ( [ & ] ( auto & ) {
undo ( ) ;
} ) ;
2022-07-04 23:22:06 -03:00
m_undo_action - > set_enabled ( false ) ;
2021-04-22 15:12:53 -03:00
m_redo_action = GUI : : CommonActions : : make_redo_action ( [ & ] ( auto & ) {
redo ( ) ;
} ) ;
2022-07-04 23:22:06 -03:00
m_redo_action - > set_enabled ( false ) ;
2022-03-19 14:29:55 -03:00
m_select_all_action = GUI : : CommonActions : : make_select_all_action ( [ this ] ( auto & ) {
m_glyph_map_widget - > set_selection ( m_range . first , m_range . last - m_range . first + 1 ) ;
m_glyph_map_widget - > update ( ) ;
auto selection = m_glyph_map_widget - > selection ( ) . normalized ( ) ;
m_undo_selection - > set_start ( selection . start ( ) ) ;
m_undo_selection - > set_size ( selection . size ( ) ) ;
} ) ;
2022-07-11 14:32:29 -03:00
m_open_preview_action = GUI : : Action : : create ( " &Preview Font " , { Mod_Ctrl , Key_P } , TRY ( Gfx : : Bitmap : : try_load_from_file ( " /res/icons/16x16/find.png " sv ) ) , [ & ] ( auto & ) {
2022-07-04 23:41:05 -03:00
if ( ! m_font_preview_window ) {
if ( auto maybe_window = create_preview_window ( ) ; maybe_window . is_error ( ) )
2022-07-30 08:29:04 -03:00
show_error ( " Failed to create preview window " sv , maybe_window . error ( ) ) ;
2022-07-04 23:41:05 -03:00
else
m_font_preview_window = maybe_window . release_value ( ) ;
}
if ( m_font_preview_window )
m_font_preview_window - > show ( ) ;
2021-04-06 13:04:21 -03:00
} ) ;
2021-04-22 14:53:17 -03:00
m_open_preview_action - > set_status_tip ( " Preview the current font " ) ;
2022-02-16 12:14:06 -03:00
2022-07-11 14:32:29 -03:00
bool show_metadata = Config : : read_bool ( " FontEditor " sv , " Layout " sv , " ShowMetadata " sv , true ) ;
2022-02-16 12:14:06 -03:00
set_show_font_metadata ( show_metadata ) ;
2021-04-22 14:53:17 -03:00
m_show_metadata_action = GUI : : Action : : create_checkable ( " Font &Metadata " , { Mod_Ctrl , Key_M } , [ & ] ( auto & action ) {
2021-04-10 14:40:59 -03:00
set_show_font_metadata ( action . is_checked ( ) ) ;
2022-07-11 14:32:29 -03:00
Config : : write_bool ( " FontEditor " sv , " Layout " sv , " ShowMetadata " sv , action . is_checked ( ) ) ;
2021-04-10 14:40:59 -03:00
} ) ;
2022-02-16 12:14:06 -03:00
m_show_metadata_action - > set_checked ( show_metadata ) ;
2021-04-22 14:53:17 -03:00
m_show_metadata_action - > set_status_tip ( " Show or hide metadata about the current font " ) ;
2022-02-16 12:14:06 -03:00
2022-07-11 14:32:29 -03:00
bool show_unicode_blocks = Config : : read_bool ( " FontEditor " sv , " Layout " sv , " ShowUnicodeBlocks " sv , true ) ;
2022-02-16 12:14:06 -03:00
set_show_unicode_blocks ( show_unicode_blocks ) ;
2022-02-13 17:18:39 -03:00
m_show_unicode_blocks_action = GUI : : Action : : create_checkable ( " &Unicode Blocks " , { Mod_Ctrl , Key_U } , [ & ] ( auto & action ) {
set_show_unicode_blocks ( action . is_checked ( ) ) ;
2022-07-11 14:32:29 -03:00
Config : : write_bool ( " FontEditor " sv , " Layout " sv , " ShowUnicodeBlocks " sv , action . is_checked ( ) ) ;
2022-02-13 17:18:39 -03:00
} ) ;
2022-02-16 12:14:06 -03:00
m_show_unicode_blocks_action - > set_checked ( show_unicode_blocks ) ;
2022-02-13 17:18:39 -03:00
m_show_unicode_blocks_action - > set_status_tip ( " Show or hide the Unicode block list " ) ;
2022-02-16 12:14:06 -03:00
2022-08-02 10:30:58 -03:00
bool highlight_modifications = Config : : read_bool ( " FontEditor " sv , " Display " sv , " HighlightModifications " sv , true ) ;
set_highlight_modifications ( highlight_modifications ) ;
m_highlight_modifications_action = GUI : : Action : : create_checkable ( " &Highlight Modifications " , { Mod_Ctrl , Key_H } , [ & ] ( auto & action ) {
set_highlight_modifications ( action . is_checked ( ) ) ;
Config : : write_bool ( " FontEditor " sv , " Display " sv , " HighlightModifications " sv , action . is_checked ( ) ) ;
} ) ;
m_highlight_modifications_action - > set_checked ( highlight_modifications ) ;
m_highlight_modifications_action - > set_status_tip ( " Show or hide highlights on modified glyphs. (Green = New, Blue = Modified, Red = Deleted) " ) ;
2022-07-11 14:32:29 -03:00
m_go_to_glyph_action = GUI : : Action : : create ( " &Go to Glyph... " , { Mod_Ctrl , Key_G } , TRY ( Gfx : : Bitmap : : try_load_from_file ( " /res/icons/16x16/go-to.png " sv ) ) , [ & ] ( auto & ) {
2021-09-09 08:43:19 -03:00
String input ;
2022-07-11 14:32:29 -03:00
if ( GUI : : InputBox : : show ( window ( ) , input , " Hexadecimal: " sv , " Go to glyph " sv ) = = GUI : : InputBox : : ExecResult : : OK & & ! input . is_empty ( ) ) {
2022-02-13 17:18:39 -03:00
auto maybe_code_point = AK : : StringUtils : : convert_to_uint_from_hex ( input ) ;
if ( ! maybe_code_point . has_value ( ) )
return ;
auto code_point = maybe_code_point . value ( ) ;
code_point = clamp ( code_point , m_range . first , m_range . last ) ;
2021-09-09 08:43:19 -03:00
m_glyph_map_widget - > set_focus ( true ) ;
2022-01-04 14:24:06 -03:00
m_glyph_map_widget - > set_active_glyph ( code_point ) ;
2021-09-09 08:43:19 -03:00
m_glyph_map_widget - > scroll_to_glyph ( code_point ) ;
}
} ) ;
m_go_to_glyph_action - > set_status_tip ( " Go to the specified code point " ) ;
2022-07-04 23:22:06 -03:00
2022-07-11 14:32:29 -03:00
m_previous_glyph_action = GUI : : Action : : create ( " Pre&vious Glyph " , { Mod_Alt , Key_Left } , TRY ( Gfx : : Bitmap : : try_load_from_file ( " /res/icons/16x16/go-back.png " sv ) ) , [ & ] ( auto & ) {
2022-01-11 17:50:59 -03:00
m_glyph_map_widget - > select_previous_existing_glyph ( ) ;
2021-09-09 08:43:19 -03:00
} ) ;
m_previous_glyph_action - > set_status_tip ( " Seek the previous visible glyph " ) ;
2022-07-04 23:22:06 -03:00
2022-07-11 14:32:29 -03:00
m_next_glyph_action = GUI : : Action : : create ( " &Next Glyph " , { Mod_Alt , Key_Right } , TRY ( Gfx : : Bitmap : : try_load_from_file ( " /res/icons/16x16/go-forward.png " sv ) ) , [ & ] ( auto & ) {
2022-01-11 17:50:59 -03:00
m_glyph_map_widget - > select_next_existing_glyph ( ) ;
2021-09-09 08:43:19 -03:00
} ) ;
m_next_glyph_action - > set_status_tip ( " Seek the next visible glyph " ) ;
2021-04-06 13:04:21 -03:00
2022-07-11 14:32:29 -03:00
i32 scale = Config : : read_i32 ( " FontEditor " sv , " GlyphEditor " sv , " Scale " sv , 10 ) ;
2022-07-04 23:22:06 -03:00
set_scale ( scale ) ;
2021-11-14 10:26:10 -03:00
m_scale_five_action = GUI : : Action : : create_checkable ( " 500% " , { Mod_Ctrl , Key_1 } , [ this ] ( auto & ) {
set_scale_and_save ( 5 ) ;
2021-04-22 15:04:19 -03:00
} ) ;
2021-11-14 10:26:10 -03:00
m_scale_five_action - > set_checked ( scale = = 5 ) ;
2021-04-22 15:04:19 -03:00
m_scale_five_action - > set_status_tip ( " Scale the editor in proportion to the current font " ) ;
2021-11-14 10:26:10 -03:00
m_scale_ten_action = GUI : : Action : : create_checkable ( " 1000% " , { Mod_Ctrl , Key_2 } , [ this ] ( auto & ) {
set_scale_and_save ( 10 ) ;
2021-04-22 15:04:19 -03:00
} ) ;
2021-11-14 10:26:10 -03:00
m_scale_ten_action - > set_checked ( scale = = 10 ) ;
2021-04-22 15:04:19 -03:00
m_scale_ten_action - > set_status_tip ( " Scale the editor in proportion to the current font " ) ;
2021-11-14 10:26:10 -03:00
m_scale_fifteen_action = GUI : : Action : : create_checkable ( " 1500% " , { Mod_Ctrl , Key_3 } , [ this ] ( auto & ) {
set_scale_and_save ( 15 ) ;
2021-04-22 15:04:19 -03:00
} ) ;
2021-11-14 10:26:10 -03:00
m_scale_fifteen_action - > set_checked ( scale = = 15 ) ;
2021-04-22 15:04:19 -03:00
m_scale_fifteen_action - > set_status_tip ( " Scale the editor in proportion to the current font " ) ;
m_glyph_editor_scale_actions . add_action ( * m_scale_five_action ) ;
m_glyph_editor_scale_actions . add_action ( * m_scale_ten_action ) ;
m_glyph_editor_scale_actions . add_action ( * m_scale_fifteen_action ) ;
m_glyph_editor_scale_actions . set_exclusive ( true ) ;
2022-07-11 14:32:29 -03:00
m_paint_glyph_action = GUI : : Action : : create_checkable ( " Paint Glyph " , { Mod_Ctrl , KeyCode : : Key_J } , TRY ( Gfx : : Bitmap : : try_load_from_file ( " /res/icons/pixelpaint/pen.png " sv ) ) , [ & ] ( auto & ) {
2021-11-29 11:26:24 -03:00
m_glyph_editor_widget - > set_mode ( GlyphEditorWidget : : Paint ) ;
} ) ;
m_paint_glyph_action - > set_checked ( true ) ;
2021-04-22 15:15:21 -03:00
2022-07-11 14:32:29 -03:00
m_move_glyph_action = GUI : : Action : : create_checkable ( " Move Glyph " , { Mod_Ctrl , KeyCode : : Key_K } , TRY ( Gfx : : Bitmap : : try_load_from_file ( " /res/icons/16x16/selection-move.png " sv ) ) , [ & ] ( auto & ) {
2021-11-29 11:26:24 -03:00
m_glyph_editor_widget - > set_mode ( GlyphEditorWidget : : Move ) ;
} ) ;
2021-11-19 22:38:24 -03:00
2021-11-29 11:26:24 -03:00
m_glyph_tool_actions . add_action ( * m_paint_glyph_action ) ;
2022-07-04 23:22:06 -03:00
m_glyph_tool_actions . add_action ( * m_move_glyph_action ) ;
2021-11-29 11:26:24 -03:00
m_glyph_tool_actions . set_exclusive ( true ) ;
2022-01-03 07:19:05 -03:00
m_rotate_counterclockwise_action = GUI : : CommonActions : : make_rotate_counterclockwise_action ( [ & ] ( auto & ) {
2021-11-29 11:26:24 -03:00
m_glyph_editor_widget - > rotate_90 ( GlyphEditorWidget : : Counterclockwise ) ;
} ) ;
2021-11-19 22:38:24 -03:00
2022-01-03 07:19:05 -03:00
m_rotate_clockwise_action = GUI : : CommonActions : : make_rotate_clockwise_action ( [ & ] ( auto & ) {
2021-11-29 11:26:24 -03:00
m_glyph_editor_widget - > rotate_90 ( GlyphEditorWidget : : Clockwise ) ;
} ) ;
2022-07-11 14:32:29 -03:00
m_flip_horizontal_action = GUI : : Action : : create ( " Flip Horizontally " , { Mod_Ctrl | Mod_Shift , Key_Q } , TRY ( Gfx : : Bitmap : : try_load_from_file ( " /res/icons/16x16/edit-flip-horizontal.png " sv ) ) , [ & ] ( auto & ) {
2021-11-19 22:38:24 -03:00
m_glyph_editor_widget - > flip_horizontally ( ) ;
2021-11-29 11:26:24 -03:00
} ) ;
2021-11-19 22:38:24 -03:00
2022-07-11 14:32:29 -03:00
m_flip_vertical_action = GUI : : Action : : create ( " Flip Vertically " , { Mod_Ctrl | Mod_Shift , Key_W } , TRY ( Gfx : : Bitmap : : try_load_from_file ( " /res/icons/16x16/edit-flip-vertical.png " sv ) ) , [ & ] ( auto & ) {
2021-11-29 11:26:24 -03:00
m_glyph_editor_widget - > flip_vertically ( ) ;
} ) ;
2022-07-11 14:32:29 -03:00
m_copy_text_action = GUI : : Action : : create ( " Copy as Te&xt " , { Mod_Ctrl , Key_T } , TRY ( Gfx : : Bitmap : : try_load_from_file ( " /res/icons/16x16/edit-copy.png " sv ) ) , [ & ] ( auto & ) {
2022-03-19 14:29:55 -03:00
StringBuilder builder ;
auto selection = m_glyph_map_widget - > selection ( ) . normalized ( ) ;
for ( auto code_point = selection . start ( ) ; code_point < selection . start ( ) + selection . size ( ) ; + + code_point ) {
if ( ! m_glyph_map_widget - > font ( ) . contains_glyph ( code_point ) )
continue ;
builder . append_code_point ( code_point ) ;
}
GUI : : Clipboard : : the ( ) . set_plain_text ( builder . to_string ( ) ) ;
2021-11-29 11:26:24 -03:00
} ) ;
2022-03-19 14:29:55 -03:00
m_copy_text_action - > set_status_tip ( " Copy to clipboard as text " ) ;
2021-11-29 11:26:24 -03:00
2022-07-04 23:22:06 -03:00
return { } ;
}
2021-11-19 23:00:58 -03:00
2022-07-05 07:37:06 -03:00
ErrorOr < void > MainWidget : : create_toolbars ( )
2022-07-04 23:22:06 -03:00
{
auto & toolbar = * find_descendant_of_type_named < GUI : : Toolbar > ( " toolbar " ) ;
( void ) TRY ( toolbar . try_add_action ( * m_new_action ) ) ;
( void ) TRY ( toolbar . try_add_action ( * m_open_action ) ) ;
( void ) TRY ( toolbar . try_add_action ( * m_save_action ) ) ;
TRY ( toolbar . try_add_separator ( ) ) ;
( void ) TRY ( toolbar . try_add_action ( * m_cut_action ) ) ;
( void ) TRY ( toolbar . try_add_action ( * m_copy_action ) ) ;
( void ) TRY ( toolbar . try_add_action ( * m_paste_action ) ) ;
( void ) TRY ( toolbar . try_add_action ( * m_delete_action ) ) ;
TRY ( toolbar . try_add_separator ( ) ) ;
( void ) TRY ( toolbar . try_add_action ( * m_undo_action ) ) ;
( void ) TRY ( toolbar . try_add_action ( * m_redo_action ) ) ;
TRY ( toolbar . try_add_separator ( ) ) ;
( void ) TRY ( toolbar . try_add_action ( * m_open_preview_action ) ) ;
TRY ( toolbar . try_add_separator ( ) ) ;
( void ) TRY ( toolbar . try_add_action ( * m_previous_glyph_action ) ) ;
( void ) TRY ( toolbar . try_add_action ( * m_next_glyph_action ) ) ;
( void ) TRY ( toolbar . try_add_action ( * m_go_to_glyph_action ) ) ;
auto & glyph_transform_toolbar = * find_descendant_of_type_named < GUI : : Toolbar > ( " glyph_transform_toolbar " ) ;
( void ) TRY ( glyph_transform_toolbar . try_add_action ( * m_flip_horizontal_action ) ) ;
( void ) TRY ( glyph_transform_toolbar . try_add_action ( * m_flip_vertical_action ) ) ;
( void ) TRY ( glyph_transform_toolbar . try_add_action ( * m_rotate_counterclockwise_action ) ) ;
( void ) TRY ( glyph_transform_toolbar . try_add_action ( * m_rotate_clockwise_action ) ) ;
auto & glyph_mode_toolbar = * find_descendant_of_type_named < GUI : : Toolbar > ( " glyph_mode_toolbar " ) ;
( void ) TRY ( glyph_mode_toolbar . try_add_action ( * m_paint_glyph_action ) ) ;
( void ) TRY ( glyph_mode_toolbar . try_add_action ( * m_move_glyph_action ) ) ;
return { } ;
}
2022-07-05 07:37:06 -03:00
ErrorOr < void > MainWidget : : create_models ( )
2022-07-04 23:22:06 -03:00
{
for ( auto & it : Gfx : : font_slope_names )
TRY ( m_font_slope_list . try_append ( it . name ) ) ;
m_slope_combobox - > set_model ( GUI : : ItemListModel < String > : : create ( m_font_slope_list ) ) ;
for ( auto & it : Gfx : : font_weight_names )
TRY ( m_font_weight_list . try_append ( it . name ) ) ;
m_weight_combobox - > set_model ( GUI : : ItemListModel < String > : : create ( m_font_weight_list ) ) ;
auto unicode_blocks = Unicode : : block_display_names ( ) ;
TRY ( m_unicode_block_list . try_append ( " Show All " ) ) ;
for ( auto & block : unicode_blocks )
TRY ( m_unicode_block_list . try_append ( block . display_name ) ) ;
m_unicode_block_model = GUI : : ItemListModel < String > : : create ( m_unicode_block_list ) ;
m_filter_model = TRY ( GUI : : FilteringProxyModel : : create ( * m_unicode_block_model ) ) ;
2022-07-11 14:32:29 -03:00
m_filter_model - > set_filter_term ( " " sv ) ;
2022-07-04 23:22:06 -03:00
m_unicode_block_listview = find_descendant_of_type_named < GUI : : ListView > ( " unicode_block_listview " ) ;
m_unicode_block_listview - > on_selection_change = [ this , unicode_blocks ] {
auto index = m_unicode_block_listview - > selection ( ) . first ( ) ;
auto mapped_index = m_filter_model - > map ( index ) ;
if ( mapped_index . row ( ) > 0 )
m_range = unicode_blocks [ mapped_index . row ( ) - 1 ] . code_point_range ;
else
m_range = { 0x0000 , 0x10FFFF } ;
m_glyph_map_widget - > set_active_range ( m_range ) ;
2021-04-10 14:40:59 -03:00
} ;
2022-07-04 23:22:06 -03:00
m_unicode_block_listview - > set_model ( m_filter_model ) ;
m_unicode_block_listview - > set_activates_on_selection ( true ) ;
m_unicode_block_listview - > horizontal_scrollbar ( ) . set_visible ( false ) ;
m_unicode_block_listview - > set_cursor ( m_unicode_block_model - > index ( 0 , 0 ) , GUI : : AbstractView : : SelectionUpdate : : Set ) ;
return { } ;
}
2022-07-05 07:37:06 -03:00
ErrorOr < void > MainWidget : : create_undo_stack ( )
2022-07-04 23:22:06 -03:00
{
m_undo_stack = TRY ( try_make < GUI : : UndoStack > ( ) ) ;
m_undo_stack - > on_state_change = [ this ] {
m_undo_action - > set_enabled ( m_undo_stack - > can_undo ( ) ) ;
m_redo_action - > set_enabled ( m_undo_stack - > can_redo ( ) ) ;
if ( m_undo_stack - > is_current_modified ( ) )
did_modify_font ( ) ;
} ;
return { } ;
}
2022-07-05 07:37:06 -03:00
MainWidget : : MainWidget ( )
2022-07-04 23:22:06 -03:00
{
load_from_gml ( font_editor_window_gml ) ;
m_font_metadata_groupbox = find_descendant_of_type_named < GUI : : GroupBox > ( " font_metadata_groupbox " ) ;
m_unicode_block_container = find_descendant_of_type_named < GUI : : Widget > ( " unicode_block_container " ) ;
2019-02-02 05:05:14 -02:00
2022-07-05 06:32:22 -03:00
m_glyph_map_widget = find_descendant_of_type_named < GUI : : GlyphMapWidget > ( " glyph_map_widget " ) ;
m_glyph_editor_widget = find_descendant_of_type_named < GlyphEditorWidget > ( " glyph_editor_widget " ) ;
2021-09-22 10:25:25 -03:00
m_glyph_editor_widget - > on_glyph_altered = [ this ] ( int glyph ) {
2019-04-06 10:28:06 -03:00
m_glyph_map_widget - > update_glyph ( glyph ) ;
2021-09-22 10:25:25 -03:00
update_preview ( ) ;
2021-04-26 10:11:14 -03:00
did_modify_font ( ) ;
2019-03-06 08:52:41 -03:00
} ;
2021-08-26 13:01:52 -03:00
m_glyph_editor_widget - > on_undo_event = [ this ] {
2022-03-19 09:52:26 -03:00
reset_selection_and_push_undo ( ) ;
2021-04-22 15:12:53 -03:00
} ;
2022-07-04 23:22:06 -03:00
m_glyph_editor_width_spinbox = find_descendant_of_type_named < GUI : : SpinBox > ( " glyph_editor_width_spinbox " ) ;
m_glyph_editor_present_checkbox = find_descendant_of_type_named < GUI : : CheckBox > ( " glyph_editor_present_checkbox " ) ;
2022-01-04 14:24:06 -03:00
m_glyph_map_widget - > on_active_glyph_changed = [ this ] ( int glyph ) {
2022-03-17 09:56:02 -03:00
if ( m_undo_selection ) {
auto selection = m_glyph_map_widget - > selection ( ) . normalized ( ) ;
m_undo_selection - > set_start ( selection . start ( ) ) ;
m_undo_selection - > set_size ( selection . size ( ) ) ;
2022-03-19 09:52:26 -03:00
m_undo_selection - > set_active_glyph ( glyph ) ;
2022-03-17 09:56:02 -03:00
}
2019-02-02 05:05:14 -02:00
m_glyph_editor_widget - > set_glyph ( glyph ) ;
2021-09-21 18:24:09 -03:00
auto glyph_width = m_edited_font - > raw_glyph_width ( glyph ) ;
if ( m_edited_font - > is_fixed_width ( ) )
m_glyph_editor_present_checkbox - > set_checked ( glyph_width > 0 , GUI : : AllowCallback : : No ) ;
else
m_glyph_editor_width_spinbox - > set_value ( glyph_width , GUI : : AllowCallback : : No ) ;
2021-04-22 14:53:17 -03:00
update_statusbar ( ) ;
2021-04-06 13:04:21 -03:00
} ;
2022-03-19 14:29:55 -03:00
m_glyph_map_widget - > on_context_menu_request = [ this ] ( auto & event ) {
m_context_menu - > popup ( event . screen_position ( ) ) ;
} ;
2022-07-04 23:22:06 -03:00
m_name_textbox = find_descendant_of_type_named < GUI : : TextBox > ( " name_textbox " ) ;
2021-04-06 13:04:21 -03:00
m_name_textbox - > on_change = [ & ] {
m_edited_font - > set_name ( m_name_textbox - > text ( ) ) ;
2021-04-26 10:11:14 -03:00
did_modify_font ( ) ;
2021-04-06 13:04:21 -03:00
} ;
2022-07-04 23:22:06 -03:00
m_family_textbox = find_descendant_of_type_named < GUI : : TextBox > ( " family_textbox " ) ;
2021-04-06 13:04:21 -03:00
m_family_textbox - > on_change = [ & ] {
m_edited_font - > set_family ( m_family_textbox - > text ( ) ) ;
2021-04-26 10:11:14 -03:00
did_modify_font ( ) ;
2019-02-02 05:05:14 -02:00
} ;
2022-07-04 23:22:06 -03:00
m_fixed_width_checkbox = find_descendant_of_type_named < GUI : : CheckBox > ( " fixed_width_checkbox " ) ;
2021-09-22 10:25:25 -03:00
m_fixed_width_checkbox - > on_checked = [ this ] ( bool checked ) {
2019-05-24 12:11:42 -03:00
m_edited_font - > set_fixed_width ( checked ) ;
2022-01-04 14:24:06 -03:00
auto glyph_width = m_edited_font - > raw_glyph_width ( m_glyph_map_widget - > active_glyph ( ) ) ;
2021-04-18 15:12:52 -03:00
m_glyph_editor_width_spinbox - > set_visible ( ! checked ) ;
2021-09-21 18:24:09 -03:00
m_glyph_editor_width_spinbox - > set_value ( glyph_width , GUI : : AllowCallback : : No ) ;
2021-04-18 15:12:52 -03:00
m_glyph_editor_present_checkbox - > set_visible ( checked ) ;
2021-09-21 18:24:09 -03:00
m_glyph_editor_present_checkbox - > set_checked ( glyph_width > 0 , GUI : : AllowCallback : : No ) ;
2019-03-06 08:52:41 -03:00
m_glyph_editor_widget - > update ( ) ;
2021-09-22 10:25:25 -03:00
update_preview ( ) ;
2021-04-26 10:11:14 -03:00
did_modify_font ( ) ;
2019-03-06 08:52:41 -03:00
} ;
2021-09-22 10:25:25 -03:00
m_glyph_editor_width_spinbox - > on_change = [ this ] ( int value ) {
2022-03-19 09:52:26 -03:00
reset_selection_and_push_undo ( ) ;
2022-01-04 14:24:06 -03:00
m_edited_font - > set_glyph_width ( m_glyph_map_widget - > active_glyph ( ) , value ) ;
2019-04-09 11:29:00 -03:00
m_glyph_editor_widget - > update ( ) ;
2022-01-04 14:24:06 -03:00
m_glyph_map_widget - > update_glyph ( m_glyph_map_widget - > active_glyph ( ) ) ;
2021-09-22 10:25:25 -03:00
update_preview ( ) ;
2021-04-22 14:53:17 -03:00
update_statusbar ( ) ;
2021-04-26 10:11:14 -03:00
did_modify_font ( ) ;
2019-03-06 08:52:41 -03:00
} ;
2021-09-22 10:25:25 -03:00
m_glyph_editor_present_checkbox - > on_checked = [ this ] ( bool checked ) {
2022-03-19 09:52:26 -03:00
reset_selection_and_push_undo ( ) ;
2022-01-04 14:24:06 -03:00
m_edited_font - > set_glyph_width ( m_glyph_map_widget - > active_glyph ( ) , checked ? m_edited_font - > glyph_fixed_width ( ) : 0 ) ;
2021-04-18 15:12:52 -03:00
m_glyph_editor_widget - > update ( ) ;
2022-01-04 14:24:06 -03:00
m_glyph_map_widget - > update_glyph ( m_glyph_map_widget - > active_glyph ( ) ) ;
2021-09-22 10:25:25 -03:00
update_preview ( ) ;
2021-04-22 14:53:17 -03:00
update_statusbar ( ) ;
2021-04-26 10:11:14 -03:00
did_modify_font ( ) ;
2021-04-18 15:12:52 -03:00
} ;
2022-07-04 23:22:06 -03:00
m_weight_combobox = find_descendant_of_type_named < GUI : : ComboBox > ( " weight_combobox " ) ;
AK+Everywhere: Disallow constructing Functions from incompatible types
Previously, AK::Function would accept _any_ callable type, and try to
call it when called, first with the given set of arguments, then with
zero arguments, and if all of those failed, it would simply not call the
function and **return a value-constructed Out type**.
This lead to many, many, many hard to debug situations when someone
forgot a `const` in their lambda argument types, and many cases of
people taking zero arguments in their lambdas to ignore them.
This commit reworks the Function interface to not include any such
surprising behaviour, if your function instance is not callable with
the declared argument set of the Function, it can simply not be
assigned to that Function instance, end of story.
2021-06-05 15:34:31 -03:00
m_weight_combobox - > on_change = [ this ] ( auto & , auto & ) {
2021-09-23 21:07:34 -03:00
m_edited_font - > set_weight ( Gfx : : name_to_weight ( m_weight_combobox - > text ( ) ) ) ;
2021-04-26 10:11:14 -03:00
did_modify_font ( ) ;
2021-04-10 14:40:59 -03:00
} ;
2021-09-23 21:07:34 -03:00
2022-07-04 23:22:06 -03:00
m_slope_combobox = find_descendant_of_type_named < GUI : : ComboBox > ( " slope_combobox " ) ;
2021-09-23 21:07:34 -03:00
m_slope_combobox - > on_change = [ this ] ( auto & , auto & ) {
m_edited_font - > set_slope ( Gfx : : name_to_slope ( m_slope_combobox - > text ( ) ) ) ;
did_modify_font ( ) ;
} ;
2021-04-10 14:40:59 -03:00
2022-07-04 23:22:06 -03:00
m_presentation_spinbox = find_descendant_of_type_named < GUI : : SpinBox > ( " presentation_spinbox " ) ;
2021-09-22 10:25:25 -03:00
m_presentation_spinbox - > on_change = [ this ] ( int value ) {
2020-10-24 12:03:39 -03:00
m_edited_font - > set_presentation_size ( value ) ;
2021-09-22 10:25:25 -03:00
update_preview ( ) ;
2021-04-26 10:11:14 -03:00
did_modify_font ( ) ;
2020-10-24 12:03:39 -03:00
} ;
2022-07-04 23:22:06 -03:00
m_spacing_spinbox = find_descendant_of_type_named < GUI : : SpinBox > ( " spacing_spinbox " ) ;
2021-09-22 10:25:25 -03:00
m_spacing_spinbox - > on_change = [ this ] ( int value ) {
2019-12-30 07:40:30 -03:00
m_edited_font - > set_glyph_spacing ( value ) ;
2021-09-22 10:25:25 -03:00
update_preview ( ) ;
2021-04-26 10:11:14 -03:00
did_modify_font ( ) ;
2019-12-30 07:40:30 -03:00
} ;
2022-07-04 23:22:06 -03:00
m_baseline_spinbox = find_descendant_of_type_named < GUI : : SpinBox > ( " baseline_spinbox " ) ;
2021-09-22 10:25:25 -03:00
m_baseline_spinbox - > on_change = [ this ] ( int value ) {
2020-09-19 13:01:32 -03:00
m_edited_font - > set_baseline ( value ) ;
2020-09-20 16:45:21 -03:00
m_glyph_editor_widget - > update ( ) ;
2021-09-22 10:25:25 -03:00
update_preview ( ) ;
2021-04-26 10:11:14 -03:00
did_modify_font ( ) ;
2020-09-19 13:01:32 -03:00
} ;
2022-07-04 23:22:06 -03:00
m_mean_line_spinbox = find_descendant_of_type_named < GUI : : SpinBox > ( " mean_line_spinbox " ) ;
2021-09-22 10:25:25 -03:00
m_mean_line_spinbox - > on_change = [ this ] ( int value ) {
2020-10-05 12:19:37 -03:00
m_edited_font - > set_mean_line ( value ) ;
m_glyph_editor_widget - > update ( ) ;
2021-09-22 10:25:25 -03:00
update_preview ( ) ;
2021-04-26 10:11:14 -03:00
did_modify_font ( ) ;
2020-10-05 12:19:37 -03:00
} ;
2022-07-04 23:22:06 -03:00
m_search_textbox = find_descendant_of_type_named < GUI : : TextBox > ( " search_textbox " ) ;
2022-02-16 12:12:46 -03:00
m_search_textbox - > on_return_pressed = [ this ] {
if ( ! m_unicode_block_listview - > selection ( ) . is_empty ( ) )
m_unicode_block_listview - > activate_selected ( ) ;
} ;
m_search_textbox - > on_down_pressed = [ this ] {
m_unicode_block_listview - > move_cursor ( GUI : : AbstractView : : CursorMovement : : Down , GUI : : AbstractView : : SelectionUpdate : : Set ) ;
} ;
m_search_textbox - > on_up_pressed = [ this ] {
m_unicode_block_listview - > move_cursor ( GUI : : AbstractView : : CursorMovement : : Up , GUI : : AbstractView : : SelectionUpdate : : Set ) ;
} ;
m_search_textbox - > on_change = [ this ] {
m_filter_model - > set_filter_term ( m_search_textbox - > text ( ) ) ;
if ( m_filter_model - > row_count ( ) ! = 0 )
m_unicode_block_listview - > set_cursor ( m_filter_model - > index ( 0 , 0 ) , GUI : : AbstractView : : SelectionUpdate : : Set ) ;
} ;
2022-07-04 23:22:06 -03:00
m_statusbar = find_descendant_of_type_named < GUI : : Statusbar > ( " statusbar " ) ;
2021-09-22 10:25:25 -03:00
GUI : : Application : : the ( ) - > on_action_enter = [ this ] ( GUI : : Action & action ) {
2021-04-22 14:53:17 -03:00
auto text = action . status_tip ( ) ;
if ( text . is_empty ( ) )
text = Gfx : : parse_ampersand_string ( action . text ( ) ) ;
2021-09-22 10:25:25 -03:00
m_statusbar - > set_override_text ( move ( text ) ) ;
2021-04-22 14:53:17 -03:00
} ;
2021-09-22 10:25:25 -03:00
GUI : : Application : : the ( ) - > on_action_leave = [ this ] ( GUI : : Action & ) {
m_statusbar - > set_override_text ( { } ) ;
2021-04-22 14:53:17 -03:00
} ;
2019-02-02 05:05:14 -02:00
}
2022-07-05 07:37:06 -03:00
ErrorOr < void > MainWidget : : initialize ( String const & path , RefPtr < Gfx : : BitmapFont > & & edited_font )
2021-04-06 13:04:21 -03:00
{
if ( m_edited_font = = edited_font )
2022-07-04 23:22:06 -03:00
return { } ;
2022-07-30 08:25:39 -03:00
auto selection = m_glyph_map_widget - > selection ( ) . normalized ( ) ;
2022-08-02 10:08:31 -03:00
m_undo_selection = TRY ( try_make_ref_counted < UndoSelection > ( selection . start ( ) , selection . size ( ) , m_glyph_map_widget - > active_glyph ( ) , * edited_font , * m_glyph_map_widget ) ) ;
2022-07-30 08:25:39 -03:00
m_undo_stack - > clear ( ) ;
2021-04-06 13:04:21 -03:00
m_path = path ;
m_edited_font = edited_font ;
2022-07-04 23:41:05 -03:00
if ( m_preview_label )
m_preview_label - > set_font ( * m_edited_font ) ;
2022-01-09 14:29:06 -03:00
m_glyph_map_widget - > set_font ( * m_edited_font ) ;
2022-07-05 06:53:36 -03:00
m_glyph_editor_widget - > set_font ( * m_edited_font ) ;
2022-07-05 06:32:22 -03:00
m_glyph_editor_widget - > set_fixed_size ( m_glyph_editor_widget - > preferred_width ( ) , m_glyph_editor_widget - > preferred_height ( ) ) ;
2021-09-21 18:24:09 -03:00
2021-04-18 15:12:52 -03:00
m_glyph_editor_width_spinbox - > set_visible ( ! m_edited_font - > is_fixed_width ( ) ) ;
2021-09-21 18:24:09 -03:00
m_glyph_editor_width_spinbox - > set_max ( m_edited_font - > max_glyph_width ( ) , GUI : : AllowCallback : : No ) ;
2022-01-04 14:24:06 -03:00
m_glyph_editor_width_spinbox - > set_value ( m_edited_font - > raw_glyph_width ( m_glyph_map_widget - > active_glyph ( ) ) , GUI : : AllowCallback : : No ) ;
2021-09-21 18:24:09 -03:00
2021-04-18 15:12:52 -03:00
m_glyph_editor_present_checkbox - > set_visible ( m_edited_font - > is_fixed_width ( ) ) ;
2022-01-04 14:24:06 -03:00
m_glyph_editor_present_checkbox - > set_checked ( m_edited_font - > contains_raw_glyph ( m_glyph_map_widget - > active_glyph ( ) ) , GUI : : AllowCallback : : No ) ;
2021-09-21 18:24:09 -03:00
m_fixed_width_checkbox - > set_checked ( m_edited_font - > is_fixed_width ( ) , GUI : : AllowCallback : : No ) ;
2021-04-06 13:04:21 -03:00
2021-09-21 18:24:09 -03:00
m_name_textbox - > set_text ( m_edited_font - > name ( ) , GUI : : AllowCallback : : No ) ;
m_family_textbox - > set_text ( m_edited_font - > family ( ) , GUI : : AllowCallback : : No ) ;
2021-04-06 13:04:21 -03:00
2021-09-21 18:24:09 -03:00
m_presentation_spinbox - > set_value ( m_edited_font - > presentation_size ( ) , GUI : : AllowCallback : : No ) ;
m_spacing_spinbox - > set_value ( m_edited_font - > glyph_spacing ( ) , GUI : : AllowCallback : : No ) ;
2021-04-22 15:20:57 -03:00
2021-09-21 18:24:09 -03:00
m_mean_line_spinbox - > set_range ( 0 , max ( m_edited_font - > glyph_height ( ) - 2 , 0 ) , GUI : : AllowCallback : : No ) ;
m_baseline_spinbox - > set_range ( 0 , max ( m_edited_font - > glyph_height ( ) - 2 , 0 ) , GUI : : AllowCallback : : No ) ;
m_mean_line_spinbox - > set_value ( m_edited_font - > mean_line ( ) , GUI : : AllowCallback : : No ) ;
m_baseline_spinbox - > set_value ( m_edited_font - > baseline ( ) , GUI : : AllowCallback : : No ) ;
2021-04-06 13:04:21 -03:00
2021-04-10 14:40:59 -03:00
int i = 0 ;
2021-09-23 21:07:34 -03:00
for ( auto & it : Gfx : : font_weight_names ) {
if ( it . style = = m_edited_font - > weight ( ) ) {
2021-11-29 16:43:02 -03:00
m_weight_combobox - > set_selected_index ( i , GUI : : AllowCallback : : No ) ;
2021-04-10 14:40:59 -03:00
break ;
}
i + + ;
}
2021-09-23 21:07:34 -03:00
i = 0 ;
for ( auto & it : Gfx : : font_slope_names ) {
if ( it . style = = m_edited_font - > slope ( ) ) {
2021-11-29 16:43:02 -03:00
m_slope_combobox - > set_selected_index ( i , GUI : : AllowCallback : : No ) ;
2021-09-23 21:07:34 -03:00
break ;
}
i + + ;
}
2021-04-10 14:40:59 -03:00
2022-07-04 23:22:06 -03:00
update_statusbar ( ) ;
2021-08-30 15:12:48 -03:00
deferred_invoke ( [ this ] {
2022-01-16 12:32:52 -03:00
auto glyph = m_glyph_map_widget - > active_glyph ( ) ;
2021-04-10 14:40:59 -03:00
m_glyph_map_widget - > set_focus ( true ) ;
2022-01-16 12:32:52 -03:00
m_glyph_map_widget - > scroll_to_glyph ( glyph ) ;
m_glyph_editor_widget - > set_glyph ( glyph ) ;
2022-07-30 08:25:39 -03:00
VERIFY ( window ( ) ) ;
window ( ) - > set_modified ( false ) ;
2021-04-26 10:11:14 -03:00
update_title ( ) ;
2021-04-10 14:40:59 -03:00
} ) ;
2021-04-07 13:05:02 -03:00
2022-07-04 23:22:06 -03:00
return { } ;
2021-04-06 13:04:21 -03:00
}
2022-07-05 07:37:06 -03:00
ErrorOr < void > MainWidget : : initialize_menubar ( GUI : : Window & window )
2021-04-10 14:40:59 -03:00
{
2022-07-04 23:22:06 -03:00
auto file_menu = TRY ( window . try_add_menu ( " &File " ) ) ;
TRY ( file_menu - > try_add_action ( * m_new_action ) ) ;
TRY ( file_menu - > try_add_action ( * m_open_action ) ) ;
TRY ( file_menu - > try_add_action ( * m_save_action ) ) ;
TRY ( file_menu - > try_add_action ( * m_save_as_action ) ) ;
TRY ( file_menu - > try_add_separator ( ) ) ;
TRY ( file_menu - > try_add_action ( GUI : : CommonActions : : make_quit_action ( [ this ] ( auto & ) {
2021-04-26 10:11:14 -03:00
if ( ! request_close ( ) )
return ;
2021-04-10 14:40:59 -03:00
GUI : : Application : : the ( ) - > quit ( ) ;
2022-07-04 23:22:06 -03:00
} ) ) ) ;
auto edit_menu = TRY ( window . try_add_menu ( " &Edit " ) ) ;
TRY ( edit_menu - > try_add_action ( * m_undo_action ) ) ;
TRY ( edit_menu - > try_add_action ( * m_redo_action ) ) ;
TRY ( edit_menu - > try_add_separator ( ) ) ;
TRY ( edit_menu - > try_add_action ( * m_cut_action ) ) ;
TRY ( edit_menu - > try_add_action ( * m_copy_action ) ) ;
TRY ( edit_menu - > try_add_action ( * m_paste_action ) ) ;
TRY ( edit_menu - > try_add_action ( * m_delete_action ) ) ;
TRY ( edit_menu - > try_add_separator ( ) ) ;
TRY ( edit_menu - > try_add_action ( * m_select_all_action ) ) ;
TRY ( edit_menu - > try_add_separator ( ) ) ;
TRY ( edit_menu - > try_add_action ( * m_copy_text_action ) ) ;
2022-07-05 06:48:40 -03:00
m_context_menu = edit_menu ;
2022-07-04 23:22:06 -03:00
auto go_menu = TRY ( window . try_add_menu ( " &Go " ) ) ;
TRY ( go_menu - > try_add_action ( * m_previous_glyph_action ) ) ;
TRY ( go_menu - > try_add_action ( * m_next_glyph_action ) ) ;
TRY ( go_menu - > try_add_action ( * m_go_to_glyph_action ) ) ;
auto view_menu = TRY ( window . try_add_menu ( " &View " ) ) ;
TRY ( view_menu - > try_add_action ( * m_open_preview_action ) ) ;
TRY ( view_menu - > try_add_separator ( ) ) ;
TRY ( view_menu - > try_add_action ( * m_show_metadata_action ) ) ;
TRY ( view_menu - > try_add_action ( * m_show_unicode_blocks_action ) ) ;
TRY ( view_menu - > try_add_separator ( ) ) ;
2022-08-02 10:30:58 -03:00
TRY ( view_menu - > try_add_action ( * m_highlight_modifications_action ) ) ;
TRY ( view_menu - > try_add_separator ( ) ) ;
2022-07-04 23:22:06 -03:00
auto scale_menu = TRY ( view_menu - > try_add_submenu ( " &Scale " ) ) ;
TRY ( scale_menu - > try_add_action ( * m_scale_five_action ) ) ;
TRY ( scale_menu - > try_add_action ( * m_scale_ten_action ) ) ;
TRY ( scale_menu - > try_add_action ( * m_scale_fifteen_action ) ) ;
auto help_menu = TRY ( window . try_add_menu ( " &Help " ) ) ;
TRY ( help_menu - > try_add_action ( GUI : : CommonActions : : make_help_action ( [ ] ( auto & ) {
2021-04-10 14:40:59 -03:00
Desktop : : Launcher : : open ( URL : : create_with_file_protocol ( " /usr/share/man/man1/FontEditor.md " ) , " /bin/Help " ) ;
2022-07-04 23:22:06 -03:00
} ) ) ) ;
2022-07-11 14:32:29 -03:00
TRY ( help_menu - > try_add_action ( GUI : : CommonActions : : make_about_action ( " Font Editor " , TRY ( GUI : : Icon : : try_create_default_icon ( " app-font-editor " sv ) ) , & window ) ) ) ;
2022-07-04 23:22:06 -03:00
return { } ;
2021-04-10 14:40:59 -03:00
}
2022-07-30 08:30:30 -03:00
ErrorOr < void > MainWidget : : save_file ( String const & path )
2020-07-10 22:20:39 -03:00
{
2022-07-30 08:30:30 -03:00
auto masked_font = TRY ( m_edited_font - > masked_character_set ( ) ) ;
TRY ( masked_font - > write_to_file ( path ) ) ;
2020-07-10 22:20:39 -03:00
m_path = path ;
2022-01-04 14:04:28 -03:00
m_undo_stack - > set_current_unmodified ( ) ;
2021-08-26 18:25:02 -03:00
window ( ) - > set_modified ( false ) ;
2021-04-26 10:11:14 -03:00
update_title ( ) ;
2022-07-30 08:30:30 -03:00
return { } ;
2020-07-10 22:20:39 -03:00
}
2021-04-06 13:04:21 -03:00
2022-07-05 07:37:06 -03:00
void MainWidget : : set_show_font_metadata ( bool show )
2021-04-06 13:04:21 -03:00
{
if ( m_font_metadata = = show )
return ;
m_font_metadata = show ;
m_font_metadata_groupbox - > set_visible ( m_font_metadata ) ;
}
2021-04-22 15:12:53 -03:00
2022-07-05 07:37:06 -03:00
void MainWidget : : set_show_unicode_blocks ( bool show )
2022-02-13 17:18:39 -03:00
{
if ( m_unicode_blocks = = show )
return ;
m_unicode_blocks = show ;
2022-02-16 12:14:06 -03:00
m_unicode_block_container - > set_visible ( m_unicode_blocks ) ;
2022-02-13 17:18:39 -03:00
}
2022-08-02 10:30:58 -03:00
void MainWidget : : set_highlight_modifications ( bool highlight_modifications )
{
m_glyph_map_widget - > set_highlight_modifications ( highlight_modifications ) ;
}
2022-07-30 08:30:30 -03:00
ErrorOr < void > MainWidget : : open_file ( String const & path )
2021-10-13 17:13:48 -03:00
{
2022-07-30 08:30:30 -03:00
auto unmasked_font = TRY ( TRY ( Gfx : : BitmapFont : : try_load_from_file ( path ) ) - > unmasked_character_set ( ) ) ;
TRY ( initialize ( path , move ( unmasked_font ) ) ) ;
return { } ;
2021-10-13 17:13:48 -03:00
}
2022-07-05 07:37:06 -03:00
void MainWidget : : push_undo ( )
2022-07-05 06:28:39 -03:00
{
auto maybe_state = m_undo_selection - > save_state ( ) ;
2022-07-30 08:29:04 -03:00
if ( maybe_state . is_error ( ) )
return show_error ( " Failed to save undo state " sv , maybe_state . error ( ) ) ;
auto maybe_command = try_make < SelectionUndoCommand > ( * m_undo_selection , move ( maybe_state . value ( ) ) ) ;
if ( maybe_command . is_error ( ) )
return show_error ( " Failed to make undo command " sv , maybe_command . error ( ) ) ;
if ( auto maybe_push = m_undo_stack - > try_push ( move ( maybe_command . value ( ) ) ) ; maybe_push . is_error ( ) )
show_error ( " Failed to push undo stack " sv , maybe_push . error ( ) ) ;
2022-07-05 06:28:39 -03:00
}
2022-07-05 07:37:06 -03:00
void MainWidget : : reset_selection_and_push_undo ( )
2022-03-19 09:52:26 -03:00
{
auto selection = m_glyph_map_widget - > selection ( ) . normalized ( ) ;
if ( selection . size ( ) ! = 1 ) {
auto start = m_glyph_map_widget - > active_glyph ( ) ;
m_undo_selection - > set_start ( start ) ;
m_undo_selection - > set_size ( 1 ) ;
m_glyph_map_widget - > set_selection ( start , 1 ) ;
m_glyph_map_widget - > update ( ) ;
}
2022-07-05 06:28:39 -03:00
push_undo ( ) ;
2022-03-19 09:52:26 -03:00
}
2022-07-05 07:37:06 -03:00
void MainWidget : : undo ( )
2021-04-22 15:12:53 -03:00
{
if ( ! m_undo_stack - > can_undo ( ) )
return ;
m_undo_stack - > undo ( ) ;
2022-03-19 09:52:26 -03:00
auto glyph = m_undo_selection - > restored_active_glyph ( ) ;
2022-03-17 09:56:02 -03:00
auto glyph_width = edited_font ( ) . raw_glyph_width ( glyph ) ;
2022-03-17 10:28:45 -03:00
if ( glyph < m_range . first | | glyph > m_range . last )
2022-07-11 14:32:29 -03:00
m_search_textbox - > set_text ( " " sv ) ;
2022-03-19 09:52:26 -03:00
deferred_invoke ( [ this , glyph ] {
auto start = m_undo_selection - > restored_start ( ) ;
auto size = m_undo_selection - > restored_size ( ) ;
m_glyph_map_widget - > set_selection ( start , size , glyph ) ;
m_glyph_map_widget - > scroll_to_glyph ( glyph ) ;
m_glyph_map_widget - > set_focus ( true ) ;
} ) ;
2021-09-21 18:42:25 -03:00
if ( m_edited_font - > is_fixed_width ( ) ) {
m_glyph_editor_present_checkbox - > set_checked ( glyph_width > 0 , GUI : : AllowCallback : : No ) ;
} else {
m_glyph_editor_width_spinbox - > set_value ( glyph_width , GUI : : AllowCallback : : No ) ;
}
2021-04-22 15:12:53 -03:00
m_glyph_editor_widget - > update ( ) ;
2022-03-17 09:56:02 -03:00
m_glyph_map_widget - > update ( ) ;
2021-09-22 10:25:25 -03:00
update_preview ( ) ;
update_statusbar ( ) ;
2021-04-22 15:12:53 -03:00
}
2022-07-05 07:37:06 -03:00
void MainWidget : : redo ( )
2021-04-22 15:12:53 -03:00
{
if ( ! m_undo_stack - > can_redo ( ) )
return ;
m_undo_stack - > redo ( ) ;
2022-03-19 09:52:26 -03:00
auto glyph = m_undo_selection - > restored_active_glyph ( ) ;
2022-03-17 09:56:02 -03:00
auto glyph_width = edited_font ( ) . raw_glyph_width ( glyph ) ;
2022-03-17 10:28:45 -03:00
if ( glyph < m_range . first | | glyph > m_range . last )
2022-07-11 14:32:29 -03:00
m_search_textbox - > set_text ( " " sv ) ;
2022-03-19 09:52:26 -03:00
deferred_invoke ( [ this , glyph ] {
auto start = m_undo_selection - > restored_start ( ) ;
auto size = m_undo_selection - > restored_size ( ) ;
m_glyph_map_widget - > set_selection ( start , size , glyph ) ;
m_glyph_map_widget - > scroll_to_glyph ( glyph ) ;
m_glyph_map_widget - > set_focus ( true ) ;
} ) ;
2021-09-21 18:42:25 -03:00
if ( m_edited_font - > is_fixed_width ( ) ) {
m_glyph_editor_present_checkbox - > set_checked ( glyph_width > 0 , GUI : : AllowCallback : : No ) ;
} else {
m_glyph_editor_width_spinbox - > set_value ( glyph_width , GUI : : AllowCallback : : No ) ;
}
2021-04-22 15:12:53 -03:00
m_glyph_editor_widget - > update ( ) ;
2022-03-17 09:56:02 -03:00
m_glyph_map_widget - > update ( ) ;
2021-09-22 10:25:25 -03:00
update_preview ( ) ;
update_statusbar ( ) ;
2021-04-22 15:12:53 -03:00
}
2022-07-05 07:37:06 -03:00
bool MainWidget : : request_close ( )
2021-04-26 10:11:14 -03:00
{
2021-08-26 18:25:02 -03:00
if ( ! window ( ) - > is_modified ( ) )
2021-04-26 10:11:14 -03:00
return true ;
2022-01-04 14:04:28 -03:00
auto result = GUI : : MessageBox : : ask_about_unsaved_changes ( window ( ) , m_path , m_undo_stack - > last_unmodified_timestamp ( ) ) ;
2022-05-13 09:10:27 -03:00
if ( result = = GUI : : MessageBox : : ExecResult : : Yes ) {
2021-04-26 10:11:14 -03:00
m_save_action - > activate ( ) ;
2021-08-26 18:25:02 -03:00
if ( ! window ( ) - > is_modified ( ) )
2021-04-26 10:11:14 -03:00
return true ;
}
2022-05-13 09:10:27 -03:00
if ( result = = GUI : : MessageBox : : ExecResult : : No )
2021-04-26 10:11:14 -03:00
return true ;
return false ;
}
2022-07-05 07:37:06 -03:00
void MainWidget : : update_title ( )
2021-04-26 10:11:14 -03:00
{
StringBuilder title ;
2021-08-26 18:25:02 -03:00
if ( m_path . is_empty ( ) )
2022-07-11 14:32:29 -03:00
title . append ( " Untitled " sv ) ;
2021-08-26 18:25:02 -03:00
else
title . append ( m_path ) ;
2022-07-11 14:32:29 -03:00
title . append ( " [*] - Font Editor " sv ) ;
2021-08-26 18:25:02 -03:00
window ( ) - > set_title ( title . to_string ( ) ) ;
2021-04-26 10:11:14 -03:00
}
2022-07-05 07:37:06 -03:00
void MainWidget : : did_modify_font ( )
2021-04-26 10:11:14 -03:00
{
2021-08-26 18:25:02 -03:00
if ( ! window ( ) | | window ( ) - > is_modified ( ) )
2021-04-26 10:11:14 -03:00
return ;
2021-08-26 18:25:02 -03:00
window ( ) - > set_modified ( true ) ;
2021-04-26 10:11:14 -03:00
update_title ( ) ;
2021-04-22 15:12:53 -03:00
}
2021-09-22 10:25:25 -03:00
2022-07-05 07:37:06 -03:00
void MainWidget : : update_statusbar ( )
2021-09-22 10:25:25 -03:00
{
2022-01-04 14:24:06 -03:00
auto glyph = m_glyph_map_widget - > active_glyph ( ) ;
2021-09-22 10:25:25 -03:00
StringBuilder builder ;
builder . appendff ( " U+{:04X} ( " , glyph ) ;
2022-01-18 10:32:39 -03:00
if ( auto abbreviation = Unicode : : code_point_abbreviation ( glyph ) ; abbreviation . has_value ( ) ) {
builder . append ( * abbreviation ) ;
2021-09-22 10:25:25 -03:00
} else if ( Gfx : : get_char_bidi_class ( glyph ) = = Gfx : : BidirectionalClass : : STRONG_RTL ) {
// FIXME: This is a necessary hack, as RTL text will mess up the painting of the statusbar text.
// For now, replace RTL glyphs with U+FFFD, the replacement character.
builder . append_code_point ( 0xFFFD ) ;
} else {
builder . append_code_point ( glyph ) ;
}
2022-07-11 17:10:18 -03:00
builder . append ( ' ) ' ) ;
2021-11-18 19:39:54 -03:00
auto glyph_name = Unicode : : code_point_display_name ( glyph ) ;
if ( glyph_name . has_value ( ) ) {
builder . appendff ( " {} " , glyph_name . value ( ) ) ;
}
2021-11-29 10:43:32 -03:00
if ( m_edited_font - > contains_raw_glyph ( glyph ) )
2021-09-22 10:25:25 -03:00
builder . appendff ( " [{}x{}] " , m_edited_font - > raw_glyph_width ( glyph ) , m_edited_font - > glyph_height ( ) ) ;
2021-11-14 09:27:17 -03:00
else if ( Gfx : : Emoji : : emoji_for_code_point ( glyph ) )
builder . appendff ( " [emoji] " ) ;
2021-09-22 10:25:25 -03:00
m_statusbar - > set_text ( builder . to_string ( ) ) ;
}
2022-07-05 07:37:06 -03:00
void MainWidget : : update_preview ( )
2021-09-22 10:25:25 -03:00
{
if ( m_font_preview_window )
m_font_preview_window - > update ( ) ;
}
2021-10-13 17:16:25 -03:00
2022-07-05 07:37:06 -03:00
void MainWidget : : drop_event ( GUI : : DropEvent & event )
2021-10-13 17:16:25 -03:00
{
event . accept ( ) ;
if ( event . mime_data ( ) . has_urls ( ) ) {
auto urls = event . mime_data ( ) . urls ( ) ;
if ( urls . is_empty ( ) )
return ;
window ( ) - > move_to_front ( ) ;
if ( ! request_close ( ) )
return ;
2022-07-30 08:30:30 -03:00
if ( auto result = open_file ( urls . first ( ) . path ( ) ) ; result . is_error ( ) )
show_error ( " Failed to load font " sv , result . error ( ) ) ;
2021-10-13 17:16:25 -03:00
}
}
2021-11-29 12:05:57 -03:00
2022-07-05 07:37:06 -03:00
void MainWidget : : set_scale ( i32 scale )
2021-11-14 10:26:10 -03:00
{
m_glyph_editor_widget - > set_scale ( scale ) ;
}
2022-07-05 07:37:06 -03:00
void MainWidget : : set_scale_and_save ( i32 scale )
2021-11-14 10:26:10 -03:00
{
set_scale ( scale ) ;
2022-07-11 14:32:29 -03:00
Config : : write_i32 ( " FontEditor " sv , " GlyphEditor " sv , " Scale " sv , scale ) ;
2022-07-05 06:32:22 -03:00
m_glyph_editor_widget - > set_fixed_size ( m_glyph_editor_widget - > preferred_width ( ) , m_glyph_editor_widget - > preferred_height ( ) ) ;
2021-11-14 10:26:10 -03:00
}
2022-01-16 11:36:43 -03:00
2022-07-30 08:30:30 -03:00
ErrorOr < void > MainWidget : : copy_selected_glyphs ( )
2022-01-04 14:24:06 -03:00
{
2022-03-17 08:53:04 -03:00
size_t bytes_per_glyph = Gfx : : GlyphBitmap : : bytes_per_row ( ) * edited_font ( ) . glyph_height ( ) ;
2022-01-04 14:24:06 -03:00
auto selection = m_glyph_map_widget - > selection ( ) . normalized ( ) ;
2022-03-17 08:53:04 -03:00
auto * rows = m_edited_font - > rows ( ) + selection . start ( ) * bytes_per_glyph ;
auto * widths = m_edited_font - > widths ( ) + selection . start ( ) ;
ByteBuffer buffer ;
2022-07-30 08:30:30 -03:00
TRY ( buffer . try_append ( rows , bytes_per_glyph * selection . size ( ) ) ) ;
TRY ( buffer . try_append ( widths , selection . size ( ) ) ) ;
2022-01-04 14:24:06 -03:00
HashMap < String , String > metadata ;
2022-03-17 08:53:04 -03:00
metadata . set ( " start " , String : : number ( selection . start ( ) ) ) ;
metadata . set ( " count " , String : : number ( selection . size ( ) ) ) ;
metadata . set ( " width " , String : : number ( edited_font ( ) . max_glyph_width ( ) ) ) ;
metadata . set ( " height " , String : : number ( edited_font ( ) . glyph_height ( ) ) ) ;
2022-01-04 14:24:06 -03:00
GUI : : Clipboard : : the ( ) . set_data ( buffer . bytes ( ) , " glyph/x-fonteditor " , metadata ) ;
2022-07-30 08:30:30 -03:00
return { } ;
2022-01-04 14:24:06 -03:00
}
2022-07-30 08:30:30 -03:00
ErrorOr < void > MainWidget : : cut_selected_glyphs ( )
2022-01-04 14:24:06 -03:00
{
2022-07-30 08:30:30 -03:00
TRY ( copy_selected_glyphs ( ) ) ;
2022-01-04 14:24:06 -03:00
delete_selected_glyphs ( ) ;
2022-07-30 08:30:30 -03:00
return { } ;
2022-01-04 14:24:06 -03:00
}
2022-07-05 07:37:06 -03:00
void MainWidget : : paste_glyphs ( )
2022-01-04 14:24:06 -03:00
{
auto [ data , mime_type , metadata ] = GUI : : Clipboard : : the ( ) . fetch_data_and_type ( ) ;
2022-07-11 14:32:29 -03:00
if ( ! mime_type . starts_with ( " glyph/ " sv ) )
2022-01-04 14:24:06 -03:00
return ;
2022-03-17 08:53:04 -03:00
auto glyph_count = metadata . get ( " count " ) . value ( ) . to_uint ( ) . value_or ( 0 ) ;
if ( ! glyph_count )
return ;
auto height = metadata . get ( " height " ) . value ( ) . to_uint ( ) . value_or ( 0 ) ;
if ( ! height )
2022-01-04 14:24:06 -03:00
return ;
2022-03-17 08:53:04 -03:00
auto selection = m_glyph_map_widget - > selection ( ) . normalized ( ) ;
auto range_bound_glyph_count = min ( glyph_count , 1 + m_range . last - selection . start ( ) ) ;
2022-03-17 09:56:02 -03:00
m_undo_selection - > set_size ( range_bound_glyph_count ) ;
2022-07-05 06:28:39 -03:00
push_undo ( ) ;
2022-03-17 08:53:04 -03:00
size_t bytes_per_glyph = Gfx : : GlyphBitmap : : bytes_per_row ( ) * edited_font ( ) . glyph_height ( ) ;
size_t bytes_per_copied_glyph = Gfx : : GlyphBitmap : : bytes_per_row ( ) * height ;
size_t copyable_bytes_per_glyph = min ( bytes_per_glyph , bytes_per_copied_glyph ) ;
auto * rows = m_edited_font - > rows ( ) + selection . start ( ) * bytes_per_glyph ;
auto * widths = m_edited_font - > widths ( ) + selection . start ( ) ;
for ( size_t i = 0 ; i < range_bound_glyph_count ; + + i ) {
auto copyable_width = edited_font ( ) . is_fixed_width ( )
2022-03-18 10:51:20 -03:00
? data [ bytes_per_copied_glyph * glyph_count + i ] ? edited_font ( ) . glyph_fixed_width ( ) : 0
2022-03-17 08:53:04 -03:00
: min ( edited_font ( ) . max_glyph_width ( ) , data [ bytes_per_copied_glyph * glyph_count + i ] ) ;
memcpy ( & rows [ i * bytes_per_glyph ] , & data [ i * bytes_per_copied_glyph ] , copyable_bytes_per_glyph ) ;
memset ( & widths [ i ] , copyable_width , sizeof ( u8 ) ) ;
2022-08-03 08:26:18 -03:00
m_glyph_map_widget - > set_glyph_modified ( selection . start ( ) + i , true ) ;
2022-01-04 14:24:06 -03:00
}
2022-03-19 09:52:26 -03:00
m_glyph_map_widget - > set_selection ( selection . start ( ) + range_bound_glyph_count - 1 , - range_bound_glyph_count + 1 ) ;
2022-01-09 15:02:16 -03:00
if ( m_edited_font - > is_fixed_width ( ) )
m_glyph_editor_present_checkbox - > set_checked ( m_edited_font - > contains_raw_glyph ( m_glyph_map_widget - > active_glyph ( ) ) , GUI : : AllowCallback : : No ) ;
else
m_glyph_editor_width_spinbox - > set_value ( m_edited_font - > raw_glyph_width ( m_glyph_map_widget - > active_glyph ( ) ) , GUI : : AllowCallback : : No ) ;
2022-01-04 14:24:06 -03:00
m_glyph_editor_widget - > update ( ) ;
2022-03-17 08:53:04 -03:00
m_glyph_map_widget - > update ( ) ;
2022-01-09 15:02:16 -03:00
update_statusbar ( ) ;
2022-01-04 14:24:06 -03:00
}
2022-07-05 07:37:06 -03:00
void MainWidget : : delete_selected_glyphs ( )
2022-01-04 14:24:06 -03:00
{
2022-07-05 06:28:39 -03:00
push_undo ( ) ;
2022-01-04 14:24:06 -03:00
2022-03-17 09:56:02 -03:00
auto selection = m_glyph_map_widget - > selection ( ) . normalized ( ) ;
2022-03-17 08:53:04 -03:00
size_t bytes_per_glyph = Gfx : : GlyphBitmap : : bytes_per_row ( ) * m_edited_font - > glyph_height ( ) ;
auto * rows = m_edited_font - > rows ( ) + selection . start ( ) * bytes_per_glyph ;
auto * widths = m_edited_font - > widths ( ) + selection . start ( ) ;
memset ( rows , 0 , bytes_per_glyph * selection . size ( ) ) ;
memset ( widths , 0 , selection . size ( ) ) ;
2022-01-09 15:02:16 -03:00
if ( m_edited_font - > is_fixed_width ( ) )
m_glyph_editor_present_checkbox - > set_checked ( false , GUI : : AllowCallback : : No ) ;
else
m_glyph_editor_width_spinbox - > set_value ( 0 , GUI : : AllowCallback : : No ) ;
m_glyph_editor_widget - > update ( ) ;
2022-03-17 08:53:04 -03:00
m_glyph_map_widget - > update ( ) ;
2022-01-09 15:02:16 -03:00
update_statusbar ( ) ;
2022-01-04 14:24:06 -03:00
}
2022-07-05 06:32:22 -03:00
2022-07-30 08:29:04 -03:00
void MainWidget : : show_error ( StringView preface , Error error )
{
auto formatted_error = String : : formatted ( " {}: {} " , preface , error ) ;
GUI : : MessageBox : : show_error ( window ( ) , formatted_error ) ;
warnln ( formatted_error ) ;
}
2022-07-05 06:32:22 -03:00
}