Mercurial > foo_out_sdl
diff foosdk/sdk/foobar2000/foo_sample/ui_element_dialog.cpp @ 1:20d02a178406 default tip
*: check in everything else
yay
| author | Paper <paper@tflc.us> |
|---|---|
| date | Mon, 05 Jan 2026 02:15:46 -0500 |
| parents | |
| children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/foosdk/sdk/foobar2000/foo_sample/ui_element_dialog.cpp Mon Jan 05 02:15:46 2026 -0500 @@ -0,0 +1,205 @@ +#include "stdafx.h" + +#include "resource.h" + +#include <libPPUI/win32_utility.h> +#include <libPPUI/win32_op.h> // WIN32_OP() +#include <libPPUI/wtl-pp.h> // CCheckBox +#include <helpers/atl-misc.h> // ui_element_impl + +#include <libPPUI/DarkMode.h> + +namespace { + // Anonymous namespace : standard practice in fb2k components + // Nothing outside should have any reason to see these symbols, and we don't want funny results if another cpp has similarly named classes. + // service_factory at the bottom takes care of publishing our class. + + + // I am Sample Component and this is *MY* GUID. + // Replace with your own when reusing code. Component authors with colliding GUIDs will be visited by Urdnot Wrex in person. + static const GUID guid_myelem = { 0x78ca1d7, 0x4e3a, 0x41d5, { 0xa5, 0xef, 0x9d, 0x1a, 0xf7, 0xd5, 0x79, 0xd0 } }; + + enum { + FlagLockMinWidth = 1 << 0, + FlagLockMinHeight = 1 << 1, + FlagLockMaxWidth = 1 << 2, + FlagLockMaxHeight = 1 << 3, + + FlagsDefault = 0 + }; + static const struct { + int btnID; + uint32_t flag; + } flagsAndButtons[] = { + { IDC_LOCK_MIN_WIDTH, FlagLockMinWidth }, + { IDC_LOCK_MIN_HEIGHT, FlagLockMinHeight }, + { IDC_LOCK_MAX_WIDTH, FlagLockMaxWidth }, + { IDC_LOCK_MAX_HEIGHT, FlagLockMaxHeight }, + }; + + class CDialogUIElem : public CDialogImpl<CDialogUIElem>, public ui_element_instance { + public: + CDialogUIElem( ui_element_config::ptr cfg, ui_element_instance_callback::ptr cb ) : m_callback(cb), m_flags( parseConfig(cfg) ) {} + + enum { IDD = IDD_UI_ELEMENT }; + + BEGIN_MSG_MAP_EX( CDialogUIElem ) + MSG_WM_INITDIALOG(OnInitDialog) + MSG_WM_SIZE(OnSize) + COMMAND_CODE_HANDLER_EX(BN_CLICKED, OnButtonClicked) + END_MSG_MAP() + + void initialize_window(HWND parent) {WIN32_OP(Create(parent) != NULL);} + HWND get_wnd() { return m_hWnd; } + void set_configuration(ui_element_config::ptr config) { + m_flags = parseConfig( config ); + if ( m_hWnd != NULL ) { + configToUI(); + } + m_callback->on_min_max_info_change(); + } + ui_element_config::ptr get_configuration() {return makeConfig(m_flags);} + static GUID g_get_guid() { + return guid_myelem; + } + static void g_get_name(pfc::string_base & out) {out = "Sample Dialog as UI Element";} + static ui_element_config::ptr g_get_default_configuration() { + return makeConfig( ); + } + static const char * g_get_description() {return "This is a sample UI Element using win32 dialog.";} + static GUID g_get_subclass() {return ui_element_subclass_utility;} + + ui_element_min_max_info get_min_max_info() { + ui_element_min_max_info ret; + + // Note that we play nicely with separate horizontal & vertical DPI. + // Such configurations have not been ever seen in circulation, but nothing stops us from supporting such. + CSize DPI = QueryScreenDPIEx( *this ); + + if ( DPI.cx <= 0 || DPI.cy <= 0 ) { // sanity + DPI = CSize(96, 96); + } + + if ( m_flags & FlagLockMinWidth ) { + ret.m_min_width = MulDiv( 200, DPI.cx, 96 ); + } + if ( m_flags & FlagLockMinHeight ) { + ret.m_min_height = MulDiv( 200, DPI.cy, 96 ); + } + if ( m_flags & FlagLockMaxWidth ) { + ret.m_max_width = MulDiv( 400, DPI.cx, 96 ); + } + if ( m_flags & FlagLockMaxHeight ) { + ret.m_max_height = MulDiv( 400, DPI.cy, 96 ); + } + + // Deal with WS_EX_STATICEDGE and alike that we might have picked from host + ret.adjustForWindow( *this ); + + return ret; + } + + void applyDark() { + t_ui_color color = 0; + if (m_callback->query_color(ui_color_darkmode, color)) { + m_dark.SetDark(color == 0); + } + } + void notify(const GUID& p_what, t_size p_param1, const void* p_param2, t_size p_param2size) override { + // Colors changed? Check dark mode config + if (p_what == ui_element_notify_colors_changed) { + applyDark(); + } + } + private: + static uint32_t parseConfig( ui_element_config::ptr cfg ) { + try { + ::ui_element_config_parser in ( cfg ); + uint32_t flags; in >> flags; + return flags; + } catch(exception_io_data) { + // If we got here, someone's feeding us nonsense, fall back to defaults + return FlagsDefault; + } + } + static ui_element_config::ptr makeConfig(uint32_t flags = FlagsDefault) { + ui_element_config_builder out; + out << flags; + return out.finish( g_get_guid() ); + } + void configToUI() { + for ( unsigned i = 0; i < PFC_TABSIZE( flagsAndButtons ); ++ i ) { + auto rec = flagsAndButtons[i]; + // CCheckBox: WTL-PP class overlaying ToggleCheck(bool) and bool IsChecked() over WTL CButton + CCheckBox cb ( GetDlgItem( rec.btnID ) ); + cb.ToggleCheck( (m_flags & rec.flag ) != 0 ); + } + } + void OnButtonClicked(UINT uNotifyCode, int nID, CWindow wndCtl) { + + uint32_t flagToFlip = 0; + for ( unsigned i = 0; i < PFC_TABSIZE( flagsAndButtons ); ++ i ) { + auto rec = flagsAndButtons[i]; + if ( rec.btnID == nID ) { + flagToFlip = rec.flag; + } + } + if ( flagToFlip != 0 ) { + uint32_t newFlags = m_flags; + CCheckBox cb ( wndCtl ); + if (cb.IsChecked()) { + newFlags |= flagToFlip; + } else { + newFlags &= ~flagToFlip; + } + if ( newFlags != m_flags ) { + m_flags = newFlags; + m_callback->on_min_max_info_change(); + } + } + } + + void OnSize(UINT, CSize s) { + auto DPI = QueryScreenDPIEx(*this); + + pfc::string_formatter msg; + msg << "Current size: "; + if ( DPI.cx > 0 && DPI.cy > 0 ) { + msg << MulDiv( s.cx, 96, DPI.cx ) << "x" << MulDiv( s.cy, 96, DPI.cy ) << " units, "; + } + msg << s.cx << "x" << s.cy << " pixels"; + + uSetDlgItemText( *this, IDC_STATIC_SIZE, msg ); + } + BOOL OnInitDialog(CWindow, LPARAM) { + + // First tell m_dark whether we're dark nor not + applyDark(); + // Then initialize it + m_dark.AddDialogWithControls(*this); + // The above two work in any order, though this way is slightly more efficient + + configToUI(); + { + CRect rc; + // WIN32_OP_D() - Debug build only retval check and assert + // For stuff that practically never fails + WIN32_OP_D( GetClientRect( &rc ) ); + OnSize( 0, rc.Size() ); + } + + return FALSE; + } + const ui_element_instance_callback::ptr m_callback; + uint32_t m_flags; + + // No fb2k::CDarkModeHooks. + // Politely ask our callback if we should render as dark or not, instead of using global settings. + // Though in real life it's all the same in the end. + DarkMode::CHooks m_dark; + }; + + + static service_factory_single_t< ui_element_impl< CDialogUIElem > > g_CDialogUIElem_factory; +} +
