Mercurial > foo_out_sdl
comparison 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 |
comparison
equal
deleted
inserted
replaced
| 0:e9bb126753e7 | 1:20d02a178406 |
|---|---|
| 1 #include "stdafx.h" | |
| 2 | |
| 3 #include "resource.h" | |
| 4 | |
| 5 #include <libPPUI/win32_utility.h> | |
| 6 #include <libPPUI/win32_op.h> // WIN32_OP() | |
| 7 #include <libPPUI/wtl-pp.h> // CCheckBox | |
| 8 #include <helpers/atl-misc.h> // ui_element_impl | |
| 9 | |
| 10 #include <libPPUI/DarkMode.h> | |
| 11 | |
| 12 namespace { | |
| 13 // Anonymous namespace : standard practice in fb2k components | |
| 14 // Nothing outside should have any reason to see these symbols, and we don't want funny results if another cpp has similarly named classes. | |
| 15 // service_factory at the bottom takes care of publishing our class. | |
| 16 | |
| 17 | |
| 18 // I am Sample Component and this is *MY* GUID. | |
| 19 // Replace with your own when reusing code. Component authors with colliding GUIDs will be visited by Urdnot Wrex in person. | |
| 20 static const GUID guid_myelem = { 0x78ca1d7, 0x4e3a, 0x41d5, { 0xa5, 0xef, 0x9d, 0x1a, 0xf7, 0xd5, 0x79, 0xd0 } }; | |
| 21 | |
| 22 enum { | |
| 23 FlagLockMinWidth = 1 << 0, | |
| 24 FlagLockMinHeight = 1 << 1, | |
| 25 FlagLockMaxWidth = 1 << 2, | |
| 26 FlagLockMaxHeight = 1 << 3, | |
| 27 | |
| 28 FlagsDefault = 0 | |
| 29 }; | |
| 30 static const struct { | |
| 31 int btnID; | |
| 32 uint32_t flag; | |
| 33 } flagsAndButtons[] = { | |
| 34 { IDC_LOCK_MIN_WIDTH, FlagLockMinWidth }, | |
| 35 { IDC_LOCK_MIN_HEIGHT, FlagLockMinHeight }, | |
| 36 { IDC_LOCK_MAX_WIDTH, FlagLockMaxWidth }, | |
| 37 { IDC_LOCK_MAX_HEIGHT, FlagLockMaxHeight }, | |
| 38 }; | |
| 39 | |
| 40 class CDialogUIElem : public CDialogImpl<CDialogUIElem>, public ui_element_instance { | |
| 41 public: | |
| 42 CDialogUIElem( ui_element_config::ptr cfg, ui_element_instance_callback::ptr cb ) : m_callback(cb), m_flags( parseConfig(cfg) ) {} | |
| 43 | |
| 44 enum { IDD = IDD_UI_ELEMENT }; | |
| 45 | |
| 46 BEGIN_MSG_MAP_EX( CDialogUIElem ) | |
| 47 MSG_WM_INITDIALOG(OnInitDialog) | |
| 48 MSG_WM_SIZE(OnSize) | |
| 49 COMMAND_CODE_HANDLER_EX(BN_CLICKED, OnButtonClicked) | |
| 50 END_MSG_MAP() | |
| 51 | |
| 52 void initialize_window(HWND parent) {WIN32_OP(Create(parent) != NULL);} | |
| 53 HWND get_wnd() { return m_hWnd; } | |
| 54 void set_configuration(ui_element_config::ptr config) { | |
| 55 m_flags = parseConfig( config ); | |
| 56 if ( m_hWnd != NULL ) { | |
| 57 configToUI(); | |
| 58 } | |
| 59 m_callback->on_min_max_info_change(); | |
| 60 } | |
| 61 ui_element_config::ptr get_configuration() {return makeConfig(m_flags);} | |
| 62 static GUID g_get_guid() { | |
| 63 return guid_myelem; | |
| 64 } | |
| 65 static void g_get_name(pfc::string_base & out) {out = "Sample Dialog as UI Element";} | |
| 66 static ui_element_config::ptr g_get_default_configuration() { | |
| 67 return makeConfig( ); | |
| 68 } | |
| 69 static const char * g_get_description() {return "This is a sample UI Element using win32 dialog.";} | |
| 70 static GUID g_get_subclass() {return ui_element_subclass_utility;} | |
| 71 | |
| 72 ui_element_min_max_info get_min_max_info() { | |
| 73 ui_element_min_max_info ret; | |
| 74 | |
| 75 // Note that we play nicely with separate horizontal & vertical DPI. | |
| 76 // Such configurations have not been ever seen in circulation, but nothing stops us from supporting such. | |
| 77 CSize DPI = QueryScreenDPIEx( *this ); | |
| 78 | |
| 79 if ( DPI.cx <= 0 || DPI.cy <= 0 ) { // sanity | |
| 80 DPI = CSize(96, 96); | |
| 81 } | |
| 82 | |
| 83 if ( m_flags & FlagLockMinWidth ) { | |
| 84 ret.m_min_width = MulDiv( 200, DPI.cx, 96 ); | |
| 85 } | |
| 86 if ( m_flags & FlagLockMinHeight ) { | |
| 87 ret.m_min_height = MulDiv( 200, DPI.cy, 96 ); | |
| 88 } | |
| 89 if ( m_flags & FlagLockMaxWidth ) { | |
| 90 ret.m_max_width = MulDiv( 400, DPI.cx, 96 ); | |
| 91 } | |
| 92 if ( m_flags & FlagLockMaxHeight ) { | |
| 93 ret.m_max_height = MulDiv( 400, DPI.cy, 96 ); | |
| 94 } | |
| 95 | |
| 96 // Deal with WS_EX_STATICEDGE and alike that we might have picked from host | |
| 97 ret.adjustForWindow( *this ); | |
| 98 | |
| 99 return ret; | |
| 100 } | |
| 101 | |
| 102 void applyDark() { | |
| 103 t_ui_color color = 0; | |
| 104 if (m_callback->query_color(ui_color_darkmode, color)) { | |
| 105 m_dark.SetDark(color == 0); | |
| 106 } | |
| 107 } | |
| 108 void notify(const GUID& p_what, t_size p_param1, const void* p_param2, t_size p_param2size) override { | |
| 109 // Colors changed? Check dark mode config | |
| 110 if (p_what == ui_element_notify_colors_changed) { | |
| 111 applyDark(); | |
| 112 } | |
| 113 } | |
| 114 private: | |
| 115 static uint32_t parseConfig( ui_element_config::ptr cfg ) { | |
| 116 try { | |
| 117 ::ui_element_config_parser in ( cfg ); | |
| 118 uint32_t flags; in >> flags; | |
| 119 return flags; | |
| 120 } catch(exception_io_data) { | |
| 121 // If we got here, someone's feeding us nonsense, fall back to defaults | |
| 122 return FlagsDefault; | |
| 123 } | |
| 124 } | |
| 125 static ui_element_config::ptr makeConfig(uint32_t flags = FlagsDefault) { | |
| 126 ui_element_config_builder out; | |
| 127 out << flags; | |
| 128 return out.finish( g_get_guid() ); | |
| 129 } | |
| 130 void configToUI() { | |
| 131 for ( unsigned i = 0; i < PFC_TABSIZE( flagsAndButtons ); ++ i ) { | |
| 132 auto rec = flagsAndButtons[i]; | |
| 133 // CCheckBox: WTL-PP class overlaying ToggleCheck(bool) and bool IsChecked() over WTL CButton | |
| 134 CCheckBox cb ( GetDlgItem( rec.btnID ) ); | |
| 135 cb.ToggleCheck( (m_flags & rec.flag ) != 0 ); | |
| 136 } | |
| 137 } | |
| 138 void OnButtonClicked(UINT uNotifyCode, int nID, CWindow wndCtl) { | |
| 139 | |
| 140 uint32_t flagToFlip = 0; | |
| 141 for ( unsigned i = 0; i < PFC_TABSIZE( flagsAndButtons ); ++ i ) { | |
| 142 auto rec = flagsAndButtons[i]; | |
| 143 if ( rec.btnID == nID ) { | |
| 144 flagToFlip = rec.flag; | |
| 145 } | |
| 146 } | |
| 147 if ( flagToFlip != 0 ) { | |
| 148 uint32_t newFlags = m_flags; | |
| 149 CCheckBox cb ( wndCtl ); | |
| 150 if (cb.IsChecked()) { | |
| 151 newFlags |= flagToFlip; | |
| 152 } else { | |
| 153 newFlags &= ~flagToFlip; | |
| 154 } | |
| 155 if ( newFlags != m_flags ) { | |
| 156 m_flags = newFlags; | |
| 157 m_callback->on_min_max_info_change(); | |
| 158 } | |
| 159 } | |
| 160 } | |
| 161 | |
| 162 void OnSize(UINT, CSize s) { | |
| 163 auto DPI = QueryScreenDPIEx(*this); | |
| 164 | |
| 165 pfc::string_formatter msg; | |
| 166 msg << "Current size: "; | |
| 167 if ( DPI.cx > 0 && DPI.cy > 0 ) { | |
| 168 msg << MulDiv( s.cx, 96, DPI.cx ) << "x" << MulDiv( s.cy, 96, DPI.cy ) << " units, "; | |
| 169 } | |
| 170 msg << s.cx << "x" << s.cy << " pixels"; | |
| 171 | |
| 172 uSetDlgItemText( *this, IDC_STATIC_SIZE, msg ); | |
| 173 } | |
| 174 BOOL OnInitDialog(CWindow, LPARAM) { | |
| 175 | |
| 176 // First tell m_dark whether we're dark nor not | |
| 177 applyDark(); | |
| 178 // Then initialize it | |
| 179 m_dark.AddDialogWithControls(*this); | |
| 180 // The above two work in any order, though this way is slightly more efficient | |
| 181 | |
| 182 configToUI(); | |
| 183 { | |
| 184 CRect rc; | |
| 185 // WIN32_OP_D() - Debug build only retval check and assert | |
| 186 // For stuff that practically never fails | |
| 187 WIN32_OP_D( GetClientRect( &rc ) ); | |
| 188 OnSize( 0, rc.Size() ); | |
| 189 } | |
| 190 | |
| 191 return FALSE; | |
| 192 } | |
| 193 const ui_element_instance_callback::ptr m_callback; | |
| 194 uint32_t m_flags; | |
| 195 | |
| 196 // No fb2k::CDarkModeHooks. | |
| 197 // Politely ask our callback if we should render as dark or not, instead of using global settings. | |
| 198 // Though in real life it's all the same in the end. | |
| 199 DarkMode::CHooks m_dark; | |
| 200 }; | |
| 201 | |
| 202 | |
| 203 static service_factory_single_t< ui_element_impl< CDialogUIElem > > g_CDialogUIElem_factory; | |
| 204 } | |
| 205 |
