Skip to content

Commit

Permalink
Merge pull request #1120 from reupen/item-details-d2d
Browse files Browse the repository at this point in the history
Migrate Item details to Direct2D
  • Loading branch information
reupen authored Feb 4, 2025
2 parents 66c60cc + 7f096e5 commit 731bdd9
Show file tree
Hide file tree
Showing 7 changed files with 145 additions and 53 deletions.
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,26 @@
# Change log

## Development version

### Features

- Item details now uses Direct2D for rendering.
[[#1120](https://github.com/reupen/columns_ui/pull/1120)]

This includes support for SVG font glyphs on recent versions of Windows,
including Windows 11 emojis.

### Bug fixes

- A bug where left and/or top padding was missing in Item details when there was
no horizontal or vertical scroll bar was fixed.
[[#1120](https://github.com/reupen/columns_ui/pull/1120)]

- A bug where the `%default_font_size%` and the deprecated `%default_font_face%`
title formatting fields did not update in Item details after a font change
until another event caused a content update was fixed.
[[#1120](https://github.com/reupen/columns_ui/pull/1120)]

## 3.0.0-alpha.5

### Features
Expand Down
8 changes: 4 additions & 4 deletions foo_ui_columns/foo_ui_columns.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@
<Culture>0x0809</Culture>
</ResourceCompile>
<Link>
<AdditionalDependencies>Urlmon.lib;comctl32.lib;shell32.lib;shlwapi.lib;Winmm.lib;gdiplus.lib;../foobar2000/shared/shared-$(Platform).lib;uxtheme.lib;Dwmapi.lib;usp10.lib;Windowscodecs.lib;Dwrite.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>Urlmon.lib;comctl32.lib;shell32.lib;shlwapi.lib;Winmm.lib;gdiplus.lib;../foobar2000/shared/shared-$(Platform).lib;uxtheme.lib;Dwmapi.lib;usp10.lib;Windowscodecs.lib;D2d1.lib;Dwrite.lib;%(AdditionalDependencies)</AdditionalDependencies>
<GenerateDebugInformation>DebugFastLink</GenerateDebugInformation>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
Expand Down Expand Up @@ -160,7 +160,7 @@
<Culture>0x0809</Culture>
</ResourceCompile>
<Link>
<AdditionalDependencies>Urlmon.lib;comctl32.lib;shell32.lib;shlwapi.lib;Winmm.lib;gdiplus.lib;../foobar2000/shared/shared-$(Platform).lib;uxtheme.lib;Dwmapi.lib;usp10.lib;Windowscodecs.lib;Dwrite.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>Urlmon.lib;comctl32.lib;shell32.lib;shlwapi.lib;Winmm.lib;gdiplus.lib;../foobar2000/shared/shared-$(Platform).lib;uxtheme.lib;Dwmapi.lib;usp10.lib;Windowscodecs.lib;D2d1.lib;Dwrite.lib;%(AdditionalDependencies)</AdditionalDependencies>
<GenerateDebugInformation>DebugFastLink</GenerateDebugInformation>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
Expand Down Expand Up @@ -198,7 +198,7 @@
<Culture>0x0809</Culture>
</ResourceCompile>
<Link>
<AdditionalDependencies>Urlmon.lib;comctl32.lib;shell32.lib;shlwapi.lib;Winmm.lib;gdiplus.lib;../foobar2000/shared/shared-$(Platform).lib;uxtheme.lib;Dwmapi.lib;usp10.lib;Windowscodecs.lib;Dwrite.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>Urlmon.lib;comctl32.lib;shell32.lib;shlwapi.lib;Winmm.lib;gdiplus.lib;../foobar2000/shared/shared-$(Platform).lib;uxtheme.lib;Dwmapi.lib;usp10.lib;Windowscodecs.lib;D2d1.lib;Dwrite.lib;%(AdditionalDependencies)</AdditionalDependencies>
<GenerateDebugInformation>Debug</GenerateDebugInformation>
<DataExecutionPrevention>
</DataExecutionPrevention>
Expand Down Expand Up @@ -233,7 +233,7 @@
<Culture>0x0809</Culture>
</ResourceCompile>
<Link>
<AdditionalDependencies>Urlmon.lib;comctl32.lib;shell32.lib;shlwapi.lib;Winmm.lib;gdiplus.lib;../foobar2000/shared/shared-$(Platform).lib;uxtheme.lib;Dwmapi.lib;usp10.lib;Windowscodecs.lib;Dwrite.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>Urlmon.lib;comctl32.lib;shell32.lib;shlwapi.lib;Winmm.lib;gdiplus.lib;../foobar2000/shared/shared-$(Platform).lib;uxtheme.lib;Dwmapi.lib;usp10.lib;Windowscodecs.lib;D2d1.lib;Dwrite.lib;%(AdditionalDependencies)</AdditionalDependencies>
<GenerateDebugInformation>Debug</GenerateDebugInformation>
<DataExecutionPrevention>
</DataExecutionPrevention>
Expand Down
141 changes: 104 additions & 37 deletions foo_ui_columns/item_details.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -348,15 +348,14 @@ void ItemDetails::release_all_full_file_info_requests()
m_aborting_full_file_info_requests.clear();
}

void ItemDetails::refresh_contents(bool reset_vertical_scroll_position, bool reset_horizontal_scroll_position)
void ItemDetails::refresh_contents(
bool reset_vertical_scroll_position, bool reset_horizontal_scroll_position, bool force_update)
{
bool b_update = true;

if (m_handles.get_count()) {
LOGFONT lf;
fb2k::std_api_get<fonts::manager>()->get_font(g_guid_item_details_font_client, lf);
const auto font = fonts::get_font(g_guid_item_details_font_client);
const auto font_size = gsl::narrow_cast<int>(uih::direct_write::dip_to_pt(font->size()) + 0.5f);

TitleformatHookChangeFont tf_hook(lf);
TitleformatHookChangeFont tf_hook(font->log_font(), font_size);
pfc::string8_fast_aggressive temp;
temp.prealloc(2048);

Expand All @@ -374,21 +373,18 @@ void ItemDetails::refresh_contents(bool reset_vertical_scroll_position, bool res
}

auto utf16_text = mmh::to_utf16(mmh::to_string_view(temp));
if (utf16_text != m_formatted_text) {
m_formatted_text = std::move(utf16_text);
} else
b_update = false;

if (!force_update && utf16_text == m_formatted_text)
return;

m_formatted_text = std::move(utf16_text);
} else {
m_formatted_text.clear();
}

if (b_update) {
reset_display_info();

update_scrollbars(reset_vertical_scroll_position, reset_horizontal_scroll_position);

invalidate_all();
}
reset_display_info();
update_scrollbars(reset_vertical_scroll_position, reset_horizontal_scroll_position);
invalidate_all();
}

void ItemDetails::update_display_info()
Expand Down Expand Up @@ -434,9 +430,9 @@ void ItemDetails::update_display_info()
scale_max(layout_height + overhang_metrics.bottom),
};

m_text_rect = {std::min(text_rect.left, overhang_rect.left) - padding,
std::min(text_rect.top, overhang_rect.top) - padding, std::max(text_rect.right, overhang_rect.right) + padding,
std::max(text_rect.bottom, overhang_rect.bottom) + padding};
m_text_rect = {std::min(text_rect.left, overhang_rect.left), std::min(text_rect.top, overhang_rect.top),
std::max(text_rect.right, overhang_rect.right) + padding * 2,
std::max(text_rect.bottom, overhang_rect.bottom) + padding * 2};
}

void ItemDetails::reset_display_info()
Expand Down Expand Up @@ -588,6 +584,19 @@ void ItemDetails::update_now()
RedrawWindow(get_wnd(), nullptr, nullptr, RDW_UPDATENOW);
}

void ItemDetails::create_d2d_render_target()
{
if (!m_d2d_context)
m_d2d_context = uih::d2d::Context::s_create();

if (!m_d2d_render_target)
m_d2d_render_target = m_d2d_context->create_hwnd_render_target(get_wnd());

const auto& rendering_params = m_text_layout->rendering_params();
m_d2d_render_target->SetTextRenderingParams(rendering_params->get(get_wnd()).get());
m_d2d_render_target->SetTextAntialiasMode(rendering_params->d2d_text_antialiasing_mode());
}

void ItemDetails::invalidate_all(bool b_update)
{
RedrawWindow(get_wnd(), nullptr, nullptr, RDW_INVALIDATE | (b_update ? RDW_UPDATENOW : NULL));
Expand All @@ -600,12 +609,19 @@ void ItemDetails::on_size()
on_size(wil::rect_width(rc), wil::rect_height(rc));
}

void ItemDetails::on_size(size_t cx, size_t cy)
void ItemDetails::on_size(int cx, int cy)
{
if (m_d2d_render_target) {
try {
m_d2d_render_target->Resize({gsl::narrow<unsigned>(cx), gsl::narrow<unsigned>(cy)});
}
CATCH_LOG();
}

if (m_text_layout) {
const auto padding = s_get_padding();
const auto max_width = std::max(0, gsl::narrow<int>(cx) - padding * 2);
const auto max_height = std::max(0, gsl::narrow<int>(cy) - padding * 2);
const auto max_width = std::max(0, cx - padding * 2);
const auto max_height = std::max(0, cy - padding * 2);

try {
m_text_layout->set_max_width(uih::direct_write::px_to_dip(gsl::narrow_cast<float>(max_width)));
Expand Down Expand Up @@ -718,7 +734,12 @@ LRESULT ItemDetails::on_message(HWND wnd, UINT msg, WPARAM wp, LPARAM lp)
m_direct_write_context.reset();
m_last_cx = 0;
m_last_cy = 0;
} break;
m_d2d_render_target.reset();
m_d2d_text_brush.reset();
m_d2d_brush_cache.clear();
m_d2d_context.reset();
break;
}
case WM_SETFOCUS:
deregister_callback();
m_selection_holder = ui_selection_manager::get()->acquire();
Expand Down Expand Up @@ -854,14 +875,44 @@ LRESULT ItemDetails::on_message(HWND wnd, UINT msg, WPARAM wp, LPARAM lp)
const auto is_horizontal_scroll_bar_visible
= m_hscroll && !m_word_wrapping && (sih.nMax - sih.nMin - 1) > gsl::narrow_cast<int>(sih.nPage);
const auto is_vertical_scroll_bar_visible = (siv.nMax - siv.nMin - 1) > gsl::narrow_cast<int>(siv.nPage);
const auto padding = gsl::narrow_cast<float>(s_get_padding());
const auto x_offset = uih::direct_write::px_to_dip(
gsl::narrow_cast<float>(is_horizontal_scroll_bar_visible ? -sih.nPos : 0));
const auto y_offset
= uih::direct_write::px_to_dip(gsl::narrow_cast<float>(is_vertical_scroll_bar_visible ? -siv.nPos : 0));
gsl::narrow_cast<float>(is_horizontal_scroll_bar_visible ? -sih.nPos : 0) + padding);
const auto y_offset = uih::direct_write::px_to_dip(
gsl::narrow_cast<float>(is_vertical_scroll_bar_visible ? -siv.nPos : 0) + padding);

try {
m_text_layout->render_with_solid_background(
wnd, dc.get(), x_offset, y_offset, ps.rcPaint, background_colour, text_colour);
create_d2d_render_target();

const auto context_1 = m_d2d_render_target.try_query<ID2D1DeviceContext1>();

if (!m_d2d_text_brush) {
const auto d2d_text_colour = uih::d2d::colorref_to_d2d_color(text_colour);
THROW_IF_FAILED(m_d2d_render_target->CreateSolidColorBrush(d2d_text_colour, &m_d2d_text_brush));
}

const auto d2d_background_colour = uih::d2d::colorref_to_d2d_color(background_colour);

m_d2d_render_target->BeginDraw();

m_d2d_render_target->Clear(d2d_background_colour);

m_d2d_render_target->DrawTextLayout({x_offset, y_offset}, m_text_layout->text_layout().get(),
m_d2d_text_brush.get(),
context_1 ? D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT : D2D1_DRAW_TEXT_OPTIONS_NONE);

const auto result = m_d2d_render_target->EndDraw();

if (result == D2DERR_RECREATE_TARGET) {
m_d2d_render_target.reset();
m_d2d_text_brush.reset();
m_d2d_brush_cache.clear();
return 0;
}

THROW_IF_FAILED(result);

ValidateRect(wnd, nullptr);
}
CATCH_LOG()
}
Expand Down Expand Up @@ -1059,13 +1110,30 @@ void ItemDetails::create_text_layout()
if (!m_text_layout)
return;

for (auto& [colour, start_character, character_count] : colour_segments) {
try {
m_text_layout->set_colour(
colour, {gsl::narrow<uint32_t>(start_character), gsl::narrow<uint32_t>(character_count)});
try {
create_d2d_render_target();

std::unordered_map<COLORREF, wil::com_ptr<ID2D1SolidColorBrush>> old_d2d_brush_cache
= std::move(m_d2d_brush_cache);

for (auto& [colour, start_character, character_count] : colour_segments) {
wil::com_ptr<ID2D1SolidColorBrush> brush;

if (auto iter = m_d2d_brush_cache.find(colour); iter != m_d2d_brush_cache.end()) {
brush = iter->second;
} else if (auto iter = old_d2d_brush_cache.find(colour); iter != old_d2d_brush_cache.end()) {
brush = iter->second;
m_d2d_brush_cache.emplace(colour, std::move(iter->second));
} else {
m_d2d_render_target->CreateSolidColorBrush(uih::d2d::colorref_to_d2d_color(colour), &brush);
m_d2d_brush_cache.emplace(colour, brush);
}

m_text_layout->set_effect(
brush.get(), {gsl::narrow<uint32_t>(start_character), gsl::narrow<uint32_t>(character_count)});
}
CATCH_LOG()
}
CATCH_LOG()

process_simple_style_property<std::wstring>(font_segments, &FormatProperties::font_family,
[&](auto&& value, auto&& text_range) { m_text_layout->set_family(value.c_str(), text_range); });
Expand All @@ -1087,13 +1155,12 @@ void ItemDetails::create_text_layout()
void ItemDetails::on_font_change()
{
recreate_text_format();
reset_display_info();
update_scrollbars(false, false);
invalidate_all();
refresh_contents(false, false, true);
}

void ItemDetails::on_colours_change()
{
m_d2d_text_brush.reset();
invalidate_all();
}

Expand Down
18 changes: 12 additions & 6 deletions foo_ui_columns/item_details.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@ class TitleformatHookChangeFont : public titleformat_hook {
bool process_function(titleformat_text_out* p_out, const char* p_name, size_t p_name_length,
titleformat_hook_function_params* p_params, bool& p_found_flag) override;

explicit TitleformatHookChangeFont(const LOGFONT& lf);
TitleformatHookChangeFont(const LOGFONT& lf, int font_size);

private:
pfc::string8 m_default_font_face;
size_t m_default_font_size;
int m_default_font_size;
};

class ItemDetails
Expand Down Expand Up @@ -236,7 +236,8 @@ class ItemDetails
void on_app_activate(bool b_activated);

void set_handles(const metadb_handle_list& handles);
void refresh_contents(bool reset_vertical_scroll_position = false, bool reset_horizontal_scroll_position = false);
void refresh_contents(bool reset_vertical_scroll_position = false, bool reset_horizontal_scroll_position = false,
bool force_update = false);
void request_full_file_info();
void on_full_file_info_request_completion(std::shared_ptr<helpers::FullFileInfoRequest> request);
void release_aborted_full_file_info_requests();
Expand All @@ -252,6 +253,7 @@ class ItemDetails
void set_window_theme() const;
void invalidate_all(bool b_update = true);
void update_now();
void create_d2d_render_target();

enum class ScrollbarType {
vertical = SB_VERT,
Expand All @@ -262,7 +264,7 @@ class ItemDetails
void update_scrollbars(bool reset_vertical_position, bool reset_horizontal_position);

void on_size();
void on_size(size_t cx, size_t cy);
void on_size(int cx, int cy);

void recreate_text_format();
void create_text_layout();
Expand All @@ -271,8 +273,8 @@ class ItemDetails

inline static std::vector<ItemDetails*> s_windows;

size_t m_last_cx{};
size_t m_last_cy{};
int m_last_cx{};
int m_last_cy{};
ui_selection_holder::ptr m_selection_holder;
metadb_handle_list m_handles;
metadb_handle_list m_selection_handles;
Expand All @@ -287,6 +289,10 @@ class ItemDetails
uih::direct_write::Context::Ptr m_direct_write_context;
std::optional<uih::direct_write::TextFormat> m_text_format;
std::optional<uih::direct_write::TextLayout> m_text_layout;
uih::d2d::Context::Ptr m_d2d_context;
wil::com_ptr<ID2D1HwndRenderTarget> m_d2d_render_target;
wil::com_ptr<ID2D1SolidColorBrush> m_d2d_text_brush;
std::unordered_map<COLORREF, wil::com_ptr<ID2D1SolidColorBrush>> m_d2d_brush_cache;

std::optional<RECT> m_text_rect{};

Expand Down
6 changes: 1 addition & 5 deletions foo_ui_columns/item_details_font.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,8 @@

namespace cui::panels::item_details {

TitleformatHookChangeFont::TitleformatHookChangeFont(const LOGFONT& lf)
TitleformatHookChangeFont::TitleformatHookChangeFont(const LOGFONT& lf, int font_size) : m_default_font_size(font_size)
{
HDC dc = GetDC(nullptr);
m_default_font_size = -MulDiv(lf.lfHeight, 72, GetDeviceCaps(dc, LOGPIXELSY));
ReleaseDC(nullptr, dc);

m_default_font_face = pfc::stringcvt::string_utf8_from_wide(lf.lfFaceName, std::size(lf.lfFaceName));
}

Expand Down
2 changes: 2 additions & 0 deletions foo_ui_columns/pch.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
#include <wincodec.h>
#include <strsafe.h>
#include <strstream>
#include <d2d1_3.h>

#include <wil/cppwinrt.h>
#include <wil/com.h>
Expand Down Expand Up @@ -99,6 +100,7 @@
#include "../svg-services/api/api.h"
#include "../columns_ui-sdk/ui_extension.h"
#include "../ui_helpers/stdafx.h"
#include "../ui_helpers/direct_2d.h"
#include "../ui_helpers/direct_write.h"
#include "../ui_helpers/direct_write_text_out.h"
#include "../ui_helpers/list_view/list_view.h"
Expand Down
2 changes: 1 addition & 1 deletion ui_helpers

0 comments on commit 731bdd9

Please sign in to comment.