Mercurial > foo_out_sdl
comparison foosdk/sdk/foobar2000/SDK/ui_element.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 "foobar2000-sdk-pch.h" | |
| 2 #include "ui_element.h" | |
| 3 | |
| 4 | |
| 5 namespace { | |
| 6 class ui_element_config_impl : public ui_element_config { | |
| 7 public: | |
| 8 ui_element_config_impl(const GUID & guid) : m_guid(guid) {} | |
| 9 ui_element_config_impl(const GUID & guid, const void * buffer, t_size size) : m_guid(guid) { | |
| 10 m_content.set_data_fromptr(reinterpret_cast<const t_uint8*>(buffer),size); | |
| 11 } | |
| 12 | |
| 13 void * get_data_var() {return m_content.get_ptr();} | |
| 14 void set_data_size(t_size size) {m_content.set_size(size);} | |
| 15 | |
| 16 GUID get_guid() const {return m_guid;} | |
| 17 const void * get_data() const {return m_content.get_ptr();} | |
| 18 t_size get_data_size() const {return m_content.get_size();} | |
| 19 private: | |
| 20 const GUID m_guid; | |
| 21 pfc::array_t<t_uint8> m_content; | |
| 22 }; | |
| 23 | |
| 24 } | |
| 25 | |
| 26 service_ptr_t<ui_element_config> ui_element_config::g_create(const GUID& id, const void * data, t_size size) { | |
| 27 return new service_impl_t<ui_element_config_impl>(id,data,size); | |
| 28 } | |
| 29 | |
| 30 service_ptr_t<ui_element_config> ui_element_config::g_create(const GUID & id, stream_reader * in, t_size bytes, abort_callback & abort) { | |
| 31 service_ptr_t<ui_element_config_impl> data = new service_impl_t<ui_element_config_impl>(id); | |
| 32 data->set_data_size(bytes); | |
| 33 in->read_object(data->get_data_var(),bytes,abort); | |
| 34 return data; | |
| 35 } | |
| 36 | |
| 37 service_ptr_t<ui_element_config> ui_element_config::g_create(stream_reader * in, t_size bytes, abort_callback & abort) { | |
| 38 if (bytes < sizeof(GUID)) throw exception_io_data_truncation(); | |
| 39 GUID id; | |
| 40 { stream_reader_formatter<> str(*in,abort); str >> id;} | |
| 41 return g_create(id,in,bytes - sizeof(GUID),abort); | |
| 42 } | |
| 43 | |
| 44 ui_element_config::ptr ui_element_config_parser::subelement(t_size size) { | |
| 45 return ui_element_config::g_create(&m_stream, size, m_abort); | |
| 46 } | |
| 47 ui_element_config::ptr ui_element_config_parser::subelement(const GUID & id, t_size dataSize) { | |
| 48 return ui_element_config::g_create(id, &m_stream, dataSize, m_abort); | |
| 49 } | |
| 50 | |
| 51 service_ptr_t<ui_element_config> ui_element_config::g_create(const void * data, t_size size) { | |
| 52 stream_reader_memblock_ref stream(data,size); | |
| 53 return g_create(&stream,size,fb2k::noAbort); | |
| 54 } | |
| 55 | |
| 56 #ifdef _WIN32 | |
| 57 | |
| 58 namespace { | |
| 59 struct sysColorMapping_t { | |
| 60 GUID guid; int idx; | |
| 61 }; | |
| 62 static const sysColorMapping_t sysColorMapping[] = { | |
| 63 { ui_color_text, COLOR_WINDOWTEXT }, | |
| 64 { ui_color_background, COLOR_WINDOW }, | |
| 65 { ui_color_highlight, COLOR_HOTLIGHT }, | |
| 66 {ui_color_selection, COLOR_HIGHLIGHT}, | |
| 67 }; | |
| 68 } | |
| 69 int ui_color_to_sys_color_index(const GUID & p_guid) { | |
| 70 for( unsigned i = 0; i < PFC_TABSIZE( sysColorMapping ); ++ i ) { | |
| 71 if ( p_guid == sysColorMapping[i].guid ) return sysColorMapping[i].idx; | |
| 72 } | |
| 73 return -1; | |
| 74 } | |
| 75 GUID ui_color_from_sys_color_index(int idx) { | |
| 76 for (unsigned i = 0; i < PFC_TABSIZE(sysColorMapping); ++i) { | |
| 77 if (idx == sysColorMapping[i].idx) return sysColorMapping[i].guid; | |
| 78 } | |
| 79 return pfc::guid_null; | |
| 80 } | |
| 81 #endif // _WIN32 | |
| 82 | |
| 83 bool ui_element_subclass_description(const GUID & id, pfc::string_base & p_out) { | |
| 84 if (id == ui_element_subclass_playlist_renderers) { | |
| 85 p_out = "Playlist Renderers"; return true; | |
| 86 } else if (id == ui_element_subclass_media_library_viewers) { | |
| 87 p_out = "Media Library Viewers"; return true; | |
| 88 } else if (id == ui_element_subclass_selection_information) { | |
| 89 p_out = "Selection Information"; return true; | |
| 90 } else if (id == ui_element_subclass_playback_visualisation) { | |
| 91 p_out = "Playback Visualization"; return true; | |
| 92 } else if (id == ui_element_subclass_playback_information) { | |
| 93 p_out = "Playback Information"; return true; | |
| 94 } else if (id == ui_element_subclass_utility) { | |
| 95 p_out = "Utility"; return true; | |
| 96 } else if (id == ui_element_subclass_containers) { | |
| 97 p_out = "Containers"; return true; | |
| 98 } else if ( id == ui_element_subclass_dsp ) { | |
| 99 p_out = "DSP"; return true; | |
| 100 } else { | |
| 101 return false; | |
| 102 } | |
| 103 } | |
| 104 | |
| 105 bool ui_element::get_element_group(pfc::string_base & p_out) { | |
| 106 return ui_element_subclass_description(get_subclass(),p_out); | |
| 107 } | |
| 108 | |
| 109 t_ui_color ui_element_instance_callback::query_std_color(const GUID & p_what) { | |
| 110 #ifdef _WIN32 | |
| 111 t_ui_color ret; | |
| 112 if (query_color(p_what,ret)) return ret; | |
| 113 int idx = ui_color_to_sys_color_index(p_what); | |
| 114 if (idx < 0) return 0;//should not be triggerable | |
| 115 return GetSysColor(idx); | |
| 116 #else | |
| 117 throw pfc::exception_not_implemented(); | |
| 118 #endif | |
| 119 } | |
| 120 #ifdef _WIN32 | |
| 121 t_ui_color ui_element_instance_callback::getSysColor(int sysColorIndex) { | |
| 122 GUID guid = ui_color_from_sys_color_index( sysColorIndex ); | |
| 123 if ( guid != pfc::guid_null ) return query_std_color(guid); | |
| 124 return GetSysColor(sysColorIndex); | |
| 125 } | |
| 126 #endif | |
| 127 | |
| 128 bool ui_element::g_find(service_ptr_t<ui_element> & out, const GUID & id) { | |
| 129 return service_by_guid(out, id); | |
| 130 } | |
| 131 | |
| 132 bool ui_element::g_get_name(pfc::string_base & p_out,const GUID & p_guid) { | |
| 133 ui_element::ptr ptr; if (!g_find(ptr,p_guid)) return false; | |
| 134 ptr->get_name(p_out); return true; | |
| 135 } | |
| 136 | |
| 137 bool ui_element_instance_callback::is_elem_visible_(service_ptr_t<class ui_element_instance> elem) { | |
| 138 ui_element_instance_callback_v2::ptr v2; | |
| 139 if (!this->service_query_t(v2)) { | |
| 140 PFC_ASSERT(!"Should not get here - somebody implemented ui_element_instance_callback but not ui_element_instance_callback_v2."); | |
| 141 return true; | |
| 142 } | |
| 143 return v2->is_elem_visible(elem); | |
| 144 } | |
| 145 | |
| 146 bool ui_element_instance_callback::set_elem_label(ui_element_instance * source, const char * label) { | |
| 147 return notify_(source, ui_element_host_notify_set_elem_label, 0, label, strlen(label)) != 0; | |
| 148 } | |
| 149 | |
| 150 t_uint32 ui_element_instance_callback::get_dialog_texture(ui_element_instance * source) { | |
| 151 return (t_uint32) notify_(source, ui_element_host_notify_get_dialog_texture, 0, NULL, 0); | |
| 152 } | |
| 153 | |
| 154 bool ui_element_instance_callback::is_border_needed(ui_element_instance * source) { | |
| 155 return notify_(source, ui_element_host_notify_is_border_needed, 0, NULL, 0) != 0; | |
| 156 } | |
| 157 | |
| 158 bool ui_element_instance_callback::is_dark_mode() { | |
| 159 t_ui_color clr = 0xFFFFFF; | |
| 160 if (this->query_color(ui_color_darkmode, clr)) return clr == 0; | |
| 161 return false; | |
| 162 } | |
| 163 | |
| 164 t_size ui_element_instance_callback::notify_(ui_element_instance * source, const GUID & what, t_size param1, const void * param2, t_size param2size) { | |
| 165 ui_element_instance_callback_v3::ptr v3; | |
| 166 if (!this->service_query_t(v3)) { PFC_ASSERT(!"Outdated UI Element host implementation"); return 0; } | |
| 167 return v3->notify(source, what, param1, param2, param2size); | |
| 168 } | |
| 169 | |
| 170 | |
| 171 #ifdef _WIN32 | |
| 172 const ui_element_min_max_info & ui_element_min_max_info::operator|=(const ui_element_min_max_info & p_other) { | |
| 173 m_min_width = pfc::max_t(m_min_width,p_other.m_min_width); | |
| 174 m_min_height = pfc::max_t(m_min_height,p_other.m_min_height); | |
| 175 m_max_width = pfc::min_t(m_max_width,p_other.m_max_width); | |
| 176 m_max_height = pfc::min_t(m_max_height,p_other.m_max_height); | |
| 177 return *this; | |
| 178 } | |
| 179 ui_element_min_max_info ui_element_min_max_info::operator|(const ui_element_min_max_info & p_other) const { | |
| 180 ui_element_min_max_info ret(*this); | |
| 181 ret |= p_other; | |
| 182 return ret; | |
| 183 } | |
| 184 | |
| 185 void ui_element_min_max_info::adjustForWindow(HWND wnd) { | |
| 186 RECT client = {0,0,10,10}; | |
| 187 RECT adjusted = client; | |
| 188 BOOL bMenu = FALSE; | |
| 189 const DWORD style = (DWORD) GetWindowLong( wnd, GWL_STYLE ); | |
| 190 if ( style & WS_POPUP ) { | |
| 191 bMenu = GetMenu( wnd ) != NULL; | |
| 192 } | |
| 193 if (AdjustWindowRectEx( &adjusted, style, bMenu, GetWindowLong(wnd, GWL_EXSTYLE) )) { | |
| 194 int dx = (adjusted.right - adjusted.left) - (client.right - client.left); | |
| 195 int dy = (adjusted.bottom - adjusted.top) - (client.bottom - client.top); | |
| 196 if ( dx < 0 ) dx = 0; | |
| 197 if ( dy < 0 ) dy = 0; | |
| 198 m_min_width += dx; | |
| 199 m_min_height += dy; | |
| 200 if ( m_max_width != ~0 ) m_max_width += dx; | |
| 201 if ( m_max_height != ~0 ) m_max_height += dy; | |
| 202 } | |
| 203 } | |
| 204 //! Retrieves element's minimum/maximum window size. Default implementation will fall back to WM_GETMINMAXINFO. | |
| 205 ui_element_min_max_info ui_element_instance::get_min_max_info() { | |
| 206 ui_element_min_max_info ret; | |
| 207 MINMAXINFO temp = {}; | |
| 208 temp.ptMaxTrackSize.x = 1024*1024;//arbitrary huge number | |
| 209 temp.ptMaxTrackSize.y = 1024*1024; | |
| 210 SendMessage(this->get_wnd(),WM_GETMINMAXINFO,0,(LPARAM)&temp); | |
| 211 if (temp.ptMinTrackSize.x >= 0) ret.m_min_width = temp.ptMinTrackSize.x; | |
| 212 if (temp.ptMaxTrackSize.x > 0) ret.m_max_width = temp.ptMaxTrackSize.x; | |
| 213 if (temp.ptMinTrackSize.y >= 0) ret.m_min_height = temp.ptMinTrackSize.y; | |
| 214 if (temp.ptMaxTrackSize.y > 0) ret.m_max_height = temp.ptMaxTrackSize.y; | |
| 215 return ret; | |
| 216 } | |
| 217 #else | |
| 218 ui_element_min_max_info ui_element_instance::get_min_max_info() { | |
| 219 return {}; | |
| 220 } | |
| 221 #endif | |
| 222 | |
| 223 namespace { | |
| 224 class ui_element_replace_dialog_notify_impl : public ui_element_replace_dialog_notify { | |
| 225 public: | |
| 226 void on_cancelled() { | |
| 227 reply(pfc::guid_null); | |
| 228 } | |
| 229 void on_ok(const GUID & guid) { | |
| 230 reply(guid); | |
| 231 } | |
| 232 std::function<void(GUID)> reply; | |
| 233 }; | |
| 234 } | |
| 235 ui_element_replace_dialog_notify::ptr ui_element_replace_dialog_notify::create(std::function<void(GUID)> reply) { | |
| 236 auto obj = fb2k::service_new<ui_element_replace_dialog_notify_impl>(); | |
| 237 obj->reply = reply; | |
| 238 return obj; | |
| 239 } | |
| 240 | |
| 241 bool ui_config_manager::is_dark_mode() { | |
| 242 PFC_ASSERT(core_api::is_main_thread()); | |
| 243 t_ui_color clr = 0xFFFFFF; | |
| 244 if (this->query_color(ui_color_darkmode, clr)) return clr == 0; | |
| 245 return false; | |
| 246 } | |
| 247 bool ui_config_manager::g_is_dark_mode() { | |
| 248 PFC_ASSERT(core_api::is_main_thread()); | |
| 249 auto api = tryGet(); | |
| 250 if (api.is_valid()) return api->is_dark_mode(); | |
| 251 else return false; | |
| 252 } | |
| 253 #ifdef _WIN32 | |
| 254 t_ui_color ui_config_manager::getSysColor(int sysColorIndex) { | |
| 255 PFC_ASSERT(core_api::is_main_thread()); | |
| 256 GUID guid = ui_color_from_sys_color_index(sysColorIndex); | |
| 257 if (guid != pfc::guid_null) { | |
| 258 t_ui_color ret = 0; | |
| 259 if (query_color(guid, ret)) return ret; | |
| 260 } | |
| 261 return GetSysColor(sysColorIndex); | |
| 262 } | |
| 263 #endif | |
| 264 | |
| 265 ui_config_callback_impl::ui_config_callback_impl() { | |
| 266 PFC_ASSERT(core_api::is_main_thread()); | |
| 267 auto api = ui_config_manager::tryGet(); | |
| 268 if (api.is_valid()) api->add_callback(this); | |
| 269 } | |
| 270 | |
| 271 ui_config_callback_impl::~ui_config_callback_impl() { | |
| 272 PFC_ASSERT(core_api::is_main_thread()); | |
| 273 auto api = ui_config_manager::tryGet(); | |
| 274 if (api.is_valid()) api->remove_callback(this); | |
| 275 } |
