mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-08-14 13:15:14 +03:00
Implemented UIFontPickerDialog.
Fixed alignment in UILinearLayout when padding is used.
This commit is contained in:
@@ -381,6 +381,12 @@
|
||||
"command": "${project_root}/bin/eepp-ui-html-debug",
|
||||
"name": "eepp-ui-html-debug",
|
||||
"working_dir": "${project_root}/bin"
|
||||
},
|
||||
{
|
||||
"args": "",
|
||||
"command": "${project_root}/bin/eepp-ui-font-picker-debug",
|
||||
"name": "eepp-ui-font-picker-debug",
|
||||
"working_dir": "${project_root}/bin"
|
||||
}
|
||||
],
|
||||
"var": {
|
||||
|
||||
@@ -35,6 +35,8 @@ class EE_API FontTrueType : public Font {
|
||||
|
||||
const Font::Info& getInfo() const;
|
||||
|
||||
const Uint32& getFaceIndex() const { return mFaceIndex; }
|
||||
|
||||
Glyph getGlyph( Uint32 codePoint, unsigned int characterSize, bool bold, bool italic,
|
||||
Float outlineThickness = 0 ) const;
|
||||
|
||||
|
||||
@@ -131,6 +131,7 @@ class EE_API Event {
|
||||
OnFocusWithin,
|
||||
OnFocusWithinLoss,
|
||||
OnItemsCountChange,
|
||||
OnApply,
|
||||
NoEvent = eeINDEX_NOT_FOUND
|
||||
};
|
||||
|
||||
|
||||
@@ -74,6 +74,7 @@
|
||||
#include <eepp/ui/tools/uicolorpicker.hpp>
|
||||
#include <eepp/ui/tools/uidiffview.hpp>
|
||||
#include <eepp/ui/tools/uidocfindreplace.hpp>
|
||||
#include <eepp/ui/tools/uifontpickerdialog.hpp>
|
||||
#include <eepp/ui/tools/uiimageviewer.hpp>
|
||||
#include <eepp/ui/tools/uiwidgetinspector.hpp>
|
||||
#include <eepp/ui/uiapplication.hpp>
|
||||
@@ -141,7 +142,6 @@
|
||||
#include <eepp/ui/uiscrollablewidget.hpp>
|
||||
#include <eepp/ui/uiscrollbar.hpp>
|
||||
#include <eepp/ui/uiscrollview.hpp>
|
||||
#include <eepp/ui/uiwebview.hpp>
|
||||
#include <eepp/ui/uiselectbutton.hpp>
|
||||
#include <eepp/ui/uiskin.hpp>
|
||||
#include <eepp/ui/uiskinstate.hpp>
|
||||
@@ -172,6 +172,7 @@
|
||||
#include <eepp/ui/uitouchdraggablewidget.hpp>
|
||||
#include <eepp/ui/uitreeview.hpp>
|
||||
#include <eepp/ui/uiviewpager.hpp>
|
||||
#include <eepp/ui/uiwebview.hpp>
|
||||
#include <eepp/ui/uiwidget.hpp>
|
||||
#include <eepp/ui/uiwidgetcreator.hpp>
|
||||
#include <eepp/ui/uiwidgettable.hpp>
|
||||
|
||||
192
include/eepp/ui/tools/uifontpickerdialog.hpp
Normal file
192
include/eepp/ui/tools/uifontpickerdialog.hpp
Normal file
@@ -0,0 +1,192 @@
|
||||
#ifndef EE_UI_TOOLS_UIFONTPICKERDIALOG_HPP
|
||||
#define EE_UI_TOOLS_UIFONTPICKERDIALOG_HPP
|
||||
|
||||
#include <atomic>
|
||||
#include <eepp/graphics/systemfontresolver.hpp>
|
||||
#include <eepp/system/color.hpp>
|
||||
#include <eepp/ui/keyboardshortcut.hpp>
|
||||
#include <eepp/ui/models/model.hpp>
|
||||
#include <eepp/ui/uiwindow.hpp>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace EE { namespace UI {
|
||||
class UICheckBox;
|
||||
class UIFileDialog;
|
||||
class UILoader;
|
||||
class UIListView;
|
||||
class UIPushButton;
|
||||
class UITextInput;
|
||||
class UITextView;
|
||||
}} // namespace EE::UI
|
||||
|
||||
namespace EE { namespace UI { namespace Tools {
|
||||
|
||||
class UIColorPicker;
|
||||
|
||||
struct UIFontSelection {
|
||||
FontDesc font;
|
||||
Uint32 size{ 12 };
|
||||
bool underline{ false };
|
||||
bool strikeThrough{ false };
|
||||
bool antialiasing{ true };
|
||||
Color color{ Color::White };
|
||||
};
|
||||
|
||||
class EE_API UIFontPickerDialog : public UIWindow {
|
||||
public:
|
||||
using FontPickedCb = std::function<void( const UIFontSelection& )>;
|
||||
|
||||
enum Flags {
|
||||
MonospaceOnly = 1 << 0,
|
||||
ShowSize = 1 << 1,
|
||||
ShowEffects = 1 << 2,
|
||||
ShowColor = 1 << 3,
|
||||
ShowApplyButton = 1 << 4,
|
||||
DefaultFlags = ShowSize | ShowEffects | ShowColor,
|
||||
};
|
||||
|
||||
struct FontStyleEntry {
|
||||
std::string label;
|
||||
FontDesc desc;
|
||||
};
|
||||
|
||||
static UIFontPickerDialog* New( Uint32 flags = DefaultFlags );
|
||||
|
||||
virtual ~UIFontPickerDialog();
|
||||
|
||||
virtual Uint32 getType() const;
|
||||
|
||||
virtual bool isType( const Uint32& type ) const;
|
||||
|
||||
virtual void setTheme( UITheme* theme );
|
||||
|
||||
void setSelectedFont( const FontDesc& desc );
|
||||
|
||||
void setSelectedFont( const std::string& path, Uint32 faceIndex = 0 );
|
||||
|
||||
const UIFontSelection& getSelection() const;
|
||||
|
||||
void setSelection( const UIFontSelection& selection );
|
||||
|
||||
void setOnFontPicked( FontPickedCb cb );
|
||||
|
||||
UIPushButton* getButtonOK() const;
|
||||
|
||||
UIPushButton* getButtonCancel() const;
|
||||
|
||||
UIPushButton* getButtonApply() const;
|
||||
|
||||
UIPushButton* getButtonBrowse() const;
|
||||
|
||||
UITextInput* getSearchInput() const;
|
||||
|
||||
UIListView* getFamilyList() const;
|
||||
|
||||
UIListView* getStyleList() const;
|
||||
|
||||
UIListView* getSizeList() const;
|
||||
|
||||
const KeyBindings::Shortcut& getCloseShortcut() const;
|
||||
|
||||
void setCloseShortcut( const KeyBindings::Shortcut& closeShortcut );
|
||||
|
||||
virtual bool show();
|
||||
|
||||
protected:
|
||||
Uint32 mFlags{ DefaultFlags };
|
||||
KeyBindings::Shortcut mCloseShortcut{ KEY_UNKNOWN };
|
||||
UIFontSelection mSelection;
|
||||
FontPickedCb mFontPickedCb;
|
||||
std::vector<FontDesc> mFonts;
|
||||
std::vector<std::string> mFamilies;
|
||||
std::vector<FontStyleEntry> mStyles;
|
||||
std::vector<Uint32> mSizes;
|
||||
std::shared_ptr<Models::Model> mFamilyModel;
|
||||
std::shared_ptr<Models::Model> mStyleModel;
|
||||
std::shared_ptr<Models::Model> mSizeModel;
|
||||
UIWidget* mFontContent{ nullptr };
|
||||
UILoader* mFontLoader{ nullptr };
|
||||
UITextInput* mSearchInput{ nullptr };
|
||||
UIListView* mFamilyList{ nullptr };
|
||||
UIListView* mStyleList{ nullptr };
|
||||
UIListView* mSizeList{ nullptr };
|
||||
UITextView* mPreviewText{ nullptr };
|
||||
UITextInput* mPreviewInput{ nullptr };
|
||||
UITextView* mDetailsText{ nullptr };
|
||||
UIColorPicker* mColorPicker{ nullptr };
|
||||
UIFileDialog* mBrowseDialog{ nullptr };
|
||||
Uint32 mColorPickerCloseCb{ 0 };
|
||||
Uint32 mBrowseDialogCloseCb{ 0 };
|
||||
Uint32 mBrowseDialogOpenCb{ 0 };
|
||||
UICheckBox* mMonospaceOnly{ nullptr };
|
||||
UICheckBox* mAntialiasing{ nullptr };
|
||||
UICheckBox* mUnderline{ nullptr };
|
||||
UICheckBox* mStrikeThrough{ nullptr };
|
||||
UIPushButton* mColorButton{ nullptr };
|
||||
UIPushButton* mButtonOK{ nullptr };
|
||||
UIPushButton* mButtonCancel{ nullptr };
|
||||
UIPushButton* mButtonApply{ nullptr };
|
||||
UIPushButton* mButtonBrowse{ nullptr };
|
||||
bool mUpdating{ false };
|
||||
bool mLoadingFonts{ false };
|
||||
Uint64 mLoadFontsTaskId{ 0 };
|
||||
|
||||
struct LoadFontsRequest {
|
||||
std::atomic<bool> alive{ true };
|
||||
std::atomic<UIFontPickerDialog*> dialog{ nullptr };
|
||||
};
|
||||
std::shared_ptr<LoadFontsRequest> mLoadFontsRequest;
|
||||
|
||||
UIFontPickerDialog( Uint32 flags = DefaultFlags );
|
||||
|
||||
virtual void onWindowReady();
|
||||
|
||||
virtual Uint32 onKeyUp( const KeyEvent& event );
|
||||
|
||||
virtual Uint32 onMessage( const NodeMessage* msg );
|
||||
|
||||
void loadWidgets();
|
||||
|
||||
void loadFonts();
|
||||
|
||||
void setFonts( std::vector<FontDesc> fonts );
|
||||
|
||||
void sortFonts();
|
||||
|
||||
void setFontsLoading( bool loading );
|
||||
|
||||
void updateFamilies();
|
||||
|
||||
void updateStyles();
|
||||
|
||||
void updateSelectionFromLists();
|
||||
|
||||
void updatePreview();
|
||||
|
||||
void selectInitialRows();
|
||||
|
||||
void selectFamily( const std::string& family );
|
||||
|
||||
void selectStyle( const FontDesc& desc );
|
||||
|
||||
void selectSize( Uint32 size );
|
||||
|
||||
void emitPicked();
|
||||
|
||||
void pickColor();
|
||||
|
||||
void browseFont();
|
||||
|
||||
bool addExternalFont( const std::string& path, Uint32 faceIndex = 0 );
|
||||
|
||||
void clearBrowseDialog();
|
||||
|
||||
bool wantsMonospaceOnly() const;
|
||||
};
|
||||
|
||||
}}} // namespace EE::UI::Tools
|
||||
|
||||
#endif
|
||||
@@ -138,6 +138,7 @@ enum UINodeType {
|
||||
UI_TYPE_WEBVIEW,
|
||||
UI_TYPE_SVG,
|
||||
UI_TYPE_TEXTNODE,
|
||||
UI_TYPE_FONTPICKERDIALOG,
|
||||
UI_TYPE_MODULES = 10000,
|
||||
UI_TYPE_TERMINAL = 10001,
|
||||
UI_TYPE_USER = 200000,
|
||||
|
||||
@@ -1669,6 +1669,12 @@ solution "eepp"
|
||||
files { "src/examples/ui_application_hello_world/*.cpp" }
|
||||
build_link_configuration( "eepp-ui-application-hello-world", true )
|
||||
|
||||
project "eepp-ui-font-picker"
|
||||
set_kind()
|
||||
language "C++"
|
||||
files { "src/examples/ui_font_picker/*.cpp" }
|
||||
build_link_configuration( "eepp-ui-font-picker", true )
|
||||
|
||||
project "eepp-ui-dropdownmodellist"
|
||||
set_kind()
|
||||
language "C++"
|
||||
|
||||
@@ -1662,6 +1662,12 @@ workspace "eepp"
|
||||
files { "src/examples/ui_application_hello_world/*.cpp" }
|
||||
build_link_configuration( "eepp-ui-application-hello-world", true )
|
||||
|
||||
project "eepp-ui-font-picker"
|
||||
set_kind()
|
||||
language "C++"
|
||||
files { "src/examples/ui_font_picker/*.cpp" }
|
||||
build_link_configuration( "eepp-ui-font-picker", true )
|
||||
|
||||
project "eepp-ui-dropdownmodellist"
|
||||
set_kind()
|
||||
language "C++"
|
||||
|
||||
@@ -111,7 +111,8 @@ FontTrueType* FontManager::getOrLoadSystemFallbackFont( const FontDesc& desc ) {
|
||||
for ( auto* font : mSystemFallbackFonts ) {
|
||||
if ( font->getType() == FontType::TTF ) {
|
||||
auto* ttf = static_cast<FontTrueType*>( font );
|
||||
if ( ttf->getInfo().fontpath + ttf->getInfo().filename == desc.path )
|
||||
if ( ttf->getInfo().fontpath + ttf->getInfo().filename == desc.path &&
|
||||
ttf->getFaceIndex() == desc.faceIndex )
|
||||
return ttf;
|
||||
}
|
||||
}
|
||||
|
||||
845
src/eepp/ui/tools/uifontpickerdialog.cpp
Normal file
845
src/eepp/ui/tools/uifontpickerdialog.cpp
Normal file
@@ -0,0 +1,845 @@
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <eepp/graphics/fontmanager.hpp>
|
||||
#include <eepp/graphics/fonttruetype.hpp>
|
||||
#include <eepp/graphics/text.hpp>
|
||||
#include <eepp/scene/scenemanager.hpp>
|
||||
#include <eepp/system/filesystem.hpp>
|
||||
#include <eepp/system/threadpool.hpp>
|
||||
#include <eepp/ui/abstract/uiabstractview.hpp>
|
||||
#include <eepp/ui/css/stylesheetparser.hpp>
|
||||
#include <eepp/ui/models/itemlistmodel.hpp>
|
||||
#include <eepp/ui/models/model.hpp>
|
||||
#include <eepp/ui/tools/uicolorpicker.hpp>
|
||||
#include <eepp/ui/tools/uifontpickerdialog.hpp>
|
||||
#include <eepp/ui/uicheckbox.hpp>
|
||||
#include <eepp/ui/uifiledialog.hpp>
|
||||
#include <eepp/ui/uilistview.hpp>
|
||||
#include <eepp/ui/uiloader.hpp>
|
||||
#include <eepp/ui/uipushbutton.hpp>
|
||||
#include <eepp/ui/uiscenenode.hpp>
|
||||
#include <eepp/ui/uitextinput.hpp>
|
||||
#include <eepp/ui/uitextview.hpp>
|
||||
#include <eepp/ui/uitheme.hpp>
|
||||
#include <eepp/ui/uithememanager.hpp>
|
||||
#include <set>
|
||||
|
||||
using namespace EE::UI::Abstract;
|
||||
using namespace EE::UI::Models;
|
||||
|
||||
namespace EE { namespace UI { namespace Tools {
|
||||
|
||||
static const Uint32 FONT_PICKER_STYLE_MARKER = String::hash( "UIFontPickerDialog" );
|
||||
|
||||
static const char* FONT_PICKER_STYLE = R"css(
|
||||
#font_picker {
|
||||
margin: 8dp;
|
||||
clip: none;
|
||||
}
|
||||
#font_picker .column_label {
|
||||
margin-bottom: 4dp;
|
||||
}
|
||||
#font_picker .footer {
|
||||
margin-top: 8dp;
|
||||
clip: none;
|
||||
}
|
||||
#font_picker .preview_text {
|
||||
padding-left: 24dp;
|
||||
padding-right: 24dp;
|
||||
word-wrap: true;
|
||||
}
|
||||
#font_picker .details {
|
||||
margin-top: 4dp;
|
||||
}
|
||||
#font_picker PushButton.footer_button {
|
||||
min-width: 80dp;
|
||||
margin-left: 8dp;
|
||||
}
|
||||
#font_picker .separator {
|
||||
background-color: #FFFFFF44;
|
||||
}
|
||||
#font_picker .color_button {
|
||||
min-width: 48dp;
|
||||
}
|
||||
#font_picker .options_panel {
|
||||
background-color: var(--list-back);
|
||||
border-color: var(--button-border);
|
||||
border-radius: var(--button-radius);
|
||||
border-width: var(--border-width);
|
||||
padding-bottom: 4dp;
|
||||
padding-left: 8dp;
|
||||
padding-right: 8dp;
|
||||
padding-top: 4dp;
|
||||
}
|
||||
)css";
|
||||
|
||||
static const char* FONT_PICKER_LAYOUT = R"xml(
|
||||
<LinearLayout id="font_picker" orientation="vertical" layout_width="match_parent" layout_height="match_parent" clip="none">
|
||||
<LinearLayout orientation="horizontal" layout_width="match_parent" layout_height="wrap_content">
|
||||
<TextInput id="search_input" layout_width="0dp" layout_weight="1" layout_height="match_parent" />
|
||||
<PushButton id="browse_button" layout_width="wrap_content" layout_height="wrap_content" margin-left="8dp" text='@string(font_picker_browse_ellipsis, "Browse...")' />
|
||||
</LinearLayout>
|
||||
<RelativeLayout layout_width="match_parent" layout_height="0dp" layout_weight="1" margin-top="8dp">
|
||||
<LinearLayout id="font_content" orientation="horizontal" layout_width="match_parent" layout_height="match_parent">
|
||||
<LinearLayout orientation="vertical" layout_width="0dp" layout_weight="0.28" layout_height="match_parent">
|
||||
<TextView class="column_label" layout_width="match_parent" layout_height="wrap_content" text='@string(font_picker_font_family, "Font Family")' />
|
||||
<ListView id="family_list" layout_width="match_parent" layout_height="0dp" layout_weight="1" />
|
||||
</LinearLayout>
|
||||
<LinearLayout orientation="vertical" layout_width="0dp" layout_weight="0.18" layout_height="match_parent" margin-left="8dp">
|
||||
<TextView class="column_label" layout_width="match_parent" layout_height="wrap_content" text='@string(font_picker_style, "Style")' />
|
||||
<ListView id="style_list" layout_width="match_parent" layout_height="0dp" layout_weight="1" />
|
||||
</LinearLayout>
|
||||
<LinearLayout id="size_column" orientation="vertical" layout_width="120dp" layout_height="match_parent" margin-left="8dp">
|
||||
<TextView class="column_label" layout_width="match_parent" layout_height="wrap_content" text='@string(font_picker_size, "Size")' />
|
||||
<ListView id="size_list" layout_width="match_parent" layout_height="0dp" layout_weight="1" />
|
||||
</LinearLayout>
|
||||
<LinearLayout orientation="vertical" layout_width="0dp" layout_weight="0.54" layout_height="match_parent" margin-left="8dp">
|
||||
<TextView class="column_label" layout_width="match_parent" layout_height="wrap_content" text='@string(font_picker_preview, "Preview")' />
|
||||
<TextView id="preview_text" class="preview_text" layout_width="match_parent" layout_height="0dp" layout_weight="1" text='The quick brown fox jumps over the lazy dog' gravity="center" />
|
||||
<TextInput id="preview_input" layout_width="match_parent" layout_height="28dp" margin-top="8dp" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
<Loader id="font_loader" lw="64dp" lh="64dp" outline-thickness="6dp" lg="center" visible="false" />
|
||||
</RelativeLayout>
|
||||
<LinearLayout id="options_row" class="options_panel" orientation="horizontal" layout_width="match_parent" layout_height="wrap_content" margin-top="8dp">
|
||||
<CheckBox id="monospace_only" layout_width="wrap_content" layout_height="wrap_content" layout_gravity="center" text='@string(font_picker_monospace_only, "Monospace only")' />
|
||||
<CheckBox id="antialiasing" layout_width="wrap_content" layout_height="wrap_content" layout_gravity="center" margin-left="16dp" text='@string(font_picker_antialiasing, "Antialiasing")' />
|
||||
<CheckBox id="underline" layout_width="wrap_content" layout_height="wrap_content" layout_gravity="center" margin-left="16dp" text='@string(font_picker_underline, "Underline")' />
|
||||
<CheckBox id="strike_through" layout_width="wrap_content" layout_height="wrap_content" layout_gravity="center" margin-left="16dp" text='@string(font_picker_strikeout, "Strikeout")' />
|
||||
<Widget class="separator" layout_width="1dp" layout_height="match_parent" layout_gravity="center" margin-left="16dp" />
|
||||
<TextView id="color_label" layout_width="wrap_content" layout_height="wrap_content" layout_gravity="center" margin-left="16dp" text='@string(font_picker_color, "Color:")' gravity="center" />
|
||||
<PushButton id="color_button" class="color_button" layout_width="48dp" layout_height="wrap_content" layout_gravity="center" margin-left="8dp" />
|
||||
</LinearLayout>
|
||||
<TextView id="details_text" class="details" layout_width="match_parent" layout_height="wrap_content" text="" />
|
||||
<LinearLayout class="footer" orientation="horizontal" layout_width="match_parent" layout_height="wrap_content" clip="none">
|
||||
<Widget layout_width="0dp" layout_weight="1" layout_height="1dp" />
|
||||
<PushButton id="cancel_button" class="footer_button" layout_width="80dp" layout_height="wrap_content" text='@string(msg_box_cancel, "Cancel")' />
|
||||
<PushButton id="apply_button" class="footer_button" layout_width="80dp" layout_height="wrap_content" text='@string(msg_box_apply, "Apply")' />
|
||||
<PushButton id="ok_button" class="footer_button" layout_width="80dp" layout_height="wrap_content" text='@string(msg_box_ok, "Ok")' />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
)xml";
|
||||
|
||||
class StyleListModel final : public Model {
|
||||
public:
|
||||
explicit StyleListModel( const std::vector<UIFontPickerDialog::FontStyleEntry>* data ) :
|
||||
mData( data ) {}
|
||||
|
||||
size_t rowCount( const ModelIndex& ) const override { return mData ? mData->size() : 0; }
|
||||
|
||||
size_t columnCount( const ModelIndex& ) const override { return 1; }
|
||||
|
||||
ModelIndex index( int row, int column,
|
||||
const ModelIndex& parent = ModelIndex() ) const override {
|
||||
if ( row >= static_cast<int>( rowCount( parent ) ) || column >= 1 )
|
||||
return {};
|
||||
return Model::index( row, column, parent );
|
||||
}
|
||||
|
||||
Variant data( const ModelIndex& index, ModelRole role = ModelRole::Display ) const override {
|
||||
if ( role == ModelRole::Display && mData &&
|
||||
index.row() < static_cast<Int64>( mData->size() ) )
|
||||
return Variant( ( *mData )[index.row()].label );
|
||||
return {};
|
||||
}
|
||||
|
||||
private:
|
||||
const std::vector<UIFontPickerDialog::FontStyleEntry>* mData{ nullptr };
|
||||
};
|
||||
|
||||
static Uint64 loadFontsTaskTag( const UIFontPickerDialog* dialog ) {
|
||||
return reinterpret_cast<Uint64>( dialog );
|
||||
}
|
||||
|
||||
static std::string styleLabel( const FontDesc& desc ) {
|
||||
std::string label;
|
||||
if ( desc.weight == FontWeight::Normal ) {
|
||||
label = desc.italic ? "Italic" : "Regular";
|
||||
} else {
|
||||
label = Text::fontWeightToString( desc.weight );
|
||||
std::replace( label.begin(), label.end(), '-', ' ' );
|
||||
if ( !label.empty() ) {
|
||||
label[0] = static_cast<char>( std::toupper( label[0] ) );
|
||||
for ( size_t i = 1; i < label.size(); i++ ) {
|
||||
if ( label[i - 1] == ' ' )
|
||||
label[i] = static_cast<char>( std::toupper( label[i] ) );
|
||||
}
|
||||
}
|
||||
if ( desc.italic )
|
||||
label += " Italic";
|
||||
}
|
||||
if ( desc.faceIndex != 0 )
|
||||
label += " #" + String::toString( desc.faceIndex );
|
||||
return label;
|
||||
}
|
||||
|
||||
static Uint32 styleFlags( const UIFontSelection& selection ) {
|
||||
Uint32 style = selection.font.italic ? Text::Italic : Text::Regular;
|
||||
if ( selection.font.weight >= FontWeight::SemiBold )
|
||||
style |= Text::Bold;
|
||||
if ( selection.underline )
|
||||
style |= Text::Underlined;
|
||||
if ( selection.strikeThrough )
|
||||
style |= Text::StrikeThrough;
|
||||
return style;
|
||||
}
|
||||
|
||||
UIFontPickerDialog* UIFontPickerDialog::New( Uint32 flags ) {
|
||||
return eeNew( UIFontPickerDialog, ( flags ) );
|
||||
}
|
||||
|
||||
UIFontPickerDialog::UIFontPickerDialog( Uint32 flags ) : UIWindow(), mFlags( flags ) {
|
||||
mVisible = false;
|
||||
mStyleConfig.WinFlags = UI_WIN_DEFAULT_FLAGS | UI_WIN_MAXIMIZE_BUTTON | UI_WIN_MODAL;
|
||||
updateWinFlags();
|
||||
|
||||
mSizes = { 8, 9, 10, 11, 12, 14, 16, 18, 20, 24, 32, 48, 64, 72 };
|
||||
mSelection.size = 12;
|
||||
|
||||
setTitle( i18n( "font_picker_select_font", "Select Font" ) );
|
||||
|
||||
const Sizef sceneSize( getUISceneNode()->getSize() );
|
||||
const Sizef maxSize( eemax( 320.f, sceneSize.getWidth() - PixelDensity::dpToPx( 32 ) ),
|
||||
eemax( 320.f, sceneSize.getHeight() - PixelDensity::dpToPx( 32 ) ) );
|
||||
setMinWindowSize(
|
||||
Sizef( eemin( 720.f, maxSize.getWidth() ), eemin( 440.f, maxSize.getHeight() ) ) );
|
||||
setSizeWithDecoration(
|
||||
Sizef( eemin( 940.f, maxSize.getWidth() ), eemin( 620.f, maxSize.getHeight() ) ) );
|
||||
|
||||
loadWidgets();
|
||||
if ( getUISceneNode()->getUIThemeManager()->getDefaultTheme() )
|
||||
setTheme( getUISceneNode()->getUIThemeManager()->getDefaultTheme() );
|
||||
selectInitialRows();
|
||||
loadFonts();
|
||||
}
|
||||
|
||||
UIFontPickerDialog::~UIFontPickerDialog() {
|
||||
if ( mLoadFontsRequest ) {
|
||||
mLoadFontsRequest->alive = false;
|
||||
mLoadFontsRequest->dialog.store( nullptr );
|
||||
}
|
||||
if ( mLoadFontsTaskId && getUISceneNode()->hasThreadPool() )
|
||||
getUISceneNode()->getThreadPool()->removeWithTag( loadFontsTaskTag( this ) );
|
||||
if ( mColorPicker && mColorPickerCloseCb )
|
||||
mColorPicker->getUIWindow()->removeEventListener( mColorPickerCloseCb );
|
||||
if ( mColorPicker && !SceneManager::instance()->isShuttingDown() )
|
||||
mColorPicker->closePicker();
|
||||
mColorPicker = nullptr;
|
||||
mColorPickerCloseCb = 0;
|
||||
clearBrowseDialog();
|
||||
}
|
||||
|
||||
Uint32 UIFontPickerDialog::getType() const {
|
||||
return UI_TYPE_FONTPICKERDIALOG;
|
||||
}
|
||||
|
||||
bool UIFontPickerDialog::isType( const Uint32& type ) const {
|
||||
return type == UI_TYPE_FONTPICKERDIALOG ? true : UIWindow::isType( type );
|
||||
}
|
||||
|
||||
void UIFontPickerDialog::setTheme( UITheme* theme ) {
|
||||
UIWindow::setTheme( theme );
|
||||
|
||||
if ( mButtonOK ) {
|
||||
if ( Drawable* icon =
|
||||
getUISceneNode()->findIconDrawable( "ok", PixelDensity::dpToPxI( 16 ) ) )
|
||||
mButtonOK->setIcon( icon );
|
||||
}
|
||||
|
||||
if ( mButtonCancel ) {
|
||||
if ( Drawable* icon =
|
||||
getUISceneNode()->findIconDrawable( "cancel", PixelDensity::dpToPxI( 16 ) ) )
|
||||
mButtonCancel->setIcon( icon );
|
||||
}
|
||||
|
||||
if ( mButtonBrowse ) {
|
||||
if ( Drawable* icon = getUISceneNode()->findIconDrawable( "document-open",
|
||||
PixelDensity::dpToPxI( 16 ) ) )
|
||||
mButtonBrowse->setIcon( icon );
|
||||
}
|
||||
|
||||
onThemeLoaded();
|
||||
}
|
||||
|
||||
void UIFontPickerDialog::loadWidgets() {
|
||||
UISceneNode* sceneNode = getUISceneNode();
|
||||
if ( !sceneNode->getStyleSheet().markerExists( FONT_PICKER_STYLE_MARKER ) ) {
|
||||
CSS::StyleSheetParser parser;
|
||||
parser.loadFromString( std::string_view{ FONT_PICKER_STYLE } );
|
||||
parser.getStyleSheet().setMarker( FONT_PICKER_STYLE_MARKER );
|
||||
sceneNode->combineStyleSheet( parser.getStyleSheet() );
|
||||
}
|
||||
|
||||
UIWidget* root = sceneNode->loadLayoutFromString( FONT_PICKER_LAYOUT, mContainer );
|
||||
root->bind( "font_content", mFontContent );
|
||||
root->bind( "font_loader", mFontLoader );
|
||||
root->bind( "search_input", mSearchInput );
|
||||
root->bind( "family_list", mFamilyList );
|
||||
root->bind( "style_list", mStyleList );
|
||||
root->bind( "size_list", mSizeList );
|
||||
root->bind( "preview_text", mPreviewText );
|
||||
root->bind( "preview_input", mPreviewInput );
|
||||
root->bind( "details_text", mDetailsText );
|
||||
root->bind( "monospace_only", mMonospaceOnly );
|
||||
root->bind( "antialiasing", mAntialiasing );
|
||||
root->bind( "underline", mUnderline );
|
||||
root->bind( "strike_through", mStrikeThrough );
|
||||
root->bind( "color_button", mColorButton );
|
||||
root->bind( "ok_button", mButtonOK );
|
||||
root->bind( "cancel_button", mButtonCancel );
|
||||
root->bind( "apply_button", mButtonApply );
|
||||
root->bind( "browse_button", mButtonBrowse );
|
||||
|
||||
mSearchInput->setHint( i18n( "font_picker_search_fonts_ellipsis", "Search fonts..." ) );
|
||||
mPreviewInput->setText( "The quick brown fox jumps over the lazy dog" );
|
||||
mAntialiasing->setChecked( true );
|
||||
mMonospaceOnly->setChecked( ( mFlags & MonospaceOnly ) != 0 );
|
||||
mMonospaceOnly->setEnabled( ( mFlags & MonospaceOnly ) == 0 );
|
||||
|
||||
if ( ( mFlags & ShowSize ) == 0 ) {
|
||||
if ( auto sizeColumn = root->find<UIWidget>( "size_column" ) )
|
||||
sizeColumn->setVisible( false )->setEnabled( false );
|
||||
}
|
||||
|
||||
if ( ( mFlags & ShowEffects ) == 0 ) {
|
||||
mAntialiasing->setVisible( false )->setEnabled( false );
|
||||
mUnderline->setVisible( false )->setEnabled( false );
|
||||
mStrikeThrough->setVisible( false )->setEnabled( false );
|
||||
}
|
||||
|
||||
if ( ( mFlags & ShowColor ) == 0 ) {
|
||||
if ( auto colorLabel = root->find<UIWidget>( "color_label" ) )
|
||||
colorLabel->setVisible( false )->setEnabled( false );
|
||||
mColorButton->setVisible( false )->setEnabled( false );
|
||||
}
|
||||
|
||||
if ( ( mFlags & ShowApplyButton ) == 0 )
|
||||
mButtonApply->setVisible( false )->setEnabled( false );
|
||||
|
||||
mFamilyList->setHeadersVisible( false );
|
||||
mStyleList->setHeadersVisible( false );
|
||||
mSizeList->setHeadersVisible( false );
|
||||
mFamilyList->setAutoExpandOnSingleColumn( true );
|
||||
mStyleList->setAutoExpandOnSingleColumn( true );
|
||||
mSizeList->setAutoExpandOnSingleColumn( true );
|
||||
|
||||
mSearchInput->on( Event::OnTextChanged, [this]( const Event* ) { updateFamilies(); } );
|
||||
mFamilyList->setOnSelectionChange( [this] {
|
||||
if ( !mUpdating ) {
|
||||
updateStyles();
|
||||
updateSelectionFromLists();
|
||||
updatePreview();
|
||||
}
|
||||
} );
|
||||
mStyleList->setOnSelectionChange( [this] {
|
||||
if ( !mUpdating ) {
|
||||
updateSelectionFromLists();
|
||||
updatePreview();
|
||||
}
|
||||
} );
|
||||
mSizeList->setOnSelectionChange( [this] {
|
||||
if ( !mUpdating ) {
|
||||
updateSelectionFromLists();
|
||||
updatePreview();
|
||||
}
|
||||
} );
|
||||
|
||||
mMonospaceOnly->on( Event::OnValueChange, [this]( const Event* ) { updateFamilies(); } );
|
||||
mAntialiasing->on( Event::OnValueChange, [this]( const Event* ) {
|
||||
mSelection.antialiasing = mAntialiasing->isChecked();
|
||||
updatePreview();
|
||||
} );
|
||||
mUnderline->on( Event::OnValueChange, [this]( const Event* ) {
|
||||
mSelection.underline = mUnderline->isChecked();
|
||||
updatePreview();
|
||||
} );
|
||||
mStrikeThrough->on( Event::OnValueChange, [this]( const Event* ) {
|
||||
mSelection.strikeThrough = mStrikeThrough->isChecked();
|
||||
updatePreview();
|
||||
} );
|
||||
mPreviewInput->on( Event::OnTextChanged, [this]( const Event* ) { updatePreview(); } );
|
||||
mColorButton->on( Event::MouseClick, [this]( const Event* ) { pickColor(); } );
|
||||
mButtonApply->on( Event::MouseClick, [this]( const Event* ) {
|
||||
emitPicked();
|
||||
sendCommonEvent( Event::OnApply );
|
||||
} );
|
||||
mButtonBrowse->on( Event::MouseClick, [this]( const Event* ) { browseFont(); } );
|
||||
}
|
||||
|
||||
void UIFontPickerDialog::loadFonts() {
|
||||
setFontsLoading( true );
|
||||
|
||||
if ( getUISceneNode()->hasThreadPool() ) {
|
||||
auto request = std::make_shared<LoadFontsRequest>();
|
||||
request->dialog.store( this );
|
||||
mLoadFontsRequest = request;
|
||||
UISceneNode* sceneNode = getUISceneNode();
|
||||
mLoadFontsTaskId = sceneNode->getThreadPool()->run(
|
||||
[request, sceneNode] {
|
||||
auto fonts = SystemFontResolver::instance()->enumerate();
|
||||
UIFontPickerDialog* dialog = request->dialog.load();
|
||||
sceneNode->runOnMainThread(
|
||||
[request, fonts = std::move( fonts )]() mutable {
|
||||
UIFontPickerDialog* dialog = request->dialog.load();
|
||||
if ( !request->alive || dialog == nullptr )
|
||||
return;
|
||||
dialog->mLoadFontsTaskId = 0;
|
||||
dialog->setFonts( std::move( fonts ) );
|
||||
},
|
||||
Time::Zero, loadFontsTaskTag( dialog ) );
|
||||
},
|
||||
[]( const Uint64& ) {}, loadFontsTaskTag( this ) );
|
||||
return;
|
||||
}
|
||||
|
||||
setFonts( SystemFontResolver::instance()->enumerate() );
|
||||
}
|
||||
|
||||
void UIFontPickerDialog::setFonts( std::vector<FontDesc> fonts ) {
|
||||
FontDesc selectedFont = mSelection.font;
|
||||
for ( const auto& font : mFonts ) {
|
||||
auto found = std::find_if( fonts.begin(), fonts.end(), [&]( const auto& desc ) {
|
||||
return desc.path == font.path && desc.faceIndex == font.faceIndex;
|
||||
} );
|
||||
if ( found == fonts.end() )
|
||||
fonts.push_back( font );
|
||||
}
|
||||
|
||||
mFonts = std::move( fonts );
|
||||
sortFonts();
|
||||
setFontsLoading( false );
|
||||
updateFamilies();
|
||||
if ( !selectedFont.path.empty() || !selectedFont.family.empty() )
|
||||
setSelectedFont( selectedFont );
|
||||
else
|
||||
updatePreview();
|
||||
}
|
||||
|
||||
void UIFontPickerDialog::sortFonts() {
|
||||
std::sort( mFonts.begin(), mFonts.end(), []( const auto& lhs, const auto& rhs ) {
|
||||
if ( lhs.family != rhs.family )
|
||||
return String::toLower( lhs.family ) < String::toLower( rhs.family );
|
||||
if ( lhs.weight != rhs.weight )
|
||||
return lhs.weight < rhs.weight;
|
||||
if ( lhs.italic != rhs.italic )
|
||||
return !lhs.italic && rhs.italic;
|
||||
if ( lhs.path != rhs.path )
|
||||
return lhs.path < rhs.path;
|
||||
return lhs.faceIndex < rhs.faceIndex;
|
||||
} );
|
||||
}
|
||||
|
||||
void UIFontPickerDialog::setFontsLoading( bool loading ) {
|
||||
mLoadingFonts = loading;
|
||||
if ( mFontContent )
|
||||
mFontContent->setVisible( !loading )->setEnabled( !loading );
|
||||
if ( mFontLoader )
|
||||
mFontLoader->setVisible( loading )->setEnabled( loading );
|
||||
if ( mSearchInput )
|
||||
mSearchInput->setEnabled( !loading );
|
||||
if ( mButtonBrowse )
|
||||
mButtonBrowse->setEnabled( !loading );
|
||||
if ( mButtonOK )
|
||||
mButtonOK->setEnabled( !loading );
|
||||
if ( mButtonApply )
|
||||
mButtonApply->setEnabled( !loading && ( mFlags & ShowApplyButton ) != 0 );
|
||||
}
|
||||
|
||||
bool UIFontPickerDialog::wantsMonospaceOnly() const {
|
||||
return mMonospaceOnly && mMonospaceOnly->isChecked();
|
||||
}
|
||||
|
||||
void UIFontPickerDialog::updateFamilies() {
|
||||
std::string previousFamily = mSelection.font.family;
|
||||
if ( !mFamilyList->getSelection().isEmpty() &&
|
||||
mFamilyList->getSelection().first().row() < static_cast<Int64>( mFamilies.size() ) )
|
||||
previousFamily = mFamilies[mFamilyList->getSelection().first().row()];
|
||||
|
||||
const std::string query = String::toLower( mSearchInput->getText().toUtf8() );
|
||||
std::set<std::string> families;
|
||||
for ( const auto& font : mFonts ) {
|
||||
if ( wantsMonospaceOnly() && !font.monospace )
|
||||
continue;
|
||||
if ( !query.empty() && String::toLower( font.family ).find( query ) == std::string::npos )
|
||||
continue;
|
||||
families.insert( font.family );
|
||||
}
|
||||
mFamilies.assign( families.begin(), families.end() );
|
||||
mFamilyModel = ItemListModel<std::string>::create( mFamilies );
|
||||
|
||||
mUpdating = true;
|
||||
mFamilyList->setModel( mFamilyModel );
|
||||
mUpdating = false;
|
||||
|
||||
if ( !previousFamily.empty() )
|
||||
selectFamily( previousFamily );
|
||||
if ( mFamilyList->getSelection().isEmpty() && !mFamilies.empty() )
|
||||
mFamilyList->setSelection( mFamilyModel->index( 0 ) );
|
||||
|
||||
updateStyles();
|
||||
updateSelectionFromLists();
|
||||
updatePreview();
|
||||
}
|
||||
|
||||
void UIFontPickerDialog::updateStyles() {
|
||||
mStyles.clear();
|
||||
if ( !mFamilyList->getSelection().isEmpty() ) {
|
||||
const Int64 row = mFamilyList->getSelection().first().row();
|
||||
if ( row >= 0 && row < static_cast<Int64>( mFamilies.size() ) ) {
|
||||
const std::string& family = mFamilies[row];
|
||||
for ( const auto& font : mFonts ) {
|
||||
if ( font.family == family && ( !wantsMonospaceOnly() || font.monospace ) )
|
||||
mStyles.push_back( { styleLabel( font ), font } );
|
||||
}
|
||||
}
|
||||
}
|
||||
mStyleModel = std::make_shared<StyleListModel>( &mStyles );
|
||||
|
||||
mUpdating = true;
|
||||
mStyleList->setModel( mStyleModel );
|
||||
mUpdating = false;
|
||||
|
||||
if ( !mStyles.empty() ) {
|
||||
selectStyle( mSelection.font );
|
||||
if ( mStyleList->getSelection().isEmpty() )
|
||||
mStyleList->setSelection( mStyleModel->index( 0 ) );
|
||||
}
|
||||
}
|
||||
|
||||
void UIFontPickerDialog::updateSelectionFromLists() {
|
||||
if ( !mStyleList->getSelection().isEmpty() ) {
|
||||
const Int64 row = mStyleList->getSelection().first().row();
|
||||
if ( row >= 0 && row < static_cast<Int64>( mStyles.size() ) )
|
||||
mSelection.font = mStyles[row].desc;
|
||||
}
|
||||
if ( !mSizeList->getSelection().isEmpty() ) {
|
||||
const Int64 row = mSizeList->getSelection().first().row();
|
||||
if ( row >= 0 && row < static_cast<Int64>( mSizes.size() ) )
|
||||
mSelection.size = mSizes[row];
|
||||
}
|
||||
mSelection.antialiasing = mAntialiasing->isChecked();
|
||||
mSelection.underline = mUnderline->isChecked();
|
||||
mSelection.strikeThrough = mStrikeThrough->isChecked();
|
||||
}
|
||||
|
||||
void UIFontPickerDialog::updatePreview() {
|
||||
if ( !mPreviewText )
|
||||
return;
|
||||
|
||||
FontTrueType* font = FontManager::instance()->getOrLoadSystemFallbackFont( mSelection.font );
|
||||
if ( font ) {
|
||||
mPreviewText->setFont( font );
|
||||
mPreviewInput->setFont( font );
|
||||
}
|
||||
|
||||
mPreviewText->setFontSize( PixelDensity::dpToPxI( mSelection.size * 2 ) );
|
||||
mPreviewInput->setFontSize( PixelDensity::dpToPxI( 12 ) );
|
||||
mPreviewText->setFontStyle( styleFlags( mSelection ) );
|
||||
mPreviewInput->setFontStyle( styleFlags( mSelection ) );
|
||||
mPreviewText->setFontColor( mSelection.color );
|
||||
mPreviewInput->setFontColor( mSelection.color );
|
||||
if ( !mPreviewInput->getText().empty() )
|
||||
mPreviewText->setText( mPreviewInput->getText() );
|
||||
|
||||
if ( mColorButton )
|
||||
mColorButton->setBackgroundColor( mSelection.color );
|
||||
|
||||
if ( mDetailsText ) {
|
||||
std::string faceIndexSuffix;
|
||||
if ( mSelection.font.faceIndex != 0 )
|
||||
faceIndexSuffix = " #" + String::toString( mSelection.font.faceIndex );
|
||||
mDetailsText->setText(
|
||||
String::format( "%s %s - %u pt - %s%s", mSelection.font.family.c_str(),
|
||||
styleLabel( mSelection.font ).c_str(), mSelection.size,
|
||||
mSelection.font.path.c_str(), faceIndexSuffix.c_str() ) );
|
||||
}
|
||||
}
|
||||
|
||||
void UIFontPickerDialog::selectInitialRows() {
|
||||
mSizeModel = ItemListModel<Uint32>::create( mSizes );
|
||||
mSizeList->setModel( mSizeModel );
|
||||
selectSize( mSelection.size );
|
||||
if ( mSizeList->getSelection().isEmpty() )
|
||||
mSizeList->setSelection( mSizeModel->index( 4 ) );
|
||||
}
|
||||
|
||||
void UIFontPickerDialog::selectFamily( const std::string& family ) {
|
||||
if ( family.empty() || !mFamilyModel )
|
||||
return;
|
||||
for ( size_t i = 0; i < mFamilies.size(); i++ ) {
|
||||
if ( mFamilies[i] == family ) {
|
||||
mFamilyList->setSelection( mFamilyModel->index( i ) );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UIFontPickerDialog::selectStyle( const FontDesc& desc ) {
|
||||
if ( desc.family.empty() || !mStyleModel )
|
||||
return;
|
||||
for ( size_t i = 0; i < mStyles.size(); i++ ) {
|
||||
const auto& style = mStyles[i].desc;
|
||||
if ( style.path == desc.path && style.faceIndex == desc.faceIndex &&
|
||||
style.weight == desc.weight && style.italic == desc.italic ) {
|
||||
mStyleList->setSelection( mStyleModel->index( i ) );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UIFontPickerDialog::selectSize( Uint32 size ) {
|
||||
if ( !mSizeModel )
|
||||
return;
|
||||
for ( size_t i = 0; i < mSizes.size(); i++ ) {
|
||||
if ( mSizes[i] == size ) {
|
||||
mSizeList->setSelection( mSizeModel->index( i ) );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UIFontPickerDialog::emitPicked() {
|
||||
updateSelectionFromLists();
|
||||
if ( mFontPickedCb )
|
||||
mFontPickedCb( mSelection );
|
||||
}
|
||||
|
||||
void UIFontPickerDialog::pickColor() {
|
||||
if ( mColorPicker ) {
|
||||
mColorPicker->getUIWindow()->toFront();
|
||||
return;
|
||||
}
|
||||
|
||||
mColorPicker = UIColorPicker::NewWindow( [this]( Color color ) {
|
||||
mSelection.color = color;
|
||||
updatePreview();
|
||||
} );
|
||||
mColorPicker->setColor( mSelection.color );
|
||||
mColorPickerCloseCb =
|
||||
mColorPicker->getUIWindow()->on( Event::OnWindowClose, [this]( const Event* ) {
|
||||
mColorPicker = nullptr;
|
||||
mColorPickerCloseCb = 0;
|
||||
} );
|
||||
}
|
||||
|
||||
void UIFontPickerDialog::browseFont() {
|
||||
if ( mBrowseDialog ) {
|
||||
mBrowseDialog->toFront();
|
||||
return;
|
||||
}
|
||||
|
||||
mBrowseDialog =
|
||||
UIFileDialog::New( UIFileDialog::DefaultFlags, "*.ttf; *.otf; *.woff; *.woff2; *.otb; "
|
||||
"*.bdf; *.ttc" );
|
||||
mBrowseDialog->setWindowFlags( UI_WIN_DEFAULT_FLAGS | UI_WIN_MAXIMIZE_BUTTON | UI_WIN_MODAL );
|
||||
mBrowseDialog->setTitle( i18n( "font_picker_browse_font", "Browse Font" ) );
|
||||
mBrowseDialog->setCloseShortcut( KEY_ESCAPE );
|
||||
mBrowseDialogOpenCb = mBrowseDialog->on( Event::OpenFile, [this]( const Event* event ) {
|
||||
auto* dialog = event->getNode()->asType<UIFileDialog>();
|
||||
const std::string path( dialog->getFullPath() );
|
||||
if ( addExternalFont( path ) )
|
||||
dialog->closeWindow();
|
||||
} );
|
||||
mBrowseDialogCloseCb = mBrowseDialog->on( Event::OnWindowClose, [this]( const Event* ) {
|
||||
mBrowseDialog = nullptr;
|
||||
mBrowseDialogOpenCb = 0;
|
||||
mBrowseDialogCloseCb = 0;
|
||||
} );
|
||||
mBrowseDialog->center();
|
||||
mBrowseDialog->show();
|
||||
}
|
||||
|
||||
bool UIFontPickerDialog::addExternalFont( const std::string& path, Uint32 faceIndex ) {
|
||||
if ( path.empty() )
|
||||
return false;
|
||||
|
||||
auto found = std::find_if( mFonts.begin(), mFonts.end(), [&]( const auto& desc ) {
|
||||
return desc.path == path && desc.faceIndex == faceIndex;
|
||||
} );
|
||||
|
||||
if ( found != mFonts.end() ) {
|
||||
if ( !mSearchInput->getText().empty() )
|
||||
mSearchInput->setText( "" );
|
||||
setSelectedFont( *found );
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::string fontName(
|
||||
FileSystem::fileRemoveExtension( FileSystem::fileNameFromPath( path ) ) );
|
||||
FontTrueType* font = FontTrueType::New( fontName );
|
||||
if ( !font || !font->loadFromFile( path, faceIndex ) ) {
|
||||
eeSAFE_DELETE( font );
|
||||
return false;
|
||||
}
|
||||
|
||||
FontDesc desc;
|
||||
desc.family = font->getInfo().family.empty() ? fontName : font->getInfo().family;
|
||||
desc.path = path;
|
||||
desc.faceIndex = font->getFaceIndex();
|
||||
desc.weight = font->isBold() || font->isBoldItalic() ? FontWeight::Bold : FontWeight::Normal;
|
||||
desc.italic = font->isItalic() || font->isBoldItalic();
|
||||
desc.monospace = font->isIdentifiedAsMonospace();
|
||||
eeSAFE_DELETE( font );
|
||||
|
||||
mFonts.push_back( desc );
|
||||
sortFonts();
|
||||
|
||||
if ( !mSearchInput->getText().empty() )
|
||||
mSearchInput->setText( "" );
|
||||
updateFamilies();
|
||||
setSelectedFont( desc );
|
||||
return true;
|
||||
}
|
||||
|
||||
void UIFontPickerDialog::clearBrowseDialog() {
|
||||
if ( !mBrowseDialog )
|
||||
return;
|
||||
if ( mBrowseDialogOpenCb )
|
||||
mBrowseDialog->removeEventListener( mBrowseDialogOpenCb );
|
||||
if ( mBrowseDialogCloseCb )
|
||||
mBrowseDialog->removeEventListener( mBrowseDialogCloseCb );
|
||||
if ( !SceneManager::instance()->isShuttingDown() )
|
||||
mBrowseDialog->closeWindow();
|
||||
mBrowseDialog = nullptr;
|
||||
mBrowseDialogOpenCb = 0;
|
||||
mBrowseDialogCloseCb = 0;
|
||||
}
|
||||
|
||||
void UIFontPickerDialog::setSelectedFont( const FontDesc& desc ) {
|
||||
FontDesc selection = desc;
|
||||
if ( !desc.path.empty() ) {
|
||||
auto found = std::find_if( mFonts.begin(), mFonts.end(), [&]( const auto& font ) {
|
||||
return font.path == desc.path && font.faceIndex == desc.faceIndex;
|
||||
} );
|
||||
if ( found == mFonts.end() && addExternalFont( desc.path, desc.faceIndex ) )
|
||||
return;
|
||||
if ( found != mFonts.end() )
|
||||
selection = *found;
|
||||
}
|
||||
|
||||
mSelection.font = selection;
|
||||
if ( selection.monospace && mMonospaceOnly )
|
||||
mMonospaceOnly->setChecked( true );
|
||||
selectFamily( selection.family );
|
||||
updateStyles();
|
||||
selectStyle( selection );
|
||||
updatePreview();
|
||||
}
|
||||
|
||||
void UIFontPickerDialog::setSelectedFont( const std::string& path, Uint32 faceIndex ) {
|
||||
auto found = std::find_if( mFonts.begin(), mFonts.end(), [&]( const auto& desc ) {
|
||||
return desc.path == path && desc.faceIndex == faceIndex;
|
||||
} );
|
||||
if ( found != mFonts.end() ) {
|
||||
setSelectedFont( *found );
|
||||
return;
|
||||
}
|
||||
|
||||
addExternalFont( path, faceIndex );
|
||||
}
|
||||
|
||||
const UIFontSelection& UIFontPickerDialog::getSelection() const {
|
||||
return mSelection;
|
||||
}
|
||||
|
||||
void UIFontPickerDialog::setSelection( const UIFontSelection& selection ) {
|
||||
mSelection = selection;
|
||||
if ( mAntialiasing )
|
||||
mAntialiasing->setChecked( selection.antialiasing );
|
||||
if ( mUnderline )
|
||||
mUnderline->setChecked( selection.underline );
|
||||
if ( mStrikeThrough )
|
||||
mStrikeThrough->setChecked( selection.strikeThrough );
|
||||
selectSize( selection.size );
|
||||
setSelectedFont( selection.font );
|
||||
}
|
||||
|
||||
void UIFontPickerDialog::setOnFontPicked( FontPickedCb cb ) {
|
||||
mFontPickedCb = std::move( cb );
|
||||
}
|
||||
|
||||
UIPushButton* UIFontPickerDialog::getButtonOK() const {
|
||||
return mButtonOK;
|
||||
}
|
||||
|
||||
UIPushButton* UIFontPickerDialog::getButtonCancel() const {
|
||||
return mButtonCancel;
|
||||
}
|
||||
|
||||
UIPushButton* UIFontPickerDialog::getButtonApply() const {
|
||||
return mButtonApply;
|
||||
}
|
||||
|
||||
UIPushButton* UIFontPickerDialog::getButtonBrowse() const {
|
||||
return mButtonBrowse;
|
||||
}
|
||||
|
||||
UITextInput* UIFontPickerDialog::getSearchInput() const {
|
||||
return mSearchInput;
|
||||
}
|
||||
|
||||
UIListView* UIFontPickerDialog::getFamilyList() const {
|
||||
return mFamilyList;
|
||||
}
|
||||
|
||||
UIListView* UIFontPickerDialog::getStyleList() const {
|
||||
return mStyleList;
|
||||
}
|
||||
|
||||
UIListView* UIFontPickerDialog::getSizeList() const {
|
||||
return mSizeList;
|
||||
}
|
||||
|
||||
const KeyBindings::Shortcut& UIFontPickerDialog::getCloseShortcut() const {
|
||||
return mCloseShortcut;
|
||||
}
|
||||
|
||||
void UIFontPickerDialog::setCloseShortcut( const KeyBindings::Shortcut& closeShortcut ) {
|
||||
mCloseShortcut = closeShortcut;
|
||||
}
|
||||
|
||||
bool UIFontPickerDialog::show() {
|
||||
bool ret = UIWindow::show();
|
||||
if ( mSearchInput && mSearchInput->isEnabled() )
|
||||
mSearchInput->setFocus();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void UIFontPickerDialog::onWindowReady() {
|
||||
UIWindow::onWindowReady();
|
||||
if ( mSearchInput && mSearchInput->isEnabled() )
|
||||
mSearchInput->setFocus();
|
||||
}
|
||||
|
||||
Uint32 UIFontPickerDialog::onKeyUp( const KeyEvent& event ) {
|
||||
if ( mCloseShortcut && event.getKeyCode() == mCloseShortcut &&
|
||||
( mCloseShortcut.mod == 0 || ( event.getMod() & mCloseShortcut.mod ) ) ) {
|
||||
sendCommonEvent( Event::OnDiscard );
|
||||
sendCommonEvent( Event::OnCancel );
|
||||
closeWindow();
|
||||
}
|
||||
|
||||
return UIWindow::onKeyUp( event );
|
||||
}
|
||||
|
||||
Uint32 UIFontPickerDialog::onMessage( const NodeMessage* msg ) {
|
||||
switch ( msg->getMsg() ) {
|
||||
case NodeMessage::MouseClick:
|
||||
if ( msg->getFlags() & EE_BUTTON_LMASK ) {
|
||||
if ( msg->getSender() == mButtonOK ) {
|
||||
emitPicked();
|
||||
sendCommonEvent( Event::OnConfirm );
|
||||
closeWindow();
|
||||
} else if ( msg->getSender() == mButtonCancel ) {
|
||||
sendCommonEvent( Event::OnDiscard );
|
||||
sendCommonEvent( Event::OnCancel );
|
||||
closeWindow();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return UIWindow::onMessage( msg );
|
||||
}
|
||||
|
||||
}}} // namespace EE::UI::Tools
|
||||
@@ -208,12 +208,13 @@ void UILinearLayout::packVertical() {
|
||||
|
||||
switch ( Font::getHorizontalAlign( widget->getLayoutGravity() ) ) {
|
||||
case UI_HALIGN_CENTER:
|
||||
pos.x = ( getPixelsSize().getWidth() - mPaddingPx.Left - mPaddingPx.Right -
|
||||
pos.x = mPaddingPx.Left +
|
||||
( getPixelsSize().getWidth() - mPaddingPx.Left - mPaddingPx.Right -
|
||||
widget->getPixelsSize().getWidth() ) /
|
||||
2;
|
||||
2;
|
||||
break;
|
||||
case UI_HALIGN_RIGHT:
|
||||
pos.x = getPixelsSize().getWidth() - mPaddingPx.Left - mPaddingPx.Right -
|
||||
pos.x = getPixelsSize().getWidth() - mPaddingPx.Right -
|
||||
widget->getPixelsSize().getWidth() -
|
||||
widget->getLayoutPixelsMargin().Right;
|
||||
break;
|
||||
@@ -342,12 +343,13 @@ void UILinearLayout::packHorizontal() {
|
||||
|
||||
switch ( Font::getVerticalAlign( widget->getLayoutGravity() ) ) {
|
||||
case UI_VALIGN_CENTER:
|
||||
pos.y = ( getPixelsSize().getHeight() - mPaddingPx.Top - mPaddingPx.Bottom -
|
||||
pos.y = mPaddingPx.Top +
|
||||
( getPixelsSize().getHeight() - mPaddingPx.Top - mPaddingPx.Bottom -
|
||||
widget->getPixelsSize().getHeight() ) /
|
||||
2;
|
||||
2;
|
||||
break;
|
||||
case UI_VALIGN_BOTTOM:
|
||||
pos.y = getPixelsSize().getHeight() - mPaddingPx.Top - mPaddingPx.Bottom -
|
||||
pos.y = getPixelsSize().getHeight() - mPaddingPx.Bottom -
|
||||
widget->getPixelsSize().getHeight() -
|
||||
widget->getLayoutPixelsMargin().Bottom;
|
||||
break;
|
||||
|
||||
@@ -816,34 +816,46 @@ void UIWidget::updateAnchors( const Vector2f& sizeChange ) {
|
||||
}
|
||||
|
||||
void UIWidget::alignAgainstLayout() {
|
||||
Vector2f pos = mDpPos;
|
||||
Vector2f pos = mPosition;
|
||||
const Sizef parentSize( getParent()->getPixelsSize() );
|
||||
const Sizef size( getPixelsSize() );
|
||||
Rectf parentContentOffset = Rectf::Zero;
|
||||
|
||||
if ( getParent()->isWidget() )
|
||||
parentContentOffset = getParent()->asType<UIWidget>()->getPixelsContentOffset();
|
||||
|
||||
const Float parentContentWidth =
|
||||
parentSize.getWidth() - parentContentOffset.Left - parentContentOffset.Right;
|
||||
const Float parentContentHeight =
|
||||
parentSize.getHeight() - parentContentOffset.Top - parentContentOffset.Bottom;
|
||||
|
||||
switch ( Font::getHorizontalAlign( mLayoutGravity ) ) {
|
||||
case UI_HALIGN_CENTER:
|
||||
pos.x = ( getParent()->getSize().getWidth() - getSize().getWidth() ) / 2;
|
||||
pos.x = parentContentOffset.Left + ( parentContentWidth - size.getWidth() ) / 2;
|
||||
break;
|
||||
case UI_HALIGN_RIGHT:
|
||||
pos.x = getParent()->getSize().getWidth() - getSize().getWidth() - mLayoutMargin.Right;
|
||||
pos.x = parentSize.getWidth() - parentContentOffset.Right - size.getWidth() -
|
||||
mLayoutMarginPx.Right;
|
||||
break;
|
||||
case UI_HALIGN_LEFT:
|
||||
pos.x = mLayoutMargin.Left;
|
||||
pos.x = parentContentOffset.Left + mLayoutMarginPx.Left;
|
||||
break;
|
||||
}
|
||||
|
||||
switch ( Font::getVerticalAlign( mLayoutGravity ) ) {
|
||||
case UI_VALIGN_CENTER:
|
||||
pos.y = ( getParent()->getSize().getHeight() - getSize().getHeight() ) / 2;
|
||||
pos.y = parentContentOffset.Top + ( parentContentHeight - size.getHeight() ) / 2;
|
||||
break;
|
||||
case UI_VALIGN_BOTTOM:
|
||||
pos.y =
|
||||
getParent()->getSize().getHeight() - getSize().getHeight() - mLayoutMargin.Bottom;
|
||||
pos.y = parentSize.getHeight() - parentContentOffset.Bottom - size.getHeight() -
|
||||
mLayoutMarginPx.Bottom;
|
||||
break;
|
||||
case UI_VALIGN_TOP:
|
||||
pos.y = mLayoutMargin.Top;
|
||||
pos.y = parentContentOffset.Top + mLayoutMarginPx.Top;
|
||||
break;
|
||||
}
|
||||
|
||||
setPosition( pos );
|
||||
setPixelsPosition( pos );
|
||||
}
|
||||
|
||||
void UIWidget::reportStyleStateChange( bool disableAnimations, bool forceReApplyStyles ) {
|
||||
|
||||
34
src/examples/ui_font_picker/ui_font_picker.cpp
Normal file
34
src/examples/ui_font_picker/ui_font_picker.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
#include <eepp/ee.hpp>
|
||||
|
||||
EE_MAIN_FUNC int main( int, char** ) {
|
||||
UIApplication app( { 1280, 720, "eepp - UIFontPickerDialog Example" } );
|
||||
|
||||
std::shared_ptr<ThreadPool> threadPool(
|
||||
ThreadPool::createShared( eemax<int>( 4, Sys::getCPUCount() ) ) );
|
||||
|
||||
if ( !app.getWindow()->isOpen() )
|
||||
return EXIT_FAILURE;
|
||||
|
||||
app.getUI()->setThreadPool( threadPool );
|
||||
app.getUI()->getUIIconThemeManager()->setCurrentTheme(
|
||||
IconManager::init( "icons", FontTrueType::New( "icon", "assets/fonts/remixicon.ttf" ),
|
||||
FontTrueType::New( "nonicons", "assets/fonts/nonicons.ttf" ),
|
||||
FontTrueType::New( "codicon", "assets/fonts/codicon.ttf" ) ) );
|
||||
|
||||
UIFontPickerDialog* dialog = UIFontPickerDialog::New();
|
||||
dialog->setCloseShortcut( KEY_ESCAPE );
|
||||
dialog->setOnFontPicked( []( const UIFontSelection& selection ) {
|
||||
Log::info( "Selected font: %s (%s, face index: %u, size: %u)",
|
||||
selection.font.family.c_str(), selection.font.path.c_str(),
|
||||
selection.font.faceIndex, selection.size );
|
||||
} );
|
||||
dialog->center();
|
||||
dialog->show();
|
||||
|
||||
app.getUI()->on( Event::KeyUp, [&app]( const Event* event ) {
|
||||
if ( event->asKeyEvent()->getKeyCode() == KEY_F11 )
|
||||
UIWidgetInspector::create( app.getUI() );
|
||||
} );
|
||||
|
||||
return app.run();
|
||||
}
|
||||
90
src/tests/unit_tests/uifontpickerdialog_tests.cpp
Normal file
90
src/tests/unit_tests/uifontpickerdialog_tests.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
#include "utest.hpp"
|
||||
#include <eepp/system/filesystem.hpp>
|
||||
#include <eepp/system/threadpool.hpp>
|
||||
#include <eepp/ui/tools/uifontpickerdialog.hpp>
|
||||
#include <eepp/ui/uiapplication.hpp>
|
||||
#include <eepp/ui/uilistview.hpp>
|
||||
#include <eepp/ui/uipushbutton.hpp>
|
||||
#include <eepp/ui/uiscenenode.hpp>
|
||||
|
||||
using namespace EE;
|
||||
using namespace EE::UI;
|
||||
using namespace EE::UI::Tools;
|
||||
|
||||
template <typename Predicate> static void pumpUntil( UISceneNode* sceneNode, Predicate predicate ) {
|
||||
for ( size_t i = 0; i < 1000 && !predicate(); i++ ) {
|
||||
sceneNode->update( Time::Zero );
|
||||
Sys::sleep( Milliseconds( 5 ) );
|
||||
}
|
||||
}
|
||||
|
||||
UTEST( UIFontPickerDialog, PreselectsExternalFontPath ) {
|
||||
UIApplication app(
|
||||
WindowSettings( 320, 240, "eepp - UIFontPickerDialog Test", WindowStyle::Default,
|
||||
WindowBackend::Default, 32 ),
|
||||
UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), 1 ) );
|
||||
|
||||
const std::string fontPath = Sys::getProcessPath() + "assets/fonts/NotoSansKR-Regular.ttf";
|
||||
ASSERT_TRUE( FileSystem::fileExists( fontPath ) );
|
||||
|
||||
UIFontPickerDialog* dialog = UIFontPickerDialog::New();
|
||||
dialog->setSelectedFont( fontPath );
|
||||
|
||||
EXPECT_STDSTREQ( fontPath, dialog->getSelection().font.path );
|
||||
EXPECT_FALSE( dialog->getSelection().font.family.empty() );
|
||||
EXPECT_FALSE( dialog->getFamilyList()->getSelection().isEmpty() );
|
||||
EXPECT_FALSE( dialog->getStyleList()->getSelection().isEmpty() );
|
||||
|
||||
UIFontPickerDialog* selectionDialog = UIFontPickerDialog::New();
|
||||
UIFontSelection selection;
|
||||
selection.font.path = fontPath;
|
||||
selectionDialog->setSelection( selection );
|
||||
|
||||
EXPECT_STDSTREQ( fontPath, selectionDialog->getSelection().font.path );
|
||||
EXPECT_FALSE( selectionDialog->getSelection().font.family.empty() );
|
||||
}
|
||||
|
||||
UTEST( UIFontPickerDialog, AsyncLoadPreservesExternalFontPreselection ) {
|
||||
UIApplication app(
|
||||
WindowSettings( 320, 240, "eepp - UIFontPickerDialog Test", WindowStyle::Default,
|
||||
WindowBackend::Default, 32 ),
|
||||
UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), 1 ) );
|
||||
app.getUI()->setThreadPool( ThreadPool::createShared( 1 ) );
|
||||
|
||||
const std::string fontPath = Sys::getProcessPath() + "assets/fonts/NotoSansKR-Regular.ttf";
|
||||
ASSERT_TRUE( FileSystem::fileExists( fontPath ) );
|
||||
|
||||
UIFontPickerDialog* dialog = UIFontPickerDialog::New();
|
||||
EXPECT_FALSE( dialog->getButtonOK()->isEnabled() );
|
||||
|
||||
dialog->setSelectedFont( fontPath );
|
||||
pumpUntil( app.getUI(), [dialog] { return dialog->getButtonOK()->isEnabled(); } );
|
||||
|
||||
EXPECT_TRUE( dialog->getButtonOK()->isEnabled() );
|
||||
EXPECT_STDSTREQ( fontPath, dialog->getSelection().font.path );
|
||||
EXPECT_FALSE( dialog->getSelection().font.family.empty() );
|
||||
EXPECT_FALSE( dialog->getFamilyList()->getSelection().isEmpty() );
|
||||
EXPECT_FALSE( dialog->getStyleList()->getSelection().isEmpty() );
|
||||
}
|
||||
|
||||
UTEST( UIFontPickerDialog, ApplyButtonEmitsOnApply ) {
|
||||
UIApplication app(
|
||||
WindowSettings( 320, 240, "eepp - UIFontPickerDialog Test", WindowStyle::Default,
|
||||
WindowBackend::Default, 32 ),
|
||||
UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), 1 ) );
|
||||
|
||||
UIFontPickerDialog* dialog = UIFontPickerDialog::New( UIFontPickerDialog::DefaultFlags |
|
||||
UIFontPickerDialog::ShowApplyButton );
|
||||
bool applied = false;
|
||||
bool picked = false;
|
||||
bool confirmed = false;
|
||||
dialog->on( Event::OnApply, [&applied]( const Event* ) { applied = true; } );
|
||||
dialog->on( Event::OnConfirm, [&confirmed]( const Event* ) { confirmed = true; } );
|
||||
dialog->setOnFontPicked( [&picked]( const UIFontSelection& ) { picked = true; } );
|
||||
|
||||
dialog->getButtonApply()->sendCommonEvent( Event::MouseClick );
|
||||
|
||||
EXPECT_TRUE( applied );
|
||||
EXPECT_TRUE( picked );
|
||||
EXPECT_FALSE( confirmed );
|
||||
}
|
||||
82
src/tests/unit_tests/uilayout_tests.cpp
Normal file
82
src/tests/unit_tests/uilayout_tests.cpp
Normal file
@@ -0,0 +1,82 @@
|
||||
#include "utest.hpp"
|
||||
#include <eepp/system/filesystem.hpp>
|
||||
#include <eepp/ui/uiapplication.hpp>
|
||||
#include <eepp/ui/uilinearlayout.hpp>
|
||||
#include <eepp/ui/uiscenenode.hpp>
|
||||
#include <eepp/ui/uiwidget.hpp>
|
||||
|
||||
using namespace EE;
|
||||
using namespace EE::UI;
|
||||
|
||||
UTEST( UILinearLayout, AlignAgainstLayoutUsesParentPadding ) {
|
||||
UIApplication app(
|
||||
WindowSettings( 320, 240, "eepp - UILinearLayout Test", WindowStyle::Default,
|
||||
WindowBackend::Default, 32 ),
|
||||
UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), 1 ) );
|
||||
|
||||
UIWidget* parent = UIWidget::New();
|
||||
parent->setPixelsSize( 200, 120 );
|
||||
parent->setPadding( { 10, 20, 30, 40 } );
|
||||
parent->setParent( app.getUI()->getRoot() );
|
||||
|
||||
UILinearLayout* layout = UILinearLayout::NewVertical();
|
||||
layout->setLayoutSizePolicy( SizePolicy::Fixed, SizePolicy::Fixed );
|
||||
layout->setPixelsSize( 50, 20 );
|
||||
layout->setLayoutGravity( UI_HALIGN_CENTER | UI_VALIGN_CENTER );
|
||||
layout->setParent( parent );
|
||||
|
||||
app.getUI()->updateDirtyLayouts();
|
||||
|
||||
EXPECT_NEAR( 65.f, layout->getPixelsPosition().x, 0.1f );
|
||||
EXPECT_NEAR( 40.f, layout->getPixelsPosition().y, 0.1f );
|
||||
}
|
||||
|
||||
UTEST( UILinearLayout, CrossAxisAlignmentUsesOwnPadding ) {
|
||||
UIApplication app(
|
||||
WindowSettings( 320, 240, "eepp - UILinearLayout Test", WindowStyle::Default,
|
||||
WindowBackend::Default, 32 ),
|
||||
UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), 1 ) );
|
||||
|
||||
UILinearLayout* vertical = UILinearLayout::NewVertical();
|
||||
vertical->setLayoutSizePolicy( SizePolicy::Fixed, SizePolicy::Fixed );
|
||||
vertical->setPixelsSize( 200, 120 );
|
||||
vertical->setPadding( { 10, 20, 30, 40 } );
|
||||
vertical->setParent( app.getUI()->getRoot() );
|
||||
|
||||
UIWidget* centered = UIWidget::New();
|
||||
centered->setLayoutSizePolicy( SizePolicy::Fixed, SizePolicy::Fixed );
|
||||
centered->setPixelsSize( 50, 20 );
|
||||
centered->setLayoutGravity( UI_HALIGN_CENTER );
|
||||
centered->setParent( vertical );
|
||||
|
||||
UIWidget* right = UIWidget::New();
|
||||
right->setLayoutSizePolicy( SizePolicy::Fixed, SizePolicy::Fixed );
|
||||
right->setPixelsSize( 50, 20 );
|
||||
right->setLayoutGravity( UI_HALIGN_RIGHT );
|
||||
right->setParent( vertical );
|
||||
|
||||
UILinearLayout* horizontal = UILinearLayout::NewHorizontal();
|
||||
horizontal->setLayoutSizePolicy( SizePolicy::Fixed, SizePolicy::Fixed );
|
||||
horizontal->setPixelsSize( 200, 120 );
|
||||
horizontal->setPadding( { 10, 20, 30, 40 } );
|
||||
horizontal->setParent( app.getUI()->getRoot() );
|
||||
|
||||
UIWidget* middle = UIWidget::New();
|
||||
middle->setLayoutSizePolicy( SizePolicy::Fixed, SizePolicy::Fixed );
|
||||
middle->setPixelsSize( 50, 20 );
|
||||
middle->setLayoutGravity( UI_VALIGN_CENTER );
|
||||
middle->setParent( horizontal );
|
||||
|
||||
UIWidget* bottom = UIWidget::New();
|
||||
bottom->setLayoutSizePolicy( SizePolicy::Fixed, SizePolicy::Fixed );
|
||||
bottom->setPixelsSize( 50, 20 );
|
||||
bottom->setLayoutGravity( UI_VALIGN_BOTTOM );
|
||||
bottom->setParent( horizontal );
|
||||
|
||||
app.getUI()->updateDirtyLayouts();
|
||||
|
||||
EXPECT_NEAR( 65.f, centered->getPixelsPosition().x, 0.1f );
|
||||
EXPECT_NEAR( 120.f, right->getPixelsPosition().x, 0.1f );
|
||||
EXPECT_NEAR( 40.f, middle->getPixelsPosition().y, 0.1f );
|
||||
EXPECT_NEAR( 60.f, bottom->getPixelsPosition().y, 0.1f );
|
||||
}
|
||||
Reference in New Issue
Block a user