diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ad7fe3d2..72683708c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,7 +42,8 @@ preferences page. [[#916](https://github.com/reupen/columns_ui/pull/916), [#919](https://github.com/reupen/columns_ui/pull/919), [#927](https://github.com/reupen/columns_ui/pull/927), - [#943](https://github.com/reupen/columns_ui/pull/943)] + [#943](https://github.com/reupen/columns_ui/pull/943), + [#1015](https://github.com/reupen/columns_ui/pull/1015)] This features better grouping of font families and now allows the entry of non-integer font sizes (to one decimal place). @@ -57,7 +58,8 @@ - New `$set_format()` and `$reset_format()` title formatting functions were added to Item details. [[#1004](https://github.com/reupen/columns_ui/pull/1004), - [#1011](https://github.com/reupen/columns_ui/pull/1011)] + [#1011](https://github.com/reupen/columns_ui/pull/1011), + [#1018](https://github.com/reupen/columns_ui/pull/1018)] These serve as replacements for the older `$set_font()` and `$reset_font()` functions. diff --git a/foo_ui_columns/dark_mode_dialog.cpp b/foo_ui_columns/dark_mode_dialog.cpp index a76f73554..9b7859917 100644 --- a/foo_ui_columns/dark_mode_dialog.cpp +++ b/foo_ui_columns/dark_mode_dialog.cpp @@ -18,6 +18,7 @@ class DialogDarkModeHelper { [[nodiscard]] std::optional handle_wm_notify(HWND wnd, LPNMHDR lpnm); void on_dark_mode_change(); void apply_dark_mode_attributes(); + void set_combobox_theme(bool is_dark) const; void set_edit_theme(bool is_dark) const; void set_spin_theme(bool is_dark) const; void set_tree_view_theme(bool is_dark) const; @@ -44,6 +45,23 @@ void DialogDarkModeHelper::set_tree_view_theme(bool is_dark) const } } +void DialogDarkModeHelper::set_combobox_theme(bool is_dark) const +{ + if (!m_wnd) + return; + + for (const auto id : m_config.combo_box_ids) { + const auto combobox_wnd = GetDlgItem(m_wnd, id); + SetWindowTheme(combobox_wnd, is_dark ? L"DarkMode_CFD" : nullptr, nullptr); + + COMBOBOXINFO cbi{}; + cbi.cbSize = sizeof cbi; + + if (GetComboBoxInfo(combobox_wnd, &cbi) && cbi.hwndList) + SetWindowTheme(cbi.hwndList, is_dark ? L"DarkMode_Explorer" : nullptr, nullptr); + } +} + void DialogDarkModeHelper::set_edit_theme(bool is_dark) const { if (!m_wnd) @@ -89,7 +107,7 @@ void DialogDarkModeHelper::apply_dark_mode_attributes() set_titlebar_mode(m_wnd, is_dark); set_window_theme(m_config.button_ids, L"DarkMode_Explorer", is_dark); set_window_theme(m_config.checkbox_ids, L"DarkMode_Explorer", is_dark); - set_window_theme(m_config.combo_box_ids, L"DarkMode_CFD", is_dark); + set_combobox_theme(is_dark); set_edit_theme(is_dark); set_window_theme(m_config.list_box_ids, L"DarkMode_Explorer", is_dark); set_spin_theme(is_dark); @@ -117,7 +135,7 @@ std::optional DialogDarkModeHelper::handle_message(HWND wnd, UINT msg, SetWindowLongPtr(wnd, DWLP_MSGRESULT, TRUE); return TRUE; case WM_PAINT: - handle_modern_background_paint(wnd, GetDlgItem(wnd, IDOK), is_active_ui_dark()); + handle_modern_background_paint(wnd, GetDlgItem(wnd, m_config.last_button_id), is_active_ui_dark()); return TRUE; case WM_NOTIFY: if (const auto result = handle_wm_notify(wnd, reinterpret_cast(lp))) diff --git a/foo_ui_columns/dark_mode_dialog.h b/foo_ui_columns/dark_mode_dialog.h index b3925744d..93aefc0e8 100644 --- a/foo_ui_columns/dark_mode_dialog.h +++ b/foo_ui_columns/dark_mode_dialog.h @@ -13,6 +13,7 @@ struct DialogDarkModeConfig { std::unordered_set list_box_ids; std::unordered_set spin_ids; std::unordered_set tree_view_ids; + int last_button_id{IDOK}; }; INT_PTR modal_dialog_box(UINT resource_id, DialogDarkModeConfig dark_mode_config, HWND parent_window, diff --git a/foo_ui_columns/foo_ui_columns.rc b/foo_ui_columns/foo_ui_columns.rc index 1a981dd55..80b2b85c6 100644 --- a/foo_ui_columns/foo_ui_columns.rc +++ b/foo_ui_columns/foo_ui_columns.rc @@ -537,25 +537,24 @@ BEGIN PUSHBUTTON "Cancel",IDCANCEL,204,364,50,14 END -IDD_ITEM_DETAILS_OPTIONS DIALOGEX 0, 0, 284, 347 +IDD_ITEM_DETAILS_OPTIONS DIALOGEX 0, 0, 284, 350 STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU CAPTION "Options - Item Details" FONT 8, "Segoe UI", 400, 0, 0x0 BEGIN LTEXT "Title format",IDC_STATIC,14,7,40,8 EDITTEXT IDC_SCRIPT,14,17,256,172,ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL - PUSHBUTTON "Generate colour code...",IDC_GEN_COLOUR,14,198,88,13 - EDITTEXT IDC_COLOUR_CODE,108,198,162,13,ES_AUTOHSCROLL | ES_READONLY - PUSHBUTTON "Generate font code...",IDC_GEN_FONT,14,220,88,13 - EDITTEXT IDC_FONT_CODE,108,220,162,13,ES_AUTOHSCROLL | ES_READONLY - LTEXT "Horizontal alignment",IDC_STATIC,14,246,75,8 - COMBOBOX IDC_HALIGN,14,257,82,65,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Vertical alignment",IDC_STATIC,108,246,67,8 - COMBOBOX IDC_VALIGN,108,257,82,65,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Panel edge style",IDC_STATIC,14,281,56,8 - COMBOBOX IDC_EDGESTYLE,14,292,82,65,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - DEFPUSHBUTTON "OK",IDOK,167,326,50,14 - PUSHBUTTON "Cancel",IDCANCEL,220,326,50,14 + PUSHBUTTON "Open format code generator",IDC_FORMAT_CODE_GENERATOR,14,202,120,13 + PUSHBUTTON "Generate colour code...",IDC_GEN_COLOUR,14,226,88,13 + EDITTEXT IDC_COLOUR_CODE,110,226,160,13,ES_AUTOHSCROLL | ES_READONLY + LTEXT "Horizontal alignment",IDC_STATIC,14,252,75,8 + COMBOBOX IDC_HALIGN,14,263,88,65,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Vertical alignment",IDC_STATIC,110,252,67,8 + COMBOBOX IDC_VALIGN,110,263,88,65,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Panel edge style",IDC_STATIC,14,284,56,8 + COMBOBOX IDC_EDGESTYLE,14,295,88,65,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + DEFPUSHBUTTON "OK",IDOK,167,329,50,14 + PUSHBUTTON "Cancel",IDCANCEL,220,329,50,14 END IDD_PREFS_FILTER_APPEARANCE DIALOGEX 0, 0, 327, 268 @@ -746,6 +745,23 @@ BEGIN LTEXT "Static",IDC_AXIS_RANGE,69,50,96,8 END +IDD_ITEM_DETAILS_PICK_FONT DIALOGEX 0, 0, 200, 227 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Format code generator – Item details" +FONT 8, "Segoe UI", 400, 0, 0x0 +BEGIN + LTEXT "Font family",-1,14,7,47,8 + COMBOBOX IDC_FONT_FAMILY,14,18,172,176,CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | CBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + LTEXT "Font style",-1,14,41,49,8 + COMBOBOX IDC_FONT_FACE,14,52,172,146,CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS | CBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + LTEXT "Font size",-1,14,75,41,8 + EDITTEXT IDC_FONT_SIZE,14,85,60,12,ES_AUTOHSCROLL + CONTROL "",IDC_FONT_SIZE_SPIN,"msctls_updown32",UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,70,85,12,14 + LTEXT "Code snippet",-1,14,110,141,8 + EDITTEXT IDC_SET_FORMAT_SNIPPET,14,121,172,64,ES_MULTILINE | ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL + PUSHBUTTON "Close",IDCANCEL,136,206,50,14 +END + ///////////////////////////////////////////////////////////////////////////// // @@ -965,7 +981,7 @@ BEGIN LEFTMARGIN, 14 RIGHTMARGIN, 270 TOPMARGIN, 7 - BOTTOMMARGIN, 340 + BOTTOMMARGIN, 343 END IDD_PREFS_FILTER_APPEARANCE, DIALOG @@ -1063,6 +1079,14 @@ BEGIN TOPMARGIN, 7 BOTTOMMARGIN, 95 END + + IDD_ITEM_DETAILS_PICK_FONT, DIALOG + BEGIN + LEFTMARGIN, 14 + RIGHTMARGIN, 186 + TOPMARGIN, 7 + BOTTOMMARGIN, 220 + END END #endif // APSTUDIO_INVOKED diff --git a/foo_ui_columns/item_details.h b/foo_ui_columns/item_details.h index 9dacfdc59..d65ccf4d1 100644 --- a/foo_ui_columns/item_details.h +++ b/foo_ui_columns/item_details.h @@ -311,6 +311,7 @@ class ItemDetailsConfig { bool m_timer_active{}; service_ptr_t m_this; HWND m_wnd{}; + HWND m_format_code_generator_wnd{}; enum { timer_id = 100 @@ -328,6 +329,7 @@ class ItemDetailsConfig { void kill_timer(); void start_timer(); void on_timer(); + void open_format_code_generator(); INT_PTR CALLBACK on_message(HWND wnd, UINT msg, WPARAM wp, LPARAM lp); }; diff --git a/foo_ui_columns/item_details_config.cpp b/foo_ui_columns/item_details_config.cpp index e0c433c02..b4ef40c38 100644 --- a/foo_ui_columns/item_details_config.cpp +++ b/foo_ui_columns/item_details_config.cpp @@ -2,24 +2,52 @@ #include "item_details.h" #include "config.h" #include "dark_mode_dialog.h" +#include "font_picker.h" namespace cui::panels::item_details { namespace { -std::string format_font_code(const LOGFONT& lf) +constexpr auto MSG_FORMAT_GENERATOR_CLOSED = WM_USER + 0x10; + +std::wstring create_set_format_snippet(const fonts::FontDescription& font_description) { - const auto dpi = uih::get_system_dpi_cached().cy; - const auto pt = -MulDiv(lf.lfHeight, 72, dpi); - const auto face = pfc::stringcvt::string_utf8_from_wide(lf.lfFaceName, std::size(lf.lfFaceName)); + const auto& desc = font_description; + + if (!desc.wss) + return L""s; - return fmt::format("$set_font({},{},{}{})", face.get_ptr(), pt, lf.lfWeight == FW_BOLD ? "bold;"sv : ""sv, - lf.lfItalic ? "italic;"sv : ""sv); + const auto font_family + = desc.typographic_family_name.empty() ? desc.wss->family_name : desc.typographic_family_name; + + const auto font_size = font_description.dip_size * 72.0f / gsl::narrow_cast(USER_DEFAULT_SCREEN_DPI); + const auto font_style = [style{desc.wss->style}] { + switch (style) { + default: + return L"normal"; + case DWRITE_FONT_STYLE_OBLIQUE: + return L"oblique"; + case DWRITE_FONT_STYLE_ITALIC: + return L"italic"; + } + }(); + + const auto snippet = fmt::format(LR"($set_format( + font-family: {}; + font-size: {}; + font-weight: {}; + font-stretch: {}; + font-style: {}; +))", + font_family, font_size, WI_EnumValue(desc.wss->weight), WI_EnumValue(desc.wss->stretch), font_style); + + return std::regex_replace(snippet, std::wregex(L"\n"), L"\r\n"); } -const dark::DialogDarkModeConfig dark_mode_config{.button_ids = {IDC_GEN_COLOUR, IDC_GEN_FONT, IDOK, IDCANCEL}, +const dark::DialogDarkModeConfig dark_mode_config{ + .button_ids = {IDC_GEN_COLOUR, IDC_FORMAT_CODE_GENERATOR, IDOK, IDCANCEL}, .combo_box_ids = {IDC_HALIGN, IDC_VALIGN, IDC_EDGESTYLE}, - .edit_ids = {IDC_SCRIPT, IDC_COLOUR_CODE, IDC_FONT_CODE}}; + .edit_ids = {IDC_SCRIPT, IDC_COLOUR_CODE}}; } // namespace @@ -59,10 +87,6 @@ INT_PTR CALLBACK ItemDetailsConfig::on_message(HWND wnd, UINT msg, WPARAM wp, LP ComboBox_AddString(wnd_combo, L"Bottom"); ComboBox_SetCurSel(wnd_combo, m_vertical_alignment); - uih::enhance_edit_control(wnd, IDC_FONT_CODE); - fb2k::std_api_get()->get_font(g_guid_item_details_font_client, m_code_generator_selected_font); - uSetDlgItemText(wnd, IDC_FONT_CODE, format_font_code(m_code_generator_selected_font).c_str()); - uih::enhance_edit_control(wnd, IDC_COLOUR_CODE); colour_code_gen(wnd, IDC_COLOUR_CODE, false, true); @@ -96,6 +120,9 @@ INT_PTR CALLBACK ItemDetailsConfig::on_message(HWND wnd, UINT msg, WPARAM wp, LP if (wp == timer_id) on_timer(); break; + case MSG_FORMAT_GENERATOR_CLOSED: + m_format_code_generator_wnd = nullptr; + break; case WM_COMMAND: switch (LOWORD(wp)) { case IDOK: @@ -112,12 +139,8 @@ INT_PTR CALLBACK ItemDetailsConfig::on_message(HWND wnd, UINT msg, WPARAM wp, LP case IDC_GEN_COLOUR: colour_code_gen(wnd, IDC_COLOUR_CODE, false, false); break; - case IDC_GEN_FONT: - if (const auto font_description = fonts::select_font(wnd, m_code_generator_selected_font); - font_description) { - m_code_generator_selected_font = font_description->log_font; - uSetDlgItemText(wnd, IDC_FONT_CODE, format_font_code(m_code_generator_selected_font).c_str()); - } + case IDC_FORMAT_CODE_GENERATOR: + open_format_code_generator(); break; case IDC_SCRIPT: switch (HIWORD(wp)) { @@ -173,6 +196,63 @@ void ItemDetailsConfig::on_timer() kill_timer(); } +void ItemDetailsConfig::open_format_code_generator() +{ + if (m_format_code_generator_wnd) { + SetForegroundWindow(m_format_code_generator_wnd); + return; + } + + m_format_code_generator_wnd = cui::dark::modeless_dialog_box(IDD_ITEM_DETAILS_PICK_FONT, + {.button_ids = {IDCANCEL}, + .combo_box_ids = {IDC_FONT_FAMILY, IDC_FONT_FACE}, + .edit_ids = {IDC_FONT_SIZE, IDC_SET_FORMAT_SNIPPET}, + .spin_ids = {IDC_FONT_SIZE_SPIN}, + .last_button_id = IDCANCEL}, + m_wnd, + [wnd_parent{m_wnd}, font_picker{utils::DirectWriteFontPicker{}}]( + auto wnd, auto msg, auto wp, auto lp) mutable -> INT_PTR { + if (const auto result = font_picker.handle_message(wnd, msg, wp, lp); result) + return *result; + + switch (msg) { + case WM_INITDIALOG: { + modeless_dialog_manager::g_add(wnd); + + const auto font + = fb2k::std_api_get()->get_client_font(g_guid_item_details_font_client); + + fonts::FontDescription font_description; + font_description.wss = uih::direct_write::WeightStretchStyle{ + font->family_name(), font->weight(), font->stretch(), font->style()}; + font_description.set_dip_size(font->size()); + + const auto snippet_wnd = GetDlgItem(wnd, IDC_SET_FORMAT_SNIPPET); + uih::enhance_edit_control(snippet_wnd); + + const auto on_font_changed = [snippet_wnd](const auto& font_description) { + SetWindowText(snippet_wnd, create_set_format_snippet(font_description).c_str()); + }; + on_font_changed(font_description); + + font_picker.set_font_description(std::move(font_description)); + font_picker.set_on_font_changed(std::move(on_font_changed)); + return FALSE; + } + case WM_DESTROY: + SendMessage(wnd_parent, MSG_FORMAT_GENERATOR_CLOSED, 0, 0); + modeless_dialog_manager::g_remove(wnd); + break; + case WM_COMMAND: + if (wp == IDCANCEL) + DestroyWindow(wnd); + return TRUE; + } + + return FALSE; + }); +} + void ItemDetailsConfig::start_timer() { kill_timer(); diff --git a/foo_ui_columns/resource.h b/foo_ui_columns/resource.h index 415b7a4a0..354ddf4bf 100644 --- a/foo_ui_columns/resource.h +++ b/foo_ui_columns/resource.h @@ -95,12 +95,12 @@ #define IDD_PREFS_STATUS_PANE 236 #define IDD_PREFS_TEXT_RENDERING 237 #define IDD_FONT_AXES 238 +#define IDD_ITEM_DETAILS_PICK_FONT 239 #define IDC_INFOSECTIONS 1003 #define IDC_STRING 1006 #define IDC_COLOUR 1007 #define IDC_DBLCLK 1007 #define IDC_NAME 1008 -#define IDC_FONT_CODE 1008 #define IDC_WIDTH 1009 #define IDC_APPLY 1010 #define IDC_PARTS 1011 @@ -262,8 +262,8 @@ #define IDC_GEN_COLOUR 1164 #define IDC_SHOWGROUPS 1164 #define IDC_INDENT_GROUPS 1164 -#define IDC_GEN_FONT 1165 #define IDC_USE_CUSTOM_INDENTATION 1165 +#define IDC_FORMAT_CODE_GENERATOR 1165 #define IDC_COLOUR_CODE 1166 #define IDC_TITLE1 1168 #define IDC_TITLE2 1169 @@ -300,6 +300,7 @@ #define IDC_AXIS_VALUE 1200 #define IDC_AXIS_VALUE_SPIN 1201 #define IDC_AXIS_RANGE 1202 +#define IDC_SET_FORMAT_SNIPPET 1203 #define IDC_STATIC -1 // Next default values for new objects @@ -309,7 +310,7 @@ #define _APS_NO_MFC 1 #define _APS_NEXT_RESOURCE_VALUE 198 #define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1203 +#define _APS_NEXT_CONTROL_VALUE 1204 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif