eterm: extract settings actions and fix macOS efsw linkage

Build:
  - Link eterm with CoreFoundation and CoreServices on macOS
  - Satisfy the framework dependencies required by efsw's FSEvents backend

  Applications:
  - Move eterm settings operations into a dedicated SettingsActions class
  - Centralize settings window lifecycle and font configuration actions
  - Route settings panel font-size updates through SettingsActions
This commit is contained in:
Martín Lucas Golini
2026-09-09 17:06:38 -03:00
parent fe91253276
commit a294d78733
7 changed files with 142 additions and 95 deletions

View File

@@ -1943,6 +1943,9 @@ solution "eepp"
if os.is_real("linux") then
links { "util" }
end
if os.is("macosx") then
links { "CoreFoundation.framework", "CoreServices.framework" }
end
if os.is("haiku") then
links { "bsd" }
end

View File

@@ -1971,6 +1971,8 @@ workspace "eepp"
linkoptions { _MAIN_SCRIPT_DIR .. "/bin/assets/icon/eterm.x64.res" }
filter "system:linux or system:bsd"
links { "util" }
filter "system:macosx"
links { "CoreFoundation.framework", "CoreServices.framework" }
filter "system:haiku"
links { "bsd" }

View File

@@ -1,6 +1,4 @@
#include "eterm.hpp"
#include "settingspanel.hpp"
#include <iostream>
namespace eterm {
@@ -101,70 +99,6 @@ void App::createNewTerminal() {
}
}
void App::openFontPicker( bool uiFont, bool fallbackFont ) {
const Uint32 flags = UIFontPickerDialog::ShowStyle |
( fallbackFont ? 0 : UIFontPickerDialog::ShowSize ) |
( !uiFont && !fallbackFont ? UIFontPickerDialog::MonospaceOnly : 0 );
auto* dialog = UIFontPickerDialog::New( flags );
dialog->setTitle( i18n( "select_font", "Select Font" ) );
dialog->setCloseShortcut( KEY_ESCAPE );
std::string currentPath = uiFont ? config->font.uiPath
: fallbackFont ? config->font.fallbackPath
: config->font.path;
if ( !currentPath.empty() )
dialog->setSelectedFont( currentPath );
if ( !fallbackFont ) {
auto selection = dialog->getSelection();
selection.size = static_cast<Uint32>( uiFont ? config->font.uiSize : config->font.size );
dialog->setSelection( selection );
}
dialog->setOnFontPicked( [this, uiFont, fallbackFont]( const UIFontSelection& selection ) {
if ( selection.font.path.empty() )
return;
auto& resourceScope = *scene->getResourceScope();
if ( uiFont ) {
auto font = FontTrueType::New( "eterm-ui-font", resourceScope );
if ( font->loadFromFile( selection.font.path ) ) {
config->font.uiPath = selection.font.path;
config->font.uiSize = selection.size;
scene->getUIThemeManager()->setDefaultFont( font.get() );
scene->getUIThemeManager()->setDefaultFontSize( config->font.uiSize );
scene->getRoot()->reloadStyle( true, true, true, true, true );
}
} else if ( fallbackFont ) {
auto font = FontTrueType::New( "eterm-fallback-font", resourceScope );
if ( font->loadFromFile( selection.font.path ) ) {
config->font.fallbackPath = selection.font.path;
resourceScope.getFontService().addFallbackFont( std::move( font ) );
}
} else {
auto font = FontTrueType::New( "eterm-monospace", resourceScope );
if ( font->loadFromFile( selection.font.path ) ) {
config->font.path = selection.font.path;
config->font.size = selection.size;
terminalFont = font.get();
terminalFontSize = PixelDensity::dpToPx( config->font.size );
FontFamily::loadFromRegular( terminalFont );
forEachTerminal( [this]( UITerminal* terminal ) {
terminal->setFont( terminalFont );
terminal->setFontSize( terminalFontSize );
} );
}
}
savePreferences();
} );
dialog->show();
}
void App::showSettings() {
if ( settingsWindow ) {
settingsWindow->show();
settingsWindow->toFront();
return;
}
settingsWindow = eterm::SettingsPanel::create( *this );
}
void App::updateWindowTitle() {
if ( !appWindow )
return;
@@ -448,7 +382,7 @@ void App::configureTab( UITab* tab ) {
} else if ( command == "restore-maximized-tab-widget" ) {
restoreMaximizedTabWidget();
} else if ( command == "open-settings" ) {
showSettings();
settingsActions->showSettings();
} else {
terminal->execute( command );
}
@@ -786,6 +720,7 @@ int App::run( int argc, char* argv[] ) {
scene = app.getUI();
if ( !appWindow || !appWindow->isOpen() || !scene )
return EXIT_FAILURE;
settingsActions = std::make_unique<SettingsActions>( this );
keybindingsPath = config->getConfigPath() + "keybindings.cfg";
loadKeybindings();
fileWatcher = std::make_unique<efsw::FileWatcher>();

View File

@@ -1,12 +1,12 @@
#pragma once
#include "appconfig.hpp"
#include "settingsactions.hpp"
#include <args/args.hxx>
#include <atomic>
#include <eepp/core/small_vector.hpp>
#include <eepp/ee.hpp>
#include <eepp/ui/iconmanager.hpp>
#include <eepp/ui/tools/uifontpickerdialog.hpp>
#include <eepp/ui/tools/uisettingspanel.hpp>
#include <eepp/ui/tools/uitabwidgetsplitter.hpp>
#include <eepp/ui/tools/uiwidgetinspector.hpp>
@@ -60,6 +60,7 @@ class App : private efsw::FileWatchListener {
private:
friend struct SettingsPanel;
friend class SettingsActions;
std::string getResourcePath() const;
@@ -100,7 +101,7 @@ class App : private efsw::FileWatchListener {
template <typename T> void registerTabCommands( T& commandTarget, UIWidget* widget ) {
tabSplitter->registerSplitterCommands( commandTarget );
commandTarget.setCommand( "create-new-terminal", [this] { createNewTerminal(); } );
commandTarget.setCommand( "open-settings", [this] { showSettings(); } );
commandTarget.setCommand( "open-settings", [this] { settingsActions->showSettings(); } );
commandTarget.setCommand( "open-keybindings", [this] { openKeybindings(); } );
commandTarget.setCommand( "debug-widget-tree-view",
[this] { UIWidgetInspector::create( scene ); } );
@@ -135,10 +136,6 @@ class App : private efsw::FileWatchListener {
void handleFileAction( efsw::WatchID, const std::string& dir, const std::string& filename,
efsw::Action action, const std::string& oldFilename ) override;
void showSettings();
void openFontPicker( bool uiFont, bool fallbackFont = false );
void forEachTerminal( const std::function<void( UITerminal* )>& fn );
void savePreferences();
@@ -156,7 +153,6 @@ class App : private efsw::FileWatchListener {
FontTrueType* terminalFont{ nullptr };
UIIcon* terminalIcon{ nullptr };
UIMessageBox* closeDialog{ nullptr };
UIWindow* settingsWindow{ nullptr };
UICodeEditor* keybindingsEditor{ nullptr };
UIWidget* closeDialogWidget{ nullptr };
UIWindow* maximizedTabWidgetWindow{ nullptr };
@@ -164,6 +160,7 @@ class App : private efsw::FileWatchListener {
UINodeLink* maximizedTabWidgetLink{ nullptr };
TerminalLaunchConfig terminalConfig;
std::unique_ptr<eterm::AppConfig> config;
std::unique_ptr<SettingsActions> settingsActions;
std::map<std::string, TerminalColorScheme> terminalColorSchemes;
std::unordered_map<std::string, std::string> keybindings;
std::string keybindingsPath;

View File

@@ -0,0 +1,93 @@
#include "settingsactions.hpp"
#include "eterm.hpp"
#include "settingspanel.hpp"
#include <eepp/ui/tools/uifontpickerdialog.hpp>
namespace eterm {
SettingsActions::SettingsActions( App* app ) : mApp( app ) {}
void SettingsActions::showSettings() {
if ( mSettingsWindow ) {
mSettingsWindow->show();
mSettingsWindow->toFront();
return;
}
mSettingsWindow = SettingsPanel::create( *mApp );
mSettingsWindow->on( Event::OnWindowClose,
[this]( const Event* ) { mSettingsWindow = nullptr; } );
}
void SettingsActions::openFontPicker( bool uiFont, bool fallbackFont ) {
const Uint32 flags = UIFontPickerDialog::ShowStyle |
( fallbackFont ? 0 : UIFontPickerDialog::ShowSize ) |
( !uiFont && !fallbackFont ? UIFontPickerDialog::MonospaceOnly : 0 );
auto* dialog = UIFontPickerDialog::New( flags );
dialog->setTitle( mApp->i18n( "select_font", "Select Font" ) );
dialog->setCloseShortcut( KEY_ESCAPE );
std::string currentPath = uiFont ? mApp->config->font.uiPath
: fallbackFont ? mApp->config->font.fallbackPath
: mApp->config->font.path;
if ( !currentPath.empty() )
dialog->setSelectedFont( currentPath );
if ( !fallbackFont ) {
auto selection = dialog->getSelection();
selection.size =
static_cast<Uint32>( uiFont ? mApp->config->font.uiSize : mApp->config->font.size );
dialog->setSelection( selection );
}
dialog->setOnFontPicked( [this, uiFont, fallbackFont]( const UIFontSelection& selection ) {
if ( selection.font.path.empty() )
return;
auto& resourceScope = *mApp->scene->getResourceScope();
if ( uiFont ) {
auto font = FontTrueType::New( "eterm-ui-font", resourceScope );
if ( font->loadFromFile( selection.font.path ) ) {
mApp->config->font.uiPath = selection.font.path;
mApp->config->font.uiSize = selection.size;
mApp->scene->getUIThemeManager()->setDefaultFont( font.get() );
mApp->scene->getUIThemeManager()->setDefaultFontSize( mApp->config->font.uiSize );
mApp->scene->getRoot()->reloadStyle( true, true, true, true, true );
}
} else if ( fallbackFont ) {
auto font = FontTrueType::New( "eterm-fallback-font", resourceScope );
if ( font->loadFromFile( selection.font.path ) ) {
mApp->config->font.fallbackPath = selection.font.path;
resourceScope.getFontService().addFallbackFont( std::move( font ) );
}
} else {
auto font = FontTrueType::New( "eterm-monospace", resourceScope );
if ( font->loadFromFile( selection.font.path ) ) {
mApp->config->font.path = selection.font.path;
mApp->config->font.size = selection.size;
mApp->terminalFont = font.get();
mApp->terminalFontSize = PixelDensity::dpToPx( mApp->config->font.size );
FontFamily::loadFromRegular( mApp->terminalFont );
mApp->forEachTerminal( [this]( UITerminal* terminal ) {
terminal->setFont( mApp->terminalFont );
terminal->setFontSize( mApp->terminalFontSize );
} );
}
}
mApp->savePreferences();
} );
dialog->show();
}
void SettingsActions::setUIFontSize( Float size ) {
mApp->config->font.uiSize = size;
mApp->scene->getUIThemeManager()->setDefaultFontSize( size );
mApp->scene->getRoot()->reloadStyle( true, true, true, true, true );
mApp->savePreferences();
}
void SettingsActions::setTerminalFontSize( Float size ) {
mApp->config->font.size = size;
mApp->terminalFontSize = PixelDensity::dpToPx( size );
mApp->forEachTerminal(
[this]( UITerminal* terminal ) { terminal->setFontSize( mApp->terminalFontSize ); } );
mApp->savePreferences();
}
} // namespace eterm

View File

@@ -0,0 +1,29 @@
#pragma once
#include <eepp/ee.hpp>
using namespace EE;
using namespace EE::UI;
namespace eterm {
class App;
class SettingsActions {
public:
explicit SettingsActions( App* app );
void showSettings();
void openFontPicker( bool uiFont, bool fallbackFont = false );
void setUIFontSize( Float size );
void setTerminalFontSize( Float size );
private:
App* mApp{ nullptr };
UIWindow* mSettingsWindow{ nullptr };
};
} // namespace eterm

View File

@@ -54,40 +54,31 @@ UIWindow* SettingsPanel::create( App& app ) {
{ "uiFont", "appearance.fonts",
app.i18n( "ui_font_and_size_ellipsis", "UI Font & Size..." ),
app.i18n( "ui_font_desc", "Choose the proportional font used by the interface." ) },
app.i18n( "choose_font", "Choose Font..." ), [&app] { app.openFontPicker( true ); } );
app.i18n( "choose_font", "Choose Font..." ),
[&app] { app.settingsActions->openFontPicker( true ); } );
panel->addAction(
{ "terminalFont", "appearance.fonts",
app.i18n( "terminal_font_and_size_ellipsis", "Terminal Font & Size..." ),
app.i18n( "terminal_font_desc", "Choose the monospace font used by terminals." ) },
app.i18n( "choose_font", "Choose Font..." ), [&app] { app.openFontPicker( false ); } );
app.i18n( "choose_font", "Choose Font..." ),
[&app] { app.settingsActions->openFontPicker( false ); } );
panel->addAction(
{ "fallbackFont", "appearance.fonts",
app.i18n( "fallback_font_ellipsis", "Fallback Font..." ),
app.i18n( "fallback_font_desc", "Choose the font used for missing glyphs." ) },
app.i18n( "choose_font", "Choose Font..." ),
[&app] { app.openFontPicker( false, true ); } );
[&app] { app.settingsActions->openFontPicker( false, true ); } );
panel->addFloat(
{ "uiFontSize", "appearance.fonts", app.i18n( "ui_font_size", "UI Font Size" ),
app.i18n( "ui_font_size_desc", "Set the font size used by the application UI." ) },
6, 72, 0.5, [&app] { return app.config->font.uiSize; },
[&app]( double value ) {
app.config->font.uiSize = value;
app.scene->getUIThemeManager()->setDefaultFontSize( value );
app.scene->getRoot()->reloadStyle( true, true, true, true, true );
app.savePreferences();
} );
[&app]( double value ) { app.settingsActions->setUIFontSize( value ); } );
panel->addFloat(
{ "terminalFontSize", "appearance.fonts",
app.i18n( "terminal_font_size", "Terminal Font Size" ),
app.i18n( "terminal_font_size_desc", "Set the default terminal font size." ) },
6, 72, 0.5, [&app] { return app.config->font.size; },
[&app]( double value ) {
app.config->font.size = value;
app.terminalFontSize = PixelDensity::dpToPx( value );
app.forEachTerminal(
[&app]( UITerminal* terminal ) { terminal->setFontSize( app.terminalFontSize ); } );
app.savePreferences();
} );
[&app]( double value ) { app.settingsActions->setTerminalFontSize( value ); } );
panel->addFloat(
{ "uiScaleFactor", "appearance.fonts", app.i18n( "ui_scale_factor", "UI Scale Factor" ),
app.i18n( "ui_scale_factor_desc",
@@ -448,14 +439,11 @@ UIWindow* SettingsPanel::create( App& app ) {
} );
panel->build();
settingsWindow->setKeyBindingCommand( "closeWindow", [&app] {
if ( app.settingsWindow )
app.settingsWindow->closeWindow();
} );
settingsWindow->setKeyBindingCommand( "closeWindow",
[settingsWindow] { settingsWindow->closeWindow(); } );
settingsWindow->getKeyBindings().addKeybind( { KEY_ESCAPE }, "closeWindow" );
settingsWindow->on( Event::OnWindowClose, [&app]( const Event* ) {
app.savePreferences();
app.settingsWindow = nullptr;
if ( app.tabSplitter && app.tabSplitter->getCurWidget() )
app.tabSplitter->getCurWidget()->setFocus();
} );