2020-01-18 05:38:21 -03:00
/*
* Copyright ( c ) 2018 - 2020 , Andreas Kling < kling @ serenityos . org >
*
2021-04-22 05:24:48 -03:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-01-18 05:38:21 -03:00
*/
2019-02-02 05:05:14 -02:00
# include "FontEditor.h"
2019-04-03 10:23:13 -03:00
# include "GlyphEditorWidget.h"
2019-06-07 06:48:03 -03:00
# include "GlyphMapWidget.h"
2021-04-10 14:47:23 -03:00
# include "NewFontDialog.h"
2019-09-04 17:50:40 -03:00
# include <AK/StringBuilder.h>
2021-04-06 13:04:21 -03:00
# include <Applications/FontEditor/FontEditorWindowGML.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-05-08 19:06:56 -03:00
# include <LibGUI/BoxLayout.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>
2021-04-10 14:40:59 -03:00
# include <LibGUI/FontPickerWeightModel.h>
2020-02-06 16:33:02 -03:00
# include <LibGUI/GroupBox.h>
# include <LibGUI/Label.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/Painter.h>
# 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>
2020-12-31 10:01:59 -03:00
# include <LibGfx/BitmapFont.h>
2020-05-08 19:06:56 -03:00
# include <LibGfx/Palette.h>
2019-04-09 22:51:03 -03:00
# include <stdlib.h>
2019-02-02 05:05:14 -02:00
2021-04-22 14:41:43 -03:00
static constexpr int s_pangram_count = 7 ;
static const char * pangrams [ s_pangram_count ] = {
" quick fox jumps nightly above wizard " ,
" five quacking zephyrs jolt my wax bed " ,
" pack my box with five dozen liquor jugs " ,
" quick brown fox jumps over the lazy dog " ,
" waxy and quivering jocks fumble the pizza " ,
" ~#:[@_1%]*{$2.3}/4^(5'6 \" )-&|7+8!=<9,0 \\ >?; " ,
" byxfjärmat föl gick på duvshowen "
} ;
2021-04-06 13:04:21 -03:00
static RefPtr < GUI : : Window > create_font_preview_window ( FontEditorWidget & editor )
2019-02-02 05:05:14 -02:00
{
2021-04-06 13:04:21 -03:00
auto window = GUI : : Window : : construct ( ) ;
window - > set_window_type ( GUI : : WindowType : : ToolWindow ) ;
window - > set_title ( " Font preview " ) ;
window - > resize ( 400 , 150 ) ;
window - > set_minimum_size ( 200 , 100 ) ;
window - > center_within ( * editor . window ( ) ) ;
auto & main_widget = window - > set_main_widget < GUI : : Widget > ( ) ;
main_widget . set_fill_with_background_color ( true ) ;
main_widget . set_layout < GUI : : VerticalBoxLayout > ( ) ;
main_widget . layout ( ) - > set_margins ( { 2 , 2 , 2 , 2 } ) ;
main_widget . layout ( ) - > set_spacing ( 4 ) ;
auto & preview_box = main_widget . add < GUI : : GroupBox > ( ) ;
preview_box . set_layout < GUI : : VerticalBoxLayout > ( ) ;
preview_box . layout ( ) - > set_margins ( { 8 , 8 , 8 , 8 } ) ;
auto & preview_label = preview_box . add < GUI : : Label > ( ) ;
preview_label . set_font ( editor . edited_font ( ) ) ;
editor . on_initialize = [ & ] {
preview_label . set_font ( editor . edited_font ( ) ) ;
2019-03-06 08:52:41 -03:00
} ;
2021-04-22 14:41:43 -03:00
auto & textbox_button_container = main_widget . add < GUI : : Widget > ( ) ;
textbox_button_container . set_layout < GUI : : HorizontalBoxLayout > ( ) ;
textbox_button_container . set_fixed_height ( 22 ) ;
auto & preview_textbox = textbox_button_container . add < GUI : : TextBox > ( ) ;
preview_textbox . set_text ( pangrams [ 0 ] ) ;
2021-04-10 14:40:59 -03:00
preview_textbox . set_placeholder ( " Preview text " ) ;
2020-10-24 12:03:39 -03:00
2021-04-06 13:04:21 -03:00
preview_textbox . on_change = [ & ] {
2021-04-10 14:40:59 -03:00
auto preview = String : : formatted ( " {} \n {} " ,
preview_textbox . text ( ) ,
preview_textbox . text ( ) . to_uppercase ( ) ) ;
preview_label . set_text ( preview ) ;
2020-10-24 12:03:39 -03:00
} ;
2021-04-22 14:41:43 -03:00
auto & reload_button = textbox_button_container . add < GUI : : Button > ( ) ;
reload_button . set_icon ( Gfx : : Bitmap : : load_from_file ( " /res/icons/16x16/reload.png " ) ) ;
reload_button . set_fixed_width ( 22 ) ;
reload_button . on_click = [ & ] {
static int i = 1 ;
if ( i > = s_pangram_count )
i = 0 ;
preview_textbox . set_text ( pangrams [ i ] ) ;
i + + ;
} ;
2021-04-06 13:04:21 -03:00
return window ;
}
FontEditorWidget : : FontEditorWidget ( const String & path , RefPtr < Gfx : : BitmapFont > & & edited_font )
{
load_from_gml ( font_editor_window_gml ) ;
2021-04-13 11:18:20 -03:00
auto & toolbar = * find_descendant_of_type_named < GUI : : Toolbar > ( " toolbar " ) ;
auto & statusbar = * find_descendant_of_type_named < GUI : : Statusbar > ( " statusbar " ) ;
2021-04-06 13:04:21 -03:00
auto & glyph_map_container = * find_descendant_of_type_named < GUI : : Widget > ( " glyph_map_container " ) ;
2021-04-22 15:15:21 -03:00
auto & move_glyph_button = * find_descendant_of_type_named < GUI : : Button > ( " move_glyph_button " ) ;
2021-04-06 13:04:21 -03:00
m_glyph_editor_container = * find_descendant_of_type_named < GUI : : Widget > ( " glyph_editor_container " ) ;
m_left_column_container = * find_descendant_of_type_named < GUI : : Widget > ( " left_column_container " ) ;
m_glyph_editor_width_spinbox = * find_descendant_of_type_named < GUI : : SpinBox > ( " glyph_editor_width_spinbox " ) ;
2021-04-18 15:12:52 -03:00
m_glyph_editor_present_checkbox = * find_descendant_of_type_named < GUI : : CheckBox > ( " glyph_editor_present_checkbox " ) ;
2021-04-06 13:04:21 -03:00
m_name_textbox = * find_descendant_of_type_named < GUI : : TextBox > ( " name_textbox " ) ;
m_family_textbox = * find_descendant_of_type_named < GUI : : TextBox > ( " family_textbox " ) ;
m_presentation_spinbox = * find_descendant_of_type_named < GUI : : SpinBox > ( " presentation_spinbox " ) ;
2021-04-10 14:40:59 -03:00
m_weight_combobox = * find_descendant_of_type_named < GUI : : ComboBox > ( " weight_combobox " ) ;
m_type_combobox = * find_descendant_of_type_named < GUI : : ComboBox > ( " type_combobox " ) ;
2021-04-06 13:04:21 -03:00
m_spacing_spinbox = * find_descendant_of_type_named < GUI : : SpinBox > ( " spacing_spinbox " ) ;
m_mean_line_spinbox = * find_descendant_of_type_named < GUI : : SpinBox > ( " mean_line_spinbox " ) ;
m_baseline_spinbox = * find_descendant_of_type_named < GUI : : SpinBox > ( " baseline_spinbox " ) ;
m_fixed_width_checkbox = * find_descendant_of_type_named < GUI : : CheckBox > ( " fixed_width_checkbox " ) ;
m_font_metadata_groupbox = * find_descendant_of_type_named < GUI : : GroupBox > ( " font_metadata_groupbox " ) ;
m_glyph_editor_widget = m_glyph_editor_container - > add < GlyphEditorWidget > ( ) ;
m_glyph_map_widget = glyph_map_container . add < GlyphMapWidget > ( ) ;
2021-04-22 14:53:17 -03:00
auto update_statusbar = [ & ] {
auto glyph = m_glyph_map_widget - > selected_glyph ( ) ;
StringBuilder builder ;
builder . appendff ( " {:#02x} ( " , glyph ) ;
if ( glyph < 128 ) {
if ( glyph = = 10 )
builder . append ( " LF " ) ;
else
builder . append ( glyph ) ;
} else {
builder . append ( 128 | 64 | ( glyph / 64 ) ) ;
builder . append ( 128 | ( glyph % 64 ) ) ;
}
builder . append ( " ) " ) ;
builder . appendff ( " [{}x{}] " , m_edited_font - > raw_glyph_width ( glyph ) , m_edited_font - > glyph_height ( ) ) ;
statusbar . set_text ( builder . to_string ( ) ) ;
} ;
2020-05-08 19:06:56 -03:00
auto update_demo = [ & ] {
2021-04-06 13:04:21 -03:00
if ( m_font_preview_window )
m_font_preview_window - > update ( ) ;
2020-05-08 19:06:56 -03:00
} ;
2019-04-09 22:51:03 -03:00
2021-04-22 14:53:17 -03:00
m_new_action = GUI : : Action : : create ( " &New Font... " , { Mod_Ctrl , Key_N } , Gfx : : Bitmap : : load_from_file ( " /res/icons/16x16/filetype-font.png " ) , [ & ] ( auto & ) {
2021-04-26 10:11:14 -03:00
if ( m_font_modified ) {
auto result = GUI : : MessageBox : : show ( window ( ) , " Save changes to the current font? " , " Unsaved changes " , GUI : : MessageBox : : Type : : Warning , GUI : : MessageBox : : InputType : : YesNoCancel ) ;
if ( result = = GUI : : Dialog : : ExecResult : : ExecYes ) {
m_save_action - > activate ( ) ;
if ( m_font_modified )
return ;
}
if ( result = = GUI : : Dialog : : ExecResult : : ExecCancel )
return ;
}
2021-04-10 14:47:23 -03:00
auto new_font_wizard = NewFontDialog : : construct ( window ( ) ) ;
if ( new_font_wizard - > exec ( ) = = GUI : : Dialog : : ExecOK ) {
auto metadata = new_font_wizard - > new_font_metadata ( ) ;
String name = metadata . name ;
auto parts = name . split ( ' ' ) ;
if ( parts . size ( ) > 1 )
name = parts [ 0 ] ;
parts . clear ( ) ;
String weight = GUI : : weight_to_name ( metadata . weight ) . to_string ( ) ;
parts = weight . split ( ' ' ) ;
if ( parts . size ( ) > 1 )
weight = String : : formatted ( " {}{} " , parts [ 0 ] , parts [ 1 ] ) ;
RefPtr < Gfx : : BitmapFont > new_font = Gfx : : BitmapFont : : create ( metadata . glyph_height , metadata . glyph_width , metadata . is_fixed_width , metadata . type ) ;
2021-04-26 10:11:14 -03:00
String path = String : : formatted ( " {}{}{}.font " , name , weight , metadata . presentation_size ) ;
2021-04-10 14:47:23 -03:00
if ( ! new_font ) {
String message = String : : formatted ( " Failed to create new font: {} \n " , path ) ;
GUI : : MessageBox : : show ( window ( ) , message , " Font Editor " , GUI : : MessageBox : : Type : : Error ) ;
return ;
}
new_font - > set_name ( metadata . name ) ;
new_font - > set_family ( metadata . family ) ;
new_font - > set_presentation_size ( metadata . presentation_size ) ;
new_font - > set_weight ( metadata . weight ) ;
new_font - > set_baseline ( metadata . baseline ) ;
new_font - > set_mean_line ( metadata . mean_line ) ;
2021-04-26 10:11:14 -03:00
m_font_modified = true ;
2021-04-10 14:47:23 -03:00
initialize ( path , move ( new_font ) ) ;
}
} ) ;
2021-04-22 14:53:17 -03:00
m_new_action - > set_status_tip ( " Create a new font " ) ;
2021-04-10 14:47:23 -03:00
m_open_action = GUI : : CommonActions : : make_open_action ( [ & ] ( auto & ) {
2021-04-26 10:11:14 -03:00
if ( m_font_modified ) {
auto result = GUI : : MessageBox : : show ( window ( ) , " Save changes to the current font? " , " Unsaved changes " , GUI : : MessageBox : : Type : : Warning , GUI : : MessageBox : : InputType : : YesNoCancel ) ;
if ( result = = GUI : : Dialog : : ExecResult : : ExecYes ) {
m_save_action - > activate ( ) ;
if ( m_font_modified )
return ;
}
if ( result = = GUI : : Dialog : : ExecResult : : ExecCancel )
return ;
}
2021-04-06 13:04:21 -03:00
Optional < String > open_path = GUI : : FilePicker : : get_open_filepath ( window ( ) , { } , " /res/fonts/ " ) ;
if ( ! open_path . has_value ( ) )
return ;
2019-03-06 08:52:41 -03:00
2021-04-06 13:04:21 -03:00
auto bitmap_font = Gfx : : BitmapFont : : load_from_file ( open_path . value ( ) ) ;
if ( ! bitmap_font ) {
String message = String : : formatted ( " Couldn't load font: {} \n " , open_path . value ( ) ) ;
GUI : : MessageBox : : show ( window ( ) , message , " Font Editor " , GUI : : MessageBox : : Type : : Error ) ;
return ;
}
RefPtr < Gfx : : BitmapFont > new_font = static_ptr_cast < Gfx : : BitmapFont > ( bitmap_font - > clone ( ) ) ;
if ( ! new_font ) {
String message = String : : formatted ( " Couldn't load font: {} \n " , open_path . value ( ) ) ;
GUI : : MessageBox : : show ( window ( ) , message , " Font Editor " , GUI : : MessageBox : : Type : : Error ) ;
return ;
}
2021-04-26 10:11:14 -03:00
m_font_newly_opened = true ;
2021-04-06 13:04:21 -03:00
initialize ( open_path . value ( ) , move ( new_font ) ) ;
} ) ;
2021-04-10 14:40:59 -03:00
m_save_action = GUI : : CommonActions : : make_save_action ( [ & ] ( auto & ) {
2021-04-26 10:11:14 -03:00
LexicalPath lexical_path ( m_path ) ;
if ( ! lexical_path . dirname ( ) . is_empty ( ) )
save_as ( m_path ) ;
else
m_save_as_action - > activate ( ) ;
2021-04-06 13:04:21 -03:00
} ) ;
2021-04-10 14:40:59 -03:00
m_save_as_action = GUI : : CommonActions : : make_save_as_action ( [ & ] ( auto & ) {
LexicalPath lexical_path ( m_path ) ;
Optional < String > save_path = GUI : : FilePicker : : get_save_filepath ( window ( ) , lexical_path . title ( ) , lexical_path . extension ( ) ) ;
if ( ! save_path . has_value ( ) )
return ;
2021-04-26 10:11:14 -03:00
save_as ( save_path . value ( ) ) ;
2021-04-10 14:40:59 -03:00
} ) ;
m_cut_action = GUI : : CommonActions : : make_cut_action ( [ & ] ( auto & ) {
2021-04-06 13:04:21 -03:00
m_glyph_editor_widget - > cut_glyph ( ) ;
} ) ;
2021-04-10 14:40:59 -03:00
m_copy_action = GUI : : CommonActions : : make_copy_action ( [ & ] ( auto & ) {
2021-04-06 13:04:21 -03:00
m_glyph_editor_widget - > copy_glyph ( ) ;
} ) ;
2021-04-10 14:40:59 -03:00
m_paste_action = GUI : : CommonActions : : make_paste_action ( [ & ] ( auto & ) {
2021-04-06 13:04:21 -03:00
m_glyph_editor_widget - > paste_glyph ( ) ;
m_glyph_map_widget - > update_glyph ( m_glyph_map_widget - > selected_glyph ( ) ) ;
} ) ;
2021-04-10 14:40:59 -03:00
m_paste_action - > set_enabled ( GUI : : Clipboard : : the ( ) . mime_type ( ) = = " glyph/x-fonteditor " ) ;
m_delete_action = GUI : : CommonActions : : make_delete_action ( [ & ] ( auto & ) {
2021-04-06 13:04:21 -03:00
m_edited_font - > set_glyph_width ( m_glyph_map_widget - > selected_glyph ( ) , m_edited_font - > max_glyph_width ( ) ) ;
m_glyph_editor_widget - > delete_glyph ( ) ;
m_glyph_map_widget - > update_glyph ( m_glyph_map_widget - > selected_glyph ( ) ) ;
2021-04-18 15:12:52 -03:00
auto glyph_width = m_edited_font - > raw_glyph_width ( m_glyph_map_widget - > selected_glyph ( ) ) ;
m_glyph_editor_width_spinbox - > set_value ( glyph_width ) ;
m_glyph_editor_present_checkbox - > set_checked ( glyph_width > 0 ) ;
2021-04-06 13:04:21 -03:00
} ) ;
2021-04-22 15:12:53 -03:00
m_undo_action = GUI : : CommonActions : : make_undo_action ( [ & ] ( auto & ) {
undo ( ) ;
} ) ;
m_undo_action - > set_enabled ( false ) ;
m_redo_action = GUI : : CommonActions : : make_redo_action ( [ & ] ( auto & ) {
redo ( ) ;
} ) ;
m_redo_action - > set_enabled ( false ) ;
2021-04-22 14:53:17 -03:00
m_open_preview_action = GUI : : Action : : create ( " &Preview Font " , { Mod_Ctrl , Key_P } , Gfx : : Bitmap : : load_from_file ( " /res/icons/16x16/find.png " ) , [ & ] ( auto & ) {
2021-04-06 13:04:21 -03:00
if ( ! m_font_preview_window )
m_font_preview_window = create_font_preview_window ( * this ) ;
m_font_preview_window - > show ( ) ;
m_font_preview_window - > move_to_front ( ) ;
} ) ;
2021-04-10 14:40:59 -03:00
m_open_preview_action - > set_checked ( false ) ;
2021-04-22 14:53:17 -03:00
m_open_preview_action - > set_status_tip ( " Preview the current font " ) ;
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 ( ) ) ;
} ) ;
m_show_metadata_action - > set_checked ( true ) ;
2021-04-22 14:53:17 -03:00
m_show_metadata_action - > set_status_tip ( " Show or hide metadata about the current font " ) ;
2021-04-06 13:04:21 -03:00
2021-04-10 14:40:59 -03:00
toolbar . add_action ( * m_new_action ) ;
toolbar . add_action ( * m_open_action ) ;
toolbar . add_action ( * m_save_action ) ;
2021-04-06 13:04:21 -03:00
toolbar . add_separator ( ) ;
2021-04-10 14:40:59 -03:00
toolbar . add_action ( * m_cut_action ) ;
toolbar . add_action ( * m_copy_action ) ;
toolbar . add_action ( * m_paste_action ) ;
toolbar . add_action ( * m_delete_action ) ;
2021-04-06 13:04:21 -03:00
toolbar . add_separator ( ) ;
2021-04-22 15:12:53 -03:00
toolbar . add_action ( * m_undo_action ) ;
toolbar . add_action ( * m_redo_action ) ;
toolbar . add_separator ( ) ;
2021-04-10 14:40:59 -03:00
toolbar . add_action ( * m_open_preview_action ) ;
2021-04-22 15:04:19 -03:00
m_scale_five_action = GUI : : Action : : create_checkable ( " 500% " , { Mod_Ctrl , Key_1 } , [ & ] ( auto & ) {
m_glyph_editor_widget - > set_scale ( 5 ) ;
m_glyph_editor_container - > set_fixed_size ( m_glyph_editor_widget - > preferred_width ( ) , m_glyph_editor_widget - > preferred_height ( ) ) ;
m_left_column_container - > set_fixed_width ( m_glyph_editor_widget - > preferred_width ( ) ) ;
} ) ;
m_scale_five_action - > set_checked ( false ) ;
m_scale_five_action - > set_status_tip ( " Scale the editor in proportion to the current font " ) ;
m_scale_ten_action = GUI : : Action : : create_checkable ( " 1000% " , { Mod_Ctrl , Key_2 } , [ & ] ( auto & ) {
m_glyph_editor_widget - > set_scale ( 10 ) ;
m_glyph_editor_container - > set_fixed_size ( m_glyph_editor_widget - > preferred_width ( ) , m_glyph_editor_widget - > preferred_height ( ) ) ;
m_left_column_container - > set_fixed_width ( m_glyph_editor_widget - > preferred_width ( ) ) ;
} ) ;
m_scale_ten_action - > set_checked ( true ) ;
m_scale_ten_action - > set_status_tip ( " Scale the editor in proportion to the current font " ) ;
m_scale_fifteen_action = GUI : : Action : : create_checkable ( " 1500% " , { Mod_Ctrl , Key_3 } , [ & ] ( auto & ) {
m_glyph_editor_widget - > set_scale ( 15 ) ;
m_glyph_editor_container - > set_fixed_size ( m_glyph_editor_widget - > preferred_width ( ) , m_glyph_editor_widget - > preferred_height ( ) ) ;
m_left_column_container - > set_fixed_width ( m_glyph_editor_widget - > preferred_width ( ) ) ;
} ) ;
m_scale_fifteen_action - > set_checked ( false ) ;
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 ) ;
2021-04-22 15:15:21 -03:00
move_glyph_button . on_click = [ & ] {
if ( move_glyph_button . is_checked ( ) )
m_glyph_editor_widget - > set_mode ( GlyphEditorWidget : : Move ) ;
else
m_glyph_editor_widget - > set_mode ( GlyphEditorWidget : : Paint ) ;
} ;
move_glyph_button . set_checkable ( true ) ;
move_glyph_button . set_icon ( Gfx : : Bitmap : : load_from_file ( " /res/icons/16x16/selection-move.png " ) ) ;
2021-04-10 14:40:59 -03:00
GUI : : Clipboard : : the ( ) . on_change = [ & ] ( const String & data_type ) {
m_paste_action - > set_enabled ( data_type = = " glyph/x-fonteditor " ) ;
} ;
2019-02-02 05:05:14 -02:00
2021-04-10 14:40:59 -03:00
m_glyph_editor_widget - > on_glyph_altered = [ this , update_demo ] ( int glyph ) {
2019-04-06 10:28:06 -03:00
m_glyph_map_widget - > update_glyph ( glyph ) ;
2019-03-06 08:52:41 -03:00
update_demo ( ) ;
2021-04-26 10:11:14 -03:00
did_modify_font ( ) ;
2019-03-06 08:52:41 -03:00
} ;
2021-04-22 15:12:53 -03:00
m_glyph_editor_widget - > on_undo_event = [ this ] ( bool finalize ) {
m_undo_stack - > push ( make < GlyphUndoCommand > ( * m_undo_glyph ) ) ;
if ( finalize )
m_undo_stack - > finalize_current_combo ( ) ;
did_change_undo_stack ( ) ;
} ;
m_glyph_map_widget - > on_glyph_selected = [ & , update_statusbar ] ( int glyph ) {
if ( m_undo_glyph )
m_undo_glyph - > set_code_point ( glyph ) ;
2019-02-02 05:05:14 -02:00
m_glyph_editor_widget - > set_glyph ( glyph ) ;
2021-04-18 15:12:52 -03:00
auto glyph_width = m_edited_font - > raw_glyph_width ( m_glyph_map_widget - > selected_glyph ( ) ) ;
m_glyph_editor_width_spinbox - > set_value ( glyph_width ) ;
m_glyph_editor_present_checkbox - > set_checked ( glyph_width > 0 ) ;
2021-04-22 14:53:17 -03:00
update_statusbar ( ) ;
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
} ;
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
} ;
2021-04-06 13:04:21 -03:00
m_fixed_width_checkbox - > on_checked = [ & , update_demo ] ( bool checked ) {
2019-05-24 12:11:42 -03:00
m_edited_font - > set_fixed_width ( checked ) ;
2021-04-18 15:12:52 -03:00
auto glyph_width = m_edited_font - > raw_glyph_width ( m_glyph_map_widget - > selected_glyph ( ) ) ;
m_glyph_editor_width_spinbox - > set_visible ( ! checked ) ;
m_glyph_editor_width_spinbox - > set_value ( glyph_width ) ;
m_glyph_editor_present_checkbox - > set_visible ( checked ) ;
m_glyph_editor_present_checkbox - > set_checked ( glyph_width > 0 ) ;
2019-03-06 08:52:41 -03:00
m_glyph_editor_widget - > update ( ) ;
update_demo ( ) ;
2021-04-26 10:11:14 -03:00
did_modify_font ( ) ;
2019-03-06 08:52:41 -03:00
} ;
2021-04-22 14:53:17 -03:00
m_glyph_editor_width_spinbox - > on_change = [ this , update_demo , update_statusbar ] ( int value ) {
2021-04-26 10:11:14 -03:00
if ( m_edited_font - > raw_glyph_width ( m_glyph_map_widget - > selected_glyph ( ) ) = = value )
return ;
2019-04-09 11:29:00 -03:00
m_edited_font - > set_glyph_width ( m_glyph_map_widget - > selected_glyph ( ) , value ) ;
m_glyph_editor_widget - > update ( ) ;
2019-04-09 23:02:20 -03:00
m_glyph_map_widget - > update_glyph ( m_glyph_map_widget - > selected_glyph ( ) ) ;
2019-04-09 11:29:00 -03:00
update_demo ( ) ;
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-04-22 14:53:17 -03:00
m_glyph_editor_present_checkbox - > on_checked = [ this , update_demo , update_statusbar ] ( bool checked ) {
2021-04-26 10:11:14 -03:00
if ( ! m_edited_font - > is_fixed_width ( )
| | m_edited_font - > raw_glyph_width ( m_glyph_map_widget - > selected_glyph ( ) ) = = checked
| | ( m_edited_font - > raw_glyph_width ( m_glyph_map_widget - > selected_glyph ( ) ) & & checked ) )
2021-04-22 14:53:17 -03:00
return ;
2021-04-18 15:12:52 -03:00
m_edited_font - > set_glyph_width ( m_glyph_map_widget - > selected_glyph ( ) , checked ? m_edited_font - > glyph_fixed_width ( ) : 0 ) ;
m_glyph_editor_widget - > update ( ) ;
m_glyph_map_widget - > update_glyph ( m_glyph_map_widget - > selected_glyph ( ) ) ;
update_demo ( ) ;
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
} ;
2021-04-10 14:40:59 -03:00
m_weight_combobox - > on_change = [ this ] ( ) {
m_edited_font - > set_weight ( GUI : : 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
} ;
m_type_combobox - > on_change = [ this ] ( auto & , const auto & index ) {
m_edited_font - > set_type ( static_cast < Gfx : : FontTypes > ( index . row ( ) ) ) ;
2021-04-18 08:31:39 -03:00
m_glyph_map_widget - > reprobe_font ( ) ;
2021-04-26 10:11:14 -03:00
did_modify_font ( ) ;
2020-10-24 12:03:39 -03:00
} ;
2021-04-06 13:04:21 -03:00
m_presentation_spinbox - > on_change = [ this , update_demo ] ( int value ) {
2020-10-24 12:03:39 -03:00
m_edited_font - > set_presentation_size ( value ) ;
update_demo ( ) ;
2021-04-26 10:11:14 -03:00
did_modify_font ( ) ;
2020-10-24 12:03:39 -03:00
} ;
2021-04-06 13:04:21 -03:00
m_spacing_spinbox - > on_change = [ this , update_demo ] ( int value ) {
2019-12-30 07:40:30 -03:00
m_edited_font - > set_glyph_spacing ( value ) ;
update_demo ( ) ;
2021-04-26 10:11:14 -03:00
did_modify_font ( ) ;
2019-12-30 07:40:30 -03:00
} ;
2021-04-06 13:04:21 -03:00
m_baseline_spinbox - > on_change = [ this , update_demo ] ( 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 ( ) ;
2020-09-19 13:01:32 -03:00
update_demo ( ) ;
2021-04-26 10:11:14 -03:00
did_modify_font ( ) ;
2020-09-19 13:01:32 -03:00
} ;
2021-04-06 13:04:21 -03:00
m_mean_line_spinbox - > on_change = [ this , update_demo ] ( int value ) {
2020-10-05 12:19:37 -03:00
m_edited_font - > set_mean_line ( value ) ;
m_glyph_editor_widget - > update ( ) ;
update_demo ( ) ;
2021-04-26 10:11:14 -03:00
did_modify_font ( ) ;
2020-10-05 12:19:37 -03:00
} ;
2021-04-22 14:53:17 -03:00
GUI : : Application : : the ( ) - > on_action_enter = [ & statusbar ] ( GUI : : Action & action ) {
auto text = action . status_tip ( ) ;
if ( text . is_empty ( ) )
text = Gfx : : parse_ampersand_string ( action . text ( ) ) ;
statusbar . set_override_text ( move ( text ) ) ;
} ;
GUI : : Application : : the ( ) - > on_action_leave = [ & statusbar ] ( GUI : : Action & ) {
statusbar . set_override_text ( { } ) ;
} ;
2021-04-06 13:04:21 -03:00
initialize ( path , move ( edited_font ) ) ;
2019-02-02 05:05:14 -02:00
}
FontEditorWidget : : ~ FontEditorWidget ( )
{
}
2020-07-10 22:20:39 -03:00
2021-04-06 13:04:21 -03:00
void FontEditorWidget : : initialize ( const String & path , RefPtr < Gfx : : BitmapFont > & & edited_font )
{
if ( m_edited_font = = edited_font )
return ;
m_path = path ;
m_edited_font = edited_font ;
2021-04-07 13:05:02 -03:00
m_glyph_map_widget - > initialize ( * m_edited_font ) ;
2021-04-06 13:04:21 -03:00
m_glyph_editor_widget - > initialize ( * m_edited_font ) ;
2021-04-07 13:05:02 -03:00
2021-04-06 13:04:21 -03:00
m_glyph_editor_container - > set_fixed_size ( m_glyph_editor_widget - > preferred_width ( ) , m_glyph_editor_widget - > preferred_height ( ) ) ;
m_left_column_container - > set_fixed_width ( m_glyph_editor_widget - > preferred_width ( ) ) ;
2021-04-18 15:12:52 -03:00
m_glyph_editor_width_spinbox - > set_visible ( ! m_edited_font - > is_fixed_width ( ) ) ;
2021-04-06 13:04:21 -03:00
m_glyph_editor_width_spinbox - > set_max ( m_edited_font - > max_glyph_width ( ) ) ;
2021-04-18 15:12:52 -03:00
m_glyph_editor_present_checkbox - > set_visible ( m_edited_font - > is_fixed_width ( ) ) ;
2021-04-06 13:04:21 -03:00
m_name_textbox - > set_text ( m_edited_font - > name ( ) ) ;
m_family_textbox - > set_text ( m_edited_font - > family ( ) ) ;
m_presentation_spinbox - > set_value ( m_edited_font - > presentation_size ( ) ) ;
m_spacing_spinbox - > set_value ( m_edited_font - > glyph_spacing ( ) ) ;
2021-04-22 15:20:57 -03:00
m_mean_line_spinbox - > set_range ( 0 , max ( m_edited_font - > glyph_height ( ) - 2 , 0 ) , false ) ;
m_baseline_spinbox - > set_range ( 0 , max ( m_edited_font - > glyph_height ( ) - 2 , 0 ) , false ) ;
2021-04-06 13:04:21 -03:00
m_mean_line_spinbox - > set_value ( m_edited_font - > mean_line ( ) ) ;
m_baseline_spinbox - > set_value ( m_edited_font - > baseline ( ) ) ;
2021-04-10 14:40:59 -03:00
m_font_weight_list . clear ( ) ;
for ( auto & it : GUI : : font_weight_names )
m_font_weight_list . append ( it . name ) ;
m_weight_combobox - > set_model ( * GUI : : ItemListModel < String > : : create ( m_font_weight_list ) ) ;
int i = 0 ;
for ( auto it : GUI : : font_weight_names ) {
if ( it . weight = = m_edited_font - > weight ( ) ) {
m_weight_combobox - > set_selected_index ( i ) ;
break ;
}
i + + ;
}
m_font_type_list . clear ( ) ;
StringBuilder type_count ;
for ( int i = 0 ; i < Gfx : : FontTypes : : __Count ; i + + ) {
type_count . appendff ( " {} " , Gfx : : BitmapFont : : type_name_by_type ( static_cast < Gfx : : FontTypes > ( i ) ) ) ;
m_font_type_list . append ( type_count . to_string ( ) ) ;
type_count . clear ( ) ;
}
m_type_combobox - > set_model ( * GUI : : ItemListModel < String > : : create ( m_font_type_list ) ) ;
m_type_combobox - > set_selected_index ( m_edited_font - > type ( ) ) ;
2021-04-06 13:04:21 -03:00
m_fixed_width_checkbox - > set_checked ( m_edited_font - > is_fixed_width ( ) ) ;
2021-04-07 13:05:02 -03:00
m_glyph_map_widget - > set_selected_glyph ( ' A ' ) ;
2021-04-10 14:40:59 -03:00
deferred_invoke ( [ this ] ( auto & ) {
m_glyph_map_widget - > set_focus ( true ) ;
m_glyph_map_widget - > scroll_to_glyph ( m_glyph_map_widget - > selected_glyph ( ) ) ;
2021-04-26 10:11:14 -03:00
if ( m_font_newly_opened )
m_font_modified = false ;
update_title ( ) ;
m_font_newly_opened = false ;
2021-04-10 14:40:59 -03:00
} ) ;
2021-04-07 13:05:02 -03:00
2021-04-22 15:12:53 -03:00
m_undo_stack = make < GUI : : UndoStack > ( ) ;
2021-04-23 11:46:57 -03:00
m_undo_glyph = adopt_ref ( * new UndoGlyph ( m_glyph_map_widget - > selected_glyph ( ) , * m_edited_font ) ) ;
2021-04-22 15:12:53 -03:00
did_change_undo_stack ( ) ;
2021-04-06 13:04:21 -03:00
if ( on_initialize )
on_initialize ( ) ;
}
2021-04-13 11:18:20 -03:00
void FontEditorWidget : : initialize_menubar ( GUI : : Menubar & menubar )
2021-04-10 14:40:59 -03:00
{
2021-05-01 05:45:39 -03:00
auto & file_menu = menubar . add_menu ( " &File " ) ;
file_menu . add_action ( * m_new_action ) ;
file_menu . add_action ( * m_open_action ) ;
file_menu . add_action ( * m_save_action ) ;
file_menu . add_action ( * m_save_as_action ) ;
file_menu . add_separator ( ) ;
file_menu . 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 ( ) ;
} ) ) ;
auto & edit_menu = menubar . add_menu ( " &Edit " ) ;
2021-04-22 15:12:53 -03:00
edit_menu . add_action ( * m_undo_action ) ;
edit_menu . add_action ( * m_redo_action ) ;
edit_menu . add_separator ( ) ;
2021-04-10 14:40:59 -03:00
edit_menu . add_action ( * m_cut_action ) ;
edit_menu . add_action ( * m_copy_action ) ;
edit_menu . add_action ( * m_paste_action ) ;
edit_menu . add_action ( * m_delete_action ) ;
auto & view_menu = menubar . add_menu ( " &View " ) ;
view_menu . add_action ( * m_open_preview_action ) ;
view_menu . add_separator ( ) ;
view_menu . add_action ( * m_show_metadata_action ) ;
2021-04-22 15:04:19 -03:00
view_menu . add_separator ( ) ;
auto & scale_menu = view_menu . add_submenu ( " &Scale " ) ;
scale_menu . add_action ( * m_scale_five_action ) ;
scale_menu . add_action ( * m_scale_ten_action ) ;
scale_menu . add_action ( * m_scale_fifteen_action ) ;
2021-04-10 14:40:59 -03:00
auto & help_menu = menubar . add_menu ( " &Help " ) ;
help_menu . add_action ( GUI : : CommonActions : : make_help_action ( [ ] ( auto & ) {
Desktop : : Launcher : : open ( URL : : create_with_file_protocol ( " /usr/share/man/man1/FontEditor.md " ) , " /bin/Help " ) ;
} ) ) ;
help_menu . add_action ( GUI : : CommonActions : : make_about_action ( " Font Editor " , GUI : : Icon : : default_icon ( " app-font-editor " ) , window ( ) ) ) ;
}
2020-07-10 22:20:39 -03:00
bool FontEditorWidget : : save_as ( const String & path )
{
auto ret_val = m_edited_font - > write_to_file ( path ) ;
if ( ! ret_val ) {
2020-07-15 23:45:11 -03:00
GUI : : MessageBox : : show ( window ( ) , " The font file could not be saved. " , " Save failed " , GUI : : MessageBox : : Type : : Error ) ;
2020-07-10 22:20:39 -03:00
return false ;
}
m_path = path ;
2021-04-26 10:11:14 -03:00
m_font_modified = false ;
update_title ( ) ;
2020-07-10 22:20:39 -03:00
return true ;
}
2021-04-06 13:04:21 -03:00
void FontEditorWidget : : set_show_font_metadata ( bool show )
{
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
void FontEditorWidget : : undo ( )
{
if ( ! m_undo_stack - > can_undo ( ) )
return ;
m_undo_stack - > undo ( ) ;
did_change_undo_stack ( ) ;
m_glyph_editor_widget - > update ( ) ;
m_glyph_map_widget - > update ( ) ;
if ( m_font_preview_window )
m_font_preview_window - > update ( ) ;
}
void FontEditorWidget : : redo ( )
{
if ( ! m_undo_stack - > can_redo ( ) )
return ;
m_undo_stack - > redo ( ) ;
did_change_undo_stack ( ) ;
m_glyph_editor_widget - > update ( ) ;
m_glyph_map_widget - > update ( ) ;
if ( m_font_preview_window )
m_font_preview_window - > update ( ) ;
}
void FontEditorWidget : : did_change_undo_stack ( )
{
m_undo_action - > set_enabled ( m_undo_stack - > can_undo ( ) ) ;
m_redo_action - > set_enabled ( m_undo_stack - > can_redo ( ) ) ;
2021-04-26 10:11:14 -03:00
did_modify_font ( ) ;
}
bool FontEditorWidget : : request_close ( )
{
if ( ! m_font_modified )
return true ;
auto result = GUI : : MessageBox : : show ( window ( ) , " Save changes to the current font? " , " Unsaved changes " , GUI : : MessageBox : : Type : : Warning , GUI : : MessageBox : : InputType : : YesNoCancel ) ;
if ( result = = GUI : : MessageBox : : ExecYes ) {
m_save_action - > activate ( ) ;
if ( ! m_font_modified )
return true ;
}
if ( result = = GUI : : MessageBox : : ExecNo )
return true ;
return false ;
}
void FontEditorWidget : : update_title ( )
{
StringBuilder title ;
title . append ( m_path ) ;
if ( m_font_modified & & ! m_font_newly_opened )
title . append ( " (*) " ) ;
title . append ( " - Font Editor " ) ;
if ( window ( ) )
window ( ) - > set_title ( title . to_string ( ) ) ;
}
void FontEditorWidget : : did_modify_font ( )
{
if ( m_font_modified )
return ;
m_font_modified = true ;
update_title ( ) ;
2021-04-22 15:12:53 -03:00
}