#include "settingsactions.hpp" #include "ecode.hpp" #include "version.hpp" namespace ecode { void SettingsActions::checkForUpdatesResponse( Http::Response response, bool fromStartup ) { auto updatesError = [this, fromStartup]() { if ( fromStartup ) return; UIMessageBox* msg = UIMessageBox::New( UIMessageBox::OK, i18n( "error_checking_version", "Failed checking for updates." ) ); msg->setTitle( "Error" ); msg->setCloseShortcut( { KEY_ESCAPE, 0 } ); msg->showWhenReady(); }; if ( response.getStatus() != Http::Response::Status::Ok || response.getBody().empty() ) { updatesError(); return; } auto addStartUpCheckbox = [this]( UIMessageBox* msg ) { msg->setId( "check_for_updates" ); msg->on( Event::OnWindowReady, [this, msg]( const Event* ) { msg->setVisible( false ); UICheckBox* cbox = UICheckBox::New(); cbox->addClass( "check_at_startup" ); cbox->setParent( msg->getLayoutCont()->getFirstChild() ); cbox->setLayoutSizePolicy( SizePolicy::WrapContent, SizePolicy::WrapContent ); cbox->setText( i18n( "check_for_new_updates_at_startup", "Always check for new updates at startup." ) ); cbox->setChecked( mApp->getConfig().workspace.checkForUpdatesAtStartup ); cbox->toPosition( 1 ); cbox->runOnMainThread( [msg]() { msg->setMinWindowSize( msg->getLayoutCont()->getSize() ); msg->center(); msg->show(); } ); cbox->on( Event::OnValueChange, [this, cbox]( const Event* ) { mApp->getConfig().workspace.checkForUpdatesAtStartup = cbox->isChecked(); } ); } ); }; json j; try { j = json::parse( response.getBody(), nullptr, true, true ); if ( j.contains( "tag_name" ) ) { auto tagName( j["tag_name"].get() ); auto versionNum = ecode::Version::getVersionNumFromTag( tagName ); if ( versionNum > ecode::Version::getVersionNum() ) { auto name( j.value( "name", tagName ) ); UIMessageBox* msg = UIMessageBox::New( UIMessageBox::OK_CANCEL, name + i18n( "ecode_updates_available", " is available!\nDo you want to download it now?" ) .unescape() ); auto url( j.value( "html_url", "https://github.com/SpartanJ/ecode/releases/" ) ); msg->on( Event::OnConfirm, [url, msg]( const Event* ) { Engine::instance()->openURI( url ); msg->closeWindow(); } ); msg->setTitle( "ecode" ); msg->setCloseShortcut( { KEY_ESCAPE, 0 } ); addStartUpCheckbox( msg ); } else if ( versionNum < ecode::Version::getVersionNum() ) { if ( fromStartup ) return; UIMessageBox* msg = UIMessageBox::New( UIMessageBox::OK, i18n( "ecode_unreleased_version", "You are running an unreleased version of ecode!\nCurrent version: " ) .unescape() + ecode::Version::getVersionNumString() ); msg->setTitle( "ecode" ); msg->setCloseShortcut( { KEY_ESCAPE, 0 } ); addStartUpCheckbox( msg ); } else { if ( fromStartup ) return; UIMessageBox* msg = UIMessageBox::New( UIMessageBox::OK, i18n( "ecode_no_updates_available", "There are currently no updates available." ) ); msg->setTitle( "ecode" ); msg->setCloseShortcut( { KEY_ESCAPE, 0 } ); addStartUpCheckbox( msg ); } } else { updatesError(); } } catch ( ... ) { updatesError(); } } void SettingsActions::checkForUpdates( bool fromStartup ) { Http::getAsync( [this, fromStartup]( const Http&, Http::Request&, Http::Response& response ) { if ( !SceneManager::existsSingleton() || SceneManager::instance()->isShuttingDown() ) return; mApp->getUISceneNode()->runOnMainThread( [this, response, fromStartup]() { checkForUpdatesResponse( response, fromStartup ); } ); }, "https://api.github.com/repos/SpartanJ/ecode/releases/latest", Seconds( 30 ) ); } void SettingsActions::aboutEcode() { String msg( ecode::Version::getVersionFullName() + " (codename: \"" + ecode::Version::getCodename() + "\")" ); UIMessageBox* msgBox = UIMessageBox::New( UIMessageBox::OK, msg ); UIImage* image = UIImage::New(); image->setParent( msgBox->getContainer()->getFirstChild() ); auto tf = TextureFactory::instance(); Texture* tex = tf->getByName( "ecode-logo" ); if ( tex == nullptr ) { tex = tf->loadFromFile( mApp->resPath() + "icon/ecode.png" ); if ( tex ) tex->setName( "ecode-logo" ); } image->setDrawable( tex ); image->setLayoutGravity( UI_NODE_ALIGN_CENTER ); image->setGravity( UI_NODE_ALIGN_CENTER ); image->setScaleType( UIScaleType::FitInside ); image->setLayoutSizePolicy( SizePolicy::Fixed, SizePolicy::Fixed ); image->setSize( { 128, 128 } ); image->toBack(); msgBox->setTitle( i18n( "about_ecode", "About ecode..." ) ); msgBox->showWhenReady(); } void SettingsActions::ecodeSource() { Engine::instance()->openURI( "https://github.com/SpartanJ/ecode" ); } void SettingsActions::setLineBreakingColumn() { UIMessageBox* msgBox = UIMessageBox::New( UIMessageBox::INPUT, i18n( "set_line_breaking_column", "Set Line Breaking Column:\nSet 0 to disable it.\n" ) .unescape() ); msgBox->setTitle( mApp->getWindowTitle() ); msgBox->setCloseShortcut( { KEY_ESCAPE, 0 } ); msgBox->getTextInput()->setAllowOnlyNumbers( true, false ); msgBox->getTextInput()->setText( String::toString( mApp->getConfig().doc.lineBreakingColumn ) ); msgBox->showWhenReady(); msgBox->on( Event::OnConfirm, [this, msgBox]( const Event* ) { int val; if ( String::fromString( val, msgBox->getTextInput()->getText() ) && val >= 0 ) { mApp->getConfig().doc.lineBreakingColumn = val; mApp->getSplitter()->forEachEditor( [val]( UICodeEditor* editor ) { editor->setLineBreakingColumn( val ); } ); msgBox->closeWindow(); } } ); mApp->setFocusEditorOnClose( msgBox ); } void SettingsActions::setLineSpacing() { UIMessageBox* msgBox = UIMessageBox::New( UIMessageBox::INPUT, i18n( "set_line_spacing", "Set Line Spacing:\nSet 0 to disable it.\n" ).unescape() ); msgBox->setTitle( mApp->getWindowTitle() ); msgBox->setCloseShortcut( { KEY_ESCAPE, 0 } ); msgBox->getTextInput()->setText( mApp->getConfig().editor.lineSpacing.toString() ); msgBox->showWhenReady(); msgBox->on( Event::OnConfirm, [this, msgBox]( const Event* ) { mApp->getConfig().editor.lineSpacing = StyleSheetLength( msgBox->getTextInput()->getText() ); mApp->getSplitter()->forEachEditor( [this]( UICodeEditor* editor ) { editor->setLineSpacing( mApp->getConfig().editor.lineSpacing ); } ); } ); mApp->setFocusEditorOnClose( msgBox ); } void SettingsActions::setCursorBlinkingTime() { UIMessageBox* msgBox = UIMessageBox::New( UIMessageBox::INPUT, i18n( "set_cursor_blinking_time", "Set Cursor Blinking Time:\nSet 0 to disable it.\n" ) .unescape() ); msgBox->setTitle( mApp->getWindowTitle() ); msgBox->setCloseShortcut( { KEY_ESCAPE, 0 } ); msgBox->getTextInput()->setText( mApp->getConfig().editor.cursorBlinkingTime.toString() ); msgBox->showWhenReady(); msgBox->on( Event::OnConfirm, [this, msgBox]( const Event* ) { mApp->getConfig().editor.cursorBlinkingTime = Time::fromString( msgBox->getTextInput()->getText().toUtf8() ); mApp->getSplitter()->forEachEditor( [this]( UICodeEditor* editor ) { editor->setCursorBlinkTime( mApp->getConfig().editor.cursorBlinkingTime ); } ); msgBox->closeWindow(); } ); mApp->setFocusEditorOnClose( msgBox ); } void SettingsActions::setIndentTabCharacter() { UIMessageBox* msgBox = UIMessageBox::New( UIMessageBox::COMBOBOX, i18n( "set_indent_tab_character", "Set the tab indentation guide character displayed." ) ); msgBox->setId( "indent_tab_window" ); msgBox->setTitle( mApp->getWindowTitle() ); msgBox->setCloseShortcut( { KEY_ESCAPE, 0 } ); UIComboBox* comboBox = msgBox->getComboBox(); UIListBox* listBox = msgBox->getComboBox()->getDropDownList()->getListBox(); listBox->addClass( "indent_tab_listbox_item" ); listBox->addListBoxItems( { u8"»", u8"→", u8"⇒", u8"↪", u8"⇢", u8"↣" } ); msgBox->getComboBox()->setText( String::fromUtf8( mApp->getConfig().editor.tabIndentCharacter.empty() ? u8"»" : mApp->getConfig().editor.tabIndentCharacter ) ); msgBox->showWhenReady(); comboBox->on( Event::OnValueChange, [this, comboBox]( const Event* ) { if ( comboBox->getText().size() != 1 ) return; mApp->getSplitter()->forEachEditor( [comboBox]( UICodeEditor* editor ) { editor->setTabIndentCharacter( comboBox->getText()[0] ); } ); } ); msgBox->on( Event::OnConfirm, [this, msgBox]( const Event* ) { auto txt( msgBox->getComboBox()->getText() ); if ( txt.size() == 1 ) { mApp->getConfig().editor.tabIndentCharacter = txt.toUtf8(); mApp->getSplitter()->forEachEditor( [txt]( UICodeEditor* editor ) { editor->setTabIndentCharacter( txt[0] ); } ); msgBox->closeWindow(); } else { UIMessageBox* msgBoxAlert = UIMessageBox::New( UIMessageBox::OK, i18n( "it_must_be_a_single_character", "It must be a single character" ) ); msgBoxAlert->setTitle( mApp->getWindowTitle() ); msgBoxAlert->setCloseShortcut( { KEY_ESCAPE, 0 } ); } } ); msgBox->on( Event::OnCancel, [this]( const Event* ) { String txt = String::fromUtf8( mApp->getConfig().editor.tabIndentCharacter ); if ( txt.size() != 1 ) return; mApp->getSplitter()->forEachEditor( [&txt]( UICodeEditor* editor ) { editor->setTabIndentCharacter( txt[0] ); } ); } ); mApp->setFocusEditorOnClose( msgBox ); } void SettingsActions::setFoldRefreshFreq() { UIMessageBox* msgBox = UIMessageBox::New( UIMessageBox::INPUT, i18n( "set_fold_refresh_frequency", "Set code folds refresh frequency:\nIt should be bigger than 1 second.\nFolds are " "only refreshed after any document modification." ) .unescape() ); msgBox->setTitle( mApp->getWindowTitle() ); msgBox->setCloseShortcut( { KEY_ESCAPE, 0 } ); msgBox->getTextInput()->setText( mApp->getConfig().editor.codeFoldingRefreshFreq.toString() ); msgBox->showWhenReady(); msgBox->on( Event::OnConfirm, [this, msgBox]( const Event* ) { mApp->getConfig().editor.codeFoldingRefreshFreq = Time::fromString( msgBox->getTextInput()->getText().toUtf8() ); if ( mApp->getConfig().editor.codeFoldingRefreshFreq < Seconds( 1 ) ) mApp->getConfig().editor.codeFoldingRefreshFreq = Seconds( 1 ); mApp->getSplitter()->forEachEditor( [this]( UICodeEditor* editor ) { editor->setFoldsRefreshTime( mApp->getConfig().editor.codeFoldingRefreshFreq ); } ); msgBox->closeWindow(); } ); mApp->setFocusEditorOnClose( msgBox ); } void SettingsActions::setUIScaleFactor() { UIMessageBox* msgBox = UIMessageBox::New( UIMessageBox::INPUT, i18n( "set_ui_scale_factor", "Set the UI scale factor (pixel density):\nMinimum value is " "1, and maximum 6. Requires restart." ) ); msgBox->setTitle( mApp->getWindowTitle() ); msgBox->getTextInput()->setText( String::fromFloat( mApp->getConfig().windowState.pixelDensity ) ); msgBox->setCloseShortcut( { KEY_ESCAPE, 0 } ); msgBox->showWhenReady(); msgBox->on( Event::OnConfirm, [this, msgBox]( const Event* ) { msgBox->closeWindow(); Float val; if ( String::fromString( val, msgBox->getTextInput()->getText() ) && val >= 1 && val <= 6 ) { if ( mApp->getConfig().windowState.pixelDensity != val ) { mApp->getConfig().windowState.pixelDensity = val; UIMessageBox* msg = UIMessageBox::New( UIMessageBox::OK, i18n( "new_ui_scale_factor", "New UI scale factor assigned.\nPlease " "restart the application." ) ); msg->showWhenReady(); mApp->setFocusEditorOnClose( msg ); } else if ( mApp->getSplitter() && mApp->getSplitter()->getCurWidget() ) { mApp->getSplitter()->getCurWidget()->setFocus(); } } else { UIMessageBox* msg = UIMessageBox::New( UIMessageBox::OK, "Invalid value!" ); msg->showWhenReady(); mApp->setFocusEditorOnClose( msg ); } } ); } void SettingsActions::setEditorFontSize() { UIMessageBox* msgBox = UIMessageBox::New( UIMessageBox::INPUT, i18n( "set_editor_font_size", "Set the editor font size:" ) ); msgBox->setTitle( mApp->getWindowTitle() ); msgBox->getTextInput()->setText( mApp->getConfig().editor.fontSize.toString() ); msgBox->setCloseShortcut( { KEY_ESCAPE, 0 } ); msgBox->showWhenReady(); msgBox->on( Event::OnConfirm, [this, msgBox]( const Event* ) { mApp->getConfig().editor.fontSize = StyleSheetLength( msgBox->getTextInput()->getText() ); mApp->getSplitter()->forEachEditor( [this]( UICodeEditor* editor ) { editor->setFontSize( mApp->getConfig().editor.fontSize.asPixels( 0, Sizef(), mApp->getDisplayDPI() ) ); } ); } ); mApp->setFocusEditorOnClose( msgBox ); } void SettingsActions::setTerminalFontSize() { UIMessageBox* msgBox = UIMessageBox::New( UIMessageBox::INPUT, i18n( "set_terminal_font_size", "Set the terminal font size:" ) ); msgBox->setTitle( mApp->getWindowTitle() ); msgBox->getTextInput()->setText( mApp->getConfig().term.fontSize.toString() ); msgBox->setCloseShortcut( { KEY_ESCAPE, 0 } ); msgBox->showWhenReady(); msgBox->on( Event::OnConfirm, [this, msgBox]( const Event* ) { mApp->getConfig().term.fontSize = StyleSheetLength( msgBox->getTextInput()->getText() ); mApp->getSplitter()->forEachWidget( [this]( UIWidget* widget ) { if ( widget && widget->isType( UI_TYPE_TERMINAL ) ) widget->asType()->setFontSize( mApp->getConfig().term.fontSize.asPixels( 0, Sizef(), mApp->getDisplayDPI() ) ); } ); } ); mApp->setFocusEditorOnClose( msgBox ); } void SettingsActions::setUIFontSize() { UIMessageBox* msgBox = UIMessageBox::New( UIMessageBox::INPUT, i18n( "set_ui_font_size", "Set the UI font size:" ) ); msgBox->setTitle( mApp->getWindowTitle() ); msgBox->getTextInput()->setText( mApp->getConfig().ui.fontSize.toString() ); msgBox->setCloseShortcut( { KEY_ESCAPE, 0 } ); msgBox->showWhenReady(); msgBox->on( Event::OnConfirm, [this, msgBox]( const Event* ) { mApp->getConfig().ui.fontSize = StyleSheetLength( msgBox->getTextInput()->getText() ); Float fontSize = mApp->getConfig().ui.fontSize.asPixels( 0, Sizef(), mApp->getDisplayDPI() ); UIThemeManager* manager = mApp->getUISceneNode()->getUIThemeManager(); manager->setDefaultFontSize( fontSize ); manager->getDefaultTheme()->setDefaultFontSize( fontSize ); mApp->getUISceneNode()->forEachNode( [this]( Node* node ) { if ( node->isType( UI_TYPE_TEXTVIEW ) ) { UITextView* textView = node->asType(); if ( !textView->getUIStyle()->hasProperty( PropertyId::FontSize ) ) { textView->setFontSize( mApp->getConfig().ui.fontSize.asPixels( node->getParent()->getPixelsSize().getWidth(), Sizef(), mApp->getUISceneNode()->getDPI() ) ); } } } ); msgBox->closeWindow(); } ); mApp->setFocusEditorOnClose( msgBox ); } void SettingsActions::setUIPanelFontSize() { UIMessageBox* msgBox = UIMessageBox::New( UIMessageBox::INPUT, i18n( "set_side_panel_font_size", "Set side panel font size:" ) ); msgBox->setTitle( mApp->getWindowTitle() ); msgBox->getTextInput()->setText( mApp->getConfig().ui.panelFontSize.toString() ); msgBox->setCloseShortcut( { KEY_ESCAPE, 0 } ); msgBox->showWhenReady(); msgBox->on( Event::OnConfirm, [this, msgBox]( const Event* ) { mApp->getConfig().ui.panelFontSize = StyleSheetLength( msgBox->getTextInput()->getText() ); // Update the CSS auto selsFound = mApp->getUISceneNode()->getStyleSheet().findStyleFromSelectorName( "#project_view > treeview::row > treeview::cell > treeview::cell::text" ); if ( !selsFound.empty() ) { for ( auto sel : selsFound ) sel->updatePropertyValue( "font-size", mApp->getConfig().ui.panelFontSize.toString() ); mApp->getUISceneNode()->getStyleSheet().refreshCacheFromStyles( selsFound ); } UITreeView* treeView = mApp->getUISceneNode()->find( "project_view" ); if ( !treeView ) { msgBox->closeWindow(); return; } treeView->reloadStyle( true, true, true, true ); treeView->updateContentSize(); msgBox->closeWindow(); } ); mApp->setFocusEditorOnClose( msgBox ); } String SettingsActions::i18n( const std::string& key, const String& def ) { return mApp->i18n( key, def ); } } // namespace ecode