diff --git a/foobar2000/ATLHelpers/ATLHelpers.h b/foobar2000/ATLHelpers/ATLHelpers.h new file mode 100644 index 0000000..31f56f8 --- /dev/null +++ b/foobar2000/ATLHelpers/ATLHelpers.h @@ -0,0 +1,23 @@ +#pragma once + +#include "ATLHelpersLean.h" + +// #pragma message("Avoid using this header. #include ATLHelpersLean.h then individual helpers instead") + +#include "../helpers/helpers.h" + +#include "WTL-PP.h" +#include "misc.h" +#include "GDIUtils.h" + +#include "WindowPositionUtils.h" +#include "CDialogResizeHelper.h" + +#include "BumpableElem.h" + +#include "inplace_edit.h" +#include "inplace_edit_v2.h" + +#include "AutoComplete.h" + +#include "Controls.h" \ No newline at end of file diff --git a/foobar2000/helpers/foobar2000+atl.h b/foobar2000/ATLHelpers/ATLHelpersLean.h similarity index 100% rename from foobar2000/helpers/foobar2000+atl.h rename to foobar2000/ATLHelpers/ATLHelpersLean.h diff --git a/foobar2000/ATLHelpers/AutoComplete.cpp b/foobar2000/ATLHelpers/AutoComplete.cpp new file mode 100644 index 0000000..fb1ad2e --- /dev/null +++ b/foobar2000/ATLHelpers/AutoComplete.cpp @@ -0,0 +1,184 @@ +#include "stdafx.h" +#include // CLSID_AutoComplete +#include "../helpers/COM_utils.h" +#include "../helpers/dropdown_helper.h" + + +namespace { + +class CEnumString : public IEnumString { +public: + typedef pfc::chain_list_v2_t > t_data; + CEnumString(const t_data & in) : m_data(in) {m_walk = m_data.first();} + CEnumString() {} + + void AddString(const TCHAR * in) { + m_data.insert_last()->set_data_fromptr(in, _tcslen(in) + 1); + m_walk = m_data.first(); + } + void AddStringU(const char * in, t_size len) { + pfc::array_t & arr = * m_data.insert_last(); + arr.set_size( pfc::stringcvt::estimate_utf8_to_wide( in, len ) ); + pfc::stringcvt::convert_utf8_to_wide( arr.get_ptr(), arr.get_size(), in, len); + m_walk = m_data.first(); + } + void AddStringU(const char * in) { + pfc::array_t & arr = * m_data.insert_last(); + arr.set_size( pfc::stringcvt::estimate_utf8_to_wide( in ) ); + pfc::stringcvt::convert_utf8_to_wide_unchecked( arr.get_ptr(), in ); + m_walk = m_data.first(); + } + void ResetStrings() {m_walk.invalidate(); m_data.remove_all();} + + typedef ImplementCOMRefCounter TImpl; + COM_QI_BEGIN() + COM_QI_ENTRY(IUnknown) + COM_QI_ENTRY(IEnumString) + COM_QI_END() + + HRESULT STDMETHODCALLTYPE Next( ULONG celt, LPOLESTR *rgelt, ULONG *pceltFetched) { + if (rgelt == NULL) return E_INVALIDARG; + ULONG done = 0; + while( done < celt && m_walk.is_valid()) { + rgelt[done] = CoStrDup(m_walk->get_ptr()); + ++m_walk; ++done; + } + if (pceltFetched != NULL) *pceltFetched = done; + return done == celt ? S_OK : S_FALSE; + } + + static TCHAR * CoStrDup(const TCHAR * in) { + const size_t lenBytes = (_tcslen(in) + 1) * sizeof(TCHAR); + TCHAR * out = reinterpret_cast(CoTaskMemAlloc(lenBytes)); + if (out) memcpy(out, in, lenBytes); + return out; + } + + HRESULT STDMETHODCALLTYPE Skip(ULONG celt) { + while(celt > 0) { + if (m_walk.is_empty()) return S_FALSE; + --celt; ++m_walk; + } + return S_OK; + } + + HRESULT STDMETHODCALLTYPE Reset() { + m_walk = m_data.first(); + return S_OK; + } + + HRESULT STDMETHODCALLTYPE Clone(IEnumString **ppenum) { + *ppenum = new TImpl(*this); return S_OK; + } +private: + t_data m_data; + t_data::const_iterator m_walk; +}; +class CACList_History : public CEnumString { +public: + CACList_History(cfg_dropdown_history_mt * var) : m_var(var) {Reset();} + typedef ImplementCOMRefCounter TImpl; + + HRESULT STDMETHODCALLTYPE Reset() { + /*if (core_api::assert_main_thread())*/ { + ResetStrings(); + pfc::string8 state; m_var->get_state(state); + for(const char * walk = state;;) { + const char * next = strchr(walk, cfg_dropdown_history_mt::separator); + t_size len = (next != NULL) ? next - walk : ~0; + AddStringU(walk, len); + if (next == NULL) break; + walk = next + 1; + } + } + return __super::Reset(); + } + + HRESULT STDMETHODCALLTYPE Clone(IEnumString **ppenum) { + *ppenum = new TImpl(*this); return S_OK; + } + +private: + cfg_dropdown_history_mt * const m_var; +}; +} + +HRESULT InitializeSimpleAC(HWND edit, IUnknown * vals, DWORD opts) { + pfc::com_ptr_t ac; + HRESULT hr; + hr = CoCreateInstance(CLSID_AutoComplete, NULL, CLSCTX_ALL, IID_IAutoComplete, (void**)ac.receive_ptr()); + if (FAILED(hr)) { + PFC_ASSERT(!"Should not get here - CoCreateInstance/IAutoComplete fail!"); return hr; + } + hr = ac->Init(edit, vals, NULL, NULL); + if (FAILED(hr)) { + PFC_ASSERT(!"Should not get here - ac->Init fail!"); return hr; + } + + pfc::com_ptr_t ac2; + hr = ac->QueryInterface( ac2.receive_ptr() ); + if (FAILED(hr)) { + PFC_ASSERT(!"Should not get here - ac->QueryInterface fail!"); return hr; + } + hr = ac2->SetOptions(opts); + if (FAILED(hr)) { + PFC_ASSERT(!"Should not get here - ac2->SetOptions fail!"); return hr; + } + return S_OK; +} + +pfc::com_ptr_t CreateACList(pfc::const_iterator valueEnum) { + pfc::com_ptr_t acl = new CEnumString::TImpl(); + while(valueEnum.is_valid()) { + acl->AddStringU(*valueEnum); ++valueEnum; + } + return acl; +} +pfc::com_ptr_t CreateACList(pfc::const_iterator valueEnum) { + pfc::com_ptr_t acl = new CEnumString::TImpl(); + while(valueEnum.is_valid()) { + acl->AddStringU(*valueEnum); ++valueEnum; + } + return acl; +} +pfc::com_ptr_t CreateACList(pfc::const_iterator valueEnum) { + pfc::com_ptr_t acl = new CEnumString::TImpl(); + while(valueEnum.is_valid()) { + acl->AddStringU(valueEnum->ptr()); ++valueEnum; + } + return acl; +} + +pfc::com_ptr_t CreateACList() { + return new CEnumString::TImpl(); +} + +void CreateACList_AddItem(IUnknown * theList, const char * item) { + static_cast(theList)->AddStringU( item ); +} + +HRESULT InitializeEditAC(HWND edit, pfc::const_iterator valueEnum, DWORD opts) { + pfc::com_ptr_t acl = CreateACList(valueEnum); + return InitializeSimpleAC(edit, acl.get_ptr(), opts); +} +HRESULT InitializeEditAC(HWND edit, const char * values, DWORD opts) { + pfc::com_ptr_t acl = new CEnumString::TImpl(); + for(const char * walk = values;;) { + const char * next = strchr(walk, cfg_dropdown_history_mt::separator); + if (next == NULL) {acl->AddStringU(walk, ~0); break;} + acl->AddStringU(walk, next - walk); + walk = next + 1; + } + return InitializeSimpleAC(edit, acl.get_ptr(), opts); +} + +HRESULT InitializeDropdownAC(HWND comboBox, cfg_dropdown_history_mt & var, const char * initVal) { + var.on_init(comboBox, initVal); + COMBOBOXINFO ci = {}; ci.cbSize = sizeof(ci); + if (!GetComboBoxInfo(comboBox, &ci)) { + PFC_ASSERT(!"Should not get here - GetComboBoxInfo fail!"); + return E_FAIL; + } + pfc::com_ptr_t acl = new CACList_History::TImpl(&var); + return InitializeSimpleAC(ci.hwndItem, acl.get_ptr(), ACO_AUTOAPPEND|ACO_AUTOSUGGEST); +} diff --git a/libPPUI/AutoComplete.h b/foobar2000/ATLHelpers/AutoComplete.h similarity index 71% rename from libPPUI/AutoComplete.h rename to foobar2000/ATLHelpers/AutoComplete.h index c6865d8..f4d1f81 100644 --- a/libPPUI/AutoComplete.h +++ b/foobar2000/ATLHelpers/AutoComplete.h @@ -2,11 +2,15 @@ #include -HRESULT InitializeEditAC(HWND edit, pfc::const_iterator valueEnum, DWORD opts = ACO_AUTOAPPEND | ACO_AUTOSUGGEST); -HRESULT InitializeEditAC(HWND edit, const char * values, DWORD opts = ACO_AUTOAPPEND | ACO_AUTOSUGGEST); +class cfg_dropdown_history_mt; + +HRESULT InitializeDropdownAC(HWND comboBox, cfg_dropdown_history_mt & var, const char * initVal); +HRESULT InitializeEditAC(HWND edit, const char * values, DWORD opts = ACO_AUTOAPPEND|ACO_AUTOSUGGEST); +HRESULT InitializeEditAC(HWND edit, pfc::const_iterator valueEnum, DWORD opts = ACO_AUTOAPPEND|ACO_AUTOSUGGEST); HRESULT InitializeSimpleAC(HWND edit, IUnknown * vals, DWORD opts); pfc::com_ptr_t CreateACList(pfc::const_iterator valueEnum); pfc::com_ptr_t CreateACList(pfc::const_iterator valueEnum); pfc::com_ptr_t CreateACList(pfc::const_iterator valueEnum); pfc::com_ptr_t CreateACList(); void CreateACList_AddItem(IUnknown * theList, const char * item); + diff --git a/foobar2000/helpers/BumpableElem.h b/foobar2000/ATLHelpers/BumpableElem.h similarity index 86% rename from foobar2000/helpers/BumpableElem.h rename to foobar2000/ATLHelpers/BumpableElem.h index cb46859..a49087c 100644 --- a/foobar2000/helpers/BumpableElem.h +++ b/foobar2000/ATLHelpers/BumpableElem.h @@ -1,7 +1,6 @@ #pragma once - -#include -#include "atl-misc.h" +#include "CFlashWindow.h" +#include "misc.h" #include @@ -39,7 +38,7 @@ private: SetMsgHandled(FALSE); } bool _bump() { - if (m_selfDestruct || this->m_hWnd == NULL) return false; + if (m_selfDestruct || m_hWnd == NULL) return false; //PROBLEM: This assumes we're implementing service_base methods at this point. Explodes if called during constructors/destructors. if (!this->m_callback->request_activation(this)) return false; m_flash.Activate(*this); @@ -62,12 +61,12 @@ pfc::avltree_t *> ImplementBumpableElem::i template class ui_element_impl_withpopup : public ui_element_impl, TInterface> { public: - t_uint32 get_flags() {return ui_element_v2::KFlagHavePopupCommand | ui_element_v2::KFlagSupportsBump;} + t_uint32 get_flags() {return KFlagHavePopupCommand | KFlagSupportsBump;} bool bump() {return ImplementBumpableElem::Bump();} }; template class ui_element_impl_visualisation : public ui_element_impl, TInterface> { public: - t_uint32 get_flags() {return ui_element_v2::KFlagsVisualisation | ui_element_v2::KFlagSupportsBump;} + t_uint32 get_flags() {return KFlagsVisualisation | KFlagSupportsBump;} bool bump() {return ImplementBumpableElem::Bump();} }; diff --git a/libPPUI/CButtonLite.h b/foobar2000/ATLHelpers/CButtonLite.h similarity index 95% rename from libPPUI/CButtonLite.h rename to foobar2000/ATLHelpers/CButtonLite.h index 7d99a8a..dfa7822 100644 --- a/libPPUI/CButtonLite.h +++ b/foobar2000/ATLHelpers/CButtonLite.h @@ -1,9 +1,7 @@ #pragma once #include -#include #include "WTL-PP.h" -#include "win32_op.h" typedef CWinTraits CButtonLiteTraits; @@ -31,24 +29,22 @@ public: unsigned Measure() { auto font = myGetFont(); LOGFONT lf; - WIN32_OP_D(font.GetLogFont(lf)); + font.GetLogFont( lf ); MakeBoldFont( lf ); CFont bold; - WIN32_OP_D(bold.CreateFontIndirect(&lf)); + bold.CreateFontIndirect(&lf); CWindowDC dc(*this); auto oldFont = dc.SelectFont( bold ); CSize size (0,0); + CSize sizeSpace (0,0); - { - CString measure; - measure = L"#"; - measure += m_textDrawMe; - WIN32_OP_D(dc.GetTextExtent(measure, measure.GetLength(), &size)); - } + + dc.GetTextExtent(m_textDrawMe, m_textDrawMe.GetLength(), &size); + dc.GetTextExtent(L" ", 1, &sizeSpace); dc.SelectFont( oldFont ); - return size.cx; + return size.cx + sizeSpace.cx; } std::function< void (HWND) > TabCycleHandler; std::function< HBRUSH (CDCHandle) > CtlColorHandler; @@ -222,9 +218,8 @@ private: return false; } if ( cMsg == WM_LBUTTONUP ) { - bool wasPressed = m_pressed; + if ( m_pressed ) OnClicked(); TogglePressed(false); - if ( wasPressed ) OnClicked(); return false; } CRect rcClient; diff --git a/foobar2000/ATLHelpers/CDialogResizeHelper.cpp b/foobar2000/ATLHelpers/CDialogResizeHelper.cpp new file mode 100644 index 0000000..5454bdf --- /dev/null +++ b/foobar2000/ATLHelpers/CDialogResizeHelper.cpp @@ -0,0 +1,141 @@ +#include "stdafx.h" + +#include "../helpers/win32_misc.h" +#include "CDialogResizeHelper.h" + +bool CDialogResizeHelper::EvalRect(UINT id, CRect & out) const { + for(t_size walk = 0; walk < m_table.get_size(); ++walk) { + if (m_table[walk].id == id) { + CRect client; WIN32_OP_D( m_thisWnd.GetClientRect(client) ); + return _EvalRect(walk, client.Size(), out); + } + } + return false; +} + +bool CDialogResizeHelper::_EvalRect(t_size index, CSize wndSize, CRect & out) const { + CRect rc; + const Param & e = m_table[index]; + if (m_origRects.query(e.id, rc)) { + int delta_x = wndSize.cx - m_rcOrigClient.right, + delta_y = wndSize.cy - m_rcOrigClient.bottom; + + rc.left += pfc::rint32( e.snapLeft * delta_x ); + rc.right += pfc::rint32( e.snapRight * delta_x ); + rc.top += pfc::rint32(e.snapTop * delta_y ); + rc.bottom += pfc::rint32(e.snapBottom * delta_y ); + + out = rc; + return true; + } + return false; +} + +void CDialogResizeHelper::OnSize(UINT, CSize newSize) +{ + if (m_thisWnd != NULL) { + HDWP hWinPosInfo = BeginDeferWindowPos( m_table.get_size() + (m_sizeGrip != NULL ? 1 : 0) ); + for(t_size n = 0; n < m_table.get_size(); ++n) { + CRect rc; + if (_EvalRect(n, newSize, rc)) { + hWinPosInfo = DeferWindowPos(hWinPosInfo, m_thisWnd.GetDlgItem(m_table[n].id), 0, rc.left,rc.top,rc.Width(),rc.Height(),SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS); + } + } + if (m_sizeGrip != NULL) + { + RECT rc, rc_grip; + if (m_thisWnd.GetClientRect(&rc) && m_sizeGrip.GetWindowRect(&rc_grip)) { + DWORD flags = SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOCOPYBITS; + if (IsZoomed(m_thisWnd)) flags |= SWP_HIDEWINDOW; + else flags |= SWP_SHOWWINDOW; + hWinPosInfo = DeferWindowPos(hWinPosInfo, m_sizeGrip, NULL, rc.right - (rc_grip.right - rc_grip.left), rc.bottom - (rc_grip.bottom - rc_grip.top), 0, 0, flags ); + } + } + EndDeferWindowPos(hWinPosInfo); + //RedrawWindow(m_thisWnd, NULL, NULL, RDW_UPDATENOW | RDW_ALLCHILDREN); + } + SetMsgHandled(FALSE); +} + +void CDialogResizeHelper::OnGetMinMaxInfo(LPMINMAXINFO info) const { + CRect r; + const DWORD dwStyle = m_thisWnd.GetWindowLong(GWL_STYLE); + const DWORD dwExStyle = m_thisWnd.GetWindowLong(GWL_EXSTYLE); + if (max_x && max_y) + { + r.left = 0; r.right = max_x; + r.top = 0; r.bottom = max_y; + MapDialogRect(m_thisWnd,&r); + AdjustWindowRectEx(&r, dwStyle, FALSE, dwExStyle); + info->ptMaxTrackSize.x = r.right - r.left; + info->ptMaxTrackSize.y = r.bottom - r.top; + } + if (min_x && min_y) + { + r.left = 0; r.right = min_x; + r.top = 0; r.bottom = min_y; + MapDialogRect(m_thisWnd,&r); + AdjustWindowRectEx(&r, dwStyle, FALSE, dwExStyle); + info->ptMinTrackSize.x = r.right - r.left; + info->ptMinTrackSize.y = r.bottom - r.top; + } +} + +void CDialogResizeHelper::OnInitDialog(CWindow thisWnd) { + m_origRects.remove_all(); + m_thisWnd = thisWnd; + m_thisWnd.GetClientRect(&m_rcOrigClient); + for(t_size n = 0; n < m_table.get_size(); n++) { + CRect rc; + const UINT id = m_table[n].id; + if (GetChildWindowRect(m_thisWnd,id,&rc)) { + m_origRects.set(id, rc); + } + } + AddSizeGrip(); + SetMsgHandled(FALSE); +} +void CDialogResizeHelper::OnDestroy() { + m_sizeGrip = NULL; m_thisWnd = NULL; + SetMsgHandled(FALSE); +} + +void CDialogResizeHelper::AddSizeGrip() +{ + if (m_thisWnd != NULL && m_sizeGrip == NULL) + { + if (m_thisWnd.GetWindowLong(GWL_STYLE) & WS_POPUP) { + m_sizeGrip = CreateWindowEx(0, WC_SCROLLBAR, _T(""), WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN, + 0, 0, CW_USEDEFAULT, CW_USEDEFAULT, + m_thisWnd, (HMENU)0, NULL, NULL); + if (m_sizeGrip != NULL) + { + RECT rc, rc_grip; + if (m_thisWnd.GetClientRect(&rc) && m_sizeGrip.GetWindowRect(&rc_grip)) { + m_sizeGrip.SetWindowPos(NULL, rc.right - (rc_grip.right - rc_grip.left), rc.bottom - (rc_grip.bottom - rc_grip.top), 0, 0, SWP_NOZORDER | SWP_NOSIZE); + } + } + } + } +} + + +void CDialogResizeHelper::InitTable(const Param* table, t_size tableSize) { + m_table.set_data_fromptr(table, tableSize); +} +void CDialogResizeHelper::InitTable(const ParamOld * table, t_size tableSize) { + m_table.set_size(tableSize); + for(t_size walk = 0; walk < tableSize; ++walk) { + const ParamOld in = table[walk]; + Param entry = {}; + entry.id = table[walk].id; + if (in.flags & dialog_resize_helper::X_MOVE) entry.snapLeft = entry.snapRight = 1; + else if (in.flags & dialog_resize_helper::X_SIZE) entry.snapRight = 1; + if (in.flags & dialog_resize_helper::Y_MOVE) entry.snapTop = entry.snapBottom = 1; + else if (in.flags & dialog_resize_helper::Y_SIZE) entry.snapBottom = 1; + m_table[walk] = entry; + } +} +void CDialogResizeHelper::InitMinMax(const CRect & range) { + min_x = range.left; min_y = range.top; max_x = range.right; max_y = range.bottom; +} diff --git a/foobar2000/ATLHelpers/CDialogResizeHelper.h b/foobar2000/ATLHelpers/CDialogResizeHelper.h new file mode 100644 index 0000000..e68fa9b --- /dev/null +++ b/foobar2000/ATLHelpers/CDialogResizeHelper.h @@ -0,0 +1,69 @@ +#pragma once + +#include "../helpers/dialog_resize_helper.h" +#include "WindowPositionUtils.h" + +class CDialogResizeHelper : public CMessageMap { +public: + typedef dialog_resize_helper::param ParamOld; + + struct Param { + t_uint32 id; + float snapLeft, snapTop, snapRight, snapBottom; + }; +private: + void AddSizeGrip(); +public: + inline void set_min_size(unsigned x,unsigned y) {min_x = x; min_y = y;} + inline void set_max_size(unsigned x,unsigned y) {max_x = x; max_y = y;} + + + BEGIN_MSG_MAP_EX(CDialogResizeHelper) + if (uMsg == WM_INITDIALOG) OnInitDialog(hWnd); + MSG_WM_SIZE(OnSize) + MSG_WM_DESTROY(OnDestroy) + MSG_WM_GETMINMAXINFO(OnGetMinMaxInfo) + END_MSG_MAP() + + template CDialogResizeHelper(const TParam (& src)[paramCount],CRect const& minMaxRange = CRect(0,0,0,0)) { + InitTable(src, paramCount); + InitMinMax(minMaxRange); + } + + void InitTable(const Param* table, t_size tableSize); + void InitTable(const ParamOld * table, t_size tableSize); + void InitMinMax(const CRect & range); + + bool EvalRect(UINT id, CRect & out) const; + +private: + bool _EvalRect(t_size index, CSize wndSize, CRect & out) const; + void OnGetMinMaxInfo(LPMINMAXINFO lpMMI) const; + void OnSize(UINT nType, CSize size); + void OnInitDialog(CWindow thisWnd); + void OnDestroy(); + + pfc::array_t m_table; + pfc::map_t m_origRects; + CRect m_rcOrigClient; + CWindow m_thisWnd, m_sizeGrip; + unsigned min_x,min_y,max_x,max_y; +}; + +template class CDialogResizeHelperTracking : public CDialogResizeHelper { +public: + template CDialogResizeHelperTracking(const TParam (& src)[paramCount],CRect const& minMaxRange, TCfgVar & cfgVar) : CDialogResizeHelper(src, minMaxRange), m_tracker(cfgVar) {} + + BEGIN_MSG_MAP_EX(CDialogResizeHelperST) + CHAIN_MSG_MAP(CDialogResizeHelper) + CHAIN_MSG_MAP_MEMBER(m_tracker) + END_MSG_MAP() + +private: + TTracker m_tracker; +}; + +typedef CDialogResizeHelperTracking CDialogResizeHelperST; +typedef CDialogResizeHelperTracking CDialogResizeHelperPT; + +#define REDRAW_DIALOG_ON_RESIZE() if (uMsg == WM_SIZE) RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN); diff --git a/foobar2000/ATLHelpers/CEditWithButtons.cpp b/foobar2000/ATLHelpers/CEditWithButtons.cpp new file mode 100644 index 0000000..729678a --- /dev/null +++ b/foobar2000/ATLHelpers/CEditWithButtons.cpp @@ -0,0 +1,3 @@ +#include "stdafx.h" +#include "CEditWithButtons.h" +// All in the header - CPP present to make MS intellisense stop showing nonsensical errors \ No newline at end of file diff --git a/libPPUI/CEditWithButtons.h b/foobar2000/ATLHelpers/CEditWithButtons.h similarity index 53% rename from libPPUI/CEditWithButtons.h rename to foobar2000/ATLHelpers/CEditWithButtons.h index 638b685..75b5a3d 100644 --- a/libPPUI/CEditWithButtons.h +++ b/foobar2000/ATLHelpers/CEditWithButtons.h @@ -45,17 +45,52 @@ public: typedef std::function handler_t; typedef std::function condition_t; - void AddMoreButton( std::function f ); - void AddClearButton( const wchar_t * clearVal = L"", bool bHandleEsc = false); - void AddButton( const wchar_t * str, handler_t handler, condition_t condition = nullptr, const wchar_t * drawAlternateText = nullptr ); + void AddMoreButton( std::function f ) { + AddButton(L"\x2026", f); + } + void AddClearButton( const wchar_t * clearVal = L"") { + std::wstring clearValCopy ( clearVal ); + auto handler = [this, clearValCopy] { + this->SetWindowText(clearValCopy.c_str()); + }; + auto condition = [clearValCopy] ( const wchar_t * txt ) -> bool { + return clearValCopy != txt; + }; + // Present "clear" to accessibility APIs but actually draw a multiplication x sign + AddButton(L"clear", handler, condition, L"\x00D7"); + } - static unsigned DefaultFixedWidth() {return GetSystemMetrics(SM_CXVSCROLL) * 3 / 4;} + void AddButton( const wchar_t * str, handler_t handler, condition_t condition = nullptr, const wchar_t * drawAlternateText = nullptr ) { + Button_t btn; + btn.handler = handler; + btn.title = str; + btn.condition = condition; + btn.visible = EvalCondition( btn, nullptr ); + + if ( drawAlternateText != nullptr ) { + btn.titleDraw = drawAlternateText; + } + + m_buttons.push_back(std::move(btn) ); + RefreshButtons(); + } + + static unsigned DefaultFixedWidth() { + return GetSystemMetrics(SM_CXVSCROLL) * 3 / 4; + } void SetFixedWidth(unsigned fw = DefaultFixedWidth() ) { m_fixedWidth = fw; RefreshButtons(); } - CRect RectOfButton( const wchar_t * text ); - + CRect RectOfButton( const wchar_t * text ) { + for ( auto i = m_buttons.begin(); i != m_buttons.end(); ++ i ) { + if ( i->title == text && i->wnd != NULL ) { + CRect rc; + if (i->wnd.GetWindowRect ( rc )) return rc; + } + } + return CRect(); + } void Invalidate() { __super::Invalidate(); for( auto i = m_buttons.begin(); i != m_buttons.end(); ++i ) { @@ -75,11 +110,10 @@ public: void SetHasAutoComplete(bool bValue = true) { m_hasAutoComplete = bValue; } - void RefreshConditions(const wchar_t * newText = nullptr); private: LRESULT OnCheckConditions( UINT msg, WPARAM wp, LPARAM lp ) { if ( msg == MSG_CHECKCONDITIONS && wp == MSG_CHECKCONDITIONS_MAGIC1 && lp == MSG_CHECKCONDITIONS_MAGIC2 ) { - this->RefreshConditions(); + this->RefreshConditions(nullptr); } else { SetMsgHandled(FALSE); } @@ -200,13 +234,132 @@ private: void TabFocusPrevNext(bool bPrev) { FindDialog().PostMessage(WM_NEXTDLGCTL, bPrev ? TRUE : FALSE, FALSE); } - void TabCycleButtons(HWND wnd); + void TabCycleButtons(HWND wnd) { + for( auto i = m_buttons.begin(); i != m_buttons.end(); ++ i ) { + if ( i->wnd == wnd ) { + if (IsShiftPressed()) { + // back + for ( ;; ) { + if (i == m_buttons.begin()) { + TabFocusThis(m_hWnd); break; + } else { + --i; + if ( i->visible ) { + TabFocusThis(i->wnd); + break; + } + } + } + } else { + // forward + for ( ;; ) { + ++i; + if (i == m_buttons.end()) { + TabFocusThis(m_hWnd); + TabFocusPrevNext(false); + break; + } else { + if ( i->visible ) { + TabFocusThis(i->wnd); + break; + } + } + } + } - bool ButtonWantTab( HWND wnd ); - bool EvalCondition( Button_t & btn, const wchar_t * newText ); - void Layout(CSize size, CFontHandle fontSetMe); - unsigned MeasureButton(Button_t const & button ); + return; + } + } + } + bool ButtonWantTab( HWND wnd ) { + if ( IsShiftPressed() ) return true; + if ( m_buttons.size() == 0 ) return false; // should not be possible + auto last = m_buttons.rbegin(); + if ( wnd == last->wnd ) return false; // not for last button + return true; + } + bool EvalCondition( Button_t & btn, const wchar_t * newText ) { + if (!btn.condition) return true; + if ( newText != nullptr ) return btn.condition( newText ); + TCHAR text[256] = {}; + GetWindowText(text, 256); + text[255] = 0; + return btn.condition( text ); + } + void RefreshConditions( const wchar_t * newText ) { + bool changed = false; + for( auto i = m_buttons.begin(); i != m_buttons.end(); ++i ) { + bool status = EvalCondition(*i, newText); + if ( status != i->visible ) { + i->visible = status; changed = true; + } + } + if ( changed ) { + Layout(); + } + } + void Layout(CSize size, CFontHandle fontSetMe) { + if ( m_buttons.size() == 0 ) return; + int walk = size.cx; + + HDWP dwp = BeginDeferWindowPos( (int) m_buttons.size() ); + for( auto iter = m_buttons.rbegin(); iter != m_buttons.rend(); ++iter ) { + if (! iter->visible ) { + if (::GetFocus() == iter->wnd ) { + this->SetFocus(); + } + ::DeferWindowPos( dwp, iter->wnd, NULL, 0,0,0,0, SWP_NOZORDER | SWP_HIDEWINDOW | SWP_NOMOVE | SWP_NOSIZE ); + continue; + } + + if (iter->wnd == NULL) { + auto b = std::make_shared< CButtonLite > ( ); + iter->buttonImpl = b; + b->Create( *this, NULL, iter->title.c_str() ); + if ( iter->titleDraw.length() > 0 ) b->DrawAlternateText( iter->titleDraw.c_str() ); + CFontHandle font = fontSetMe; + if ( font == NULL ) font = GetFont(); + b->SetFont( font ); + b->ClickHandler = iter->handler; + b->CtlColorHandler = [=] (CDCHandle dc) -> HBRUSH { + return this->OnColorBtn( dc, NULL ); + }; + b->TabCycleHandler = [=] (HWND wnd) { + TabCycleButtons(wnd); + }; + b->WantTabCheck = [=] (HWND wnd) -> bool { + return ButtonWantTab(wnd); + }; + if (! IsWindowEnabled( ) ) b->EnableWindow(FALSE); + iter->wnd = * b; + } else if ( fontSetMe ) { + iter->wnd.SetFont( fontSetMe ); + } + + unsigned delta = MeasureButton(*iter); + int left = walk - delta; + + if ( iter->wnd != NULL ) { + CRect rc; + rc.top = 0; + rc.bottom = size.cy; + rc.left = left; + rc.right = walk; + ::DeferWindowPos( dwp, iter->wnd, NULL, rc.left, rc.top, rc.Width(), rc.Height(), SWP_NOZORDER | SWP_SHOWWINDOW); + } + + walk = left; + } + EndDeferWindowPos( dwp ); + this->SetMargins(0, size.cx - walk, EC_RIGHTMARGIN ); + } + + unsigned MeasureButton(Button_t const & button ) { + if ( m_fixedWidth != 0 ) return m_fixedWidth; + + return button.buttonImpl->Measure(); + } unsigned m_fixedWidth; std::list< Button_t > m_buttons; bool m_hasAutoComplete = false; diff --git a/libPPUI/CFlashWindow.h b/foobar2000/ATLHelpers/CFlashWindow.h similarity index 96% rename from libPPUI/CFlashWindow.h rename to foobar2000/ATLHelpers/CFlashWindow.h index 2c8bfa2..a313c35 100644 --- a/libPPUI/CFlashWindow.h +++ b/foobar2000/ATLHelpers/CFlashWindow.h @@ -1,7 +1,5 @@ #pragma once -#include "win32_op.h" - typedef CWinTraits CFlashWindowTraits; class CFlashWindow : public CWindowImpl { @@ -64,6 +62,6 @@ private: return 0; } CWindow m_parent; - uint32_t m_tickCount; + t_uint32 m_tickCount; }; diff --git a/libPPUI/CIconOverlayWindow.h b/foobar2000/ATLHelpers/CIconOverlayWindow.h similarity index 86% rename from libPPUI/CIconOverlayWindow.h rename to foobar2000/ATLHelpers/CIconOverlayWindow.h index d79514b..fce920c 100644 --- a/libPPUI/CIconOverlayWindow.h +++ b/foobar2000/ATLHelpers/CIconOverlayWindow.h @@ -1,10 +1,10 @@ #pragma once -#include "win32_op.h" +#include "../ATLHelpers/misc.h" -typedef CWinTraits _COverlayWindowTraits; +typedef CWinTraits __COverlayWindowTraits; -class CIconOverlayWindow : public CWindowImpl { +class CIconOverlayWindow : public CWindowImpl { public: DECLARE_WND_CLASS_EX(TEXT("{384298D0-4370-4f9b-9C36-49FC1A396DC7}"),0,(-1)); @@ -15,7 +15,7 @@ public: ColorKey = 0xc0ffee }; - BEGIN_MSG_MAP_EX(CIconOverlayWindow) + BEGIN_MSG_MAP(CIconOverlayWindow) MESSAGE_HANDLER(WM_CREATE,OnCreate); MESSAGE_HANDLER(WM_PAINT,OnPaint); MESSAGE_HANDLER(WM_ERASEBKGND,OnEraseBkgnd); diff --git a/libPPUI/CMiddleDragImpl.h b/foobar2000/ATLHelpers/CMiddleDragImpl.h similarity index 72% rename from libPPUI/CMiddleDragImpl.h rename to foobar2000/ATLHelpers/CMiddleDragImpl.h index bafce5c..c7626dd 100644 --- a/libPPUI/CMiddleDragImpl.h +++ b/foobar2000/ATLHelpers/CMiddleDragImpl.h @@ -2,31 +2,19 @@ #include "CIconOverlayWindow.h" #include -#include "ppresources.h" -#include "win32_utility.h" -class CMiddleDragCommon { -public: +template +class CMiddleDragImpl : public TBase { +private: + typedef CMiddleDragImpl TSelf; enum { KTimerID = 0x389675f8, KTimerPeriod = 15, }; - static double myPow(double p_val, double p_exp); - static double ProcessMiddleDragDeltaInternal(double p_delta); - static double radiusHelper(double p_x, double p_y); - static int mySGN(LONG v); - static int32_t Round(double val, double & acc); - static LONG LineToPixelsHelper(LONG & p_overflow, LONG p_pixels, LONG p_dpi, LONG p_lineWidth); -}; - -template -class CMiddleDragImpl : public TBase, protected CMiddleDragCommon { -private: - typedef CMiddleDragImpl TSelf; public: - template CMiddleDragImpl( arg_t && ... arg ) : TBase(std::forward(arg) ... ) {} + template CMiddleDragImpl( arg_t && ... arg ) : TBase(std::forward(arg) ... ) { m_active = false; m_accX = m_accY = 0; } - BEGIN_MSG_MAP_EX(TSelf) + BEGIN_MSG_MAP(TSelf) MESSAGE_HANDLER(WM_TIMER,OnTimer); MESSAGE_HANDLER(WM_CAPTURECHANGED,OnCaptureChanged); MESSAGE_HANDLER(WM_MBUTTONDOWN,OnMButtonDown); @@ -50,10 +38,10 @@ protected: return !m_active; } private: - bool m_active = false, m_dragged = false; + bool m_active, m_dragged; CPoint m_base; CIconOverlayWindow m_overlay; - double m_accX = 0, m_accY = 0; + double m_accX, m_accY; LRESULT OnDestroyPassThru(UINT,WPARAM,LPARAM,BOOL& bHandled) { if (m_overlay != NULL) m_overlay.DestroyWindow(); @@ -74,9 +62,9 @@ private: return 0; } EndDrag(); - this->SetFocus(); + SetFocus(); CPoint pt(p_lp); - WIN32_OP_D( this->ClientToScreen(&pt) ); + WIN32_OP_D( ClientToScreen(&pt) ); StartDrag(pt); return 0; } @@ -85,7 +73,7 @@ private: if (m_active) { if (!m_dragged) { CPoint pt(p_lp); - WIN32_OP_D( this->ClientToScreen(&pt) ); + WIN32_OP_D( ClientToScreen(&pt) ); if (pt != m_base) { m_dragged = true; } @@ -107,10 +95,10 @@ private: ::SetCapture(NULL); if (m_overlay == NULL) { - PFC_ASSERT( this->m_hWnd != NULL ); + PFC_ASSERT( m_hWnd != NULL ); if (m_overlay.Create(*this) == NULL) {PFC_ASSERT(!"Should not get here!"); return;} HANDLE temp; - WIN32_OP_D( (temp = LoadImage(GetThisModuleHandle(),MAKEINTRESOURCE(CPPUIResources::get_IDI_SCROLL()),IMAGE_ICON,32,32,LR_DEFAULTCOLOR)) != NULL ); + WIN32_OP_D( (temp = LoadImage(core_api::get_my_instance(),MAKEINTRESOURCE(IDI_SCROLL),IMAGE_ICON,32,32,LR_DEFAULTCOLOR)) != NULL ); m_overlay.AttachIcon((HICON) temp); } @@ -120,8 +108,8 @@ private: m_dragged = false; m_base = p_point; m_accX = m_accY = 0; - this->SetCapture(); - this->SetTimer(KTimerID,KTimerPeriod); + SetCapture(); + SetTimer(KTimerID,KTimerPeriod); { CSize radius(16,16); @@ -138,7 +126,7 @@ private: void HandleEndDrag() { if (m_active) { m_active = false; - this->KillTimer(KTimerID); + KillTimer(KTimerID); if (m_overlay != NULL) m_overlay.ShowWindow(SW_HIDE); } } @@ -152,7 +140,7 @@ private: LRESULT OnTimer(UINT,WPARAM p_wp,LPARAM,BOOL& bHandled) { switch(p_wp) { case KTimerID: - this->MoveViewOriginDelta(ProcessMiddleDragDelta(CPoint(GetCursorPos()) - m_base)); + this->MoveViewOriginDelta(ProcessMiddleDragDelta(CPoint((LPARAM)GetMessagePos()) - m_base)); return 0; default: bHandled = FALSE; @@ -160,13 +148,27 @@ private: } } + static double myPow(double p_val,double p_exp) { + double ex = pow(pfc::abs_t(p_val),p_exp); + return p_val < 0 ? -ex : ex; + } + + static double ProcessMiddleDragDeltaInternal(double p_delta) { + p_delta *= (double) KTimerPeriod / 25; /*originally calculated for 25ms timer interval*/ + return myPow(p_delta * 0.05,2.0); + } + + static double radiusHelper(double p_x,double p_y) { + return sqrt(p_x * p_x + p_y * p_y); + } + CPoint ProcessMiddleDragDelta(CPoint p_delta) { const CSize dpi = QueryScreenDPIEx(); - if (dpi.cx <= 0 || dpi.cy <= 0 || p_delta == CPoint(0, 0)) return CPoint(0, 0); - const double dpiMulX = 96.0 / (double)dpi.cx; - const double dpiMulY = 96.0 / (double)dpi.cy; + if (dpi.cx <= 0 || dpi.cy <= 0 || p_delta == CPoint(0,0)) return CPoint(0,0); + const double dpiMulX = 96.0 / (double) dpi.cx; + const double dpiMulY = 96.0 / (double) dpi.cy; - const double deltaTotal = ProcessMiddleDragDeltaInternal(radiusHelper((double)p_delta.x * dpiMulX, (double)p_delta.y * dpiMulY)); + const double deltaTotal = ProcessMiddleDragDeltaInternal( radiusHelper( (double) p_delta.x * dpiMulX, (double) p_delta.y * dpiMulY ) ); double xVal = 0, yVal = 0; @@ -175,18 +177,22 @@ private: } else if (p_delta.y == 0) { xVal = deltaTotal; } else { - const double ratio = (double)p_delta.x / (double)p_delta.y; - yVal = sqrt((deltaTotal*deltaTotal) / (1.0 + (ratio*ratio))); + const double ratio = (double) p_delta.x / (double) p_delta.y; + yVal = sqrt(pfc::sqr_t(deltaTotal) / (1.0 + pfc::sqr_t(ratio))); xVal = yVal * ratio; } - xVal = mySGN(p_delta.x) * fabs(xVal); - yVal = mySGN(p_delta.y) * fabs(yVal); - + xVal = pfc::sgn_t( p_delta.x ) * pfc::abs_t(xVal); + yVal = pfc::sgn_t( p_delta.y ) * pfc::abs_t(yVal); return CPoint(Round(xVal / dpiMulX, m_accX), Round(yVal / dpiMulY, m_accY)); } - + static t_int32 Round(double val, double & acc) { + val += acc; + t_int32 ret = pfc::rint32(val); + acc = val - ret; + return ret; + } }; template @@ -196,7 +202,7 @@ private: public: template CMiddleDragWrapper(arg_t && ... arg ) : TBase(std::forward(arg) ... ) { m_overflow = CPoint(0, 0); m_lineWidth = CSize(4, 16); } - BEGIN_MSG_MAP_EX(TSelf) + BEGIN_MSG_MAP(TSelf) MESSAGE_HANDLER(WM_CAPTURECHANGED,OnCaptureChanged); CHAIN_MSG_MAP(TBase) END_MSG_MAP() @@ -212,7 +218,7 @@ public: private: void FireScrollMessage(UINT p_msg,int p_delta) { - UINT count = (UINT)(p_delta<0?-p_delta:p_delta); + UINT count = (UINT)pfc::abs_t(p_delta); const UINT which = (p_msg == WM_HSCROLL ? SB_HORZ : SB_VERT); SCROLLINFO si = {}; si.cbSize = sizeof(si); si.fMask = SIF_PAGE | SIF_RANGE; if (!this->GetScrollInfo(which, &si) || si.nPage <= 0) return; @@ -230,13 +236,21 @@ private: return 0; } + static LONG LineToPixelsHelper(LONG & p_overflow,LONG p_pixels,LONG p_dpi,LONG p_lineWidth) { + const int lineWidth = MulDiv(p_lineWidth,p_dpi,96); + if (lineWidth == 0) return 0; + p_overflow += p_pixels; + LONG ret = p_overflow / lineWidth; + p_overflow -= ret * lineWidth; + return ret; + } CPoint MiddleDrag_PixelsToLines(CPoint & p_overflow,CPoint p_pixels) { const CSize dpi = QueryScreenDPIEx(); if (dpi.cx <= 0 || dpi.cy <= 0) return CPoint(0,0); CPoint pt; - pt.x = CMiddleDragCommon::LineToPixelsHelper(p_overflow.x,p_pixels.x,dpi.cx,m_lineWidth.cx); - pt.y = CMiddleDragCommon::LineToPixelsHelper(p_overflow.y,p_pixels.y,dpi.cy,m_lineWidth.cy); + pt.x = LineToPixelsHelper(p_overflow.x,p_pixels.x,dpi.cx,m_lineWidth.cx); + pt.y = LineToPixelsHelper(p_overflow.y,p_pixels.y,dpi.cy,m_lineWidth.cy); return pt; } @@ -257,9 +271,7 @@ typedef CMiddleDragImpl > > CMiddleDrag template class CContainedWindow_MsgMap : public CContainedWindowT > { protected: - CContainedWindow_MsgMap() : CContainedWindowT >(msgMapCast(this)) {} -private: - template static CMessageMap * msgMapCast(t* arg) { return arg; } + CContainedWindow_MsgMap() : CContainedWindowT >(pfc::implicit_cast(this)) {} }; template @@ -270,7 +282,7 @@ template class CMiddleDragImplCtrlHookEx : public CMiddleDragImp public: CMiddleDragImplCtrlHookEx(CMessageMap * hook, DWORD hookMapID = 0) : m_hook(*hook), m_hookMapID(hookMapID) {} - BEGIN_MSG_MAP_EX(CMiddleDragImplCtrlHookEx) + BEGIN_MSG_MAP(CMiddleDragImplCtrlHookEx) CHAIN_MSG_MAP(CMiddleDragImplCtrlHook) CHAIN_MSG_MAP_ALT_MEMBER(m_hook,m_hookMapID); END_MSG_MAP() diff --git a/foobar2000/ATLHelpers/Controls.h b/foobar2000/ATLHelpers/Controls.h new file mode 100644 index 0000000..2baf28c --- /dev/null +++ b/foobar2000/ATLHelpers/Controls.h @@ -0,0 +1,166 @@ +#pragma once + +#include "misc.h" + +void PaintSeparatorControl(CWindow wnd); + +class CStaticSeparator : public CContainedWindowT, private CMessageMap { +public: + CStaticSeparator() : CContainedWindowT(this, 0) {} + BEGIN_MSG_MAP_EX(CSeparator) + MSG_WM_PAINT(OnPaint) + MSG_WM_SETTEXT(OnSetText) + END_MSG_MAP() +private: + int OnSetText(LPCTSTR lpstrText) { + Invalidate(); + SetMsgHandled(FALSE); + return 0; + } + void OnPaint(CDCHandle) { + PaintSeparatorControl(*this); + } +}; + + + +template +class CTextControl : public CWindowRegisteredT { +public: + BEGIN_MSG_MAP_EX(CTextControl) + MSG_WM_SETFONT(OnSetFont) + MSG_WM_GETFONT(OnGetFont) + MSG_WM_SETTEXT(OnSetText) + CHAIN_MSG_MAP(__super) + END_MSG_MAP() +private: + HFONT OnGetFont() { + return m_font; + } + void OnSetFont(HFONT font, BOOL bRedraw) { + m_font = font; + if (bRedraw) Invalidate(); + } + int OnSetText(LPCTSTR lpstrText) { + Invalidate();SetMsgHandled(FALSE); return 0; + } + CFontHandle m_font; +}; + +#ifndef VSCLASS_TEXTSTYLE +// +// TEXTSTYLE class parts and states +// +#define VSCLASS_TEXTSTYLE L"TEXTSTYLE" + +enum TEXTSTYLEPARTS { + TEXT_MAININSTRUCTION = 1, + TEXT_INSTRUCTION = 2, + TEXT_BODYTITLE = 3, + TEXT_BODYTEXT = 4, + TEXT_SECONDARYTEXT = 5, + TEXT_HYPERLINKTEXT = 6, + TEXT_EXPANDED = 7, + TEXT_LABEL = 8, + TEXT_CONTROLLABEL = 9, +}; + +enum HYPERLINKTEXTSTATES { + TS_HYPERLINK_NORMAL = 1, + TS_HYPERLINK_HOT = 2, + TS_HYPERLINK_PRESSED = 3, + TS_HYPERLINK_DISABLED = 4, +}; + +enum CONTROLLABELSTATES { + TS_CONTROLLABEL_NORMAL = 1, + TS_CONTROLLABEL_DISABLED = 2, +}; + +#endif + + +class CStaticThemed : public CContainedWindowT, private CMessageMap { +public: + CStaticThemed() : CContainedWindowT(this, 0), m_id(), m_fallback() {} + BEGIN_MSG_MAP_EX(CStaticThemed) + MSG_WM_PAINT(OnPaint) + MSG_WM_THEMECHANGED(OnThemeChanged) + MSG_WM_SETTEXT(OnSetText) + END_MSG_MAP() + + void SetThemePart(int id) {m_id = id; if (m_hWnd != NULL) Invalidate();} +private: + int OnSetText(LPCTSTR lpstrText) { + Invalidate(); + SetMsgHandled(FALSE); + return 0; + } + void OnThemeChanged() { + m_theme.Release(); + m_fallback = false; + } + void OnPaint(CDCHandle) { + if (m_fallback) { + SetMsgHandled(FALSE); return; + } + if (m_theme == NULL) { + m_theme.OpenThemeData(*this, L"TextStyle"); + if (m_theme == NULL) { + m_fallback = true; SetMsgHandled(FALSE); return; + } + } + CPaintDC dc(*this); + TCHAR buffer[512] = {}; + GetWindowText(buffer, _countof(buffer)); + const int txLen = pfc::strlen_max_t(buffer, _countof(buffer)); + CRect contentRect; + WIN32_OP_D( GetClientRect(contentRect) ); + SelectObjectScope scopeFont(dc, GetFont()); + dc.SetTextColor(GetSysColor(COLOR_WINDOWTEXT)); + dc.SetBkMode(TRANSPARENT); + + if (txLen > 0) { + CRect rcText(contentRect); + DWORD flags = 0; + DWORD style = GetStyle(); + if (style & SS_LEFT) flags |= DT_LEFT; + else if (style & SS_RIGHT) flags |= DT_RIGHT; + else if (style & SS_CENTER) flags |= DT_CENTER; + if (style & SS_ENDELLIPSIS) flags |= DT_END_ELLIPSIS; + + HRESULT retval = DrawThemeText(m_theme, dc, m_id, 0, buffer, txLen, flags, 0, rcText); + PFC_ASSERT( SUCCEEDED( retval ) ); + } + } + int m_id; + CTheme m_theme; + bool m_fallback; +}; +class CStaticMainInstruction : public CStaticThemed { +public: + CStaticMainInstruction() { SetThemePart(TEXT_MAININSTRUCTION); } +}; + + + +class CSeparator : public CTextControl { +public: + BEGIN_MSG_MAP_EX(CSeparator) + MSG_WM_PAINT(OnPaint) + MSG_WM_ENABLE(OnEnable) + CHAIN_MSG_MAP(__super) + END_MSG_MAP() + + static const TCHAR * GetClassName() { + return _T("foobar2000:separator"); + } +private: + void OnEnable(BOOL bEnable) { + Invalidate(); + } + void OnPaint(CDCHandle dc) { + PaintSeparatorControl(*this); + } +}; + diff --git a/libPPUI/GDIUtils.h b/foobar2000/ATLHelpers/GDIUtils.h similarity index 96% rename from libPPUI/GDIUtils.h rename to foobar2000/ATLHelpers/GDIUtils.h index 5f29674..34f0f35 100644 --- a/libPPUI/GDIUtils.h +++ b/foobar2000/ATLHelpers/GDIUtils.h @@ -1,5 +1,4 @@ #pragma once -#include "win32_op.h" static HBITMAP CreateDIB24(CSize size) { struct { @@ -90,7 +89,7 @@ public: } private: void _initWnd(CWindow wnd) { - this->SubclassWindow(wnd); this->SetFont(m_font); + SubclassWindow(wnd); SetFont(m_font); } CFont m_font; }; @@ -252,10 +251,3 @@ private: HDC m_dc; COLORREF m_oldCol; }; - -static CSize GetBitmapSize( HBITMAP bmp ) { - CBitmapHandle h ( bmp ); - BITMAP bm = {}; - WIN32_OP_D( h.GetBitmap(bm) ); - return CSize(bm.bmWidth, bm.bmHeight); -} diff --git a/libPPUI/wtl-pp.h b/foobar2000/ATLHelpers/WTL-PP.h similarity index 89% rename from libPPUI/wtl-pp.h rename to foobar2000/ATLHelpers/WTL-PP.h index a2070ce..0ea0c26 100644 --- a/libPPUI/wtl-pp.h +++ b/foobar2000/ATLHelpers/WTL-PP.h @@ -1,9 +1,6 @@ #pragma once // Various WTL extensions that are not fb2k specific and can be reused in other WTL based software -#include -#include - #define ATLASSERT_SUCCESS(X) {auto RetVal = (X); ATLASSERT( RetVal ); } class NoRedrawScope { @@ -79,7 +76,6 @@ private: } - class CImageListContainer : public CImageList { public: CImageListContainer() {} @@ -126,12 +122,9 @@ public: class CEditPPHooks : public CContainedWindowT, private CMessageMap { public: - bool HandleCtrlA = true, NoEscSteal = false, NoEnterSteal = false; - - std::function onEnterKey; - std::function onEscKey; + bool HandleCtrlA, NoEscSteal, NoEnterSteal; - CEditPPHooks(CMessageMap * hookMM = nullptr, int hookMMID = 0) : CContainedWindowT(this, 0), m_hookMM(hookMM), m_hookMMID(hookMMID) {} + CEditPPHooks(CMessageMap * hookMM = nullptr, int hookMMID = 0) : CContainedWindowT(this, 0), HandleCtrlA(true), NoEscSteal(), NoEnterSteal(), m_suppressChar(), m_hookMM(hookMM), m_hookMMID(hookMMID) {} BEGIN_MSG_MAP_EX(CEditPPHooks) MSG_WM_KEYDOWN(OnKeyDown) @@ -178,38 +171,26 @@ private: } void OnChar(UINT nChar, UINT, UINT nFlags) { if (m_suppressChar != 0) { - if (nChar == m_suppressChar) return; - } - if (m_suppressScanCode != 0) { UINT code = nFlags & 0xFF; - if (code == m_suppressScanCode) return; + if (code == m_suppressChar) return; } SetMsgHandled(FALSE); } void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { m_suppressChar = 0; - m_suppressScanCode = 0; if (HandleCtrlA) { if (nChar == 'A') { if (GetHotkeyModifierFlags() == MOD_CONTROL) { - m_suppressScanCode = nFlags & 0xFF; + m_suppressChar = nFlags & 0xFF; this->SetSelAll(); return; } } if ( nChar == VK_BACK ) { if (GetHotkeyModifierFlags() == MOD_CONTROL) { - m_suppressScanCode = nFlags & 0xFF; + m_suppressChar = nFlags & 0xFF; DeleteLastWord( *this ) ; return; } } - if ( nChar == VK_RETURN && onEnterKey ) { - m_suppressChar = nChar; - onEnterKey(); return; - } - if ( nChar == VK_ESCAPE && onEscKey ) { - m_suppressChar = nChar; - onEscKey(); return; - } } SetMsgHandled(FALSE); } @@ -222,15 +203,9 @@ private: case WM_SYSKEYDOWN: switch(lpMsg->wParam) { case VK_ESCAPE: - if (onEscKey) { - return DLGC_WANTMESSAGE; - } SetMsgHandled(!!NoEscSteal); return 0; case VK_RETURN: - if (onEnterKey) { - return DLGC_WANTMESSAGE; - } SetMsgHandled(!!NoEnterSteal); return 0; default: @@ -242,7 +217,7 @@ private: } } } - UINT m_suppressChar = 0, m_suppressScanCode = 0; + UINT m_suppressChar; CMessageMap * const m_hookMM; const int m_hookMMID; }; @@ -413,8 +388,8 @@ public: } private: - CSRWlock(const CSRWlock&) = delete; - void operator=(const CSRWlock&) = delete; + CSRWlock(const CSRWlock&); + void operator=(const CSRWlock&); SRWLOCK theLock; #if _WIN32_WINNT < 0x600 @@ -455,8 +430,8 @@ public: else LeaveCriticalSection(&cs); } private: - CSRWorCS(const CSRWorCS&) = delete; - void operator=(const CSRWorCS&) = delete; + CSRWorCS(const CSRWorCS&); + void operator=(const CSRWorCS&); CSRWlock srw; CRITICAL_SECTION cs; @@ -464,11 +439,3 @@ private: #else typedef CSRWlock CSRWorCS; #endif - - -template class CContainedWindowSimpleT : public CContainedWindowT, public CMessageMap { -public: - CContainedWindowSimpleT() : CContainedWindowT(this) {} - BEGIN_MSG_MAP(CContainedWindowSimpleT) - END_MSG_MAP() -}; diff --git a/foobar2000/helpers/WindowPositionUtils.h b/foobar2000/ATLHelpers/WindowPositionUtils.h similarity index 78% rename from foobar2000/helpers/WindowPositionUtils.h rename to foobar2000/ATLHelpers/WindowPositionUtils.h index fa899b8..40a875d 100644 --- a/foobar2000/helpers/WindowPositionUtils.h +++ b/foobar2000/ATLHelpers/WindowPositionUtils.h @@ -1,6 +1,6 @@ #pragma once -#include "win32_misc.h" +#include "../helpers/win32_misc.h" static BOOL AdjustWindowRectHelper(CWindow wnd, CRect & rc) { const DWORD style = wnd.GetWindowLong(GWL_STYLE), exstyle = wnd.GetWindowLong(GWL_EXSTYLE); @@ -56,20 +56,20 @@ static BOOL ShowWindowCentered(CWindow wnd,CWindow wndParent) { class cfgWindowSize : public cfg_var { public: - cfgWindowSize(const GUID & p_guid) : cfg_var(p_guid) {} + cfgWindowSize(const GUID & p_guid) : cfg_var(p_guid), m_width(~0), m_height(~0) {} void get_data_raw(stream_writer * p_stream,abort_callback & p_abort) { - stream_writer_formatter<> str(*p_stream,p_abort); str << m_width << m_height; + stream_writer_formatter<>(*p_stream,p_abort) << m_width << m_height; } void set_data_raw(stream_reader * p_stream,t_size p_sizehint,abort_callback & p_abort) { - stream_reader_formatter<> str(*p_stream,p_abort); str >> m_width >> m_height; + stream_reader_formatter<>(*p_stream,p_abort) >> m_width >> m_height; } - uint32_t m_width = UINT32_MAX, m_height = UINT32_MAX; + t_uint32 m_width, m_height; }; class cfgWindowSizeTracker { public: - cfgWindowSizeTracker(cfgWindowSize & p_var) : m_var(p_var) {} + cfgWindowSizeTracker(cfgWindowSize & p_var) : m_var(p_var), m_applied(false) {} bool Apply(HWND p_wnd) { bool retVal = false; @@ -95,7 +95,7 @@ public: } private: cfgWindowSize & m_var; - bool m_applied = false; + bool m_applied; }; class cfgDialogSizeTracker : public cfgWindowSizeTracker { @@ -290,8 +290,8 @@ FB2K_STREAM_WRITER_OVERLOAD(cfgDialogPositionData) { class cfgDialogPosition : public cfgDialogPositionData, public cfg_var { public: cfgDialogPosition(const GUID & id) : cfg_var(id) {} - void get_data_raw(stream_writer * p_stream,abort_callback & p_abort) {FetchConfig(); stream_writer_formatter<> str(*p_stream, p_abort); str << *pfc::implicit_cast(this);} - void set_data_raw(stream_reader * p_stream,t_size p_sizehint,abort_callback & p_abort) {stream_reader_formatter<> str(*p_stream, p_abort); str >> *pfc::implicit_cast(this);} + void get_data_raw(stream_writer * p_stream,abort_callback & p_abort) {FetchConfig(); stream_writer_formatter<>(*p_stream, p_abort) << *pfc::implicit_cast(this);} + void set_data_raw(stream_reader * p_stream,t_size p_sizehint,abort_callback & p_abort) {stream_reader_formatter<>(*p_stream, p_abort) >> *pfc::implicit_cast(this);} }; class cfgDialogPositionTracker { @@ -321,71 +321,3 @@ private: cfgDialogPosition & m_var; CWindow m_wnd; }; - -//! DPI-safe window size var \n -//! Stores size in pixel and original DPI\n -//! Use with cfgWindowSizeTracker2 -class cfgWindowSize2 : public cfg_var { -public: - cfgWindowSize2(const GUID & p_guid) : cfg_var(p_guid) {} - void get_data_raw(stream_writer * p_stream,abort_callback & p_abort) { - stream_writer_formatter<> str(*p_stream,p_abort); str << m_size.cx << m_size.cy << m_dpi.cx << m_dpi.cy; - } - void set_data_raw(stream_reader * p_stream,t_size p_sizehint,abort_callback & p_abort) { - stream_reader_formatter<> str(*p_stream,p_abort); str >> m_size.cx >> m_size.cy >> m_dpi.cx >> m_dpi.cy; - } - - bool is_valid() const { - return m_size.cx > 0 && m_size.cy > 0; - } - - CSize get( CSize forDPI ) const { - if ( forDPI == m_dpi ) return m_size; - - CSize ret; - ret.cx = MulDiv( m_size.cx, forDPI.cx, m_dpi.cx ); - ret.cy = MulDiv( m_size.cy, forDPI.cy, m_dpi.cy ); - return ret; - } - - CSize m_size = CSize(0,0), m_dpi = CSize(0,0); -}; - -//! Forward messages to this class to utilize cfgWindowSize2 -class cfgWindowSizeTracker2 : public CMessageMap { -public: - cfgWindowSizeTracker2( cfgWindowSize2 & var ) : m_var(var) {} - - BEGIN_MSG_MAP_EX(cfgWindowSizeTracker2) - if (uMsg == WM_CREATE || uMsg == WM_INITDIALOG) { - Apply(hWnd); - } - MSG_WM_SIZE( OnSize ) - END_MSG_MAP() - - bool Apply(HWND p_wnd) { - bool retVal = false; - m_applied = false; - if (m_var.is_valid()) { - CRect rect( CPoint(0,0), m_var.get( m_DPI ) ); - if (AdjustWindowRectHelper(p_wnd, rect)) { - SetWindowPos(p_wnd,NULL,0,0,rect.right-rect.left,rect.bottom-rect.top,SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER); - retVal = true; - } - } - m_applied = true; - return retVal; - } - -private: - void OnSize(UINT nType, CSize size) { - if ( m_applied && size.cx > 0 && size.cy > 0 ) { - m_var.m_size = size; - m_var.m_dpi = m_DPI; - } - SetMsgHandled(FALSE); - } - cfgWindowSize2 & m_var; - bool m_applied = false; - const CSize m_DPI = QueryScreenDPIEx(); -}; \ No newline at end of file diff --git a/foobar2000/ATLHelpers/foobar2000_ATL_helpers.vcxproj b/foobar2000/ATLHelpers/foobar2000_ATL_helpers.vcxproj new file mode 100644 index 0000000..a391e18 --- /dev/null +++ b/foobar2000/ATLHelpers/foobar2000_ATL_helpers.vcxproj @@ -0,0 +1,122 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {622E8B19-8109-4717-BD4D-9657AA78363E} + foobar2000_ATL_helpers + Win32Proj + 10.0.14393.0 + + + + StaticLibrary + Unicode + true + v141_xp + + + StaticLibrary + Unicode + v141_xp + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + + + + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + false + EnableFastChecks + Use + Level3 + ProgramDatabase + MultiThreadedDebugDLL + 4715 + true + NoExtensions + + + + + MinSpace + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + false + Fast + false + Use + Level3 + ProgramDatabase + MultiThreadedDLL + NoExtensions + /d2notypeopt %(AdditionalOptions) + 4715 + true + true + true + + + + + + + true + true + + + + + + Create + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/foobar2000/ATLHelpers/foobar2000_ATL_helpers.vcxproj.filters b/foobar2000/ATLHelpers/foobar2000_ATL_helpers.vcxproj.filters new file mode 100644 index 0000000..c1805a0 --- /dev/null +++ b/foobar2000/ATLHelpers/foobar2000_ATL_helpers.vcxproj.filters @@ -0,0 +1,102 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/foobar2000/ATLHelpers/inplace_edit.cpp b/foobar2000/ATLHelpers/inplace_edit.cpp new file mode 100644 index 0000000..1be3a36 --- /dev/null +++ b/foobar2000/ATLHelpers/inplace_edit.cpp @@ -0,0 +1,477 @@ +#include "stdafx.h" + +#include "inplace_edit.h" +#include "AutoComplete.h" +#include "misc.h" +#include "WTL-PP.h" + +#ifndef WM_MOUSEHWHEEL +#define WM_MOUSEHWHEEL 0x20E +#endif + +using namespace InPlaceEdit; + + +namespace { + +enum { + MSG_COMPLETION = WM_USER, + MSG_DISABLE_EDITING +}; + + +static pfc::avltree_t g_editboxes; +static HHOOK g_hook = NULL /*, g_keyHook = NULL*/; + +static void GAbortEditing(HWND edit, t_uint32 code) { + CWindow parent = ::GetParent(edit); + parent.SendMessage(MSG_DISABLE_EDITING); + parent.PostMessage(MSG_COMPLETION, code, 0); +} + +static void GAbortEditing(t_uint32 code) { + for(auto walk = g_editboxes.cfirst(); walk.is_valid(); ++walk ) { + GAbortEditing(*walk, code); + } +} + +static bool IsSamePopup(CWindow wnd1, CWindow wnd2) { + return FindOwningPopup(wnd1) == FindOwningPopup(wnd2); +} + +static void MouseEventTest(HWND target, CPoint pt, bool isWheel) { + for(auto walk = g_editboxes.cfirst(); walk.is_valid(); ++walk) { + CWindow edit ( *walk ); + bool cancel = false; + if (target != edit && IsSamePopup(target, edit)) { + cancel = true; + } else if (isWheel) { + CWindow target2 = WindowFromPoint(pt); + if (target2 != edit && IsSamePopup(target2, edit)) { + cancel = true; + } + } + + if (cancel) GAbortEditing(edit, KEditLostFocus); + } +} + +static LRESULT CALLBACK GMouseProc(int nCode,WPARAM wParam,LPARAM lParam) { + if (nCode == HC_ACTION) { + const MOUSEHOOKSTRUCT * mhs = reinterpret_cast(lParam); + switch(wParam) { + case WM_NCLBUTTONDOWN: + case WM_NCRBUTTONDOWN: + case WM_NCMBUTTONDOWN: + case WM_NCXBUTTONDOWN: + case WM_LBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_XBUTTONDOWN: + MouseEventTest(mhs->hwnd, mhs->pt, false); + break; + case WM_MOUSEWHEEL: + case WM_MOUSEHWHEEL: + MouseEventTest(mhs->hwnd, mhs->pt, true); + break; + } + } + return CallNextHookEx(g_hook,nCode,wParam,lParam); +} +#if 0 +static LRESULT CALLBACK GKeyboardProc(int code, WPARAM wp, LPARAM lp) { + if (code == HC_ACTION && (lp & (1<<31)) == 0) { + switch(wp) { + case VK_RETURN: + if (!IsKeyPressed(VK_LCONTROL) && !IsKeyPressed(VK_RCONTROL)) { + GAbortEditing(KEditEnter); + } + break; + case VK_TAB: + GAbortEditing(IsKeyPressed(VK_SHIFT) ? KEditShiftTab : KEditTab); + break; + case VK_ESCAPE: + GAbortEditing(KEditAborted); + break; + } + } + return CallNextHookEx(g_keyHook,code,wp,lp); +} +#endif + +static void on_editbox_creation(HWND p_editbox) { + PFC_ASSERT( core_api::is_main_thread() ); + g_editboxes.add(p_editbox); + if (g_hook == NULL) { + g_hook = SetWindowsHookEx(WH_MOUSE,GMouseProc,NULL,GetCurrentThreadId()); + } + /*if (g_keyHook == NULL) { + g_keyHook = SetWindowsHookEx(WH_KEYBOARD, GKeyboardProc, NULL, GetCurrentThreadId()); + }*/ +} +static void UnhookHelper(HHOOK & hook) { + HHOOK v = pfc::replace_null_t(hook); + if (v != NULL) UnhookWindowsHookEx(v); +} +static void on_editbox_destruction(HWND p_editbox) { + PFC_ASSERT( core_api::is_main_thread() ); + g_editboxes.remove_item(p_editbox); + if (g_editboxes.get_count() == 0) { + UnhookHelper(g_hook); /*UnhookHelper(g_keyHook);*/ + } +} + +class CInPlaceEditBox : public CContainedWindowSimpleT { +public: + CInPlaceEditBox() : m_selfDestruct(), m_suppressChar() {} + BEGIN_MSG_MAP_EX(CInPlaceEditBox) + //MSG_WM_CREATE(OnCreate) + MSG_WM_DESTROY(OnDestroy) + MSG_WM_GETDLGCODE(OnGetDlgCode) + MSG_WM_KILLFOCUS(OnKillFocus) + MSG_WM_CHAR(OnChar) + MSG_WM_KEYDOWN(OnKeyDown) + END_MSG_MAP() + void OnCreation() { + m_typableScope.Set(m_hWnd); + on_editbox_creation(m_hWnd); + } +private: + void OnDestroy() { + m_selfDestruct = true; + m_typableScope.Set(NULL); + on_editbox_destruction(m_hWnd); + SetMsgHandled(FALSE); + } + int OnCreate(LPCREATESTRUCT lpCreateStruct) { + OnCreation(); + SetMsgHandled(FALSE); + return 0; + } + UINT OnGetDlgCode(LPMSG lpMsg) { + if (lpMsg == NULL) { + return DLGC_WANTALLKEYS; + } else { + switch(lpMsg->message) { + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + switch(lpMsg->wParam) { + case VK_TAB: + case VK_ESCAPE: + case VK_RETURN: + return DLGC_WANTALLKEYS; + default: + SetMsgHandled(FALSE); return 0; + } + default: + SetMsgHandled(FALSE); return 0; + + } + } + } + void OnKillFocus(CWindow wndFocus) { + ForwardCompletion(KEditLostFocus); + SetMsgHandled(FALSE); + } + + void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) { + if (m_suppressChar != 0) { + UINT code = nFlags & 0xFF; + if (code == m_suppressChar) return; + } + SetMsgHandled(FALSE); + } + void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { + m_suppressChar = nFlags & 0xFF; + switch(nChar) { + case VK_BACK: + if (GetHotkeyModifierFlags() == MOD_CONTROL) { + CEditPPHooks::DeleteLastWord( * this ); + return; + } + break; + case 'A': + if (GetHotkeyModifierFlags() == MOD_CONTROL) { + this->SetSelAll(); return; + } + break; + case VK_RETURN: + if (!IsKeyPressed(VK_LCONTROL) && !IsKeyPressed(VK_RCONTROL)) { + ForwardCompletion(KEditEnter); + return; + } + break; + case VK_TAB: + ForwardCompletion(IsKeyPressed(VK_SHIFT) ? KEditShiftTab : KEditTab); + return; + case VK_ESCAPE: + ForwardCompletion(KEditAborted); + return; + } + m_suppressChar = 0; + SetMsgHandled(FALSE); + } + + void ForwardCompletion(t_uint32 code) { + if (IsWindowEnabled()) { + CWindow owner = GetParent(); + owner.SendMessage(MSG_DISABLE_EDITING); + owner.PostMessage(MSG_COMPLETION,code,0); + EnableWindow(FALSE); + } + } + + CTypableWindowScope m_typableScope; + bool m_selfDestruct; + UINT m_suppressChar; +}; + +class InPlaceEditContainer : public CWindowImpl { +public: + DECLARE_WND_CLASS_EX(_T("{54340C80-248C-4b8e-8CD4-D624A8E9377B}"),0,-1); + + + HWND Create(CWindow parent) { + + RECT rect_cropped; + { + RECT client; + WIN32_OP_D(parent.GetClientRect(&client)); + IntersectRect(&rect_cropped,&client,&m_initRect); + } + const DWORD containerStyle = WS_BORDER|WS_CHILD; + AdjustWindowRect(&rect_cropped,containerStyle,FALSE); + + + + WIN32_OP( __super::Create(parent,rect_cropped, NULL, containerStyle) != NULL ); + + try { + CRect rcClient; + WIN32_OP_D(GetClientRect(rcClient)); + + + DWORD style = WS_CHILD|WS_VISIBLE;//parent is invisible now + if (m_flags & KFlagMultiLine) style |= WS_VSCROLL|ES_MULTILINE; + else style |= ES_AUTOHSCROLL; + if (m_flags & KFlagReadOnly) style |= ES_READONLY; + if (m_flags & KFlagAlignCenter) style |= ES_CENTER; + else if (m_flags & KFlagAlignRight) style |= ES_RIGHT; + else style |= ES_LEFT; + + + CEdit edit; + + WIN32_OP( edit.Create(*this, rcClient, NULL, style, 0, ID_MYEDIT) != NULL ); + edit.SetFont(parent.GetFont()); + + if (m_ACData.is_valid()) InitializeSimpleAC(edit, m_ACData.get_ptr(), m_ACOpts); + m_edit.SubclassWindow(edit); + m_edit.OnCreation(); + + uSetWindowText(m_edit,*m_content); + m_edit.SetSelAll(); + } catch(...) { + PostMessage(MSG_COMPLETION,InPlaceEdit::KEditAborted,0); + return m_hWnd; + } + + ShowWindow(SW_SHOW); + m_edit.SetFocus(); + + m_initialized = true; + + PFC_ASSERT( m_hWnd != NULL ); + + return m_hWnd; + } + + InPlaceEditContainer(const RECT & p_rect,t_uint32 p_flags,pfc::rcptr_t p_content,completion_notify_ptr p_notify, IUnknown * ACData, DWORD ACOpts) + : m_content(p_content), m_notify(p_notify), m_completed(false), m_initialized(false), m_changed(false), m_disable_editing(false), m_initRect(p_rect), m_flags(p_flags), m_selfDestruct(), m_ACData(ACData), m_ACOpts(ACOpts) + { + } + + enum {ID_MYEDIT = 666}; + + BEGIN_MSG_MAP_EX(InPlaceEditContainer) + MESSAGE_HANDLER_EX(WM_CTLCOLOREDIT, MsgForwardToParent) + MESSAGE_HANDLER_EX(WM_CTLCOLORSTATIC, MsgForwardToParent) + MESSAGE_HANDLER_EX(WM_MOUSEWHEEL, MsgLostFocus) + MESSAGE_HANDLER_EX(WM_MOUSEHWHEEL, MsgLostFocus) + MESSAGE_HANDLER_SIMPLE(MSG_DISABLE_EDITING, OnMsgDisableEditing) + MESSAGE_HANDLER_EX(MSG_COMPLETION, OnMsgCompletion) + COMMAND_HANDLER_EX(ID_MYEDIT, EN_CHANGE, OnEditChange) + MSG_WM_DESTROY(OnDestroy) + END_MSG_MAP() + + HWND GetEditBox() const {return m_edit;} + +private: + void OnDestroy() {m_selfDestruct = true;} + + LRESULT MsgForwardToParent(UINT msg, WPARAM wParam, LPARAM lParam) { + return GetParent().SendMessage(msg, wParam, lParam); + } + LRESULT MsgLostFocus(UINT, WPARAM, LPARAM) { + PostMessage(MSG_COMPLETION,InPlaceEdit::KEditLostFocus,0); + return 0; + } + void OnMsgDisableEditing() { + ShowWindow(SW_HIDE); + GetParent().UpdateWindow(); + m_disable_editing = true; + } + LRESULT OnMsgCompletion(UINT, WPARAM wParam, LPARAM lParam) { + PFC_ASSERT(m_initialized); + if ((wParam & KEditMaskReason) != KEditLostFocus) { + GetParent().SetFocus(); + } + OnCompletion(wParam); + if (!m_selfDestruct) { + m_selfDestruct = true; + DestroyWindow(); + } + return 0; + } + void OnEditChange(UINT, int, CWindow source) { + if (m_initialized && !m_disable_editing) { + uGetWindowText(source,*m_content); + m_changed = true; + } + } + +private: + + void OnCompletion(unsigned p_status) { + if (!m_completed) { + m_completed = true; + p_status &= KEditMaskReason; + unsigned code = p_status; + if (m_changed && p_status != KEditAborted) code |= KEditFlagContentChanged; + if (m_notify.is_valid()) m_notify->on_completion(code); + } + } + + const pfc::rcptr_t m_content; + const completion_notify_ptr m_notify; + bool m_completed; + bool m_initialized, m_changed; + bool m_disable_editing; + bool m_selfDestruct; + const CRect m_initRect; + const t_uint32 m_flags; + CInPlaceEditBox m_edit; + + const pfc::com_ptr_t m_ACData; + const DWORD m_ACOpts; +}; + +} + +static void fail(completion_notify_ptr p_notify) { + completion_notify::g_signal_completion_async(p_notify,KEditAborted); +} + +HWND InPlaceEdit::Start(HWND p_parentwnd,const RECT & p_rect,bool p_multiline,pfc::rcptr_t p_content,completion_notify_ptr p_notify) { + return StartEx(p_parentwnd,p_rect,p_multiline ? KFlagMultiLine : 0, p_content,p_notify); +} + +void InPlaceEdit::Start_FromListView(HWND p_listview,unsigned p_item,unsigned p_subitem,unsigned p_linecount,pfc::rcptr_t p_content,completion_notify_ptr p_notify) { + Start_FromListViewEx(p_listview,p_item,p_subitem,p_linecount,0,p_content,p_notify); +} + +bool InPlaceEdit::TableEditAdvance_ListView(HWND p_listview,unsigned p_column_base,unsigned & p_item,unsigned & p_column, unsigned p_item_count,unsigned p_column_count, unsigned p_whathappened) { + if (p_column >= p_column_count) return false; + + + pfc::array_t orderRev; + { + pfc::array_t order; + const unsigned orderExCount = /*p_column_base + p_column_count*/ ListView_GetColumnCount(p_listview); + PFC_ASSERT( orderExCount >= p_column_base + p_column_count ); + pfc::array_t orderEx; orderEx.set_size(orderExCount); + if (!ListView_GetColumnOrderArray(p_listview,orderExCount,orderEx.get_ptr())) { + PFC_ASSERT(!"Should not get here - probably mis-calculated column count"); + return false; + } + order.set_size(p_column_count); + for(unsigned walk = 0; walk < p_column_count; ++walk) order[walk] = orderEx[p_column_base + walk]; + + orderRev.set_size(p_column_count); order_helper::g_fill(orderRev); + pfc::sort_get_permutation_t(order,pfc::compare_t,p_column_count,orderRev.get_ptr()); + } + + unsigned columnVisible = (unsigned)orderRev[p_column]; + + + if (!TableEditAdvance(p_item,columnVisible,p_item_count,p_column_count,p_whathappened)) return false; + + p_column = (unsigned)order_helper::g_find_reverse(orderRev.get_ptr(),columnVisible); + + return true; +} + +bool InPlaceEdit::TableEditAdvance(unsigned & p_item,unsigned & p_column, unsigned p_item_count,unsigned p_column_count, unsigned p_whathappened) { + if (p_item >= p_item_count || p_column >= p_column_count) return false; + int delta = 0; + + switch(p_whathappened & KEditMaskReason) { + case KEditEnter: + delta = (int) p_column_count; + break; + case KEditTab: + delta = 1; + break; + case KEditShiftTab: + delta = -1; + break; + default: + return false; + } + while(delta > 0) { + p_column++; + if (p_column >= p_column_count) { + p_column = 0; + p_item++; + if (p_item >= p_item_count) return false; + } + delta--; + } + while(delta < 0) { + if (p_column == 0) { + if (p_item == 0) return false; + p_item--; + p_column = p_column_count; + } + p_column--; + delta++; + } + return true; +} + +HWND InPlaceEdit::StartEx(HWND p_parentwnd,const RECT & p_rect,unsigned p_flags,pfc::rcptr_t p_content,completion_notify_ptr p_notify, IUnknown * ACData , DWORD ACOpts) { + try { + PFC_ASSERT( (CWindow(p_parentwnd).GetWindowLong(GWL_STYLE) & WS_CLIPCHILDREN) != 0 ); + return (new CWindowAutoLifetime(p_parentwnd,p_rect,p_flags,p_content,p_notify, ACData, ACOpts))->GetEditBox(); + } catch(...) { + fail(p_notify); + return NULL; + } +} + +void InPlaceEdit::Start_FromListViewEx(HWND p_listview,unsigned p_item,unsigned p_subitem,unsigned p_linecount,unsigned p_flags,pfc::rcptr_t p_content,completion_notify_ptr p_notify) { + try { + ListView_EnsureVisible(p_listview,p_item,FALSE); + RECT itemrect; + WIN32_OP_D( ListView_GetSubItemRect(p_listview,p_item,p_subitem,LVIR_LABEL,&itemrect) ); + + const bool multiline = p_linecount > 1; + if (multiline) { + itemrect.bottom = itemrect.top + (itemrect.bottom - itemrect.top) * p_linecount; + } + + StartEx(p_listview,itemrect,p_flags | (multiline ? KFlagMultiLine : 0),p_content,p_notify); + } catch(...) { + fail(p_notify); + } +} diff --git a/foobar2000/ATLHelpers/inplace_edit.h b/foobar2000/ATLHelpers/inplace_edit.h new file mode 100644 index 0000000..6c60e24 --- /dev/null +++ b/foobar2000/ATLHelpers/inplace_edit.h @@ -0,0 +1,132 @@ +#pragma once + +#include "../helpers/listview_helper.h" + +namespace InPlaceEdit { + + enum { + KEditAborted = 0, + KEditTab, + KEditShiftTab, + KEditEnter, + KEditLostFocus, + + KEditMaskReason = 0xFF, + KEditFlagContentChanged = 0x100, + + KFlagReadOnly = 1 << 0, + KFlagMultiLine = 1 << 1, + KFlagAlignCenter = 1 << 2, + KFlagAlignRight = 1 << 3, + }; + + HWND Start(HWND p_parentwnd,const RECT & p_rect,bool p_multiline,pfc::rcptr_t p_content,completion_notify_ptr p_notify); + + HWND StartEx(HWND p_parentwnd,const RECT & p_rect,unsigned p_flags,pfc::rcptr_t p_content,completion_notify_ptr p_notify, IUnknown * ACData = NULL, DWORD ACOpts = 0); + + void Start_FromListView(HWND p_listview,unsigned p_item,unsigned p_subitem,unsigned p_linecount,pfc::rcptr_t p_content,completion_notify_ptr p_notify); + void Start_FromListViewEx(HWND p_listview,unsigned p_item,unsigned p_subitem,unsigned p_linecount,unsigned p_flags,pfc::rcptr_t p_content,completion_notify_ptr p_notify); + + bool TableEditAdvance(unsigned & p_item,unsigned & p_column, unsigned p_item_count,unsigned p_column_count, unsigned p_whathappened); + bool TableEditAdvance_ListView(HWND p_listview,unsigned p_column_base,unsigned & p_item,unsigned & p_column, unsigned p_item_count,unsigned p_column_count, unsigned p_whathappened); + + + class CTableEditHelper { + public: + void TableEdit_Start(HWND p_listview,unsigned p_item,unsigned p_column,unsigned p_itemcount,unsigned p_columncount,unsigned p_basecolumn,unsigned p_flags = 0) { + if (m_notify.is_valid() || p_columncount == 0 || p_itemcount == 0 || p_item >= p_itemcount || p_column >= p_columncount) return; + m_listview = p_listview; + m_item = p_item; + m_column = p_column; + m_itemcount = p_itemcount; + m_columncount = p_columncount; + m_basecolumn = p_basecolumn; + m_flags = p_flags; + __Start(); + } + + void TableEdit_Abort(bool p_forwardcontent) { + if (m_notify.is_valid()) { + m_notify->orphan(); + m_notify.release(); + + if (p_forwardcontent && (m_flags & KFlagReadOnly) == 0) { + if (m_content.is_valid()) { + pfc::string8 temp(*m_content); + m_content.release(); + TableEdit_SetItemText(m_item,m_column,temp); + } + } else { + m_content.release(); + } + SetFocus(NULL); + TableEdit_Finished(); + } + } + + + bool TableEdit_IsActive() const { + return m_notify.is_valid(); + } + + virtual bool TableEdit_GetItemText(unsigned p_item,unsigned p_column,pfc::string_base & p_out,unsigned & p_linecount) { + listview_helper::get_item_text(m_listview,p_item,p_column + m_basecolumn,p_out); + p_linecount = pfc::is_multiline(p_out) ? 5 : 1; + return true; + } + virtual void TableEdit_SetItemText(unsigned p_item,unsigned p_column,const char * p_text) { + listview_helper::set_item_text(m_listview,p_item,p_column + m_basecolumn,p_text); + } + + virtual void TableEdit_Finished() {} + + void on_task_completion(unsigned p_taskid,unsigned p_state) { + if (p_taskid == KTaskID) { + m_notify.release(); + if (m_content.is_valid()) { + if (p_state & InPlaceEdit::KEditFlagContentChanged) { + TableEdit_SetItemText(m_item,m_column,*m_content); + } + m_content.release(); + } + /*if (InPlaceEdit::TableEditAdvance(m_item,m_column,m_itemcount,m_columncount,p_state))*/ + if (TableEdit_OnEditCompleted(m_item,m_column,p_state) && + InPlaceEdit::TableEditAdvance_ListView(m_listview,m_basecolumn,m_item,m_column,m_itemcount,m_columncount,p_state)) { + __Start(); + } else { + TableEdit_Finished(); + } + } + } + + ~CTableEditHelper() { + if (m_notify.is_valid()) { + m_notify->orphan(); + m_notify.release(); + } + } + protected: + HWND TableEdit_GetListView() const {return m_listview;} + //return false to abort + virtual bool TableEdit_OnEditCompleted(unsigned item,unsigned column,unsigned state) {return true;} + private: + void __Start() { + listview_helper::select_single_item(m_listview,m_item); + m_content.new_t(); + unsigned linecount = 1; + if (!TableEdit_GetItemText(m_item,m_column,*m_content,linecount)) return; + m_notify = completion_notify_create(this,KTaskID); + InPlaceEdit::Start_FromListViewEx(m_listview,m_item,m_column+m_basecolumn,linecount,m_flags,m_content,m_notify); + } + enum { + KTaskID = 0xc0ffee + }; + HWND m_listview; + unsigned m_item,m_column; + unsigned m_itemcount,m_columncount,m_basecolumn; + unsigned m_flags; + pfc::rcptr_t m_content; + service_ptr_t m_notify; + }; + +} diff --git a/foobar2000/ATLHelpers/inplace_edit_v2.cpp b/foobar2000/ATLHelpers/inplace_edit_v2.cpp new file mode 100644 index 0000000..fbfd0f4 --- /dev/null +++ b/foobar2000/ATLHelpers/inplace_edit_v2.cpp @@ -0,0 +1,147 @@ +#include "stdafx.h" + +#include "../helpers/win32_misc.h" +#include "inplace_edit.h" +#include "inplace_edit_v2.h" +#include "AutoComplete.h" + + +namespace InPlaceEdit { + + t_size CTableEditHelperV2::ColumnToPosition(t_size col) const { + PFC_ASSERT( TableEdit_IsColumnEditable(col) ); + pfc::array_t colOrder; GrabColumnOrder(colOrder); + t_size skipped = 0; + for(t_size walk = 0; walk < colOrder.get_size(); ++walk) { + const t_size curCol = colOrder[walk]; + if (TableEdit_IsColumnEditable(curCol)) { + if (curCol == col) return skipped; + ++skipped; + } + } + PFC_ASSERT( !"Should not get here." ); + return ~0; + } + t_size CTableEditHelperV2::PositionToColumn(t_size pos) const { + pfc::array_t colOrder; GrabColumnOrder(colOrder); + t_size skipped = 0; + for(t_size walk = 0; walk < colOrder.get_size(); ++walk) { + const t_size curCol = colOrder[walk]; + if (TableEdit_IsColumnEditable(curCol)) { + if (skipped == pos) return curCol; + ++skipped; + } + } + PFC_ASSERT( !"Should not get here." ); + return ~0; + } + t_size CTableEditHelperV2::EditableColumnCount() const { + const t_size total = TableEdit_GetColumnCount(); + t_size found = 0; + for(t_size walk = 0; walk < total; ++walk) { + if (TableEdit_IsColumnEditable(walk)) found++; + } + return found; + } + + bool CTableEditHelperV2::TableEdit_Advance(t_size & item, t_size & subItem, t_uint32 whathappened) { + //moo + unsigned _item((unsigned)item), _subItem((unsigned)ColumnToPosition(subItem)); + if (!InPlaceEdit::TableEditAdvance(_item,_subItem,(unsigned) TableEdit_GetItemCount(), (unsigned) EditableColumnCount(), whathappened)) return false; + item = _item; subItem = PositionToColumn(_subItem); + return true; + } + + void CTableEditHelperV2::TableEdit_Abort(bool forwardContent) { + if (this->have_task(KTaskID)) { + this->orphan_task(KTaskID); + if (forwardContent && (m_editFlags & KFlagReadOnly) == 0) { + if (m_editData.is_valid()) { + pfc::string8 temp(*m_editData); + TableEdit_SetField(m_editItem,m_editSubItem, temp); + } + } + m_editData.release(); + SetFocus(NULL); + TableEdit_Finished(); + } + + } + + void CTableEditHelperV2::TableEdit_Start(t_size item, t_size subItem) { + PFC_ASSERT( TableEdit_IsColumnEditable( subItem ) ); + m_editItem = item; m_editSubItem = subItem; + _ReStart(); + } + + void CTableEditHelperV2::_ReStart() { + PFC_ASSERT( m_editItem < TableEdit_GetItemCount() ); + PFC_ASSERT( m_editSubItem < TableEdit_GetColumnCount() ); + + TableEdit_SetItemFocus(m_editItem,m_editSubItem); + m_editData.new_t(); + t_size lineCount = 1; + TableEdit_GetField(m_editItem, m_editSubItem, *m_editData, lineCount); + m_editFlags = TableEdit_GetEditFlags(m_editItem, m_editSubItem); + + RECT rc = TableEdit_GetItemRect(m_editItem, m_editSubItem); + if (lineCount > 1) { + rc.bottom = rc.top + (rc.bottom - rc.top) * lineCount; + m_editFlags |= KFlagMultiLine; + } + pfc::com_ptr_t acl; + if (!TableEdit_GetAutoComplete(m_editItem, m_editSubItem, acl)) acl.release(); + + InPlaceEdit::StartEx(TableEdit_GetParentWnd(), rc, m_editFlags, m_editData, create_task(KTaskID), acl.get_ptr(), ACO_AUTOSUGGEST); + } + + void CTableEditHelperV2::on_task_completion(unsigned id, unsigned status) { + if (id == KTaskID) { + orphan_task(KTaskID); + if (m_editData.is_valid()) { + if (status & InPlaceEdit::KEditFlagContentChanged) { + TableEdit_SetField(m_editItem,m_editSubItem,*m_editData); + } + m_editData.release(); + } + + if (TableEdit_Advance(m_editItem,m_editSubItem,status)) { + _ReStart(); + } else { + TableEdit_Finished(); + } + } + } + + + + + + void CTableEditHelperV2_ListView::TableEdit_GetColumnOrder(t_size * out, t_size count) const { + pfc::array_t temp; temp.set_size(count); + WIN32_OP_D( ListView_GetColumnOrderArray( TableEdit_GetParentWnd(), count, temp.get_ptr() ) ); + for(t_size walk = 0; walk < count; ++walk) out[walk] = temp[walk]; + } + + RECT CTableEditHelperV2_ListView::TableEdit_GetItemRect(t_size item, t_size subItem) const { + RECT rc; + WIN32_OP_D( ListView_GetSubItemRect(TableEdit_GetParentWnd(),item,subItem,LVIR_LABEL,&rc) ); + return rc; + } + + void CTableEditHelperV2_ListView::TableEdit_GetField(t_size item, t_size subItem, pfc::string_base & out, t_size & lineCount) { + listview_helper::get_item_text( TableEdit_GetParentWnd(), item, subItem, out); + lineCount = pfc::is_multiline(out) ? 5 : 1; + } + void CTableEditHelperV2_ListView::TableEdit_SetField(t_size item, t_size subItem, const char * value) { + WIN32_OP_D( listview_helper::set_item_text( TableEdit_GetParentWnd(), item, subItem, value) ); + } + t_size CTableEditHelperV2_ListView::TableEdit_GetItemCount() const { + LRESULT temp; + WIN32_OP_D( ( temp = ListView_GetItemCount( TableEdit_GetParentWnd() ) ) >= 0 ); + return (t_size) temp; + } + void CTableEditHelperV2_ListView::TableEdit_SetItemFocus(t_size item, t_size subItem) { + WIN32_OP_D( listview_helper::select_single_item( TableEdit_GetParentWnd(), item ) ); + } +} diff --git a/foobar2000/ATLHelpers/inplace_edit_v2.h b/foobar2000/ATLHelpers/inplace_edit_v2.h new file mode 100644 index 0000000..c44a49a --- /dev/null +++ b/foobar2000/ATLHelpers/inplace_edit_v2.h @@ -0,0 +1,55 @@ +#pragma once + +#include "../helpers/listview_helper.h" + +namespace InPlaceEdit { + class NOVTABLE CTableEditHelperV2 : protected completion_notify_receiver { + public: + virtual RECT TableEdit_GetItemRect(t_size item, t_size subItem) const = 0; + virtual void TableEdit_GetField(t_size item, t_size subItem, pfc::string_base & out, t_size & lineCount) = 0; + virtual void TableEdit_SetField(t_size item, t_size subItem, const char * value) = 0; + virtual HWND TableEdit_GetParentWnd() const = 0; + virtual bool TableEdit_Advance(t_size & item, t_size & subItem, t_uint32 whathappened); + virtual void TableEdit_Finished() {} + virtual t_size TableEdit_GetItemCount() const = 0; + virtual t_size TableEdit_GetColumnCount() const = 0; + virtual void TableEdit_SetItemFocus(t_size item, t_size subItem) = 0; + virtual bool TableEdit_IsColumnEditable(t_size subItem) const {return true;} + virtual void TableEdit_GetColumnOrder(t_size * out, t_size count) const {order_helper::g_fill(out,count);} + virtual t_uint32 TableEdit_GetEditFlags(t_size item, t_size subItem) const {return 0;} + virtual bool TableEdit_GetAutoComplete(t_size item, t_size subItem, pfc::com_ptr_t & out) {return false;} + void TableEdit_Start(t_size item, t_size subItem); + void TableEdit_Abort(bool forwardContent); + bool TableEdit_IsActive() const {return have_task(KTaskID);} + protected: + void on_task_completion(unsigned p_id,unsigned p_status); + private: + t_size ColumnToPosition(t_size col) const; + t_size PositionToColumn(t_size pos) const; + t_size EditableColumnCount() const; + void GrabColumnOrder(pfc::array_t & buffer) const {buffer.set_size(TableEdit_GetColumnCount()); TableEdit_GetColumnOrder(buffer.get_ptr(), buffer.get_size());} + void _ReStart(); + + t_size m_editItem, m_editSubItem; + t_uint32 m_editFlags; + pfc::rcptr_t m_editData; + static const unsigned KTaskID = 0x6f0a3de6; + }; + + + + + class NOVTABLE CTableEditHelperV2_ListView : public CTableEditHelperV2 { + public: + RECT TableEdit_GetItemRect(t_size item, t_size subItem) const; + void TableEdit_GetField(t_size item, t_size subItem, pfc::string_base & out, t_size & lineCount); + void TableEdit_SetField(t_size item, t_size subItem, const char * value); + + t_size TableEdit_GetColumnCount() const {return (t_size) ListView_GetColumnCount(TableEdit_GetParentWnd());} + + t_size TableEdit_GetItemCount() const; + void TableEdit_SetItemFocus(t_size item, t_size subItem); + + void TableEdit_GetColumnOrder(t_size * out, t_size count) const; + }; +} diff --git a/foobar2000/ATLHelpers/misc.cpp b/foobar2000/ATLHelpers/misc.cpp new file mode 100644 index 0000000..fdac11c --- /dev/null +++ b/foobar2000/ATLHelpers/misc.cpp @@ -0,0 +1,100 @@ +#include "stdafx.h" +#include "Controls.h" +#include "../helpers/win32_misc.h" + +void PaintSeparatorControl(CWindow wnd) { + CPaintDC dc(wnd); + TCHAR buffer[512] = {}; + wnd.GetWindowText(buffer, _countof(buffer)); + const int txLen = pfc::strlen_max_t(buffer, _countof(buffer)); + CRect contentRect; + WIN32_OP_D( wnd.GetClientRect(contentRect) ); + + dc.SetTextColor(GetSysColor(COLOR_WINDOWTEXT)); + dc.SetBkMode(TRANSPARENT); + + { + CBrushHandle brush = (HBRUSH) wnd.GetParent().SendMessage(WM_CTLCOLORSTATIC, (WPARAM) (HDC) dc, (LPARAM) wnd.m_hWnd); + if (brush != NULL) dc.FillRect(contentRect, brush); + } + SelectObjectScope scopeFont(dc, wnd.GetFont()); + + if (txLen > 0) { + CRect rcText(contentRect); + if ( !wnd.IsWindowEnabled() ) { + dc.SetTextColor( GetSysColor(COLOR_GRAYTEXT) ); + } + WIN32_OP_D( dc.DrawText(buffer,txLen,rcText,DT_NOPREFIX | DT_END_ELLIPSIS | DT_SINGLELINE | DT_VCENTER | DT_LEFT ) > 0); + // WIN32_OP_D( dc.GrayString(NULL, NULL, (LPARAM) buffer, txLen, rcText.left, rcText.top, rcText.Width(), rcText.Height() ) ); + } + + SIZE txSize, probeSize; + const TCHAR probe[] = _T("#"); + if (dc.GetTextExtent(buffer,txLen,&txSize) && dc.GetTextExtent(probe, _countof(probe), &probeSize)) { + int spacing = txSize.cx > 0 ? (probeSize.cx / 4) : 0; + if (txSize.cx + spacing < contentRect.Width()) { + const CPoint center = contentRect.CenterPoint(); + CRect rcEdge(contentRect.left + txSize.cx + spacing, center.y, contentRect.right, contentRect.bottom); + WIN32_OP_D( dc.DrawEdge(rcEdge, EDGE_ETCHED, BF_TOP) ); + } + } +} + + + +void ui_element_instance_standard_context_menu(service_ptr_t p_elem, LPARAM p_pt) { + CPoint pt; + bool fromKeyboard; + if (p_pt == -1) { + fromKeyboard = true; + if (!p_elem->edit_mode_context_menu_get_focus_point(pt)) { + CRect rc; + WIN32_OP_D( GetWindowRect(p_elem->get_wnd(), rc) ); + pt = rc.CenterPoint(); + } + } else { + fromKeyboard = false; + pt = p_pt; + } + if (p_elem->edit_mode_context_menu_test(pt,fromKeyboard)) { + const unsigned idBase = 1; + CMenu menu; + WIN32_OP( menu.CreatePopupMenu() ); + p_elem->edit_mode_context_menu_build(pt,fromKeyboard,menu,idBase); + + int cmd; + { + CMenuSelectionReceiver_UiElement receiver(p_elem,idBase); + cmd = menu.TrackPopupMenu(TPM_RIGHTBUTTON|TPM_NONOTIFY|TPM_RETURNCMD,pt.x,pt.y,receiver); + } + if (cmd > 0) p_elem->edit_mode_context_menu_command(pt,fromKeyboard,cmd,idBase); + } +} +void ui_element_instance_standard_context_menu_eh(service_ptr_t p_elem, LPARAM p_pt) { + try { + ui_element_instance_standard_context_menu(p_elem, p_pt); + } catch(std::exception const & e) { + console::complain("Context menu failure", e); + } +} + + +#if _WIN32_WINNT >= 0x501 +void HeaderControl_SetSortIndicator(CHeaderCtrl header, int column, bool isUp) { + const int total = header.GetItemCount(); + for(int walk = 0; walk < total; ++walk) { + HDITEM item = {}; item.mask = HDI_FORMAT; + if (header.GetItem(walk,&item)) { + DWORD newFormat = item.fmt; + newFormat &= ~( HDF_SORTUP | HDF_SORTDOWN ); + if (walk == column) { + newFormat |= isUp ? HDF_SORTUP : HDF_SORTDOWN; + } + if (newFormat != item.fmt) { + item.fmt = newFormat; + header.SetItem(walk,&item); + } + } + } +} +#endif diff --git a/foobar2000/helpers/atl-misc.h b/foobar2000/ATLHelpers/misc.h similarity index 66% rename from foobar2000/helpers/atl-misc.h rename to foobar2000/ATLHelpers/misc.h index ee7c39c..826f711 100644 --- a/foobar2000/helpers/atl-misc.h +++ b/foobar2000/ATLHelpers/misc.h @@ -1,7 +1,7 @@ #pragma once -#include "win32_misc.h" -#include +#include "../helpers/win32_misc.h" +#include "WTL-PP.h" #include class CMenuSelectionReceiver : public CWindowImpl { @@ -129,7 +129,7 @@ public: CHAIN_MSG_MAP(TClass) END_MSG_MAP_HOOK() private: - BOOL OnInitDialog(CWindow, LPARAM) {m_modeless.Set( this->m_hWnd ); SetMsgHandled(FALSE); return FALSE; } + BOOL OnInitDialog(CWindow, LPARAM) {m_modeless.Set( m_hWnd ); SetMsgHandled(FALSE); return FALSE; } void OnDestroy() {m_modeless.Set(NULL); SetMsgHandled(FALSE); } CModelessDialogEntry m_modeless; }; @@ -155,6 +155,45 @@ private: const service_ptr_t m_owner; }; +void ui_element_instance_standard_context_menu(service_ptr_t p_elem, LPARAM p_pt); +void ui_element_instance_standard_context_menu_eh(service_ptr_t p_elem, LPARAM p_pt); + +#if _WIN32_WINNT >= 0x501 +void HeaderControl_SetSortIndicator(CHeaderCtrl header, int column, bool isUp); +#endif + +class CTypableWindowScope { +public: + CTypableWindowScope() : m_wnd() {} + ~CTypableWindowScope() {Set(NULL);} + void Set(HWND wnd) { + try { + if (m_wnd != NULL) { + static_api_ptr_t()->remove(m_wnd); + } + m_wnd = wnd; + if (m_wnd != NULL) { + static_api_ptr_t()->add(m_wnd); + } + } catch(exception_service_not_found) { + m_wnd = NULL; + } + } + +private: + HWND m_wnd; + PFC_CLASS_NOT_COPYABLE_EX(CTypableWindowScope); +}; + + +template class CContainedWindowSimpleT : public CContainedWindowT, public CMessageMap { +public: + CContainedWindowSimpleT() : CContainedWindowT(this) {} + BEGIN_MSG_MAP(CContainedWindowSimpleT) + END_MSG_MAP() +}; + + static bool window_service_trait_defer_destruction(const service_base *) {return true;} @@ -175,9 +214,9 @@ public: if (ret == 0) { if (window_service_trait_defer_destruction(this) && !InterlockedExchange(&m_delayedDestroyInProgress,1)) { PFC_ASSERT_NO_EXCEPTION( service_impl_helper::release_object_delayed(this); ); - } else if (this->m_hWnd != NULL) { + } else if (m_hWnd != NULL) { if (!m_destroyWindowInProgress) { // don't double-destroy in weird scenarios - PFC_ASSERT_NO_EXCEPTION( ::DestroyWindow(this->m_hWnd) ); + PFC_ASSERT_NO_EXCEPTION( ::DestroyWindow(m_hWnd) ); } } else { PFC_ASSERT_NO_EXCEPTION( delete this ); @@ -202,12 +241,6 @@ private: pfc::refcounter m_counter; }; -namespace fb2k { - template - service_ptr_t service_new_window(arg_t && ... arg) { - return new window_service_impl_t< obj_t > ( std::forward (arg) ... ); - } -} static void AppendMenuPopup(HMENU menu, UINT flags, CMenu & popup, const TCHAR * label) { PFC_ASSERT( flags & MF_POPUP ); @@ -221,27 +254,143 @@ public: LRESULT& lResult, DWORD dwMsgMapID) {return FALSE;} }; +class CPopupTooltipMessage { +public: + CPopupTooltipMessage(DWORD style = TTS_BALLOON | TTS_NOPREFIX) : m_style(style | WS_POPUP), m_toolinfo(), m_shutDown() {} + void ShowFocus(const TCHAR * message, CWindow wndParent) { + Show(message, wndParent); wndParent.SetFocus(); + } + void Show(const TCHAR * message, CWindow wndParent) { + if (m_shutDown || (message == NULL && m_tooltip.m_hWnd == NULL)) return; + Initialize(); + Hide(); + + if (message != NULL) { + CRect rect; + WIN32_OP_D( wndParent.GetWindowRect(rect) ); + ShowInternal(message, wndParent, rect); + } + } + void ShowEx(const TCHAR * message, CWindow wndParent, CRect rect) { + if (m_shutDown) return; + Initialize(); + Hide(); + ShowInternal(message, wndParent, rect); + } + void Hide() { + if (m_tooltip.m_hWnd != NULL && m_tooltip.GetToolCount() > 0) { + m_tooltip.TrackActivate(&m_toolinfo,FALSE); + m_tooltip.DelTool(&m_toolinfo); + } + } + + void CleanUp() { + if (m_tooltip.m_hWnd != NULL) { + m_tooltip.DestroyWindow(); + } + } + void ShutDown() { + m_shutDown = true; CleanUp(); + } +private: + void ShowInternal(const TCHAR * message, CWindow wndParent, CRect rect) { + + PFC_ASSERT( !m_shutDown ); + PFC_ASSERT( message != NULL ); + PFC_ASSERT( wndParent != NULL ); + + if ( _tcschr( message, '\n') != nullptr ) { + m_tooltip.SetMaxTipWidth( rect.Width() ); + } + m_toolinfo.cbSize = sizeof(m_toolinfo); + m_toolinfo.uFlags = TTF_TRACK|TTF_IDISHWND|TTF_ABSOLUTE|TTF_TRANSPARENT|TTF_CENTERTIP; + m_toolinfo.hwnd = wndParent; + m_toolinfo.uId = 0; + m_toolinfo.lpszText = const_cast(message); + m_toolinfo.hinst = NULL; //core_api::get_my_instance(); + if (m_tooltip.AddTool(&m_toolinfo)) { + m_tooltip.TrackPosition(rect.CenterPoint().x,rect.bottom); + m_tooltip.TrackActivate(&m_toolinfo,TRUE); + } + } + void Initialize() { + if (m_tooltip.m_hWnd == NULL) { + WIN32_OP( m_tooltip.Create( NULL , NULL, NULL, m_style) ); + } + } + CContainedWindowSimpleT m_tooltip; + TOOLINFO m_toolinfo; + const DWORD m_style; + bool m_shutDown; +}; + + +template class CDialogWithTooltip : public CDialogImpl { +public: + BEGIN_MSG_MAP(CDialogWithTooltip) + MSG_WM_DESTROY(OnDestroy) + END_MSG_MAP() + + void ShowTip(UINT id, const TCHAR * label) { + m_tip.Show(label, GetDlgItem(id)); + } + void ShowTip(HWND child, const TCHAR * label) { + m_tip.Show(label, child); + } + + void ShowTipF(UINT id, const TCHAR * label) { + m_tip.ShowFocus(label, GetDlgItem(id)); + } + void ShowTipF(HWND child, const TCHAR * label) { + m_tip.ShowFocus(label, child); + } + void HideTip() {m_tip.Hide();} +private: + void OnDestroy() {m_tip.ShutDown(); SetMsgHandled(FALSE); } + CPopupTooltipMessage m_tip; +}; + + +static void ListView_FixContextMenuPoint(CListViewCtrl list,CPoint & coords) { + if (coords == CPoint(-1,-1)) { + int selWalk = -1; + CRect rcClient; WIN32_OP_D(list.GetClientRect(rcClient)); + for(;;) { + selWalk = list.GetNextItem(selWalk, LVNI_SELECTED); + if (selWalk < 0) { + CRect rc; + WIN32_OP_D( list.GetWindowRect(&rc) ); + coords = rc.CenterPoint(); + return; + } + CRect rcItem, rcVisible; + WIN32_OP_D( list.GetItemRect(selWalk, &rcItem, LVIR_BOUNDS) ); + if (rcVisible.IntersectRect(rcItem, rcClient)) { + coords = rcVisible.CenterPoint(); + WIN32_OP_D( list.ClientToScreen(&coords) ); + return; + } + } + } +} + + template class preferences_page_instance_impl : public TDialog { public: - preferences_page_instance_impl(HWND parent, preferences_page_callback::ptr callback) : TDialog(callback) { - WIN32_OP(this->Create(parent) != NULL); - - // complain early if what we created isn't a child window - PFC_ASSERT( (this->GetStyle() & (WS_POPUP|WS_CHILD)) == WS_CHILD ); - } + preferences_page_instance_impl(HWND parent, preferences_page_callback::ptr callback) : TDialog(callback) {WIN32_OP(this->Create(parent) != NULL);} HWND get_wnd() {return this->m_hWnd;} }; static bool window_service_trait_defer_destruction(const preferences_page_instance *) {return false;} template class preferences_page_impl : public preferences_page_v3 { public: preferences_page_instance::ptr instantiate(HWND parent, preferences_page_callback::ptr callback) { - return fb2k::service_new_window >(parent, callback); + return new window_service_impl_t >(parent, callback); } }; diff --git a/foobar2000/ATLHelpers/stdafx.cpp b/foobar2000/ATLHelpers/stdafx.cpp new file mode 100644 index 0000000..28d0c35 --- /dev/null +++ b/foobar2000/ATLHelpers/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// foobar2000_ATL_helpers.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/foobar2000/ATLHelpers/stdafx.h b/foobar2000/ATLHelpers/stdafx.h new file mode 100644 index 0000000..326d808 --- /dev/null +++ b/foobar2000/ATLHelpers/stdafx.h @@ -0,0 +1,15 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later. +#define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows. +#endif + + +// TODO: reference additional headers your program requires here + +#include "ATLHelpersLean.h" diff --git a/foobar2000/helpers/ui_element_helpers.cpp b/foobar2000/ATLHelpers/ui_element_helpers.cpp similarity index 91% rename from foobar2000/helpers/ui_element_helpers.cpp rename to foobar2000/ATLHelpers/ui_element_helpers.cpp index f52b48b..1285f9d 100644 --- a/foobar2000/helpers/ui_element_helpers.cpp +++ b/foobar2000/ATLHelpers/ui_element_helpers.cpp @@ -3,8 +3,8 @@ #if FOOBAR2000_TARGET_VERSION >= 79 #include "ui_element_helpers.h" -#include -#include "atl-misc.h" +#include "../helpers/IDataObjectUtils.h" +#include "misc.h" namespace ui_element_helpers { @@ -19,7 +19,7 @@ namespace ui_element_helpers { if (!find(ptr,cfg->get_guid())) throw exception_io_data("UI Element Not Found"); auto ret = ptr->instantiate(p_parent,cfg,p_callback); if (ret.is_empty()) throw std::runtime_error("Null UI Element returned"); - return ret; + return std::move(ret); } catch(std::exception const & e) { console::complain("UI Element instantiation failure",e); return instantiate_dummy(p_parent,cfg,p_callback); @@ -51,7 +51,7 @@ namespace ui_element_helpers { }; void ui_element_helpers::replace_with_new_element(ui_element_instance_ptr & p_item,const GUID & p_guid,HWND p_parent,ui_element_instance_callback_ptr p_callback) { - auto & l_abort = fb2k::noAbort; + abort_callback_dummy l_abort; ui_element_config::ptr cfg; try { if (p_item.is_empty()) { @@ -350,41 +350,4 @@ bool ui_element_helpers::ui_element_instance_host_base::grabTopPriorityChild(ui_ if (best.is_empty()) return false; out = best; outPriority = bestPriority; outWhich = bestWhich; return true; } - -void ui_element_instance_standard_context_menu(service_ptr_t p_elem, LPARAM p_pt) { - CPoint pt; - bool fromKeyboard; - if (p_pt == -1) { - fromKeyboard = true; - if (!p_elem->edit_mode_context_menu_get_focus_point(pt)) { - CRect rc; - WIN32_OP_D(GetWindowRect(p_elem->get_wnd(), rc)); - pt = rc.CenterPoint(); - } - } else { - fromKeyboard = false; - pt = p_pt; - } - if (p_elem->edit_mode_context_menu_test(pt, fromKeyboard)) { - const unsigned idBase = 1; - CMenu menu; - WIN32_OP(menu.CreatePopupMenu()); - p_elem->edit_mode_context_menu_build(pt, fromKeyboard, menu, idBase); - - int cmd; - { - CMenuSelectionReceiver_UiElement receiver(p_elem, idBase); - cmd = menu.TrackPopupMenu(TPM_RIGHTBUTTON | TPM_NONOTIFY | TPM_RETURNCMD, pt.x, pt.y, receiver); - } - if (cmd > 0) p_elem->edit_mode_context_menu_command(pt, fromKeyboard, cmd, idBase); - } -} -void ui_element_instance_standard_context_menu_eh(service_ptr_t p_elem, LPARAM p_pt) { - try { - ui_element_instance_standard_context_menu(p_elem, p_pt); - } catch (std::exception const & e) { - console::complain("Context menu failure", e); - } -} - #endif // FOOBAR2000_TARGET_VERSION >= 79 diff --git a/foobar2000/helpers/ui_element_helpers.h b/foobar2000/ATLHelpers/ui_element_helpers.h similarity index 98% rename from foobar2000/helpers/ui_element_helpers.h rename to foobar2000/ATLHelpers/ui_element_helpers.h index 48e7c98..a7d329d 100644 --- a/foobar2000/helpers/ui_element_helpers.h +++ b/foobar2000/ATLHelpers/ui_element_helpers.h @@ -371,7 +371,4 @@ namespace ui_element_helpers { void handle_WM_GETMINMAXINFO(LPARAM p_lp,const ui_element_min_max_info & p_myinfo); }; -void ui_element_instance_standard_context_menu(service_ptr_t p_elem, LPARAM p_pt); -void ui_element_instance_standard_context_menu_eh(service_ptr_t p_elem, LPARAM p_pt); - #endif // FOOBAR2000_TARGET_VERSION >= 79 diff --git a/foobar2000/SDK/abort_callback.cpp b/foobar2000/SDK/abort_callback.cpp index 7bb8fa4..4e27d52 100644 --- a/foobar2000/SDK/abort_callback.cpp +++ b/foobar2000/SDK/abort_callback.cpp @@ -22,21 +22,3 @@ bool abort_callback::waitForEvent( pfc::eventHandle_t evtHandle, double timeOut default: uBugCheck(); } } - -bool abort_callback::waitForEvent(pfc::event& evt, double timeOut) { - return waitForEvent(evt.get_handle(), timeOut); -} - -void abort_callback::waitForEvent(pfc::eventHandle_t evtHandle) { - bool status = waitForEvent(evtHandle, -1); (void)status; - PFC_ASSERT(status); // should never return false -} - -void abort_callback::waitForEvent(pfc::event& evt) { - bool status = waitForEvent(evt, -1); (void)status; - PFC_ASSERT(status); // should never return false -} - -namespace fb2k { - abort_callback_dummy noAbort; -} diff --git a/foobar2000/SDK/abort_callback.h b/foobar2000/SDK/abort_callback.h index e0c30cc..c814055 100644 --- a/foobar2000/SDK/abort_callback.h +++ b/foobar2000/SDK/abort_callback.h @@ -40,17 +40,8 @@ public: //! Sleeps p_timeout_seconds or less when aborted, returns true when execution should continue, false when not. bool sleep_ex(double p_timeout_seconds) const; - //! Waits for an event. Returns true if event is now signaled, false if the specified period has elapsed and the event did not become signaled. \n - //! Throws exception_aborted if aborted. - bool waitForEvent( pfc::eventHandle_t evtHandle, double timeOut ); - //! Waits for an event. Returns true if event is now signaled, false if the specified period has elapsed and the event did not become signaled. \n - //! Throws exception_aborted if aborted. - bool waitForEvent(pfc::event& evt, double timeOut); - - //! Waits for an event. Returns once the event became signaled; throw exception_aborted if abort occurred first. - void waitForEvent(pfc::eventHandle_t evtHandle); - //! Waits for an event. Returns once the event became signaled; throw exception_aborted if abort occurred first. - void waitForEvent(pfc::event& evt); + bool waitForEvent( pfc::eventHandle_t evtHandle, double timeOut ); + bool waitForEvent( pfc::event & evt, double timeOut ) {return waitForEvent( evt.get_handle(), timeOut ); } protected: abort_callback() {} ~abort_callback() {} @@ -73,8 +64,8 @@ public: abort_callback_event get_abort_event() const {return m_event.get_handle();} private: - abort_callback_impl(const abort_callback_impl &) = delete; - const abort_callback_impl & operator=(const abort_callback_impl&) = delete; + abort_callback_impl(const abort_callback_impl &); + const abort_callback_impl & operator=(const abort_callback_impl&); volatile bool m_aborting; pfc::event m_event; @@ -110,10 +101,4 @@ using namespace foobar2000_io; PP::aborter aborter_pfcv2( aborterRef ); \ PP::aborterScope l_aborterScope( aborter_pfcv2 ); - -namespace fb2k { - // A shared abort_callback_dummy instance - extern abort_callback_dummy noAbort; -} - #endif //_foobar2000_sdk_abort_callback_h_ diff --git a/foobar2000/SDK/advconfig.cpp b/foobar2000/SDK/advconfig.cpp index b75cdf9..6da30c7 100644 --- a/foobar2000/SDK/advconfig.cpp +++ b/foobar2000/SDK/advconfig.cpp @@ -1,13 +1,5 @@ #include "foobar2000.h" -bool advconfig_entry::is_branch() { - advconfig_branch::ptr branch; - return branch &= this; -} - -bool advconfig_entry::g_find(service_ptr_t& out, const GUID & id) { - service_enum_t e; service_ptr_t ptr; while(e.next(ptr)) { if (ptr->get_guid() == id) {out = ptr; return true;} } return false; -} t_uint32 advconfig_entry::get_preferences_flags_() { { diff --git a/foobar2000/SDK/advconfig.h b/foobar2000/SDK/advconfig.h index 72ab8fe..41cf68c 100644 --- a/foobar2000/SDK/advconfig.h +++ b/foobar2000/SDK/advconfig.h @@ -11,10 +11,11 @@ public: virtual void reset() = 0; virtual double get_sort_priority() = 0; - bool is_branch(); t_uint32 get_preferences_flags_(); - static bool g_find(service_ptr_t& out, const GUID & id); + static bool g_find(service_ptr_t& out, const GUID & id) { + service_enum_t e; service_ptr_t ptr; while(e.next(ptr)) { if (ptr->get_guid() == id) {out = ptr; return true;} } return false; + } template static bool g_find_t(outptr & out, const GUID & id) { service_ptr_t temp; @@ -23,7 +24,7 @@ public: } static const GUID guid_root; - static const GUID guid_branch_tagging,guid_branch_decoding,guid_branch_tools,guid_branch_playback,guid_branch_display,guid_branch_debug, guid_branch_tagging_general; + static const GUID guid_branch_tagging,guid_branch_decoding,guid_branch_tools,guid_branch_playback,guid_branch_display,guid_branch_debug; FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(advconfig_entry); }; @@ -249,8 +250,8 @@ public: advconfig_integer_factory_(const char * p_name,const GUID & p_guid,const GUID & p_parent,double p_priority,t_uint64 p_initialstate,t_uint64 p_min,t_uint64 p_max, t_uint32 p_prefFlags = 0) : service_factory_single_t >(p_name,p_guid,p_parent,p_priority,p_initialstate,p_min,p_max,p_prefFlags) {} - int_t get() const {return this->get_static_instance().get_state_int();} - void set(int_t val) {this->get_static_instance().set_state_int(val);} + int_t get() const {return get_static_instance().get_state_int();} + void set(int_t val) {get_static_instance().set_state_int(val);} operator int_t() const {return get();} int_t operator=(int_t val) {set(val); return val;} diff --git a/foobar2000/SDK/album_art.cpp b/foobar2000/SDK/album_art.cpp index edf0daa..642e581 100644 --- a/foobar2000/SDK/album_art.cpp +++ b/foobar2000/SDK/album_art.cpp @@ -1,17 +1,5 @@ #include "foobar2000.h" -GUID album_art_extractor::get_guid() { - album_art_extractor_v2::ptr v2; - if ( v2 &= this ) return v2->get_guid(); - return pfc::guid_null; -} - -GUID album_art_editor::get_guid() { - album_art_editor_v2::ptr v2; - if ( v2 &= this ) return v2->get_guid(); - return pfc::guid_null; -} - bool album_art_extractor_instance::query(const GUID & what, album_art_data::ptr & out, abort_callback & abort) { try { out = query(what, abort); return true; } catch (exception_album_art_not_found) { return false; } } @@ -20,23 +8,9 @@ bool album_art_extractor_instance::have_entry(const GUID & what, abort_callback try { query(what, abort); return true; } catch(exception_album_art_not_found) { return false; } } -void album_art_editor_instance::remove_all_() { - album_art_editor_instance_v2::ptr v2; - if ( v2 &= this ) { - v2->remove_all(); - } else { - for( size_t walk = 0; walk < album_art_ids::num_types(); ++ walk ) { - try { - this->remove( album_art_ids::query_type( walk ) ); - } catch(exception_io_data) {} - catch(exception_album_art_not_found) {} - } - } -} - bool album_art_editor::g_get_interface(service_ptr_t & out,const char * path) { service_enum_t e; ptr ptr; - auto ext = pfc::string_extension(path); + pfc::string_extension ext(path); while(e.next(ptr)) { if (ptr->is_our_path(path,ext)) { out = ptr; return true; } } @@ -48,18 +22,6 @@ bool album_art_editor::g_is_supported_path(const char * path) { } album_art_editor_instance_ptr album_art_editor::g_open(file_ptr p_filehint,const char * p_path,abort_callback & p_abort) { - -#ifdef FOOBAR2000_DESKTOP - { - input_manager_v2::ptr m; - if (fb2k::std_api_try_get(m)) { - album_art_editor_instance::ptr ret; - ret ^= m->open_v2(album_art_editor_instance::class_guid, p_filehint, p_path, false, nullptr, p_abort); - return ret; - } - } -#endif - album_art_editor::ptr obj; if (!g_get_interface(obj, p_path)) throw exception_album_art_unsupported_format(); return obj->open(p_filehint, p_path, p_abort); @@ -68,7 +30,7 @@ album_art_editor_instance_ptr album_art_editor::g_open(file_ptr p_filehint,const bool album_art_extractor::g_get_interface(service_ptr_t & out,const char * path) { service_enum_t e; ptr ptr; - auto ext = pfc::string_extension(path); + pfc::string_extension ext(path); while(e.next(ptr)) { if (ptr->is_our_path(path,ext)) { out = ptr; return true; } } @@ -79,17 +41,6 @@ bool album_art_extractor::g_is_supported_path(const char * path) { ptr ptr; return g_get_interface(ptr,path); } album_art_extractor_instance_ptr album_art_extractor::g_open(file_ptr p_filehint,const char * p_path,abort_callback & p_abort) { -#ifdef FOOBAR2000_DESKTOP - { - input_manager_v2::ptr m; - if (fb2k::std_api_try_get(m)) { - album_art_extractor_instance::ptr ret; - ret ^= m->open_v2(album_art_extractor_instance::class_guid, p_filehint, p_path, false, nullptr, p_abort); - return ret; - } - } -#endif - album_art_extractor::ptr obj; if (!g_get_interface(obj, p_path)) throw exception_album_art_unsupported_format(); return obj->open(p_filehint, p_path, p_abort); @@ -120,66 +71,4 @@ now_playing_album_art_notify * now_playing_album_art_notify_manager::add(std::fu obj->f = f; add(obj); return obj; -} - -namespace { - struct aa_t { - GUID type; const char * name; - }; - static const GUID guids[] = { - album_art_ids::cover_front, - album_art_ids::cover_back, - album_art_ids::artist, - album_art_ids::disc, - album_art_ids::icon, - }; - static const char * const names[] = { - "front cover", - "back cover", - "artist", - "disc", - "icon" - }; - static const char * const names2[] = { - "Front Cover", - "Back Cover", - "Artist", - "Disc", - "Icon" - }; -} - -size_t album_art_ids::num_types() { - PFC_STATIC_ASSERT( PFC_TABSIZE( guids ) == PFC_TABSIZE( names ) ); - PFC_STATIC_ASSERT( PFC_TABSIZE( guids ) == PFC_TABSIZE( names2 ) ); - return PFC_TABSIZE( guids ); -} - -GUID album_art_ids::query_type(size_t idx) { - PFC_ASSERT( idx < PFC_TABSIZE( guids ) ); - return guids[idx]; -} - -const char * album_art_ids::query_name(size_t idx) { - PFC_ASSERT( idx < PFC_TABSIZE( names ) ); - return names[idx]; -} - -const char * album_art_ids::name_of(const GUID & id) { - for( size_t w = 0; w < num_types(); ++w ) { - if ( query_type(w) == id ) return query_name(w); - } - return nullptr; -} - -const char * album_art_ids::query_capitalized_name( size_t idx ) { - PFC_ASSERT( idx < PFC_TABSIZE( names2 ) ); - return names2[idx]; -} - -const char * album_art_ids::capitalized_name_of( const GUID & id) { - for( size_t w = 0; w < num_types(); ++w ) { - if ( query_type(w) == id ) return query_capitalized_name(w); - } - return nullptr; -} +} \ No newline at end of file diff --git a/foobar2000/SDK/album_art.h b/foobar2000/SDK/album_art.h index 7c0cf90..4ef2cca 100644 --- a/foobar2000/SDK/album_art.h +++ b/foobar2000/SDK/album_art.h @@ -25,9 +25,6 @@ public: }; typedef service_ptr_t album_art_data_ptr; -namespace fb2k { - typedef album_art_data_ptr memBlockRef; -} //! Namespace containing identifiers of album art types. namespace album_art_ids { @@ -42,14 +39,6 @@ namespace album_art_ids { //! Artist picture. static const GUID artist = { 0x9a654042, 0xacd1, 0x43f7, { 0xbf, 0xcf, 0xd3, 0xec, 0xf, 0xfe, 0x40, 0xfa } }; - size_t num_types(); - GUID query_type( size_t ); - // returns lowercase name - const char * query_name( size_t ); - const char * name_of( const GUID & ); - // returns Capitalized name - const char * query_capitalized_name( size_t ); - const char * capitalized_name_of( const GUID & ); }; PFC_DECLARE_EXCEPTION(exception_album_art_not_found,exception_io_not_found,"Attached picture not found"); @@ -80,9 +69,6 @@ public: //! Finalizes file tag update operation. virtual void commit(abort_callback & p_abort) = 0; - - //! Helper; see album_art_editor_instance_v2::remove_all(); - void remove_all_(); }; class NOVTABLE album_art_editor_instance_v2 : public album_art_editor_instance { @@ -98,7 +84,6 @@ typedef service_ptr_t album_art_editor_instance_ptr; //! Entrypoint class for accessing album art extraction functionality. Register your own implementation to allow album art extraction from your media file format. \n //! If you want to extract album art from a media file, it's recommended that you use album_art_manager API instead of calling album_art_extractor directly. class NOVTABLE album_art_extractor : public service_base { - FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(album_art_extractor); public: //! Returns whether the specified file is one of formats supported by our album_art_extractor implementation. //! @param p_path Path to file being queried. @@ -115,21 +100,11 @@ public: static album_art_extractor_instance_ptr g_open(file_ptr p_filehint,const char * p_path,abort_callback & p_abort); static album_art_extractor_instance_ptr g_open_allowempty(file_ptr p_filehint,const char * p_path,abort_callback & p_abort); - //! Returns GUID of the corresponding input class. Null GUID if none. - GUID get_guid(); -}; - -//! \since 1.5 -class NOVTABLE album_art_extractor_v2 : public album_art_extractor { - FB2K_MAKE_SERVICE_INTERFACE(album_art_extractor_v2 , album_art_extractor); -public: - //! Returns GUID of the corresponding input class. Null GUID if none. - virtual GUID get_guid() = 0; + FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(album_art_extractor); }; //! Entrypoint class for accessing album art editing functionality. Register your own implementation to allow album art editing on your media file format. class NOVTABLE album_art_editor : public service_base { - FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(album_art_editor); public: //! Returns whether the specified file is one of formats supported by our album_art_editor implementation. //! @param p_path Path to file being queried. @@ -148,20 +123,11 @@ public: static album_art_editor_instance_ptr g_open(file_ptr p_filehint,const char * p_path,abort_callback & p_abort); - //! Returns GUID of the corresponding input class. Null GUID if none. - GUID get_guid(); + FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(album_art_editor); }; -//! \since 1.5 -class NOVTABLE album_art_editor_v2 : public album_art_editor { - FB2K_MAKE_SERVICE_INTERFACE( album_art_editor_v2, album_art_editor ) -public: - //! Returns GUID of the corresponding input class. Null GUID if none. - virtual GUID get_guid() = 0; -}; -//! \since 0.9.5 -//! Helper API for extracting album art from APEv2 tags. +//! Helper API for extracting album art from APEv2 tags - introduced in 0.9.5. class NOVTABLE tag_processor_album_art_utils : public service_base { FB2K_MAKE_SERVICE_COREAPI(tag_processor_album_art_utils) public: diff --git a/foobar2000/SDK/album_art_helpers.h b/foobar2000/SDK/album_art_helpers.h index 786c22c..6f985ae 100644 --- a/foobar2000/SDK/album_art_helpers.h +++ b/foobar2000/SDK/album_art_helpers.h @@ -1,4 +1,3 @@ -#pragma once //! Implements album_art_data. class album_art_data_impl : public album_art_data { public: @@ -51,37 +50,32 @@ private: }; //! Helper implementation of album_art_extractor - reads album art from arbitrary file formats that comply with APEv2 tagging specification. -class album_art_extractor_impl_stdtags : public album_art_extractor_v2 { +class album_art_extractor_impl_stdtags : public album_art_extractor { public: //! @param exts Semicolon-separated list of file format extensions to support. - album_art_extractor_impl_stdtags(const char * exts, const GUID & guid) : m_guid(guid) { + album_art_extractor_impl_stdtags(const char * exts) { pfc::splitStringSimple_toList(m_extensions,';',exts); } - bool is_our_path(const char * p_path,const char * p_extension) override { + bool is_our_path(const char * p_path,const char * p_extension) { return m_extensions.have_item(p_extension); } - album_art_extractor_instance_ptr open(file_ptr p_filehint,const char * p_path,abort_callback & p_abort) override { + album_art_extractor_instance_ptr open(file_ptr p_filehint,const char * p_path,abort_callback & p_abort) { PFC_ASSERT( is_our_path(p_path, pfc::string_extension(p_path) ) ); file_ptr l_file ( p_filehint ); if (l_file.is_empty()) filesystem::g_open_read(l_file, p_path, p_abort); return tag_processor_album_art_utils::get()->open( l_file, p_abort ); } - - GUID get_guid() override { - return m_guid; - } private: pfc::avltree_t m_extensions; - const GUID m_guid; }; //! Helper implementation of album_art_editor - edits album art from arbitrary file formats that comply with APEv2 tagging specification. -class album_art_editor_impl_stdtags : public album_art_editor_v2 { +class album_art_editor_impl_stdtags : public album_art_editor { public: //! @param exts Semicolon-separated list of file format extensions to support. - album_art_editor_impl_stdtags(const char * exts, const GUID & guid) : m_guid(guid) { + album_art_editor_impl_stdtags(const char * exts) { pfc::splitStringSimple_toList(m_extensions,';',exts); } @@ -95,12 +89,8 @@ public: if (l_file.is_empty()) filesystem::g_open(l_file, p_path, filesystem::open_mode_write_existing, p_abort); return tag_processor_album_art_utils::get()->edit( l_file, p_abort ); } - GUID get_guid() override { - return m_guid; - } private: pfc::avltree_t m_extensions; - const GUID m_guid; }; diff --git a/foobar2000/SDK/archive.h b/foobar2000/SDK/archive.h deleted file mode 100644 index d70548a..0000000 --- a/foobar2000/SDK/archive.h +++ /dev/null @@ -1,85 +0,0 @@ -#pragma once - -namespace foobar2000_io { - class archive; - - class NOVTABLE archive_callback : public abort_callback { - public: - virtual bool on_entry(archive * owner,const char * url,const t_filestats & p_stats,const service_ptr_t & p_reader) = 0; - }; - - //! Interface for archive reader services. When implementing, derive from archive_impl rather than from deriving from archive directly. - class NOVTABLE archive : public filesystem { - FB2K_MAKE_SERVICE_INTERFACE(archive,filesystem); - public: - //! Lists archive contents. \n - //! May be called with any path, not only path accepted by is_our_archive. - virtual void archive_list(const char * p_path,const service_ptr_t & p_reader,archive_callback & p_callback,bool p_want_readers) = 0; - - //! Optional method to weed out unsupported formats prior to calling archive_list. \n - //! Use this to suppress calls to archive_list() to avoid spurious exceptions being thrown. \n - //! Implemented via archive_v2. - bool is_our_archive( const char * path ); - }; - - //! \since 1.5 - //! New 1.5 series API, though allowed to implement/call in earlier versions. \n - //! Suppresses spurious C++ exceptions on all files not recognized as archives by this instance. - class NOVTABLE archive_v2 : public archive { - FB2K_MAKE_SERVICE_INTERFACE(archive_v2, archive) - public: - - //! Optional method to weed out unsupported formats prior to calling archive_list. \n - //! Use this to suppress calls to archive_list() to avoid spurious exceptions being thrown. - virtual bool is_our_archive( const char * path ) = 0; - }; - - //! \since 1.6 - //! New 1.6 series API, though allowed to implement/call in earlier versions. - class NOVTABLE archive_v3 : public archive_v2 { - FB2K_MAKE_SERVICE_INTERFACE(archive_v3, archive_v2) - public: - //! Determine supported archive file types. \n - //! Returns a list of extensions, colon delimited, e.g.: "zip,rar,7z" - virtual void list_extensions(pfc::string_base & out) = 0; - }; - - //! Root class for archive implementations. Derive from this instead of from archive directly. - class NOVTABLE archive_impl : public archive_v3 { - private: - //do not override these - bool get_canonical_path(const char * path,pfc::string_base & out); - bool is_our_path(const char * path); - bool get_display_path(const char * path,pfc::string_base & out); - void remove(const char * path,abort_callback & p_abort); - void move(const char * src,const char * dst,abort_callback & p_abort); - bool is_remote(const char * src); - bool relative_path_create(const char * file_path,const char * playlist_path,pfc::string_base & out); - bool relative_path_parse(const char * relative_path,const char * playlist_path,pfc::string_base & out); - void open(service_ptr_t & p_out,const char * path, t_open_mode mode,abort_callback & p_abort); - void create_directory(const char * path,abort_callback &); - void list_directory(const char * p_path,directory_callback & p_out,abort_callback & p_abort); - void get_stats(const char * p_path,t_filestats & p_stats,bool & p_is_writeable,abort_callback & p_abort); - void list_extensions(pfc::string_base & out) override { out = get_archive_type(); } - protected: - //override these - virtual const char * get_archive_type()=0;//eg. "zip", must be lowercase - virtual t_filestats get_stats_in_archive(const char * p_archive,const char * p_file,abort_callback & p_abort) = 0; - virtual void open_archive(service_ptr_t & p_out,const char * archive,const char * file, abort_callback & p_abort) = 0;//opens for reading - public: - //override these - virtual void archive_list(const char * path,const service_ptr_t & p_reader,archive_callback & p_out,bool p_want_readers)= 0 ; - virtual bool is_our_archive( const char * path ) = 0; - - static bool g_is_unpack_path(const char * path); - static bool g_parse_unpack_path(const char * path,pfc::string_base & archive,pfc::string_base & file); - static bool g_parse_unpack_path_ex(const char * path,pfc::string_base & archive,pfc::string_base & file, pfc::string_base & type); - static void g_make_unpack_path(pfc::string_base & path,const char * archive,const char * file,const char * type); - void make_unpack_path(pfc::string_base & path,const char * archive,const char * file); - - - }; - - template - class archive_factory_t : public service_factory_single_t {}; -} diff --git a/foobar2000/SDK/audio_chunk.cpp b/foobar2000/SDK/audio_chunk.cpp index 8817ca7..bfe5d04 100644 --- a/foobar2000/SDK/audio_chunk.cpp +++ b/foobar2000/SDK/audio_chunk.cpp @@ -101,7 +101,7 @@ template static void _import32any(const void * in, for(size_t walk = 0; walk < count; ++walk) { uint32_t v = *inPtr++; if (byteSwap) v = pfc::byteswap_t(v); - if (!isSigned) v ^= 0x80000000u; // to signed + if (!isSigned) v ^= 0x80000000; // to signed *out++ = (audio_sample) (int32_t) v * factor; } } @@ -325,14 +325,8 @@ void audio_chunk::set_data_floatingpoint_ex(const void * ptr,t_size size,unsigne set_channels(nch,p_channel_config); } -pfc::string8 audio_chunk::formatChunkSpec() const { - pfc::string8 msg; - msg << get_sample_rate() << " Hz, " << get_channels() << ":0x" << pfc::format_hex(get_channel_config(), 2) << " channels, " << get_sample_count() << " samples"; - return msg; -} - void audio_chunk::debugChunkSpec() const { - FB2K_DebugLog() << "Chunk: " << this->formatChunkSpec(); + FB2K_DebugLog() << "Chunk: " << get_sample_rate() << " Hz, " << get_channels() << ":0x" << pfc::format_hex(get_channel_config(),2) << " channels, " << get_sample_count() << " samples"; } #if PFC_DEBUG @@ -347,7 +341,7 @@ void audio_chunk::assert_valid(const char * ctx) const { bool audio_chunk::is_valid() const { unsigned nch = get_channels(); - if (nch == 0 || nch > 32) return false; + if (nch==0 || nch>256) return false; if (!g_is_valid_sample_rate(get_srate())) return false; t_size samples = get_sample_count(); if (samples==0 || samples >= 0x80000000ul / (sizeof(audio_sample) * nch) ) return false; @@ -596,19 +590,13 @@ bool audio_chunk::spec_t::equals( const spec_t & v1, const spec_t & v2 ) { return v1.sampleRate == v2.sampleRate && v1.chanCount == v2.chanCount && v1.chanMask == v2.chanMask; } -pfc::string8 audio_chunk::spec_t::toString(const char * delim) const { +pfc::string8 audio_chunk::spec_t::toString() const { pfc::string_formatter temp; - if ( sampleRate > 0 ) temp << sampleRate << "Hz"; - if (chanCount > 0) { - if ( temp.length() > 0 ) temp << delim; - temp << chanCount << "ch"; - } - + temp << sampleRate << "Hz " << chanCount << "ch"; if ( chanMask != audio_chunk::channel_config_mono && chanMask != audio_chunk::channel_config_stereo ) { pfc::string8 strMask; audio_chunk::g_formatChannelMaskDesc( chanMask, strMask ); - if ( temp.length() > 0) temp << delim; - temp << strMask; + temp << " " << strMask; } return temp; } @@ -689,14 +677,3 @@ WAVEFORMATEXTENSIBLE audio_chunk::spec_t::toWFXEXWithBPS(uint32_t bps) const { return wfxe; } #endif // _WIN32 - -void audio_chunk::append(const audio_chunk& other) { - if (other.get_spec() != this->get_spec()) { - throw pfc::exception_invalid_params(); - } - - this->grow_data_size(get_used_size() + other.get_used_size()); - audio_sample* p = this->get_data() + get_used_size(); - memcpy(p, other.get_data(), other.get_used_size() * sizeof(audio_sample)); - set_sample_count(get_sample_count() + other.get_sample_count()); -} diff --git a/foobar2000/SDK/audio_chunk.h b/foobar2000/SDK/audio_chunk.h index 22df50c..6a50a4a 100644 --- a/foobar2000/SDK/audio_chunk.h +++ b/foobar2000/SDK/audio_chunk.h @@ -45,9 +45,6 @@ public: channel_config_5point1_side = channel_front_left | channel_front_right | channel_front_center | channel_lfe | channel_side_left | channel_side_right, channel_config_7point1 = channel_config_5point1 | channel_side_left | channel_side_right, - channels_back_left_right = channel_back_left | channel_back_right, - channels_side_left_right = channel_side_left | channel_side_right, - defined_channel_count = 18, }; @@ -139,7 +136,6 @@ public: bool is_valid() const; void debugChunkSpec() const; - pfc::string8 formatChunkSpec() const; #if PFC_DEBUG void assert_valid(const char * ctx) const; #else @@ -162,7 +158,7 @@ public: inline void reset() { set_sample_count(0); set_srate(0); - set_channels(0,0); + set_channels(0); set_data_size(0); } @@ -289,7 +285,7 @@ public: WAVEFORMATEXTENSIBLE toWFXEXWithBPS(uint32_t bps) const; #endif - pfc::string8 toString( const char * delim = " " ) const; + pfc::string8 toString() const; }; static spec_t makeSpec(uint32_t rate, uint32_t channels); static spec_t makeSpec(uint32_t rate, uint32_t channels, uint32_t chanMask); @@ -297,8 +293,6 @@ public: spec_t get_spec() const; void set_spec(const spec_t &); - - void append(const audio_chunk& other); protected: audio_chunk() {} ~audio_chunk() {} @@ -353,17 +347,17 @@ public: audio_sample * get_data() {throw pfc::exception_not_implemented();} const audio_sample * get_data() const {return m_data;} t_size get_data_size() const {return m_samples * m_channels;} - void set_data_size(t_size) {throw pfc::exception_not_implemented();} + void set_data_size(t_size p_new_size) {throw pfc::exception_not_implemented();} unsigned get_srate() const {return m_sample_rate;} - void set_srate(unsigned) {throw pfc::exception_not_implemented();} + void set_srate(unsigned val) {throw pfc::exception_not_implemented();} unsigned get_channels() const {return m_channels;} unsigned get_channel_config() const {return m_channel_config;} - void set_channels(unsigned,unsigned) {throw pfc::exception_not_implemented();} + void set_channels(unsigned p_count,unsigned p_config) {throw pfc::exception_not_implemented();} t_size get_sample_count() const {return m_samples;} - void set_sample_count(t_size) {throw pfc::exception_not_implemented();} + void set_sample_count(t_size val) {throw pfc::exception_not_implemented();} private: t_size m_samples; diff --git a/foobar2000/SDK/audio_chunk_channel_config.cpp b/foobar2000/SDK/audio_chunk_channel_config.cpp index d4a700d..dd445cf 100644 --- a/foobar2000/SDK/audio_chunk_channel_config.cpp +++ b/foobar2000/SDK/audio_chunk_channel_config.cpp @@ -88,27 +88,32 @@ static const unsigned g_audio_channel_config_table[] = audio_chunk::channel_front_left | audio_chunk::channel_front_right | audio_chunk::channel_back_left | audio_chunk::channel_back_right, audio_chunk::channel_front_left | audio_chunk::channel_front_right | audio_chunk::channel_back_left | audio_chunk::channel_back_right | audio_chunk::channel_lfe, audio_chunk::channel_config_5point1, + audio_chunk::channel_front_left | audio_chunk::channel_front_right | audio_chunk::channel_back_left | audio_chunk::channel_back_right | audio_chunk::channel_lfe | audio_chunk::channel_front_center_right | audio_chunk::channel_front_center_left, + audio_chunk::channel_front_left | audio_chunk::channel_front_right | audio_chunk::channel_back_left | audio_chunk::channel_back_right | audio_chunk::channel_front_center | audio_chunk::channel_lfe | audio_chunk::channel_front_center_right | audio_chunk::channel_front_center_left, +}; + +static const unsigned g_audio_channel_config_table_xiph[] = +{ 0, - audio_chunk::channel_config_7point1, - 0, - audio_chunk::channel_config_7point1 | audio_chunk::channel_front_center_right | audio_chunk::channel_front_center_left, + audio_chunk::channel_config_mono, + audio_chunk::channel_config_stereo, + audio_chunk::channel_front_left | audio_chunk::channel_front_right | audio_chunk::channel_front_center, + audio_chunk::channel_front_left | audio_chunk::channel_front_right | audio_chunk::channel_back_left | audio_chunk::channel_back_right, + audio_chunk::channel_front_left | audio_chunk::channel_front_right | audio_chunk::channel_back_left | audio_chunk::channel_back_right | audio_chunk::channel_front_center, + audio_chunk::channel_config_5point1, + audio_chunk::channel_front_left | audio_chunk::channel_front_right | audio_chunk::channel_front_center | audio_chunk::channel_lfe | audio_chunk::channel_back_center | audio_chunk::channel_side_left | audio_chunk::channel_side_right, + audio_chunk::channel_front_left | audio_chunk::channel_front_right | audio_chunk::channel_front_center | audio_chunk::channel_lfe | audio_chunk::channel_back_left | audio_chunk::channel_back_right | audio_chunk::channel_side_left | audio_chunk::channel_side_right, }; unsigned audio_chunk::g_guess_channel_config(unsigned count) { - if (count == 0) return 0; - if (count > 32) throw exception_io_data(); - unsigned ret = 0; - if (count < PFC_TABSIZE(g_audio_channel_config_table)) ret = g_audio_channel_config_table[count]; - if (ret == 0) { - ret = (1 << count) - 1; - } - PFC_ASSERT(g_count_channels(ret) == count); - return ret; + if (count >= PFC_TABSIZE(g_audio_channel_config_table)) return 0; + return g_audio_channel_config_table[count]; } unsigned audio_chunk::g_guess_channel_config_xiph(unsigned count) { - return g_guess_channel_config(count); + if (count == 0 || count >= PFC_TABSIZE(g_audio_channel_config_table_xiph)) throw exception_io_data(); + return g_audio_channel_config_table_xiph[count]; } unsigned audio_chunk::g_channel_index_from_flag(unsigned p_config,unsigned p_flag) { diff --git a/foobar2000/SDK/audio_postprocessor.h b/foobar2000/SDK/audio_postprocessor.h index 6526b64..030a716 100644 --- a/foobar2000/SDK/audio_postprocessor.h +++ b/foobar2000/SDK/audio_postprocessor.h @@ -1,5 +1,3 @@ -#pragma once - //! This class handles conversion of audio data (audio_chunk) to various linear PCM types, with optional dithering. class NOVTABLE audio_postprocessor : public service_base diff --git a/foobar2000/SDK/autoplaylist.h b/foobar2000/SDK/autoplaylist.h index e95c30c..3ddf3eb 100644 --- a/foobar2000/SDK/autoplaylist.h +++ b/foobar2000/SDK/autoplaylist.h @@ -28,10 +28,7 @@ public: template void get_configuration(t_array & p_out) { PFC_STATIC_ASSERT( sizeof(p_out[0]) == 1 ); typedef pfc::array_t t_temp; t_temp temp; - { - stream_writer_buffer_append_ref_t writer(temp); - get_configuration(&writer,fb2k::noAbort); - } + get_configuration(&stream_writer_buffer_append_ref_t(temp),abort_callback_dummy()); p_out = temp; } }; diff --git a/foobar2000/SDK/cfg_var.h b/foobar2000/SDK/cfg_var.h index 7c75b3f..ec5d1b2 100644 --- a/foobar2000/SDK/cfg_var.h +++ b/foobar2000/SDK/cfg_var.h @@ -67,7 +67,7 @@ private: t_inttype m_val; protected: void get_data_raw(stream_writer * p_stream,abort_callback & p_abort) {p_stream->write_lendian_t(m_val,p_abort);} - void set_data_raw(stream_reader * p_stream,t_size,abort_callback & p_abort) { + void set_data_raw(stream_reader * p_stream,t_size p_sizehint,abort_callback & p_abort) { t_inttype temp; p_stream->read_lendian_t(temp,p_abort);//alter member data only on success, this will throw an exception when something isn't right m_val = temp; @@ -88,11 +88,9 @@ public: typedef cfg_int_t cfg_int; typedef cfg_int_t cfg_uint; -//! Since relevant byteswapping functions also understand GUIDs, this can be used to declare a cfg_guid. +//! Since relevant byteswapping functions also understand GUIDs, this can be abused to declare a cfg_guid. typedef cfg_int_t cfg_guid; typedef cfg_int_t cfg_bool; -typedef cfg_int_t cfg_float; -typedef cfg_int_t cfg_double; //! String config variable. Stored in the stream with int32 header containing size in bytes, followed by non-null-terminated UTF-8 data.\n //! Note that cfg_var class and its derivatives may be only instantiated statically (as static objects or members of other static objects), NEVER dynamically (operator new, local variables, members of objects instantiated as such). @@ -120,7 +118,7 @@ protected: get(temp); p_stream->write_object(temp.get_ptr(), temp.length(),p_abort); } - void set_data_raw(stream_reader * p_stream,t_size,abort_callback & p_abort) { + void set_data_raw(stream_reader * p_stream,t_size p_sizehint,abort_callback & p_abort) { pfc::string8_fastalloc temp; p_stream->read_string_raw(temp,p_abort); set(temp); diff --git a/foobar2000/SDK/completion_notify.h b/foobar2000/SDK/completion_notify.h index 9bdc9a0..599e96a 100644 --- a/foobar2000/SDK/completion_notify.h +++ b/foobar2000/SDK/completion_notify.h @@ -1,5 +1,3 @@ -#pragma once - #include //! Generic service for receiving notifications about async operation completion. Used by various other services. @@ -22,7 +20,7 @@ public: //! Implementation helper. class completion_notify_dummy : public completion_notify { public: - void on_completion(unsigned) {} + void on_completion(unsigned p_code) {} }; //! Implementation helper. @@ -70,7 +68,7 @@ public: ~completion_notify_receiver(); void orphan_all_tasks(); - virtual void on_task_completion(unsigned p_id,unsigned p_status) {(void)p_id;(void)p_status;} + virtual void on_task_completion(unsigned p_id,unsigned p_status) {} private: static void orphanfunc(unsigned,completion_notify_orphanable_nnptr p_item) {p_item->orphan();} pfc::map_t m_tasks; diff --git a/foobar2000/SDK/componentversion.cpp b/foobar2000/SDK/componentversion.cpp index a5f6536..5a208f1 100644 --- a/foobar2000/SDK/componentversion.cpp +++ b/foobar2000/SDK/componentversion.cpp @@ -14,7 +14,8 @@ bool component_installation_validator::have_other_file(const char * fn) { path << fn; try { try { - bool v = filesystem::g_exists(path, fb2k::noAbort); + abort_callback_dummy aborter; + bool v = filesystem::g_exists(path, aborter); PFC_ASSERT( v ); return v; } catch(std::exception const & e) { diff --git a/foobar2000/SDK/config_object.cpp b/foobar2000/SDK/config_object.cpp index b6f619d..eacd65a 100644 --- a/foobar2000/SDK/config_object.cpp +++ b/foobar2000/SDK/config_object.cpp @@ -146,20 +146,23 @@ namespace { t_size config_object::get_data_raw(void * p_out,t_size p_bytes) { t_size ret = 0; stream_writer_fixedbuffer stream(p_out,p_bytes,ret); - get_data(&stream,fb2k::noAbort); + abort_callback_dummy aborter; + get_data(&stream,aborter); return ret; } t_size config_object::get_data_raw_length() { t_size ret = 0; stream_writer_get_length stream(ret); - get_data(&stream,fb2k::noAbort); + abort_callback_dummy aborter; + get_data(&stream,aborter); return ret; } void config_object::set_data_raw(const void * p_data,t_size p_bytes, bool p_notify) { stream_reader_memblock_ref stream(p_data,p_bytes); - set_data(&stream,fb2k::noAbort,p_notify); + abort_callback_dummy aborter; + set_data(&stream,aborter,p_notify); } void config_object::set_data_string(const char * p_data,t_size p_length) { @@ -168,7 +171,8 @@ void config_object::set_data_string(const char * p_data,t_size p_length) { void config_object::get_data_string(pfc::string_base & p_out) { stream_writer_string stream(p_out); - get_data(&stream,fb2k::noAbort); + abort_callback_dummy aborter; + get_data(&stream,aborter); } diff --git a/foobar2000/SDK/contextmenu.h b/foobar2000/SDK/contextmenu.h index e593b35..f6b6ee2 100644 --- a/foobar2000/SDK/contextmenu.h +++ b/foobar2000/SDK/contextmenu.h @@ -1,5 +1,3 @@ -#pragma once - //! Reserved for future use. typedef void * t_glyph; @@ -123,7 +121,6 @@ public: //! Return DEFAULT_ON to show this item in the context menu by default - useful for most cases. \n //! Return DEFAULT_OFF to hide this item in the context menu by default - useful for rarely used utility commands. \n //! Return FORCE_OFF to hide this item by default and prevent the user from making it visible (very rarely used). \n - //! foobar2000 v1.6 and newer: FORCE_OFF items are meant for being shown only in the keyboard shortcut list, not anywhere else. \n //! Values returned by this method should be constant for this context menu item and not change later. Do not use this to conditionally hide the item - return false from get_display_data() instead. virtual t_enabled_state get_enabled_state(unsigned p_index) = 0; //! Executes the menu item command without going thru the instantiate_item path. For items with dynamically-generated sub-items, p_node is identifies of the sub-item command to execute. diff --git a/foobar2000/SDK/core_api.h b/foobar2000/SDK/core_api.h index 36ca756..b0c4fb3 100644 --- a/foobar2000/SDK/core_api.h +++ b/foobar2000/SDK/core_api.h @@ -27,7 +27,7 @@ namespace core_api { const char * get_profile_path(); //! Returns a path to in fb2k profile folder. - inline pfc::string8 pathInProfile(const char * fileName) { pfc::string8 p( core_api::get_profile_path() ); p.add_filename( fileName ); return p; } + inline pfc::string8 pathInProfile(const char * fileName) { pfc::string8 p( core_api::get_profile_path() ); p.add_filename( fileName ); return std::move(p); } //! Returns whether foobar2000 has been installed in "portable" mode. bool is_portable_mode_enabled(); diff --git a/foobar2000/SDK/dsp.cpp b/foobar2000/SDK/dsp.cpp index b1604c8..2ffe37f 100644 --- a/foobar2000/SDK/dsp.cpp +++ b/foobar2000/SDK/dsp.cpp @@ -85,9 +85,6 @@ void dsp_chunk_list::remove_bad_chunks() audio_chunk * chunk = get_item(idx); if (!chunk->is_valid()) { -#if PFC_DEBUG - FB2K_console_formatter() << "Removing bad chunk: " << chunk->formatChunkSpec(); -#endif chunk->reset(); remove_by_idx(idx); blah = true; @@ -285,42 +282,6 @@ dsp_chain_config_impl::~dsp_chain_config_impl() m_data.delete_all(); } -pfc::string8 dsp_preset::get_owner_name() const { - pfc::string8 ret; - dsp_entry::ptr obj; - if (dsp_entry::g_get_interface(obj, this->get_owner())) { - obj->get_name(ret); - } - return ret; -} - -pfc::string8 dsp_preset::get_owner_name_debug() const { - pfc::string8 ret; - dsp_entry::ptr obj; - if (dsp_entry::g_get_interface(obj, this->get_owner())) { - obj->get_name(ret); - } else { - ret = "[unknown]"; - } - return ret; -} - -pfc::string8 dsp_preset::debug() const { - pfc::string8 ret; - ret << this->get_owner_name_debug() << " :: " << pfc::print_guid(this->get_owner()) << " :: " << pfc::format_hexdump(this->get_data(), this->get_data_size()); - return ret; -} - -pfc::string8 dsp_chain_config::debug() const { - const size_t count = get_count(); - pfc::string8 ret; - ret << "dsp_chain_config: " << count << " items"; - for (size_t walk = 0; walk < count; ++walk) { - ret << "\n" << get_item(walk).debug(); - } - return ret; -} - void dsp_preset::contents_to_stream(stream_writer * p_stream,abort_callback & p_abort) const { t_uint32 size = pfc::downcast_guarded(get_data_size()); p_stream->write_lendian_t(get_owner(),p_abort); @@ -470,24 +431,6 @@ bool dsp_chain_config::equals(dsp_chain_config const & v1, dsp_chain_config cons } return true; } -bool dsp_chain_config::equals_debug(dsp_chain_config const& v1, dsp_chain_config const& v2) { - FB2K_DebugLog() << "Comparing DSP chains"; - const t_size count = v1.get_count(); - if (count != v2.get_count()) { - FB2K_DebugLog() << "Count mismatch, " << count << " vs " << v2.get_count(); - return false; - } - for (t_size walk = 0; walk < count; ++walk) { - if (v1.get_item(walk) != v2.get_item(walk)) { - FB2K_DebugLog() << "Item " << (walk+1) << " mismatch"; - FB2K_DebugLog() << "Item 1: " << v1.get_item(walk).debug(); - FB2K_DebugLog() << "Item 2: " << v2.get_item(walk).debug(); - return false; - } - } - FB2K_DebugLog() << "DSP chains are identical"; - return true; -} void dsp_chain_config::get_name_list(pfc::string_base & p_out) const { const t_size count = get_count(); @@ -537,20 +480,4 @@ bool dsp_entry_v2::show_config_popup(dsp_preset & p_data,HWND p_parent) { return true; } -void resampler_manager::make_chain_(dsp_chain_config& outChain, unsigned rateFrom, unsigned rateTo, float qualityScale) { - resampler_manager_v2::ptr v2; - if (v2 &= this) { - v2->make_chain(outChain, rateFrom, rateTo, qualityScale); - } else { - outChain.remove_all(); - auto obj = this->get_resampler(rateFrom, rateTo); - if (obj.is_valid()) { - dsp_preset_impl p; - if (obj->create_preset(p, rateTo, qualityScale)) { - outChain.add_item(p); - } - } - } -} - #endif // FOOBAR2000_HAVE_DSP diff --git a/foobar2000/SDK/dsp.h b/foobar2000/SDK/dsp.h index 67b29e3..447f9da 100644 --- a/foobar2000/SDK/dsp.h +++ b/foobar2000/SDK/dsp.h @@ -76,7 +76,8 @@ public: virtual void run_v2(dsp_chunk_list * p_chunk_list,const metadb_handle_ptr & p_cur_file,int p_flags,abort_callback & p_abort) = 0; private: void run(dsp_chunk_list * p_chunk_list,const metadb_handle_ptr & p_cur_file,int p_flags) { - run_v2(p_chunk_list,p_cur_file,p_flags,fb2k::noAbort); + abort_callback_dummy dummy; + run_v2(p_chunk_list,p_cur_file,p_flags,dummy); } FB2K_MAKE_SERVICE_INTERFACE(dsp_v2,dsp); @@ -205,10 +206,6 @@ public: bool operator!=(const dsp_preset & p_other) const { return !(*this == p_other); } - - pfc::string8 get_owner_name() const; - pfc::string8 get_owner_name_debug() const; - pfc::string8 debug() const; protected: dsp_preset() {} ~dsp_preset() {} @@ -451,9 +448,6 @@ public: void get_name_list(pfc::string_base & p_out) const; static bool equals(dsp_chain_config const & v1, dsp_chain_config const & v2); - static bool equals_debug(dsp_chain_config const& v1, dsp_chain_config const& v2); - - pfc::string8 debug() const; bool operator==(const dsp_chain_config & other) const {return equals(*this, other);} bool operator!=(const dsp_chain_config & other) const {return !equals(*this, other);} @@ -525,7 +519,7 @@ private: //! Helper. class dsp_preset_parser : public stream_reader_formatter<> { public: - dsp_preset_parser(const dsp_preset & in) : m_data(in), _m_stream(in.get_data(),in.get_data_size()), stream_reader_formatter(_m_stream,fb2k::noAbort) {} + dsp_preset_parser(const dsp_preset & in) : m_data(in), _m_stream(in.get_data(),in.get_data_size()), stream_reader_formatter(_m_stream,_m_abort) {} void reset() {_m_stream.reset();} t_size get_remaining() const {return _m_stream.get_remaining();} @@ -537,13 +531,14 @@ public: GUID get_owner() const {return m_data.get_owner();} private: const dsp_preset & m_data; + abort_callback_dummy _m_abort; stream_reader_memblock_ref _m_stream; }; //! Helper. class dsp_preset_builder : public stream_writer_formatter<> { public: - dsp_preset_builder() : stream_writer_formatter(_m_stream,fb2k::noAbort) {} + dsp_preset_builder() : stream_writer_formatter(_m_stream,_m_abort) {} void finish(const GUID & id, dsp_preset & out) { out.set_owner(id); out.set_data(_m_stream.m_buffer.get_ptr(), _m_stream.m_buffer.get_size()); @@ -552,6 +547,7 @@ public: _m_stream.m_buffer.set_size(0); } private: + abort_callback_dummy _m_abort; stream_writer_buffer_simple _m_stream; }; diff --git a/foobar2000/SDK/dsp_manager.cpp b/foobar2000/SDK/dsp_manager.cpp index 68b9267..aa8170d 100644 --- a/foobar2000/SDK/dsp_manager.cpp +++ b/foobar2000/SDK/dsp_manager.cpp @@ -64,7 +64,7 @@ double dsp_manager::run(dsp_chunk_list * p_list,const metadb_handle_ptr & p_cur_ } - // Recycle existing DSPs in a special case when user has apparently only altered settings of one of DSPs. + //HACK: recycle existing DSPs in a special case when user has apparently only altered settings of one of DSPs. if (newchain.get_count() == m_chain.get_count()) { t_size data_mismatch_count = 0; t_size owner_mismatch_count = 0; diff --git a/foobar2000/SDK/dsp_manager.h b/foobar2000/SDK/dsp_manager.h index 3470bad..2d38cae 100644 --- a/foobar2000/SDK/dsp_manager.h +++ b/foobar2000/SDK/dsp_manager.h @@ -5,7 +5,7 @@ //! Helper class for running audio data through a DSP chain. class dsp_manager { public: - dsp_manager() {} + dsp_manager() : m_config_changed(false) {} //! Alters the DSP chain configuration. Should be called before the first run() to set the configuration but can be also called anytime later between run() calls. void set_config( const dsp_chain_config & p_data ); @@ -32,7 +32,7 @@ private: t_dsp_chain m_chain; dsp_chain_config_impl m_config; - bool m_config_changed = false; + bool m_config_changed; void dsp_run(t_dsp_chain::const_iterator p_iter,dsp_chunk_list * list,const metadb_handle_ptr & cur_file,unsigned flags,double & latency,abort_callback&); diff --git a/foobar2000/SDK/event_logger.h b/foobar2000/SDK/event_logger.h index 6436c9b..f9c7d56 100644 --- a/foobar2000/SDK/event_logger.h +++ b/foobar2000/SDK/event_logger.h @@ -1,12 +1,3 @@ -#pragma once - -#if defined(FOOBAR2000_DESKTOP) || PFC_DEBUG -// RATIONALE -// Mobile target doesn't really care about event logging, logger interface exists there only for source compat -// We can use macros to suppress all PFC_string_formatter bloat for targets that do not care about any of this -#define FB2K_HAVE_EVENT_LOGGER -#endif - class NOVTABLE event_logger : public service_base { FB2K_MAKE_SERVICE_INTERFACE(event_logger, service_base); public: @@ -35,16 +26,8 @@ public: static event_logger_recorder::ptr create(); }; -#ifdef FB2K_HAVE_EVENT_LOGGER - #define FB2K_LOG_STATUS(X,Y) (X)->log_status(Y) #define FB2K_LOG_WARNING(X,Y) (X)->log_warning(Y) #define FB2K_LOG_ERROR(X,Y) (X)->log_error(Y) -#else - -#define FB2K_LOG_STATUS(X,Y) ((void)0) -#define FB2K_LOG_WARNING(X,Y) ((void)0) -#define FB2K_LOG_ERROR(X,Y) ((void)0) - -#endif +#define FB2K_HAVE_EVENT_LOGGER \ No newline at end of file diff --git a/foobar2000/SDK/exceptions.h b/foobar2000/SDK/exceptions.h index bf1e23e..95f4b34 100644 --- a/foobar2000/SDK/exceptions.h +++ b/foobar2000/SDK/exceptions.h @@ -11,3 +11,5 @@ PFC_DECLARE_EXCEPTION(exception_osfailure, exception_messagebox, "Internal error PFC_DECLARE_EXCEPTION(exception_out_of_resources, exception_messagebox, "Not enough system resources available."); PFC_DECLARE_EXCEPTION(exception_configdamaged, exception_messagebox, "Internal error - configuration files are unreadable."); + +PFC_DECLARE_EXCEPTION(exception_profileaccess, exception_messagebox, "Internal error - cannot access configuration folder."); diff --git a/foobar2000/SDK/file_cached_impl.cpp b/foobar2000/SDK/file_cached_impl.cpp index 55f0b97..6fa22de 100644 --- a/foobar2000/SDK/file_cached_impl.cpp +++ b/foobar2000/SDK/file_cached_impl.cpp @@ -3,7 +3,7 @@ namespace { #define FILE_CACHED_DEBUG_LOG 0 -class file_cached_impl_v2 : public service_multi_inherit< file_cached, file_lowLevelIO > { +class file_cached_impl_v2 : public file_cached { public: enum {minBlockSize = 4096}; enum {maxSkipSize = 128*1024}; @@ -20,15 +20,6 @@ public: m_can_seek = m_base->can_seek(); _reinit(p_abort); } - size_t lowLevelIO(const GUID & guid, size_t arg1, void * arg2, size_t arg2size, abort_callback & abort) override { - abort.check(); - file_lowLevelIO::ptr ll; - if ( ll &= m_base ) { - flush_buffer(); - return ll->lowLevelIO(guid, arg1, arg2, arg2size, abort ); - } - return 0; - } private: void _reinit(abort_callback & p_abort) { m_position = 0; @@ -222,7 +213,7 @@ private: size_t m_readSize; }; -class file_cached_impl : public service_multi_inherit< file_cached, file_lowLevelIO > { +class file_cached_impl : public file_cached { public: file_cached_impl(t_size blocksize) { m_buffer.set_size(blocksize); @@ -249,15 +240,7 @@ private: flush_buffer(); } public: - size_t lowLevelIO(const GUID & guid, size_t arg1, void * arg2, size_t arg2size, abort_callback & abort) override { - abort.check(); - file_lowLevelIO::ptr ll; - if ( ll &= m_base ) { - flush_buffer(); - return ll->lowLevelIO(guid, arg1, arg2, arg2size, abort); - } - return 0; - } + t_size read(void * p_buffer,t_size p_bytes,abort_callback & p_abort) { t_uint8 * outptr = (t_uint8*)p_buffer; t_size done = 0; diff --git a/foobar2000/SDK/file_info.cpp b/foobar2000/SDK/file_info.cpp index 4f43f52..149d2f7 100644 --- a/foobar2000/SDK/file_info.cpp +++ b/foobar2000/SDK/file_info.cpp @@ -5,9 +5,6 @@ #define _atoi64 atoll #endif -const float replaygain_info::peak_invalid = -1; -const float replaygain_info::gain_invalid = -1000; - t_size file_info::meta_find_ex(const char * p_name,t_size p_name_length) const { t_size n, m = meta_get_count(); @@ -414,19 +411,6 @@ void file_info::info_calculate_bitrate(t_filesize p_filesize,double p_length) if ( b > 0 ) info_set_bitrate(b); } -bool file_info::is_encoding_overkill() const { - auto bs = info_get_int("bitspersample"); - auto extra = info_get("bitspersample_extra"); - if ( bs <= 24 ) return false; // fixedpoint up to 24bit, OK - if ( bs > 32 ) return true; // fixed or float beyond 32bit, overkill - - if ( extra != nullptr ) { - if (strcmp(extra, "fixed-point") == 0) return true; // int32, overkill - } - - return false; -} - bool file_info::is_encoding_lossy() const { const char * encoding = info_get("encoding"); if (encoding != NULL) { @@ -766,4 +750,4 @@ audio_chunk::spec_t file_info::audio_chunk_spec() const rv.chanMask = audio_chunk::g_guess_channel_config( rv.chanCount ); } return rv; -} +} \ No newline at end of file diff --git a/foobar2000/SDK/file_info.h b/foobar2000/SDK/file_info.h index 41a4b96..907ae79 100644 --- a/foobar2000/SDK/file_info.h +++ b/foobar2000/SDK/file_info.h @@ -7,7 +7,7 @@ struct replaygain_info enum {text_buffer_size = 16 }; typedef char t_text_buffer[text_buffer_size]; - static const float peak_invalid, gain_invalid; + enum { peak_invalid = -1, gain_invalid = -1000 }; static bool g_format_gain(float p_value,char p_buffer[text_buffer_size]); static bool g_format_peak(float p_value,char p_buffer[text_buffer_size]); @@ -18,15 +18,14 @@ struct replaygain_info inline bool format_album_peak(char p_buffer[text_buffer_size]) const {return g_format_peak(m_album_peak,p_buffer);} inline bool format_track_peak(char p_buffer[text_buffer_size]) const {return g_format_peak(m_track_peak,p_buffer);} - static float g_parse_gain_text(const char * p_text, t_size p_text_len = SIZE_MAX); - void set_album_gain_text(const char * p_text,t_size p_text_len = SIZE_MAX); - void set_track_gain_text(const char * p_text,t_size p_text_len = SIZE_MAX); - void set_album_peak_text(const char * p_text,t_size p_text_len = SIZE_MAX); - void set_track_peak_text(const char * p_text,t_size p_text_len = SIZE_MAX); + void set_album_gain_text(const char * p_text,t_size p_text_len = pfc_infinite); + void set_track_gain_text(const char * p_text,t_size p_text_len = pfc_infinite); + void set_album_peak_text(const char * p_text,t_size p_text_len = pfc_infinite); + void set_track_peak_text(const char * p_text,t_size p_text_len = pfc_infinite); - static bool g_is_meta_replaygain(const char * p_name,t_size p_name_len = SIZE_MAX); + static bool g_is_meta_replaygain(const char * p_name,t_size p_name_len = pfc_infinite); bool set_from_meta_ex(const char * p_name,t_size p_name_len,const char * p_value,t_size p_value_len); - inline bool set_from_meta(const char * p_name,const char * p_value) {return set_from_meta_ex(p_name,SIZE_MAX,p_value,SIZE_MAX);} + inline bool set_from_meta(const char * p_name,const char * p_value) {return set_from_meta_ex(p_name,pfc_infinite,p_value,pfc_infinite);} inline bool is_album_gain_present() const {return m_album_gain != gain_invalid;} inline bool is_track_gain_present() const {return m_track_gain != gain_invalid;} @@ -158,29 +157,29 @@ public: bool info_remove_ex(const char * p_name,t_size p_name_length); const char * info_get_ex(const char * p_name,t_size p_name_length) const; - inline t_size meta_find(const char * p_name) const {return meta_find_ex(p_name,SIZE_MAX);} - inline bool meta_exists(const char * p_name) const {return meta_exists_ex(p_name,SIZE_MAX);} - inline void meta_remove_field(const char * p_name) {meta_remove_field_ex(p_name,SIZE_MAX);} - inline t_size meta_set(const char * p_name,const char * p_value) {return meta_set_ex(p_name,SIZE_MAX,p_value,SIZE_MAX);} - inline void meta_insert_value(t_size p_index,t_size p_value_index,const char * p_value) {meta_insert_value_ex(p_index,p_value_index,p_value,SIZE_MAX);} - inline void meta_add_value(t_size p_index,const char * p_value) {meta_add_value_ex(p_index,p_value,SIZE_MAX);} - inline const char* meta_get(const char * p_name,t_size p_index) const {return meta_get_ex(p_name,SIZE_MAX,p_index);} - inline t_size meta_get_count_by_name(const char * p_name) const {return meta_get_count_by_name_ex(p_name,SIZE_MAX);} - inline t_size meta_add(const char * p_name,const char * p_value) {return meta_add_ex(p_name,SIZE_MAX,p_value,SIZE_MAX);} - inline void meta_modify_value(t_size p_index,t_size p_value_index,const char * p_value) {meta_modify_value_ex(p_index,p_value_index,p_value,SIZE_MAX);} + inline t_size meta_find(const char * p_name) const {return meta_find_ex(p_name,pfc_infinite);} + inline bool meta_exists(const char * p_name) const {return meta_exists_ex(p_name,pfc_infinite);} + inline void meta_remove_field(const char * p_name) {meta_remove_field_ex(p_name,pfc_infinite);} + inline t_size meta_set(const char * p_name,const char * p_value) {return meta_set_ex(p_name,pfc_infinite,p_value,pfc_infinite);} + inline void meta_insert_value(t_size p_index,t_size p_value_index,const char * p_value) {meta_insert_value_ex(p_index,p_value_index,p_value,pfc_infinite);} + inline void meta_add_value(t_size p_index,const char * p_value) {meta_add_value_ex(p_index,p_value,pfc_infinite);} + inline const char* meta_get(const char * p_name,t_size p_index) const {return meta_get_ex(p_name,pfc_infinite,p_index);} + inline t_size meta_get_count_by_name(const char * p_name) const {return meta_get_count_by_name_ex(p_name,pfc_infinite);} + inline t_size meta_add(const char * p_name,const char * p_value) {return meta_add_ex(p_name,pfc_infinite,p_value,pfc_infinite);} + inline void meta_modify_value(t_size p_index,t_size p_value_index,const char * p_value) {meta_modify_value_ex(p_index,p_value_index,p_value,pfc_infinite);} - inline t_size info_set(const char * p_name,const char * p_value) {return info_set_ex(p_name,SIZE_MAX,p_value,SIZE_MAX);} - inline t_size info_find(const char * p_name) const {return info_find_ex(p_name,SIZE_MAX);} - inline bool info_exists(const char * p_name) const {return info_exists_ex(p_name,SIZE_MAX);} - inline bool info_remove(const char * p_name) {return info_remove_ex(p_name,SIZE_MAX);} - inline const char * info_get(const char * p_name) const {return info_get_ex(p_name,SIZE_MAX);} + inline t_size info_set(const char * p_name,const char * p_value) {return info_set_ex(p_name,pfc_infinite,p_value,pfc_infinite);} + inline t_size info_find(const char * p_name) const {return info_find_ex(p_name,pfc_infinite);} + inline bool info_exists(const char * p_name) const {return info_exists_ex(p_name,pfc_infinite);} + inline bool info_remove(const char * p_name) {return info_remove_ex(p_name,pfc_infinite);} + inline const char * info_get(const char * p_name) const {return info_get_ex(p_name,pfc_infinite);} bool info_set_replaygain_ex(const char * p_name,t_size p_name_len,const char * p_value,t_size p_value_len); - inline bool info_set_replaygain(const char * p_name,const char * p_value) {return info_set_replaygain_ex(p_name,SIZE_MAX,p_value,SIZE_MAX);} + inline bool info_set_replaygain(const char * p_name,const char * p_value) {return info_set_replaygain_ex(p_name,pfc_infinite,p_value,pfc_infinite);} void info_set_replaygain_auto_ex(const char * p_name,t_size p_name_len,const char * p_value,t_size p_value_len); - inline void info_set_replaygain_auto(const char * p_name,const char * p_value) {info_set_replaygain_auto_ex(p_name,SIZE_MAX,p_value,SIZE_MAX);} + inline void info_set_replaygain_auto(const char * p_name,const char * p_value) {info_set_replaygain_auto_ex(p_name,pfc_infinite,p_value,pfc_infinite);} @@ -188,12 +187,12 @@ public: void copy_info_single(const file_info & p_source,t_size p_index); void copy_meta_single_by_name_ex(const file_info & p_source,const char * p_name,t_size p_name_length); void copy_info_single_by_name_ex(const file_info & p_source,const char * p_name,t_size p_name_length); - inline void copy_meta_single_by_name(const file_info & p_source,const char * p_name) {copy_meta_single_by_name_ex(p_source,p_name,SIZE_MAX);} - inline void copy_info_single_by_name(const file_info & p_source,const char * p_name) {copy_info_single_by_name_ex(p_source,p_name,SIZE_MAX);} + inline void copy_meta_single_by_name(const file_info & p_source,const char * p_name) {copy_meta_single_by_name_ex(p_source,p_name,pfc_infinite);} + inline void copy_info_single_by_name(const file_info & p_source,const char * p_name) {copy_info_single_by_name_ex(p_source,p_name,pfc_infinite);} void reset(); void reset_replaygain(); void copy_meta_single_rename_ex(const file_info & p_source,t_size p_index,const char * p_new_name,t_size p_new_name_length); - inline void copy_meta_single_rename(const file_info & p_source,t_size p_index,const char * p_new_name) {copy_meta_single_rename_ex(p_source,p_index,p_new_name,SIZE_MAX);} + inline void copy_meta_single_rename(const file_info & p_source,t_size p_index,const char * p_new_name) {copy_meta_single_rename_ex(p_source,p_index,p_new_name,pfc_infinite);} void overwrite_info(const file_info & p_source); void overwrite_meta(const file_info & p_source); @@ -216,7 +215,6 @@ public: uint32_t info_get_wfx_chanMask() const; bool is_encoding_lossy() const; - bool is_encoding_overkill() const; void info_calculate_bitrate(t_filesize p_filesize,double p_length); @@ -243,16 +241,16 @@ public: //! Unsafe - does not check whether the field already exists and will result in duplicates if it does - call only when appropriate checks have been applied externally. t_size __meta_add_unsafe_ex(const char * p_name,t_size p_name_length,const char * p_value,t_size p_value_length) {return meta_set_nocheck_ex(p_name,p_name_length,p_value,p_value_length);} //! Unsafe - does not check whether the field already exists and will result in duplicates if it does - call only when appropriate checks have been applied externally. - t_size __meta_add_unsafe(const char * p_name,const char * p_value) {return meta_set_nocheck_ex(p_name,SIZE_MAX,p_value,SIZE_MAX);} + t_size __meta_add_unsafe(const char * p_name,const char * p_value) {return meta_set_nocheck_ex(p_name,pfc_infinite,p_value,pfc_infinite);} //! Unsafe - does not check whether the field already exists and will result in duplicates if it does - call only when appropriate checks have been applied externally. t_size __info_add_unsafe_ex(const char * p_name,t_size p_name_length,const char * p_value,t_size p_value_length) {return info_set_nocheck_ex(p_name,p_name_length,p_value,p_value_length);} //! Unsafe - does not check whether the field already exists and will result in duplicates if it does - call only when appropriate checks have been applied externally. - t_size __info_add_unsafe(const char * p_name,const char * p_value) {return info_set_nocheck_ex(p_name,SIZE_MAX,p_value,SIZE_MAX);} + t_size __info_add_unsafe(const char * p_name,const char * p_value) {return info_set_nocheck_ex(p_name,pfc_infinite,p_value,pfc_infinite);} void _copy_meta_single_nocheck(const file_info & p_source,t_size p_index) {copy_meta_single_nocheck(p_source, p_index);} - static bool g_is_valid_field_name(const char * p_name,t_size p_length = SIZE_MAX); + static bool g_is_valid_field_name(const char * p_name,t_size p_length = pfc_infinite); //typedef pfc::comparator_stricmp_ascii field_name_comparator; typedef pfc::string::comparatorCaseInsensitiveASCII field_name_comparator; @@ -277,11 +275,11 @@ protected: void copy_info_single_nocheck(const file_info & p_source,t_size p_index); void copy_meta_single_by_name_nocheck_ex(const file_info & p_source,const char * p_name,t_size p_name_length); void copy_info_single_by_name_nocheck_ex(const file_info & p_source,const char * p_name,t_size p_name_length); - inline void copy_meta_single_by_name_nocheck(const file_info & p_source,const char * p_name) {copy_meta_single_by_name_nocheck_ex(p_source,p_name,SIZE_MAX);} - inline void copy_info_single_by_name_nocheck(const file_info & p_source,const char * p_name) {copy_info_single_by_name_nocheck_ex(p_source,p_name,SIZE_MAX);} + inline void copy_meta_single_by_name_nocheck(const file_info & p_source,const char * p_name) {copy_meta_single_by_name_nocheck_ex(p_source,p_name,pfc_infinite);} + inline void copy_info_single_by_name_nocheck(const file_info & p_source,const char * p_name) {copy_info_single_by_name_nocheck_ex(p_source,p_name,pfc_infinite);} virtual t_size meta_set_nocheck_ex(const char * p_name,t_size p_name_length,const char * p_value,t_size p_value_length) = 0; virtual t_size info_set_nocheck_ex(const char * p_name,t_size p_name_length,const char * p_value,t_size p_value_length) = 0; - inline t_size meta_set_nocheck(const char * p_name,const char * p_value) {return meta_set_nocheck_ex(p_name,SIZE_MAX,p_value,SIZE_MAX);} - inline t_size info_set_nocheck(const char * p_name,const char * p_value) {return info_set_nocheck_ex(p_name,SIZE_MAX,p_value,SIZE_MAX);} + inline t_size meta_set_nocheck(const char * p_name,const char * p_value) {return meta_set_nocheck_ex(p_name,pfc_infinite,p_value,pfc_infinite);} + inline t_size info_set_nocheck(const char * p_name,const char * p_value) {return info_set_nocheck_ex(p_name,pfc_infinite,p_value,pfc_infinite);} }; diff --git a/foobar2000/SDK/file_info_filter.h b/foobar2000/SDK/file_info_filter.h deleted file mode 100644 index 92bef39..0000000 --- a/foobar2000/SDK/file_info_filter.h +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once -#include "tracks.h" - -//! Implementing this class gives you direct control over which part of file_info gets altered during a tag update uperation. To be used with metadb_io_v2::update_info_async(). -class NOVTABLE file_info_filter : public service_base { - FB2K_MAKE_SERVICE_INTERFACE(file_info_filter, service_base); -public: - //! Alters specified file_info entry; called as a part of tag update process. Specified file_info has been read from a file, and will be written back.\n - //! WARNING: This will be typically called from another thread than main app thread (precisely, from thread created by tag updater). You should copy all relevant data to members of your file_info_filter instance in constructor and reference only member data in apply_filter() implementation. - //! @returns True when you have altered file_info and changes need to be written back to the file; false if no changes have been made. - virtual bool apply_filter(trackRef p_location, t_filestats p_stats, file_info & p_info) = 0; - - typedef std::function< bool (trackRef, t_filestats, file_info & ) > func_t; - static file_info_filter::ptr create( func_t f ); -}; - -//! Extended file_info_filter allowing the caller to do their own manipulation of the file before and after the metadata update takes place. \n -//! Respected by foobar2000 v1.5 and up; if metadb_io_v4 is supported, then file_info_filter_v2 is understood. -class NOVTABLE file_info_filter_v2 : public file_info_filter { - FB2K_MAKE_SERVICE_INTERFACE(file_info_filter_v2, file_info_filter); -public: - - enum filterStatus_t { - filterNoUpdate = 0, - filterProceed, - filterAlreadyUpdated - }; - //! Called after just before rewriting metadata. The file is not yet opened for writing, but a file_lock has already been granted (so don't call it on your own). \n - //! You can use this method to perform album art updates (via album_art_editor API) alongside metadata updates. \n - //! Return value can be used to stop fb2k from proceeding with metadata update on this file. \n - //! If your own operations on this file fail, just pass the exceptions to the caller and they will be reported just as other tag update errors. - //! @param fileIfAlreadyOpened Reference to an already opened file object, if already opened by the caller. May be null. - virtual filterStatus_t before_tag_update(const char * location, file::ptr fileIfAlreadyOpened, abort_callback & aborter) = 0; - - //! Called after metadata has been updated. \n - //! If you wish to alter the file on your own, use before_tag_update() for this instead. \n - //! If your own operations on this file fail, just pass the exceptions to the caller and they will be reported just as other tag update errors. \n - //! The passed reader object can be used to read the properties of the updated file back. In most cases it will be the writer that was used to update the tags. Do not call tag writing methods on it from this function. - virtual void after_tag_update(const char * location, service_ptr_t reader, abort_callback & aborter) = 0; - - virtual void after_all_tag_updates(abort_callback & aborter) = 0; - - //! Allows you to do your own error logging. - //! @returns True if the error has been noted by your code and does not need to be shown to the user. - virtual bool filter_error(const char * location, const char * msg) = 0; -}; diff --git a/foobar2000/SDK/file_info_filter_impl.h b/foobar2000/SDK/file_info_filter_impl.h deleted file mode 100644 index 6af30f6..0000000 --- a/foobar2000/SDK/file_info_filter_impl.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -//! Generic implementation of file_info_filter_impl. -class file_info_filter_impl : public file_info_filter { -public: - file_info_filter_impl(const pfc::list_base_const_t & p_list, const pfc::list_base_const_t & p_new_info) { - FB2K_DYNAMIC_ASSERT(p_list.get_count() == p_new_info.get_count()); - pfc::array_t order; - order.set_size(p_list.get_count()); - order_helper::g_fill(order.get_ptr(), order.get_size()); - p_list.sort_get_permutation_t(pfc::compare_t, order.get_ptr()); - m_handles.set_count(order.get_size()); - m_infos.set_size(order.get_size()); - for (t_size n = 0; n < order.get_size(); n++) { - m_handles[n] = p_list[order[n]]; - m_infos[n] = *p_new_info[order[n]]; - } - } - - bool apply_filter(metadb_handle_ptr p_location, t_filestats p_stats, file_info & p_info) { - t_size index; - if (m_handles.bsearch_t(pfc::compare_t, p_location, index)) { - p_info = m_infos[index]; - return true; - } - else { - return false; - } - } -private: - metadb_handle_list m_handles; - pfc::array_t m_infos; -}; diff --git a/foobar2000/SDK/file_lock_manager.h b/foobar2000/SDK/file_lock_manager.h index 3bda3f2..810f3a9 100644 --- a/foobar2000/SDK/file_lock_manager.h +++ b/foobar2000/SDK/file_lock_manager.h @@ -30,23 +30,6 @@ public: typedef service_ptr_t file_lock_ptr; -//! \since 1.5 -//! Modern version of file locking. \n -//! A read lock can be interrupted by a write lock request, from the thread that requested writing. \n -class NOVTABLE file_lock_interrupt : public service_base { - FB2K_MAKE_SERVICE_INTERFACE(file_lock_interrupt, service_base); -public: - //! Please note that interrupt() is called outside any sync scopes and may be called after lock reference has been released. \n - //! It is implementer's responsibility to safeguard against such. \n - //! The interrupt() function must *never* fail, unless aborted by calling context - which means that whoever asked for write access is aborting whatever they're doing. \n - //! This function may block for as long as it takes to release the owned resources, but must be able to abort cleanly if doing so. \n - //! If the function was aborted, it may be called again on the same object. \n - //! If the function succeeded, it will not be called again on the same object; the object will be released immediately after. - virtual void interrupt( abort_callback & aborter ) = 0; - - static file_lock_interrupt::ptr create( std::function< void (abort_callback&)> ); -}; - //! Entry point class for obtaining file_lock objects. class NOVTABLE file_lock_manager : public service_base { public: @@ -68,10 +51,3 @@ public: FB2K_MAKE_SERVICE_COREAPI(file_lock_manager); }; - -// \since 1.5 -class NOVTABLE file_lock_manager_v2 : public file_lock_manager { - FB2K_MAKE_SERVICE_COREAPI_EXTENSION( file_lock_manager_v2, file_lock_manager ); -public: - virtual fb2k::objRef acquire_read_v2(const char * p_path, file_lock_interrupt::ptr interruptHandler, abort_callback & p_abort) = 0; -}; diff --git a/foobar2000/SDK/filesystem.cpp b/foobar2000/SDK/filesystem.cpp index 8497648..e361d39 100644 --- a/foobar2000/SDK/filesystem.cpp +++ b/foobar2000/SDK/filesystem.cpp @@ -210,7 +210,7 @@ void filesystem::g_move(const char * src,const char * dst,abort_callback & p_abo void filesystem::g_link(const char * p_src,const char * p_dst,abort_callback & p_abort) { if (!foobar2000_io::_extract_native_path_ptr(p_src) || !foobar2000_io::_extract_native_path_ptr(p_dst)) throw exception_io_no_handler_for_path(); - WIN32_IO_OP( CreateHardLink( pfc::stringcvt::string_os_from_utf8( pfc::winPrefixPath( p_dst ) ), pfc::stringcvt::string_os_from_utf8( pfc::winPrefixPath( p_src ) ), NULL) ); + WIN32_IO_OP( CreateHardLink( pfc::stringcvt::string_os_from_utf8( p_dst ), pfc::stringcvt::string_os_from_utf8( p_src ), NULL) ); } void filesystem::g_link_timeout(const char * p_src,const char * p_dst,double p_timeout,abort_callback & p_abort) { @@ -300,11 +300,7 @@ bool filesystem::g_relative_path_parse(const char * relative_path,const char * p return false; } -bool archive::is_our_archive( const char * path ) { - archive_v2::ptr v2; - if ( v2 &= this ) return v2->is_our_archive( path ); - return true; // accept all files -} + bool archive_impl::get_canonical_path(const char * path,pfc::string_base & out) { @@ -551,7 +547,8 @@ namespace { file::g_transfer_object(r_src,r_dst,size,p_abort); } catch(...) { r_dst.release(); - try {m_fs->remove(dst,fb2k::noAbort);} catch(...) {} + abort_callback_dummy dummy; + try {m_fs->remove(dst,dummy);} catch(...) {} throw; } } @@ -612,14 +609,11 @@ void filesystem::g_copy(const char * src,const char * dst,abort_callback & p_abo file::g_transfer_object(r_src,r_dst,size,p_abort); } catch(...) { r_dst.release(); - try {g_remove(dst,fb2k::noAbort);} catch(...) {} + abort_callback_dummy dummy; + try {g_remove(dst,dummy);} catch(...) {} throw; } } - - try { - file::g_copy_timestamps(r_src, r_dst, p_abort); - } catch (exception_io) {} } void stream_reader::read_object(void * p_buffer,t_size p_bytes,abort_callback & p_abort) { @@ -679,7 +673,8 @@ void filesystem::g_open_tempmem(service_ptr_t & p_out,abort_callback & p_a } file::ptr filesystem::g_open_tempmem() { - file::ptr f; g_open_tempmem(f, fb2k::noAbort); return f; + abort_callback_dummy aborter; + file::ptr f; g_open_tempmem(f, aborter); return f; } void archive_impl::list_directory(const char * p_path,directory_callback & p_out,abort_callback & p_abort) { @@ -715,21 +710,6 @@ bool file::is_eof(abort_callback & p_abort) { } -t_filetimestamp foobar2000_io::import_DOS_time(uint32_t v) { -#ifdef _WIN32 - FILETIME ft = {}; - if (DosDateTimeToFileTime(HIWORD(v), LOWORD(v), &ft)) { - FILETIME ft2 = {}; - if (LocalFileTimeToFileTime(&ft, &ft2)) { - return ((uint64_t)ft2.dwHighDateTime << 32) | (uint64_t)ft2.dwLowDateTime; - } - - } -#endif - // FIX ME - return filetimestamp_invalid; -} - t_filetimestamp foobar2000_io::filetimestamp_from_system_timer() { return pfc::fileTimeNow(); @@ -803,18 +783,7 @@ namespace { class exception_io_win32_ex : public exception_io_win32 { public: - static pfc::string8 format(DWORD code) { - pfc::string8 ret; - ret << "I/O error (win32 "; - if (code & 0x80000000) { - ret << "0x" << pfc::format_hex(code, 8); - } else { - ret << "#" << (uint32_t)code; - } - ret << ")"; - return ret; - } - exception_io_win32_ex(DWORD p_code) : m_msg(format(p_code)) {} + exception_io_win32_ex(DWORD p_code) : m_msg(pfc::string_formatter() << "I/O error (win32 #" << (t_uint32)p_code << ")") {} exception_io_win32_ex(const exception_io_win32_ex & p_other) {*this = p_other;} const char * what() const throw() {return m_msg;} private: @@ -832,7 +801,7 @@ PFC_NORETURN void foobar2000_io::win32_file_write_failure(DWORD p_code, const ch PFC_NORETURN void foobar2000_io::exception_io_from_win32(DWORD p_code) { #if PFC_DEBUG - PFC_DEBUGLOG << "exception_io_from_win32: " << p_code; + pfc::debugLog() << "exception_io_from_win32: " << p_code; #endif //pfc::string_fixed_t<32> debugMsg; debugMsg << "Win32 I/O error #" << (t_uint32)p_code; //TRACK_CALL_TEXT(debugMsg); @@ -890,7 +859,6 @@ PFC_NORETURN void foobar2000_io::exception_io_from_win32(DWORD p_code) { case ERROR_BAD_NETPATH: // known to be inflicted by momentary net connectivity issues - NOT the same as exception_io_not_found throw exception_io("Network path not found"); -#if FB2K_SUPPORT_TRANSACTED_FILESYSTEM case ERROR_TRANSACTIONAL_OPEN_NOT_ALLOWED: case ERROR_TRANSACTIONS_UNSUPPORTED_REMOTE: case ERROR_RM_NOT_ACTIVE: @@ -901,16 +869,9 @@ PFC_NORETURN void foobar2000_io::exception_io_from_win32(DWORD p_code) { throw exception_io_transactional_conflict(); case ERROR_TRANSACTION_ALREADY_ABORTED: throw exception_io_transaction_aborted(); - case ERROR_EFS_NOT_ALLOWED_IN_TRANSACTION: - throw exception_io("Transacted updates of encrypted content are not supported"); -#endif // FB2K_SUPPORT_TRANSACTED_FILESYSTEM case ERROR_UNEXP_NET_ERR: // QNAP threw this when messing with very long file paths and concurrent conversion, probably SMB daemon crashed - throw exception_io("Unexpected network error"); - case ERROR_NOT_SAME_DEVICE: - throw exception_io("Source and destination must be on the same device"); - case 0x80310000: - throw exception_io("Drive locked by BitLocker"); + throw exception_io("Unexpected netwrok error"); default: throw exception_io_win32_ex(p_code); } @@ -1049,17 +1010,6 @@ bool foobar2000_io::extract_native_path_ex(const char * p_fspath, pfc::string_ba return true; } -bool foobar2000_io::extract_native_path_archive_aware(const char * in, pfc::string_base & out) { - if (foobar2000_io::extract_native_path(in, out)) return true; - if (archive_impl::g_is_unpack_path(in)) { - pfc::string8 arc, dummy; - if (archive_impl::g_parse_unpack_path(in, arc, dummy)) { - return foobar2000_io::extract_native_path(arc, out); - } - } - return false; -} - pfc::string stream_reader::read_string(abort_callback & p_abort) { t_uint32 len; read_lendian_t(len,p_abort); @@ -1169,8 +1119,7 @@ bool foobar2000_io::matchContentType(const char * fullString, const char * ourTy const char * foobar2000_io::contentTypeFromExtension( const char * ext ) { if ( pfc::stringEqualsI_ascii( ext, "mp3" ) ) return "audio/mpeg"; if ( pfc::stringEqualsI_ascii( ext, "flac" ) ) return "audio/flac"; - if ( pfc::stringEqualsI_ascii( ext, "mp4" ) ) return "application/mp4"; // We don't know if it's audio-only or other. - if ( pfc::stringEqualsI_ascii( ext, "m4a" ) ) return "audio/mp4"; + if ( pfc::stringEqualsI_ascii( ext, "mp4" ) || pfc::stringEqualsI_ascii( ext, "m4a" ) ) return "audio/mp4"; if ( pfc::stringEqualsI_ascii( ext, "mpc" ) ) return "audio/musepack"; if ( pfc::stringEqualsI_ascii( ext, "ogg" ) ) return "audio/ogg"; if ( pfc::stringEqualsI_ascii( ext, "opus" ) ) return "audio/opus"; @@ -1183,7 +1132,6 @@ const char * foobar2000_io::contentTypeFromExtension( const char * ext ) { const char * foobar2000_io::extensionFromContentType( const char * contentType ) { if (matchContentType_MP3( contentType )) return "mp3"; if (matchContentType_FLAC( contentType )) return "flac"; - if (matchContentType_MP4audio( contentType)) return "m4a"; if (matchContentType_MP4( contentType)) return "mp4"; if (matchContentType_Musepack( contentType )) return "mpc"; if (matchContentType_Ogg( contentType )) return "ogg"; @@ -1199,12 +1147,6 @@ bool foobar2000_io::matchContentType_MP3( const char * type) { return matchContentType(type,"audio/mp3") || matchContentType(type,"audio/mpeg") || matchContentType(type,"audio/mpg") || matchContentType(type,"audio/x-mp3") || matchContentType(type,"audio/x-mpeg") || matchContentType(type,"audio/x-mpg"); } bool foobar2000_io::matchContentType_MP4( const char * type ) { - return matchContentType(type, "audio/mp4") || matchContentType(type, "audio/x-mp4") - || matchContentType(type, "video/mp4") || matchContentType(type, "video/x-mp4") - || matchContentType(type, "application/mp4") || matchContentType(type, "application/x-mp4"); - -} -bool foobar2000_io::matchContentType_MP4audio( const char * type ) { return matchContentType(type, "audio/mp4") || matchContentType(type, "audio/x-mp4"); } bool foobar2000_io::matchContentType_Ogg( const char * type) { @@ -1414,7 +1356,6 @@ void filesystem::rewrite_file(const char * path, abort_callback & abort, double { auto f = this->openWriteNew( temp, abort, opTimeout ); worker(f); - f->flushFileBuffers_( abort ); } retryOnSharingViolation(opTimeout, abort, [&] { @@ -1423,7 +1364,8 @@ void filesystem::rewrite_file(const char * path, abort_callback & abort, double } catch(...) { try { - retryOnSharingViolation(opTimeout, abort, [&] { this->remove(temp, fb2k::noAbort); } ); + abort_callback_dummy noAbort; + retryOnSharingViolation(opTimeout, abort, [&] { this->remove(temp, noAbort); } ); } catch(...) {} throw; } @@ -1528,72 +1470,7 @@ bool filesystem::commit_if_transacted(abort_callback &abort) { return rv; } -t_filestats filesystem::get_stats(const char * path, abort_callback & abort) { - t_filestats s; bool dummy; - this->get_stats(path, s, dummy, abort); - return s; -} - bool file_dynamicinfo_v2::get_dynamic_info(class file_info & p_out) { t_filesize dummy = 0; return this->get_dynamic_info_v2(p_out, dummy); } - -void file::flushFileBuffers_(abort_callback&a) { - file_lowLevelIO::ptr f; - if ( f &= this ) f->flushFileBuffers(a); -} - -size_t file::lowLevelIO_(const GUID & guid, size_t arg1, void * arg2, size_t arg2size, abort_callback & abort) { - size_t retval = 0; - file_lowLevelIO::ptr f; - if (f &= this) retval = f->lowLevelIO(guid, arg1, arg2, arg2size, abort); - return retval; -} - -bool file_lowLevelIO::flushFileBuffers(abort_callback & abort) { - return this->lowLevelIO( guid_flushFileBuffers, 0, nullptr, 0, abort) != 0; -} - -bool file_lowLevelIO::getFileTimes(filetimes_t & out, abort_callback & a) { - return this->lowLevelIO(guid_getFileTimes, 0, &out, sizeof(out), a) != 0; -} - -bool file_lowLevelIO::setFileTimes(filetimes_t const & in, abort_callback & a) { - return this->lowLevelIO(guid_setFileTimes, 0, (void*)&in, sizeof(in), a) != 0; -} - -bool file::g_copy_creation_time(service_ptr_t from, service_ptr_t to, abort_callback& a) { - file_lowLevelIO::ptr llFrom, llTo; - bool rv = false; - if (llTo &= to) { - if (llFrom &= from) { - file_lowLevelIO::filetimes_t filetimes; - if (llFrom->getFileTimes(filetimes, a)) { - if (filetimes.creation != filetimestamp_invalid) { - file_lowLevelIO::filetimes_t ft2; - ft2.creation = filetimes.creation; - rv = llTo->setFileTimes(ft2, a); - } - } - } - } - return rv; -} -bool file::g_copy_timestamps(file::ptr from, file::ptr to, abort_callback& a) { - file_lowLevelIO::ptr llFrom, llTo; - if ( llTo &= to ) { - if (llFrom &= from) { - file_lowLevelIO::filetimes_t filetimes = {}; - if (llFrom->getFileTimes(filetimes, a)) { - return llTo->setFileTimes(filetimes, a); - } - } - file_lowLevelIO::filetimes_t filetimes = {}; - filetimes.lastWrite = from->get_timestamp(a); - if ( filetimes.lastWrite != filetimestamp_invalid ) { - return llTo->setFileTimes(filetimes, a); - } - } - return false; -} diff --git a/foobar2000/SDK/filesystem.h b/foobar2000/SDK/filesystem.h index e13e61c..8aea4d5 100644 --- a/foobar2000/SDK/filesystem.h +++ b/foobar2000/SDK/filesystem.h @@ -23,8 +23,7 @@ namespace foobar2000_io PFC_DECLARE_EXCEPTION(exception_io, pfc::exception,"I/O error"); //! Object not found. PFC_DECLARE_EXCEPTION(exception_io_not_found, exception_io,"Object not found"); - //! Access denied. \n - //! Special Windows note: this MAY be thrown instead of exception_io_sharing_violation by operations that rename/move files due to Win32 MoveFile() bugs. + //! Access denied. PFC_DECLARE_EXCEPTION(exception_io_denied, exception_io,"Access denied"); //! Access denied. PFC_DECLARE_EXCEPTION(exception_io_denied_readonly, exception_io_denied,"File is read-only"); @@ -269,12 +268,12 @@ namespace foobar2000_io //! Optional, called by owner thread before sleeping. //! @param p_abort abort_callback object signaling user aborting the operation. - virtual void on_idle(abort_callback & p_abort) {(void)p_abort;} + virtual void on_idle(abort_callback & p_abort) {} //! Retrieves last modification time of the file. //! @param p_abort abort_callback object signaling user aborting the operation. //! @returns Last modification time o fthe file; filetimestamp_invalid if N/A. - virtual t_filetimestamp get_timestamp(abort_callback & p_abort) {(void)p_abort;return filetimestamp_invalid;} + virtual t_filetimestamp get_timestamp(abort_callback & p_abort) {return filetimestamp_invalid;} //! Resets non-seekable stream, or seeks to zero on seekable file. //! @param p_abort abort_callback object signaling user aborting the operation. @@ -318,19 +317,12 @@ namespace foobar2000_io static void g_transfer_object(stream_reader * src,stream_writer * dst,t_filesize bytes,abort_callback & p_abort); //! Helper; transfers entire file content from one file to another, erasing previous content. static void g_transfer_file(const service_ptr_t & p_from,const service_ptr_t & p_to,abort_callback & p_abort); - //! Helper; transfers file modification times from one file to another, if supported by underlying objects. Returns true on success, false if the operation doesn't appear to be supported. - static bool g_copy_timestamps(service_ptr_t from, service_ptr_t to, abort_callback& abort); - static bool g_copy_creation_time(service_ptr_t from, service_ptr_t to, abort_callback& abort); //! Helper; improved performance over g_transfer on streams (avoids disk fragmentation when transferring large blocks). static t_filesize g_transfer(service_ptr_t p_src,service_ptr_t p_dst,t_filesize p_bytes,abort_callback & p_abort); //! Helper; improved performance over g_transfer_file on streams (avoids disk fragmentation when transferring large blocks). static void g_transfer_object(service_ptr_t p_src,service_ptr_t p_dst,t_filesize p_bytes,abort_callback & p_abort); - //! file_lowLevelIO wrapper - void flushFileBuffers_(abort_callback &); - //! file_lowLevelIO wrapper - size_t lowLevelIO_(const GUID & guid, size_t arg1, void * arg2, size_t arg2size, abort_callback & abort); t_filesize skip(t_filesize p_bytes,abort_callback & p_abort); t_filesize skip_seek(t_filesize p_bytes,abort_callback & p_abort); @@ -376,46 +368,6 @@ namespace foobar2000_io static void g_decodeInitCache(file::ptr & theFile, abort_callback & abort, size_t blockSize); }; - //! \since 1.5 - //! Additional service implemented by standard file object providing access to low level OS specific APIs. - class file_lowLevelIO : public service_base { - FB2K_MAKE_SERVICE_INTERFACE(file_lowLevelIO, service_base ); - public: - //! @returns 0 if the command was not recognized, a command-defined non zero value otherwise. - virtual size_t lowLevelIO( const GUID & guid, size_t arg1, void * arg2, size_t arg2size, abort_callback & abort ) = 0; - - //! Win32 FlushFileBuffers() wrapper. \n - //! Throws exception_io_denied on a file opened for reading. \n - //! No arguments are defined. \n - //! Returns 1 if handled, 0 if unsupported. - static const GUID guid_flushFileBuffers; - //! Retrieves file creation / last access / last write times. \n - //! Parameters: arg2 points to a filetimes_t struct to receive the data; arg2size must be set to sizeof(filetimes_t). \n - //! If the filesystem does not support a specific portion of the information, relevant struct member will be set to filetimestamp_invalid. \n - //! Returns 1 if handled, 0 if unsupported. - static const GUID guid_getFileTimes; - //! Sets file creation / last access / last write times. \n - //! Parameters: arg2 points to a filetimes_t struct holding the new data; arg2size must be set to sizeof(filetimes_t). \n - //! Individual members of the filetimes_t struct can be set to filetimestamp_invalid, if not all of the values are to be altered on the file. \n - //! Returns 1 if handled, 0 if unsupported. - static const GUID guid_setFileTimes; - - //! Struct to be used with guid_getFileTimes / guid_setFileTimes. - struct filetimes_t { - t_filetimestamp creation = filetimestamp_invalid; - t_filetimestamp lastAccess = filetimestamp_invalid; - t_filetimestamp lastWrite = filetimestamp_invalid; - }; - - //! Helper - bool flushFileBuffers(abort_callback &); - //! Helper - bool getFileTimes( filetimes_t & out, abort_callback &); - //! Helper - bool setFileTimes( filetimes_t const & in, abort_callback &); - - }; - //! Implementation helper - contains dummy implementations of methods that modify the file template class file_readonly_t : public t_base { public: @@ -426,13 +378,13 @@ namespace foobar2000_io class file_streamstub : public file_readonly { public: - t_size read(void *,t_size,abort_callback &) {return 0;} - t_filesize get_size(abort_callback &) {return filesize_invalid;} - t_filesize get_position(abort_callback &) {return 0;} - bool get_content_type(pfc::string_base &) {return false;} + t_size read(void * p_buffer,t_size p_bytes,abort_callback & p_abort) {return 0;} + t_filesize get_size(abort_callback & p_abort) {return filesize_invalid;} + t_filesize get_position(abort_callback & p_abort) {return 0;} + bool get_content_type(pfc::string_base & p_out) {return false;} bool is_remote() {return true;} void reopen(abort_callback&) {} - void seek(t_filesize,abort_callback &) {throw exception_io_object_not_seekable();} + void seek(t_filesize p_position,abort_callback & p_abort) {throw exception_io_object_not_seekable();} bool can_seek() {return false;} }; @@ -470,16 +422,12 @@ namespace foobar2000_io virtual void open(service_ptr_t & p_out,const char * p_path, t_open_mode p_mode,abort_callback & p_abort)=0; virtual void remove(const char * p_path,abort_callback & p_abort)=0; - //! Moves/renames a file. Will fail if the destination file already exists. \n - //! Note that this function may throw exception_io_denied instead of exception_io_sharing_violation when the file is momentarily in use, due to bugs in Windows MoveFile() API. There is no legitimate way for us to distinguish between the two scenarios. virtual void move(const char * p_src,const char * p_dst,abort_callback & p_abort)=0; - //! Queries whether a file at specified path belonging to this filesystem is a remote object or not. + //! Queries whether a file at specified path belonging to this filesystem is a remove object or not. virtual bool is_remote(const char * p_src) = 0; //! Retrieves stats of a file at specified path. virtual void get_stats(const char * p_path,t_filestats & p_stats,bool & p_is_writeable,abort_callback & p_abort) = 0; - //! Helper - t_filestats get_stats( const char * path, abort_callback & abort ); virtual bool relative_path_create(const char * file_path,const char * playlist_path,pfc::string_base & out) {return false;} virtual bool relative_path_parse(const char * relative_path,const char * playlist_path,pfc::string_base & out) {return false;} @@ -522,7 +470,6 @@ namespace foobar2000_io //! Attempts to remove file at specified path; if the operation fails with a sharing violation error, keeps retrying (with short sleep period between retries) for specified amount of time. static void g_remove_timeout(const char * p_path,double p_timeout,abort_callback & p_abort); //! Moves file from one path to another. - //! Note that this function may throw exception_io_denied instead of exception_io_sharing_violation when the file is momentarily in use, due to bugs in Windows MoveFile() API. There is no legitimate way for us to distinguish between the two scenarios. static void g_move(const char * p_src,const char * p_dst,abort_callback & p_abort); //! Attempts to move file from one path to another; if the operation fails with a sharing violation error, keeps retrying (with short sleep period between retries) for specified amount of time. static void g_move_timeout(const char * p_src,const char * p_dst,double p_timeout,abort_callback & p_abort); @@ -559,12 +506,10 @@ namespace foobar2000_io // Presumes both source and destination belong to this filesystem. void copy_directory(const char * p_src, const char * p_dst, abort_callback & p_abort); - //! Moves/renames a file, overwriting the destination atomically if exists. \n - //! Note that this function may throw exception_io_denied instead of exception_io_sharing_violation when the file is momentarily in use, due to bugs in Windows MoveFile() API. There is no legitimate way for us to distinguish between the two scenarios. + //! Move file overwriting an existing one. Regular move() will fail if the file exists. void move_overwrite( const char * src, const char * dst, abort_callback & abort); - //! Moves/renames a file, overwriting the destination atomically if exists. \n - //! Meant to retain destination attributes if feasible. Otherwise identical to move_overwrite(). \n - //! Note that this function may throw exception_io_denied instead of exception_io_sharing_violation when the file is momentarily in use, due to bugs in Windows MoveFile() API. There is no legitimate way for us to distinguish between the two scenarios. + //! Same as move_overwrite(). \n + //! This used to call win32 ReplaceFile() but that was pulled due to extreme stupidity of ReplaceFile() implementation. void replace_file(const char * src, const char * dst, abort_callback & abort); //! Create a directory, without throwing an exception if it already exists. //! @param didCreate bool flag indicating whether a new directory was created or not. \n @@ -598,12 +543,6 @@ namespace foobar2000_io //! See also: filesystem_transacted. \n //! In order to perform transacted operations, you must obtain a transacted filesystem explicitly, or get one passed down from a higher level context (example: in config_io_callback_v3). void rewrite_file( const char * path, abort_callback & abort, double opTimeout, std::function worker ); - //! Full directory rewrite helper that automatically does the right thing to ensure atomic update. \n - //! If this is a transacted filesystem, a simple in-place rewrite is performed. \n - //! If this is not a transacted filesystem, your content first goes to a temporary folder, which then replaces the original. \n - //! It is encouraged to perform flushFileBuffers on all files accessed from within. \n - //! See also: filesystem_transacted. \n - //! In order to perform transacted operations, you must obtain a transacted filesystem explicitly, or get one passed down from a higher level context (example: in config_io_callback_v3). void rewrite_directory(const char * path, abort_callback & abort, double opTimeout, std::function worker); protected: static bool get_parent_helper(const char * path, char separator, pfc::string_base & out); @@ -628,16 +567,8 @@ namespace foobar2000_io class filesystem_v2 : public filesystem { FB2K_MAKE_SERVICE_INTERFACE( filesystem_v2, filesystem ) public: - //! Moves/renames a file, overwriting the destination atomically if exists. \n - //! Note that this function may throw exception_io_denied instead of exception_io_sharing_violation when the file is momentarily in use, due to bugs in Windows MoveFile() API. There is no legitimate way for us to distinguish between the two scenarios. virtual void move_overwrite(const char * src, const char * dst, abort_callback & abort) = 0; - //! Moves/renames a file, overwriting the destination atomically if exists. \n - //! Meant to retain destination attributes if feasible. Otherwise identical to move_overwrite(). \n - //! Note that this function may throw exception_io_denied instead of exception_io_sharing_violation when the file is momentarily in use, due to bugs in Windows MoveFile() API. There is no legitimate way for us to distinguish between the two scenarios. virtual void replace_file(const char * src, const char * dst, abort_callback & abort); - //! Create a directory, without throwing an exception if it already exists. - //! @param didCreate bool flag indicating whether a new directory was created or not. \n - //! This should be a retval, but because it's messy to obtain this information with certain APIs, the caller can opt out of receiving this information,. virtual void make_directory(const char * path, abort_callback & abort, bool * didCreate = nullptr) = 0; virtual bool directory_exists(const char * path, abort_callback & abort) = 0; virtual bool file_exists(const char * path, abort_callback & abort) = 0; @@ -678,9 +609,61 @@ namespace foobar2000_io void sort() {m_data.sort_t(sortfunc);} }; + class archive; + + class NOVTABLE archive_callback : public abort_callback { + public: + virtual bool on_entry(archive * owner,const char * url,const t_filestats & p_stats,const service_ptr_t & p_reader) = 0; + }; + + //! Interface for archive reader services. When implementing, derive from archive_impl rather than from deriving from archive directly. + class NOVTABLE archive : public filesystem { + public: + virtual void archive_list(const char * p_path,const service_ptr_t & p_reader,archive_callback & p_callback,bool p_want_readers) = 0; + + FB2K_MAKE_SERVICE_INTERFACE(archive,filesystem); + }; + + //! Root class for archive implementations. Derive from this instead of from archive directly. + class NOVTABLE archive_impl : public archive { + private: + //do not override these + bool get_canonical_path(const char * path,pfc::string_base & out); + bool is_our_path(const char * path); + bool get_display_path(const char * path,pfc::string_base & out); + void remove(const char * path,abort_callback & p_abort); + void move(const char * src,const char * dst,abort_callback & p_abort); + bool is_remote(const char * src); + bool relative_path_create(const char * file_path,const char * playlist_path,pfc::string_base & out); + bool relative_path_parse(const char * relative_path,const char * playlist_path,pfc::string_base & out); + void open(service_ptr_t & p_out,const char * path, t_open_mode mode,abort_callback & p_abort); + void create_directory(const char * path,abort_callback &); + void list_directory(const char * p_path,directory_callback & p_out,abort_callback & p_abort); + void get_stats(const char * p_path,t_filestats & p_stats,bool & p_is_writeable,abort_callback & p_abort); + protected: + //override these + virtual const char * get_archive_type()=0;//eg. "zip", must be lowercase + virtual t_filestats get_stats_in_archive(const char * p_archive,const char * p_file,abort_callback & p_abort) = 0; + virtual void open_archive(service_ptr_t & p_out,const char * archive,const char * file, abort_callback & p_abort)=0;//opens for reading + public: + //override these + virtual void archive_list(const char * path,const service_ptr_t & p_reader,archive_callback & p_out,bool p_want_readers)=0; + + + static bool g_is_unpack_path(const char * path); + static bool g_parse_unpack_path(const char * path,pfc::string_base & archive,pfc::string_base & file); + static bool g_parse_unpack_path_ex(const char * path,pfc::string_base & archive,pfc::string_base & file, pfc::string_base & type); + static void g_make_unpack_path(pfc::string_base & path,const char * archive,const char * file,const char * type); + void make_unpack_path(pfc::string_base & path,const char * archive,const char * file); + + + }; + + template + class archive_factory_t : public service_factory_single_t {}; + t_filetimestamp filetimestamp_from_system_timer(); - t_filetimestamp import_DOS_time(uint32_t); #ifdef _WIN32 inline t_filetimestamp import_filetimestamp(FILETIME ft) { @@ -776,8 +759,6 @@ namespace foobar2000_io bool is_native_filesystem( const char * p_fspath ); bool extract_native_path_ex(const char * p_fspath, pfc::string_base & p_native);//prepends \\?\ where needed - bool extract_native_path_archive_aware( const char * fspatch, pfc::string_base & out ); - template pfc::string getPathDisplay(const T& source) { const char * c = pfc::stringToPtr(source); @@ -802,7 +783,6 @@ namespace foobar2000_io void substituteProtocol(pfc::string_base & out, const char * fullString, const char * protocolName); bool matchContentType_MP3( const char * fullString); - bool matchContentType_MP4audio( const char * fullString); bool matchContentType_MP4( const char * fullString); bool matchContentType_Ogg( const char * fullString); bool matchContentType_Opus( const char * fullString); @@ -814,22 +794,6 @@ namespace foobar2000_io const char * contentTypeFromExtension( const char * ext ); void purgeOldFiles(const char * directory, t_filetimestamp period, abort_callback & abort); - - //! \since 1.6 - class read_ahead_tools : public service_base { - FB2K_MAKE_SERVICE_COREAPI(read_ahead_tools); - public: - //! Turn any file object into asynchronous read-ahead-buffered file. - //! @param f File object to wrap. Do not call this object's method after a successful call to add_read_ahead; new file object takes over the ownership of it. - //! @param size Requested read-ahead bytes. Pass 0 to use user settings for local/remote playback. - virtual file::ptr add_read_ahead(file::ptr f, size_t size, abort_callback & aborter) = 0; - - //! A helper method to use prior to opening decoders. \n - //! May open the file if needed or leave it blank for the decoder to open. - //! @param f File object to open if needed (buffering mandated by user settings). May be valid or null prior to call. May be valid or null (no buffering) after call. - //! @param path Path to open. May be null if f is not null. At least one of f and path must be valid prior to call. - virtual void open_file_helper(file::ptr & f, const char * path, abort_callback & aborter) = 0; - }; } using namespace foobar2000_io; diff --git a/foobar2000/SDK/filesystem_helper.cpp b/foobar2000/SDK/filesystem_helper.cpp index c0aa906..0481267 100644 --- a/foobar2000/SDK/filesystem_helper.cpp +++ b/foobar2000/SDK/filesystem_helper.cpp @@ -244,6 +244,8 @@ namespace foobar2000_io { } DWORD winVolumeFlags( const char * fb2kPath ) { + PFC_ASSERT( matchProtocol( fb2kPath, "file" ) ); + PFC_ASSERT(matchProtocol(fb2kPath, "file")); pfc::string8 native; if (!filesystem::g_get_native_path(fb2kPath, native)) throw pfc::exception_invalid_params(); diff --git a/foobar2000/SDK/filesystem_helper.h b/foobar2000/SDK/filesystem_helper.h index 214faa7..0619726 100644 --- a/foobar2000/SDK/filesystem_helper.h +++ b/foobar2000/SDK/filesystem_helper.h @@ -470,20 +470,21 @@ FB2K_STREAM_READER_OVERLOAD(bool) { template class stream_writer_formatter_simple : public stream_writer_formatter { public: - stream_writer_formatter_simple() : stream_writer_formatter(_m_stream,fb2k::noAbort), m_buffer(_m_stream.m_buffer) {} + stream_writer_formatter_simple() : stream_writer_formatter(_m_stream,_m_abort), m_buffer(_m_stream.m_buffer) {} typedef stream_writer_buffer_simple::t_buffer t_buffer; t_buffer & m_buffer; private: stream_writer_buffer_simple _m_stream; + abort_callback_dummy _m_abort; }; template class stream_reader_formatter_simple_ref : public stream_reader_formatter { public: - stream_reader_formatter_simple_ref(const void * source, t_size sourceSize) : stream_reader_formatter(_m_stream,fb2k::noAbort), _m_stream(source,sourceSize) {} - template stream_reader_formatter_simple_ref(const TSource& source) : stream_reader_formatter(_m_stream,fb2k::noAbort), _m_stream(source) {} - stream_reader_formatter_simple_ref() : stream_reader_formatter(_m_stream,fb2k::noAbort) {} + stream_reader_formatter_simple_ref(const void * source, t_size sourceSize) : stream_reader_formatter(_m_stream,_m_abort), _m_stream(source,sourceSize) {} + template stream_reader_formatter_simple_ref(const TSource& source) : stream_reader_formatter(_m_stream,_m_abort), _m_stream(source) {} + stream_reader_formatter_simple_ref() : stream_reader_formatter(_m_stream,_m_abort) {} void set_data(const void * source, t_size sourceSize) {_m_stream.set_data(source,sourceSize);} template void set_data(const TSource & source) {_m_stream.set_data(source);} @@ -494,6 +495,7 @@ public: const void * get_ptr_() const {return _m_stream.get_ptr_();} private: stream_reader_memblock_ref _m_stream; + abort_callback_dummy _m_abort; }; template diff --git a/foobar2000/SDK/filesystem_transacted.h b/foobar2000/SDK/filesystem_transacted.h index ee945d8..00c239c 100644 --- a/foobar2000/SDK/filesystem_transacted.h +++ b/foobar2000/SDK/filesystem_transacted.h @@ -38,7 +38,5 @@ public: virtual bool is_our_path( const char * path ) = 0; }; -// Since 1.5, transacted filesystem is no longer supported -// as it adds extra complexity without actually solving any problems. -// Even Microsoft recommends not to use this API. -#define FB2K_SUPPORT_TRANSACTED_FILESYSTEM 0 +// Defined but not actually provided for MS Store target - because it plainly doesn't work there +#define FB2K_SUPPORT_TRANSACTED_FILESYSTEM (!FB2K_TARGET_MICROSOFT_STORE) diff --git a/foobar2000/SDK/foobar2000-winver.h b/foobar2000/SDK/foobar2000-winver.h index b93249c..fca700e 100644 --- a/foobar2000/SDK/foobar2000-winver.h +++ b/foobar2000/SDK/foobar2000-winver.h @@ -1,15 +1,23 @@ #pragma once +#ifndef UNICODE +#error Only UNICODE environment supported. +#endif + + #define FOOBAR2000_DESKTOP #define FOOBAR2000_DESKTOP_WINDOWS #define FOOBAR2000_DESKTOP_WINDOWS_OR_BOOM +// Set target versions to Windows XP as that's what foobar2000 supports, unless overridden before #including us +#if !defined(_WIN32_WINNT) && !defined(WINVER) +#define _WIN32_WINNT 0x501 +#define WINVER 0x501 +#endif + #define FOOBAR2000_HAVE_FILE_FORMAT_SANITIZER #define FOOBAR2000_HAVE_CHAPTERIZER #define FOOBAR2000_HAVE_ALBUM_ART #define FOOBAR2000_DECLARE_FILE_TYPES #define FOOBAR2000_HAVE_DSP #define FOOBAR2000_HAVE_CONSOLE -#define FOOBAR2000_INTERACTIVE -#define FOOBAR2000_WINAPI_CLASSIC -#define FOOBAR2000_HAVE_METADB \ No newline at end of file diff --git a/foobar2000/SDK/foobar2000.h b/foobar2000/SDK/foobar2000.h index 96b6882..90fe455 100644 --- a/foobar2000/SDK/foobar2000.h +++ b/foobar2000/SDK/foobar2000.h @@ -7,13 +7,12 @@ // #define FOOBAR2000_TARGET_VERSION 75 // 0.9.6 // #define FOOBAR2000_TARGET_VERSION 76 // 1.0 -// #define FOOBAR2000_TARGET_VERSION 77 // 1.1, 1.2 -// #define FOOBAR2000_TARGET_VERSION 78 // 1.3 -#define FOOBAR2000_TARGET_VERSION 79 // 1.4 -// #define FOOBAR2000_TARGET_VERSION 80 // 1.5, 1.6 +// #define FOOBAR2000_TARGET_VERSION 77 // 1.1 +#define FOOBAR2000_TARGET_VERSION 78 // 1.3 +// #define FOOBAR2000_TARGET_VERSION 79 // 1.4 // Use this to determine what foobar2000 SDK version is in use, undefined for releases older than 2018 -#define FOOBAR2000_SDK_VERSION 20210223 +#define FOOBAR2000_SDK_VERSION 20190617 #include "foobar2000-pfc.h" @@ -34,8 +33,8 @@ typedef const char * pcchar; #include "core_api.h" #include "service.h" #include "service_impl.h" +#include "service_factory.h" #include "service_by_guid.h" -#include "service_compat.h" #include "completion_notify.h" #include "abort_callback.h" @@ -44,7 +43,6 @@ typedef const char * pcchar; #include "coreversion.h" #include "filesystem.h" #include "filesystem_transacted.h" -#include "archive.h" #include "audio_chunk.h" #include "cfg_var.h" #include "mem_block_container.h" @@ -55,7 +53,6 @@ typedef const char * pcchar; #include "hasher_md5.h" #include "metadb_handle.h" #include "metadb.h" -#include "file_info_filter.h" #include "console.h" #include "dsp.h" #include "dsp_manager.h" @@ -124,7 +121,5 @@ typedef const char * pcchar; #include "commonObjects.h" #include "file_lock_manager.h" -#include "imageLoaderLite.h" -#include "imageViewer.h" #endif //_FOOBAR2000_H_ diff --git a/foobar2000/SDK/foobar2000_SDK.vcxproj b/foobar2000/SDK/foobar2000_SDK.vcxproj index 1772538..226d605 100644 --- a/foobar2000/SDK/foobar2000_SDK.vcxproj +++ b/foobar2000/SDK/foobar2000_SDK.vcxproj @@ -13,6 +13,7 @@ {E8091321-D79D-4575-86EF-064EA1A4A20D} foobar2000_SDK + 7.0 @@ -20,13 +21,13 @@ false Unicode true - v141 + v141_xp StaticLibrary false Unicode - v141 + v141_xp @@ -44,6 +45,7 @@ Disabled + WIN32;_DEBUG;_WINDOWS;_WIN32_WINNT=0x501;%(PreprocessorDefinitions) EnableFastChecks Use foobar2000.h @@ -53,6 +55,7 @@ MultiThreadedDebugDLL 4715 true + NoExtensions _DEBUG;%(PreprocessorDefinitions) @@ -65,6 +68,7 @@ MinSpace + WIN32;NDEBUG;_WINDOWS;_WIN32_WINNT=0x501;%(PreprocessorDefinitions) true false Fast @@ -75,12 +79,11 @@ true ProgramDatabase MultiThreadedDLL + NoExtensions /d2notypeopt %(AdditionalOptions) 4715 true true - true - NDEBUG;_UNICODE;UNICODE;%(PreprocessorDefinitions) NDEBUG;%(PreprocessorDefinitions) @@ -96,7 +99,6 @@ - @@ -124,8 +126,6 @@ - - @@ -140,8 +140,6 @@ - - @@ -175,18 +173,16 @@ - + - - @@ -280,7 +276,6 @@ - diff --git a/foobar2000/SDK/foobar2000_SDK.vcxproj.filters b/foobar2000/SDK/foobar2000_SDK.vcxproj.filters index db996c1..6ca0e94 100644 --- a/foobar2000/SDK/foobar2000_SDK.vcxproj.filters +++ b/foobar2000/SDK/foobar2000_SDK.vcxproj.filters @@ -269,6 +269,9 @@ Header Files + + Header Files + Header Files @@ -281,30 +284,6 @@ Header Files - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - @@ -481,8 +460,5 @@ Source Files - - Source Files - \ No newline at end of file diff --git a/foobar2000/SDK/guids.cpp b/foobar2000/SDK/guids.cpp index bf0f395..03f469c 100644 --- a/foobar2000/SDK/guids.cpp +++ b/foobar2000/SDK/guids.cpp @@ -55,8 +55,6 @@ FOOGUIDDECL const GUID resampler_entry::class_guid = { 0x3feed4fc, 0xa400, 0x4a3 #ifdef FOOBAR2000_DESKTOP FOOGUIDDECL const GUID resampler_manager::class_guid = { 0x9a7e5f01, 0x975b, 0x4373,{ 0xb8, 0x55, 0x3e, 0xf4, 0x16, 0x17, 0x43, 0x3 } }; -FOOGUIDDECL const GUID resampler_manager_v2::class_guid = { 0xfe4d7f2e, 0xb705, 0x48fa, { 0x89, 0xce, 0xd7, 0x34, 0xa6, 0x3b, 0x9f, 0x15 } }; -FOOGUIDDECL const GUID resampler_manager_v3::class_guid = { 0x262bfb95, 0x7f3c, 0x45c2, { 0xb0, 0x64, 0x9b, 0x6a, 0xd8, 0x3d, 0x34, 0xdd } }; #endif #endif // FOOBAR2000_HAVE_DSP @@ -99,10 +97,6 @@ FOOGUIDDECL const GUID packet_decoder_streamparse::class_guid = FOOGUIDDECL const GUID packet_decoder_entry::class_guid = { 0x53006a71, 0xc03c, 0x4c38, { 0x82, 0x2f, 0x9a, 0x34, 0xa5, 0x65, 0x50, 0x95 } }; -// {C20940DC-8632-414A-BCF5-415DB77CF9BA} -FOOGUIDDECL const GUID packet_decoder_entry_v2::class_guid = -{ 0xc20940dc, 0x8632, 0x414a, { 0xbc, 0xf5, 0x41, 0x5d, 0xb7, 0x7c, 0xf9, 0xba } }; - // {D3BD5F53-A6D6-4346-991F-CF14DFAD2B3A} FOOGUIDDECL const GUID contextmenu_manager::class_guid = { 0xd3bd5f53, 0xa6d6, 0x4346, { 0x99, 0x1f, 0xcf, 0x14, 0xdf, 0xad, 0x2b, 0x3a } }; @@ -119,11 +113,6 @@ FOOGUIDDECL const GUID input_file_type_v2::class_guid = FOOGUIDDECL const GUID ui_control::class_guid = { 0x2dc57ff7, 0x476d, 0x42f5, { 0xa0, 0x5a, 0x60, 0x49, 0x98, 0x96, 0x13, 0x4a } }; -#if FOOBAR2000_TARGET_VERSION >= 80 -FOOGUIDDECL const GUID ui_control_v2::class_guid = { 0x6fc5d5c3, 0x13aa, 0x4f7f, { 0x97, 0x8d, 0x89, 0x6b, 0x9b, 0x90, 0x4a, 0x5 } }; -#endif // FOOBAR2000_TARGET_VERSION >= 80 - - // {392B88DE-50FC-43b0-9F03-2D79B071CAF6} FOOGUIDDECL const GUID ui_status_text_override::class_guid = { 0x392b88de, 0x50fc, 0x43b0, { 0x9f, 0x3, 0x2d, 0x79, 0xb0, 0x71, 0xca, 0xf6 } }; @@ -176,14 +165,6 @@ FOOGUIDDECL const GUID unpacker::class_guid = FOOGUIDDECL const GUID archive::class_guid = { 0xec707440, 0xfa3e, 0x4d12, { 0x98, 0x76, 0xfc, 0x36, 0x9f, 0x4, 0xd4, 0xa4 } }; -// {69897890-90CB-4F7D-9969-1A9DCC5D9DDB} -FOOGUIDDECL const GUID archive_v2::class_guid = -{ 0x69897890, 0x90cb, 0x4f7d, { 0x99, 0x69, 0x1a, 0x9d, 0xcc, 0x5d, 0x9d, 0xdb } }; - -// {8D3F8B2D-A866-4F1F-9A4F-FF23929ED6DA} -FOOGUIDDECL const GUID archive_v3::class_guid = -{ 0x8d3f8b2d, 0xa866, 0x4f1f, { 0x9a, 0x4f, 0xff, 0x23, 0x92, 0x9e, 0xd6, 0xda } }; - // {B2F9FC40-3E55-4b23-A2C9-22BAAD8795B1} FOOGUIDDECL const GUID file::class_guid = { 0xb2f9fc40, 0x3e55, 0x4b23, { 0xa2, 0xc9, 0x22, 0xba, 0xad, 0x87, 0x95, 0xb1 } }; @@ -270,11 +251,6 @@ FOOGUIDDECL const GUID packet_decoder::owner_MP4_ALAC = FOOGUIDDECL const GUID packet_decoder::owner_MP4_AC3 = { 0x62263199, 0x48c2, 0x4777, { 0xb3, 0x3a, 0x87, 0xed, 0x16, 0x1a, 0x16, 0x30 } }; -// {AE6325BE-6C65-4B8F-B60D-5C803763BFB5} -FOOGUIDDECL const GUID packet_decoder::owner_MP4_EAC3 = -{ 0xae6325be, 0x6c65, 0x4b8f, { 0xb6, 0xd, 0x5c, 0x80, 0x37, 0x63, 0xbf, 0xb5 } }; - - // {40017871-50A9-48b6-BF60-BD181A227F9B} FOOGUIDDECL const GUID packet_decoder::owner_MP4_AMR = { 0x40017871, 0x50a9, 0x48b6, { 0xbf, 0x60, 0xbd, 0x18, 0x1a, 0x22, 0x7f, 0x9b } }; @@ -347,14 +323,6 @@ FOOGUIDDECL const GUID packet_decoder::property_eventlogger = FOOGUIDDECL const GUID packet_decoder::property_mp3_delayless = { 0x7ad5e747, 0xcbf3, 0x487d, { 0x88, 0x4f, 0xd9, 0x3c, 0xf8, 0xb8, 0x6e, 0xb0 } }; -// {CC2741CF-B57F-43A7-83C9-01C8628E6FDC} -FOOGUIDDECL const GUID packet_decoder::property_query_delay_samples = -{ 0xcc2741cf, 0xb57f, 0x43a7, { 0x83, 0xc9, 0x1, 0xc8, 0x62, 0x8e, 0x6f, 0xdc } }; - -// {69DD756A-1396-4D69-A08D-82B34B033141} -FOOGUIDDECL const GUID packet_decoder::property_query_mp4_use_elst = -{ 0x69dd756a, 0x1396, 0x4d69, { 0xa0, 0x8d, 0x82, 0xb3, 0x4b, 0x3, 0x31, 0x41 } }; - // {6F441057-1D18-4a58-9AC4-8F409CDA7DFD} FOOGUIDDECL const GUID standard_commands::guid_context_file_properties = { 0x6f441057, 0x1d18, 0x4a58, { 0x9a, 0xc4, 0x8f, 0x40, 0x9c, 0xda, 0x7d, 0xfd } }; @@ -633,8 +601,8 @@ FOOGUIDDECL const GUID standard_commands::guid_main_playlist_redo = { 0x7a9d9450, 0xa8bf, 0x4a88, { 0xb4, 0x4f, 0xdc, 0xd8, 0x3a, 0x49, 0xdd, 0x7a } }; // {02D89A8A-5F7D-41c3-A215-6731D8621036} -FOOGUIDDECL const GUID standard_commands::guid_main_show_console = -{ 0x5b652d25, 0xce44, 0x4737, { 0x99, 0xbb, 0xa3, 0xcf, 0x2a, 0xeb, 0x35, 0xcc } }; +FOOGUIDDECL const GUID standard_commands::guid_main_show_console = +{ 0x2d89a8a, 0x5f7d, 0x41c3, { 0xa2, 0x15, 0x67, 0x31, 0xd8, 0x62, 0x10, 0x36 } }; // {E6970E91-33BE-4288-AC01-4B02F07B5D38} FOOGUIDDECL const GUID standard_commands::guid_main_play_cd = @@ -819,9 +787,6 @@ FOOGUIDDECL const GUID preferences_page::guid_tag_writing= FOOGUIDDECL const GUID preferences_page::guid_media_library= { 0x2d269fa9, 0x6f78, 0x4cec, { 0x9f, 0x1f, 0xa, 0x17, 0x6e, 0xfc, 0xe7, 0x7a } }; -FOOGUIDDECL const GUID preferences_page::guid_output = { 0xa9038870, 0xdc08, 0x431d, { 0x8c, 0x91, 0x3b, 0x4e, 0x41, 0xd2, 0x43, 0x6d } }; -FOOGUIDDECL const GUID preferences_page::guid_advanced = { 0x56eb56ab, 0xedfe, 0x4853, { 0x90, 0xf7, 0xc6, 0xb8, 0x34, 0xfa, 0x2f, 0x6b } }; -FOOGUIDDECL const GUID preferences_page::guid_components = { 0xe966267, 0x7dfb, 0x433b, { 0xa0, 0x7c, 0x3f, 0x8c, 0xdd, 0x31, 0xa2, 0x58 } }; // {B8C5CEEA-A5F4-4278-AA2D-798E4403001F} FOOGUIDDECL const GUID library_viewer::class_guid= { 0xb8c5ceea, 0xa5f4, 0x4278, { 0xaa, 0x2d, 0x79, 0x8e, 0x44, 0x3, 0x0, 0x1f } }; @@ -836,9 +801,6 @@ FOOGUIDDECL const GUID input_decoder_v3::class_guid = { 0x953c71ed, 0xd3a2, 0x43 FOOGUIDDECL const GUID input_decoder_v4::class_guid = { 0x7bbf10b5, 0x2064, 0x4da2,{ 0x8a, 0x72, 0xeb, 0x4c, 0xe9, 0xb3, 0xa0, 0xb4 } }; FOOGUIDDECL const GUID input_params::seeking_expensive = { 0x10973582, 0x1aae, 0x4169, { 0xb9, 0x76, 0xb5, 0xbe, 0xf9, 0x4b, 0x7a, 0x71 } }; FOOGUIDDECL const GUID input_params::set_preferred_sample_rate = { 0x7dc7f926, 0x9b9f, 0x4a73, { 0xa2, 0x37, 0x83, 0xe9, 0x93, 0x38, 0x41, 0x75 } }; -FOOGUIDDECL const GUID input_params::query_position = { 0xa9d79933, 0x5438, 0x480f, { 0x85, 0xf3, 0xb6, 0xb8, 0xee, 0x1e, 0xfa, 0xe9 } }; -FOOGUIDDECL const GUID input_params::continue_stream = { 0x673050df, 0x11f6, 0x4039, { 0x8b, 0x4, 0x6c, 0x31, 0x98, 0x91, 0x4b, 0x89 } }; - // {8E9BB1D4-A52B-4df6-A929-1AAE4075388A} FOOGUIDDECL const GUID input_info_reader::class_guid = @@ -856,23 +818,13 @@ FOOGUIDDECL const GUID input_entry::class_guid = FOOGUIDDECL const GUID input_entry_v2::class_guid = { 0x7037df35, 0xd246, 0x4cdd,{ 0xb2, 0x24, 0x8, 0xcf, 0x44, 0x4c, 0xe4, 0xce } }; -FOOGUIDDECL const GUID input_entry_v3::class_guid = { 0x7099fac8, 0x10ee, 0x4906, { 0xa3, 0x13, 0xb9, 0x8c, 0x69, 0x74, 0xe7, 0xb9 } }; - #ifdef FOOBAR2000_DESKTOP FOOGUIDDECL const GUID input_manager::class_guid = { 0x291fccfd, 0xe7de, 0x4e08,{ 0x8d, 0xef, 0x6b, 0xe5, 0xf8, 0x23, 0xc4, 0x9a } }; -FOOGUIDDECL const GUID input_manager_v2::class_guid = { 0x81b36d9e, 0x4fb6, 0x4788, { 0xa1, 0x2c, 0x40, 0xc0, 0x64, 0x82, 0xe5, 0xc6 } }; -FOOGUIDDECL const GUID input_manager_v3::class_guid = { 0xc1c414be, 0x74f, 0x41f0, { 0xb8, 0x7f, 0x29, 0x2e, 0xad, 0x50, 0xc0, 0x76 } }; FOOGUIDDECL const GUID input_stream_selector::class_guid = { 0x2a511979, 0x2e57, 0x438a,{ 0x9a, 0x6e, 0x37, 0x3c, 0x25, 0x2, 0xd7, 0x63 } }; FOOGUIDDECL const GUID input_stream_info_reader::class_guid = { 0x934f1361, 0x9c18, 0x497a,{ 0xb6, 0xef, 0xc0, 0x4e, 0xa1, 0x66, 0x3e, 0xab } }; FOOGUIDDECL const GUID input_stream_info_reader_entry::class_guid = { 0xb53b66f2, 0x7cd3, 0x4ce2,{ 0xbf, 0x63, 0x7b, 0xcf, 0xcf, 0xa1, 0xb2, 0x8f } }; FOOGUIDDECL const GUID input_stream_manipulator::class_guid = { 0xc258aa65, 0x961a, 0x4e8e,{ 0x83, 0x98, 0xcc, 0x88, 0xd2, 0xba, 0xe0, 0x5d } }; FOOGUIDDECL const GUID input_stream_manipulator_callback::class_guid = { 0x88ce44b6, 0x8721, 0x440f,{ 0x9e, 0xab, 0xbd, 0xc6, 0x63, 0xed, 0xe1, 0x73 } }; -FOOGUIDDECL const GUID input_info_filter::class_guid = { 0xd64af9aa, 0x1c0d, 0x4dd9, { 0xa3, 0x49, 0x2, 0xa3, 0x77, 0xbd, 0x7a, 0xf2 } }; -FOOGUIDDECL const GUID input_info_filter_v2::class_guid = { 0x7a2023cb, 0xfb7c, 0x4f04, { 0xa5, 0x45, 0x7f, 0xbd, 0x52, 0x92, 0x31, 0x92 } }; -FOOGUIDDECL const GUID input_stream_info_filter::class_guid = { 0xfd056bba, 0xc6a1, 0x40b5, { 0xa6, 0x17, 0x37, 0xb9, 0x71, 0x34, 0xb4, 0xc6 } }; -FOOGUIDDECL const GUID input_playback_shim::class_guid = { 0xaf8aea76, 0x144f, 0x4770, { 0x8d, 0x84, 0x7, 0x27, 0x22, 0x8f, 0x29, 0x8 } }; - -FOOGUIDDECL const GUID preferences_page::guid_input_info_filter = { 0xf9de8ee1, 0x9a5b, 0x4bbd, { 0xb4, 0x62, 0xef, 0x7b, 0x3a, 0xa5, 0x0, 0x24 } }; #endif // {3296219B-EBA5-4c32-A193-C9BB174801DA} @@ -1094,8 +1046,6 @@ FOOGUIDDECL const GUID advconfig_entry::guid_branch_tools = { 0x35365484, 0xcc58 FOOGUIDDECL const GUID advconfig_entry::guid_branch_playback = { 0xc48d430d, 0x112, 0x4922, { 0x97, 0x23, 0x28, 0x38, 0xc7, 0xd9, 0x7d, 0xd7 } }; FOOGUIDDECL const GUID advconfig_entry::guid_branch_display = { 0x6c4bc1c8, 0xbaf4, 0x40c3, { 0x9d, 0xb1, 0x9, 0x50, 0x7f, 0xc, 0xc, 0xb9 } }; FOOGUIDDECL const GUID advconfig_entry::guid_branch_debug = { 0xc375447d, 0x58e6, 0x4fd5, { 0xbd, 0xd8, 0x99, 0xfa, 0xef, 0x7b, 0x30, 0x9f } }; -FOOGUIDDECL const GUID advconfig_entry::guid_branch_tagging_general = { 0x1a7757de, 0x55bd, 0x4c25, { 0xb2, 0xf9, 0xc6, 0x3a, 0x85, 0x0, 0xba, 0xed } }; - @@ -1106,7 +1056,6 @@ FOOGUIDDECL const GUID preferences_branch_v2::class_guid = { 0x167ebeb9, 0x8334, - FOOGUIDDECL const GUID advconfig_entry_enum::class_guid = { 0xb1451540, 0x98ec, 0x4d36, { 0x9f, 0x19, 0xe3, 0x10, 0xfb, 0xa7, 0xab, 0x5a } }; FOOGUIDDECL const GUID info_lookup_handler::class_guid = { 0x4fcfdab7, 0x55b5, 0x47d6, { 0xb1, 0x9d, 0xa4, 0xdc, 0x9f, 0xd7, 0x69, 0x4c } }; @@ -1117,9 +1066,6 @@ FOOGUIDDECL const GUID completion_notify::class_guid = { 0xdf26d586, 0xf7ec, 0x4 FOOGUIDDECL const GUID metadb_io_v2::class_guid = { 0x265c4ece, 0xffb2, 0x4299, { 0x91, 0xb5, 0x6c, 0xa6, 0x60, 0x3d, 0xa1, 0x53 } }; FOOGUIDDECL const GUID file_info_filter::class_guid = { 0x45d0b800, 0xde83, 0x4a77, { 0xad, 0x34, 0x3f, 0x84, 0x2d, 0x40, 0xe7, 0x95 } }; -FOOGUIDDECL const GUID file_info_filter_v2::class_guid = { 0x9bb4da92, 0xd334, 0x4f18, { 0x91, 0xc1, 0x91, 0x9f, 0xb2, 0xf4, 0x4f, 0x30 } }; - - FOOGUIDDECL const GUID metadb_hint_list::class_guid = { 0x719dc072, 0x8d4d, 0x4aa6, { 0xa6, 0xf3, 0x90, 0x73, 0x7, 0xe5, 0xbc, 0xee } }; @@ -1241,8 +1187,6 @@ FOOGUIDDECL const GUID library_file_move_manager::class_guid = { 0xc4cd4818, 0xe FOOGUIDDECL const GUID library_file_move_notify::class_guid = { 0xd8ae7613, 0x7577, 0x4192, { 0x8f, 0xa4, 0x2d, 0x8f, 0x7e, 0xc6, 0x6, 0x38 } }; FOOGUIDDECL const GUID library_meta_autocomplete::class_guid = { 0x4b976e34, 0xf05a, 0x4da4, { 0xad, 0x65, 0x71, 0x9c, 0xdf, 0xd, 0xed, 0xae } }; -FOOGUIDDECL const GUID library_meta_autocomplete_v2::class_guid = { 0xd60d585e, 0xb42e, 0x4a6e, { 0x8f, 0x24, 0x27, 0x50, 0x71, 0x1a, 0x87, 0x30 } }; - FOOGUIDDECL const GUID input_protocol_type::class_guid = { 0x6a03c4ee, 0xf87b, 0x49d7, { 0x81, 0xdb, 0x66, 0xb, 0xe8, 0xc1, 0x0, 0x7e } }; @@ -1263,7 +1207,6 @@ FOOGUIDDECL const GUID album_art_fallback::class_guid = { 0x45481581, 0x40b3, 0x FOOGUIDDECL const GUID preferences_page_callback::class_guid = { 0x3d26e08e, 0x861c, 0x4599, { 0x9c, 0x89, 0xaa, 0xa7, 0x19, 0xaf, 0x50, 0x70 } }; FOOGUIDDECL const GUID preferences_page_instance::class_guid = { 0x6893a996, 0xa816, 0x49fe, { 0x82, 0xce, 0xc, 0xb8, 0x4, 0xa4, 0xcf, 0xec } }; FOOGUIDDECL const GUID preferences_page_v3::class_guid = { 0xd6d0f741, 0x9f17, 0x4df8, { 0x9d, 0x5c, 0x87, 0xf2, 0x8b, 0x1f, 0xe, 0x64 } }; -FOOGUIDDECL const GUID preferences_page_v4::class_guid = { 0x76227dab, 0xc740, 0x4d49, { 0xa2, 0xe2, 0x50, 0x80, 0x13, 0xe, 0xf6, 0xba } }; FOOGUIDDECL const GUID advconfig_entry_string_v2::class_guid = { 0x2ec9b1fa, 0xe1e4, 0x42f0, { 0x87, 0x97, 0x4a, 0x63, 0x16, 0x94, 0x86, 0xbc } }; FOOGUIDDECL const GUID advconfig_entry_checkbox_v2::class_guid = { 0xe29b37d0, 0xa957, 0x4a85, { 0x82, 0x40, 0x1e, 0x96, 0xc7, 0x29, 0xb6, 0x69 } }; @@ -1298,7 +1241,6 @@ FOOGUIDDECL const GUID playback_stream_capture::class_guid = { 0x9423439e, 0x8cd FOOGUIDDECL const GUID http_request::class_guid = { 0x48580056, 0x2c5f, 0x45a8, { 0xb8, 0x6e, 0x5, 0x83, 0x55, 0x3e, 0xaa, 0x4f } }; FOOGUIDDECL const GUID http_request_post::class_guid = { 0xe254b804, 0xeac5, 0x4be0, { 0x99, 0x4d, 0x53, 0x1c, 0x17, 0xea, 0xfd, 0x37 } }; -FOOGUIDDECL const GUID http_request_post_v2::class_guid = { 0x95309335, 0xd301, 0x4946, { 0x99, 0x27, 0x2d, 0xb7, 0x9b, 0x22, 0x46, 0x9c } }; FOOGUIDDECL const GUID http_client::class_guid = { 0x3b5ffe0c, 0xd75a, 0x491e, { 0xbb, 0x6f, 0x10, 0x3f, 0x73, 0x1e, 0x81, 0x84 } }; FOOGUIDDECL const GUID http_reply::class_guid = { 0x7f02bf78, 0x5c98, 0x4d6d, { 0x83, 0x6b, 0xb7, 0x77, 0xa4, 0xa3, 0x3e, 0xe5 } }; @@ -1331,14 +1273,9 @@ FOOGUIDDECL const GUID track_property_provider_v3::class_guid = { 0xdbbce29c, 0x FOOGUIDDECL const GUID output::class_guid = { 0xb9632c4f, 0x596e, 0x43ee, { 0xb2, 0x14, 0x71, 0x4, 0x48, 0x4b, 0x65, 0xf1 } }; FOOGUIDDECL const GUID output_entry::class_guid = { 0xe7480b4f, 0x4941, 0x4dd2, { 0xad, 0xbf, 0x96, 0x6c, 0x76, 0x63, 0x43, 0x92 } }; FOOGUIDDECL const GUID output_entry_v2::class_guid = { 0xaacc17f3, 0xb7cc, 0x48c2, { 0x95, 0x6e, 0x52, 0xba, 0x72, 0x89, 0x42, 0xe5 } }; -FOOGUIDDECL const GUID output_entry_v3::class_guid = { 0xfa18060e, 0xfc84, 0x4f53, { 0xa8, 0xe3, 0x60, 0xc5, 0xf5, 0x22, 0x50, 0x7a } }; FOOGUIDDECL const GUID volume_control::class_guid = { 0x39f9fc0c, 0x4dc9, 0x4a7a, { 0xb9, 0xad, 0x75, 0x8b, 0x78, 0x57, 0x78, 0xad } }; FOOGUIDDECL const GUID output_v2::class_guid = { 0x4f679e4b, 0x79e0, 0x4fc9, { 0x90, 0x27, 0x55, 0x49, 0x85, 0x72, 0x26, 0xbf } }; FOOGUIDDECL const GUID output_v3::class_guid = { 0x3b764d8e, 0x6c1c, 0x40bd, { 0x9a, 0x7e, 0xac, 0x3, 0x2a, 0x3e, 0x25, 0xf1 } }; -FOOGUIDDECL const GUID output_v4::class_guid = { 0x2c7a21a, 0xcc12, 0x48f3, { 0x89, 0x2e, 0xa7, 0x98, 0xb0, 0xc8, 0xaa, 0x49 } }; -FOOGUIDDECL const GUID output_v5::class_guid = { 0x735e6e3f, 0x95d8, 0x45ca, { 0xad, 0x1a, 0xca, 0x88, 0x1f, 0x1d, 0x5c, 0xfa } }; - - FOOGUIDDECL const GUID output_manager::class_guid = { 0x6cc5827e, 0x2c89, 0x42ff, { 0x83, 0x51, 0x76, 0xa9, 0x2e, 0x2f, 0x34, 0x50 } }; FOOGUIDDECL const GUID output_manager_v2::class_guid = { 0xcc8aa352, 0x7af1, 0x41d2, { 0x94, 0x7e, 0xa2, 0x65, 0x17, 0x5b, 0x68, 0x96 } }; @@ -1357,6 +1294,7 @@ FOOGUIDDECL const GUID ui_element_replace_dialog_notify::class_guid = { 0x95f925 FOOGUIDDECL const GUID ui_element_popup_host::class_guid = { 0xfcc381e9, 0xe527, 0x4887,{ 0xae, 0x63, 0x27, 0xc0, 0x3f, 0x4, 0xd, 0x1 } }; FOOGUIDDECL const GUID ui_element_popup_host_callback::class_guid = { 0x2993a043, 0x2e70, 0x4d8f,{ 0x81, 0xb, 0x41, 0x3, 0x37, 0x73, 0x97, 0xcd } }; FOOGUIDDECL const GUID ui_element_config::class_guid = { 0xd34bba46, 0x1bad, 0x4547,{ 0xba, 0xb4, 0x17, 0xe2, 0x44, 0xd5, 0xeb, 0x94 } }; +FOOGUIDDECL const GUID ui_element_typable_window_manager::class_guid = { 0xbaa99ee2, 0xf770, 0x4981,{ 0x9e, 0x50, 0xf3, 0x4c, 0x5c, 0x6d, 0x98, 0x81 } }; FOOGUIDDECL const GUID ui_element_instance_callback_v3::class_guid = { 0x6d15c0c6, 0x90b6, 0x4c7e,{ 0xbf, 0x39, 0xe9, 0x39, 0xf2, 0xdf, 0x9b, 0x91 } }; FOOGUIDDECL const GUID ui_element_popup_host_v2::class_guid = { 0x8caac11e, 0x52b6, 0x47f7,{ 0x97, 0xc9, 0x2c, 0x87, 0xdb, 0xdb, 0x2e, 0x5b } }; @@ -1382,32 +1320,5 @@ FOOGUIDDECL const GUID playlist_incoming_item_filter_v4::class_guid = { 0x9bd438 FOOGUIDDECL const GUID file_lock::class_guid = { 0xb2f0b2f8, 0x1ccf, 0x438e, { 0xb9, 0x75, 0x9f, 0x5b, 0x75, 0x5a, 0xa3, 0x2e } }; FOOGUIDDECL const GUID file_lock_manager::class_guid = { 0xa808fe53, 0xd36, 0x42fb, { 0xac, 0x2, 0x6a, 0xc8, 0x9c, 0xcb, 0x24, 0xbe } }; -FOOGUIDDECL const GUID file_lock_manager_v2::class_guid = { 0x30c07c6a, 0xde51, 0x4094, { 0x82, 0xe6, 0xf1, 0x57, 0xd1, 0xb2, 0x3a, 0xe8 } }; -FOOGUIDDECL const GUID file_lock_interrupt::class_guid = { 0x73ebabc8, 0xfe66, 0x4dae, { 0x95, 0x90, 0x3d, 0xa3, 0x9f, 0x17, 0x19, 0x15 } }; - -FOOGUIDDECL const GUID track_property_provider_v4::class_guid = { 0x707abb57, 0x35f7, 0x41c3, { 0xac, 0x43, 0xc9, 0xb6, 0xc, 0xc6, 0xa9, 0xae } }; - - -FOOGUIDDECL const GUID album_art_extractor_v2::class_guid = { 0x3aa31001, 0xaf5b, 0x497a, { 0xbd, 0xdc, 0xa9, 0x3f, 0x23, 0xb2, 0x1b, 0xc2 } }; -FOOGUIDDECL const GUID album_art_editor_v2::class_guid = { 0xf16827d3, 0xca20, 0x44fe, { 0x94, 0xe0, 0x56, 0xd7, 0x2d, 0x35, 0x81, 0x6 } }; - - -FOOGUIDDECL const GUID replaygain_scanner_config::class_guid = { 0x210970e1, 0xa478, 0x4d76, { 0xa5, 0x7c, 0x95, 0x9, 0xae, 0x82, 0xae, 0x41 } }; - -#if FOOBAR2000_TARGET_VERSION >= 80 -FOOGUIDDECL const GUID metadb_io_v4::class_guid = { 0x6ec07034, 0xd5c2, 0x4fb5, { 0xb7, 0x59, 0x7d, 0x12, 0x4f, 0xa7, 0x27, 0xf4 } }; -FOOGUIDDECL const GUID popup_message_v3::class_guid = { 0xef3c83fd, 0x1144, 0x4edb, { 0xb8, 0x43, 0xcf, 0xba, 0xc6, 0xe5, 0xe1, 0x8b } }; -#endif // FOOBAR2000_TARGET_VERSION >= 80 - -FOOGUIDDECL const GUID file_lowLevelIO::class_guid = { 0xbcacb272, 0x8e6c, 0x4d23, { 0x91, 0x9a, 0xe, 0xaa, 0x55, 0x2e, 0xc9, 0x70 } }; -FOOGUIDDECL const GUID file_lowLevelIO::guid_flushFileBuffers = { 0xace5356b, 0x8c72, 0x408a, { 0x8e, 0x32, 0x78, 0x1e, 0x7d, 0x7f, 0xe9, 0x97 } }; -FOOGUIDDECL const GUID file_lowLevelIO::guid_getFileTimes = { 0xb5a3cd80, 0x23ae, 0x4c51, { 0x83, 0x3b, 0xa5, 0x98, 0x6b, 0xe1, 0xec, 0x59 } }; -FOOGUIDDECL const GUID file_lowLevelIO::guid_setFileTimes = { 0x46501e0d, 0x644d, 0x4d00, { 0xaf, 0x8c, 0xc5, 0xc1, 0xb, 0x34, 0xae, 0x37 } }; - FOOGUIDDECL const GUID async_task_manager::class_guid = { 0xea055f49, 0x7c6d, 0x4695, { 0x8c, 0xf, 0xeb, 0xbd, 0x92, 0xdb, 0xa7, 0xa7 } }; - -FOOGUIDDECL const GUID read_ahead_tools::class_guid = { 0x709671bf, 0x449a, 0x4dc8, { 0x9f, 0xcf, 0x84, 0xb3, 0xbc, 0xec, 0x98, 0x4d } }; - -FOOGUIDDECL const GUID fb2k::imageLoaderLite::class_guid = { 0xbe06ead9, 0x1c9, 0x42e0, { 0x9f, 0x9f, 0x12, 0xb2, 0xde, 0x95, 0xca, 0x96 } }; -FOOGUIDDECL const GUID fb2k::imageViewer::class_guid = { 0xdbdaaa24, 0x2f90, 0x426c, { 0x86, 0x3, 0x1c, 0x5a, 0xe5, 0xf9, 0x82, 0x21 } }; diff --git a/foobar2000/SDK/hasher_md5.h b/foobar2000/SDK/hasher_md5.h index a83882d..1223eba 100644 --- a/foobar2000/SDK/hasher_md5.h +++ b/foobar2000/SDK/hasher_md5.h @@ -14,13 +14,6 @@ struct hasher_md5_result { static hasher_md5_result null() {hasher_md5_result h = {}; return h;} }; -FB2K_STREAM_READER_OVERLOAD(hasher_md5_result) { - stream.read_raw(&value, sizeof(value)); return stream; -} -FB2K_STREAM_WRITER_OVERLOAD(hasher_md5_result) { - stream.write_raw(&value, sizeof(value)); return stream; -} - inline bool operator==(const hasher_md5_result & p_item1,const hasher_md5_result & p_item2) {return memcmp(&p_item1,&p_item2,sizeof(hasher_md5_result)) == 0;} inline bool operator!=(const hasher_md5_result & p_item1,const hasher_md5_result & p_item2) {return memcmp(&p_item1,&p_item2,sizeof(hasher_md5_result)) != 0;} @@ -81,7 +74,7 @@ private: template class stream_formatter_hasher_md5 : public stream_writer_formatter { public: - stream_formatter_hasher_md5() : stream_writer_formatter(_m_stream,fb2k::noAbort) {} + stream_formatter_hasher_md5() : stream_writer_formatter(_m_stream,_m_abort) {} hasher_md5_result result() const { return _m_stream.result(); @@ -90,5 +83,6 @@ public: return hasher_md5::guid_from_result(result()); } private: + abort_callback_dummy _m_abort; stream_writer_hasher_md5 _m_stream; }; diff --git a/foobar2000/SDK/http_client.h b/foobar2000/SDK/http_client.h index 4bba21b..c999ee1 100644 --- a/foobar2000/SDK/http_client.h +++ b/foobar2000/SDK/http_client.h @@ -41,13 +41,6 @@ public: void add_post_data(const char * name, const char * value) { add_post_data(name, value, strlen(value), "", ""); } }; -//! \since 1.5 -class NOVTABLE http_request_post_v2 : public http_request_post { - FB2K_MAKE_SERVICE_INTERFACE(http_request_post_v2, http_request_post); -public: - virtual void set_post_data(const void* blob, size_t bytes, const char* contentType) = 0; -}; - class NOVTABLE http_client : public service_base { FB2K_MAKE_SERVICE_COREAPI(http_client) public: diff --git a/foobar2000/SDK/imageLoaderLite.h b/foobar2000/SDK/imageLoaderLite.h deleted file mode 100644 index c12e7e7..0000000 --- a/foobar2000/SDK/imageLoaderLite.h +++ /dev/null @@ -1,52 +0,0 @@ -#pragma once - -#ifdef _WIN32 -namespace Gdiplus { - class Image; -} -#endif -namespace fb2k { -#ifdef _WIN32 - typedef Gdiplus::Image * nativeImage_t; -#else - typedef void * nativeImage_t; -#endif - - struct imageInfo_t { - uint32_t width, height, bitDepth; - bool haveAlpha; - const char * formatName; - const char * mime; - }; - - //! \since 1.6 - //! Interface to common image loader routines that turn a bytestream into a image that can be drawn in a window. \n - //! Windows: Using imageLoaderLite methods initializes gdiplus if necessary, leaving gdiplus initialized for the rest of app lifetime. \n - //! If your component supports running on foobar2000 older than 1.6, use tryGet() to gracefully fall back to your own image loader: \n - //! auto api = fb2k::imageLoaderLite::tryGet(); if (api.is_valid()) { do stuff with api; } else { use fallbacks; } - class imageLoaderLite : public service_base { - FB2K_MAKE_SERVICE_COREAPI(imageLoaderLite); - public: - //! Throws excpetions on failure, returns valid image otherwise.\n - //! Caller takes ownership of the returned object. \n - //! @param outInfo Optional struct to receive information about the loaded image. - virtual nativeImage_t load(const void * data, size_t bytes, imageInfo_t * outInfo = nullptr, abort_callback & aborter = fb2k::noAbort) = 0; - - //! Parses the image data just enough to hand over basic info about what's inside. \n - //! Much faster than load(). \n - //! Supports all formats recognized by load(). - virtual imageInfo_t getInfo(const void * data, size_t bytes, abort_callback & aborter = fb2k::noAbort) = 0; - - //! Helper - made virtual so it can be possibly specialized in the future - virtual nativeImage_t load(album_art_data_ptr data, imageInfo_t * outInfo = nullptr, abort_callback & aborter = fb2k::noAbort) { - return load(data->get_ptr(), data->get_size(), outInfo, aborter); - } - //! Helper - made virtual so it can be possibly specialized in the future - virtual imageInfo_t getInfo(album_art_data_ptr data, abort_callback & aborter = fb2k::noAbort) { - return getInfo(data->get_ptr(), data->get_size(), aborter); - } - }; -} - -#define FB2K_GETOPENFILENAME_PICTUREFILES "Picture files|*.jpg;*.jpeg;*.png;*.bmp;*.gif;*.webp" -#define FB2K_GETOPENFILENAME_PICTUREFILES_ALL FB2K_GETOPENFILENAME_PICTUREFILES "|All files|*.*" \ No newline at end of file diff --git a/foobar2000/SDK/imageViewer.h b/foobar2000/SDK/imageViewer.h deleted file mode 100644 index ccf3d07..0000000 --- a/foobar2000/SDK/imageViewer.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -namespace fb2k { - //! \since 1.6.2 - class imageViewer : public service_base { - FB2K_MAKE_SERVICE_COREAPI(imageViewer); - public: - //! Spawns an image viewer window, showing the specified picture already loaded into application memory. - virtual void show(HWND parent, fb2k::memBlockRef data) = 0; - //! Spawns an image viewer window, showing album art from the specified list of items. - //! @param aaType Type of picture to load, front cover, back cover or other. - //! @param pageno Reserved for future use, set to 0. - virtual void load_and_show(HWND parent, metadb_handle_list_cref items, const GUID & aaType, unsigned pageno = 0) = 0; - }; -} \ No newline at end of file diff --git a/foobar2000/SDK/initquit.h b/foobar2000/SDK/initquit.h index 107ce50..a95eba9 100644 --- a/foobar2000/SDK/initquit.h +++ b/foobar2000/SDK/initquit.h @@ -24,7 +24,6 @@ namespace init_stages { before_config_read = 10, after_config_read = 20, before_library_init = 30, - // Since foobar2000 v2.0, after_library_init is fired OUT OF ORDER with the rest, after ASYNCHRONOUS library init has completed. after_library_init = 40, before_ui_init = 50, after_ui_init = 60, diff --git a/foobar2000/SDK/input.cpp b/foobar2000/SDK/input.cpp index d4551ae..11eb266 100644 --- a/foobar2000/SDK/input.cpp +++ b/foobar2000/SDK/input.cpp @@ -1,15 +1,21 @@ -#include "foobar2000.h" // PCH -#ifdef FOOBAR2000_MODERN -#include "foobar2000-input.h" -#include -#include -#endif -#include -#include "album_art.h" -#include "file_info_impl.h" - -service_ptr input_entry::open(const GUID & whatFor, file::ptr hint, const char * path, event_logger::ptr logger, abort_callback & aborter) { +#include "foobar2000.h" +service_ptr input_entry::open(const GUID & whatFor, file::ptr hint, const char * path, abort_callback & aborter) { + if (whatFor == input_decoder::class_guid) { + input_decoder::ptr obj; + open(obj, hint, path, aborter); + return obj; + } + if (whatFor == input_info_reader::class_guid) { + input_info_reader::ptr obj; + open(obj, hint, path, aborter); + return obj; + } + if (whatFor == input_info_writer::class_guid) { + input_info_writer::ptr obj; + open(obj, hint, path, aborter); + return obj; + } #ifdef FOOBAR2000_DESKTOP if ( whatFor == input_stream_info_reader::class_guid ) { input_entry_v2::ptr v2; @@ -26,62 +32,7 @@ service_ptr input_entry::open(const GUID & whatFor, file::ptr hint, const char * throw exception_io_unsupported_format(); } #endif - if ( whatFor == album_art_extractor_instance::class_guid ) { - input_entry_v2::ptr v2; - if (v2 &= this) { - GUID g = v2->get_guid(); - service_enum_t e; - album_art_extractor_v2::ptr p; - while( e.next(p) ) { - if ( p->get_guid() == g ) { - return p->open( hint, path, aborter ); - } - } - } - throw exception_io_unsupported_format(); - } - if ( whatFor == album_art_editor_instance::class_guid ) { - input_entry_v2::ptr v2; - if (v2 &= this) { - GUID g = v2->get_guid(); - service_enum_t e; - album_art_editor_v2::ptr p; - while( e.next(p) ) { - if ( p->get_guid() == g ) { - return p->open( hint, path, aborter ); - } - } - } - throw exception_io_unsupported_format(); - } - - input_entry_v3::ptr v3; - - if (v3 &= this) { - return v3->open_v3( whatFor, hint, path, logger, aborter ); - } else { - if (whatFor == input_decoder::class_guid) { - input_decoder::ptr obj; - open(obj, hint, path, aborter); - if ( logger.is_valid() ) { - input_decoder_v2::ptr v2; - if (v2 &= obj) v2->set_logger(logger); - } - return obj; - } - if (whatFor == input_info_reader::class_guid) { - input_info_reader::ptr obj; - open(obj, hint, path, aborter); - return obj; - } - if (whatFor == input_info_writer::class_guid) { - input_info_writer::ptr obj; - open(obj, hint, path, aborter); - return obj; - } - } - - throw pfc::exception_not_implemented(); + uBugCheck(); } bool input_entry::g_find_service_by_path(service_ptr_t & p_out,const char * p_path) @@ -155,41 +106,24 @@ static void prepare_for_open(service_ptr_t & p_service,service_ptr_ #endif bool input_entry::g_find_inputs_by_content_type(pfc::list_base_t > & p_out, const char * p_content_type, bool p_from_redirect) { - auto filter = [=] (input_entry::ptr p) { - return !(p_from_redirect && p->is_redirect()); - }; - return g_find_inputs_by_content_type_ex(p_out, p_content_type, filter ); -} - -bool input_entry::g_find_inputs_by_path(pfc::list_base_t > & p_out, const char * p_path, bool p_from_redirect) { - auto filter = [=] (input_entry::ptr p) { - return !(p_from_redirect && p->is_redirect()); - }; - return g_find_inputs_by_path_ex(p_out, p_path, filter); -} - -bool input_entry::g_find_inputs_by_content_type_ex(pfc::list_base_t > & p_out, const char * p_content_type, input_filter_t filter ) { service_enum_t e; service_ptr_t ptr; bool ret = false; while (e.next(ptr)) { - if ( filter(ptr) ) { + if (!(p_from_redirect && ptr->is_redirect())) { if (ptr->is_our_content_type(p_content_type)) { p_out.add_item(ptr); ret = true; } } } return ret; } -bool input_entry::g_find_inputs_by_path_ex(pfc::list_base_t > & p_out, const char * p_path, input_filter_t filter ) { +bool input_entry::g_find_inputs_by_path(pfc::list_base_t > & p_out, const char * p_path, bool p_from_redirect) { service_enum_t e; service_ptr_t ptr; auto extension = pfc::string_extension(p_path); bool ret = false; while (e.next(ptr)) { - GUID guid = pfc::guid_null; - input_entry_v3::ptr ex; - if ( ex &= ptr ) guid = ex->get_guid(); - if ( filter(ptr) ) { + if (!(p_from_redirect && ptr->is_redirect())) { if (ptr->is_our_path(p_path, extension)) { p_out.add_item(ptr); ret = true; } } } @@ -204,82 +138,50 @@ static GUID input_get_guid( input_entry::ptr e ) { return pfc::guid_null; } -service_ptr input_entry::g_open_from_list(input_entry_list_t const & p_list, const GUID & whatFor, service_ptr_t p_filehint, const char * p_path, event_logger::ptr logger, abort_callback & p_abort, GUID * outGUID) { +service_ptr input_entry::g_open_from_list(input_entry_list_t const & p_list, const GUID & whatFor, service_ptr_t p_filehint, const char * p_path, abort_callback & p_abort, GUID * outGUID) { const t_size count = p_list.get_count(); if ( count == 0 ) { // sanity throw exception_io_unsupported_format(); } else if (count == 1) { - auto ret = p_list[0]->open(whatFor, p_filehint, p_path, logger, p_abort); + auto ret = p_list[0]->open(whatFor, p_filehint, p_path, p_abort); if ( outGUID != nullptr ) * outGUID = input_get_guid( p_list[0] ); return ret; } else { - std::exception_ptr errData, errUnsupported; + unsigned bad_data_count = 0; + pfc::string8 bad_data_message; for (t_size n = 0; n < count; n++) { try { - auto ret = p_list[n]->open(whatFor, p_filehint, p_path, logger, p_abort); + auto ret = p_list[n]->open(whatFor, p_filehint, p_path, p_abort); if (outGUID != nullptr) * outGUID = input_get_guid(p_list[n]); return ret; } catch (exception_io_no_handler_for_path) { //do nothing, skip over - } catch(exception_io_unsupported_format) { - if (!errUnsupported) errUnsupported = std::current_exception(); - } catch (exception_io_data) { - if (!errData) errData = std::current_exception(); + } catch (exception_io_unsupported_format) { + //do nothing, skip over + } catch (exception_io_data const & e) { + if (bad_data_count++ == 0) bad_data_message = e.what(); } } - if (errData) std::rethrow_exception(errData); - if (errUnsupported) std::rethrow_exception(errUnsupported); - throw exception_io_unsupported_format(); + if (bad_data_count > 1) throw exception_io_data(); + else if (bad_data_count == 0) pfc::throw_exception_with_message(bad_data_message); + else throw exception_io_unsupported_format(); } } -#ifdef FOOBAR2000_DESKTOP -service_ptr input_manager::open_v2(const GUID & whatFor, file::ptr hint, const char * path, bool fromRedirect, event_logger::ptr logger, abort_callback & aborter, GUID * outUsedEntry) { - // We're wrapping open_v2() on top of old open(). - // Assert on GUIDs that old open() is known to recognize. - PFC_ASSERT(whatFor == input_decoder::class_guid || whatFor == input_info_reader::class_guid || whatFor == input_info_writer::class_guid || whatFor == input_stream_selector::class_guid); - - { - input_manager_v2::ptr v2; - if ( v2 &= this ) { - return v2->open_v2( whatFor, hint, path, fromRedirect, logger, aborter, outUsedEntry ); - } - } - - auto ret = open( whatFor, hint, path, fromRedirect, aborter, outUsedEntry ); - -#ifdef FB2K_HAVE_EVENT_LOGGER - if ( logger.is_valid() ) { - input_decoder_v2::ptr dec; - if (dec &= ret) { - dec->set_logger(logger); - } - } -#endif - return ret; -} -#endif - -service_ptr input_entry::g_open(const GUID & whatFor, file::ptr p_filehint, const char * p_path, event_logger::ptr logger, abort_callback & p_abort, bool p_from_redirect) { +service_ptr input_entry::g_open(const GUID & whatFor, file::ptr p_filehint, const char * p_path, abort_callback & p_abort, bool p_from_redirect) { #ifdef FOOBAR2000_DESKTOP - // #define rationale: not all FOOBAR2000_MODERN flavours come with input_manager implementation, but classic 1.4+ does -#if !defined(FOOBAR2000_MODERN) && FOOBAR2000_TARGET_VERSION >= 79 - -#if FOOBAR2000_TARGET_VERSION > 79 - return input_manager_v2::get()->open_v2(whatFor, p_filehint, p_path, p_from_redirect, logger, p_abort); -#else - return input_manager::get()->open_v2(whatFor, p_filehint, p_path, p_from_redirect, logger, p_abort); +#if FOOBAR2000_TARGET_VERSION >= 79 + return input_manager::get()->open(whatFor, p_filehint, p_path, p_from_redirect, p_abort); #endif -#endif { input_manager::ptr m; service_enum_t e; if (e.next(m)) { - return m->open_v2(whatFor, p_filehint, p_path, p_from_redirect, logger, p_abort); + return m->open(whatFor, p_filehint, p_path, p_from_redirect, p_abort); } } #endif @@ -305,7 +207,7 @@ service_ptr input_entry::g_open(const GUID & whatFor, file::ptr p_filehint, cons #endif if (g_find_inputs_by_content_type(list, content_type, p_from_redirect)) { try { - return g_open_from_list(list, whatFor, l_file, p_path, logger, p_abort); + return g_open_from_list(list, whatFor, l_file, p_path, p_abort); } catch (exception_io_unsupported_format) { #if PFC_DEBUG FB2K_DebugLog() << "Failed to open by content type, using fallback"; @@ -321,7 +223,7 @@ service_ptr input_entry::g_open(const GUID & whatFor, file::ptr p_filehint, cons { pfc::list_t< input_entry::ptr > list; if (g_find_inputs_by_path(list, p_path, p_from_redirect)) { - return g_open_from_list(list, whatFor, l_file, p_path, logger, p_abort); + return g_open_from_list(list, whatFor, l_file, p_path, p_abort); } } @@ -330,17 +232,17 @@ service_ptr input_entry::g_open(const GUID & whatFor, file::ptr p_filehint, cons void input_entry::g_open_for_decoding(service_ptr_t & p_instance,service_ptr_t p_filehint,const char * p_path,abort_callback & p_abort,bool p_from_redirect) { TRACK_CALL_TEXT("input_entry::g_open_for_decoding"); - p_instance ^= g_open(input_decoder::class_guid, p_filehint, p_path, nullptr, p_abort, p_from_redirect); + p_instance ^= g_open(input_decoder::class_guid, p_filehint, p_path, p_abort, p_from_redirect); } void input_entry::g_open_for_info_read(service_ptr_t & p_instance,service_ptr_t p_filehint,const char * p_path,abort_callback & p_abort,bool p_from_redirect) { TRACK_CALL_TEXT("input_entry::g_open_for_info_read"); - p_instance ^= g_open(input_info_reader::class_guid, p_filehint, p_path, nullptr, p_abort, p_from_redirect); + p_instance ^= g_open(input_info_reader::class_guid, p_filehint, p_path, p_abort, p_from_redirect); } void input_entry::g_open_for_info_write(service_ptr_t & p_instance,service_ptr_t p_filehint,const char * p_path,abort_callback & p_abort,bool p_from_redirect) { TRACK_CALL_TEXT("input_entry::g_open_for_info_write"); - p_instance ^= g_open(input_info_writer::class_guid, p_filehint, p_path, nullptr, p_abort, p_from_redirect); + p_instance ^= g_open(input_info_writer::class_guid, p_filehint, p_path, p_abort, p_from_redirect); } void input_entry::g_open_for_info_write_timeout(service_ptr_t & p_instance,service_ptr_t p_filehint,const char * p_path,abort_callback & p_abort,double p_timeout,bool p_from_redirect) { @@ -390,61 +292,12 @@ void input_open_file_helper(service_ptr_t & p_file,const char * p_path,t_i } } -uint32_t input_entry::g_flags_for_path( const char * path, uint32_t mask ) { -#if FOOBAR2000_TARGET_VERSION >= 80 - return input_manager_v3::get()->flags_for_path(path, mask); -#else - input_manager_v3::ptr api; - if ( input_manager_v3::tryGet(api) ) { - return api->flags_for_path(path, mask); - } - uint32_t ret = 0; - service_enum_t e; input_entry::ptr p; - auto ext = pfc::string_extension(path); - while(e.next(p)) { - uint32_t f = p->get_flags() & mask; - if ( f != 0 && p->is_our_path( path, ext ) ) ret |= f;; - } - return ret; -#endif -} -uint32_t input_entry::g_flags_for_content_type( const char * ct, uint32_t mask ) { -#if FOOBAR2000_TARGET_VERSION >= 80 - return input_manager_v3::get()->flags_for_content_type(ct, mask); -#else - input_manager_v3::ptr api; - if ( input_manager_v3::tryGet(api) ) { - return api->flags_for_content_type( ct, mask ); - } - uint32_t ret = 0; - service_enum_t e; input_entry::ptr p; - while(e.next(p)) { - uint32_t f = p->get_flags() & mask; - if ( f != 0 && p->is_our_content_type(ct) ) ret |= f; - } - return ret; -#endif -} - bool input_entry::g_are_parallel_reads_slow(const char * path) { - return g_flags_for_path(path, flag_parallel_reads_slow) != 0; -} - -void input_entry_v3::open_for_decoding(service_ptr_t & p_instance, service_ptr_t p_filehint, const char * p_path, abort_callback & p_abort) { - p_instance ^= open_v3( input_decoder::class_guid, p_filehint, p_path, nullptr, p_abort ); -} -void input_entry_v3::open_for_info_read(service_ptr_t & p_instance, service_ptr_t p_filehint, const char * p_path, abort_callback & p_abort) { - p_instance ^= open_v3(input_info_reader::class_guid, p_filehint, p_path, nullptr, p_abort); -} -void input_entry_v3::open_for_info_write(service_ptr_t & p_instance, service_ptr_t p_filehint, const char * p_path, abort_callback & p_abort) { - p_instance ^= open_v3(input_info_writer::class_guid, p_filehint, p_path, nullptr, p_abort); -} - -void input_info_writer::remove_tags_fallback(abort_callback & abort) { - uint32_t total = this->get_subsong_count(); - file_info_impl blank; - for( uint32_t walk = 0; walk < total; ++ walk ) { - this->set_info( this->get_subsong(walk), blank, abort ); + auto ext = pfc::string_extension(path); + input_entry::ptr svc; + service_enum_t e; + while (e.next(svc)) { + if (svc->is_our_path(path, ext) && svc->are_parallel_reads_slow()) return true; } - this->commit( abort ); -} + return false; +} \ No newline at end of file diff --git a/foobar2000/SDK/input.h b/foobar2000/SDK/input.h index 5169d28..7c7b1a8 100644 --- a/foobar2000/SDK/input.h +++ b/foobar2000/SDK/input.h @@ -1,8 +1,3 @@ -#pragma once -#include -#include "event_logger.h" -#include "audio_chunk.h" - PFC_DECLARE_EXCEPTION(exception_tagging_unsupported, exception_io_data, "Tagging of this file format is not supported") enum { @@ -107,8 +102,8 @@ public: //! Returned raw data should be possible to cut into individual samples; size in bytes should be divisible by audio_chunk's sample count for splitting in case partial output is needed (with cuesheets etc). virtual bool run_raw(audio_chunk & out, mem_block_container & outRaw, abort_callback & abort) = 0; - //! OBSOLETE since 1.5 \n - //! Specify logger when opening to reliably get info generated during input open operation. + //! OPTIONAL, the call is ignored if this implementation doesn't support status logging. \n + //! Mainly used to generate logs when ripping CDs etc. virtual void set_logger(event_logger::ptr ptr) = 0; }; @@ -139,21 +134,6 @@ public: //! Tells the decoder to output at this sample rate if the decoder's sample rate is adjustable. \n //! Sample rate signaled in arg1. static const GUID set_preferred_sample_rate; - - //! Retrieves logical decode position from the decoder. Implemented only in some rare cases where logical position does not match duration of returned data so far. - //! arg2 points to double position in seconds. - //! Return 1 if position was written to arg2, 0 if n/a. - static const GUID query_position; - - struct continue_stream_t { - file::ptr reader; - const char * path; - }; - //! Tells the decoder to continue decoding from another URL, without flushing etc. Mainly used by HLS streams. - //! arg2: continue_stream_t - //! Return 1 to acknowledge, 0 if unsupported. - //! A call to decode_initialize() will follow if you return 1; perform actual file open from there. - static const GUID continue_stream; }; //! Class providing interface for writing metadata and replaygain info to files. Also see: file_info. \n @@ -172,9 +152,6 @@ public: //! @param p_abort abort_callback object signaling user aborting the operation. WARNING: abort_callback object is provided for consistency; if writing tags actually gets aborted, user will be likely left with corrupted file. Anything calling this should make sure that aborting is either impossible, or gives appropriate warning to the user first. virtual void commit(abort_callback & p_abort) = 0; - //! Helper for writers not implementing input_info_writer_v2::remove_tags(). - void remove_tags_fallback(abort_callback & abort); - FB2K_MAKE_SERVICE_INTERFACE(input_info_writer,input_info_reader); }; @@ -245,25 +222,20 @@ public: static void g_open_for_info_write(service_ptr_t & p_instance,service_ptr_t p_filehint,const char * p_path,abort_callback & p_abort,bool p_from_redirect = false); static void g_open_for_info_write_timeout(service_ptr_t & p_instance,service_ptr_t p_filehint,const char * p_path,abort_callback & p_abort,double p_timeout,bool p_from_redirect = false); static bool g_is_supported_path(const char * p_path); - typedef std::function input_filter_t; static bool g_find_inputs_by_content_type(pfc::list_base_t > & p_out, const char * p_content_type, bool p_from_redirect); - static bool g_find_inputs_by_path(pfc::list_base_t > & p_out, const char * p_path, bool p_from_redirect ); - static bool g_find_inputs_by_content_type_ex(pfc::list_base_t > & p_out, const char * p_content_type, input_filter_t filter ); - static bool g_find_inputs_by_path_ex(pfc::list_base_t > & p_out, const char * p_path, input_filter_t filter ); - static service_ptr g_open(const GUID & whatFor, file::ptr hint, const char * path, event_logger::ptr logger, abort_callback & aborter, bool fromRedirect = false); + static bool g_find_inputs_by_path(pfc::list_base_t > & p_out, const char * p_path, bool p_from_redirect); + static service_ptr g_open(const GUID & whatFor, file::ptr hint, const char * path, abort_callback & aborter, bool fromRedirect = false); void open(service_ptr_t & p_instance,service_ptr_t const & p_filehint,const char * p_path,abort_callback & p_abort) {open_for_decoding(p_instance,p_filehint,p_path,p_abort);} void open(service_ptr_t & p_instance,service_ptr_t const & p_filehint,const char * p_path,abort_callback & p_abort) {open_for_info_read(p_instance,p_filehint,p_path,p_abort);} void open(service_ptr_t & p_instance,service_ptr_t const & p_filehint,const char * p_path,abort_callback & p_abort) {open_for_info_write(p_instance,p_filehint,p_path,p_abort);} - service_ptr open(const GUID & whatFor, file::ptr hint, const char * path, event_logger::ptr logger, abort_callback & aborter); + service_ptr open(const GUID & whatFor, file::ptr hint, const char * path, abort_callback & aborter); typedef pfc::list_base_const_t< input_entry::ptr > input_entry_list_t; - static service_ptr g_open_from_list(input_entry_list_t const & list, const GUID & whatFor, file::ptr hint, const char * path, event_logger::ptr logger, abort_callback & aborter, GUID * outGUID = nullptr); + static service_ptr g_open_from_list(input_entry_list_t const & list, const GUID & whatFor, file::ptr hint, const char * path, abort_callback & aborter, GUID * outGUID = nullptr); static bool g_are_parallel_reads_slow( const char * path ); - static uint32_t g_flags_for_path( const char * pathFor, uint32_t mask = UINT32_MAX ); - static uint32_t g_flags_for_content_type( const char * ct, uint32_t mask = UINT32_MAX ); }; //! \since 1.4 @@ -272,7 +244,8 @@ public: class input_entry_v2 : public input_entry { FB2K_MAKE_SERVICE_INTERFACE(input_entry_v2, input_entry); public: - //! @returns GUID used to identify us among other decoders in the decoder priority table. +#ifdef FOOBAR2000_DESKTOP // none of this is used in fb2k mobile + //! @returns GUID used to identify us among other deciders in the decoder priority table. virtual GUID get_guid() = 0; //! @returns Name to present to the user in the decoder priority table. virtual const char * get_name() = 0; @@ -280,22 +253,7 @@ public: virtual GUID get_preferences_guid() = 0; //! @returns true if the decoder should be put at the end of the list when it's first sighted, false otherwise (will be put at the beginning of the list). virtual bool is_low_merit() = 0; -}; - -//! \since 1.5 -class input_entry_v3 : public input_entry_v2 { - FB2K_MAKE_SERVICE_INTERFACE(input_entry_v3, input_entry_v2); -public: - //! New unified open() function for all supported interfaces. Supports any future interfaces via alternate GUIDs, as well as allows the event logger to be set prior to the open() call. - //! @param whatFor The class GUID of the service we want. \n - //! Currently allowed are: input_decoder::class_guid, input_info_reader::class_guid, input_info_writer::class_guid. \n - //! This method must throw pfc::exception_not_implemented for any GUIDs it does not recognize. - virtual service_ptr open_v3( const GUID & whatFor, file::ptr hint, const char * path, event_logger::ptr logger, abort_callback & aborter ) = 0; - - - void open_for_decoding(service_ptr_t & p_instance, service_ptr_t p_filehint, const char * p_path, abort_callback & p_abort) ; - void open_for_info_read(service_ptr_t & p_instance, service_ptr_t p_filehint, const char * p_path, abort_callback & p_abort); - void open_for_info_write(service_ptr_t & p_instance, service_ptr_t p_filehint, const char * p_path, abort_callback & p_abort); +#endif }; #ifdef FOOBAR2000_DESKTOP @@ -306,40 +264,6 @@ class input_manager : public service_base { FB2K_MAKE_SERVICE_COREAPI(input_manager); public: virtual service_ptr open(const GUID & whatFor, file::ptr hint, const char * path, bool fromRedirect, abort_callback & aborter, GUID * outUsedEntry = nullptr) = 0; - - //! input_manager_v2 wrapper. - service_ptr open_v2(const GUID & whatFor, file::ptr hint, const char * path, bool fromRedirect, event_logger::ptr logger, abort_callback & aborter, GUID * outUsedEntry = nullptr); -}; - -//! \since 1.5 -//! Extension of input_manager. \n -//! Extended open_v2() supports album_art_extractor and album_art_editor. It reliably throws pfc::exception_not_implemented() for unsupported GUIDs (old version would bugcheck). \n -//! It also allows event_logger to be specified in advance so open() implementation can already use it. -class input_manager_v2 : public input_manager { - FB2K_MAKE_SERVICE_COREAPI_EXTENSION(input_manager_v2, input_manager) -public: - virtual service_ptr open_v2(const GUID & whatFor, file::ptr hint, const char * path, bool fromRedirect, event_logger::ptr logger, abort_callback & aborter, GUID * outUsedEntry = nullptr) = 0; -}; - -//! \since 1.5 -class input_manager_v3 : public input_manager_v2 { - FB2K_MAKE_SERVICE_COREAPI_EXTENSION(input_manager_v3, input_manager_v2); -public: - //! Retrieves list of enabled inputs, in user-specified order. \n - //! This is rarely needed. If you need this function, consider redesigning your code to call input_manager open methods instead. - virtual void get_enabled_inputs( pfc::list_base_t & out ) = 0; - //! Returns input_entry get_flags() values for this path, as returned by enabled inputs. - virtual uint32_t flags_for_path( const char * pathFor, uint32_t mask = UINT32_MAX ) = 0; - //! Returns input_entry get_flags() values for this content type, as returned by enabled inputs. - virtual uint32_t flags_for_content_type( const char * ct, uint32_t mask = UINT32_MAX ) = 0; - - - enum { - flagFromRedirect = 1 << 0, - flagSuppressFilters = 1 << 1, - }; - - virtual service_ptr open_v3(const GUID & whatFor, file::ptr hint, const char * path, uint32_t flags, event_logger::ptr logger, abort_callback & aborter, GUID * outUsedEntry = nullptr) = 0; }; //! \since 1.4 @@ -385,8 +309,6 @@ public: }; //! \since 1.4 -//! Callback for input_stream_manipulator \n -//! Used for applying ReplayGain to encoded audio streams. class input_stream_manipulator_callback : public service_base { FB2K_MAKE_SERVICE_INTERFACE(input_stream_manipulator_callback, service_base); public: @@ -402,8 +324,6 @@ public: }; //! \since 1.4 -//! Manipulate audio stream payload in files. \n -//! Used for applying ReplayGain to encoded audio streams. class input_stream_manipulator : public service_base { FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(input_stream_manipulator); public: @@ -425,121 +345,4 @@ public: //! Return GUID of the matching input_entry. virtual GUID get_guid() = 0; }; - -//! \since 1.5 -//! An input_info_filter lets you hook into all performed tag read & write operations. \n -//! Your tag manipulations will be transparent to all fb2k components, as if the tags were read/written by relevant inputs. \n -//! Your input_info_filter needs to be enabled in Preferences in order to become active. Newly added ones are inactive by default. -class input_info_filter : public service_base { - FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT( input_info_filter ); -public: - //! Tags are being read from a file. - virtual void filter_info_read( const playable_location & loc,file_info & info,abort_callback & abort ) = 0; - //! Tags are being written to a file. \n - //! Return true to continue, false to suppress writing of tags. - virtual bool filter_info_write( const playable_location & loc, file_info & info, abort_callback & abort ) = 0; - //! Tags are being removed from a file. - virtual void on_info_remove( const char * path, abort_callback & abort ) = 0; - //! Return GUID of your filter. - virtual GUID get_guid() = 0; - //! Return preferences page or advconfig branch GUID of your filter. - virtual GUID get_preferences_guid() = 0; - //! Return user-friendly name of your filter to be shown in preferences. - virtual const char * get_name() = 0; - //! Optional backwards compatibility method. \n - //! If you also provide input services for old foobar2000 versions which don't recognize input_info_filter, report their GUIDs here so they can be ignored. \n - //! @param outGUIDs empty on entry, contains GUIDs of ignored inputs (if any) on return. - virtual void get_suppressed_inputs( pfc::list_base_t & outGUIDs ) {outGUIDs.remove_all();} - //! write_fallback() supported or not? \n - //! Used if your filter can store tags for untaggable files. - virtual bool supports_fallback() = 0; - //! Optional; called when user attempted to tag an untaggable/readonly file. \n - //! Used if your filter can store tags for untaggable files. - virtual bool write_fallback( const playable_location & loc, file_info const & info, abort_callback & abort ) = 0; - //! Optional; called when user attempted to remove tags from an untaggable/readonly file.\ n - //! Used if your filter can store tags for untaggable files. - virtual void remove_tags_fallback( const char * path, abort_callback & abort ) = 0; -}; - -//! \since 1.5 -class input_stream_info_filter : public service_base { - FB2K_MAKE_SERVICE_INTERFACE( input_stream_info_filter, service_base ); -public: - virtual void filter_dynamic_info( file_info & info ) = 0; - virtual void filter_dynamic_info_track( file_info & info ) = 0; -}; - -class album_art_data; - -//! \since 1.5 -//! Extended input_info_filter. -class input_info_filter_v2 : public input_info_filter { - FB2K_MAKE_SERVICE_INTERFACE( input_info_filter_v2, input_info_filter ); -public: - //! Creates an object which then can work with dynamic track titles etc of a decoded track. \n - //! Returning null to filter the info is allowed. - virtual input_stream_info_filter::ptr open_stream(playable_location const & loc, abort_callback & abort) = 0; - - - typedef service_ptr_t aaptr_t; - - //! Album art is being read from the file. \n - //! info may be null if file had no such picture. \n - //! Return passed info, altered info or null. - virtual aaptr_t filter_album_art_read( const char * path, const GUID & type, aaptr_t info, abort_callback & aborter ) = 0; - //! Album art is being written to the file. \n - //! Return passed info, altered info or null to suppress writing. - virtual aaptr_t filter_album_art_write( const char * path, const GUID & type, aaptr_t info, abort_callback & aborter ) = 0; - //! Specific album art is being removed from the file. \n - //! Return true to go on, false to suppress file update. - virtual bool filter_album_art_remove( const char * path, const GUID & type, abort_callback & aborter ) = 0; - //! All album art is being removed from the file. \n - //! Return true to go on, false to suppress file update. - virtual bool filter_album_art_remove_all( const char * path, abort_callback & aborter ) = 0; - - //! Valid with supports_fallback() = true \n - //! Album art is being written to an untaggable file. - virtual void write_album_art_fallback( const char * path, const GUID & type, aaptr_t info, abort_callback & aborter ) = 0; - //! Valid with supports_fallback() = true \n - //! Specific album art is being removed from an untaggable file. - virtual void remove_album_art_fallback( const char * path, const GUID & type, abort_callback & aborter ) = 0; - //! Valid with supports_fallback() = true \n - //! All album art is being removed from an untaggable file. - virtual void remove_all_album_art_fallback( const char * path, abort_callback & aborter ) = 0; -}; - -class dsp_preset; - -//! \since 1.5 -//! An input_playback_shim adds additional functionality to a DSP, allowing full control of the decoder. \n -//! Currently, input_playback_shim can only exist alongside a DSP, must have the same GUID as a DSP. \n -//! It will only be used in supported scenarios when the user has put your DSP in the chain. \n -//! Your DSP will be deactivated in such case when your input_playback_shim is active. \n -//! input_playback_shim is specifically intended to be instantiated for playback. Do not call this service from your component. \n/ -//! Implement this service ONLY IF NECESSARY. Very few tasks really need it, primarily DSPs that manipulate logical playback time & seeking. -class input_playback_shim : public service_base { - FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT( input_playback_shim ); -public: - //! Same GUID as your DSP. - virtual GUID get_guid() = 0; - //! Preferences page / advconfig branch GUID of your shim, pfc::guid_null if none. \n - //! This is currently unused / reserved for future use. - virtual GUID get_preferences_guid() = 0; - //! Same as your DSP. \n - //! This is currently unused / reserved for future use. - virtual const char * get_name() = 0; - //! Instantiates your shim on top of existing input_decoder. \n - //! If you don't want to do anything with this specific decoder, just return the passed decoder. - virtual input_decoder::ptr shim( input_decoder::ptr dec, const char * path, dsp_preset const & preset, abort_callback & aborter ) = 0; - //! Optional backwards compatibility method. \n - //! If you also provide input services for old versions of foobar2000 which don't recognize input_playback_shim, report their GUIDs here so they can be ignored. \n - //! @param outGUIDs empty on entry, contains GUIDs of ignored inputs (if any) on return. - virtual void get_suppressed_inputs( pfc::list_base_t & outGUIDs ) {outGUIDs.remove_all();} -}; - -#endif // #ifdef FOOBAR2000_DESKTOP - - -typedef input_info_writer_v2 input_info_writer_vhighest; -typedef input_decoder_v4 input_decoder_vhighest; -typedef input_info_reader input_info_reader_vhighest; +#endif diff --git a/foobar2000/SDK/input_file_type.cpp b/foobar2000/SDK/input_file_type.cpp index 1e7dda0..0d33852 100644 --- a/foobar2000/SDK/input_file_type.cpp +++ b/foobar2000/SDK/input_file_type.cpp @@ -66,10 +66,9 @@ void input_file_type::make_extension_support_fingerprint(pfc::string_base & str) } str = out; } - -void input_file_type::build_openfile_mask(pfc::string_base & out, bool b_include_playlists, bool b_include_archives) +void input_file_type::build_openfile_mask(pfc::string_base & out, bool b_include_playlists) { - t_fnList extensionsAll, extensionsPl, extensionsArc; + t_fnList extensionsAll, extensionsPl;; if (b_include_playlists) { service_enum_t e; service_ptr_t ptr; @@ -81,19 +80,6 @@ void input_file_type::build_openfile_mask(pfc::string_base & out, bool b_include } } } - if (b_include_archives) { - service_enum_t e; - archive_v3::ptr p; - pfc::string_formatter temp; - while (e.next(p)) { - p->list_extensions(temp); - pfc::chain_list_v2_t lst; - pfc::splitStringByChar(lst, temp, ','); - for (auto iter = lst.first(); iter.is_valid(); ++iter) { - extensionsArc += PFC_string_formatter() << "*." << *iter; - } - } - } typedef pfc::map_t t_masks; t_masks masks; @@ -117,11 +103,8 @@ void input_file_type::build_openfile_mask(pfc::string_base & out, bool b_include } pfc::string_formatter outBuf; outBuf << "All files|*.*|"; - formatMaskList(outBuf, extensionsAll, "All supported media types"); + formatMaskList(outBuf, extensionsAll, "All supported types"); formatMaskList(outBuf, extensionsPl, "Playlists"); - formatMaskList(outBuf, extensionsArc, "Archives"); - - for(auto walk = masks.cfirst(); walk.is_valid(); ++walk) { formatMaskList(outBuf,walk->m_value,walk->m_key); } diff --git a/foobar2000/SDK/input_file_type.h b/foobar2000/SDK/input_file_type.h index 32664f8..f20edbb 100644 --- a/foobar2000/SDK/input_file_type.h +++ b/foobar2000/SDK/input_file_type.h @@ -8,7 +8,7 @@ public: virtual bool is_associatable(unsigned idx) = 0; #if FOOBAR2000_TARGET_VERSION >= 76 - static void build_openfile_mask(pfc::string_base & out,bool b_include_playlists=true, bool b_include_archives = false); + static void build_openfile_mask(pfc::string_base & out,bool b_include_playlists=true); static void make_extension_support_fingerprint(pfc::string_base & str); static void make_filetype_support_fingerprint(pfc::string_base & str); #endif diff --git a/foobar2000/SDK/input_impl.h b/foobar2000/SDK/input_impl.h index 44261cc..38c50cd 100644 --- a/foobar2000/SDK/input_impl.h +++ b/foobar2000/SDK/input_impl.h @@ -1,8 +1,3 @@ -#pragma once - -#include "input.h" -#include "mem_block_container.h" - enum t_input_open_reason { input_open_info_read, input_open_decode, @@ -78,8 +73,7 @@ public: //! See: input_decoder_v2::run_raw(). Relevant only when implementing input_decoder_v2. Valid after decode_initialize(). bool decode_run_raw(audio_chunk & p_chunk, mem_block_container & p_raw, abort_callback & p_abort); - //! OLD way: may be called at any time from input_decoder_v2 \n - //! NEW way (1.5): called prior to open(). + //! See: input_decoder::set_logger(). Relevant only when implementing input_decoder_v2. Valid after any open(). void set_logger(event_logger::ptr ptr); protected: input_impl() {} @@ -98,11 +92,6 @@ public: static GUID g_get_preferences_guid() {return pfc::guid_null;} static bool g_is_low_merit() { return false; } - bool decode_get_dynamic_info(file_info & p_out, double & p_timestamp_delta) { return false; } - bool decode_get_dynamic_info_track(file_info & p_out, double & p_timestamp_delta) { return false; } - void decode_on_idle(abort_callback & p_abort) { } - - //! These typedefs indicate which interfaces your class actually supports. You can override them to support non default input API interfaces without specifying input_factory parameters. typedef input_decoder_v4 interface_decoder_t; typedef input_info_reader interface_info_reader_t; @@ -165,9 +154,8 @@ template class input_impl_interface_wrapper_t : public interface_t { public: - template - void open( args_t && ... args) { - m_instance.open(std::forward(args) ... ); + void open(service_ptr_t p_filehint,const char * p_path,t_input_open_reason p_reason,abort_callback & p_abort) { + m_instance.open(p_filehint,p_path,p_reason,p_abort); } // input_info_reader methods @@ -307,10 +295,9 @@ class input_wrapper_singletrack_t : public input_forward_static_methods public: input_wrapper_singletrack_t() {} - template - void open( args_t && ... args) { - m_instance.open(std::forward(args) ... ); - } + void open(service_ptr_t p_filehint,const char * p_path,t_input_open_reason p_reason,abort_callback & p_abort) { + m_instance.open(p_filehint,p_path,p_reason,p_abort); + } void get_info(t_uint32 p_subsong,file_info & p_info,abort_callback & p_abort) { if (p_subsong != 0) throw exception_io_bad_subsong_index(); @@ -373,40 +360,32 @@ private: //! Helper; standard input_entry implementation. Do not instantiate this directly, use input_factory_t or one of other input_*_factory_t helpers instead. template -class input_entry_impl_t : public input_entry_v3 +class input_entry_impl_t : public input_entry_v2 { +private: + + template + void instantiate_t(service_ptr_t & p_instance,service_ptr_t p_filehint,const char * p_path,t_input_open_reason p_reason,abort_callback & p_abort) + { + service_ptr_t< service_impl_t > > temp; + temp = new service_impl_t >(); + temp->open(p_filehint,p_path,p_reason,p_abort); + p_instance = temp.get_ptr(); + } public: bool is_our_content_type(const char * p_type) {return I::g_is_our_content_type(p_type);} bool is_our_path(const char * p_full_path,const char * p_extension) {return I::g_is_our_path(p_full_path,p_extension);} + + void open_for_decoding(service_ptr_t & p_instance,service_ptr_t p_filehint,const char * p_path,abort_callback & p_abort) { + instantiate_t(p_instance,p_filehint,p_path,input_open_decode,p_abort); + } - template - void open_ex(service_ptr_t & p_instance,args_t && ... args) - { - auto temp = fb2k::service_new >(); - temp->open(std::forward(args) ... ); - p_instance = temp.get_ptr(); - } + void open_for_info_read(service_ptr_t & p_instance,service_ptr_t p_filehint,const char * p_path,abort_callback & p_abort) { + instantiate_t(p_instance,p_filehint,p_path,input_open_info_read,p_abort); + } - service_ptr open_v3(const GUID & whatFor, file::ptr hint, const char * path, event_logger::ptr logger, abort_callback & aborter) { - if ( whatFor == input_decoder::class_guid ) { - auto obj = fb2k::service_new< input_impl_interface_wrapper_t > (); - if ( logger.is_valid() ) obj->set_logger(logger); - obj->open( hint, path, input_open_decode, aborter ); - return obj; - } - if ( whatFor == input_info_reader::class_guid ) { - auto obj = fb2k::service_new < input_impl_interface_wrapper_t >(); - if (logger.is_valid()) obj->set_logger(logger); - obj->open(hint, path, input_open_info_read, aborter); - return obj; - } - if ( whatFor == input_info_writer::class_guid ) { - auto obj = fb2k::service_new < input_impl_interface_wrapper_t >(); - if (logger.is_valid()) obj->set_logger(logger); - obj->open(hint, path, input_open_info_write, aborter); - return obj; - } - throw pfc::exception_not_implemented(); + void open_for_info_write(service_ptr_t & p_instance,service_ptr_t p_filehint,const char * p_path,abort_callback & p_abort) { + instantiate_t(p_instance,p_filehint,p_path,input_open_info_write,p_abort); } void get_extended_data(service_ptr_t p_filehint,const playable_location & p_location,const GUID & p_guid,mem_block_container & p_out,abort_callback & p_abort) { diff --git a/foobar2000/SDK/library_manager.h b/foobar2000/SDK/library_manager.h index a85a907..2e9d969 100644 --- a/foobar2000/SDK/library_manager.h +++ b/foobar2000/SDK/library_manager.h @@ -195,12 +195,3 @@ class NOVTABLE library_meta_autocomplete : public service_base { public: virtual bool get_value_list(const char * metaName, pfc::com_ptr_t & out) = 0; }; - -//! \since 1.6.1 -//! Caching & asynchronous version. \n -//! Keep a reference to your library_meta_autocomplete_v2 object in your dialog class to cache the looked up values & speed up the operation. -class NOVTABLE library_meta_autocomplete_v2 : public service_base { - FB2K_MAKE_SERVICE_COREAPI(library_meta_autocomplete_v2) -public: - virtual bool get_value_list_async(const char* metaName, pfc::com_ptr_t& out) = 0; -}; diff --git a/foobar2000/SDK/main_thread_callback.h b/foobar2000/SDK/main_thread_callback.h index b1158cc..b238761 100644 --- a/foobar2000/SDK/main_thread_callback.h +++ b/foobar2000/SDK/main_thread_callback.h @@ -1,27 +1,6 @@ -#pragma once #include -// ====================================================================================================== -// Most of main_thread_callback.h declares API internals and obsolete helpers. -// In modern code, simply use fb2k::inMainThread() declared below and disregard the rest. -// ====================================================================================================== -namespace fb2k { - //! Queue a call in main thread. Returns immediately. \n - //! You can call this from any thread, including main thread - to execute some code outside the current call stack / global fb2k callbacks / etc. - void inMainThread(std::function f); - //! Call f synchronously if called from main thread, queue call if called from another. - void inMainThread2(std::function f); -} - - - - -// ====================================================================================================== -// API declarations -// ====================================================================================================== - -//! Callback object class for main_thread_callback_manager service. \n -//! You do not need to implement this directly - simply use fb2k::inMainThread() with a lambda. +//! Callback object class for main_thread_callback_manager service. class NOVTABLE main_thread_callback : public service_base { public: //! Gets called from main app thread. See main_thread_callback_manager description for more info. @@ -34,8 +13,7 @@ public: /*! Allows you to queue a callback object to be called from main app thread. This is commonly used to trigger main-thread-only API calls from worker threads.\n -This can be also used from main app thread, to avoid race conditions when trying to use APIs that dispatch global callbacks from inside some other global callback, or using message loops / modal dialogs inside global callbacks. \n -There is no need to use this API directly - use fb2k::inMainThread() with a lambda. +This can be also used from main app thread, to avoid race conditions when trying to use APIs that dispatch global callbacks from inside some other global callback, or using message loops / modal dialogs inside global callbacks. */ class NOVTABLE main_thread_callback_manager : public service_base { public: @@ -46,11 +24,6 @@ public: }; -// ====================================================================================================== -// Obsolete helpers - they still work, but it's easier to just use fb2k::inMainThread(). -// ====================================================================================================== - -//! Helper, equivalent to main_thread_callback_manager::get()->add_callback(ptr) void main_thread_callback_add(main_thread_callback::ptr ptr); template static void main_thread_callback_spawn() { @@ -107,8 +80,7 @@ static void callInMainThreadSvc(myservice_t * host, param_t const & param) { //! Have this as a member of your class, then use m_mthelper.add( this, somearg ) ; to defer a call to this->inMainThread(somearg). \n //! If your class becomes invalid before inMainThread is executed, the pending callback is discarded. \n //! You can optionally call shutdown() to invalidate all pending callbacks early (in a destructor of your class - without waiting for callInMainThreadHelper destructor to do the job. \n -//! In order to let callInMainThreadHelper access your private methods, declare friend class callInMainThread. \n -//! Note that callInMainThreadHelper is expected to be created and destroyed in main thread. +//! In order to let callInMainThreadHelper access your private methods, declare friend class callInMainThread. class callInMainThreadHelper { public: @@ -185,3 +157,11 @@ private: killswitch_t m_ks; }; + +// Modern helper +namespace fb2k { + // Queue call in main thread + void inMainThread( std::function f ); + // Call f synchronously if called from main thread, queue call if called from another + void inMainThread2( std::function f ); +} diff --git a/foobar2000/SDK/menu_manager.cpp b/foobar2000/SDK/menu_manager.cpp index 2e1b097..2ae95e4 100644 --- a/foobar2000/SDK/menu_manager.cpp +++ b/foobar2000/SDK/menu_manager.cpp @@ -2,8 +2,6 @@ #ifdef WIN32 -#include "ui_element_typable_window_manager.h" - static void fix_ampersand(const char * src,pfc::string_base & out) { out.reset(); @@ -351,8 +349,8 @@ bool keyboard_shortcut_manager::on_keydown_restricted_auto_context(const pfc::li static bool filterTypableWindowMessage(const MSG * msg, t_uint32 modifiers) { if (keyboard_shortcut_manager::is_typing_key_combo((t_uint32)msg->wParam, modifiers)) { const DWORD mask = DLGC_HASSETSEL | DLGC_WANTCHARS | DLGC_WANTARROWS; - auto status = ::SendMessage(msg->hwnd, WM_GETDLGCODE,0, 0); - if ( (status & mask) == mask ) return false; + auto status = ::SendMessage(msg->hwnd, WM_GETDLGCODE, 0, 0); + if ((status & mask) == mask) return false; ui_element_typable_window_manager::ptr api; if (ui_element_typable_window_manager::tryGet(api)) { diff --git a/foobar2000/SDK/metadb.cpp b/foobar2000/SDK/metadb.cpp index 99cea1e..7a7fd58 100644 --- a/foobar2000/SDK/metadb.cpp +++ b/foobar2000/SDK/metadb.cpp @@ -1,5 +1,5 @@ #include "foobar2000.h" -#include "file_info_filter_impl.h" + void metadb::handle_create_replace_path_canonical(metadb_handle_ptr & p_out,const metadb_handle_ptr & p_source,const char * p_new_path) { handle_create(p_out,make_playable_location(p_new_path,p_source->get_subsong_index())); @@ -93,20 +93,3 @@ void metadb_io_v2::on_files_rechaptered( metadb_handle_list_cref newHandles ) { load_info_async( newHandles, metadb_io::load_info_force, core_api::get_main_window(), metadb_io_v3::op_flag_delay_ui, notify ); } - - -metadb_hint_list::ptr metadb_hint_list::create() { - return metadb_io_v2::get()->create_hint_list(); -} - -metadb_hint_list_v2::ptr metadb_hint_list_v2::create() { - metadb_hint_list_v2::ptr ret; - ret ^= metadb_hint_list::create(); - return ret; -} - -metadb_hint_list_v3::ptr metadb_hint_list_v3::create() { - metadb_hint_list_v3::ptr ret; - ret ^= metadb_hint_list::create(); - return ret; -} diff --git a/foobar2000/SDK/metadb.h b/foobar2000/SDK/metadb.h index 47c0d59..5399c14 100644 --- a/foobar2000/SDK/metadb.h +++ b/foobar2000/SDK/metadb.h @@ -1,9 +1,3 @@ -#pragma once - - -class file_info_filter; // forward decl; file_info_filter moved to file_info_filter.h - - //! API for tag read/write operations. Legal to call from main thread only, except for hint_multi_async() / hint_async() / hint_reader().\n //! Implemented only by core, do not reimplement.\n //! Use static_api_ptr_t template to access metadb_io methods.\n @@ -68,72 +62,49 @@ public: FB2K_MAKE_SERVICE_COREAPI(metadb_io); }; -//! Advanced interface for passing infos read from files to metadb backend. Use metadb_io_v2::create_hint_list() to instantiate. \n -//! Thread safety: all methods other than on_done() are intended for worker threads. Instantiate and use the object in a worker thread, call on_done() in main thread to finalize. \n -//! Typical usage pattern: create a hint list (in any thread), hand infos to it from files that you work with (in a worker thread), call on_done() in main thread. \n +//! Implementing this class gives you direct control over which part of file_info gets altered during a tag update uperation. To be used with metadb_io_v2::update_info_async(). +class NOVTABLE file_info_filter : public service_base { +public: + //! Alters specified file_info entry; called as a part of tag update process. Specified file_info has been read from a file, and will be written back.\n + //! WARNING: This will be typically called from another thread than main app thread (precisely, from thread created by tag updater). You should copy all relevant data to members of your file_info_filter instance in constructor and reference only member data in apply_filter() implementation. + //! @returns True when you have altered file_info and changes need to be written back to the file; false if no changes have been made. + virtual bool apply_filter(metadb_handle_ptr p_location,t_filestats p_stats,file_info & p_info) = 0; + + FB2K_MAKE_SERVICE_INTERFACE(file_info_filter,service_base); +}; + +//! Advanced interface for passing infos read from files to metadb backend. Use metadb_io_v2::create_hint_list() to instantiate. class NOVTABLE metadb_hint_list : public service_base { FB2K_MAKE_SERVICE_INTERFACE(metadb_hint_list,service_base); public: - //! Helper. - static metadb_hint_list::ptr create(); //! Adds a hint to the list. //! @param p_location Location of the item the hint applies to. //! @param p_info file_info object describing the item. //! @param p_stats Information about the file containing item the hint applies to. //! @param p_freshflag Set to true if the info has been directly read from the file, false if it comes from another source such as a playlist file. virtual void add_hint(metadb_handle_ptr const & p_location,const file_info & p_info,const t_filestats & p_stats,bool p_freshflag) = 0; - //! Reads info from specified info reader instance and adds hints. May throw an exception in case info read has failed. \n - //! If the file has multiple subsongs, info from all the subsongs will be read and pssed to add_hint(). \n - //! Note that an input_info_writer is a subclass of input_info_reader - so any input_info_reader OR input_info_writer is a valid argument for add_hint_reader(). \n - //! This method is often called with your input_info_writer instance after committing tag updates, to notify metadb about altered tags. + //! Reads info from specified info reader instance and adds hints. May throw an exception in case info read has failed. virtual void add_hint_reader(const char * p_path,service_ptr_t const & p_reader,abort_callback & p_abort) = 0; - //! Call this when you're done working with this metadb_hint_list instance, to apply hints and dispatch callbacks. \n - //! If you don't call this, all added hints will be ignored. \n - //! As a general rule, you should add as many infos as possible - such as all the tracks involved in some operation that you perform - then call on_done() once. \n - //! on_done() is expensive because it not only updates the metadb, but tells all components about the changes made - refreshes playlists/autoplaylists, library viewers, etc. \n - //! Calling on_done() repeatedly is inefficient and should be avoided. + //! Call this when you're done working with this metadb_hint_list instance, to apply hints and dispatch callbacks. If you don't call this, all added hints will be ignored. virtual void on_done() = 0; }; //! \since 1.0 -//! To obtain metadb_hint_list_v2, use service_query on a metadb_hint_list object. \n -//! Simplified: metadb_hint_list_v2::ptr v2; v2 ^= myHintList; ( causes bugcheck if old fb2k / no interface ). class NOVTABLE metadb_hint_list_v2 : public metadb_hint_list { FB2K_MAKE_SERVICE_INTERFACE(metadb_hint_list_v2, metadb_hint_list); public: - //! Helper. - static metadb_hint_list_v2::ptr create(); - //! Hint with browse info. \n - //! See: metadb_handle::get_browse_info() for browse info rationale. - //! @param p_location Location for which we're providing browse info. - //! @param p_info Browse info for this location. - //! @param browseTS timestamp of the browse info - such as last-modified time of the playlist file providing browse info. virtual void add_hint_browse(metadb_handle_ptr const & p_location,const file_info & p_info, t_filetimestamp browseTS) = 0; }; //! \since 1.3 -//! To obtain metadb_hint_list_v3, use service_query on a metadb_hint_list object. \n -//! Simplified: metadb_hint_list_v3::ptr v3; v3 ^= myHintList; ( causes bugcheck if old fb2k / no interface ). class NOVTABLE metadb_hint_list_v3 : public metadb_hint_list_v2 { FB2K_MAKE_SERVICE_INTERFACE(metadb_hint_list_v3, metadb_hint_list_v2); public: - //! Helper. - static metadb_hint_list_v3::ptr create(); - //! Hint primary info with a metadb_info_container. virtual void add_hint_v3(metadb_handle_ptr const & p_location, metadb_info_container::ptr info,bool p_freshflag) = 0; - //! Hint browse info with a metadb_info_container. virtual void add_hint_browse_v3(metadb_handle_ptr const & p_location,metadb_info_container::ptr info) = 0; - //! Add a forced hint.\n - //! A normal hint may or may not cause metadb update - metadb is not updated if the file has not changed according to last modified time. \n - //! A forced hint always updates metadb regardless of timestamps. virtual void add_hint_forced(metadb_handle_ptr const & p_location, const file_info & p_info,const t_filestats & p_stats,bool p_freshflag) = 0; - //! Add a forced hint, with metadb_info_container. \n - //! Forced hint rationale - see add_hint_forced(). virtual void add_hint_forced_v3(metadb_handle_ptr const & p_location, metadb_info_container::ptr info,bool p_freshflag) = 0; - //! Adds a forced hint, with an input_info_reader. \n - //! Forced hint rationale - see add_hint_forced(). \n - //! Info reader use rationale - see add_hint_reader(). virtual void add_hint_forced_reader(const char * p_path,service_ptr_t const & p_reader,abort_callback & p_abort) = 0; }; @@ -178,8 +149,7 @@ public: //! @param p_notify Called when the task is completed. Status code is one of t_update_info values. Can be null if caller doesn't care. virtual void remove_info_async(metadb_handle_list_cref p_list,HWND p_parent_window,t_uint32 p_op_flags,completion_notify_ptr p_notify) = 0; - //! Creates a metadb_hint_list object. \n - //! Contrary to other metadb_io methods, this can be safely called in a worker thread. You only need to call the hint list's on_done() method in main thread to finalize. + //! Creates a metadb_hint_list object. virtual metadb_hint_list::ptr create_hint_list() = 0; //! Updates tags of the specified tracks. Helper; uses update_info_async internally. @@ -192,8 +162,6 @@ public: //! Helper to be called after a file has been rechaptered. \n //! Forcibly reloads info then tells playlist_manager to update all affected playlists. void on_file_rechaptered( const char * path, metadb_handle_list_cref newItems ); - //! Helper to be called after a file has been rechaptered. \n - //! Forcibly reloads info then tells playlist_manager to update all affected playlists. void on_files_rechaptered( metadb_handle_list_cref newHandles ); FB2K_MAKE_SERVICE_COREAPI_EXTENSION(metadb_io_v2,metadb_io); @@ -206,7 +174,7 @@ public: virtual void on_changed_sorted(metadb_handle_list_cref p_items_sorted, bool p_fromhook) = 0; }; -//! \since 0.9.5 +//! New (0.9.5) class NOVTABLE metadb_io_v3 : public metadb_io_v2 { public: virtual void register_callback(metadb_io_callback_dynamic * p_callback) = 0; @@ -215,29 +183,6 @@ public: FB2K_MAKE_SERVICE_COREAPI_EXTENSION(metadb_io_v3,metadb_io_v2); }; - -class threaded_process_callback; - -#if FOOBAR2000_TARGET_VERSION >= 80 -//! \since 1.5 -class NOVTABLE metadb_io_v4 : public metadb_io_v3 { - FB2K_MAKE_SERVICE_COREAPI_EXTENSION(metadb_io_v4, metadb_io_v3); -public: - //! Creates an update-info task, that can be either fed to threaded_process API, or invoked by yourself respecting threaded_process semantics. \n - //! May return null pointer if the operation has been refused (by user settings or such). \n - //! Useful for performing the operation with your own in-dialog progress display instead of the generic progress popup. - virtual service_ptr_t spawn_update_info( metadb_handle_list_cref items, service_ptr_t p_filter, uint32_t opFlags, completion_notify_ptr reply ) = 0; - //! Creates an remove-info task, that can be either fed to threaded_process API, or invoked by yourself respecting threaded_process semantics. \n - //! May return null pointer if the operation has been refused (by user settings or such). \n - //! Useful for performing the operation with your own in-dialog progress display instead of the generic progress popup. - virtual service_ptr_t spawn_remove_info( metadb_handle_list_cref items, uint32_t opFlags, completion_notify_ptr reply) = 0; - //! Creates an load-info task, that can be either fed to threaded_process API, or invoked by yourself respecting threaded_process semantics. \n - //! May return null pointer if the operation has been refused (for an example no loading is needed for these items). \n - //! Useful for performing the operation with your own in-dialog progress display instead of the generic progress popup. - virtual service_ptr_t spawn_load_info( metadb_handle_list_cref items, t_load_info_type opType, uint32_t opFlags, completion_notify_ptr reply) = 0; -}; -#endif - //! metadb_io_callback_dynamic implementation helper. class metadb_io_callback_dynamic_impl_base : public metadb_io_callback_dynamic { public: @@ -297,8 +242,8 @@ public: //! @returns True on success; false on failure (no known playable locations). static bool g_get_random_handle(metadb_handle_ptr & p_out); - enum {case_sensitive = playable_location::case_sensitive}; - typedef playable_location::path_comparator path_comparator; + enum {case_sensitive = true}; + typedef pfc::comparator_strcmp path_comparator; inline static int path_compare_ex(const char * p1,t_size len1,const char * p2,t_size len2) {return case_sensitive ? pfc::strcmp_ex(p1,len1,p2,len2) : stricmp_utf8_ex(p1,len1,p2,len2);} inline static int path_compare_nc(const char * p1, size_t len1, const char * p2, size_t len2) {return case_sensitive ? pfc::strcmp_nc(p1,len1,p2,len2) : stricmp_utf8_ex(p1,len1,p2,len2);} @@ -349,6 +294,38 @@ public: +//! Helper implementation of file_info_filter_impl. +class file_info_filter_impl : public file_info_filter { +public: + file_info_filter_impl(const pfc::list_base_const_t & p_list,const pfc::list_base_const_t & p_new_info) { + FB2K_DYNAMIC_ASSERT(p_list.get_count() == p_new_info.get_count()); + pfc::array_t order; + order.set_size(p_list.get_count()); + order_helper::g_fill(order.get_ptr(),order.get_size()); + p_list.sort_get_permutation_t(pfc::compare_t,order.get_ptr()); + m_handles.set_count(order.get_size()); + m_infos.set_size(order.get_size()); + for(t_size n = 0; n < order.get_size(); n++) { + m_handles[n] = p_list[order[n]]; + m_infos[n] = *p_new_info[order[n]]; + } + } + + bool apply_filter(metadb_handle_ptr p_location,t_filestats p_stats,file_info & p_info) { + t_size index; + if (m_handles.bsearch_t(pfc::compare_t,p_location,index)) { + p_info = m_infos[index]; + return true; + } else { + return false; + } + } +private: + metadb_handle_list m_handles; + pfc::array_t m_infos; +}; + + //! \since 1.1 //! metadb_index_manager hash, currently a 64bit int, typically made from halving MD5 hash. typedef t_uint64 metadb_index_hash; diff --git a/foobar2000/SDK/metadb_handle.cpp b/foobar2000/SDK/metadb_handle.cpp index 967423d..4721595 100644 --- a/foobar2000/SDK/metadb_handle.cpp +++ b/foobar2000/SDK/metadb_handle.cpp @@ -99,30 +99,3 @@ metadb_info_container::ptr metadb_handle::get_full_info_ref( abort_callback & ab reader->get_info( this->get_subsong_index(), obj->m_info, aborter ); return obj; } - -namespace fb2k { - pfc::string_formatter formatTrackList( metadb_handle_list_cref lst ) { - pfc::string_formatter ret; - auto cnt = lst.get_count(); - if ( cnt == 0 ) ret << "[Empty track list]\n"; - else { - if (cnt == 1) ret << "[Track list: 1 track]\n"; - else ret << "[Track list: " << cnt << " tracks]\n"; - for( size_t walk = 0; walk < cnt; ++ walk ) { - ret << " " << lst[walk]->get_location() << "\n"; - } - ret << "[Track list end]"; - } - return ret; - } - pfc::string_formatter formatTrackTitle(metadb_handle_ptr item, const char * script ) { - pfc::string_formatter ret; - item->format_title_legacy(NULL,ret,script,NULL); - return ret; - } - pfc::string_formatter formatTrackTitle(metadb_handle_ptr item,service_ptr_t script) { - pfc::string_formatter ret; - item->format_title(NULL,ret,script,NULL); - return ret; - } -} diff --git a/foobar2000/SDK/metadb_handle.h b/foobar2000/SDK/metadb_handle.h index 25eadb7..f350f91 100644 --- a/foobar2000/SDK/metadb_handle.h +++ b/foobar2000/SDK/metadb_handle.h @@ -1,5 +1,3 @@ -#pragma once - class titleformat_hook; class titleformat_text_filter; class titleformat_object; @@ -17,6 +15,7 @@ public: //! To obtain a metadb_handle to specific location, use metadb::handle_create(). To obtain a list of metadb_handle objects corresponding to specific path (directory, playlist, multitrack file, etc), use relevant playlist_incoming_item_filter methods (recommended), or call playlist_loader methods directly.\n //! A metadb_handle is also the most efficient way of passing playable object locations around because it provides fast access to both location and infos, and is reference counted so duplicating it is as fast as possible.\n //! To retrieve a path of a file from a metadb_handle, use metadb_handle::get_path() function. Note that metadb_handle is NOT just file path, some formats support multiple subsongs per physical file, which are signaled using subsong indexes. + class NOVTABLE metadb_handle : public service_base { public: @@ -40,11 +39,9 @@ public: //! Returns last seen file stats, filestats_invalid if unknown. virtual t_filestats get_filestats() const = 0; - //! Obsolete, use get_info_ref() family of methods instead. \n //! Queries whether cached info about item referenced by this metadb_handle object is already available. Note that this function causes the metadb to be temporarily locked; you can not use it in context that where locking is forbidden.\n //! Note that state of cached info changes only inside main thread, so you can safely assume that it doesn't change while some block of your code inside main thread is being executed. virtual bool is_info_loaded() const = 0; - //! Obsolete, use get_info_ref() instead. \n //! Queries cached info about item referenced by this metadb_handle object. Returns true on success, false when info is not yet known. Note that this function causes the metadb to be temporarily locked; you can not use it in context that where locking is forbidden. \n //! Note that state of cached info changes only inside main thread, so you can safely assume that it doesn't change while some block of your code inside main thread is being executed. virtual bool get_info(file_info & p_info) const = 0; @@ -52,11 +49,9 @@ public: //! OBSOLETE, DO NOT CALL __declspec(deprecated) virtual bool get_info_locked(const file_info * & p_info) const = 0; - //! Obsolete, use get_info_ref() family of methods instead. \n //! Queries whether cached info about item referenced by this metadb_handle object is already available.\n //! This is intended for use in special cases when you need to immediately retrieve info sent by metadb_io hint from another thread; state of returned data can be altered by any thread, as opposed to non-async methods. - virtual bool is_info_loaded_async() const = 0; - //! Obsolete, use get_info_ref() family of methods instead. \n + virtual bool is_info_loaded_async() const = 0; //! Queries cached info about item referenced by this metadb_handle object. Returns true on success, false when info is not yet known. Note that this function causes the metadb to be temporarily locked; you can not use it in context that where locking is forbidden.\n //! This is intended for use in special cases when you need to immediately retrieve info sent by metadb_io hint from another thread; state of returned data can be altered by any thread, as opposed to non-async methods. virtual bool get_info_async(file_info & p_info) const = 0; @@ -73,40 +68,34 @@ public: __declspec(deprecated) virtual void format_title_from_external_info_nonlocking(const file_info & p_info,titleformat_hook * p_hook,pfc::string_base & p_out,const service_ptr_t & p_script,titleformat_text_filter * p_filter) = 0; #if FOOBAR2000_TARGET_VERSION >= 76 - //! \since 1.0 - //! Returns browse info for this track. \n - //! Browse info comes from an external source - such as internet playlist metadata - not from the media file itself, and is maintained separately. \n - //! When title formatting calls are invoked on for a track having browse info present, data for title formatting is sourced from both primary and browse info. \n - //! Example: internet radio stream provides no metadata but its playlist XML has title (radio station name), %title% resolves to the radio station name from the playlist. + //! New in 1.0 virtual bool get_browse_info(file_info & info, t_filetimestamp & ts) const = 0; - //! \since 1.0 //! OBSOLETE, DO NOT CALL __declspec(deprecated) virtual bool get_browse_info_locked(const file_info * & p_info, t_filetimestamp & ts) const = 0; #endif #if FOOBAR2000_TARGET_VERSION >= 78 //! \since 1.3 //! Retrieve a reference to the primary info. \n - //! You can hold the reference to the info as long as you like, call the method in any context you like with no lock semantics involved. The info held by the returned reference will remain constant even if the metadb content changes. \n + //! You can hold the reference to the info as long as you like, call the method in any context you like with no lock semantics involved. The info held by the returned reference will remain constant even if the metadb content changes. //! Returns true and sets outInfo to a reference to this item's primary info on success, returns false on failure (no info known at this time). virtual bool get_info_ref(metadb_info_container::ptr & outInfo) const = 0; //! \since 1.3 //! Retrieve a reference to the async info (pending info update). If async info isn't set, a reference to the primary info is returned.\n - //! You can hold the reference to the info as long as you like, call the method in any context you like with no lock semantics involved. The info held by the returned reference will remain constant even if the metadb content changes. \n + //! You can hold the reference to the info as long as you like, call the method in any context you like with no lock semantics involved. The info held by the returned reference will remain constant even if the metadb content changes. //! Returns true and sets outInfo to a reference to this item's async or primary info on success, returns false on failure (no info known at this time). virtual bool get_async_info_ref(metadb_info_container::ptr & outInfo) const = 0; //! \since 1.3 //! Retrieve references to the item's primary and browse infos. If no info is set, NULL pointers are returned. For most local files, browse info is not available and you get a NULL for it.\n - //! Since browse info is usually used along with the primary info (as a fallback for missing metas), you can get the two with one call for better performance. \n - //! You can hold the reference to the info as long as you like, call the method in any context you like with no lock semantics involved. The info held by the returned reference will remain constant even if the metadb content changes. \n - //! See also: get_browse_info(), for browse info rationale. + //! Since browse info is usually used along with the primary info (as a fallback for missing metas), you can get the two with one call for better performance. + //! You can hold the reference to the info as long as you like, call the method in any context you like with no lock semantics involved. The info held by the returned reference will remain constant even if the metadb content changes. virtual void get_browse_info_ref(metadb_info_container::ptr & outInfo, metadb_info_container::ptr & outBrowse) const = 0; - //! Simplified method, always returns non-null, dummy info if nothing to return. + //! Simplified method, always returns non-null, dummy info if nothing to return virtual metadb_info_container::ptr get_info_ref() const = 0; - //! Simplified method, always returns non-null, dummy info if nothing to return. + //! Simplified method, always returns non-null, dummy info if nothing to return virtual metadb_info_container::ptr get_async_info_ref() const = 0; //! \since 1.3 @@ -116,11 +105,10 @@ public: #endif //! \since 1.3 - //! Helper using get_browse_info_ref(). \n - //! Retrieves primary info + browse info merged together. \n - //! Returns true on success, false if neither info is available. \n - //! If neither info is avaialble, output data structure is emptied. \n - //! See also: get_browse_info() for browse info rationale. + //! Helper using get_browse_info_ref() + //! Retrieves primary info + browse info merged together. + //! Returns true on success, false if neither info is available. + //! If neither info is avaialble, output data structure is emptied. bool get_browse_info_merged(file_info & infoMerged) const; @@ -143,9 +131,6 @@ public: t_filetimestamp get_filetimestamp(); t_filesize get_filesize(); - //! Internal method, do not use - inline const char * _get_path() const { return get_path(); } - FB2K_MAKE_SERVICE_INTERFACE(metadb_handle,service_base); }; @@ -253,10 +238,17 @@ inline pfc::string_base & operator<<(pfc::string_base & p_fmt,const metadb_handl } +class string_format_title { +public: + string_format_title(metadb_handle_ptr p_item,const char * p_script) { + p_item->format_title_legacy(NULL,m_data,p_script,NULL); + } + string_format_title(metadb_handle_ptr p_item,service_ptr_t p_script) { + p_item->format_title(NULL,m_data,p_script,NULL); + } -namespace fb2k { - pfc::string_formatter formatTrackList( metadb_handle_list_cref ); - pfc::string_formatter formatTrackTitle(metadb_handle_ptr item, const char * script = "%title%" ); - pfc::string_formatter formatTrackTitle(metadb_handle_ptr item,service_ptr_t script); -} - + const char * get_ptr() const {return m_data.get_ptr();} + operator const char * () const {return m_data.get_ptr();} +private: + pfc::string8_fastalloc m_data; +}; diff --git a/foobar2000/SDK/metadb_handle_list.cpp b/foobar2000/SDK/metadb_handle_list.cpp index 2c03b6e..aec165e 100644 --- a/foobar2000/SDK/metadb_handle_list.cpp +++ b/foobar2000/SDK/metadb_handle_list.cpp @@ -89,7 +89,8 @@ namespace { void metadb_handle_list_helper::sort_by_format_get_order(metadb_handle_list_cref p_list,t_size* order,const service_ptr_t & p_script,titleformat_hook * p_hook,int p_direction) { - sort_by_format_get_order_v2(p_list, order, p_script, p_hook, p_direction, fb2k::noAbort ); + abort_callback_dummy noAbort; + sort_by_format_get_order_v2(p_list, order, p_script, p_hook, p_direction, noAbort ); } void metadb_handle_list_helper::sort_by_relative_path(metadb_handle_list_ref p_list) diff --git a/foobar2000/SDK/ole_interaction.h b/foobar2000/SDK/ole_interaction.h index 3e81232..5ac4cf1 100644 --- a/foobar2000/SDK/ole_interaction.h +++ b/foobar2000/SDK/ole_interaction.h @@ -44,11 +44,12 @@ public: set_entry_count(total); t_size done = 0; pfc::string8 name; metadb_handle_list content; + abort_callback_dummy abort; for(t_size walk = 0; walk < pltotal; ++walk) if (mask[walk]) { pfc::dynamic_assert( done < total ); api->playlist_get_name(walk,name); api->playlist_get_all_items(walk,content); set_entry_name(done,name); set_entry_content(done,content); - stream_writer_buffer_simple sideData; api->playlist_get_sideinfo(walk, &sideData, fb2k::noAbort); + stream_writer_buffer_simple sideData; api->playlist_get_sideinfo(walk, &sideData, abort); set_side_data(done,sideData.m_buffer.get_ptr(), sideData.m_buffer.get_size()); ++done; } diff --git a/foobar2000/SDK/output.cpp b/foobar2000/SDK/output.cpp index 817934e..5442fc7 100644 --- a/foobar2000/SDK/output.cpp +++ b/foobar2000/SDK/output.cpp @@ -1,13 +1,9 @@ #include "foobar2000.h" -#include "output.h" -#include "audio_chunk_impl.h" -#include "dsp.h" -#include "resampler.h" pfc::string8 output_entry::get_device_name( const GUID & deviceID ) { pfc::string8 temp; if (!get_device_name(deviceID, temp)) temp = "[unknown device]"; - return temp; + return std::move(temp); } namespace { @@ -50,25 +46,8 @@ output_entry::ptr output_entry::g_find( const GUID & outputID ) { } -bool output::is_progressing_() { - output_v4::ptr v4; - if ( v4 &= this ) return v4->is_progressing(); - return true; -} -size_t output::update_v2_() { - output_v4::ptr v4; - if ( v4 &= this ) return v4->update_v2(); - bool bReady = false; - this->update(bReady); - return bReady ? SIZE_MAX : 0; -} -pfc::eventHandle_t output::get_trigger_event_() { - output_v4::ptr v4; - if ( v4 &= this ) return v4->get_trigger_event(); - return pfc::eventInvalid; -} void output_impl::flush() { m_incoming_ptr = 0; @@ -80,11 +59,7 @@ void output_impl::flush_changing_track() { m_incoming.set_size(0); on_flush_changing_track(); } - void output_impl::update(bool & p_ready) { - p_ready = update_v2() > 0; -} -size_t output_impl::update_v2() { on_update(); if (m_incoming_spec != m_active_spec && m_incoming_ptr < m_incoming.get_size()) { if (get_latency_samples() == 0) { @@ -93,8 +68,7 @@ size_t output_impl::update_v2() { } else { force_play(); } - } - size_t retCanWriteSamples = 0; + } if (m_incoming_spec == m_active_spec && m_incoming_ptr < m_incoming.get_size()) { t_size cw = can_write_samples() * m_incoming_spec.m_channels; t_size delta = pfc::min_t(m_incoming.get_size() - m_incoming_ptr,cw); @@ -102,13 +76,9 @@ size_t output_impl::update_v2() { write(audio_chunk_temp_impl(m_incoming.get_ptr()+m_incoming_ptr,delta / m_incoming_spec.m_channels,m_incoming_spec.m_sample_rate,m_incoming_spec.m_channels,m_incoming_spec.m_channel_config)); m_incoming_ptr += delta; } - retCanWriteSamples = (cw - delta) / m_incoming_spec.m_channels; - } else if ( m_incoming_ptr == m_incoming.get_size() ) { - retCanWriteSamples = SIZE_MAX; - } - return retCanWriteSamples; + } + p_ready = (m_incoming_ptr == m_incoming.get_size()); } - double output_impl::get_latency() { double ret = 0; if (m_incoming_spec.is_valid()) { @@ -117,7 +87,7 @@ double output_impl::get_latency() { if (m_active_spec.is_valid()) { ret += audio_math::samples_to_time( get_latency_samples() , m_active_spec.m_sample_rate ); } - return ret; + return ret; } void output_impl::process_samples(const audio_chunk & p_chunk) { pfc::dynamic_assert(m_incoming_ptr == m_incoming.get_size()); @@ -131,50 +101,18 @@ void output_impl::process_samples(const audio_chunk & p_chunk) { } void output_v3::get_injected_dsps( dsp_chain_config & dsps ) { +#ifdef FOOBAR2000_HAVE_DSP dsps.remove_all(); -#if 0 // DEPRECATED unsigned rate = this->get_forced_sample_rate(); if (rate != 0) { -#if PFC_DEBUG - FB2K_console_formatter() << "output_v3::get_injected_dsps() : requesting resampling to " << rate << " Hz"; -#endif dsp_preset_impl temp; if (resampler_entry::g_create_preset( temp, 0, rate, 0 )) { dsps.insert_item( temp, dsps.get_count() ); - } else { -#if PFC_DEBUG - FB2K_console_formatter() << "output_v3::get_injected_dsps() : resampler could not be created"; -#endif } } -#endif +#endif // FOOBAR2000_HAVE_DSP } -size_t output_v4::update_v2() { - bool bReady = false; - update(bReady); - return bReady ? SIZE_MAX : 0; -} - -uint32_t output_entry::get_config_flags_compat() { - uint32_t ret = get_config_flags(); - if ((ret & (flag_low_latency | flag_high_latency)) == 0) { - // output predating flag_high_latency + flag_low_latency - // if it's old foo_out_upnp, report high latency, otherwise low latency. - static const GUID guid_foo_out_upnp = { 0x9900b4f6, 0x8431, 0x4b0a, { 0x95, 0x56, 0xa7, 0xfc, 0xb9, 0x5b, 0x74, 0x3 } }; - if (this->get_guid() == guid_foo_out_upnp) ret |= flag_high_latency; - else ret |= flag_low_latency; - } - return ret; -} - -bool output_entry::is_high_latency() { - return (this->get_config_flags_compat() & flag_high_latency) != 0; -} - -bool output_entry::is_low_latency() { - return (this->get_config_flags_compat() & flag_low_latency) != 0; -} // {EEEB07DE-C2C8-44c2-985C-C85856D96DA1} const GUID output_id_null = diff --git a/foobar2000/SDK/output.h b/foobar2000/SDK/output.h index 1957f25..d2f34a6 100644 --- a/foobar2000/SDK/output.h +++ b/foobar2000/SDK/output.h @@ -4,9 +4,6 @@ PFC_DECLARE_EXCEPTION(exception_output_device_not_found, pfc::exception, "Audio device not found") PFC_DECLARE_EXCEPTION(exception_output_module_not_found, exception_output_device_not_found, "Output module not found") -PFC_DECLARE_EXCEPTION(exception_output_invalidated, pfc::exception, "Audio device invalidated") -PFC_DECLARE_EXCEPTION(exception_output_device_in_use, pfc::exception, "Audio device in use") -PFC_DECLARE_EXCEPTION(exception_output_unsupported_stream_format, pfc::exception, "Unsupported audio stream format") // ======================================================= @@ -20,15 +17,17 @@ PFC_DECLARE_EXCEPTION(exception_output_unsupported_stream_format, pfc::exception //! Structure describing PCM audio data format, with basic helper functions. struct t_pcmspec { - unsigned m_sample_rate = 0; - unsigned m_bits_per_sample = 0; - unsigned m_channels = 0,m_channel_config = 0; - bool m_float = false; + inline t_pcmspec() {reset();} + inline t_pcmspec(const t_pcmspec & p_source) {*this = p_source;} + unsigned m_sample_rate; + unsigned m_bits_per_sample; + unsigned m_channels,m_channel_config; + bool m_float; inline unsigned align() const {return (m_bits_per_sample / 8) * m_channels;} - uint64_t time_to_bytes(double p_time) const {return audio_math::time_to_samples(p_time,m_sample_rate) * (m_bits_per_sample / 8) * m_channels;} - double bytes_to_time(uint64_t p_bytes) const {return (double) (p_bytes / ((m_bits_per_sample / 8) * m_channels)) / (double) m_sample_rate;} + t_size time_to_bytes(double p_time) const {return (t_size)audio_math::time_to_samples(p_time,m_sample_rate) * (m_bits_per_sample / 8) * m_channels;} + double bytes_to_time(t_size p_bytes) const {return (double) (p_bytes / ((m_bits_per_sample / 8) * m_channels)) / (double) m_sample_rate;} inline bool operator==(/*const t_pcmspec & p_spec1,*/const t_pcmspec & p_spec2) const { @@ -44,7 +43,7 @@ struct t_pcmspec return !(*this == p_spec2); } - inline void reset() { *this = t_pcmspec(); } + inline void reset() {m_sample_rate = 0; m_bits_per_sample = 0; m_channels = 0; m_channel_config = 0; m_float = false;} inline bool is_valid() const { return m_sample_rate >= 1000 && m_sample_rate <= 1000000 && @@ -114,72 +113,27 @@ public: //! Sets playback volume. //! @p_val Volume level in dB. Value of 0 indicates full ("100%") volume, negative values indciate different attenuation levels. virtual void volume_set(double p_val) = 0; - - //! Helper, see output_v4::is_progressing(). - bool is_progressing_(); - //! Helper, see output_v4::update_v2() - size_t update_v2_(); - //! Helper, see output_v4::get_event_trigger() - pfc::eventHandle_t get_trigger_event_(); - - //! Helper for output_entry implementation. - static uint32_t g_extra_flags() { return 0; } }; class NOVTABLE output_v2 : public output { FB2K_MAKE_SERVICE_INTERFACE(output_v2, output); public: - //! Obsolete, do not use. virtual bool want_track_marks() {return false;} - //! Obsolete, do not use. virtual void on_track_mark() {} - //! Obsolete, do not use. virtual void enable_fading(bool state) {} - //! Called when flushing due to manual track change rather than seek-within-track virtual void flush_changing_track() {flush();} }; class dsp_chain_config; -//! \since 1.4 class NOVTABLE output_v3 : public output_v2 { FB2K_MAKE_SERVICE_INTERFACE(output_v3, output_v2); public: - //! Does this output require a specific sample rate? If yes, return the value, otherwise return zero. \n - //! Returning a nonzero will cause a resampler DSP to be injected. virtual unsigned get_forced_sample_rate() { return 0; } - //! Allows the output to inject specific DSPs at the end of the used chain. \n - //! Default implementation queries get_forced_sample_rate() and injects a resampler. virtual void get_injected_dsps( dsp_chain_config & ); }; -//! \since 1.6 -class NOVTABLE output_v4 : public output_v3 { - FB2K_MAKE_SERVICE_INTERFACE(output_v4, output_v3); -public: - //! Returns an event handle that becomes signaled once the output wants an update() call and possibly process_samples(). \n - //! Optional; may return pfc::eventInvalid if not available at this time or not supported. \n - //! If implemented, calling update() should clear the event each time. - virtual pfc::eventHandle_t get_trigger_event() {return pfc::eventInvalid;} - //! Returns whether the audio stream is currently being played or not. \n - //! Typically, for a short period of time, initially send data is not played until a sufficient amount is queued to initiate playback without glitches. \n - //! For old outputs that do not implement this, the value can be assumed to be true. - virtual bool is_progressing() {return true;} - - //! Improved version of update(); returns 0 if the output isn't ready to receive any new data, otherwise an advisory number of samples - at the current stream format - that the output expects to take now. \n - //! If the caller changes the stream format, the value is irrelevant. \n - //! The output may return SIZE_MAX to indicate that it can take data but does not currently have any hints to tell how much. - virtual size_t update_v2(); -}; - -//! \since 1.6 -class output_v5 : public output_v4 { - FB2K_MAKE_SERVICE_INTERFACE(output_v5, output_v4); -public: - virtual unsigned get_forced_channel_mask() { return 0; } -}; - class NOVTABLE output_entry : public service_base { FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(output_entry); public: @@ -192,34 +146,20 @@ public: //! For internal use by backend. Retrieves human-readable name of this output_entry implementation. virtual const char * get_name() = 0; - //! Obsolete, do not use. + //! Pops up advanced settings dialog. This method is optional and not supported if get_config_flag() return value does not have flag_needs_advanced_config set. + //! @param p_parent Parent window for the dialog. + //! @param p_menupoint Point in screen coordinates - can be used to display a simple popup menu with options to be checked instead of a full dialog. virtual void advanced_settings_popup(HWND p_parent,POINT p_menupoint) = 0; enum { flag_needs_bitdepth_config = 1 << 0, flag_needs_dither_config = 1 << 1, - //! Obsolete, do not use. flag_needs_advanced_config = 1 << 2, flag_needs_device_list_prefixes = 1 << 3, - - //! Supports playing multiple simultaneous audio streams thru one device? - flag_supports_multiple_streams = 1 << 4, - - //! High latency operation (such as remote network playback), mutually exclusive with flag_low_latency - flag_high_latency = 1 << 5, - //! Low latency operation (local playback), mutually exclusive with flag_high_latency - flag_low_latency = 1 << 6, - //! When set, the output will be used in special compatibility mode: guaranteed regular update() calls, injected padding (silence) at the end of stream. - flag_needs_shims = 1 << 7, }; virtual t_uint32 get_config_flags() = 0; - uint32_t get_config_flags_compat(); - - bool is_high_latency(); - bool is_low_latency(); - pfc::string8 get_device_name( const GUID & deviceID); bool get_device_name( const GUID & deviceID, pfc::string_base & out ); @@ -245,11 +185,7 @@ public: if (T::g_advanced_settings_query()) flags |= output_entry::flag_needs_advanced_config; if (T::g_needs_bitdepth_config()) flags |= output_entry::flag_needs_bitdepth_config; if (T::g_needs_dither_config()) flags |= output_entry::flag_needs_dither_config; - if (T::g_needs_device_list_prefixes()) flags |= output_entry::flag_needs_device_list_prefixes; - if (T::g_supports_multiple_streams()) flags |= output_entry::flag_supports_multiple_streams; - if (T::g_is_high_latency()) flags |= output_entry::flag_high_latency; - else flags |= output_entry::flag_low_latency; - flags |= T::g_extra_flags(); + if (T::g_needs_device_list_prefixes()) flags |= output_entry::flag_needs_device_list_prefixes ; return flags; } }; @@ -259,7 +195,7 @@ public: template class output_factory_t : public service_factory_single_t > {}; -class output_impl : public output_v5 { +class output_impl : public output_v3 { protected: output_impl() : m_incoming_ptr(0) {} virtual void on_update() = 0; @@ -280,7 +216,6 @@ private: void flush(); void flush_changing_track(); void update(bool & p_ready); - size_t update_v2(); double get_latency(); void process_samples(const audio_chunk & p_chunk); @@ -292,8 +227,8 @@ private: class NOVTABLE volume_callback { public: - virtual void on_volume_scale(float v) = 0; - virtual void on_volume_arbitrary(int v) = 0; + virtual void on_volume_scale(float v) = 0; + virtual void on_volume_arbitrary(int v) = 0; }; class NOVTABLE volume_control : public service_base { @@ -328,31 +263,6 @@ public: virtual bool hasVisualisation() = 0; }; -//! \since 1.5 -class NOVTABLE output_devices_notify { -public: - virtual void output_devices_changed() = 0; -protected: - output_devices_notify() {} -private: - output_devices_notify(const output_devices_notify &) = delete; - void operator=(const output_devices_notify &) = delete; -}; - -//! \since 1.5 -class NOVTABLE output_entry_v3 : public output_entry_v2 { - FB2K_MAKE_SERVICE_INTERFACE(output_entry_v3, output_entry_v2) -public: - - //! Main thread only! - virtual void add_notify(output_devices_notify *) = 0; - //! Main thread only! - virtual void remove_notify(output_devices_notify *) = 0; - - //! Main thread only! - virtual void set_pinned_device(const GUID & guid) = 0; -}; - #pragma pack(push, 1) //! \since 1.3.5 struct outputCoreConfig_t { diff --git a/foobar2000/SDK/packet_decoder.cpp b/foobar2000/SDK/packet_decoder.cpp index 982867d..986f7f8 100644 --- a/foobar2000/SDK/packet_decoder.cpp +++ b/foobar2000/SDK/packet_decoder.cpp @@ -1,35 +1,16 @@ #include "foobar2000.h" -#include void packet_decoder::g_open(service_ptr_t & p_out,bool p_decode,const GUID & p_owner,t_size p_param1,const void * p_param2,t_size p_param2size,abort_callback & p_abort) { - std::exception_ptr rethrow; - bool havePartial = false, tryingPartial = false; - for ( ;; ) { - service_enum_t e; - service_ptr_t ptr; - - while (e.next(ptr)) { - p_abort.check(); - if (ptr->is_our_setup(p_owner, p_param1, p_param2, p_param2size)) { - if (!tryingPartial && ptr->is_supported_partially_(p_owner, p_param1, p_param2, p_param2size)) { - havePartial = true; - } else { - try { - ptr->open(p_out, p_decode, p_owner, p_param1, p_param2, p_param2size, p_abort); - return; - } catch (exception_io_data) { - rethrow = std::current_exception(); - } - } - } + service_enum_t e; + service_ptr_t ptr; + while(e.next(ptr)) { + p_abort.check(); + if (ptr->is_our_setup(p_owner,p_param1,p_param2,p_param2size)) { + ptr->open(p_out,p_decode,p_owner,p_param1,p_param2,p_param2size,p_abort); + return; } - - if (!havePartial || tryingPartial) break; - tryingPartial = true; } - - if (rethrow) std::rethrow_exception(rethrow); throw exception_io_data(); } @@ -53,11 +34,3 @@ void packet_decoder::setAllowDelayed( bool bAllow ) { this->set_stream_property( property_allow_delayed_output, bAllow ? 1 : 0, NULL, 0); } -bool packet_decoder_entry::is_supported_partially_(const GUID& p_owner, t_size p_param1, const void* p_param2, t_size p_param2size) { - bool ret = false; - packet_decoder_entry_v2::ptr v2; - if (v2 &= this) { - ret = v2->is_supported_partially(p_owner, p_param1, p_param2, p_param2size); - } - return ret; -} \ No newline at end of file diff --git a/foobar2000/SDK/packet_decoder.h b/foobar2000/SDK/packet_decoder.h index df6b18d..f1a3063 100644 --- a/foobar2000/SDK/packet_decoder.h +++ b/foobar2000/SDK/packet_decoder.h @@ -13,10 +13,6 @@ protected: void open(const GUID & p_owner,bool p_decode,t_size p_param1,const void * p_param2,t_size p_param2size,abort_callback & p_abort) {throw exception_io_data();} public: - //! Prototype of function that must be implemented by packet_decoder implementation but is not accessible through packet_decoder interface itself. - //! Returns true if this is not the preferred decoder for this format, another one should be used if found. - static bool g_is_supported_partially(const GUID& p_owner, t_size p_param1, const void* p_param2, t_size p_param2size) { return false; } - //! Forwards additional information about stream being decoded. \n //! Calling: this must be called immediately after packet_decoder object is created, before any other methods are called.\n @@ -38,7 +34,6 @@ public: //! Decodes a block of audio data.\n //! It may return empty chunk even when successful (caused by encoder+decoder delay for an example), caller must check for it and handle it appropriately. - //! Called with 0 bytes at the end of stream - if the decoder introduces a delay between input/output, any buffered data should be passed back then. virtual void decode(const void * p_buffer,t_size p_bytes,audio_chunk & p_chunk,abort_callback & p_abort)=0; //! Returns whether this packet decoder supports analyze_first_frame() function. @@ -49,7 +44,7 @@ public: //! Static helper, creates a packet_decoder instance and initializes it with specific decoder setup data. static void g_open(service_ptr_t & p_out,bool p_decode,const GUID & p_owner,t_size p_param1,const void * p_param2,t_size p_param2size,abort_callback & p_abort); - static const GUID owner_MP4,owner_matroska,owner_MP3,owner_MP2,owner_MP1,owner_MP4_ALAC,owner_ADTS,owner_ADIF, owner_Ogg, owner_MP4_AMR, owner_MP4_AMR_WB, owner_MP4_AC3, owner_MP4_EAC3; + static const GUID owner_MP4,owner_matroska,owner_MP3,owner_MP2,owner_MP1,owner_MP4_ALAC,owner_ADTS,owner_ADIF, owner_Ogg, owner_MP4_AMR, owner_MP4_AMR_WB, owner_MP4_AC3; struct matroska_setup { @@ -87,21 +82,12 @@ public: //property_mp4_esds : p_param2 = MP4 ESDS chunk content as needed by some decoders static const GUID property_mp4_esds; - // DEPRECATED + //property_allow_delayed_output : p_param1 = bool flag indicating whether the decoder than delay outputting audio data at will; essential for Apple AQ decoder static const GUID property_allow_delayed_output; // property_mp3_delayless : return non-zero if this codec drops MP3 delay by itself static const GUID property_mp3_delayless; - - // property_query_delay_samples : - // Return non-zero if this codec has a decoder delay that the caller should deal with. - // Param1 signals sample rate used by input - should always match decoder's sample rate - return zero if it does not match. - static const GUID property_query_delay_samples; - // property_query_mp4_use_elst : - // Return non-zero if MP4 elst should be used with this codec. - static const GUID property_query_mp4_use_elst; - size_t initPadding(); void setEventLogger(event_logger::ptr logger); void setCheckingIntegrity(bool checkingIntegrity); @@ -119,40 +105,29 @@ public: FB2K_MAKE_SERVICE_INTERFACE(packet_decoder_streamparse,packet_decoder); }; -class NOVTABLE packet_decoder_entry : public service_base { - FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(packet_decoder_entry); +class NOVTABLE packet_decoder_entry : public service_base +{ public: virtual bool is_our_setup(const GUID & p_owner,t_size p_param1,const void * p_param2,t_size p_param2size) = 0; virtual void open(service_ptr_t & p_out,bool p_decode,const GUID & p_owner,t_size p_param1,const void * p_param2,t_size p_param2size,abort_callback & p_abort) = 0; - //! Returns true if this is not the preferred decoder for this format, another one should be used if found. - bool is_supported_partially_(const GUID& p_owner, t_size p_param1, const void* p_param2, t_size p_param2size); -}; - -class NOVTABLE packet_decoder_entry_v2 : public packet_decoder_entry { - FB2K_MAKE_SERVICE_INTERFACE(packet_decoder_entry_v2, packet_decoder_entry); -public: - //! Returns true if this is not the preferred decoder for this format, another one should be used if found. - virtual bool is_supported_partially(const GUID& p_owner, t_size p_param1, const void* p_param2, t_size p_param2size) = 0; + FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(packet_decoder_entry); }; template -class packet_decoder_entry_impl_t : public packet_decoder_entry_v2 +class packet_decoder_entry_impl_t : public packet_decoder_entry { public: - bool is_our_setup(const GUID & p_owner,t_size p_param1,const void * p_param2,t_size p_param2size) override { + bool is_our_setup(const GUID & p_owner,t_size p_param1,const void * p_param2,t_size p_param2size) { return T::g_is_our_setup(p_owner,p_param1,p_param2,p_param2size); } - void open(service_ptr_t & p_out,bool p_decode,const GUID & p_owner,t_size p_param1,const void * p_param2,t_size p_param2size,abort_callback & p_abort) override { + void open(service_ptr_t & p_out,bool p_decode,const GUID & p_owner,t_size p_param1,const void * p_param2,t_size p_param2size,abort_callback & p_abort) { PFC_ASSERT(is_our_setup(p_owner,p_param1,p_param2,p_param2size)); service_ptr_t instance = new service_impl_t(); instance->open(p_owner,p_decode,p_param1,p_param2,p_param2size,p_abort); p_out = instance.get_ptr(); } - bool is_supported_partially(const GUID& p_owner, t_size p_param1, const void* p_param2, t_size p_param2size) override { - return T::g_is_supported_partially(p_owner, p_param1, p_param2, p_param2size); - } }; template diff --git a/foobar2000/SDK/play_callback.h b/foobar2000/SDK/play_callback.h index 8c85d96..0113e12 100644 --- a/foobar2000/SDK/play_callback.h +++ b/foobar2000/SDK/play_callback.h @@ -5,26 +5,26 @@ Use play_callback_manager to register your dynamically created instances. Static class NOVTABLE play_callback { public: //! Playback process is being initialized. on_playback_new_track() should be called soon after this when first file is successfully opened for decoding. - virtual void on_playback_starting(play_control::t_track_command p_command,bool p_paused) = 0; + virtual void FB2KAPI on_playback_starting(play_control::t_track_command p_command,bool p_paused) = 0; //! Playback advanced to new track. - virtual void on_playback_new_track(metadb_handle_ptr p_track) = 0; + virtual void FB2KAPI on_playback_new_track(metadb_handle_ptr p_track) = 0; //! Playback stopped. - virtual void on_playback_stop(play_control::t_stop_reason p_reason) = 0; + virtual void FB2KAPI on_playback_stop(play_control::t_stop_reason p_reason) = 0; //! User has seeked to specific time. - virtual void on_playback_seek(double p_time) = 0; + virtual void FB2KAPI on_playback_seek(double p_time) = 0; //! Called on pause/unpause. - virtual void on_playback_pause(bool p_state) = 0; + virtual void FB2KAPI on_playback_pause(bool p_state) = 0; //! Called when currently played file gets edited. - virtual void on_playback_edited(metadb_handle_ptr p_track) = 0; + virtual void FB2KAPI on_playback_edited(metadb_handle_ptr p_track) = 0; //! Dynamic info (VBR bitrate etc) change. - virtual void on_playback_dynamic_info(const file_info & p_info) = 0; + virtual void FB2KAPI on_playback_dynamic_info(const file_info & p_info) = 0; //! Per-track dynamic info (stream track titles etc) change. Happens less often than on_playback_dynamic_info(). - virtual void on_playback_dynamic_info_track(const file_info & p_info) = 0; + virtual void FB2KAPI on_playback_dynamic_info_track(const file_info & p_info) = 0; //! Called every second, for time display - virtual void on_playback_time(double p_time) = 0; + virtual void FB2KAPI on_playback_time(double p_time) = 0; //! User changed volume settings. Possibly called when not playing. //! @param p_new_val new volume level in dB; 0 for full volume. - virtual void on_volume_change(float p_new_val) = 0; + virtual void FB2KAPI on_volume_change(float p_new_val) = 0; enum { flag_on_playback_starting = 1 << 0, @@ -51,23 +51,25 @@ protected: //! Standard API (always present); manages registrations of dynamic play_callbacks. \n //! Usage: use play_callback_manager::get() to obtain on instance. \n //! Do not reimplement. -class NOVTABLE play_callback_manager : public service_base { - FB2K_MAKE_SERVICE_COREAPI(play_callback_manager); +class NOVTABLE play_callback_manager : public service_base +{ public: //! Registers a play_callback object. //! @param p_callback Interface to register. //! @param p_flags Indicates which notifications are requested. //! @param p_forward_status_on_register Set to true to have the callback immediately receive current playback status as notifications if playback is active (eg. to receive info about playback process that started before our callback was registered). - virtual void register_callback(play_callback * p_callback,unsigned p_flags,bool p_forward_status_on_register) = 0; + virtual void FB2KAPI register_callback(play_callback * p_callback,unsigned p_flags,bool p_forward_status_on_register) = 0; //! Unregisters a play_callback object. //! @p_callback Previously registered interface to unregister. - virtual void unregister_callback(play_callback * p_callback) = 0; + virtual void FB2KAPI unregister_callback(play_callback * p_callback) = 0; + + FB2K_MAKE_SERVICE_COREAPI(play_callback_manager); }; //! Implementation helper. class play_callback_impl_base : public play_callback { public: - play_callback_impl_base(unsigned p_flags = UINT_MAX) { + play_callback_impl_base(unsigned p_flags = ~0) { play_callback_manager::get()->register_callback(this,p_flags,false); } ~play_callback_impl_base() { @@ -94,10 +96,11 @@ public: //! Static (autoregistered) version of play_callback. Use play_callback_static_factory_t to register. class play_callback_static : public service_base, public play_callback { - FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(play_callback_static); public: //! Controls which methods your callback wants called; returned value should not change in run time, you should expect it to be queried only once (on startup). See play_callback::flag_* constants. virtual unsigned get_flags() = 0; + + FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(play_callback_static); }; template @@ -107,9 +110,10 @@ class play_callback_static_factory_t : public service_factory_single_t {}; //! Gets notified about tracks being played. Notification occurs when at least 60s of the track has been played, or the track has reached its end after at least 1/3 of it has been played through. //! Use playback_statistics_collector_factory_t to register. class NOVTABLE playback_statistics_collector : public service_base { - FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(playback_statistics_collector); public: virtual void on_item_played(metadb_handle_ptr p_item) = 0; + + FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(playback_statistics_collector); }; template diff --git a/foobar2000/SDK/playable_location.h b/foobar2000/SDK/playable_location.h index d43c2d0..c1ffebb 100644 --- a/foobar2000/SDK/playable_location.h +++ b/foobar2000/SDK/playable_location.h @@ -36,9 +36,6 @@ public: bool is_valid() const; - enum {case_sensitive = true}; - typedef pfc::comparator_strcmp path_comparator; - class comparator { public: static int compare(const playable_location & v1, const playable_location & v2) {return g_compare(v1,v2);} diff --git a/foobar2000/SDK/playback_stream_capture.h b/foobar2000/SDK/playback_stream_capture.h index f9a33e2..240be60 100644 --- a/foobar2000/SDK/playback_stream_capture.h +++ b/foobar2000/SDK/playback_stream_capture.h @@ -1,7 +1,4 @@ -#pragma once - //! \since 1.0 -//! Implemented by components - register with playback_stream_capture methods. class NOVTABLE playback_stream_capture_callback { public: //! Delivers a real-time chunk of audio data. \n @@ -14,12 +11,13 @@ protected: }; //! \since 1.0 -//! Implemented by core. class NOVTABLE playback_stream_capture : public service_base { - FB2K_MAKE_SERVICE_COREAPI(playback_stream_capture) public: //! Possible to call only from the main thread. virtual void add_callback(playback_stream_capture_callback * ) = 0; //! Possible to call only from the main thread. virtual void remove_callback(playback_stream_capture_callback * ) = 0; + + + FB2K_MAKE_SERVICE_COREAPI(playback_stream_capture) }; diff --git a/foobar2000/SDK/playlist.cpp b/foobar2000/SDK/playlist.cpp index 14ddbd3..7091dee 100644 --- a/foobar2000/SDK/playlist.cpp +++ b/foobar2000/SDK/playlist.cpp @@ -90,14 +90,12 @@ void playlist_manager::playlist_get_all_items(t_size p_playlist,pfc::list_base_t void playlist_manager::playlist_get_selected_items(t_size p_playlist,pfc::list_base_t & out) { - enum_items_callback_retrieve_selected_items cb(out); - playlist_enum_items(p_playlist,cb,pfc::bit_array_true()); + playlist_enum_items(p_playlist,enum_items_callback_retrieve_selected_items(out),pfc::bit_array_true()); } void playlist_manager::playlist_get_selection_mask(t_size p_playlist,bit_array_var & out) { - enum_items_callback_retrieve_selection_mask cb(out); - playlist_enum_items(p_playlist,cb,pfc::bit_array_true()); + playlist_enum_items(p_playlist,enum_items_callback_retrieve_selection_mask(out),pfc::bit_array_true()); } bool playlist_manager::playlist_is_item_selected(t_size p_playlist,t_size p_item) @@ -134,9 +132,8 @@ bool playlist_manager::playlist_move_selection(t_size p_playlist,int p_delta) { pfc::array_t order; order.set_size(count); pfc::array_t selection; selection.set_size(count); - pfc::bit_array_var_table mask(selection.get_ptr(),selection.get_size()); - playlist_get_selection_mask(p_playlist, mask); - g_make_selection_move_permutation(order.get_ptr(),count,mask,p_delta); + playlist_get_selection_mask(p_playlist, pfc::bit_array_var_table(selection.get_ptr(),selection.get_size())); + g_make_selection_move_permutation(order.get_ptr(),count, pfc::bit_array_table(selection.get_ptr(),selection.get_size()),p_delta); return playlist_reorder_items(p_playlist,order.get_ptr(),count); } @@ -552,8 +549,7 @@ bool playlist_manager::highlight_playing_item() void playlist_manager::playlist_get_items(t_size p_playlist,pfc::list_base_t & out,const bit_array & p_mask) { - enum_items_callback_retrieve_all_items cb(out); - playlist_enum_items(p_playlist,cb,p_mask); + playlist_enum_items(p_playlist,enum_items_callback_retrieve_all_items(out),p_mask); } void playlist_manager::activeplaylist_get_items(pfc::list_base_t & out,const bit_array & p_mask) diff --git a/foobar2000/SDK/playlist.h b/foobar2000/SDK/playlist.h index 669bfea..28a7947 100644 --- a/foobar2000/SDK/playlist.h +++ b/foobar2000/SDK/playlist.h @@ -441,8 +441,7 @@ public: //! \param p_data array that contains the data that will be associated with the property template void playlist_set_property(t_size p_playlist,const GUID & p_property,const t_array & p_data) { PFC_STATIC_ASSERT( sizeof(p_data[0]) == 1 ); - stream_reader_memblock_ref reader(p_data); - playlist_set_property(p_playlist,p_property,&reader,p_data.get_size(),fb2k::noAbort); + playlist_set_property(p_playlist,p_property,&stream_reader_memblock_ref(p_data),p_data.get_size(),abort_callback_dummy()); } //! Read a persistent playlist property. //! \param p_playlist Index of the playlist @@ -453,10 +452,7 @@ public: PFC_STATIC_ASSERT( sizeof(p_data[0]) == 1 ); typedef pfc::array_t t_temp; t_temp temp; - { - stream_writer_buffer_append_ref_t reader(temp); - if (!playlist_get_property(p_playlist,p_property,&reader,fb2k::noAbort)) return false; - } + if (!playlist_get_property(p_playlist,p_property,&stream_writer_buffer_append_ref_t(temp),abort_callback_dummy())) return false; p_data = temp; return true; } diff --git a/foobar2000/SDK/playlist_loader.cpp b/foobar2000/SDK/playlist_loader.cpp index 8f0bf75..6a9743c 100644 --- a/foobar2000/SDK/playlist_loader.cpp +++ b/foobar2000/SDK/playlist_loader.cpp @@ -155,7 +155,7 @@ static void track_indexer__g_get_tracks_wrap(const char * p_path,const service_p fail = true; } catch(std::exception const & e) { fail = true; - FB2K_console_formatter() << "could not enumerate tracks (" << e << ") on:\n" << file_path_display(p_path); + console::formatter() << "could not enumerate tracks (" << e << ") on:\n" << file_path_display(p_path); } if (fail) { if (!got_input && !p_abort.is_aborting()) { @@ -276,7 +276,7 @@ static void process_path_internal(const char * p_path,const service_ptr_t while(e.next(f)) { abort.check(); service_ptr_t arch; - if (f->service_query_t(arch) && arch->is_our_archive(p_path)) { + if (f->service_query_t(arch)) { if (p_reader.is_valid()) p_reader->reopen(abort); try { diff --git a/foobar2000/SDK/popup_message.cpp b/foobar2000/SDK/popup_message.cpp index 9c24518..bbbd278 100644 --- a/foobar2000/SDK/popup_message.cpp +++ b/foobar2000/SDK/popup_message.cpp @@ -22,16 +22,6 @@ void popup_message::g_complain(const char * p_whatFailed, const char * msg) { g_complain( PFC_string_formatter() << p_whatFailed << ": " << msg ); } -#if FOOBAR2000_TARGET_VERSION >= 80 -void popup_message_v3::show_query( const char * title, const char * msg, unsigned buttons, completion_notify::ptr reply) { - query_t q; - q.title = title; q.msg = msg; q.buttons = buttons; q.reply = reply; - this->show_query( q ); -} -#endif - - -#ifdef FOOBAR2000_DESKTOP_WINDOWS void popup_message_v2::g_show(HWND parent, const char * msg, const char * title) { service_enum_t< popup_message_v2 > e; service_ptr_t< popup_message_v2 > m; @@ -47,91 +37,3 @@ void popup_message_v2::g_complain(HWND parent, const char * whatFailed, const ch void popup_message_v2::g_complain(HWND parent, const char * whatFailed, const std::exception & e) { g_complain(parent, whatFailed, e.what()); } -#endif // FOOBAR2000_DESKTOP_WINDOWS - -#ifdef FOOBAR2000_MODERN -void fb2k::showToast( const char * msg ) { - fb2k::popup_toast::arg_t arg; - fb2k::popup_toast::get()->show_toast(msg, arg); -} - -void fb2k::showToastLongDuration( const char * msg ) { - fb2k::popup_toast::arg_t arg; - arg.longDuration = true; - fb2k::popup_toast::get()->show_toast(msg, arg); -} -void popup_message::g_showToast(const char * msg) { - fb2k::showToast( msg ); -} -void popup_message::g_showToastLongDuration(const char * msg) { - fb2k::showToastLongDuration( msg ); -} - -#endif // FOOBAR2000_MODERN - -#if defined(FOOBAR2000_DESKTOP_WINDOWS) && FOOBAR2000_TARGET_VERSION >= 80 -int popup_message_v3::messageBox(HWND parent, const char* msg, const char* title, UINT flags) { - query_t q = {}; - q.title = title; - q.msg = msg; - q.wndParent = parent; - - switch (flags & 0xF) { - default: - case MB_OK: - q.buttons = buttonOK; - q.defButton = buttonOK; - break; - case MB_OKCANCEL: - q.buttons = buttonOK | buttonCancel; - q.defButton = (flags & MB_DEFBUTTON2) ? buttonCancel : buttonOK; - break; - case MB_ABORTRETRYIGNORE: - q.buttons = buttonAbort | buttonRetry | buttonIgnore; - if (flags & MB_DEFBUTTON3) q.defButton = buttonIgnore; - else if (flags & MB_DEFBUTTON2) q.defButton = buttonRetry; - else q.defButton = buttonAbort; - break; - case MB_YESNOCANCEL: - q.buttons = buttonYes | buttonNo | buttonCancel; - if (flags & MB_DEFBUTTON3) q.defButton = buttonCancel; - else if (flags & MB_DEFBUTTON2) q.defButton = buttonNo; - else q.defButton = buttonYes; - break; - case MB_YESNO: - q.buttons = buttonYes | buttonNo; - q.defButton = (flags & MB_DEFBUTTON2) ? buttonNo : buttonYes; - break; - case MB_RETRYCANCEL: - q.buttons = buttonRetry | buttonCancel; - q.defButton = (flags & MB_DEFBUTTON2) ? buttonCancel : buttonRetry; - break; - } - switch (flags & 0xF0) { - case MB_ICONHAND: - q.icon = iconWarning; - break; - case MB_ICONQUESTION: - q.icon = iconQuestion; - break; - case MB_ICONEXCLAMATION: - q.icon = iconError; - break; - case MB_ICONASTERISK: - q.icon = iconInformation; - break; - } - - uint32_t status = this->show_query_modal(q); - - if (status & buttonOK) return IDOK; - if (status & buttonCancel) return IDCANCEL; - if (status & buttonYes) return IDYES; - if (status & buttonNo) return IDNO; - if (status & buttonRetry) return IDRETRY; - if (status & buttonAbort) return IDABORT; - if (status & buttonIgnore) return IDIGNORE; - - return -1; -} -#endif diff --git a/foobar2000/SDK/popup_message.h b/foobar2000/SDK/popup_message.h index f3e7cbf..1710bfa 100644 --- a/foobar2000/SDK/popup_message.h +++ b/foobar2000/SDK/popup_message.h @@ -1,8 +1,3 @@ -#pragma once - -#include // UINT_MAX - -#include "completion_notify.h" //! This interface allows you to show generic nonmodal noninteractive dialog with a text message. This should be used instead of MessageBox where possible.\n //! Usage: use popup_message::g_show / popup_message::g_show_ex static helpers, or popup_message::get() to obtain an instance.\n @@ -23,12 +18,12 @@ public: //! @param p_msg Message to show (UTF-8 encoded string). //! @param p_title Title of dialog to show (UTF-8 encoded string). //! @param p_icon Icon of the dialog - can be set to icon_information, icon_error or icon_query. - inline void show(const char * p_msg,const char * p_title,t_icon p_icon = icon_information) {show_ex(p_msg,UINT_MAX,p_title,UINT_MAX,p_icon);} + inline void show(const char * p_msg,const char * p_title,t_icon p_icon = icon_information) {show_ex(p_msg,~0,p_title,~0,p_icon);} //! Static helper function instantiating the service and activating the message dialog. See show_ex() for description of parameters. static void g_show_ex(const char * p_msg,unsigned p_msg_length,const char * p_title,unsigned p_title_length,t_icon p_icon = icon_information); //! Static helper function instantiating the service and activating the message dialog. See show() for description of parameters. - static inline void g_show(const char * p_msg,const char * p_title,t_icon p_icon = icon_information) {g_show_ex(p_msg,UINT_MAX,p_title,UINT_MAX,p_icon);} + static inline void g_show(const char * p_msg,const char * p_title,t_icon p_icon = icon_information) {g_show_ex(p_msg,~0,p_title,~0,p_icon);} //! Shows generic box with a failure message static void g_complain(const char * what); @@ -37,20 +32,14 @@ public: //! : static void g_complain(const char * p_whatFailed, const char * msg); -#ifdef FOOBAR2000_MODERN - static void g_showToast(const char * msg); - static void g_showToastLongDuration(const char * msg); -#endif - - FB2K_MAKE_SERVICE_COREAPI(popup_message); + FB2K_MAKE_SERVICE_COREAPI(popup_message); }; #define EXCEPTION_TO_POPUP_MESSAGE(CODE,LABEL) try { CODE; } catch(std::exception const & e) {popup_message::g_complain(LABEL,e);} -#ifdef FOOBAR2000_DESKTOP_WINDOWS //! \since 1.1 class NOVTABLE popup_message_v2 : public service_base { - FB2K_MAKE_SERVICE_COREAPI(popup_message_v2); + FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(popup_message_v2); public: virtual void show(HWND parent, const char * msg, t_size msg_length, const char * title, t_size title_length) = 0; void show(HWND parent, const char * msg, const char * title) {show(parent, msg, ~0, title, ~0);} @@ -59,83 +48,3 @@ public: static void g_complain(HWND parent, const char * whatFailed, const char * msg); static void g_complain(HWND parent, const char * whatFailed, const std::exception & e); }; -#endif - -#ifdef FOOBAR2000_MODERN -namespace fb2k { - class popup_toast : public service_base { - FB2K_MAKE_SERVICE_COREAPI( popup_toast ); - public: - struct arg_t { - bool longDuration = false; - }; - virtual void show_toast(const char * msg, arg_t const & arg) = 0; - }; - void showToast( const char * msg ); - void showToastLongDuration( const char * msg ); - - class toastFormatter : public pfc::string_formatter { - public: - ~toastFormatter() { - if ( this->length() > 0 ) showToast( c_str() ); - } - }; -} - -#define FB2K_Toast() ::fb2k::toastFormatter()._formatter() -#endif - -#if FOOBAR2000_TARGET_VERSION >= 80 -//! \since 1.5 -class NOVTABLE popup_message_v3 : public service_base { - FB2K_MAKE_SERVICE_COREAPI(popup_message_v3); -public: - - //! show_query button codes. \n - //! Combine one or more of these to create a button mask to pass to show_query(). - enum { - buttonOK = 1 << 0, - buttonCancel = 1 << 1, - buttonYes = 1 << 2, - buttonNo = 1 << 3, - buttonRetry = 1 << 4, - buttonAbort = 1 << 5, - buttonIgnore = 1 << 6, - - flagDoNotAskAgain = 1 << 16, - - iconNone = 0, - iconInformation, - iconQuestion, - iconWarning, - iconError, - }; - - struct query_t { - const char * title = nullptr; - const char * msg = nullptr; - uint32_t buttons = 0; - uint32_t defButton = 0; - uint32_t icon = iconNone; - completion_notify::ptr reply; -#ifdef _WIN32 - HWND wndParent = NULL; -#endif - const char * msgDoNotAskAgain = nullptr; - }; - - //! Shows an interactive query presenting the user with multiple actions to choose from. - virtual void show_query(query_t const &) = 0; - - //! Modal version of show_query. Reply part of the argument can be empty; the status code will be returned. - virtual uint32_t show_query_modal(query_t const &) = 0; - -#ifdef FOOBAR2000_DESKTOP_WINDOWS - // Minimalist MessageBox() reimplementation wrapper - int messageBox(HWND, const char*, const char*, UINT); -#endif - - //! Old method wrapper - void show_query( const char * title, const char * msg, unsigned buttons, completion_notify::ptr reply); -}; -#endif // FOOBAR2000_TARGET_VERSION >= 80 diff --git a/foobar2000/SDK/preferences_page.h b/foobar2000/SDK/preferences_page.h index 6059cc4..47ff174 100644 --- a/foobar2000/SDK/preferences_page.h +++ b/foobar2000/SDK/preferences_page.h @@ -1,5 +1,3 @@ -#pragma once - //! Implementing this service will generate a page in preferences dialog. Use preferences_page_factory_t template to register. \n //! In 1.0 and newer you should always derive from preferences_page_v3 rather than from preferences_page directly. class NOVTABLE preferences_page : public service_base { @@ -21,9 +19,7 @@ public: static void get_help_url_helper(pfc::string_base & out, const char * category, const GUID & id, const char * name); - static const GUID guid_root, guid_hidden, guid_tools,guid_core,guid_display,guid_playback,guid_visualisations,guid_input,guid_tag_writing,guid_media_library, guid_tagging, guid_output, guid_advanced, guid_components; - //! \since 1.5 - static const GUID guid_input_info_filter; + static const GUID guid_root, guid_hidden, guid_tools,guid_core,guid_display,guid_playback,guid_visualisations,guid_input,guid_tag_writing,guid_media_library, guid_tagging; FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(preferences_page); }; @@ -137,14 +133,7 @@ class preferences_page_v3 : public preferences_page_v2 { public: virtual preferences_page_instance::ptr instantiate(HWND parent, preferences_page_callback::ptr callback) = 0; private: - HWND create(HWND) {throw pfc::exception_not_implemented();} //stub + HWND create(HWND p_parent) {throw pfc::exception_not_implemented();} //stub bool reset_query() {return false;} //stub - the new apply-friendly reset should be used instead. void reset() {} //stub }; - -//! \since 1.5 -class NOVTABLE preferences_page_v4 : public preferences_page_v3 { - FB2K_MAKE_SERVICE_INTERFACE(preferences_page_v4, preferences_page_v3); -public: - virtual bool is_hidden() = 0; -}; diff --git a/foobar2000/SDK/progress_meter.h b/foobar2000/SDK/progress_meter.h index 0d120da..7021d5f 100644 --- a/foobar2000/SDK/progress_meter.h +++ b/foobar2000/SDK/progress_meter.h @@ -7,8 +7,6 @@ public: virtual void set_progress(float value) = 0; //! Toggles paused state. virtual void set_pause(bool isPaused) = 0; - - static bool serviceRequiresMainThreadDestructor() { return true; } }; //! Entrypoint interface for instantiating progress_meter_instance objects. diff --git a/foobar2000/SDK/replaygain_info.cpp b/foobar2000/SDK/replaygain_info.cpp index 663d71e..eaec32f 100644 --- a/foobar2000/SDK/replaygain_info.cpp +++ b/foobar2000/SDK/replaygain_info.cpp @@ -115,21 +115,22 @@ float replaygain_info::anyGain(bool bPreferAlbum) const { } } -float replaygain_info::g_parse_gain_text(const char * p_text, t_size p_text_len) { +void replaygain_info::set_album_gain_text(const char * p_text,t_size p_text_len) +{ RG_FPU(); if (p_text != 0 && p_text_len > 0 && *p_text != 0) - return (float)pfc::string_to_float(p_text, p_text_len); + m_album_gain = (float)pfc::string_to_float(p_text,p_text_len); else - return gain_invalid; -} - -void replaygain_info::set_album_gain_text(const char * p_text,t_size p_text_len) { - m_album_gain = g_parse_gain_text(p_text, p_text_len); + remove_album_gain(); } void replaygain_info::set_track_gain_text(const char * p_text,t_size p_text_len) { - m_track_gain = g_parse_gain_text(p_text, p_text_len); + RG_FPU(); + if (p_text != 0 && p_text_len > 0 && *p_text != 0) + m_track_gain = (float)pfc::string_to_float(p_text,p_text_len); + else + remove_track_gain(); } void replaygain_info::set_album_peak_text(const char * p_text,t_size p_text_len) diff --git a/foobar2000/SDK/replaygain_scanner.h b/foobar2000/SDK/replaygain_scanner.h index 03cceda..0a658b3 100644 --- a/foobar2000/SDK/replaygain_scanner.h +++ b/foobar2000/SDK/replaygain_scanner.h @@ -73,14 +73,6 @@ public: virtual replaygain_scanner::ptr instantiate(uint32_t flags) = 0; }; -//! Internal service introduced in 1.5. No guarantees about compatibility. May be changed or removed at any time. -class replaygain_scanner_config : public service_base { - FB2K_MAKE_SERVICE_COREAPI(replaygain_scanner_config); -public: - virtual void get_album_pattern( pfc::string_base & out ) = 0; - virtual uint64_t get_read_size_bytes() = 0; -}; - #ifdef FOOBAR2000_DESKTOP //! \since 1.4 //! A class for applying gain to compressed audio packets such as MP3 or AAC. \n diff --git a/foobar2000/SDK/resampler.h b/foobar2000/SDK/resampler.h index 161642a..9728cd5 100644 --- a/foobar2000/SDK/resampler.h +++ b/foobar2000/SDK/resampler.h @@ -2,11 +2,6 @@ #ifdef FOOBAR2000_HAVE_DSP -//! A resampler DSP entry. \n -//! It is STRICTLY REQUIRED that the output is: \n -//! (A) In the requested sample rate (specified when creating the preset), \n -//! (B) .. or untouched if the conversion cannot be performed / there's no conversion to be performed (input rate == output rate). \n -//! Not every resampler supports every possible sample rate conversion ratio. Bundled PPHS resampler (always installed since foobar2000 v1.6) does accept every possible conversion. class NOVTABLE resampler_entry : public dsp_entry { public: @@ -40,36 +35,9 @@ class resampler_factory_t : public service_factory_single_tservice_add_ref(); - fb2k::inMainThread( [ptr] { - try { ptr->service_release(); } catch(...) {} - } ); + void release_object_delayed(service_ptr obj) { + main_thread_callback_manager::get()->add_callback(new service_impl_t(obj)); } }; @@ -38,11 +49,6 @@ void _standard_api_create_internal(service_ptr & out, const GUID & classID) { service_class_ref c = service_factory_base::enum_find_class(classID); switch(service_factory_base::enum_get_count(c)) { case 0: -#if PFC_DEBUG - if ( core_api::are_services_available() ) { - FB2K_DebugLog() << "Service not found of type: " << pfc::print_guid(classID); - } -#endif throw exception_service_not_found(); case 1: PFC_ASSERT_SUCCESS( service_factory_base::enum_create(out, c, 0) ); diff --git a/foobar2000/SDK/service.h b/foobar2000/SDK/service.h index 6ac530c..5f6982b 100644 --- a/foobar2000/SDK/service.h +++ b/foobar2000/SDK/service.h @@ -18,6 +18,16 @@ PFC_DECLARE_EXCEPTION(exception_service_duplicated,pfc::exception,"Service dupli #define DECLARE_GUID(NAME,A,S,D,F,G,H,J,K,L,Z,X) FOOGUIDDECL const GUID NAME = {A,S,D,{F,G,H,J,K,L,Z,X}}; #define DECLARE_CLASS_GUID(NAME,A,S,D,F,G,H,J,K,L,Z,X) FOOGUIDDECL const GUID NAME::class_guid = {A,S,D,{F,G,H,J,K,L,Z,X}}; +//! Special hack to ensure errors when someone tries to ->service_add_ref()/->service_release() on a service_ptr_t +template class service_obscure_refcounting : public T { +private: + int service_add_ref() throw(); + int service_release() throw(); +}; + +//! Converts a service interface pointer to a pointer that obscures service counter functionality. +template static inline service_obscure_refcounting* service_obscure_refcounting_cast(T * p_source) throw() {return static_cast*>(p_source);} + //Must be templated instead of taking service_base* because of multiple inheritance issues. template static void service_release_safe(T * p_ptr) throw() { if (p_ptr != NULL) PFC_ASSERT_NO_EXCEPTION( p_ptr->service_release() ); @@ -34,7 +44,6 @@ template class service_ptr_base_t { public: inline T* get_ptr() const throw() {return m_ptr;} - typedef T obj_t; protected: T * m_ptr; }; @@ -42,10 +51,6 @@ protected: // forward declaration template class service_nnptr_t; -template struct forced_cast_t { - T* ptr; -}; - //! Autopointer class to be used with all services. Manages reference counter calls behind-the-scenes. template class service_ptr_t : public service_ptr_base_t { @@ -101,7 +106,6 @@ public: return *this; } - inline void reset() throw() { release(); } inline void release() throw() { service_release_safe(this->m_ptr); @@ -109,15 +113,7 @@ public: } - inline T* operator->() const throw() { -#if PFC_DEBUG - if (this->m_ptr == NULL) { - FB2K_DebugLog() << "service_ptr operator-> on a null pointer, type: " << T::debugServiceName(); - uBugCheck(); - } -#endif - return this->m_ptr; - } + inline service_obscure_refcounting* operator->() const throw() {PFC_ASSERT(this->m_ptr != NULL);return service_obscure_refcounting_cast(this->m_ptr);} inline T* get_ptr() const throw() {return this->m_ptr;} @@ -170,8 +166,8 @@ public: //! Forced cast operator - obtains a valid service pointer to the expected class or crashes the app if such pointer cannot be obtained. template void operator ^= ( otherPtr_t other ) { - if (other.is_empty()) release(); - else forcedCastFrom(other); + if (other.is_empty()) release(); // allow null ptr, get upset only on type mismatch + else if (!other->cast(*this)) uBugCheck(); } template void operator ^= ( otherObj_t * other ) { @@ -179,15 +175,10 @@ public: else forcedCastFrom( other ); } - bool testForInterface(const GUID & guid) const { - if (this->m_ptr == nullptr) return false; - service_ptr_t dummy; - return this->m_ptr->service_query(dummy, guid); - } //! Conditional cast operator - attempts to obtain a vaild service pointer to the expected class; returns true on success, false on failure. template bool operator &= ( otherPtr_t other ) { - if (other.is_empty()) return false; + PFC_ASSERT( other.is_valid() ); return other->cast(*this); } template @@ -196,28 +187,6 @@ public: return other->cast( *this ); } - template - void operator=(forced_cast_t other) { - if (other.ptr == NULL) release(); - else forcedCastFrom(other.ptr); - } - - //! Alternate forcedCast syntax, for contexts where operator^= fails to compile. \n - //! Usage: target = source.forcedCast(); - forced_cast_t forcedCast() const { - forced_cast_t r = { this->m_ptr }; - return r; - } - - template - void forcedCastFrom(source_t const & other) { - if (!other->cast(*this)) { -#if PFC_DEBUG - FB2K_DebugLog() << "Forced cast failure: " << pfc::print_guid(T::class_guid); -#endif - uBugCheck(); - } - } }; //! Autopointer class to be used with all services. Manages reference counter calls behind-the-scenes. \n @@ -262,7 +231,7 @@ public: template inline t_self & operator=(service_ptr_t && p_source) throw() {this->m_ptr->service_release(); this->m_ptr = p_source.detach();} - inline T* operator->() const throw() {PFC_ASSERT(this->m_ptr != NULL);return this->m_ptr;} + inline service_obscure_refcounting* operator->() const throw() {PFC_ASSERT(this->m_ptr != NULL);return service_obscure_refcounting_cast(this->m_ptr);} inline T* get_ptr() const throw() {return this->m_ptr;} @@ -295,11 +264,6 @@ public: static bool _as_base_ptr_check() { return static_cast((T*)NULL) == reinterpret_cast((T*)NULL); } - - forced_cast_t forcedCast() const { - forced_cast_t r = { this->m_ptr }; - return r; - } }; namespace pfc { @@ -313,6 +277,11 @@ namespace pfc { } +template class t_alloc = pfc::alloc_fast> +class service_list_t : public pfc::list_t, t_alloc > +{ +}; + //! For internal use, see FB2K_MAKE_SERVICE_INTERFACE #define FB2K_MAKE_SERVICE_INTERFACE_EX(THISCLASS,PARENTCLASS,IS_CORE_API) \ public: \ @@ -325,7 +294,6 @@ namespace pfc { typedef service_nnptr_t nnptr; \ typedef ptr ref; \ typedef nnptr nnref; \ - static const char * debugServiceName() { return #THISCLASS; } \ enum { _is_core_api = IS_CORE_API }; \ protected: \ THISCLASS() {} \ @@ -345,7 +313,6 @@ namespace pfc { #define FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT_EX(THISCLASS, IS_CORE_API) \ public: \ typedef THISCLASS t_interface_entrypoint; \ - static service_enum_t enumerate() { return service_enum_t(); } \ FB2K_MAKE_SERVICE_INTERFACE_EX(THISCLASS,service_base, IS_CORE_API) //! Helper macro for use when defining a service class. Generates standard features of a service, without ability to register using service_factory / enumerate using service_enum_t. \n @@ -364,17 +331,11 @@ namespace pfc { #define FB2K_MAKE_SERVICE_COREAPI(THISCLASS) \ FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT_EX( THISCLASS, true ) \ -public: \ - static ptr get() { return fb2k::std_api_get(); } \ - static bool tryGet(ptr & out) { return fb2k::std_api_try_get(out); } \ - static ptr tryGet() { ptr ret; tryGet(ret); return ret; } + public: static ptr get() { return fb2k::std_api_get(); } static bool tryGet(ptr & out) { return fb2k::std_api_try_get(out); } #define FB2K_MAKE_SERVICE_COREAPI_EXTENSION(THISCLASS, BASECLASS) \ FB2K_MAKE_SERVICE_INTERFACE_EX( THISCLASS, BASECLASS, true ) \ -public: \ - static ptr get() { return fb2k::std_api_get(); } \ - static bool tryGet(ptr & out) { return fb2k::std_api_try_get(out); } \ - static ptr tryGet() { ptr ret; tryGet(ret); return ret; } + public: static ptr get() { return fb2k::std_api_get(); } static bool tryGet(ptr & out) { return fb2k::std_api_try_get(out); } @@ -398,6 +359,7 @@ class service_base; typedef service_ptr_t service_ptr; typedef service_nnptr_t service_nnptr; + //! Base class for all service classes.\n //! Provides interfaces for reference counter and querying for different interfaces supported by the object.\n class NOVTABLE service_base @@ -433,14 +395,8 @@ public: typedef service_base t_interface; enum { _is_core_api = false }; - static const char * debugServiceName() {return "service_base"; } - static bool serviceRequiresMainThreadDestructor() { return false; } -#ifdef FOOBAR2000_MODERN - static bool shouldRegisterService() { return true; } -#endif - service_base * as_service_base() { return this; } protected: service_base() {} @@ -466,6 +422,7 @@ private: const service_base & operator=(const service_base&) = delete; }; + template inline void _validate_service_class_helper() { _validate_service_class_helper(); @@ -475,48 +432,6 @@ template<> inline void _validate_service_class_helper() {} -#include "service_impl.h" - -class NOVTABLE service_factory_base { -protected: - inline service_factory_base(const GUID & p_guid, service_factory_base * & factoryList = __internal__list) : m_guid(p_guid) { PFC_ASSERT(!core_api::are_services_available()); __internal__next = factoryList; factoryList = this; } -public: - inline const GUID & get_class_guid() const {return m_guid;} - - static service_class_ref enum_find_class(const GUID & p_guid); - static bool enum_create(service_ptr_t & p_out,service_class_ref p_class,t_size p_index); - static t_size enum_get_count(service_class_ref p_class); - - inline static bool is_service_present(const GUID & g) {return enum_get_count(enum_find_class(g))>0;} - - //! Throws std::bad_alloc or another exception on failure. - virtual void instance_create(service_ptr_t & p_out) = 0; -#ifdef FOOBAR2000_MODERN - virtual bool should_register() { return true; } -#endif - - //! FOR INTERNAL USE ONLY - static service_factory_base *__internal__list; - //! FOR INTERNAL USE ONLY - service_factory_base * __internal__next; -private: - const GUID & m_guid; -}; - -template -class service_factory_traits { -public: - static service_factory_base * & factory_list() {return service_factory_base::__internal__list;} -}; - -template -class service_factory_base_t : public service_factory_base { -public: - service_factory_base_t() : service_factory_base(B::class_guid, service_factory_traits::factory_list()) { - pfc::assert_same_type(); - } -}; - template static void _validate_service_ptr(service_ptr_t const & ptr) { PFC_ASSERT( ptr.is_valid() ); service_ptr_t test; @@ -597,12 +512,7 @@ template inline void standard_api_create_t(service_ptr_t & p_out) } else { service_ptr_t temp; standard_api_create_t(temp); - if (!temp->service_query_t(p_out)) { -#if PFC_DEBUG - FB2K_DebugLog() << "Service extension not found: " << T::debugServiceName() << " (" << pfc::print_guid(T::class_guid) << ") of base type: " << T::t_interface_entrypoint::debugServiceName() << " (" << pfc::print_guid(T::t_interface_entrypoint::class_guid) << ")"; -#endif - throw exception_service_extension_not_found(); - } + if (!temp->service_query_t(p_out)) throw exception_service_extension_not_found(); } } @@ -644,7 +554,7 @@ public: static_api_ptr_t() { standard_api_create_t(m_ptr); } - t_interface* operator->() const {return m_ptr;} + service_obscure_refcounting* operator->() const {return service_obscure_refcounting_cast(m_ptr);} t_interface * get_ptr() const {return m_ptr;} ~static_api_ptr_t() {m_ptr->service_release();} @@ -656,6 +566,26 @@ private: t_interface * m_ptr; }; +//! Helper; simulates array with instance of each available implementation of given service class. +template class service_instance_array_t { +public: + typedef service_ptr_t t_ptr; + service_instance_array_t() { + service_class_helper_t helper; + const t_size count = helper.get_count(); + m_data.set_size(count); + for(t_size n=0;n m_data; +}; + template class service_enum_t { public: @@ -684,27 +614,6 @@ public: } } - service_ptr_t get() const { - PFC_ASSERT(!finished()); - return m_helper.create(m_index); - } - - void operator++() { - PFC_ASSERT(!finished()); - ++m_index; - } - void operator++(int) { - PFC_ASSERT(!finished()); - ++m_index; - } - - bool finished() const { - return m_index >= m_helper.get_count(); - } - - service_ptr_t operator*() const { - return get(); - } private: bool _next(service_ptr_t & p_out) { return m_helper.create(p_out,m_index++); @@ -713,9 +622,6 @@ private: service_class_helper_t m_helper; }; -//! New fb2k service enumeration syntax -//! for(auto e = FB2K_ENUMERATE(someclass); !e.finished(); ++e) { auto srv = *e; srv->do_stuff(); } -#define FB2K_ENUMERATE(what_t) service_enum_t() namespace fb2k { //! Modern get-std-api helper. \n @@ -747,99 +653,3 @@ namespace fb2k { } } } - - - -template -class service_factory_t : public service_factory_base_t { -public: - void instance_create(service_ptr_t & p_out) override { - p_out = pfc::implicit_cast(pfc::implicit_cast(pfc::implicit_cast( new service_impl_t ))); - } -#ifdef FOOBAR2000_MODERN - bool should_register() override { return T::shouldRegisterService(); } -#endif -}; - - -template -class service_factory_single_t : public service_factory_base_t { - service_impl_single_t g_instance; -public: - template service_factory_single_t(arg_t && ... arg) : g_instance(std::forward(arg) ...) {} - - void instance_create(service_ptr_t & p_out) override { - p_out = pfc::implicit_cast(pfc::implicit_cast(pfc::implicit_cast(&g_instance))); - } -#ifdef FOOBAR2000_MODERN - bool should_register() override { return g_instance.shouldRegisterService(); } -#endif - - inline T& get_static_instance() { return g_instance; } - inline const T& get_static_instance() const { return g_instance; } -}; - -//! Alternate service_factory_single, shared instance created on first access and never deallocated. \n -//! Addresses the problem of dangling references to our object getting invoked or plainly de-refcounted during late shutdown. -template -class service_factory_single_v2_t : public service_factory_base_t { -public: - T * get() { - static T * g_instance = new service_impl_single_t; - return g_instance; - } - void instance_create(service_ptr_t & p_out) override { - p_out = pfc::implicit_cast(pfc::implicit_cast(get())); - } -#ifdef FOOBAR2000_MODERN - bool should_register() override { return T::shouldRegisterService(); } -#endif -}; - -template -class service_factory_single_ref_t : public service_factory_base_t -{ -private: - T & instance; -public: - service_factory_single_ref_t(T& param) : instance(param) {} - - void instance_create(service_ptr_t & p_out) override { - p_out = pfc::implicit_cast(pfc::implicit_cast(pfc::implicit_cast(&instance))); - } -#ifdef FOOBAR2000_MODERN - bool should_register() override { return instance.shouldRegisterService(); } -#endif - - inline T& get_static_instance() { return instance; } -}; - -template -class service_factory_single_transparent_t : public service_factory_base_t, public service_impl_single_t -{ -public: - template service_factory_single_transparent_t(arg_t && ... arg) : service_impl_single_t( std::forward(arg) ...) {} - - void instance_create(service_ptr_t & p_out) override { - p_out = pfc::implicit_cast(pfc::implicit_cast(pfc::implicit_cast(this))); - } -#ifdef FOOBAR2000_MODERN - bool should_register() override { return this->shouldRegisterService(); } -#endif - - inline T& get_static_instance() {return *(T*)this;} - inline const T& get_static_instance() const {return *(const T*)this;} -}; - - -#ifdef _MSC_VER -#define FB2K_SERVICE_FACTORY_ATTR -#else -#define FB2K_SERVICE_FACTORY_ATTR __attribute__ (( __used__ )) -#endif - -#define FB2K_SERVICE_FACTORY( TYPE ) static ::service_factory_single_t< TYPE > g_##TYPE##factory FB2K_SERVICE_FACTORY_ATTR; -#define FB2K_SERVICE_FACTORY_DYNAMIC( TYPE ) static ::service_factory_t< TYPE > g_##TYPE##factory FB2K_SERVICE_FACTORY_ATTR; - - -#define FB2K_FOR_EACH_SERVICE(type, call) {service_enum_t e; service_ptr_t ptr; while(e.next(ptr)) {ptr->call;} } diff --git a/foobar2000/SDK/service_by_guid.h b/foobar2000/SDK/service_by_guid.h index d638042..b1388fa 100644 --- a/foobar2000/SDK/service_by_guid.h +++ b/foobar2000/SDK/service_by_guid.h @@ -1,16 +1,11 @@ #pragma once -#ifdef FOOBAR2000_MODERN -#include -#endif - - template static bool service_by_guid_fallback(service_ptr_t & out, const GUID & id) { service_enum_t e; service_ptr_t ptr; - while(e.next(ptr)) { - if (ptr->get_guid() == id) {out = ptr; return true;} + while (e.next(ptr)) { + if (ptr->get_guid() == id) { out = ptr; return true; } } return false; } @@ -18,9 +13,9 @@ static bool service_by_guid_fallback(service_ptr_t & out, const GUID & id) template class service_by_guid_data { public: - service_by_guid_data() : m_inited(), m_servClass() {} + service_by_guid_data() : m_servClass(), m_inited() {} - bool ready() const {return m_inited;} + bool ready() const { return m_inited; } // Caller must ensure initialize call before create() as well as thread safety of initialize() calls. The rest of this class is thread safe (only reads member data). void initialize() { @@ -28,7 +23,7 @@ public: pfc::assert_same_type< what, typename what::t_interface_entrypoint >(); m_servClass = service_factory_base::enum_find_class(what::class_guid); const t_size servCount = service_factory_base::enum_get_count(m_servClass); - for(t_size walk = 0; walk < servCount; ++walk) { + for (t_size walk = 0; walk < servCount; ++walk) { service_ptr_t temp; if (_service_instantiate_helper(temp, m_servClass, walk)) { m_order.set(temp->get_guid(), walk); @@ -40,16 +35,16 @@ public: bool create(service_ptr_t & out, const GUID & theID) const { PFC_ASSERT(m_inited); t_size index; - if (!m_order.query(theID,index)) return false; + if (!m_order.query(theID, index)) return false; return _service_instantiate_helper(out, m_servClass, index); } service_ptr_t create(const GUID & theID) const { - service_ptr_t temp; if (!crete(temp,theID)) throw exception_service_not_found(); return temp; + service_ptr_t temp; if (!crete(temp, theID)) throw exception_service_not_found(); return temp; } private: volatile bool m_inited; - pfc::map_t m_order; + pfc::map_t m_order; service_class_ref m_servClass; }; @@ -75,25 +70,21 @@ static bool service_by_guid(service_ptr_t & out, const GUID & theID) { } else if (core_api::is_main_thread()) { data.initialize(); } else { -#if PFC_DEBUG +#ifdef _DEBUG FB2K_DebugLog() << "Warning: service_by_guid() used in non-main thread without initialization, using fallback"; #endif - return service_by_guid_fallback(out,theID); + return service_by_guid_fallback(out, theID); } - return data.create(out,theID); + return data.create(out, theID); } template static service_ptr_t service_by_guid(const GUID & theID) { service_ptr_t temp; - if (!service_by_guid(temp, theID)) { -#if PFC_DEBUG - FB2K_DebugLog() << "service_by_guid failure: " << what::debugServiceName() << " : " << pfc::print_guid( theID ); -#endif - throw exception_service_not_found(); - } + if (!service_by_guid(temp, theID)) throw exception_service_not_found(); return temp; } +#define FB2K_FOR_EACH_SERVICE(type, call) {service_enum_t e; service_ptr_t ptr; while(e.next(ptr)) {ptr->call;} } diff --git a/foobar2000/SDK/service_compat.h b/foobar2000/SDK/service_compat.h deleted file mode 100644 index d1a960e..0000000 --- a/foobar2000/SDK/service_compat.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -// Obsolete features - -//! Special hack to ensure errors when someone tries to ->service_add_ref()/->service_release() on a service_ptr_t -template class service_obscure_refcounting : public T { -private: - int service_add_ref() throw(); - int service_release() throw(); -}; - -//! Converts a service interface pointer to a pointer that obscures service counter functionality. -template static inline service_obscure_refcounting* service_obscure_refcounting_cast(T * p_source) throw() {return static_cast*>(p_source);} - -template class t_alloc = pfc::alloc_fast> -class service_list_t : public pfc::list_t, t_alloc > -{ -}; - -//! Helper; simulates array with instance of each available implementation of given service class. -template class service_instance_array_t { -public: - typedef service_ptr_t t_ptr; - service_instance_array_t() { - service_class_helper_t helper; - const t_size count = helper.get_count(); - m_data.set_size(count); - for(t_size n=0;n m_data; -}; diff --git a/foobar2000/SDK/service_factory.h b/foobar2000/SDK/service_factory.h new file mode 100644 index 0000000..57fc6fe --- /dev/null +++ b/foobar2000/SDK/service_factory.h @@ -0,0 +1,117 @@ +#pragma once + +class NOVTABLE service_factory_base { +public: + inline const GUID & get_class_guid() const { return m_guid; } + + static service_class_ref enum_find_class(const GUID & p_guid); + static bool enum_create(service_ptr_t & p_out, service_class_ref p_class, t_size p_index); + static t_size enum_get_count(service_class_ref p_class); + + inline static bool is_service_present(const GUID & g) { return enum_get_count(enum_find_class(g))>0; } + + //! Throws std::bad_alloc or another exception on failure. + virtual void instance_create(service_ptr_t & p_out) = 0; + + //! FOR INTERNAL USE ONLY + static service_factory_base *__internal__list; + //! FOR INTERNAL USE ONLY + service_factory_base * __internal__next; +private: + const GUID & m_guid; + +protected: + inline service_factory_base(const GUID & p_guid, service_factory_base * & factoryList = __internal__list) : m_guid(p_guid) { PFC_ASSERT(!core_api::are_services_available()); __internal__next = factoryList; factoryList = this; } + inline ~service_factory_base() { PFC_ASSERT(!core_api::are_services_available()); } + +}; + +template +class service_factory_traits { +public: + static service_factory_base * & factory_list() { return service_factory_base::__internal__list; } +}; + +template +class service_factory_base_t : public service_factory_base { +public: + service_factory_base_t() : service_factory_base(B::class_guid, service_factory_traits::factory_list()) { + pfc::assert_same_type(); + } +}; + +template +class service_factory_t : public service_factory_base_t { +public: + void instance_create(service_ptr_t & p_out) { + p_out = pfc::implicit_cast(pfc::implicit_cast(pfc::implicit_cast(new service_impl_t))); + } +}; + + +template +class service_factory_single_t : public service_factory_base_t { + service_impl_single_t g_instance; +public: + template service_factory_single_t(arg_t && ... arg) : g_instance(std::forward(arg) ...) {} + + void instance_create(service_ptr_t & p_out) { + p_out = pfc::implicit_cast(pfc::implicit_cast(pfc::implicit_cast(&g_instance))); + } + + inline T& get_static_instance() { return g_instance; } + inline const T& get_static_instance() const { return g_instance; } +}; + +//! Alternate service_factory_single, shared instance created on first access and never deallocated. \n +//! Addresses the problem of dangling references to our object getting invoked or plainly de-refcounted during late shutdown. +template +class service_factory_single_v2_t : public service_factory_base_t { +public: + T * get() { + static T * g_instance = new service_impl_single_t; + return g_instance; + } + void instance_create(service_ptr_t & p_out) { + p_out = pfc::implicit_cast(pfc::implicit_cast(get())); + } +}; + +template +class service_factory_single_ref_t : public service_factory_base_t +{ +private: + T & instance; +public: + service_factory_single_ref_t(T& param) : instance(param) {} + + void instance_create(service_ptr_t & p_out) { + p_out = pfc::implicit_cast(pfc::implicit_cast(pfc::implicit_cast(&instance))); + } + + inline T& get_static_instance() { return instance; } +}; + + +template +class service_factory_single_transparent_t : public service_factory_base_t, public service_impl_single_t +{ +public: + template service_factory_single_transparent_t(arg_t && ... arg) : service_impl_single_t(std::forward(arg) ...) {} + + void instance_create(service_ptr_t & p_out) { + p_out = pfc::implicit_cast(pfc::implicit_cast(pfc::implicit_cast(this))); + } + + inline T& get_static_instance() { return *(T*)this; } +}; + + +#ifdef _MSC_VER +#define FB2K_SERVICE_FACTORY_ATTR +#else +#define FB2K_SERVICE_FACTORY_ATTR __attribute__ (( __used__ )) +#endif + +#define FB2K_SERVICE_FACTORY( TYPE ) static ::service_factory_single_t< TYPE > g_##TYPE##factory FB2K_SERVICE_FACTORY_ATTR; +#define FB2K_SERVICE_FACTORY_DYNAMIC( TYPE ) static ::service_factory_t< TYPE > g_##TYPE##factory FB2K_SERVICE_FACTORY_ATTR; diff --git a/foobar2000/SDK/service_impl.h b/foobar2000/SDK/service_impl.h index c1c026b..898946c 100644 --- a/foobar2000/SDK/service_impl.h +++ b/foobar2000/SDK/service_impl.h @@ -8,10 +8,9 @@ #include namespace service_impl_helper { - //! Helper function to defer destruction of a service object. \n - //! Enqueues a main_thread_callback to release the object at a later time, escaping the current scope. \n - //! Important: this takes a raw service_base* - not an autoptr - to ensure that the last reference can be released in main thread. \n - void release_object_delayed(service_base* obj); + //! Helper function to defer destruction of a service object. + //! Enqueues a main_thread_callback to release the object at a later time, escaping the current scope. + void release_object_delayed(service_ptr obj); }; //! Multi inheritance helper. \n @@ -28,7 +27,6 @@ public: } service_base * as_service_base() { return class1_t::as_service_base(); } - static const char * debugServiceName() { return "multi inherited service"; } // Obscure service_base methods from both so calling myclass->service_query() works like it should virtual int service_release() throw() = 0; @@ -66,7 +64,6 @@ public: if (!this->serviceRequiresMainThreadDestructor() || core_api::is_main_thread()) { PFC_ASSERT_NO_EXCEPTION( delete this ); } else { - // Pass to release_object_delayed() with zero ref count - a temporary single reference will be created there service_impl_helper::release_object_delayed(this->as_service_base()); } } diff --git a/foobar2000/SDK/tag_processor.cpp b/foobar2000/SDK/tag_processor.cpp index d8d4276..bb7b244 100644 --- a/foobar2000/SDK/tag_processor.cpp +++ b/foobar2000/SDK/tag_processor.cpp @@ -124,7 +124,7 @@ void tag_processor::read_trailing(const service_ptr_t & p_file,file_info & tag_processor_trailing::get()->read(p_file,p_info,p_abort); } -void tag_processor::read_trailing_ex(const service_ptr_t & p_file,file_info & p_info,t_filesize & p_tagoffset,abort_callback & p_abort) { +void tag_processor::read_trailing_ex(const service_ptr_t & p_file,file_info & p_info,t_uint64 & p_tagoffset,abort_callback & p_abort) { tag_processor_trailing::get()->read_ex(p_file,p_info,p_tagoffset,p_abort); } @@ -165,7 +165,7 @@ void tag_processor::read_id3v2_trailing(const service_ptr_t & p_file,file_ } } -void tag_processor::skip_id3v2(const service_ptr_t & p_file,t_filesize & p_size_skipped,abort_callback & p_abort) { +void tag_processor::skip_id3v2(const service_ptr_t & p_file,t_uint64 & p_size_skipped,abort_callback & p_abort) { tag_processor_id3v2::g_skip(p_file,p_size_skipped,p_abort); } diff --git a/foobar2000/SDK/tag_processor.h b/foobar2000/SDK/tag_processor.h index 102225b..e7fef91 100644 --- a/foobar2000/SDK/tag_processor.h +++ b/foobar2000/SDK/tag_processor.h @@ -37,7 +37,6 @@ public: static t_size g_multiskip(const service_ptr_t & p_file,t_filesize & p_size_skipped,abort_callback & p_abort); static void g_remove(const service_ptr_t & p_file,t_filesize & p_size_removed,abort_callback & p_abort); static void g_remove_ex(tag_write_callback & p_callback,const service_ptr_t & p_file,t_filesize & p_size_removed,abort_callback & p_abort); - static uint32_t g_tagsize(const void* pHeader10bytes); FB2K_MAKE_SERVICE_COREAPI(tag_processor_id3v2); }; diff --git a/foobar2000/SDK/tag_processor_id3v2.cpp b/foobar2000/SDK/tag_processor_id3v2.cpp index 410d1f8..d76b00e 100644 --- a/foobar2000/SDK/tag_processor_id3v2.cpp +++ b/foobar2000/SDK/tag_processor_id3v2.cpp @@ -2,8 +2,7 @@ bool tag_processor_id3v2::g_get(service_ptr_t & p_out) { - p_out = get(); - return true; + return service_enum_t().first(p_out); } void tag_processor_id3v2::g_remove(const service_ptr_t & p_file,t_uint64 & p_size_removed,abort_callback & p_abort) { @@ -58,25 +57,6 @@ t_size tag_processor_id3v2::g_multiskip(const service_ptr_t & p_file,t_fil p_size_skipped = offset; return count; } - -uint32_t tag_processor_id3v2::g_tagsize(const void* pHeader10bytes) { - const uint8_t* tmp = (const uint8_t*)pHeader10bytes; - if ( 0 != memcmp(tmp, "ID3", 3) || (tmp[5] & 0x0F) != 0 || ((tmp[6] | tmp[7] | tmp[8] | tmp[9]) & 0x80) != 0 ) { - return 0; - } - - int FooterPresent = tmp[5] & 0x10; - - uint32_t ret; - ret = tmp[6] << 21; - ret += tmp[7] << 14; - ret += tmp[8] << 7; - ret += tmp[9]; - ret += 10; - if (FooterPresent) ret += 10; - return ret; -} - void tag_processor_id3v2::g_skip(const service_ptr_t & p_file,t_uint64 & p_size_skipped,abort_callback & p_abort) { g_skip_at(p_file, 0, p_size_skipped, p_abort); } @@ -93,13 +73,26 @@ void tag_processor_id3v2::g_skip_at(const service_ptr_t & p_file,t_filesiz return; } - uint32_t ret = g_tagsize(tmp); - if (ret == 0) { - p_file->seek(p_base, p_abort); + if ( + 0 != memcmp ( tmp, "ID3", 3) || + ( tmp[5] & 0x0F ) != 0 || + ((tmp[6] | tmp[7] | tmp[8] | tmp[9]) & 0x80) != 0 + ) { + p_file->seek ( p_base, p_abort ); p_size_skipped = 0; return; } + int FooterPresent = tmp[5] & 0x10; + + t_uint32 ret; + ret = tmp[6] << 21; + ret += tmp[7] << 14; + ret += tmp[8] << 7; + ret += tmp[9] ; + ret += 10; + if ( FooterPresent ) ret += 10; + try { p_file->seek ( p_base + ret, p_abort ); } catch(exception_io_seek_out_of_range) { @@ -109,4 +102,5 @@ void tag_processor_id3v2::g_skip_at(const service_ptr_t & p_file,t_filesiz } p_size_skipped = ret; + } diff --git a/foobar2000/SDK/threaded_process.cpp b/foobar2000/SDK/threaded_process.cpp index a58ea9b..2eb95fb 100644 --- a/foobar2000/SDK/threaded_process.cpp +++ b/foobar2000/SDK/threaded_process.cpp @@ -107,12 +107,12 @@ service_ptr_t threaded_process_callback_lambda service_ptr_t threaded_process_callback_lambda::create(run_t f) { auto obj = create(); obj->m_run = f; - return obj; + return std::move(obj); } service_ptr_t threaded_process_callback_lambda::create(on_init_t f1, run_t f2, on_done_t f3) { auto obj = create(); obj->m_on_init = f1; obj->m_run = f2; obj->m_on_done = f3; - return obj; + return std::move(obj); } diff --git a/foobar2000/SDK/threaded_process.h b/foobar2000/SDK/threaded_process.h index d92354a..7073ea3 100644 --- a/foobar2000/SDK/threaded_process.h +++ b/foobar2000/SDK/threaded_process.h @@ -2,28 +2,28 @@ #include //! Callback class passed to your threaded_process client code; allows you to give various visual feedback to the user. -class threaded_process_status { +class NOVTABLE threaded_process_status { public: enum {progress_min = 0, progress_max = 5000}; //! Sets the primary progress bar state; scale from progress_min to progress_max. - virtual void set_progress(t_size p_state) {} + virtual void set_progress(t_size p_state) = 0; //! Sets the secondary progress bar state; scale from progress_min to progress_max. - virtual void set_progress_secondary(t_size p_state) {} + virtual void set_progress_secondary(t_size p_state) = 0; //! Sets the currently progressed item label. When working with files, you should use set_file_path() instead. - virtual void set_item(const char * p_item,t_size p_item_len = ~0) {} + virtual void set_item(const char * p_item,t_size p_item_len = ~0) = 0; //! Sets the currently progressed item label; treats the label as a file path. - virtual void set_item_path(const char * p_item,t_size p_item_len = ~0) {} + virtual void set_item_path(const char * p_item,t_size p_item_len = ~0) = 0; //! Sets the title of the dialog. You normally don't need this function unless you want to override the title you set when initializing the threaded_process. - virtual void set_title(const char * p_title,t_size p_title_len = ~0) {} + virtual void set_title(const char * p_title,t_size p_title_len = ~0) = 0; //! Should not be used. - virtual void force_update() {} + virtual void force_update() = 0; //! Returns whether the process is paused. - virtual bool is_paused() {return false;} + virtual bool is_paused() = 0; //! Checks if process is paused and sleeps if needed; returns false when process should be aborted, true on success. \n //! You should use poll_pause() instead of calling this directly. - virtual bool process_pause() {return true;} + virtual bool process_pause() = 0; //! Automatically sleeps if the process is paused. void poll_pause() {if (!process_pause()) throw exception_aborted();} @@ -39,12 +39,9 @@ public: //! Helper; gracefully reports multiple items being concurrently worked on. void set_items( metadb_handle_list_cref items ); void set_items( pfc::list_base_const_t const & paths ); -}; - -//! Fb2k mobile compatibility -class threaded_process_context { -public: - static HWND g_default() { return core_api::get_main_window(); } +protected: + threaded_process_status() {} + ~threaded_process_status() {} }; //! Callback class for the threaded_process API. You must implement this to create your own threaded_process client. diff --git a/foobar2000/SDK/titleformat.cpp b/foobar2000/SDK/titleformat.cpp index 584b382..974d672 100644 --- a/foobar2000/SDK/titleformat.cpp +++ b/foobar2000/SDK/titleformat.cpp @@ -55,8 +55,7 @@ void titleformat_compiler::remove_forbidden_chars(titleformat_text_out * p_out,c void titleformat_compiler::remove_forbidden_chars_string_append(pfc::string_receiver & p_out,const char * p_source,t_size p_source_len,const char * p_reserved_chars) { - titleformat_text_out_impl_string tfout(p_out); - remove_forbidden_chars(&tfout,pfc::guid_null,p_source,p_source_len,p_reserved_chars); + remove_forbidden_chars(&titleformat_text_out_impl_string(p_out),pfc::guid_null,p_source,p_source_len,p_reserved_chars); } void titleformat_compiler::remove_forbidden_chars_string(pfc::string_base & p_out,const char * p_source,t_size p_source_len,const char * p_reserved_chars) @@ -76,21 +75,24 @@ void titleformat_object::run_hook(const playable_location & p_location,const fil { if (p_hook) { - titleformat_hook_impl_file_info hook1(p_location, p_source); - titleformat_hook_impl_splitter hook2(p_hook, &hook1); - run(&hook2,p_out,p_filter); + run( + &titleformat_hook_impl_splitter( + p_hook, + &titleformat_hook_impl_file_info(p_location,p_source) + ), + p_out,p_filter); } else { - titleformat_hook_impl_file_info hook(p_location, p_source); - run(&hook,p_out,p_filter); + run( + &titleformat_hook_impl_file_info(p_location,p_source), + p_out,p_filter); } } void titleformat_object::run_simple(const playable_location & p_location,const file_info * p_source,pfc::string_base & p_out) { - titleformat_hook_impl_file_info hook(p_location, p_source); - run(&hook,p_out,NULL); + run(&titleformat_hook_impl_file_info(p_location,p_source),p_out,NULL); } t_size titleformat_hook_function_params::get_param_uint(t_size index) diff --git a/foobar2000/SDK/track_property.cpp b/foobar2000/SDK/track_property.cpp deleted file mode 100644 index 14de537..0000000 --- a/foobar2000/SDK/track_property.cpp +++ /dev/null @@ -1,70 +0,0 @@ -#include "foobar2000.h" - -#include "track_property.h" - -namespace { - class track_property_provider_v3_info_source_impl : public track_property_provider_v3_info_source { - public: - track_property_provider_v3_info_source_impl(trackListRef items) : m_items(items) {} - trackInfoContainer::ptr get_info(size_t index) { - return trackGetInfoRef(m_items, index); - } - private: - trackListRef m_items; - }; - - class track_property_callback_v2_proxy : public track_property_callback_v2 { - public: - track_property_callback_v2_proxy(track_property_callback & callback) : m_callback(callback) {} - void set_property(const char * p_group, double p_sortpriority, const char * p_name, const char * p_value) { m_callback.set_property(p_group, p_sortpriority, p_name, p_value); } - bool is_group_wanted(const char*) { return true; } - - private: - track_property_callback & m_callback; - }; - - -} - -void track_property_provider_v3::enumerate_properties(trackListRef p_tracks, track_property_callback & p_out) { - track_property_provider_v3_info_source_impl src(p_tracks); track_property_callback_v2_proxy cb(p_out); enumerate_properties_v3(p_tracks, src, cb); -} - -void track_property_provider_v3::enumerate_properties_v2(trackListRef p_tracks, track_property_callback_v2 & p_out) { - track_property_provider_v3_info_source_impl src(p_tracks); enumerate_properties_v3(p_tracks, src, p_out); -} - -void track_property_provider_v4::enumerate_properties_v3(trackListRef items, track_property_provider_v3_info_source & info, track_property_callback_v2 & callback) { - this->enumerate_properties_v4(items, info, callback, fb2k::noAbort ); -} - -void track_property_provider::enumerate_properties_helper(trackListRef items, track_property_provider_v3_info_source * info, track_property_callback_v2 & callback, abort_callback & abort) { - - abort.check(); - - track_property_provider_v2::ptr v2; - if ( ! this->cast( v2 ) ) { - // no v2 - PFC_ASSERT(core_api::is_main_thread()); - this->enumerate_properties( items, callback ); return; - } - - track_property_provider_v3::ptr v3; - if ( ! (v3 &= v2 ) ) { - // no v3 - PFC_ASSERT(core_api::is_main_thread()); - v2->enumerate_properties_v2( items, callback ); return; - } - - track_property_provider_v3_info_source_impl infoFallback ( items ); - if ( info == nullptr ) info = & infoFallback; - - track_property_provider_v4::ptr v4; - if (! ( v4 &= v3 ) ) { - // no v4 - PFC_ASSERT( core_api::is_main_thread() ); - v3->enumerate_properties_v3( items, *info, callback ); - } else { - v4->enumerate_properties_v4( items, *info, callback, abort ); - } -} diff --git a/foobar2000/SDK/track_property.h b/foobar2000/SDK/track_property.h index 7cd8658..3e83d55 100644 --- a/foobar2000/SDK/track_property.h +++ b/foobar2000/SDK/track_property.h @@ -1,7 +1,3 @@ -#pragma once - -#include "tracks.h" - //! Callback interface for track_property_provider::enumerate_properties(). class NOVTABLE track_property_callback { public: @@ -14,8 +10,10 @@ public: protected: track_property_callback() {} ~track_property_callback() {} - track_property_callback(track_property_callback const &) {}; - void operator=(track_property_callback const &) {}; +private: + track_property_callback(track_property_callback const &) = delete; + track_property_callback const & operator=(track_property_callback const &) = delete; + }; //! Extended version of track_property_callback @@ -28,71 +26,59 @@ protected: ~track_property_callback_v2() {} }; -//! \since 1.3 -class NOVTABLE track_property_provider_v3_info_source { -public: - virtual trackInfoContainer::ptr get_info(size_t index) = 0; - -protected: - track_property_provider_v3_info_source() {} - ~track_property_provider_v3_info_source() {} - track_property_provider_v3_info_source( const track_property_provider_v3_info_source & ) {}; - void operator=( const track_property_provider_v3_info_source & ) {}; -}; - //! Service for adding custom entries in "Properties" tab of the properties dialog. class NOVTABLE track_property_provider : public service_base { public: //! Enumerates properties of specified track list. //! @param p_tracks List of tracks to enumerate properties on. //! @param p_out Callback interface receiving enumerated properties. - virtual void enumerate_properties(trackListRef p_tracks, track_property_callback & p_out) = 0; + virtual void enumerate_properties(metadb_handle_list_cref p_tracks, track_property_callback & p_out) = 0; //! Returns whether specified tech info filed is processed by our service and should not be displayed among unknown fields. //! @param p_name Name of tech info field being queried. //! @returns True if the field is among fields processed by this track_property_provider implementation and should not be displayed among unknown fields, false otherwise. virtual bool is_our_tech_info(const char * p_name) = 0; - - //! Helper; calls modern versions of this API where appropriate. - //! @param items List of tracks to enumerate properties on. - //! @param info Callback object to fetch info from. Pass null to use a generic implementation querying the metadb. - //! @param callback Callback interface receiving enumerated properties. - //! @param abort The aborter for this operation. - void enumerate_properties_helper(trackListRef items, track_property_provider_v3_info_source * info, track_property_callback_v2 & callback, abort_callback & abort); - FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(track_property_provider); }; class NOVTABLE track_property_provider_v2 : public track_property_provider { FB2K_MAKE_SERVICE_INTERFACE(track_property_provider_v2,track_property_provider) public: - virtual void enumerate_properties_v2(trackListRef p_tracks, track_property_callback_v2 & p_out) = 0; + virtual void enumerate_properties_v2(metadb_handle_list_cref p_tracks, track_property_callback_v2 & p_out) = 0; }; +class NOVTABLE track_property_provider_v3_info_source { +public: + virtual metadb_info_container::ptr get_info(size_t index) = 0; +}; + +class track_property_provider_v3_info_source_impl : public track_property_provider_v3_info_source { +public: + track_property_provider_v3_info_source_impl(metadb_handle_list_cref items) : m_items(items) {} + metadb_info_container::ptr get_info(size_t index) {return m_items[index]->get_info_ref();} +private: + metadb_handle_list_cref m_items; +}; + +class track_property_callback_v2_proxy : public track_property_callback_v2 { +public: + track_property_callback_v2_proxy(track_property_callback & callback) : m_callback(callback) {} + void set_property(const char * p_group,double p_sortpriority,const char * p_name,const char * p_value) {m_callback.set_property(p_group, p_sortpriority, p_name, p_value);} + bool is_group_wanted(const char*) {return true;} + +private: + track_property_callback & m_callback; +}; //! \since 1.3 class NOVTABLE track_property_provider_v3 : public track_property_provider_v2 { FB2K_MAKE_SERVICE_INTERFACE(track_property_provider_v3,track_property_provider_v2) public: - virtual void enumerate_properties_v3(trackListRef items, track_property_provider_v3_info_source & info, track_property_callback_v2 & callback) = 0; + virtual void enumerate_properties_v3(metadb_handle_list_cref items, track_property_provider_v3_info_source & info, track_property_callback_v2 & callback) = 0; - void enumerate_properties(trackListRef p_tracks, track_property_callback & p_out) override; - void enumerate_properties_v2(trackListRef p_tracks, track_property_callback_v2 & p_out) override; + void enumerate_properties(metadb_handle_list_cref p_tracks, track_property_callback & p_out) {track_property_provider_v3_info_source_impl src(p_tracks); track_property_callback_v2_proxy cb(p_out); enumerate_properties_v3(p_tracks, src, cb);} + void enumerate_properties_v2(metadb_handle_list_cref p_tracks, track_property_callback_v2 & p_out) {track_property_provider_v3_info_source_impl src(p_tracks); enumerate_properties_v3(p_tracks, src, p_out);} }; template class track_property_provider_factory_t : public service_factory_single_t {}; - -//! \since 1.5 -//! Adds abortability on top of track_property_provider_v3 interface. \n -//! The previous revisions of this API were only legal to call from the main thread. \n -//! track_property_provider_v4 implementers should make NO ASSUMPTIONS about the thread they are in. \n -//! Implementing track_property_provider_v4 declares your class as safe to call from any thread. \n -//! If called via enumerate_properties_v4() method or off-main-thread, the implementation can assume the info source object to be thread-safe. -class NOVTABLE track_property_provider_v4 : public track_property_provider_v3 { - FB2K_MAKE_SERVICE_INTERFACE(track_property_provider_v4, track_property_provider_v3 ); -public: - void enumerate_properties_v3(trackListRef items, track_property_provider_v3_info_source & info, track_property_callback_v2 & callback) override; - - virtual void enumerate_properties_v4(trackListRef items, track_property_provider_v3_info_source & info, track_property_callback_v2 & callback, abort_callback & abort) = 0; -}; diff --git a/foobar2000/SDK/tracks.h b/foobar2000/SDK/tracks.h deleted file mode 100644 index 3fe2c80..0000000 --- a/foobar2000/SDK/tracks.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -// Special header with fb2k mobile metadb<=>trackList interop wrappers - -typedef metadb_handle_ptr trackRef; -typedef metadb_handle_list_cref trackListRef; -typedef metadb_handle_list trackListStore; -typedef metadb_info_container trackInfoContainer; - -inline size_t trackCount(trackListRef l) {return l.get_size();} -inline trackRef trackListGetTrack(trackListRef l, size_t n) { return l[n]; } - -// Returns blank info if no info is known, never null. -inline trackInfoContainer::ptr trackGetInfoRef(trackRef t) { return t->get_info_ref(); } -inline trackInfoContainer::ptr trackGetInfoRef(trackListRef l, size_t n) { return trackGetInfoRef(l[n]); } - -// Returns null info if no info is known, contrary to trackGetInfoRef -inline trackInfoContainer::ptr trackGetInfo(trackRef t) { trackInfoContainer::ptr ret; if(!t->get_info_ref(ret)) ret = nullptr; return ret; } -inline trackInfoContainer::ptr trackGetInfo(trackListRef l, size_t n) { return trackGetInfo(l[n]); } - -// Returns const char* or pfc::string8 depending on which fb2k! -inline const char * trackGetPath(trackListRef l, size_t n) { return l[n]->get_path(); } -inline const char * trackGetPath(trackRef t) { return t->get_path(); } - -// Returns const playable_location& or playable_location_impl depending on which fb2k! -inline playable_location const & trackGetLocation(trackListRef l, size_t n) { return l[n]->get_location(); } -inline playable_location const & trackGetLocation(trackRef t) { return t->get_location(); } - -inline double trackGetLength(trackListRef l, size_t n) { return l[n]->get_length(); } -inline double trackGetLength(trackRef t) { return t->get_length(); } - -inline void trackFormatTitle(trackRef trk, titleformat_hook * hook, pfc::string_base & out, service_ptr_t script, titleformat_text_filter * filter) { - trk->format_title(hook, out, script, filter); -} \ No newline at end of file diff --git a/foobar2000/SDK/ui.h b/foobar2000/SDK/ui.h index ae83333..bac7d02 100644 --- a/foobar2000/SDK/ui.h +++ b/foobar2000/SDK/ui.h @@ -88,8 +88,7 @@ public: //! Loads main GUI icon, version with specified width/height. Returned handle needs to be freed with DestroyIcon when you are done using it. virtual HICON load_main_icon(unsigned width,unsigned height) = 0; - //! Activates preferences dialog and navigates to specified page. See also: preference_page API. \n - //! Since foobar2000 1.5, this can be used to show advanced preferences branches or settings, just pass GUID of the advconfig_entry you wish to show. + //! Activates preferences dialog and navigates to specified page. See also: preference_page API. virtual void show_preferences(const GUID & p_page) = 0; //! Instantiates ui_status_text_override service, that can be used to display status messages. @@ -98,18 +97,6 @@ public: virtual bool override_status_text_create(service_ptr_t & p_out) = 0; }; -typedef ui_status_text_override ui_status_host; - -#if FOOBAR2000_TARGET_VERSION >= 80 -//! \since 1.5 -class NOVTABLE ui_control_v2 : public ui_control { - FB2K_MAKE_SERVICE_COREAPI_EXTENSION(ui_control_v2, ui_control) -public: - virtual void register_status_host(HWND wndFor, ui_status_host::ptr obj) = 0; - virtual void unregister_status_host(HWND wndFor) = 0; -}; -#endif // if FOOBAR2000_TARGET_VERSION >= 80 - //! Service called from the UI when some object is dropped into the UI. Usable for modifying drag&drop behaviors such as adding custom handlers for object types other than supported media files.\n //! Implement where needed; use ui_drop_item_callback_factory_t<> template to register, e.g. static ui_drop_item_callback_factory_t g_myclass_factory. class NOVTABLE ui_drop_item_callback : public service_base { diff --git a/foobar2000/SDK/ui_element.cpp b/foobar2000/SDK/ui_element.cpp index 5ae02f2..63583c0 100644 --- a/foobar2000/SDK/ui_element.cpp +++ b/foobar2000/SDK/ui_element.cpp @@ -1,28 +1,5 @@ #include "foobar2000.h" -namespace { - struct sysColorMapping_t { - GUID guid; int idx; - }; - static const sysColorMapping_t sysColorMapping[] = { - { ui_color_text, COLOR_WINDOWTEXT }, - { ui_color_background, COLOR_WINDOW }, - { ui_color_highlight, COLOR_HOTLIGHT }, - {ui_color_selection, COLOR_HIGHLIGHT}, - }; -} -int ui_color_to_sys_color_index(const GUID & p_guid) { - for( unsigned i = 0; i < PFC_TABSIZE( sysColorMapping ); ++ i ) { - if ( p_guid == sysColorMapping[i].guid ) return sysColorMapping[i].idx; - } - return -1; -} -GUID ui_color_from_sys_color_index(int idx) { - for (unsigned i = 0; i < PFC_TABSIZE(sysColorMapping); ++i) { - if (idx == sysColorMapping[i].idx) return sysColorMapping[i].guid; - } - return pfc::guid_null; -} namespace { class ui_element_config_impl : public ui_element_config { @@ -58,8 +35,7 @@ service_ptr_t ui_element_config::g_create(const GUID & id, st service_ptr_t ui_element_config::g_create(stream_reader * in, t_size bytes, abort_callback & abort) { if (bytes < sizeof(GUID)) throw exception_io_data_truncation(); - GUID id; - { stream_reader_formatter<> str(*in,abort); str >> id;} + GUID id; stream_reader_formatter<>(*in,abort) >> id; return g_create(id,in,bytes - sizeof(GUID),abort); } @@ -72,7 +48,7 @@ ui_element_config::ptr ui_element_config_parser::subelement(const GUID & id, t_s service_ptr_t ui_element_config::g_create(const void * data, t_size size) { stream_reader_memblock_ref stream(data,size); - return g_create(&stream,size,fb2k::noAbort); + return g_create(&stream,size,abort_callback_dummy()); } bool ui_element_subclass_description(const GUID & id, pfc::string_base & p_out) { @@ -112,13 +88,6 @@ t_ui_color ui_element_instance_callback::query_std_color(const GUID & p_what) { #error portme #endif } -#ifdef _WIN32 -t_ui_color ui_element_instance_callback::getSysColor(int sysColorIndex) { - GUID guid = ui_color_from_sys_color_index( sysColorIndex ); - if ( guid != pfc::guid_null ) return query_std_color(guid); - return GetSysColor(sysColorIndex); -} -#endif bool ui_element::g_find(service_ptr_t & out, const GUID & id) { return service_by_guid(out, id); diff --git a/foobar2000/SDK/ui_element.h b/foobar2000/SDK/ui_element.h index f944fc3..290dde1 100644 --- a/foobar2000/SDK/ui_element.h +++ b/foobar2000/SDK/ui_element.h @@ -34,7 +34,7 @@ public: //! Helper for reading data from ui_element_config. class ui_element_config_parser : public stream_reader_formatter<> { public: - ui_element_config_parser(ui_element_config::ptr in) : m_data(in), _m_stream(in->get_data(),in->get_data_size()), stream_reader_formatter(_m_stream,fb2k::noAbort) {} + ui_element_config_parser(ui_element_config::ptr in) : m_data(in), _m_stream(in->get_data(),in->get_data_size()), stream_reader_formatter(_m_stream,_m_abort) {} void reset() {_m_stream.reset();} t_size get_remaining() const {return _m_stream.get_remaining();} @@ -43,13 +43,14 @@ public: ui_element_config::ptr subelement(const GUID & id, t_size dataSize); private: const ui_element_config::ptr m_data; + abort_callback_dummy _m_abort; stream_reader_memblock_ref _m_stream; }; //! Helper creating ui_element_config from your data. class ui_element_config_builder : public stream_writer_formatter<> { public: - ui_element_config_builder() : stream_writer_formatter(_m_stream,fb2k::noAbort) {} + ui_element_config_builder() : stream_writer_formatter(_m_stream,_m_abort) {} ui_element_config::ptr finish(const GUID & id) { return ui_element_config::g_create(id,_m_stream.m_buffer); } @@ -57,6 +58,7 @@ public: _m_stream.m_buffer.set_size(0); } private: + abort_callback_dummy _m_abort; stream_writer_buffer_simple _m_stream; }; @@ -96,9 +98,23 @@ static const GUID ui_font_statusbar = { 0xc7fd555b, 0xbd15, 0x4f74, { 0x93, 0xe, static const GUID ui_font_console = { 0xb08c619d, 0xd3d1, 0x4089, { 0x93, 0xb2, 0xd5, 0xb, 0x87, 0x2d, 0x1a, 0x25 } }; + + //! @returns -1 when the GUID is unknown / unmappable, index that can be passed over to GetSysColor() otherwise. -int ui_color_to_sys_color_index(const GUID & p_guid); -GUID ui_color_from_sys_color_index( int idx ); +static int ui_color_to_sys_color_index(const GUID & p_guid) { + if (p_guid == ui_color_text) { + return COLOR_WINDOWTEXT; + } else if (p_guid == ui_color_background) { + return COLOR_WINDOW; + } else if (p_guid == ui_color_highlight) { + return COLOR_HOTLIGHT; + } else if (p_guid == ui_color_selection) { + return COLOR_HIGHLIGHT; + } else { + return -1; + } +} + struct ui_element_min_max_info { ui_element_min_max_info() : m_min_width(0), m_max_width(~0), m_min_height(0), m_max_height(~0) {} @@ -138,9 +154,6 @@ public: //! Helper - a wrapper around query_color(), if the color is not user-overridden, returns relevant system color. t_ui_color query_std_color(const GUID & p_what); -#ifdef _WIN32 - t_ui_color getSysColor( int sysColorIndex ); -#endif bool is_elem_visible_(service_ptr_t elem); @@ -516,6 +529,14 @@ public: virtual HWND highlight_element( HWND wndElem ) = 0; }; +class NOVTABLE ui_element_typable_window_manager : public service_base { + FB2K_MAKE_SERVICE_COREAPI(ui_element_typable_window_manager) +public: + virtual void add(HWND wnd) = 0; + virtual void remove(HWND wnd) = 0; + virtual bool is_registered(HWND wnd) = 0; +}; + //! Dispatched through ui_element_instance::notify() when host changes color settings. Other parameters are not used and should be set to zero. static const GUID ui_element_notify_colors_changed = { 0xeedda994, 0xe3d2, 0x441a, { 0xbe, 0x47, 0xa1, 0x63, 0x5b, 0x71, 0xab, 0x60 } }; static const GUID ui_element_notify_font_changed = { 0x7a6964a8, 0xc797, 0x4737, { 0x90, 0x55, 0x7d, 0x84, 0xe7, 0x3d, 0x63, 0x6e } }; diff --git a/foobar2000/SDK/ui_element_typable_window_manager.h b/foobar2000/SDK/ui_element_typable_window_manager.h deleted file mode 100644 index 0d72cf6..0000000 --- a/foobar2000/SDK/ui_element_typable_window_manager.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -// API obsoleted in 1.5 and should no longer be used by anything -// Core-implemented to keep components that specifically rely on it working - -class NOVTABLE ui_element_typable_window_manager : public service_base { - FB2K_MAKE_SERVICE_COREAPI(ui_element_typable_window_manager); -public: - virtual void add(HWND wnd) = 0; - virtual void remove(HWND wnd) = 0; - virtual bool is_registered(HWND wnd) = 0; -}; - -FOOGUIDDECL const GUID ui_element_typable_window_manager::class_guid = { 0xbaa99ee2, 0xf770, 0x4981,{ 0x9e, 0x50, 0xf3, 0x4c, 0x5c, 0x6d, 0x98, 0x81 } }; diff --git a/foobar2000/SDK/utility.cpp b/foobar2000/SDK/utility.cpp index 3f66dca..c5116b3 100644 --- a/foobar2000/SDK/utility.cpp +++ b/foobar2000/SDK/utility.cpp @@ -29,10 +29,7 @@ namespace fb2k { } namespace pfc { - /* - Redirect PFC methods to shared.dll - If you're getting linker multiple-definition errors on these, change build configuration of PFC from "Debug" / "Release" to "Debug FB2K" / "Release FB2K" - */ + // Redirect PFC methods to shared.dll BOOL winFormatSystemErrorMessageHook(pfc::string_base & p_out, DWORD p_code) { return uFormatSystemErrorMessage(p_out, p_code); } @@ -40,38 +37,3 @@ namespace pfc { uBugCheck(); } } - - -// file_lock_manager.h functionality -#include "file_lock_manager.h" -namespace { - class file_lock_interrupt_impl : public file_lock_interrupt { - public: - void interrupt( abort_callback & a ) { f(a); } - std::function f; - }; -} - -file_lock_interrupt::ptr file_lock_interrupt::create( std::function< void (abort_callback&)> f ) { - service_ptr_t i = new service_impl_t(); - i->f = f; - return i; -} - -// file_info_filter.h functionality -#include "file_info_filter.h" -namespace { - class file_info_filter_lambda : public file_info_filter { - public: - bool apply_filter(trackRef p_track,t_filestats p_stats,file_info & p_info) override { - return f(p_track, p_stats, p_info); - } - func_t f; - }; -} - -file_info_filter::ptr file_info_filter::create(func_t f) { - auto o = fb2k::service_new(); - o->f = f; - return o; -} diff --git a/foobar2000/foo_sample/dsp.cpp b/foobar2000/foo_sample/dsp.cpp index aa68737..1e912cd 100644 --- a/foobar2000/foo_sample/dsp.cpp +++ b/foobar2000/foo_sample/dsp.cpp @@ -95,7 +95,7 @@ public: RangeTotal = RangeMax - RangeMin }; - BEGIN_MSG_MAP_EX(CMyDSPPopup) + BEGIN_MSG_MAP(CMyDSPPopup) MSG_WM_INITDIALOG(OnInitDialog) COMMAND_HANDLER_EX(IDOK, BN_CLICKED, OnButton) COMMAND_HANDLER_EX(IDCANCEL, BN_CLICKED, OnButton) diff --git a/foobar2000/foo_sample/foo_sample.rc b/foobar2000/foo_sample/foo_sample.rc index ab2b95c..e6c2cd7 100644 --- a/foobar2000/foo_sample/foo_sample.rc +++ b/foobar2000/foo_sample/foo_sample.rc @@ -112,14 +112,6 @@ BEGIN LTEXT "Header",IDC_HEADER,8,4,348,8 END -IDD_LISTCONTROL_DEMO DIALOGEX 0, 0, 311, 177 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Dialog" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "",IDC_LIST1,"SysListView32",LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,12,12,288,156 -END - ///////////////////////////////////////////////////////////////////////////// // @@ -168,14 +160,6 @@ BEGIN TOPMARGIN, 7 BOTTOMMARGIN, 225 END - - IDD_LISTCONTROL_DEMO, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 304 - TOPMARGIN, 7 - BOTTOMMARGIN, 170 - END END #endif // APSTUDIO_INVOKED @@ -195,21 +179,6 @@ BEGIN 0 END -IDD_LISTCONTROL_DEMO AFX_DIALOG_LAYOUT -BEGIN - 0 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDI_SCROLL ICON "..\\..\\libPPUI\\IDI_SCROLL.ico" - #endif // English (United States) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/foobar2000/foo_sample/foo_sample.sln b/foobar2000/foo_sample/foo_sample.sln index f797125..29f1d56 100644 --- a/foobar2000/foo_sample/foo_sample.sln +++ b/foobar2000/foo_sample/foo_sample.sln @@ -5,6 +5,8 @@ VisualStudioVersion = 15.0.27130.2027 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "foo_sample", "foo_sample.vcxproj", "{85FBFD09-0099-4FE9-9DB6-78DB6F60F817}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "foobar2000_ATL_helpers", "..\ATLHelpers\foobar2000_ATL_helpers.vcxproj", "{622E8B19-8109-4717-BD4D-9657AA78363E}" +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "foobar2000_SDK", "..\SDK\foobar2000_SDK.vcxproj", "{E8091321-D79D-4575-86EF-064EA1A4A20D}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pfc", "..\..\pfc\pfc.vcxproj", "{EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}" @@ -13,8 +15,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "foobar2000_sdk_helpers", ". EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "foobar2000_component_client", "..\foobar2000_component_client\foobar2000_component_client.vcxproj", "{71AD2674-065B-48F5-B8B0-E1F9D3892081}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libPPUI", "..\..\libPPUI\libPPUI.vcxproj", "{7729EB82-4069-4414-964B-AD399091A03F}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x86 = Debug|x86 @@ -25,14 +25,18 @@ Global {85FBFD09-0099-4FE9-9DB6-78DB6F60F817}.Debug|x86.Build.0 = Debug|Win32 {85FBFD09-0099-4FE9-9DB6-78DB6F60F817}.Release|x86.ActiveCfg = Release|Win32 {85FBFD09-0099-4FE9-9DB6-78DB6F60F817}.Release|x86.Build.0 = Release|Win32 + {622E8B19-8109-4717-BD4D-9657AA78363E}.Debug|x86.ActiveCfg = Debug|Win32 + {622E8B19-8109-4717-BD4D-9657AA78363E}.Debug|x86.Build.0 = Debug|Win32 + {622E8B19-8109-4717-BD4D-9657AA78363E}.Release|x86.ActiveCfg = Release|Win32 + {622E8B19-8109-4717-BD4D-9657AA78363E}.Release|x86.Build.0 = Release|Win32 {E8091321-D79D-4575-86EF-064EA1A4A20D}.Debug|x86.ActiveCfg = Debug|Win32 {E8091321-D79D-4575-86EF-064EA1A4A20D}.Debug|x86.Build.0 = Debug|Win32 {E8091321-D79D-4575-86EF-064EA1A4A20D}.Release|x86.ActiveCfg = Release|Win32 {E8091321-D79D-4575-86EF-064EA1A4A20D}.Release|x86.Build.0 = Release|Win32 - {EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}.Debug|x86.ActiveCfg = Debug FB2K|Win32 - {EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}.Debug|x86.Build.0 = Debug FB2K|Win32 - {EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}.Release|x86.ActiveCfg = Release FB2K|Win32 - {EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}.Release|x86.Build.0 = Release FB2K|Win32 + {EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}.Debug|x86.ActiveCfg = Debug|Win32 + {EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}.Debug|x86.Build.0 = Debug|Win32 + {EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}.Release|x86.ActiveCfg = Release|Win32 + {EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}.Release|x86.Build.0 = Release|Win32 {EE47764E-A202-4F85-A767-ABDAB4AFF35F}.Debug|x86.ActiveCfg = Debug|Win32 {EE47764E-A202-4F85-A767-ABDAB4AFF35F}.Debug|x86.Build.0 = Debug|Win32 {EE47764E-A202-4F85-A767-ABDAB4AFF35F}.Release|x86.ActiveCfg = Release|Win32 @@ -41,10 +45,6 @@ Global {71AD2674-065B-48F5-B8B0-E1F9D3892081}.Debug|x86.Build.0 = Debug|Win32 {71AD2674-065B-48F5-B8B0-E1F9D3892081}.Release|x86.ActiveCfg = Release|Win32 {71AD2674-065B-48F5-B8B0-E1F9D3892081}.Release|x86.Build.0 = Release|Win32 - {7729EB82-4069-4414-964B-AD399091A03F}.Debug|x86.ActiveCfg = Debug|Win32 - {7729EB82-4069-4414-964B-AD399091A03F}.Debug|x86.Build.0 = Debug|Win32 - {7729EB82-4069-4414-964B-AD399091A03F}.Release|x86.ActiveCfg = Release|Win32 - {7729EB82-4069-4414-964B-AD399091A03F}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/foobar2000/foo_sample/foo_sample.vcxproj b/foobar2000/foo_sample/foo_sample.vcxproj index c8b3b6f..1057bfd 100644 --- a/foobar2000/foo_sample/foo_sample.vcxproj +++ b/foobar2000/foo_sample/foo_sample.vcxproj @@ -14,18 +14,19 @@ {85FBFD09-0099-4FE9-9DB6-78DB6F60F817} foo_input_raw Win32Proj + 10.0.14393.0 DynamicLibrary Unicode true - v141 + v141_xp DynamicLibrary Unicode - v141 + v141_xp @@ -49,6 +50,7 @@ Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;FOO_INPUT_RAW_EXPORTS;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebugDLL Use @@ -56,6 +58,7 @@ Level3 ProgramDatabase 4715 + NoExtensions ..;../.. Fast @@ -71,11 +74,13 @@ + WIN32;NDEBUG;_WINDOWS;_USRDLL;FOO_INPUT_RAW_EXPORTS;%(PreprocessorDefinitions) MultiThreadedDLL Use stdafx.h Level3 ProgramDatabase + NoExtensions /d2notypeopt %(AdditionalOptions) 4715 false @@ -83,7 +88,6 @@ true ..;../.. Fast - NDEBUG;_WINDLL;%(PreprocessorDefinitions) true @@ -103,11 +107,7 @@ - - - - @@ -115,7 +115,6 @@ Create - @@ -123,7 +122,6 @@ - @@ -134,12 +132,12 @@ - - {7729eb82-4069-4414-964b-ad399091a03f} - {ebfffb4e-261d-44d3-b89c-957b31a0bf9c} + + {622e8b19-8109-4717-bd4d-9657aa78363e} + {71ad2674-065b-48f5-b8b0-e1f9d3892081} @@ -150,9 +148,6 @@ {e8091321-d79d-4575-86ef-064ea1a4a20d} - - - diff --git a/foobar2000/foo_sample/foo_sample.vcxproj.filters b/foobar2000/foo_sample/foo_sample.vcxproj.filters index 3e00fa0..25be624 100644 --- a/foobar2000/foo_sample/foo_sample.vcxproj.filters +++ b/foobar2000/foo_sample/foo_sample.vcxproj.filters @@ -60,21 +60,6 @@ Source Files - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - @@ -83,9 +68,6 @@ Header Files - - Header Files - @@ -95,9 +77,4 @@ - - - Resource Files - - \ No newline at end of file diff --git a/foobar2000/foo_sample/listcontrol-advanced.cpp b/foobar2000/foo_sample/listcontrol-advanced.cpp deleted file mode 100644 index 9b48c09..0000000 --- a/foobar2000/foo_sample/listcontrol-advanced.cpp +++ /dev/null @@ -1,323 +0,0 @@ -// Advanced CListControl use demo -// Subclasses a CListControl to use all its features - -#include "stdafx.h" -#include "resource.h" -#include -#include -#include -#include -#include -#include - -namespace { - struct listData_t { - std::string m_key, m_value; - bool m_checkState = false; - }; - static std::vector makeListData() { - std::vector data; - data.resize( 10 ); - for( size_t walk = 0; walk < data.size(); ++ walk ) { - auto & rec = data[walk]; - rec.m_key = (PFC_string_formatter() << "Item #" << (walk+1) ).c_str(); - rec.m_value = "edit me"; - } - return data; - } - - // See CListControlComplete.h for base class description - typedef CListControlComplete CListControlDemoParent; - - class CListControlDemo : public CListControlDemoParent { - typedef CListControlDemoParent parent_t; - public: - BEGIN_MSG_MAP_EX(CListControlDemo) - CHAIN_MSG_MAP( parent_t ); - MSG_WM_CREATE(OnCreate) - MSG_WM_CONTEXTMENU(OnContextMenu) - END_MSG_MAP() - - - // Context menu handler - void OnContextMenu(CWindow wnd, CPoint point) { - // did we get a (-1,-1) point due to context menu key rather than right click? - // GetContextMenuPoint fixes that, returning a proper point at which the menu should be shown - point = this->GetContextMenuPoint(point); - - CMenu menu; - // WIN32_OP_D() : debug build only return value check - // Used to check for obscure errors in debug builds, does nothing (ignores errors) in release build - WIN32_OP_D(menu.CreatePopupMenu()); - - enum { ID_TEST1 = 1, ID_TEST2, ID_SELECTALL, ID_SELECTNONE, ID_INVERTSEL }; - menu.AppendMenu(MF_STRING, ID_TEST1, L"Test 1"); - menu.AppendMenu(MF_STRING, ID_TEST2, L"Test 2"); - menu.AppendMenu(MF_SEPARATOR); - // Note: Ctrl+A handled automatically by CListControl, no need for us to catch it - menu.AppendMenu(MF_STRING, ID_SELECTALL, L"Select all\tCtrl+A"); - menu.AppendMenu(MF_STRING, ID_SELECTNONE, L"Select none"); - menu.AppendMenu(MF_STRING, ID_INVERTSEL, L"Invert selection"); - - int cmd; - { - // Callback object to show menu command descriptions in the status bar. - // it's actually a hidden window, needs a parent HWND, where we feed our control's HWND - CMenuDescriptionMap descriptions(m_hWnd); - - // Set descriptions of all our items - descriptions.Set(ID_TEST1, "This is a test item #1"); - descriptions.Set(ID_TEST2, "This is a test item #2"); - - descriptions.Set(ID_SELECTALL, "Selects all items"); - descriptions.Set(ID_SELECTNONE, "Deselects all items"); - descriptions.Set(ID_INVERTSEL, "Invert selection"); - - cmd = menu.TrackPopupMenuEx(TPM_RIGHTBUTTON | TPM_NONOTIFY | TPM_RETURNCMD, point.x, point.y, descriptions, nullptr); - } - switch(cmd) { - case ID_TEST1: - { - pfc::string_formatter msg; - msg << "Test command #1 triggered.\r\n"; - msg << this->GetSelectedCount() << " items selected."; - // popup_message : non-blocking MessageBox equivalent - popup_message::g_show(msg, "Information"); - } - break; - case ID_TEST2: - { - pfc::string_formatter msg; - msg << "Test command #1 triggered.\r\n"; - msg << "Selected items:\r\n"; - for( size_t walk = 0; walk < GetItemCount(); ++ walk) { - if ( this->IsItemSelected( walk ) ) { - msg << m_data[walk].m_key.c_str() << "\r\n"; - } - } - msg << "End selected items."; - // popup_message : non-blocking MessageBox equivalent - popup_message::g_show(msg, "Information"); - } - break; - case ID_SELECTALL: - this->SelectAll(); // trivial - break; - case ID_SELECTNONE: - this->SelectNone(); // trivial - break; - case ID_INVERTSEL: - { - auto mask = this->GetSelectionMask(); - this->SetSelection( - // Items which we alter - all of them - pfc::bit_array_true(), - // Selection values - NOT'd original selection mask - pfc::bit_array_not(mask) - ); - // Exclusion of footer item from selection handled via CanSelectItem() - } - break; - } - } - - int OnCreate(LPCREATESTRUCT lpCreateStruct) { - InitHeader(); // set up header control with columns - SetWindowText(L"List Control Demo"); // screen reader will see this - return 0; - } - void InitHeader() { - InitializeHeaderCtrl(HDS_FULLDRAG); - - // never hardcode values in pixels, always use screen DPI - auto DPI = m_dpi; - AddColumn( "Check", MulDiv(60, DPI.cx, 96 ) ); - AddColumn( "Name", MulDiv(100, DPI.cx, 96 ) ); - AddColumn( "Value", MulDiv(100, DPI.cx, 96 ) ); - } - - bool CanSelectItem( size_t row ) const override { - // can not select footer - return row != footerRow(); - } - size_t footerRow() const { - return m_data.size(); - } - t_size GetItemCount() const override { - return m_data.size() + 1; // footer - } - void onFooterClicked() { - SelectNone(); - listData_t obj = {}; - obj.m_key = "New item"; - size_t index = m_data.size(); - m_data.push_back( std::move(obj) ); - OnItemsInserted(index, 1, true); - } - void OnSubItemClicked(t_size item, t_size subItem, CPoint pt) override { - if ( item == footerRow() ) { - onFooterClicked(); return; - } - if ( subItem == 2 ) { - TableEdit_Start(item, subItem); return; - } - __super::OnSubItemClicked( item, subItem, pt ); - } - bool AllowScrollbar(bool vertical) const override { - return true; - } - t_size InsertIndexFromPointEx(const CPoint & pt, bool & bInside) const override { - // Drag&drop insertion point hook, for reordering only - auto ret = __super::InsertIndexFromPointEx(pt, bInside); - bInside = false; // never drop *into* an item, only between, as we only allow reorder - if ( ret > m_data.size() ) ret = m_data.size(); // never allow drop beyond footer - return ret; - } - void RequestReorder(size_t const * order, size_t count) override { - // we've been asked to reorder the items, by either drag&drop or cursors+modifiers - // we can either reorder as requested, reorder partially if some of the items aren't moveable, or reject the request - - PFC_ASSERT( count == GetItemCount() ); - - // Footer row cannot be moved - if ( order[footerRow()] != footerRow() ) return; - - pfc::reorder_t( m_data, order, count ); - this->OnItemsReordered( order, count ); - } - void RemoveMask( pfc::bit_array const & mask ) { - if ( mask.get(footerRow() ) ) return; // footer row cannot be removed - auto oldCount = GetItemCount(); - pfc::remove_mask_t( m_data, mask ); - this->OnItemsRemoved( mask, oldCount ); - } - void RequestRemoveSelection() override { - // Delete key etc - RemoveMask(GetSelectionMask()); - } - void ExecuteDefaultAction(t_size index) override { - // double click, enter key, etc - if ( index == footerRow() ) onFooterClicked(); - } - - bool GetSubItemText(t_size item, t_size subItem, pfc::string_base & out) const override { - if ( item == footerRow() ) { - if ( subItem == 0 ) { - out = "+ add new"; - return true; - } - return false; - } - auto & rec = m_data[item]; - switch(subItem) { - case 0: - // pass blank string or return false to create a checkbox only column - out = "check"; - return true; - case 1: - out = rec.m_key.c_str(); - return true; - case 2: - out = rec.m_value.c_str(); - return true; - default: - return false; - } - } - - size_t GetSubItemSpan(size_t row, size_t column) const override { - if ( row == footerRow() && column == 0 ) { - return GetColumnCount(); - } - return 1; - } - cellType_t GetCellType(size_t item, size_t subItem) const override { - // cellType_t is a pointer to a cell class object supplying cell behavior specification & rendering methods - // use PFC_SINGLETON to provide static instances of used cells - if ( item == footerRow() ) { - if ( subItem == 0 ) { - return & PFC_SINGLETON( CListCell_Button ); - } else { - return nullptr; - } - } - switch(subItem) { - case 0: - return & PFC_SINGLETON( CListCell_Checkbox ); - default: - return & PFC_SINGLETON( CListCell_Text ); - } - - } - bool GetCellTypeSupported() const override { - return true; - } - bool GetCellCheckState(size_t item, size_t subItem) const override { - if ( subItem == 0 ) { - auto & rec = m_data[item]; - return rec.m_checkState; - } - return false; - } - void SetCellCheckState(size_t item, size_t subItem, bool value) override { - if ( subItem == 0 ) { - auto & rec = m_data[item]; - if (rec.m_checkState != value) { - rec.m_checkState = value; - __super::SetCellCheckState(item, subItem, value); - } - } - } - - uint32_t QueryDragDropTypes() const override {return dragDrop_reorder;} - - // Inplace edit handlers - // Overrides of CTableEditHelperV2 methods - void TableEdit_SetField(t_size item, t_size subItem, const char * value) override { - if ( subItem == 2 ) { - m_data[item].m_value = value; - ReloadItem( item ); - } - } - bool TableEdit_IsColumnEditable(t_size subItem) const override { - return subItem == 2; - } - private: - std::vector< listData_t > m_data = makeListData(); - }; - - // Straightforward WTL dialog code - class CListControlAdvancedDemoDialog : public CDialogImpl { - public: - enum { IDD = IDD_LISTCONTROL_DEMO }; - - BEGIN_MSG_MAP_EX(CListControlAdvancedDemoDialog) - MSG_WM_INITDIALOG(OnInitDialog) - COMMAND_HANDLER_EX(IDCANCEL, BN_CLICKED, OnCancel) - END_MSG_MAP() - private: - void OnCancel(UINT, int, CWindow) { - DestroyWindow(); - } - - BOOL OnInitDialog(CWindow, LPARAM) { - - // Create replacing existing windows list control - // automatically initialize position, font, etc - m_list.CreateInDialog( *this, IDC_LIST1 ); - - ShowWindow(SW_SHOW); - - return TRUE; // system should set focus - } - - CListControlDemo m_list; - }; -} - -// Called from mainmenu.cpp -void RunListControlAdvancedDemo() { - // automatically creates the dialog with object lifetime management and modeless dialog registration - fb2k::newDialog(); -} - diff --git a/foobar2000/foo_sample/listcontrol-ownerdata.cpp b/foobar2000/foo_sample/listcontrol-ownerdata.cpp deleted file mode 100644 index c328ed7..0000000 --- a/foobar2000/foo_sample/listcontrol-ownerdata.cpp +++ /dev/null @@ -1,204 +0,0 @@ -#include "stdafx.h" - -// Owner-data CListControl use demo -// CListControlOwnerData with callbacks - -#include "stdafx.h" -#include "resource.h" -#include -#include -#include -#include -#include - -namespace { - struct listData_t { - std::string m_key, m_value; - }; - static std::vector makeListData() { - std::vector data; - data.resize( 10 ); - for( size_t walk = 0; walk < data.size(); ++ walk ) { - auto & rec = data[walk]; - rec.m_key = (PFC_string_formatter() << "Item #" << (walk+1) ).c_str(); - rec.m_value = "edit me"; - } - return data; - } - - - class CListControlOwnerDataDemoDialog : public CDialogImpl, private IListControlOwnerDataSource { - public: - - // CListControlOwnerData constructor requires ptr to IListControlOwnerDataSource object - CListControlOwnerDataDemoDialog() : m_list(this) {} - - enum { IDD = IDD_LISTCONTROL_DEMO }; - - BEGIN_MSG_MAP_EX(CListControlOwnerDataDemoDialog) - MSG_WM_INITDIALOG(OnInitDialog) - COMMAND_HANDLER_EX(IDCANCEL, BN_CLICKED, OnCancel) - MSG_WM_CONTEXTMENU(OnContextMenu) - END_MSG_MAP() - private: - void OnCancel(UINT, int, CWindow) { - DestroyWindow(); - } - - BOOL OnInitDialog(CWindow, LPARAM) { - - // Create replacing existing windows list control - // automatically initialize position, font, etc - m_list.CreateInDialog( *this, IDC_LIST1 ); - - // never hardcode values in pixels, always use screen DPI - auto DPI = m_list.GetDPI(); - m_list.AddColumn( "Name", MulDiv(100, DPI.cx, 96 ) ); - m_list.AddColumn( "Value", MulDiv(150, DPI.cx, 96 ) ); - - ShowWindow(SW_SHOW); - - return TRUE; // system should set focus - } - - // Context menu handler - void OnContextMenu(CWindow wnd, CPoint point) { - // did we get a (-1,-1) point due to context menu key rather than right click? - // GetContextMenuPoint fixes that, returning a proper point at which the menu should be shown - point = m_list.GetContextMenuPoint(point); - - CMenu menu; - // WIN32_OP_D() : debug build only return value check - // Used to check for obscure errors in debug builds, does nothing (ignores errors) in release build - WIN32_OP_D(menu.CreatePopupMenu()); - - enum { ID_TEST1 = 1, ID_TEST2, ID_SELECTALL, ID_SELECTNONE, ID_INVERTSEL }; - menu.AppendMenu(MF_STRING, ID_TEST1, L"Test 1"); - menu.AppendMenu(MF_STRING, ID_TEST2, L"Test 2"); - menu.AppendMenu(MF_SEPARATOR); - // Note: Ctrl+A handled automatically by CListControl, no need for us to catch it - menu.AppendMenu(MF_STRING, ID_SELECTALL, L"Select all\tCtrl+A"); - menu.AppendMenu(MF_STRING, ID_SELECTNONE, L"Select none"); - menu.AppendMenu(MF_STRING, ID_INVERTSEL, L"Invert selection"); - - int cmd; - { - // Callback object to show menu command descriptions in the status bar. - // it's actually a hidden window, needs a parent HWND, where we feed our control's HWND - CMenuDescriptionMap descriptions(m_hWnd); - - // Set descriptions of all our items - descriptions.Set(ID_TEST1, "This is a test item #1"); - descriptions.Set(ID_TEST2, "This is a test item #2"); - - descriptions.Set(ID_SELECTALL, "Selects all items"); - descriptions.Set(ID_SELECTNONE, "Deselects all items"); - descriptions.Set(ID_INVERTSEL, "Invert selection"); - - cmd = menu.TrackPopupMenuEx(TPM_RIGHTBUTTON | TPM_NONOTIFY | TPM_RETURNCMD, point.x, point.y, descriptions, nullptr); - } - switch(cmd) { - case ID_TEST1: - { - pfc::string_formatter msg; - msg << "Test command #1 triggered.\r\n"; - msg << m_list.GetSelectedCount() << " items selected."; - // popup_message : non-blocking MessageBox equivalent - popup_message::g_show(msg, "Information"); - } - break; - case ID_TEST2: - { - pfc::string_formatter msg; - msg << "Test command #1 triggered.\r\n"; - msg << "Selected items:\r\n"; - for( size_t walk = 0; walk < m_list.GetItemCount(); ++ walk) { - if ( m_list.IsItemSelected( walk ) ) { - msg << m_data[walk].m_key.c_str() << "\r\n"; - } - } - msg << "End selected items."; - // popup_message : non-blocking MessageBox equivalent - popup_message::g_show(msg, "Information"); - } - break; - case ID_SELECTALL: - m_list.SelectAll(); // trivial - break; - case ID_SELECTNONE: - m_list.SelectNone(); // trivial - break; - case ID_INVERTSEL: - { - auto mask = m_list.GetSelectionMask(); - m_list.SetSelection( - // Items which we alter - all of them - pfc::bit_array_true(), - // Selection values - NOT'd original selection mask - pfc::bit_array_not(mask) - ); - // Exclusion of footer item from selection handled via CanSelectItem() - } - break; - } - } - - private: - // IListControlOwnerDataSource methods - - size_t listGetItemCount( ctx_t ctx ) override { - PFC_ASSERT( ctx == &m_list ); // ctx is a pointer to the object calling us - return m_data.size(); - } - pfc::string8 listGetSubItemText( ctx_t, size_t item, size_t subItem ) override { - auto & rec = m_data[item]; - switch(subItem) { - case 0: - return rec.m_key.c_str(); - case 1: - return rec.m_value.c_str(); - default: - return ""; - } - - } - bool listCanReorderItems( ctx_t ) override { - return true; - } - bool listReorderItems( ctx_t, const size_t* order, size_t count) override { - PFC_ASSERT( count == m_data.size() ); - pfc::reorder_t( m_data, order, count ); - return true; - } - bool listRemoveItems( ctx_t, pfc::bit_array const & mask) override { - pfc::remove_mask_t( m_data, mask ); - return true; - } - void listItemAction(ctx_t, size_t item) override { - m_list.TableEdit_Start( item, 1 ); - } - void listSubItemClicked( ctx_t, size_t item, size_t subItem) override { - if ( subItem == 1 ) { - m_list.TableEdit_Start( item, subItem ); - } - } - void listSetEditField(ctx_t ctx, size_t item, size_t subItem, const char * val) override { - if ( subItem == 1 ) { - m_data[item].m_value = val; - } - } - bool listIsColumnEditable( ctx_t, size_t subItem ) override { - return subItem == 1; - } - - - std::vector< listData_t > m_data = makeListData(); - - CListControlOwnerData m_list; - }; -} -// Called from mainmenu.cpp -void RunListControlOwnerDataDemo() { - // automatically creates the dialog with object lifetime management and modeless dialog registration - fb2k::newDialog(); -} diff --git a/foobar2000/foo_sample/listcontrol-simple.cpp b/foobar2000/foo_sample/listcontrol-simple.cpp deleted file mode 100644 index 146889e..0000000 --- a/foobar2000/foo_sample/listcontrol-simple.cpp +++ /dev/null @@ -1,163 +0,0 @@ -#include "stdafx.h" - -// Simple CListControl use demo -// CListControlSimple - -#include "stdafx.h" -#include "resource.h" -#include -#include -#include -#include -#include - -namespace { - struct listData_t { - std::string m_key, m_value; - }; - static std::vector makeListData() { - std::vector data; - data.resize( 10 ); - for( size_t walk = 0; walk < data.size(); ++ walk ) { - auto & rec = data[walk]; - rec.m_key = (PFC_string_formatter() << "Item #" << (walk+1) ).c_str(); - rec.m_value = "sample value"; - } - return data; - } - - - class CListControlSimpleDemoDialog : public CDialogImpl { - public: - - enum { IDD = IDD_LISTCONTROL_DEMO }; - - BEGIN_MSG_MAP_EX(CListControlOwnerDataDemoDialog) - MSG_WM_INITDIALOG(OnInitDialog) - COMMAND_HANDLER_EX(IDCANCEL, BN_CLICKED, OnCancel) - MSG_WM_CONTEXTMENU(OnContextMenu) - END_MSG_MAP() - private: - void OnCancel(UINT, int, CWindow) { - DestroyWindow(); - } - - BOOL OnInitDialog(CWindow, LPARAM) { - - // Create replacing existing windows list control - // automatically initialize position, font, etc - m_list.CreateInDialog( *this, IDC_LIST1 ); - - // never hardcode values in pixels, always use screen DPI - auto DPI = m_list.GetDPI(); - m_list.AddColumn( "Name", MulDiv(100, DPI.cx, 96 ) ); - m_list.AddColumn( "Value", MulDiv(150, DPI.cx, 96 ) ); - - { - auto data = makeListData(); - - m_list.SetItemCount( data.size( ) ); - for( size_t walk = 0; walk < data.size(); ++ walk ) { - auto & rec = data[walk]; - m_list.SetItemText( walk, 0, rec.m_key.c_str() ); - m_list.SetItemText( walk, 1, rec.m_value.c_str() ); - } - } - - ShowWindow(SW_SHOW); - - return TRUE; // system should set focus - } - - // Context menu handler - void OnContextMenu(CWindow wnd, CPoint point) { - // did we get a (-1,-1) point due to context menu key rather than right click? - // GetContextMenuPoint fixes that, returning a proper point at which the menu should be shown - point = m_list.GetContextMenuPoint(point); - - CMenu menu; - // WIN32_OP_D() : debug build only return value check - // Used to check for obscure errors in debug builds, does nothing (ignores errors) in release build - WIN32_OP_D(menu.CreatePopupMenu()); - - enum { ID_TEST1 = 1, ID_TEST2, ID_SELECTALL, ID_SELECTNONE, ID_INVERTSEL }; - menu.AppendMenu(MF_STRING, ID_TEST1, L"Test 1"); - menu.AppendMenu(MF_STRING, ID_TEST2, L"Test 2"); - menu.AppendMenu(MF_SEPARATOR); - // Note: Ctrl+A handled automatically by CListControl, no need for us to catch it - menu.AppendMenu(MF_STRING, ID_SELECTALL, L"Select all\tCtrl+A"); - menu.AppendMenu(MF_STRING, ID_SELECTNONE, L"Select none"); - menu.AppendMenu(MF_STRING, ID_INVERTSEL, L"Invert selection"); - - int cmd; - { - // Callback object to show menu command descriptions in the status bar. - // it's actually a hidden window, needs a parent HWND, where we feed our control's HWND - CMenuDescriptionMap descriptions(m_hWnd); - - // Set descriptions of all our items - descriptions.Set(ID_TEST1, "This is a test item #1"); - descriptions.Set(ID_TEST2, "This is a test item #2"); - - descriptions.Set(ID_SELECTALL, "Selects all items"); - descriptions.Set(ID_SELECTNONE, "Deselects all items"); - descriptions.Set(ID_INVERTSEL, "Invert selection"); - - cmd = menu.TrackPopupMenuEx(TPM_RIGHTBUTTON | TPM_NONOTIFY | TPM_RETURNCMD, point.x, point.y, descriptions, nullptr); - } - switch(cmd) { - case ID_TEST1: - { - pfc::string_formatter msg; - msg << "Test command #1 triggered.\r\n"; - msg << m_list.GetSelectedCount() << " items selected."; - // popup_message : non-blocking MessageBox equivalent - popup_message::g_show(msg, "Information"); - } - break; - case ID_TEST2: - { - pfc::string_formatter msg; - msg << "Test command #1 triggered.\r\n"; - msg << "Selected items:\r\n"; - for( size_t walk = 0; walk < m_list.GetItemCount(); ++ walk) { - if ( m_list.IsItemSelected( walk ) ) { - msg << "#" << (walk+1) << "\r\n"; - } - } - msg << "End selected items."; - // popup_message : non-blocking MessageBox equivalent - popup_message::g_show(msg, "Information"); - } - break; - case ID_SELECTALL: - m_list.SelectAll(); // trivial - break; - case ID_SELECTNONE: - m_list.SelectNone(); // trivial - break; - case ID_INVERTSEL: - { - auto mask = m_list.GetSelectionMask(); - m_list.SetSelection( - // Items which we alter - all of them - pfc::bit_array_true(), - // Selection values - NOT'd original selection mask - pfc::bit_array_not(mask) - ); - // Exclusion of footer item from selection handled via CanSelectItem() - } - break; - } - } - - private: - - CListControlSimple m_list; - }; -} - -// Called from mainmenu.cpp -void RunListControlSimpleDemo() { - fb2k::newDialog(); -} diff --git a/foobar2000/foo_sample/mainmenu-dynamic.cpp b/foobar2000/foo_sample/mainmenu-dynamic.cpp deleted file mode 100644 index f6b5362..0000000 --- a/foobar2000/foo_sample/mainmenu-dynamic.cpp +++ /dev/null @@ -1,120 +0,0 @@ -#include "stdafx.h" -#include - -namespace { // anon namespace everything, it's not accessible by means other than the service factory - -// The command ID. -// Generate a new GUID when reusing code. -static const GUID guid_menucommand = { 0xab754b0b, 0x204, 0x4471, { 0xb5, 0x29, 0xff, 0x73, 0xae, 0x51, 0x5d, 0xe9 } }; - -// Shared with mainmenu.cpp -static const GUID guid_mainmenu_group_id = { 0x44963e7a, 0x4b2a, 0x4588, { 0xb0, 0x17, 0xa8, 0x69, 0x18, 0xcb, 0x8a, 0xa5 } }; - -class sample_command : public mainmenu_node_command { -public: - sample_command( size_t index ) : m_index(index) { - } - void get_display(pfc::string_base & text, t_uint32 & flags) override { - flags = 0; - text = PFC_string_formatter() << "Test dynamic item #" << m_index; - } - void execute(service_ptr_t callback) override { - popup_message::g_show(PFC_string_formatter() << "Invoked test menu item #" << m_index, "Information"); - } - GUID get_guid() override { - // This method returns our subcommand ID. - // Dynamic commands are identified by a pair of GUIDs: - // - command ID ( see: mainmenu_commands interface ) - // - subcommand ID ( identifier of one of the dynamic items ) - // Subcommand identifiers don't have to be actually globally unique, - // as long as they're unique among the subcommand identifiers for this command ID. - - // In our case, we'll just create a makeshift GUID from a hash of the index. - // This is perfectly okay for production code - as long as your command ID is a proper GUID! - - // Don't ever hash size_t which varies with CPU architecture - // Integer endianness intentionally disregarded - uint32_t hashme = (uint32_t) m_index; - - auto api = hasher_md5::get(); - hasher_md5_state state; - api->initialize( state ); - api->process( state, &hashme, sizeof(hashme) ); - - // fb2k hasher_md5 API even provides a convenient method to return MD5 hashes cast to GUIDs for this. - return api->get_result_guid( state ); - } - bool get_description(pfc::string_base & out) { - out = PFC_string_formatter() << "This is a test menu item #" << m_index << "."; - return true; - } -private: - const size_t m_index; -}; -class sample_group : public mainmenu_node_group { -public: - sample_group() { - m_children.resize(11); - for( size_t walk = 0; walk < m_children.size(); ++ walk ) { - mainmenu_node::ptr node; - // Insert separators for odd items, commands for even - if ( walk % 2 ) { - node = fb2k::service_new(); - } else { - auto cmdIndex = walk/2 + 1; - node = fb2k::service_new( cmdIndex ); - } - m_children[walk] = std::move(node); - } - } - void get_display(pfc::string_base & text, t_uint32 & flags) override { - flags = 0; - text = "Dynamic menu test group"; - } - t_size get_children_count() override { - return m_children.size(); - } - mainmenu_node::ptr get_child(t_size index) override { - PFC_ASSERT( index < m_children.size() ); - return m_children[index]; - } -private: - std::vector m_children; - -}; - -class mainmenu_sample_dynamic : public mainmenu_commands_v2 { -public: - // mainmenu_commands_v2 methods - t_uint32 get_command_count() override { return 1; } - GUID get_command(t_uint32 p_index) override {return guid_menucommand;} - void get_name(t_uint32 p_index,pfc::string_base & p_out) override {p_out = "Dynamic menu test";} - - bool get_description(t_uint32 p_index,pfc::string_base & p_out) override { - // Should not get here much - p_out = "This is a dynamic menu command test."; - return true; - } - GUID get_parent() override {return guid_mainmenu_group_id; } - void execute(t_uint32 p_index,service_ptr_t p_callback) override { - // Should not get here, someone not aware of our dynamic status tried to invoke us? - } - - bool is_command_dynamic(t_uint32 index) override { return true; } - mainmenu_node::ptr dynamic_instantiate(t_uint32 index) override { - return fb2k::service_new(); - } - - bool dynamic_execute(t_uint32 index, const GUID & subID, service_ptr_t callback) override { - // If your component provides a more efficient way to execute the command, - // than doing full dynamic_instantiate() and walking all the dynamic items to find one with the matching identifier, - // please implement it here. - - // ... or just skip implementing this method entirely. - return __super::dynamic_execute( index, subID, callback ); - } -}; - -static service_factory_single_t g_mainmenu_sample_dynamic; - -} // namespace \ No newline at end of file diff --git a/foobar2000/foo_sample/mainmenu.cpp b/foobar2000/foo_sample/mainmenu.cpp index adfe475..b73388f 100644 --- a/foobar2000/foo_sample/mainmenu.cpp +++ b/foobar2000/foo_sample/mainmenu.cpp @@ -1,26 +1,16 @@ #include "stdafx.h" -#include "playback_stream_capture.h" - // I am foo_sample and these are *my* GUIDs // Make your own when reusing code or else static const GUID guid_mainmenu_group_id = { 0x44963e7a, 0x4b2a, 0x4588, { 0xb0, 0x17, 0xa8, 0x69, 0x18, 0xcb, 0x8a, 0xa5 } }; static const GUID guid_test = { 0x7c4726df, 0x3b2d, 0x4c7c,{ 0xad, 0xe8, 0x43, 0xd8, 0x46, 0xbe, 0xce, 0xa8 } }; static const GUID guid_playbackstate = { 0xbd880c51, 0xf0cc, 0x473f,{ 0x9d, 0x14, 0xa6, 0x6e, 0x8c, 0xed, 0x25, 0xae } }; static const GUID guid_io = { 0xd380c333, 0xa72c, 0x4e1e,{ 0x97, 0xca, 0xed, 0x14, 0xeb, 0x93, 0x76, 0x23 } }; -static const GUID guid_listcontrol_advanced = { 0x27e29db0, 0x3079, 0x4ce0, { 0x8b, 0x4a, 0xa0, 0x78, 0xeb, 0x6, 0x56, 0x86 } }; -static const GUID guid_listcontrol_simple = { 0x34664996, 0x54cd, 0x48eb, { 0xa8, 0x20, 0x8f, 0x45, 0x7d, 0xcc, 0xff, 0xbb } }; -static const GUID guid_listcontrol_ownerdata = { 0xc6d23696, 0x4be5, 0x4daa, { 0xaf, 0xb2, 0x35, 0x14, 0xa, 0x47, 0xd2, 0xf9 } }; -static const GUID guid_playback_stream_capture = { 0x3d0f0f1a, 0x6b5f, 0x42e3, { 0xa4, 0x6d, 0x49, 0x1, 0x3, 0xf0, 0x54, 0xb2 } }; - static mainmenu_group_popup_factory g_mainmenu_group(guid_mainmenu_group_id, mainmenu_groups::file, mainmenu_commands::sort_priority_dontcare, "Sample component"); void RunPlaybackStateDemo(); //playback_state.cpp void RunIOTest(); // IO.cpp -void RunListControlSimpleDemo(); // listcontrol-simple.cpp -void RunListControlOwnerDataDemo(); // listcontrol-ownerdata.cpp -void RunListControlAdvancedDemo(); // listcontrol-advanced.cpp class mainmenu_commands_sample : public mainmenu_commands { public: @@ -28,56 +18,40 @@ public: cmd_test = 0, cmd_playbackstate, cmd_io, - cmd_listcontrol_simple, - cmd_listcontrol_ownerdata, - cmd_listcontrol_advanced, - cmd_playback_stream_capture, cmd_total }; - t_uint32 get_command_count() override { + t_uint32 get_command_count() { return cmd_total; } - GUID get_command(t_uint32 p_index) override { + GUID get_command(t_uint32 p_index) { switch(p_index) { case cmd_test: return guid_test; case cmd_playbackstate: return guid_playbackstate; case cmd_io: return guid_io; - case cmd_listcontrol_simple: return guid_listcontrol_simple; - case cmd_listcontrol_ownerdata: return guid_listcontrol_ownerdata; - case cmd_listcontrol_advanced: return guid_listcontrol_advanced; - case cmd_playback_stream_capture: return guid_playback_stream_capture; default: uBugCheck(); // should never happen unless somebody called us with invalid parameters - bail } } - void get_name(t_uint32 p_index,pfc::string_base & p_out) override { + void get_name(t_uint32 p_index,pfc::string_base & p_out) { switch(p_index) { case cmd_test: p_out = "Test command"; break; case cmd_playbackstate: p_out = "Playback state demo"; break; case cmd_io: p_out = "I/O test"; break; - case cmd_listcontrol_simple: p_out = "Simple CListControl demo"; break; - case cmd_listcontrol_ownerdata: p_out = "Owner-data CListControl demo"; break; - case cmd_listcontrol_advanced: p_out = "Advanced CListControl demo"; break; - case cmd_playback_stream_capture: p_out = "Playback stream capture demo"; break; default: uBugCheck(); // should never happen unless somebody called us with invalid parameters - bail } } - bool get_description(t_uint32 p_index,pfc::string_base & p_out) override { + bool get_description(t_uint32 p_index,pfc::string_base & p_out) { switch(p_index) { case cmd_test: p_out = "This is a sample menu command."; return true; case cmd_playbackstate: p_out = "Opens the playback state demo dialog."; return true; case cmd_io: p_out = "Runs I/O test."; return true; - case cmd_listcontrol_simple: p_out = "Runs Simple CListControl demo."; return true; - case cmd_listcontrol_ownerdata: p_out = "Runs Owner Data CListControl demo."; return true; - case cmd_listcontrol_advanced: p_out = "Runs Advanced CListControl demo."; return true; - case cmd_playback_stream_capture: p_out = "Toggles playback stream capture operation."; return true; - default: return false; + default: uBugCheck(); // should never happen unless somebody called us with invalid parameters - bail } } - GUID get_parent() override { + GUID get_parent() { return guid_mainmenu_group_id; } - void execute(t_uint32 p_index,service_ptr_t p_callback) override { + void execute(t_uint32 p_index,service_ptr_t p_callback) { switch(p_index) { case cmd_test: popup_message::g_show("This is a sample menu command.", "Blah"); @@ -88,33 +62,10 @@ public: case cmd_io: RunIOTest(); break; - case cmd_listcontrol_simple: - RunListControlSimpleDemo(); - break; - case cmd_listcontrol_ownerdata: - RunListControlOwnerDataDemo(); - break; - case cmd_listcontrol_advanced: - RunListControlAdvancedDemo(); - break; - case cmd_playback_stream_capture: - ToggleCapture(); - break; default: uBugCheck(); // should never happen unless somebody called us with invalid parameters - bail } } - bool get_display(t_uint32 p_index,pfc::string_base & p_text,t_uint32 & p_flags) override { - // OPTIONAL method - bool rv = __super::get_display(p_index, p_text, p_flags); - if (rv) switch(p_index) { - case cmd_playback_stream_capture: - // Add checkmark if capture is in progress - if ( IsCaptureRunning() ) p_flags |= flag_checked; - break; - } - return rv; - } }; static mainmenu_commands_factory_t g_mainmenu_commands_sample_factory; diff --git a/foobar2000/foo_sample/playback_state.cpp b/foobar2000/foo_sample/playback_state.cpp index 200c5f0..d417664 100644 --- a/foobar2000/foo_sample/playback_state.cpp +++ b/foobar2000/foo_sample/playback_state.cpp @@ -1,13 +1,11 @@ #include "stdafx.h" #include "resource.h" -#include -#include class CPlaybackStateDemo : public CDialogImpl, private play_callback_impl_base { public: enum {IDD = IDD_PLAYBACK_STATE}; - BEGIN_MSG_MAP_EX(CPlaybackStateDemo) + BEGIN_MSG_MAP(CPlaybackStateDemo) MSG_WM_INITDIALOG(OnInitDialog) COMMAND_HANDLER_EX(IDC_PATTERN, EN_CHANGE, OnPatternChange) COMMAND_HANDLER_EX(IDCANCEL, BN_CLICKED, OnCancel) diff --git a/foobar2000/foo_sample/playback_stream_capture.cpp b/foobar2000/foo_sample/playback_stream_capture.cpp deleted file mode 100644 index cc74c0b..0000000 --- a/foobar2000/foo_sample/playback_stream_capture.cpp +++ /dev/null @@ -1,121 +0,0 @@ -#include "stdafx.h" -#include - -namespace { - // private classes in anon namespace - - typedef CWavWriter wav_writer; - typedef wavWriterSetup_t wav_writer_setup; - - static pfc::string8 g_outputPath; - static wav_writer g_wav_writer; - - class playback_stream_capture_callback_impl : public playback_stream_capture_callback { - public: - void on_chunk(const audio_chunk & chunk) override { - PFC_ASSERT(core_api::is_main_thread()); - - try { - // writing files in main thread is not pretty, but good enough for our demo - - auto & abort = fb2k::noAbort; - - if (g_wav_writer.is_open() && g_wav_writer.get_spec() != chunk.get_spec()) { - g_wav_writer.finalize(abort); - } - if (!g_wav_writer.is_open() && ! core_api::is_shutting_down() ) { - wav_writer_setup setup; setup.initialize(chunk, 16, false, false); - - GUID g; CoCreateGuid(&g); - pfc::string_formatter fn; - fn << "capture-" << pfc::print_guid(g) << ".wav"; - pfc::string_formatter path = g_outputPath; - path.add_filename( fn ); // pretty method to add file path components with auto inserted delimiter - g_wav_writer.open(path, setup, abort); - } - g_wav_writer.write(chunk, abort); - } catch(std::exception const & e) { - FB2K_console_formatter() << "Playback stream capture error: " << e; - // FIX ME handle this in a pretty manner, likely inaccessible output folder or out of disk space - } - } - }; - static playback_stream_capture_callback_impl g_callback; - static bool g_active = false; - - static void FlushCapture() { - if (g_active) { - g_wav_writer.finalize(fb2k::noAbort); - } - } - static void StopCapture() { - if ( g_active ) { - g_active = false; - playback_stream_capture::get()->remove_callback(&g_callback); - g_wav_writer.finalize(fb2k::noAbort); - } - } - static void StartCapture() { - PFC_ASSERT( g_outputPath.length() > 0 ); - if (!g_active && !core_api::is_shutting_down()) { - g_active = true; - playback_stream_capture::get()->add_callback(&g_callback); - } - } - - // Forcibly stop capture when fb2k is shutting down - class initquit_psc : public initquit { - public: - void on_quit() override { - PFC_ASSERT( core_api::is_shutting_down() ); - StopCapture(); - } - }; - - // Handle playback stop events to split output WAV files - class play_callback_psc : public play_callback_static { - public: - unsigned get_flags() override { - return flag_on_playback_stop; - } - void on_playback_stop(play_control::t_stop_reason p_reason) override { - // Terminate the current stream - FlushCapture(); - } - void on_playback_starting(play_control::t_track_command p_command,bool p_paused) override {} - void on_playback_new_track(metadb_handle_ptr p_track) override {} - void on_playback_seek(double p_time) override {} - void on_playback_pause(bool p_state) override {} - void on_playback_edited(metadb_handle_ptr p_track) override {} - void on_playback_dynamic_info(const file_info & p_info) override {} - void on_playback_dynamic_info_track(const file_info & p_info) override {} - void on_playback_time(double p_time) override {} - void on_volume_change(float p_new_val) override {} - }; - - // pretty modern macro for service_factory_single_t<> - FB2K_SERVICE_FACTORY( initquit_psc ); - FB2K_SERVICE_FACTORY( play_callback_psc ); -} - -void ToggleCapture() { - // Block modal dialog recursions. - // Folder picker below is a modal dialog, don't ever call it if there's another modal dialog in progress. - // Also prevents this function from recursing into itself if someone manages to hit the menu item while already picking folder. - // This will bump whatever modal dialog already exists, so the user has some idea why this was refused. - if ( !ModalDialogPrologue() ) return; - - if (g_active) { - StopCapture(); - } else { - const HWND wndParent = core_api::get_main_window(); - modal_dialog_scope scope(wndParent); // we can't have a handle to the modal dialog, but parent handle is good enough - if (uBrowseForFolder(wndParent, "Choose output folder", g_outputPath)) { - StartCapture(); - } - } -} - -bool IsCaptureRunning() { - return g_active; -} diff --git a/foobar2000/foo_sample/playback_stream_capture.h b/foobar2000/foo_sample/playback_stream_capture.h deleted file mode 100644 index fcc8bc7..0000000 --- a/foobar2000/foo_sample/playback_stream_capture.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once - -void ToggleCapture(); -bool IsCaptureRunning(); \ No newline at end of file diff --git a/foobar2000/foo_sample/preferences.cpp b/foobar2000/foo_sample/preferences.cpp index 9aa5296..2e06b5e 100644 --- a/foobar2000/foo_sample/preferences.cpp +++ b/foobar2000/foo_sample/preferences.cpp @@ -1,6 +1,5 @@ #include "stdafx.h" #include "resource.h" -#include // Sample preferences interface: two meaningless configuration settings accessible through a preferences page and one accessible through advanced preferences. @@ -43,7 +42,7 @@ public: void reset(); //WTL message map - BEGIN_MSG_MAP_EX(CMyPreferences) + BEGIN_MSG_MAP(CMyPreferences) MSG_WM_INITDIALOG(OnInitDialog) COMMAND_HANDLER_EX(IDC_BOGO1, EN_CHANGE, OnEditChange) COMMAND_HANDLER_EX(IDC_BOGO2, EN_CHANGE, OnEditChange) diff --git a/foobar2000/foo_sample/resource.h b/foobar2000/foo_sample/resource.h index 50d7220..4eaae21 100644 --- a/foobar2000/foo_sample/resource.h +++ b/foobar2000/foo_sample/resource.h @@ -6,9 +6,6 @@ #define IDD_DSP 102 #define IDD_UI_ELEMENT 103 #define IDD_THREADS 105 -#define IDD_LISTCONTROL_DEMO 107 -#define IDI_ICON1 109 -#define IDI_SCROLL 109 #define IDD_MYPREFERENCES 148 #define IDC_BOGO1 1001 #define IDC_BOGO2 1002 @@ -38,7 +35,7 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 110 +#define _APS_NEXT_RESOURCE_VALUE 107 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1021 #define _APS_NEXT_SYMED_VALUE 101 diff --git a/foobar2000/foo_sample/stdafx.h b/foobar2000/foo_sample/stdafx.h index 0c227c7..f003958 100644 --- a/foobar2000/foo_sample/stdafx.h +++ b/foobar2000/foo_sample/stdafx.h @@ -1,2 +1,2 @@ -#include +#include diff --git a/foobar2000/foo_sample/ui_and_threads.cpp b/foobar2000/foo_sample/ui_and_threads.cpp index effc8f9..0bb83ce 100644 --- a/foobar2000/foo_sample/ui_and_threads.cpp +++ b/foobar2000/foo_sample/ui_and_threads.cpp @@ -5,10 +5,6 @@ // Or: how I learned to stop worrying and love the lambdas #include // shared_ptr -#include -#include -#include -#include @@ -30,13 +26,6 @@ namespace { // anon namespace local classes for good measure {IDCANCEL, 1,1,1,1 }, {IDC_HEADER, 0,0,1,0 }, {IDC_LIST, 0,0,1,1 }, - - // current position of a control is determined by initial_position + factor * (current_dialog_size - initial_dialog_size) - // where factor is the value from the table above - // applied to all four values - left, top, right, bottom - // 0,0,0,0 means that a control doesn't react to dialog resizing (aligned to top+left, no resize) - // 1,1,1,1 means that the control is aligned to bottom+right but doesn't resize - // 0,0,1,0 means that the control disregards vertical resize (aligned to top) and changes its width with the dialog }; // Minimum/maximum size, in dialog box units; see MSDN MapDialogRect for more info about dialog box units. diff --git a/foobar2000/foo_sample/ui_element.cpp b/foobar2000/foo_sample/ui_element.cpp index 1190aa8..d250285 100644 --- a/foobar2000/foo_sample/ui_element.cpp +++ b/foobar2000/foo_sample/ui_element.cpp @@ -1,7 +1,5 @@ #include "stdafx.h" -#include -#include namespace { @@ -19,7 +17,7 @@ namespace { void initialize_window(HWND parent) {WIN32_OP(Create(parent) != NULL);} - BEGIN_MSG_MAP_EX(CMyElemWindow) + BEGIN_MSG_MAP(CMyElemWindow) MESSAGE_HANDLER(WM_LBUTTONDOWN,OnLButtonDown); MSG_WM_ERASEBKGND(OnEraseBkgnd) MSG_WM_PAINT(OnPaint) diff --git a/foobar2000/foo_sample/ui_element_dialog.cpp b/foobar2000/foo_sample/ui_element_dialog.cpp index 4ee3fbb..dd0abc3 100644 --- a/foobar2000/foo_sample/ui_element_dialog.cpp +++ b/foobar2000/foo_sample/ui_element_dialog.cpp @@ -2,11 +2,6 @@ #include "resource.h" -#include -#include // WIN32_OP() -#include // CCheckBox -#include // ui_element_impl - 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. diff --git a/foobar2000/foobar2000_component_client/foobar2000_component_client.vcxproj b/foobar2000/foobar2000_component_client/foobar2000_component_client.vcxproj index e0e24c3..988b5d6 100644 --- a/foobar2000/foobar2000_component_client/foobar2000_component_client.vcxproj +++ b/foobar2000/foobar2000_component_client/foobar2000_component_client.vcxproj @@ -13,6 +13,7 @@ {71AD2674-065B-48F5-B8B0-E1F9D3892081} foobar2000_component_client + 10.0.14393.0 @@ -20,13 +21,13 @@ false Unicode true - v141 + v141_xp StaticLibrary false Unicode - v141 + v141_xp @@ -48,6 +49,7 @@ Disabled + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) EnableFastChecks @@ -56,6 +58,7 @@ ProgramDatabase MultiThreadedDebugDLL 4715 + NoExtensions _DEBUG;%(PreprocessorDefinitions) @@ -68,6 +71,7 @@ MinSpace + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) true false Fast @@ -76,10 +80,10 @@ true ProgramDatabase MultiThreadedDLL + NoExtensions /d2notypeopt %(AdditionalOptions) 4715 true - NDEBUG;_UNICODE;UNICODE;%(PreprocessorDefinitions) NDEBUG;%(PreprocessorDefinitions) diff --git a/foobar2000/helpers/AutoComplete.cpp b/foobar2000/helpers/AutoComplete.cpp deleted file mode 100644 index 0e404d6..0000000 --- a/foobar2000/helpers/AutoComplete.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "stdafx.h" -#include "AutoComplete.h" -#include // CLSID_AutoComplete -#include "../helpers/COM_utils.h" -#include "../helpers/dropdown_helper.h" -#include - -using PP::CEnumString; - -namespace { - class CACList_History : public CEnumString { - public: - CACList_History(cfg_dropdown_history_mt * var) : m_var(var) { Reset(); } - typedef ImplementCOMRefCounter TImpl; - - HRESULT STDMETHODCALLTYPE Reset() { - /*if (core_api::assert_main_thread())*/ { - ResetStrings(); - pfc::string8 state; m_var->get_state(state); - for (const char * walk = state;;) { - const char * next = strchr(walk, cfg_dropdown_history_mt::separator); - t_size len = (next != NULL) ? next - walk : ~0; - AddStringU(walk, len); - if (next == NULL) break; - walk = next + 1; - } - } - return __super::Reset(); - } - - HRESULT STDMETHODCALLTYPE Clone(IEnumString **ppenum) { - *ppenum = new TImpl(*this); return S_OK; - } - - private: - cfg_dropdown_history_mt * const m_var; - }; -} - -HRESULT InitializeDropdownAC(HWND comboBox, cfg_dropdown_history_mt & var, const char * initVal) { - var.on_init(comboBox, initVal); - COMBOBOXINFO ci = {}; ci.cbSize = sizeof(ci); - if (!GetComboBoxInfo(comboBox, &ci)) { - PFC_ASSERT(!"Should not get here - GetComboBoxInfo fail!"); - return E_FAIL; - } - pfc::com_ptr_t acl = new CACList_History::TImpl(&var); - return InitializeSimpleAC(ci.hwndItem, acl.get_ptr(), ACO_AUTOAPPEND|ACO_AUTOSUGGEST); -} diff --git a/foobar2000/helpers/AutoComplete.h b/foobar2000/helpers/AutoComplete.h deleted file mode 100644 index db7b5cd..0000000 --- a/foobar2000/helpers/AutoComplete.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include - -class cfg_dropdown_history_mt; - -HRESULT InitializeDropdownAC(HWND comboBox, cfg_dropdown_history_mt & var, const char * initVal); diff --git a/foobar2000/helpers/CDialogResizeHelper.h b/foobar2000/helpers/CDialogResizeHelper.h deleted file mode 100644 index 4ce4b5b..0000000 --- a/foobar2000/helpers/CDialogResizeHelper.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include "WindowPositionUtils.h" - -#include - -template class CDialogResizeHelperTracking : public CDialogResizeHelper { -public: - template CDialogResizeHelperTracking(const TParam (& src)[paramCount],CRect const& minMaxRange, TCfgVar & cfgVar) : CDialogResizeHelper(src, minMaxRange), m_tracker(cfgVar) {} - - BEGIN_MSG_MAP_EX(CDialogResizeHelperST) - CHAIN_MSG_MAP(CDialogResizeHelper) - CHAIN_MSG_MAP_MEMBER(m_tracker) - END_MSG_MAP() - -private: - TTracker m_tracker; -}; - -typedef CDialogResizeHelperTracking CDialogResizeHelperST; -typedef CDialogResizeHelperTracking CDialogResizeHelperPT; -typedef CDialogResizeHelperTracking CDialogResizeHelperST2; - -#define REDRAW_DIALOG_ON_RESIZE() if (uMsg == WM_SIZE) RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN); diff --git a/foobar2000/helpers/COM_utils.h b/foobar2000/helpers/COM_utils.h index 7c46ec5..672d422 100644 --- a/foobar2000/helpers/COM_utils.h +++ b/foobar2000/helpers/COM_utils.h @@ -1,6 +1,12 @@ #pragma once +#define FB2K_COM_CATCH catch(exception_com const & e) {return e.get_code();} catch(std::bad_alloc) {return E_OUTOFMEMORY;} catch(pfc::exception_invalid_params) {return E_INVALIDARG;} catch(...) {return E_UNEXPECTED;} -#include +#define COM_QI_BEGIN() HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid,void ** ppvObject) { if (ppvObject == NULL) return E_INVALIDARG; +#define COM_QI_ENTRY(IWhat) { if (iid == __uuidof(IWhat)) {IWhat * temp = this; temp->AddRef(); * ppvObject = temp; return S_OK;} } +#define COM_QI_ENTRY_(IWhat, IID) { if (iid == IID) {IWhat * temp = this; temp->AddRef(); * ppvObject = temp; return S_OK;} } +#define COM_QI_END() * ppvObject = NULL; return E_NOINTERFACE; } -#define FB2K_COM_CATCH PP_COM_CATCH +#define COM_QI_CHAIN(Parent) { HRESULT status = Parent::QueryInterface(iid, ppvObject); if (SUCCEEDED(status)) return status; } + +#define COM_QI_SIMPLE(IWhat) COM_QI_BEGIN() COM_QI_ENTRY(IUnknown) COM_QI_ENTRY(IWhat) COM_QI_END() \ No newline at end of file diff --git a/libPPUI/CPowerRequest.cpp b/foobar2000/helpers/CPowerRequest.cpp similarity index 97% rename from libPPUI/CPowerRequest.cpp rename to foobar2000/helpers/CPowerRequest.cpp index 66016c6..8becb50 100644 --- a/libPPUI/CPowerRequest.cpp +++ b/foobar2000/helpers/CPowerRequest.cpp @@ -39,6 +39,7 @@ HANDLE CPowerRequestAPI::PowerCreateRequestNamed( const wchar_t * str ) { } CPowerRequest::CPowerRequest(const wchar_t * Reason) : m_Request(INVALID_HANDLE_VALUE), m_bSystem(), m_bDisplay() { + HMODULE kernel32 = GetModuleHandle(_T("kernel32.dll")); if (m_API.IsValid()) { winapi_substitute::REASON_CONTEXT ctx = {POWER_REQUEST_CONTEXT_VERSION, POWER_REQUEST_CONTEXT_SIMPLE_STRING}; ctx.Reason.SimpleReasonString = const_cast(Reason); diff --git a/libPPUI/CPowerRequest.h b/foobar2000/helpers/CPowerRequest.h similarity index 100% rename from libPPUI/CPowerRequest.h rename to foobar2000/helpers/CPowerRequest.h diff --git a/foobar2000/helpers/CPropVariant.h b/foobar2000/helpers/CPropVariant.h index 4c5f1fd..c94d97b 100644 --- a/foobar2000/helpers/CPropVariant.h +++ b/foobar2000/helpers/CPropVariant.h @@ -1,3 +1,54 @@ #pragma once -#include \ No newline at end of file +class CPropVariant : public PROPVARIANT { +public: + CPropVariant() {init();} + ~CPropVariant() {clear();} + CPropVariant( const CPropVariant & other ) { + init(); + PropVariantCopy( this, &other ); + } + const CPropVariant& operator=( const CPropVariant & other ) { + clear(); + PropVariantCopy(this, &other); + return *this; + } + + bool toInt64(int64_t & out) const { + switch( vt ) { + case VT_I1: out = (int64_t) cVal; return true; + case VT_I2: out = (int64_t) iVal; return true; + case VT_I4: out = (int64_t) lVal; return true; + case VT_I8: out = (int64_t) hVal.QuadPart; return true; + case VT_INT: out = (int64_t) intVal; return true; + default: return false; + } + } + bool toUint64(uint64_t & out) const { + switch( vt ) { + case VT_UI1: out = (uint64_t) bVal; return true; + case VT_UI2: out = (uint64_t) uiVal; return true; + case VT_UI4: out = (uint64_t) ulVal; return true; + case VT_UI8: out = (uint64_t) uhVal.QuadPart; return true; + case VT_UINT: out = (uint64_t) uintVal; return true; + default: return false; + } + } + bool toString( pfc::string_base & out ) const { + switch( vt ) { + case VT_LPSTR: + out = pfc::stringcvt::string_utf8_from_ansi( pszVal ); return true; + case VT_LPWSTR: + out = pfc::stringcvt::string_utf8_from_wide( pwszVal ); return true; + default: return false; + } + } +private: + void clear() { + PropVariantClear( this ); + } + void init() { + PROPVARIANT * pv = this; + PropVariantInit( pv ); + } +}; diff --git a/foobar2000/helpers/CTableEditHelper-Legacy.cpp b/foobar2000/helpers/CTableEditHelper-Legacy.cpp deleted file mode 100644 index 58726de..0000000 --- a/foobar2000/helpers/CTableEditHelper-Legacy.cpp +++ /dev/null @@ -1,80 +0,0 @@ -#include "stdafx.h" -#include "CTableEditHelper-Legacy.h" -#include - -namespace InPlaceEdit { - void CTableEditHelper::TableEdit_Start(HWND p_listview, unsigned p_item, unsigned p_column, unsigned p_itemcount, unsigned p_columncount, unsigned p_basecolumn, unsigned p_flags) { - if (m_notify.is_valid() || p_columncount == 0 || p_itemcount == 0 || p_item >= p_itemcount || p_column >= p_columncount) return; - m_listview = p_listview; - m_item = p_item; - m_column = p_column; - m_itemcount = p_itemcount; - m_columncount = p_columncount; - m_basecolumn = p_basecolumn; - m_flags = p_flags; - _Start(); - } - - void CTableEditHelper::TableEdit_Abort(bool p_forwardcontent) { - if (m_notify.is_valid()) { - m_notify->orphan(); - m_notify.release(); - - if (p_forwardcontent && (m_flags & KFlagReadOnly) == 0) { - if (m_content.is_valid()) { - pfc::string8 temp(*m_content); - m_content.release(); - TableEdit_SetItemText(m_item, m_column, temp); - } - } else { - m_content.release(); - } - SetFocus(NULL); - TableEdit_Finished(); - } - } - - bool CTableEditHelper::TableEdit_GetItemText(unsigned p_item, unsigned p_column, pfc::string_base & p_out, unsigned & p_linecount) { - listview_helper::get_item_text(m_listview, p_item, p_column + m_basecolumn, p_out); - p_linecount = pfc::is_multiline(p_out) ? 5 : 1; - return true; - } - void CTableEditHelper::TableEdit_SetItemText(unsigned p_item, unsigned p_column, const char * p_text) { - listview_helper::set_item_text(m_listview, p_item, p_column + m_basecolumn, p_text); - } - - void CTableEditHelper::on_task_completion(unsigned p_taskid, unsigned p_state) { - if (p_taskid == KTaskID) { - m_notify.release(); - if (m_content.is_valid()) { - if (p_state & InPlaceEdit::KEditFlagContentChanged) { - TableEdit_SetItemText(m_item, m_column, *m_content); - } - m_content.release(); - } - /*if (InPlaceEdit::TableEditAdvance(m_item,m_column,m_itemcount,m_columncount,p_state))*/ - if (TableEdit_OnEditCompleted(m_item, m_column, p_state) && - InPlaceEdit::TableEditAdvance_ListView(m_listview, m_basecolumn, m_item, m_column, m_itemcount, m_columncount, p_state)) { - _Start(); - } else { - TableEdit_Finished(); - } - } - } - - CTableEditHelper::~CTableEditHelper() { - if (m_notify.is_valid()) { - m_notify->orphan(); - m_notify.release(); - } - } - - void CTableEditHelper::_Start() { - listview_helper::select_single_item(m_listview, m_item); - m_content.new_t(); - unsigned linecount = 1; - if (!TableEdit_GetItemText(m_item, m_column, *m_content, linecount)) return; - m_notify = completion_notify_create(this, KTaskID); - InPlaceEdit::Start_FromListViewEx(m_listview, m_item, m_column + m_basecolumn, linecount, m_flags, m_content, m_notify); - } -} \ No newline at end of file diff --git a/foobar2000/helpers/CTableEditHelper-Legacy.h b/foobar2000/helpers/CTableEditHelper-Legacy.h deleted file mode 100644 index f4dce69..0000000 --- a/foobar2000/helpers/CTableEditHelper-Legacy.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once -#include "inplace_edit.h" -#include - -namespace InPlaceEdit { - class CTableEditHelper { - public: - void TableEdit_Start(HWND p_listview, unsigned p_item, unsigned p_column, unsigned p_itemcount, unsigned p_columncount, unsigned p_basecolumn, unsigned p_flags = 0); - void TableEdit_Abort(bool p_forwardcontent); - bool TableEdit_IsActive() const {return m_notify.is_valid();} - - virtual bool TableEdit_GetItemText(unsigned p_item, unsigned p_column, pfc::string_base & p_out, unsigned & p_linecount); - virtual void TableEdit_SetItemText(unsigned p_item, unsigned p_column, const char * p_text); - - virtual void TableEdit_Finished() {} - - void on_task_completion(unsigned p_taskid, unsigned p_state); - ~CTableEditHelper(); - protected: - HWND TableEdit_GetListView() const { return m_listview; } - //return false to abort - virtual bool TableEdit_OnEditCompleted(unsigned item, unsigned column, unsigned state) { return true; } - private: - void _Start(); - enum { - KTaskID = 0xc0ffee - }; - HWND m_listview; - unsigned m_item, m_column; - unsigned m_itemcount, m_columncount, m_basecolumn; - unsigned m_flags; - pfc::rcptr_t m_content; - service_ptr_t m_notify; - }; -} \ No newline at end of file diff --git a/foobar2000/helpers/CallForwarder.h b/foobar2000/helpers/CallForwarder.h index 7c261ad..3477d73 100644 --- a/foobar2000/helpers/CallForwarder.h +++ b/foobar2000/helpers/CallForwarder.h @@ -14,18 +14,11 @@ namespace CF { }; template class CallForwarder { - private: - CallForwarder() = delete; - protected: - CallForwarder(TWhat * ptr) : m_ptr(pfc::rcnew_t(ptr)) {} - void Orphan() { - *m_ptr = NULL; - } public: - bool IsValid() const { - PFC_ASSERT( m_ptr.is_valid() ); - return m_ptr.is_valid() && *m_ptr != NULL; - } + CallForwarder(TWhat * ptr) { m_ptr.new_t(ptr); } + + void Orphan() {*m_ptr = NULL;} + bool IsValid() const { return *m_ptr != NULL; } bool IsEmpty() const { return !IsValid(); } TWhat * operator->() const { @@ -43,18 +36,15 @@ namespace CF { main_thread_callback_add( new service_impl_t<_inMainThread< CallForwarder, arg_t> >(*this, arg) ); } private: - const pfc::rcptr_t m_ptr; + pfc::rcptr_t m_ptr; }; template class CallForwarderMaster : public CallForwarder { public: - CallForwarderMaster(TWhat * ptr) : CallForwarder(ptr) {PFC_ASSERT(ptr!=NULL);} + CallForwarderMaster(TWhat * ptr) : CallForwarder(ptr) {} ~CallForwarderMaster() { this->Orphan(); } - using CallForwarder::Orphan; - private: - CallForwarderMaster() = delete; - CallForwarderMaster( const CallForwarderMaster & ) = delete; - void operator=( const CallForwarderMaster & ) = delete; + + PFC_CLASS_NOT_COPYABLE(CallForwarderMaster, CallForwarderMaster); }; } \ No newline at end of file diff --git a/foobar2000/helpers/CmdThread.h b/foobar2000/helpers/CmdThread.h index be15ab5..b91d115 100644 --- a/foobar2000/helpers/CmdThread.h +++ b/foobar2000/helpers/CmdThread.h @@ -1,10 +1,8 @@ #pragma once #include #include -#include #include #include "rethrow.h" -#include namespace ThreadUtils { @@ -15,95 +13,46 @@ namespace ThreadUtils { typedef std::function func_t; typedef pfc::waitQueue queue_t; typedef std::function funcAbortable_t; - - protected: - std::function makeWorker() { - auto q = m_queue; - auto x = m_atExit; - return [q, x] { - for ( ;; ) { - func_t f; - if (!q->get(f)) break; - try { f(); } catch(...) {} - } - // No guard for atExit access, as nobody is supposed to be still able to call host object methods by the time we get here - for( auto i = x->begin(); i != x->end(); ++ i ) { - auto f = *i; - try { f(); } catch(...) {} - } - }; - }; - std::function makeWorker2( std::function updater, double interval) { - auto q = m_queue; - auto x = m_atExit; - return [=] { - pfc::lores_timer t; t.start(); - for ( ;; ) { - { - bool bWorkReady = false; - double left = interval - t.query(); - if ( left > 0 ) { - if (q->wait_read( left )) bWorkReady = true; - } - - if (!bWorkReady) { - updater(); - t.start(); - continue; - } - } - - func_t f; - if (!q->get(f)) break; - try { f(); } catch(...) {} - } - // No guard for atExit access, as nobody is supposed to be still able to call host object methods by the time we get here - for( auto i = x->begin(); i != x->end(); ++ i ) { - auto f = *i; - try { f(); } catch(...) {} - } - }; - }; - - // For derived classes: create new instance without starting thread, supply thread using by yourself - class noCreate {}; - cmdThread( noCreate ) {} - public: - cmdThread() { - pfc::splitThread( makeWorker() ); + auto q = std::make_shared(); + m_queue = q; + auto x = std::make_shared(); + m_atExit = x; + pfc::splitThread( [q, x] { + for ( ;; ) { + func_t f; + if (!q->get(f)) break; + try { f(); } catch(...) {} + } + // No guard for atExit access, as nobody is supposed to be still able to call host object methods by the time we get here + for( auto i = x->begin(); i != x->end(); ++ i ) { + auto f = *i; + try { f(); } catch(...) {} + } + } ); } - void atExit( func_t f ) { m_atExit->push_back(f); } ~cmdThread() { m_queue->set_eof(); } - void runSynchronously( func_t f ) { runSynchronously_(f, nullptr); } - void runSynchronously_( func_t f, abort_callback * abortOrNull ) { - auto evt = m_eventPool.make(); - evt->set_state(false); - auto rethrow = std::make_shared(); - auto worker2 = [f, rethrow, evt] { - rethrow->exec(f); - evt->set_state( true ); - }; - - add ( worker2 ); - - if ( abortOrNull != nullptr ) { - abortOrNull->waitForEvent( * evt, -1 ); - } else { - evt->wait_for(-1); - } - - m_eventPool.put( evt ); - - rethrow->rethrow(); - } void runSynchronously( func_t f, abort_callback & abort ) { - runSynchronously_(f, &abort); + auto evt = m_eventPool.make(); + evt->set_state(false); + auto rethrow = std::make_shared(); + auto worker2 = [f, rethrow, evt] { + rethrow->exec(f); + evt->set_state( true ); + }; + + add ( worker2 ); + + abort.waitForEvent( * evt, -1 ); + + m_eventPool.put( evt ); + + rethrow->rethrow(); } void runSynchronously2( funcAbortable_t f, abort_callback & abort ) { auto subAbort = m_abortPool.make(); @@ -125,8 +74,8 @@ namespace ThreadUtils { private: pfc::objPool m_eventPool; pfc::objPool m_abortPool; - std::shared_ptr m_queue = std::make_shared(); + std::shared_ptr m_queue; typedef std::list atExit_t; - std::shared_ptr m_atExit = std::make_shared< atExit_t >(); + std::shared_ptr m_atExit; }; -} +} \ No newline at end of file diff --git a/libPPUI/IDataObjectUtils.cpp b/foobar2000/helpers/IDataObjectUtils.cpp similarity index 98% rename from libPPUI/IDataObjectUtils.cpp rename to foobar2000/helpers/IDataObjectUtils.cpp index be85121..7d15c75 100644 --- a/libPPUI/IDataObjectUtils.cpp +++ b/foobar2000/helpers/IDataObjectUtils.cpp @@ -1,5 +1,7 @@ #include "stdafx.h" +#ifdef FOOBAR2000_DESKTOP_WINDOWS + #include "IDataObjectUtils.h" HRESULT IDataObjectUtils::DataBlockToSTGMEDIUM(const void * blockPtr, t_size blockSize, STGMEDIUM * medium, DWORD tymed, bool bHere) throw() { @@ -185,3 +187,5 @@ HRESULT IDataObjectUtils::SetDataObjectDWORD(pfc::com_ptr_t obj, UI HRESULT IDataObjectUtils::PasteSucceeded(pfc::com_ptr_t obj, DWORD effect) { return SetDataObjectDWORD(obj, RegisterClipboardFormat(CFSTR_PASTESUCCEEDED), effect); } + +#endif // FOOBAR2000_DESKTOP_WINDOWS diff --git a/libPPUI/IDataObjectUtils.h b/foobar2000/helpers/IDataObjectUtils.h similarity index 73% rename from libPPUI/IDataObjectUtils.h rename to foobar2000/helpers/IDataObjectUtils.h index 4a7bf6a..175323d 100644 --- a/libPPUI/IDataObjectUtils.h +++ b/foobar2000/helpers/IDataObjectUtils.h @@ -1,8 +1,8 @@ #pragma once +#ifdef FOOBAR2000_DESKTOP_WINDOWS #include -#include // IAsyncOperation -#include "pp-COM-macros.h" +#include "../helpers/COM_utils.h" namespace IDataObjectUtils { @@ -56,26 +56,26 @@ namespace IDataObjectUtils { public: COM_QI_SIMPLE(IDataObject) - HRESULT STDMETHODCALLTYPE GetData(FORMATETC * formatetc, STGMEDIUM * medium) override { + HRESULT STDMETHODCALLTYPE GetData(FORMATETC * formatetc, STGMEDIUM * medium) { return GetData_internal(formatetc,medium,false); } - HRESULT STDMETHODCALLTYPE GetDataHere(FORMATETC * formatetc, STGMEDIUM * medium) override { + HRESULT STDMETHODCALLTYPE GetDataHere(FORMATETC * formatetc, STGMEDIUM * medium) { return GetData_internal(formatetc,medium,true); } - HRESULT STDMETHODCALLTYPE QueryGetData(FORMATETC * formatetc) override { + HRESULT STDMETHODCALLTYPE QueryGetData(FORMATETC * formatetc) { if (formatetc == NULL) return E_INVALIDARG; if ((DataBlockToSTGMEDIUM_SupportedTymeds & formatetc->tymed) == 0) return DV_E_TYMED; try { return RenderDataTest(formatetc->cfFormat,formatetc->dwAspect,formatetc->lindex); - } PP_COM_CATCH; + } FB2K_COM_CATCH; } - HRESULT STDMETHODCALLTYPE GetCanonicalFormatEtc(FORMATETC * in, FORMATETC * out) override { + HRESULT STDMETHODCALLTYPE GetCanonicalFormatEtc(FORMATETC * in, FORMATETC * out) { //check this again if (in == NULL || out == NULL) return E_INVALIDARG; @@ -83,7 +83,7 @@ namespace IDataObjectUtils { return DATA_S_SAMEFORMATETC; } - HRESULT STDMETHODCALLTYPE EnumFormatEtc(DWORD dwDirection,IEnumFORMATETC ** ppenumFormatetc) override { + HRESULT STDMETHODCALLTYPE EnumFormatEtc(DWORD dwDirection,IEnumFORMATETC ** ppenumFormatetc) { if (dwDirection == DATADIR_GET) { if (ppenumFormatetc == NULL) return E_INVALIDARG; return CreateIEnumFORMATETC(ppenumFormatetc); @@ -94,7 +94,7 @@ namespace IDataObjectUtils { } } - HRESULT STDMETHODCALLTYPE SetData(FORMATETC * pFormatetc, STGMEDIUM * pmedium, BOOL fRelease) override { + HRESULT STDMETHODCALLTYPE SetData(FORMATETC * pFormatetc, STGMEDIUM * pmedium, BOOL fRelease) { try { ReleaseStgMediumScope relScope(fRelease ? pmedium : NULL); if (pFormatetc == NULL || pmedium == NULL) return E_INVALIDARG; @@ -112,24 +112,23 @@ namespace IDataObjectUtils { if (FAILED(state)) return state; m_entries.set(*pFormatetc,temp); return S_OK; - } PP_COM_CATCH; + } FB2K_COM_CATCH; } - HRESULT STDMETHODCALLTYPE DAdvise(FORMATETC * pFormatetc, DWORD advf, IAdviseSink * pAdvSink, DWORD * pdwConnection) override {return OLE_E_ADVISENOTSUPPORTED;} - HRESULT STDMETHODCALLTYPE DUnadvise(DWORD dwConnection) override {return OLE_E_ADVISENOTSUPPORTED;} - HRESULT STDMETHODCALLTYPE EnumDAdvise(IEnumSTATDATA ** ppenumAdvise) override {return OLE_E_ADVISENOTSUPPORTED;} + HRESULT STDMETHODCALLTYPE DAdvise(FORMATETC * pFormatetc, DWORD advf, IAdviseSink * pAdvSink, DWORD * pdwConnection) {return OLE_E_ADVISENOTSUPPORTED;} + HRESULT STDMETHODCALLTYPE DUnadvise(DWORD dwConnection) {return OLE_E_ADVISENOTSUPPORTED;} + HRESULT STDMETHODCALLTYPE EnumDAdvise(IEnumSTATDATA ** ppenumAdvise) {return OLE_E_ADVISENOTSUPPORTED;} protected: - typedef pfc::array_t data_t; - virtual HRESULT RenderData(UINT format,DWORD aspect,LONG dataIndex, data_t & out) const { + virtual HRESULT RenderData(UINT format,DWORD aspect,LONG dataIndex,stream_writer_formatter<> & out) const { FORMATETC fmt = {}; fmt.cfFormat = format; fmt.dwAspect = aspect; fmt.lindex = dataIndex; const pfc::array_t * entry = m_entries.query_ptr(fmt); if (entry != NULL) { - out = * entry; + out.write_raw(entry->get_ptr(), entry->get_size()); return S_OK; } return DV_E_FORMATETC; } - virtual HRESULT RenderDataTest(UINT format,DWORD aspect,LONG dataIndex) const { + virtual HRESULT RenderDataTest(UINT format,DWORD aspect, LONG dataIndex) const { FORMATETC fmt = {}; fmt.cfFormat = format; fmt.dwAspect = aspect; fmt.lindex = dataIndex; if (m_entries.have_item(fmt)) return S_OK; @@ -165,64 +164,23 @@ namespace IDataObjectUtils { pfc::list_t out; EnumFormats(out); return SHCreateStdEnumFmtEtc((UINT)out.get_count(), out.get_ptr(), outptr); - } PP_COM_CATCH; + } FB2K_COM_CATCH; } private: HRESULT GetData_internal(FORMATETC * formatetc, STGMEDIUM * medium,bool bHere) { if (formatetc == NULL || medium == NULL) return E_INVALIDARG; try { - data_t out; + stream_writer_formatter_simple<> out; HRESULT hr = RenderData(formatetc->cfFormat,formatetc->dwAspect,formatetc->lindex,out); if (FAILED(hr)) return hr; - return DataBlockToSTGMEDIUM(out.get_ptr(),out.get_size(),medium,formatetc->tymed,bHere); - } PP_COM_CATCH; + return DataBlockToSTGMEDIUM(out.m_buffer.get_ptr(),out.m_buffer.get_size(),medium,formatetc->tymed,bHere); + } FB2K_COM_CATCH; } typedef pfc::map_t, comparator_FORMATETC> t_entries; t_entries m_entries; }; - -#ifdef __IDataObjectAsyncCapability_INTERFACE_DEFINED__ - typedef IDataObjectAsyncCapability IDataObjectAsyncCapability_t; -#else - typedef IAsyncOperation IDataObjectAsyncCapability_t; -#endif - - class CAsyncDataObjectBase : public CDataObjectBase, public IDataObjectAsyncCapability_t { - BOOL m_inOperation = FALSE; - BOOL m_asyncMode = TRUE; - protected: - COM_QI_BEGIN() - COM_QI_CHAIN(CDataObjectBase) - COM_QI_ENTRY(IDataObjectAsyncCapability_t) - COM_QI_END() - public: - HRESULT STDMETHODCALLTYPE SetAsyncMode(BOOL fDoOpAsync) override { - m_asyncMode = fDoOpAsync; - return S_OK; - } - - HRESULT STDMETHODCALLTYPE GetAsyncMode(BOOL *pfIsOpAsync) override { - if ( pfIsOpAsync == nullptr ) return E_INVALIDARG; - *pfIsOpAsync = m_asyncMode; - return S_OK; - } - - HRESULT STDMETHODCALLTYPE StartOperation(IBindCtx *pbcReserved) override { - m_inOperation = TRUE; - return S_OK; - } - - HRESULT STDMETHODCALLTYPE InOperation(BOOL *pfInAsyncOp) override { - if ( pfInAsyncOp == nullptr ) return E_INVALIDARG; - *pfInAsyncOp = m_inOperation; - return S_OK; - } - - HRESULT STDMETHODCALLTYPE EndOperation(HRESULT hResult,IBindCtx *pbcReserved,DWORD dwEffects) override { - m_inOperation = FALSE; - return S_OK; - } - }; } + +#endif // FOOBAR2000_DESKTOP_WINDOWS diff --git a/foobar2000/helpers/ProcessUtils.h b/foobar2000/helpers/ProcessUtils.h index bfd70c4..b921769 100644 --- a/foobar2000/helpers/ProcessUtils.h +++ b/foobar2000/helpers/ProcessUtils.h @@ -2,8 +2,6 @@ #ifdef FOOBAR2000_DESKTOP_WINDOWS -#include - namespace ProcessUtils { class PipeIO : public stream_reader, public stream_writer { public: @@ -162,7 +160,7 @@ namespace ProcessUtils { try { WIN32_OP( CreateProcess(pfc::stringcvt::string_os_from_utf8(ExePath), NULL, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi) ); } catch(std::exception const & e) { - throw failure(PFC_string_formatter() << "Could not start the worker process - " << e); + throw failure(pfc::string_formatter() << "Could not start the worker process - " << e); } hProcess = pi.hProcess; _Close(pi.hThread); } catch(...) { @@ -230,7 +228,7 @@ namespace ProcessUtils { static pfc::string_formatter makePipeName() { GUID id; CoCreateGuid (&id); - return PFC_string_formatter() << "\\\\.\\pipe\\" << pfc::print_guid(id); + return pfc::string_formatter() << "\\\\.\\pipe\\" << pfc::print_guid(id); } static void myCreatePipeOut(HANDLE & in, HANDLE & out) { diff --git a/libPPUI/SmartStrStr.cpp b/foobar2000/helpers/SmartStrStr.cpp similarity index 96% rename from libPPUI/SmartStrStr.cpp rename to foobar2000/helpers/SmartStrStr.cpp index 850c5ef..3d233b7 100644 --- a/libPPUI/SmartStrStr.cpp +++ b/foobar2000/helpers/SmartStrStr.cpp @@ -63,12 +63,6 @@ const wchar_t * SmartStrStr::matchHereW(const wchar_t * pString, const wchar_t * } } -bool SmartStrStr::equals(const char * pString, const char * pUserString) const { - auto p = matchHere(pString, pUserString); - if ( p == nullptr ) return false; - return *p == 0; -} - const char * SmartStrStr::matchHere(const char * pString, const char * pUserString) const { const char * walkData = pString; const char * walkUser = pUserString; @@ -164,7 +158,7 @@ uint32_t SmartStrStr::Transform(uint32_t c) { } uint32_t SmartStrStr::ToLower(uint32_t c) { - return pfc::charLower(c); + return (uint32_t)uCharLower(c); } void SmartStrStr::ImportTwoCharMappings(const wchar_t * list, const char * replacement) { diff --git a/libPPUI/SmartStrStr.h b/foobar2000/helpers/SmartStrStr.h similarity index 92% rename from libPPUI/SmartStrStr.h rename to foobar2000/helpers/SmartStrStr.h index 6c41325..38654fe 100644 --- a/libPPUI/SmartStrStr.h +++ b/foobar2000/helpers/SmartStrStr.h @@ -24,9 +24,6 @@ public: const char * matchHere(const char * pString, const char * pUserString) const; const wchar_t * matchHereW( const wchar_t * pString, const wchar_t * pUserString) const; - //! String-equals tool, compares strings rather than searching for occurance - bool equals( const char * pString, const char * pUserString) const; - //! One-char match. Doesn't use twoCharMappings, use only if you have to operate on char by char basis rather than call the other methods. bool matchOneChar(uint32_t cInput, uint32_t cData) const; private: diff --git a/foobar2000/helpers/StdAfx.h b/foobar2000/helpers/StdAfx.h index 0d7e085..9efd168 100644 --- a/foobar2000/helpers/StdAfx.h +++ b/foobar2000/helpers/StdAfx.h @@ -10,7 +10,7 @@ #pragma once #endif // _MSC_VER > 1000 -#include "foobar2000+atl.h" +#include "../SDK/foobar2000.h" // TODO: reference additional headers your program requires here diff --git a/foobar2000/helpers/ThreadUtils.cpp b/foobar2000/helpers/ThreadUtils.cpp index 28651b0..e4a9d3a 100644 --- a/foobar2000/helpers/ThreadUtils.cpp +++ b/foobar2000/helpers/ThreadUtils.cpp @@ -68,68 +68,104 @@ namespace ThreadUtils { } } void WaitAbortable_MsgLoop(HANDLE ev, abort_callback & abort) { - abort.check(); const HANDLE handles[2] = {ev, abort.get_abort_event()}; - MultiWait_MsgLoop(handles, 2); - abort.check(); + for(;;) { + SetLastError(0); + const DWORD status = MsgWaitForMultipleObjects(2, handles, FALSE, INFINITE, QS_ALLINPUT); + switch(status) { + case WAIT_TIMEOUT: + PFC_ASSERT(!"How did we get here?"); + uBugCheck(); + case WAIT_OBJECT_0: + return; + case WAIT_OBJECT_0 + 1: + throw exception_aborted(); + case WAIT_OBJECT_0 + 2: + ProcessPendingMessages(); + break; + case WAIT_FAILED: + WIN32_OP_FAIL(); + default: + uBugCheck(); + } + } } t_size MultiWaitAbortable_MsgLoop(const HANDLE * ev, t_size evCount, abort_callback & abort) { - abort.check(); pfc::array_t handles; handles.set_size(evCount + 1); handles[0] = abort.get_abort_event(); pfc::memcpy_t(handles.get_ptr() + 1, ev, evCount); - DWORD status = MultiWait_MsgLoop(handles.get_ptr(), handles.get_count()); - abort.check(); - return (size_t)(status - WAIT_OBJECT_0); - } - - void SleepAbortable_MsgLoop(abort_callback & abort, DWORD timeout) { - HANDLE handles[] = { abort.get_abort_event() }; - MultiWait_MsgLoop(handles, 1, timeout); - abort.check(); - } - - bool WaitAbortable_MsgLoop(HANDLE ev, abort_callback & abort, DWORD timeout) { - abort.check(); - HANDLE handles[2] = { abort.get_abort_event(), ev }; - DWORD status = MultiWait_MsgLoop(handles, 2, timeout); - abort.check(); - return status != WAIT_TIMEOUT; - } - - DWORD MultiWait_MsgLoop(const HANDLE* ev, DWORD evCount) { - for (;; ) { + for(;;) { SetLastError(0); - const DWORD status = MsgWaitForMultipleObjects((DWORD) evCount, ev, FALSE, INFINITE, QS_ALLINPUT); - if (status == WAIT_FAILED) WIN32_OP_FAIL(); - if (status == WAIT_OBJECT_0 + evCount) { - ProcessPendingMessages(); - } else if ( status >= WAIT_OBJECT_0 && status < WAIT_OBJECT_0 + evCount ) { - return status; - } else { - uBugCheck(); + const DWORD status = MsgWaitForMultipleObjects(handles.get_count(), handles.get_ptr(), FALSE, INFINITE, QS_ALLINPUT); + switch(status) { + case WAIT_TIMEOUT: + PFC_ASSERT(!"How did we get here?"); + uBugCheck(); + case WAIT_OBJECT_0: + throw exception_aborted(); + case WAIT_FAILED: + WIN32_OP_FAIL(); + default: + { + t_size index = (t_size)(status - (WAIT_OBJECT_0 + 1)); + if (index == evCount) { + ProcessPendingMessages(); + } else if (index < evCount) { + return index; + } else { + uBugCheck(); + } + } } } } - DWORD MultiWait_MsgLoop(const HANDLE* ev, DWORD evCount, DWORD timeout) { - if (timeout == INFINITE) return MultiWait_MsgLoop(ev, evCount); + void SleepAbortable_MsgLoop(abort_callback & abort, DWORD timeout /*must not be INFINITE*/) { + PFC_ASSERT( timeout != INFINITE ); const DWORD entry = GetTickCount(); - DWORD now = entry; - for (;;) { - const DWORD done = now - entry; - if (done >= timeout) return WAIT_TIMEOUT; + const HANDLE handles[1] = {abort.get_abort_event()}; + for(;;) { + const DWORD done = GetTickCount() - entry; + if (done >= timeout) return; SetLastError(0); - const DWORD status = MsgWaitForMultipleObjects((DWORD)evCount, ev, FALSE, timeout - done, QS_ALLINPUT); - if (status == WAIT_FAILED) WIN32_OP_FAIL(); - if (status == WAIT_OBJECT_0 + evCount) { - ProcessPendingMessages(); - } else if (status == WAIT_TIMEOUT || (status >= WAIT_OBJECT_0 && status < WAIT_OBJECT_0 + evCount) ) { - return status; - } else { - uBugCheck(); + const DWORD status = MsgWaitForMultipleObjects(1, handles, FALSE, timeout - done, QS_ALLINPUT); + switch(status) { + case WAIT_TIMEOUT: + return; + case WAIT_OBJECT_0: + throw exception_aborted(); + case WAIT_OBJECT_0 + 1: + ProcessPendingMessages(); + default: + throw exception_win32(GetLastError()); + } + } + } + + bool WaitAbortable_MsgLoop(HANDLE ev, abort_callback & abort, DWORD timeout /*must not be INFINITE*/) { + PFC_ASSERT( timeout != INFINITE ); + const DWORD entry = GetTickCount(); + const HANDLE handles[2] = {ev, abort.get_abort_event()}; + for(;;) { + const DWORD done = GetTickCount() - entry; + if (done >= timeout) return false; + SetLastError(0); + const DWORD status = MsgWaitForMultipleObjects(2, handles, FALSE, timeout - done, QS_ALLINPUT); + switch(status) { + case WAIT_TIMEOUT: + return false; + case WAIT_OBJECT_0: + return true; + case WAIT_OBJECT_0 + 1: + throw exception_aborted(); + case WAIT_OBJECT_0 + 2: + ProcessPendingMessages(); + break; + case WAIT_FAILED: + WIN32_OP_FAIL(); + default: + uBugCheck(); } - now = GetTickCount(); } } diff --git a/foobar2000/helpers/ThreadUtils.h b/foobar2000/helpers/ThreadUtils.h index 70afe36..122fd09 100644 --- a/foobar2000/helpers/ThreadUtils.h +++ b/foobar2000/helpers/ThreadUtils.h @@ -16,9 +16,6 @@ namespace ThreadUtils { void SleepAbortable_MsgLoop(abort_callback & abort, DWORD timeout /*must not be INFINITE*/); bool WaitAbortable_MsgLoop(HANDLE ev, abort_callback & abort, DWORD timeout /*must not be INFINITE*/); - DWORD MultiWait_MsgLoop(const HANDLE* ev, DWORD evCount, DWORD timeout); - DWORD MultiWait_MsgLoop(const HANDLE* ev, DWORD evCount); - template class CObjectQueue { public: diff --git a/libPPUI/TypeFind.h b/foobar2000/helpers/TypeFind.h similarity index 100% rename from libPPUI/TypeFind.h rename to foobar2000/helpers/TypeFind.h diff --git a/foobar2000/helpers/VolumeMap.cpp b/foobar2000/helpers/VolumeMap.cpp deleted file mode 100644 index ba68e8d..0000000 --- a/foobar2000/helpers/VolumeMap.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "stdafx.h" -#include "VolumeMap.h" - -static const double powval = 2.0; -static const double silence = -100.0; - -double VolumeMap::SliderToDB2(double slider) { - double v = SliderToDB(slider); - v = floor(v * 2.0 + 0.5) * 0.5; - return v; -} - -double VolumeMap::SliderToDB(double slider) { - if (slider > 0) { - return pfc::max_t(silence,10.0 * log(slider) / log(powval)); - } else { - return silence; - } -} -double VolumeMap::DBToSlider(double volumeDB) { - return pfc::clip_t(pow(powval,volumeDB / 10.0), 0, 1); -} diff --git a/foobar2000/helpers/VolumeMap.h b/foobar2000/helpers/VolumeMap.h deleted file mode 100644 index 6b9b1d6..0000000 --- a/foobar2000/helpers/VolumeMap.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -namespace VolumeMap { - double SliderToDB(double slider /*0..1 range*/); - double SliderToDB2(double slider); // rounds to 0.5dB - double DBToSlider(double volumeDB); -} diff --git a/foobar2000/helpers/advconfig_impl.h b/foobar2000/helpers/advconfig_impl.h deleted file mode 100644 index 0d420c0..0000000 --- a/foobar2000/helpers/advconfig_impl.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -// fb2k mobile compat \ No newline at end of file diff --git a/foobar2000/helpers/bitreader_helper.h b/foobar2000/helpers/bitreader_helper.h index 7e12d98..bfb117a 100644 --- a/foobar2000/helpers/bitreader_helper.h +++ b/foobar2000/helpers/bitreader_helper.h @@ -2,11 +2,11 @@ namespace bitreader_helper { - inline static size_t extract_bit(const uint8_t * p_stream,size_t p_offset) { + inline static size_t extract_bit(const t_uint8 * p_stream,size_t p_offset) { return (p_stream[p_offset>>3] >> (7-(p_offset&7)))&1; } - inline static size_t extract_int(const uint8_t * p_stream,size_t p_base,size_t p_width) { + inline static size_t extract_int(const t_uint8 * p_stream,size_t p_base,size_t p_width) { size_t ret = 0; size_t offset = p_base; for(size_t bit=0;bit>3]; - b = (b & ~mask) | ((bit&1) << bshift); - } - inline static void write_int( uint8_t * p_stream, size_t p_base, size_t p_width, size_t p_value) { - size_t offset = p_base; - size_t val = p_value; - for( size_t bit = 0; bit < p_width; ++ bit ) { - write_bit( p_stream, offset++, val >> (p_width - bit - 1)); - } - } class bitreader { @@ -42,31 +29,18 @@ public: m_bitptr += p_bits; } - template - t_ret peek_t(t_size p_bits) const { - size_t ptr = m_bitptr; + t_ret read_t(t_size p_bits) { t_ret ret = 0; for(t_size bit=0;bit>3] >> (7-(ptr &7)))&1; - ptr++; + ret |= (m_ptr[m_bitptr>>3] >> (7-(m_bitptr&7)))&1; + m_bitptr++; } return ret; } - template - t_ret read_t(t_size p_bits) { - t_ret ret = peek_t(p_bits); - skip(p_bits); - return ret; - } - - size_t peek(size_t bits) const { - return peek_t(bits); - } - t_size read(t_size p_bits) {return read_t(p_bits);} inline t_size get_bitptr() const {return m_bitptr;} @@ -131,10 +105,6 @@ public: m_reader.skip(p_bits); } - size_t peek(size_t bits) { - if (bits > m_remaining) throw exception_io_data_truncation(); - return m_reader.peek(bits); - } t_size read(t_size p_bits) { if (p_bits > m_remaining) throw exception_io_data_truncation(); @@ -151,4 +121,4 @@ inline static t_size extract_bits(const t_uint8 * p_buffer,t_size p_base,t_size return bitreader(p_buffer,p_base).read(p_count); } -} +} \ No newline at end of file diff --git a/foobar2000/helpers/cfg_guidlist.h b/foobar2000/helpers/cfg_guidlist.h index 9cdff2d..3ddc66f 100644 --- a/foobar2000/helpers/cfg_guidlist.h +++ b/foobar2000/helpers/cfg_guidlist.h @@ -3,12 +3,12 @@ class cfg_guidlist : public cfg_var, public pfc::list_t { public: - void get_data_raw(stream_writer * p_stream,abort_callback & p_abort) override { + void get_data_raw(stream_writer * p_stream,abort_callback & p_abort) { t_uint32 n, m = pfc::downcast_guarded(get_count()); p_stream->write_lendian_t(m,p_abort); for(n=0;nwrite_lendian_t(get_item(n),p_abort); } - void set_data_raw(stream_reader * p_stream,t_size p_sizehint,abort_callback & p_abort) override { + void set_data_raw(stream_reader * p_stream,t_size p_sizehint,abort_callback & p_abort) { t_uint32 n,count; p_stream->read_lendian_t(count,p_abort); m_buffer.set_size(count); diff --git a/libPPUI/clipboard.cpp b/foobar2000/helpers/clipboard.cpp similarity index 82% rename from libPPUI/clipboard.cpp rename to foobar2000/helpers/clipboard.cpp index 52cda9a..3616b34 100644 --- a/libPPUI/clipboard.cpp +++ b/foobar2000/helpers/clipboard.cpp @@ -1,7 +1,7 @@ #include "stdafx.h" +#ifdef FOOBAR2000_DESKTOP_WINDOWS #include "clipboard.h" -#include "win32_op.h" #ifdef UNICODE #define CF_TCHAR CF_UNICODETEXT @@ -10,17 +10,6 @@ #endif namespace ClipboardHelper { - void OpenScope::Open(HWND p_owner) { - Close(); - WIN32_OP(OpenClipboard(p_owner)); - m_open = true; - } - void OpenScope::Close() { - if (m_open) { - m_open = false; - CloseClipboard(); - } - } void SetRaw(UINT format,const void * data, t_size size) { HANDLE buffer = GlobalAlloc(GMEM_DDESHARE,size); if (buffer == NULL) throw std::bad_alloc(); @@ -49,3 +38,5 @@ namespace ClipboardHelper { return IsClipboardFormatAvailable(CF_TCHAR) == TRUE; } } + +#endif // FOOBAR2000_DESKTOP_WINDOWS diff --git a/libPPUI/clipboard.h b/foobar2000/helpers/clipboard.h similarity index 71% rename from libPPUI/clipboard.h rename to foobar2000/helpers/clipboard.h index 05b6479..3c215a8 100644 --- a/libPPUI/clipboard.h +++ b/foobar2000/helpers/clipboard.h @@ -1,13 +1,26 @@ #pragma once +#ifdef FOOBAR2000_DESKTOP_WINDOWS + +#include "win32_misc.h" + namespace ClipboardHelper { class OpenScope { public: OpenScope() : m_open(false) {} ~OpenScope() {Close();} - void Open(HWND p_owner); - void Close(); + void Open(HWND p_owner) { + Close(); + WIN32_OP(OpenClipboard(p_owner)); + m_open = true; + } + void Close() { + if (m_open) { + m_open = false; + CloseClipboard(); + } + } private: bool m_open; @@ -31,3 +44,4 @@ namespace ClipboardHelper { } bool IsTextAvailable(); }; +#endif // FOOBAR2000_DESKTOP_WINDOWS diff --git a/foobar2000/helpers/create_directory_helper.cpp b/foobar2000/helpers/create_directory_helper.cpp index 18ac531..d005560 100644 --- a/foobar2000/helpers/create_directory_helper.cpp +++ b/foobar2000/helpers/create_directory_helper.cpp @@ -1,6 +1,5 @@ -#include "StdAfx.h" +#include "stdafx.h" #include "create_directory_helper.h" -#include namespace create_directory_helper { @@ -118,38 +117,29 @@ namespace create_directory_helper } pfc::string create_directory_helper::sanitize_formatted_path(pfc::stringp formatted, bool allowWC) { - return sanitize_formatted_path_ex(formatted, allowWC, pfc::io::path::charReplaceDefault); -}; - -pfc::string create_directory_helper::sanitize_formatted_path_ex(pfc::stringp formatted, bool allowWC, charReplace_t replace) { pfc::string out; t_size curSegBase = 0; - for (t_size walk = 0; ; ++walk) { + for(t_size walk = 0; ; ++walk) { const char c = formatted[walk]; const bool end = (c == 0); if (end || pfc::io::path::isSeparator(c)) { if (curSegBase < walk) { - pfc::string seg(formatted + curSegBase, walk - curSegBase); - out = pfc::io::path::combine(out, pfc::io::path::validateFileName(seg, allowWC, end /*preserve ext*/, replace)); + pfc::string seg( formatted + curSegBase, walk - curSegBase ); + out = pfc::io::path::combine(out, pfc::io::path::validateFileName(seg, allowWC, end /*preserve ext*/)); } - if (end) break; + if ( end ) break; curSegBase = walk + 1; } } return out; -} +}; -void create_directory_helper::format_filename_ex(const metadb_handle_ptr & handle, titleformat_hook * p_hook, titleformat_object::ptr spec, const char * suffix, pfc::string_base & out) { - format_filename_ex(handle, p_hook, spec, suffix, out, pfc::io::path::charReplaceDefault); -} - -void create_directory_helper::format_filename_ex(const metadb_handle_ptr & handle,titleformat_hook * p_hook,titleformat_object::ptr spec,const char * suffix, pfc::string_base & out, charReplace_t replace) { +void create_directory_helper::format_filename_ex(const metadb_handle_ptr & handle,titleformat_hook * p_hook,titleformat_object::ptr spec,const char * suffix, pfc::string_base & out) { pfc::string_formatter formatted; titleformat_text_filter_myimpl filter; - filter.m_replace = replace; handle->format_title(p_hook,formatted,spec,&filter); formatted << suffix; - out = sanitize_formatted_path_ex(formatted, false, replace).ptr(); + out = sanitize_formatted_path(formatted).ptr(); } void create_directory_helper::format_filename(const metadb_handle_ptr & handle,titleformat_hook * p_hook,titleformat_object::ptr spec,pfc::string_base & out) { format_filename_ex(handle, p_hook, spec, "", out); @@ -164,30 +154,16 @@ void create_directory_helper::format_filename(const metadb_handle_ptr & handle,t } } -static bool substSanity(const char * subst) { - if (subst == nullptr) return false; - for (size_t w = 0; subst[w]; ++w) { - if (pfc::io::path::isSeparator(subst[w])) return false; - } - return true; -} - void create_directory_helper::titleformat_text_filter_myimpl::write(const GUID & p_inputType,pfc::string_receiver & p_out,const char * p_data,t_size p_dataLength) { if (p_inputType == titleformat_inputtypes::meta) { pfc::string_formatter temp; for(t_size walk = 0; walk < p_dataLength; ++walk) { char c = p_data[walk]; if (c == 0) break; - const char * subst = nullptr; if (pfc::io::path::isSeparator(c)) { - if (m_replace) { - const char * proposed = m_replace(c); - if (substSanity(proposed)) subst = proposed; - } - if (subst == nullptr) subst = "-"; + c = '-'; } - if (subst != nullptr) temp.add_string(subst); - else temp.add_byte(c); + temp.add_byte(c); } p_out.add_string(temp); } else p_out.add_string(p_data,p_dataLength); diff --git a/foobar2000/helpers/create_directory_helper.h b/foobar2000/helpers/create_directory_helper.h index 353f69a..bb7316f 100644 --- a/foobar2000/helpers/create_directory_helper.h +++ b/foobar2000/helpers/create_directory_helper.h @@ -1,30 +1,16 @@ #pragma once -#include -#include - -#ifdef FOOBAR2000_MODERN -#include "metadb_compat.h" -#include -#endif - namespace create_directory_helper { - typedef std::function charReplace_t; - void create_path(const char * p_path,abort_callback & p_abort); void make_path(const char * parent,const char * filename,const char * extension,bool allow_new_dirs,pfc::string8 & out,bool b_really_create_dirs,abort_callback & p_dir_create_abort); void format_filename(const metadb_handle_ptr & handle,titleformat_hook * p_hook,const char * spec,pfc::string_base & out); void format_filename(const metadb_handle_ptr & handle,titleformat_hook * p_hook,titleformat_object::ptr spec,pfc::string_base & out); void format_filename_ex(const metadb_handle_ptr & handle,titleformat_hook * p_hook,titleformat_object::ptr spec,const char * suffix, pfc::string_base & out); - void format_filename_ex(const metadb_handle_ptr & handle, titleformat_hook * p_hook, titleformat_object::ptr spec, const char * suffix, pfc::string_base & out, charReplace_t replace); - pfc::string sanitize_formatted_path(pfc::stringp str, bool allowWC = false); - pfc::string sanitize_formatted_path_ex(pfc::stringp str, bool allowWC, charReplace_t replace); class titleformat_text_filter_myimpl : public titleformat_text_filter { public: - charReplace_t m_replace; void write(const GUID & p_inputType,pfc::string_receiver & p_out,const char * p_data,t_size p_dataLength); }; diff --git a/foobar2000/helpers/cue_creator.cpp b/foobar2000/helpers/cue_creator.cpp index 7e68c1a..e244df2 100644 --- a/foobar2000/helpers/cue_creator.cpp +++ b/foobar2000/helpers/cue_creator.cpp @@ -25,19 +25,15 @@ static bool is_meta_same_everywhere(const cue_creator::t_entry_list & p_list,con { pfc::string8_fastalloc reference,temp; - bool first = true; - for(auto iter = p_list.first(); iter.is_valid(); ++ iter ) { - if ( ! iter->isTrackAudio() ) continue; - - if ( first ) { - first = false; - if (!iter->m_infos.meta_format(p_meta,reference)) return false; - } else { - if (!iter->m_infos.meta_format(p_meta,temp)) return false; - if (strcmp(temp,reference)!=0) return false; - } + cue_creator::t_entry_list::const_iterator iter; + iter = p_list.first(); + if (!iter.is_valid()) return false; + if (!iter->m_infos.meta_format(p_meta,reference)) return false; + for(;iter.is_valid();++iter) + { + if (!iter->m_infos.meta_format(p_meta,temp)) return false; + if (strcmp(temp,reference)!=0) return false; } - return true; } @@ -58,53 +54,46 @@ namespace cue_creator catalog_global = is_meta_same_everywhere(p_data,"catalog"), songwriter_global = is_meta_same_everywhere(p_data,"songwriter"); + if (genre_global) { + p_out << "REM GENRE " << format_meta(p_data.first()->m_infos,"genre") << g_eol; + } + if (date_global) { + p_out << "REM DATE " << format_meta(p_data.first()->m_infos,"date") << g_eol; + } + if (discid_global) { + p_out << "REM DISCID " << format_meta(p_data.first()->m_infos,"discid") << g_eol; + } + if (comment_global) { + p_out << "REM COMMENT " << format_meta(p_data.first()->m_infos,"comment") << g_eol; + } + if (catalog_global) { + p_out << "CATALOG " << format_meta(p_data.first()->m_infos,"catalog") << g_eol; + } + if (songwriter_global) { + p_out << "SONGWRITER \"" << format_meta(p_data.first()->m_infos,"songwriter") << "\"" << g_eol; + } + + if (album_artist_global) { - auto firstTrack = p_data.first(); - while( firstTrack.is_valid() && ! firstTrack->isTrackAudio() ) ++ firstTrack; - if ( firstTrack.is_valid() ) { - if (genre_global) { - p_out << "REM GENRE " << format_meta(firstTrack->m_infos,"genre") << g_eol; - } - if (date_global) { - p_out << "REM DATE " << format_meta(firstTrack->m_infos,"date") << g_eol; - } - if (discid_global) { - p_out << "REM DISCID " << format_meta(firstTrack->m_infos,"discid") << g_eol; - } - if (comment_global) { - p_out << "REM COMMENT " << format_meta(firstTrack->m_infos,"comment") << g_eol; - } - if (catalog_global) { - p_out << "CATALOG " << format_meta(firstTrack->m_infos,"catalog") << g_eol; - } - if (songwriter_global) { - p_out << "SONGWRITER \"" << format_meta(firstTrack->m_infos,"songwriter") << "\"" << g_eol; - } + p_out << "PERFORMER \"" << format_meta(p_data.first()->m_infos,"album artist") << "\"" << g_eol; + artist_global = false; + } + else if (artist_global) + { + p_out << "PERFORMER \"" << format_meta(p_data.first()->m_infos,"artist") << "\"" << g_eol; + } + if (album_global) + { + p_out << "TITLE \"" << format_meta(p_data.first()->m_infos,"album") << "\"" << g_eol; + } - if (album_artist_global) - { - p_out << "PERFORMER \"" << format_meta(firstTrack->m_infos,"album artist") << "\"" << g_eol; - artist_global = false; - } - else if (artist_global) - { - p_out << "PERFORMER \"" << format_meta(firstTrack->m_infos,"artist") << "\"" << g_eol; - } - if (album_global) - { - p_out << "TITLE \"" << format_meta(firstTrack->m_infos,"album") << "\"" << g_eol; - } - - { - replaygain_info::t_text_buffer rgbuffer; - replaygain_info rg = firstTrack->m_infos.get_replaygain(); - if (rg.format_album_gain(rgbuffer)) - p_out << "REM REPLAYGAIN_ALBUM_GAIN " << rgbuffer << g_eol; - if (rg.format_album_peak(rgbuffer)) - p_out << "REM REPLAYGAIN_ALBUM_PEAK " << rgbuffer << g_eol; - } - - } + { + replaygain_info::t_text_buffer rgbuffer; + replaygain_info rg = p_data.first()->m_infos.get_replaygain(); + if (rg.format_album_gain(rgbuffer)) + p_out << "REM REPLAYGAIN_ALBUM_GAIN " << rgbuffer << g_eol; + if (rg.format_album_peak(rgbuffer)) + p_out << "REM REPLAYGAIN_ALBUM_PEAK " << rgbuffer << g_eol; } pfc::string8 last_file; @@ -113,19 +102,11 @@ namespace cue_creator { if (strcmp(last_file,iter->m_file) != 0) { - auto fileType = iter->m_fileType; - if ( fileType.length() == 0 ) fileType = "WAVE"; - p_out << "FILE \"" << iter->m_file << "\" " << fileType << g_eol; + p_out << "FILE \"" << iter->m_file << "\" WAVE" << g_eol; last_file = iter->m_file; } - { - auto trackType = iter->m_trackType; - if (trackType.length() == 0) trackType = "AUDIO"; - p_out << " TRACK " << pfc::format_int(iter->m_track_number,2) << " " << trackType << g_eol; - } - - + p_out << " TRACK " << pfc::format_int(iter->m_track_number,2) << " AUDIO" << g_eol; if (iter->m_infos.meta_find("title") != pfc_infinite) p_out << " TITLE \"" << format_meta(iter->m_infos,"title") << "\"" << g_eol; @@ -192,11 +173,5 @@ namespace cue_creator m_index_list.m_positions[1] = index1; } - bool t_entry::isTrackAudio() const { - PFC_ASSERT( m_trackType.length() > 0 ); - return pfc::stringEqualsI_ascii( m_trackType, "AUDIO" ); - } } - - diff --git a/foobar2000/helpers/cue_creator.h b/foobar2000/helpers/cue_creator.h index c0b511c..a727128 100644 --- a/foobar2000/helpers/cue_creator.h +++ b/foobar2000/helpers/cue_creator.h @@ -7,11 +7,9 @@ namespace cue_creator struct t_entry { file_info_impl m_infos; - pfc::string8 m_file, m_fileType, m_flags, m_trackType = "AUDIO"; + pfc::string8 m_file,m_flags; unsigned m_track_number; - bool isTrackAudio() const; - t_cuesheet_index_list m_index_list; void set_simple_index(double p_time); diff --git a/foobar2000/helpers/cue_parser.cpp b/foobar2000/helpers/cue_parser.cpp index 152dc47..2eef0f7 100644 --- a/foobar2000/helpers/cue_parser.cpp +++ b/foobar2000/helpers/cue_parser.cpp @@ -6,7 +6,6 @@ namespace { PFC_DECLARE_EXCEPTION(exception_cue,pfc::exception,"Invalid cuesheet"); - PFC_DECLARE_EXCEPTION(exception_cue_tracktype, exception_cue, "Not an audio track") } static bool is_numeric(char c) {return c>='0' && c<='9';} @@ -32,9 +31,7 @@ static void validate_file_type(const char * p_type,t_size p_type_length) { stricmp_utf8_ex(p_type,p_type_length,"APE",pfc_infinite) != 0 && stricmp_utf8_ex(p_type,p_type_length,"FLAC",pfc_infinite) != 0 && stricmp_utf8_ex(p_type,p_type_length,"WV",pfc_infinite) != 0 && - stricmp_utf8_ex(p_type,p_type_length,"WAVPACK",pfc_infinite) != 0 && - // BINARY - stricmp_utf8_ex(p_type,p_type_length,"BINARY",pfc_infinite) != 0 + stricmp_utf8_ex(p_type,p_type_length,"WAVPACK",pfc_infinite) != 0 ) pfc::throw_exception_with_message< exception_cue >(PFC_string_formatter() << "expected WAVE, MP3 or AIFF, got : \"" << pfc::string_part(p_type,p_type_length) << "\""); } @@ -137,17 +134,15 @@ namespace { { validate_file_type(p_type,p_type_length); m_file.set_string(p_file,p_file_length); - m_fileType.set_string(p_type, p_type_length); } void on_track(unsigned p_index,const char * p_type,t_size p_type_length) { - finalize_track(); // finalize previous track - - m_trackIsAudio = stricmp_utf8_ex(p_type,p_type_length,"audio",pfc_infinite) == 0; + if (stricmp_utf8_ex(p_type,p_type_length,"audio",pfc_infinite)) pfc::throw_exception_with_message("only tracks of type AUDIO supported"); + //if (p_index != m_track + 1) throw exception_cue("cuesheet tracks out of order"); + if (m_track != 0) finalize_track(); if (m_file.is_empty()) pfc::throw_exception_with_message("declaring a track with no file set"); m_trackfile = m_file; - m_trackFileType = m_fileType; m_track = p_index; } @@ -176,40 +171,38 @@ namespace { void finalize() { - finalize_track(); // finalize last track + if (m_track != 0) + { + finalize_track(); + m_track = 0; + } } private: void finalize_track() { - if ( m_track != 0 && m_trackIsAudio ) { - if (!m_index1_set) pfc::throw_exception_with_message< exception_cue > ("INDEX 01 not set"); - if (!m_index0_set) m_index_list.m_positions[0] = m_index_list.m_positions[1] - m_pregap; - if (!m_index_list.is_valid()) pfc::throw_exception_with_message< exception_cue > ("invalid index list"); - - cue_parser::t_cue_entry_list::iterator iter; - iter = m_out.insert_last(); - if (m_trackfile.is_empty()) pfc::throw_exception_with_message< exception_cue > ("track has no file assigned"); - iter->m_file = m_trackfile; - iter->m_fileType = m_trackFileType; - iter->m_track_number = m_track; - iter->m_indexes = m_index_list; - } + if (!m_index1_set) pfc::throw_exception_with_message< exception_cue > ("INDEX 01 not set"); + if (!m_index0_set) m_index_list.m_positions[0] = m_index_list.m_positions[1] - m_pregap; + if (!m_index_list.is_valid()) pfc::throw_exception_with_message< exception_cue > ("invalid index list"); + cue_parser::t_cue_entry_list::iterator iter; + iter = m_out.insert_last(); + if (m_trackfile.is_empty()) pfc::throw_exception_with_message< exception_cue > ("track has no file assigned"); + iter->m_file = m_trackfile; + iter->m_track_number = m_track; + iter->m_indexes = m_index_list; + m_index_list.reset(); m_index0_set = false; m_index1_set = false; m_pregap = 0; - - m_track = 0; m_trackIsAudio = false; } bool m_index0_set,m_index1_set; t_cuesheet_index_list m_index_list; double m_pregap; unsigned m_track; - bool m_trackIsAudio = false; - pfc::string8 m_file,m_fileType,m_trackfile,m_trackFileType; + pfc::string8 m_file,m_trackfile; cue_parser::t_cue_entry_list & m_out; }; @@ -225,7 +218,7 @@ namespace { if (p_index == 0) pfc::throw_exception_with_message< exception_cue > ("invalid TRACK index"); if (p_index == m_wanted_track) { - if (stricmp_utf8_ex(p_type,p_type_length,"audio",pfc_infinite)) throw exception_cue_tracktype(); + if (stricmp_utf8_ex(p_type,p_type_length,"audio",pfc_infinite)) pfc::throw_exception_with_message< exception_cue > ("only tracks of type AUDIO supported"); } m_track = p_index; m_totaltracks++; @@ -387,17 +380,6 @@ namespace { }; -static pfc::string_part_ref cue_line_argument( const char * base, size_t length ) { - const char * end = base + length; - while(base < end && is_spacing(base[0]) ) ++base; - while(base < end && is_spacing(end[-1]) ) --end; - if ( base + 1 < end ) { - if ( base[0] == '\"' && end[-1] == '\"' ) { - ++base; --end; - } - } - return pfc::string_part(base, end-base); -} static void g_parse_cue_line(const char * p_line,t_size p_line_length,cue_parser_callback & p_callback) { @@ -518,18 +500,66 @@ static void g_parse_cue_line(const char * p_line,t_size p_line_length,cue_parser } else if (!stricmp_utf8_ex(p_line,ptr,"title",pfc_infinite)) { - auto arg = cue_line_argument(p_line+ptr, p_line_length-ptr); - if ( arg.m_len > 0 ) p_callback.on_title( arg.m_ptr, arg.m_len ); + while(ptr < p_line_length && is_spacing(p_line[ptr])) ptr++; + if (ptr == p_line_length) pfc::throw_exception_with_message< exception_cue > ("invalid TITLE syntax"); + if (p_line[ptr] == '\"') + { + ptr++; + t_size base = ptr; + while(ptr < p_line_length && p_line[ptr] != '\"') ptr++; + if (ptr == p_line_length) pfc::throw_exception_with_message< exception_cue > ("invalid TITLE syntax"); + t_size length = ptr-base; + ptr++; + while(ptr < p_line_length && is_spacing(p_line[ptr])) ptr++; + if (ptr != p_line_length) pfc::throw_exception_with_message< exception_cue > ("invalid TITLE syntax"); + p_callback.on_title(p_line+base,length); + } + else + { + p_callback.on_title(p_line+ptr,p_line_length-ptr); + } } else if (!stricmp_utf8_ex(p_line,ptr,"performer",pfc_infinite)) { - auto arg = cue_line_argument(p_line + ptr, p_line_length - ptr); - if (arg.m_len > 0) p_callback.on_performer(arg.m_ptr, arg.m_len); + while(ptr < p_line_length && is_spacing(p_line[ptr])) ptr++; + if (ptr == p_line_length) pfc::throw_exception_with_message< exception_cue > ("invalid PERFORMER syntax"); + if (p_line[ptr] == '\"') + { + ptr++; + t_size base = ptr; + while(ptr < p_line_length && p_line[ptr] != '\"') ptr++; + if (ptr == p_line_length) pfc::throw_exception_with_message< exception_cue > ("invalid PERFORMER syntax"); + t_size length = ptr-base; + ptr++; + while(ptr < p_line_length && is_spacing(p_line[ptr])) ptr++; + if (ptr != p_line_length) pfc::throw_exception_with_message< exception_cue > ("invalid PERFORMER syntax"); + p_callback.on_performer(p_line+base,length); + } + else + { + p_callback.on_performer(p_line+ptr,p_line_length-ptr); + } } else if (!stricmp_utf8_ex(p_line,ptr,"songwriter",pfc_infinite)) { - auto arg = cue_line_argument(p_line + ptr, p_line_length - ptr); - if (arg.m_len > 0) p_callback.on_songwriter(arg.m_ptr, arg.m_len); + while(ptr < p_line_length && is_spacing(p_line[ptr])) ptr++; + if (ptr == p_line_length) pfc::throw_exception_with_message< exception_cue > ("invalid SONGWRITER syntax"); + if (p_line[ptr] == '\"') + { + ptr++; + t_size base = ptr; + while(ptr < p_line_length && p_line[ptr] != '\"') ptr++; + if (ptr == p_line_length) pfc::throw_exception_with_message< exception_cue > ("invalid SONGWRITER syntax"); + t_size length = ptr-base; + ptr++; + while(ptr < p_line_length && is_spacing(p_line[ptr])) ptr++; + if (ptr != p_line_length) pfc::throw_exception_with_message< exception_cue > ("invalid SONGWRITER syntax"); + p_callback.on_songwriter(p_line+base,length); + } + else + { + p_callback.on_songwriter(p_line+ptr,p_line_length-ptr); + } } else if (!stricmp_utf8_ex(p_line,ptr,"isrc",pfc_infinite)) { @@ -640,20 +670,15 @@ namespace { void on_file(const char * p_file,t_size p_file_length,const char * p_type,t_size p_type_length) { validate_file_type(p_type,p_type_length); m_file.set_string(p_file,p_file_length); - m_fileType.set_string(p_type, p_type_length); } void on_track(unsigned p_index,const char * p_type,t_size p_type_length) { - finalize_track(); - - m_trackType.set_string( p_type, p_type_length ); - + if (stricmp_utf8_ex(p_type,p_type_length,"audio",pfc_infinite)) pfc::throw_exception_with_message< exception_cue > ("only tracks of type AUDIO supported"); //if (p_index != m_track + 1) throw exception_cue("cuesheet tracks out of order",0); - + if (m_track != 0) finalize_track(); if (m_file.is_empty()) pfc::throw_exception_with_message< exception_cue > ("declaring a track with no file set"); m_trackfile = m_file; - m_trackFileType = m_fileType; m_track = p_index; } @@ -682,7 +707,11 @@ namespace { void on_comment(const char * p_comment,t_size p_comment_length) {} void finalize() { - finalize_track(); + if (m_track != 0) + { + finalize_track(); + m_track = 0; + } } void on_flags(const char * p_flags,t_size p_flags_length) { m_flags.set_string(p_flags,p_flags_length); @@ -690,34 +719,28 @@ namespace { private: void finalize_track() { - if ( m_track != 0 ) { - if (m_track < 1 || m_track > maximumCueTrackNumber) pfc::throw_exception_with_message< exception_cue > ("track number out of range"); - if (!m_index1_set) pfc::throw_exception_with_message< exception_cue > ("INDEX 01 not set"); - if (!m_index0_set) m_indexes.m_positions[0] = m_indexes.m_positions[1] - m_pregap; - if (!m_indexes.is_valid()) pfc::throw_exception_with_message< exception_cue > ("invalid index list"); + if (m_track < 1 || m_track > maximumCueTrackNumber) pfc::throw_exception_with_message< exception_cue > ("track number out of range"); + if (!m_index1_set) pfc::throw_exception_with_message< exception_cue > ("INDEX 01 not set"); + if (!m_index0_set) m_indexes.m_positions[0] = m_indexes.m_positions[1] - m_pregap; + if (!m_indexes.is_valid()) pfc::throw_exception_with_message< exception_cue > ("invalid index list"); - cue_creator::t_entry_list::iterator iter; - iter = m_out.insert_last(); - iter->m_track_number = m_track; - iter->m_file = m_trackfile; - iter->m_fileType = m_trackFileType; - iter->m_index_list = m_indexes; - iter->m_flags = m_flags; - iter->m_trackType = m_trackType; - } + cue_creator::t_entry_list::iterator iter; + iter = m_out.insert_last(); + iter->m_track_number = m_track; + iter->m_file = m_trackfile; + iter->m_index_list = m_indexes; + iter->m_flags = m_flags; m_pregap = 0; m_indexes.reset(); m_index0_set = m_index1_set = false; m_flags.reset(); - m_trackType.reset(); } bool m_index0_set,m_index1_set; double m_pregap; unsigned m_track; - bool m_trackIsAudio = false; cue_creator::t_entry_list & m_out; - pfc::string8 m_file, m_fileType,m_trackfile, m_trackFileType, m_flags, m_trackType; + pfc::string8 m_file,m_trackfile,m_flags; t_cuesheet_index_list m_indexes; }; } @@ -732,12 +755,11 @@ void cue_parser::parse_full(const char * p_cuesheet,cue_creator::t_entry_list & { cue_creator::t_entry_list::iterator iter; - for(iter=p_out.first();iter.is_valid();++iter) { - if ( iter->isTrackAudio() ) { - cue_parser_callback_retrieveinfo callback(iter->m_infos,iter->m_track_number); - g_parse_cue(p_cuesheet,callback); - callback.finalize(); - } + for(iter=p_out.first();iter.is_valid();++iter) + { + cue_parser_callback_retrieveinfo callback(iter->m_infos,iter->m_track_number); + g_parse_cue(p_cuesheet,callback); + callback.finalize(); } } } catch(exception_cue const & e) { diff --git a/foobar2000/helpers/cue_parser.h b/foobar2000/helpers/cue_parser.h index 29028c3..f3b3443 100644 --- a/foobar2000/helpers/cue_parser.h +++ b/foobar2000/helpers/cue_parser.h @@ -62,10 +62,9 @@ namespace file_info_record_helper { namespace cue_parser { struct cue_entry { - pfc::string8 m_file, m_fileType; + pfc::string8 m_file; unsigned m_track_number; t_cuesheet_index_list m_indexes; - bool isFileBinary() const {return pfc::stringEqualsI_ascii(m_fileType, "BINARY");} }; typedef pfc::chain_list_v2_t t_cue_entry_list; @@ -114,29 +113,22 @@ namespace cue_parser public: typedef input_info_writer_v2 interface_info_writer_t; // remove_tags supplied void open(service_ptr_t p_filehint,const char * p_path,t_input_open_reason p_reason,abort_callback & p_abort) { - m_remote = filesystem::g_is_recognized_and_remote( p_path ); - if (m_remote && p_reason == input_open_info_write) throw exception_io_object_is_remote(); m_impl.open( p_filehint, p_path, p_reason, p_abort ); - if (!m_remote) { - file_info_impl info; - m_impl.get_info(info, p_abort); - m_meta.set_tag(info); - } + file_info_impl info; + m_impl.get_info(info,p_abort); + m_meta.set_tag(info); } t_uint32 get_subsong_count() { - return this->expose_cuesheet() ? (uint32_t) m_meta.get_cue_track_count() : 1; + return m_meta.have_cuesheet() ? (uint32_t) m_meta.get_cue_track_count() : 1; } t_uint32 get_subsong(t_uint32 p_index) { - return this->expose_cuesheet() ? m_meta.remap_trackno(p_index) : 0; + return m_meta.have_cuesheet() ? m_meta.remap_trackno(p_index) : 0; } void get_info(t_uint32 p_subsong,file_info & p_info,abort_callback & p_abort) { - if (m_remote) { - PFC_ASSERT(p_subsong == 0); - m_impl.get_info(p_info, p_abort); - } else if (p_subsong == 0) { + if (p_subsong == 0) { m_meta.get_tag(p_info); } else { m_meta.get_track_info(p_subsong,p_info); @@ -151,7 +143,7 @@ namespace cue_parser m_decodeFrom = 0; m_decodeLength = -1; m_decodePos = 0; } else { double start, length; - _query_track_offsets(p_subsong,start,length); + m_meta.query_track_offsets(p_subsong,start,length); unsigned flags2 = p_flags; if (start > 0) flags2 &= ~input_flag_no_seeking; flags2 &= ~input_flag_allow_inaccurate_seeking; @@ -200,7 +192,6 @@ namespace cue_parser } void remove_tags(abort_callback & abort) { - PFC_ASSERT(!m_remote); m_impl.remove_tags( abort ); file_info_impl info; m_impl.get_info(info, abort); @@ -208,7 +199,6 @@ namespace cue_parser } void retag_set_info(t_uint32 p_subsong,const file_info & p_info,abort_callback & p_abort) { - PFC_ASSERT(!m_remote); if (p_subsong == 0) { m_meta.set_tag(p_info); } else { @@ -217,7 +207,6 @@ namespace cue_parser } void retag_commit(abort_callback & p_abort) { - PFC_ASSERT(!m_remote); file_info_impl info; m_meta.get_tag(info); m_impl.retag(pfc::implicit_cast(info), p_abort); @@ -225,12 +214,6 @@ namespace cue_parser m_impl.get_info(info, p_abort); m_meta.set_tag( info ); } - void _query_track_offsets(unsigned p_subsong, double& start, double& length) const { - m_meta.query_track_offsets(p_subsong,start,length); - } - bool expose_cuesheet() const { - return !m_remote && m_meta.have_cuesheet(); - } private: bool _run(audio_chunk & chunk, mem_block_container * raw, abort_callback & aborter) { if (m_decodeLength >= 0 && m_decodePos >= m_decodeLength) return false; @@ -265,7 +248,7 @@ namespace cue_parser } t_base m_impl; double m_decodeFrom, m_decodeLength, m_decodePos; - bool m_remote = false; + embeddedcue_metadata_manager m_meta; }; #ifdef FOOBAR2000_HAVE_CHAPTERIZER @@ -325,13 +308,6 @@ namespace cue_parser instance.open(0,p_path,input_open_info_read,p_abort); const t_uint32 total = instance.get_subsong_count(); - if (instance.expose_cuesheet()) { - double start, len; - instance._query_track_offsets(1, start, len); - p_list.set_pregap( start ); - } - - p_list.set_chapter_count(total); for(t_uint32 walk = 0; walk < total; ++walk) { file_info_impl info; diff --git a/foobar2000/helpers/cue_parser_embedding.cpp b/foobar2000/helpers/cue_parser_embedding.cpp index 449d541..b4860d3 100644 --- a/foobar2000/helpers/cue_parser_embedding.cpp +++ b/foobar2000/helpers/cue_parser_embedding.cpp @@ -26,7 +26,6 @@ namespace { void operator() (unsigned p_trackno,const track_record & p_record) { if (p_trackno > 0) { cue_creator::t_entry_list::iterator iter = m_entries.insert_last(); - iter->m_trackType = "AUDIO"; iter->m_file = p_record.m_file; iter->m_flags = p_record.m_flags; iter->m_index_list = p_record.m_index_list; @@ -124,18 +123,9 @@ namespace { }; }; -static bool meta_value_equals(const char* v1, const char* v2, bool asNumber) { - if (asNumber) { - // Special fix: leading zeros on track numbers - while( *v1 == '0' ) ++ v1; - while( *v2 == '0' ) ++ v2; - } - return strcmp(v1,v2) == 0; -} - -static void strip_redundant_track_meta(unsigned p_tracknumber,const file_info & p_cueinfo,file_info_record::t_meta_map & p_meta,const char * p_metaname, bool asNumber) { - const size_t metaindex = p_cueinfo.meta_find(p_metaname); - if (metaindex == SIZE_MAX) return; +static void strip_redundant_track_meta(unsigned p_tracknumber,const file_info & p_cueinfo,file_info_record::t_meta_map & p_meta,const char * p_metaname) { + t_size metaindex = p_cueinfo.meta_find(p_metaname); + if (metaindex == ~0) return; pfc::string_formatter namelocal; build_cue_meta_name(p_metaname,p_tracknumber,namelocal); { @@ -144,8 +134,7 @@ static void strip_redundant_track_meta(unsigned p_tracknumber,const file_info & file_info_record::t_meta_value::const_iterator iter = val->first(); for(t_size valwalk = 0, valcount = p_cueinfo.meta_enum_value_count(metaindex); valwalk < valcount; ++valwalk) { if (iter.is_empty()) return; - - if (!meta_value_equals(*iter,p_cueinfo.meta_enum_value(metaindex,valwalk), asNumber)) return; + if (strcmp(*iter,p_cueinfo.meta_enum_value(metaindex,valwalk)) != 0) return; ++iter; } if (!iter.is_empty()) return; @@ -192,8 +181,8 @@ void embeddedcue_metadata_manager::get_tag(file_info & p_info) const { //strip redundant titles and tracknumbers that the cuesheet already contains for(cue_creator::t_entry_list::const_iterator iter = entries.first(); iter.is_valid(); ++iter) { - strip_redundant_track_meta(iter->m_track_number,iter->m_infos,output.m_meta,"tracknumber", true); - strip_redundant_track_meta(iter->m_track_number,iter->m_infos,output.m_meta,"title", false); + strip_redundant_track_meta(iter->m_track_number,iter->m_infos,output.m_meta,"tracknumber"); + strip_redundant_track_meta(iter->m_track_number,iter->m_infos,output.m_meta,"title"); } diff --git a/foobar2000/helpers/dialog_resize_helper.cpp b/foobar2000/helpers/dialog_resize_helper.cpp index 311cbcb..b217116 100644 --- a/foobar2000/helpers/dialog_resize_helper.cpp +++ b/foobar2000/helpers/dialog_resize_helper.cpp @@ -3,13 +3,13 @@ #ifdef FOOBAR2000_DESKTOP_WINDOWS #include "dialog_resize_helper.h" -static BOOL GetChildWindowRect(HWND wnd, UINT id, RECT* child) +BOOL GetChildWindowRect(HWND wnd,UINT id,RECT* child) { RECT temp; HWND wndChild = GetDlgItem(wnd, id); if (wndChild == NULL) return FALSE; - if (!GetWindowRect(wndChild, &temp)) return FALSE; - if (!MapWindowPoints(0, wnd, (POINT*)&temp, 2)) return FALSE; + if (!GetWindowRect(wndChild,&temp)) return FALSE; + if (!MapWindowPoints(0,wnd,(POINT*)&temp,2)) return FALSE; *child = temp; return TRUE; } diff --git a/foobar2000/helpers/dialog_resize_helper.h b/foobar2000/helpers/dialog_resize_helper.h index 56d7dbf..b23a82e 100644 --- a/foobar2000/helpers/dialog_resize_helper.h +++ b/foobar2000/helpers/dialog_resize_helper.h @@ -2,11 +2,9 @@ #ifdef FOOBAR2000_DESKTOP_WINDOWS -#include +BOOL GetChildWindowRect(HWND wnd,UINT id,RECT* child); -// Legacy class referenced by old code -// Do not use in new code, use libPPUI instead -class dialog_resize_helper : public CDialogResizeHelperCompat +class dialog_resize_helper { pfc::array_t rects; RECT orig_client; @@ -14,6 +12,12 @@ class dialog_resize_helper : public CDialogResizeHelperCompat HWND sizegrip; unsigned min_x,min_y,max_x,max_y; +public: + struct param { + unsigned short id; + unsigned short flags; + }; +private: pfc::array_t m_table; void set_parent(HWND wnd); @@ -24,6 +28,11 @@ public: inline void set_max_size(unsigned x,unsigned y) {max_x = x; max_y = y;} void add_sizegrip(); + enum { + X_MOVE = 1, X_SIZE = 2, Y_MOVE = 4, Y_SIZE = 8, + XY_MOVE = X_MOVE|Y_MOVE, XY_SIZE = X_SIZE|Y_SIZE, + X_MOVE_Y_SIZE = X_MOVE|Y_SIZE, X_SIZE_Y_MOVE = X_SIZE|Y_MOVE, + }; //the old way bool process_message(HWND wnd,UINT msg,WPARAM wp,LPARAM lp); diff --git a/foobar2000/helpers/duration_counter.h b/foobar2000/helpers/duration_counter.h index 36c62d3..030afda 100644 --- a/foobar2000/helpers/duration_counter.h +++ b/foobar2000/helpers/duration_counter.h @@ -1,8 +1,5 @@ #pragma once -#include -#include - //! Duration counter class - accumulates duration using sample values, without any kind of rounding error accumulation. class duration_counter { public: @@ -40,14 +37,6 @@ public: void add(const audio_chunk & c) { add(c.get_sample_count(), c.get_sample_rate()); } -#ifdef FOOBAR2000_HAVE_DSP - void add(dsp_chunk_list const & c) { - const size_t num = c.get_count(); - for (size_t walk = 0; walk < num; ++walk) { - add(*c.get_item(walk)); - } - } -#endif void add(t_uint64 sampleCount, t_uint32 sampleRate) { PFC_ASSERT(sampleRate > 0); if (sampleRate > 0 && sampleCount > 0) { diff --git a/foobar2000/helpers/file_list_helper.cpp b/foobar2000/helpers/file_list_helper.cpp index dd81e2d..7c30cd7 100644 --- a/foobar2000/helpers/file_list_helper.cpp +++ b/foobar2000/helpers/file_list_helper.cpp @@ -61,11 +61,8 @@ namespace file_list_helper _add(temp); } file_list_remove_duplicates(m_data); - } - file_list_from_metadb_handle_list::file_list_from_metadb_handle_list(metadb_handle_list_cref lst, bool bDisplayPaths) { - if ( bDisplayPaths ) init_from_list_display(lst); - else init_from_list( lst ); + } t_size file_list_from_metadb_handle_list::get_count() const {return m_data.get_count();} diff --git a/foobar2000/helpers/file_list_helper.h b/foobar2000/helpers/file_list_helper.h index b90743a..3b15b2c 100644 --- a/foobar2000/helpers/file_list_helper.h +++ b/foobar2000/helpers/file_list_helper.h @@ -5,8 +5,6 @@ namespace file_list_helper //list guaranteed to be sorted by metadb::path_compare class file_list_from_metadb_handle_list : public pfc::list_base_const_t { public: - file_list_from_metadb_handle_list() {} - file_list_from_metadb_handle_list( metadb_handle_list_cref lst, bool bDisplayPaths = false ); static t_size g_get_count(const list_base_const_t & p_list, t_size max = ~0); diff --git a/foobar2000/helpers/file_readonly.h b/foobar2000/helpers/file_readonly.h deleted file mode 100644 index 9acbb9c..0000000 --- a/foobar2000/helpers/file_readonly.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once -// fb2k mobile compat - -#include "../SDK/filesystem_helper.h" \ No newline at end of file diff --git a/foobar2000/helpers/file_win32_wrapper.cpp b/foobar2000/helpers/file_win32_wrapper.cpp index f8b955b..28bd454 100644 --- a/foobar2000/helpers/file_win32_wrapper.cpp +++ b/foobar2000/helpers/file_win32_wrapper.cpp @@ -74,7 +74,7 @@ namespace file_win32_helpers { } void writeOverlapped(HANDLE handle, HANDLE myEvent, t_filesize & position, const void * in, size_t inBytes, abort_callback & abort) { - enum {writeMAX = 16*1024*1024}; + const enum {writeMAX = 16*1024*1024}; size_t done = 0; while(done < inBytes) { size_t delta = inBytes - done; @@ -85,7 +85,7 @@ namespace file_win32_helpers { } } void writeStreamOverlapped(HANDLE handle, HANDLE myEvent, const void * in, size_t inBytes, abort_callback & abort) { - enum {writeMAX = 16*1024*1024}; + const enum {writeMAX = 16*1024*1024}; size_t done = 0; while(done < inBytes) { size_t delta = inBytes - done; @@ -140,7 +140,7 @@ namespace file_win32_helpers { throw exception_aborted(); } size_t readOverlapped(HANDLE handle, HANDLE myEvent, t_filesize & position, void * out, size_t outBytes, abort_callback & abort) { - enum {readMAX = 16*1024*1024}; + const enum {readMAX = 16*1024*1024}; size_t done = 0; while(done < outBytes) { size_t delta = outBytes - done; @@ -154,7 +154,7 @@ namespace file_win32_helpers { } size_t readStreamOverlapped(HANDLE handle, HANDLE myEvent, void * out, size_t outBytes, abort_callback & abort) { - enum {readMAX = 16*1024*1024}; + const enum {readMAX = 16*1024*1024}; size_t done = 0; while(done < outBytes) { size_t delta = outBytes - done; @@ -237,44 +237,6 @@ namespace file_win32_helpers { #endif } - size_t lowLevelIO(HANDLE hFile, const GUID & guid, size_t arg1, void * arg2, size_t arg2size, bool canWrite, abort_callback & abort) { - if ( guid == file_lowLevelIO::guid_flushFileBuffers ) { - if (!canWrite) { - PFC_ASSERT(!"File opened for reading, not writing"); - throw exception_io_denied(); - } - WIN32_IO_OP( ::FlushFileBuffers(hFile) ); - return 1; - } else if ( guid == file_lowLevelIO::guid_getFileTimes ) { - if ( arg2size == sizeof(file_lowLevelIO::filetimes_t) ) { - if (canWrite) WIN32_IO_OP(::FlushFileBuffers(hFile)); - auto ft = reinterpret_cast(arg2); - static_assert(sizeof(t_filetimestamp) == sizeof(FILETIME), "struct sanity"); - WIN32_IO_OP( GetFileTime( hFile, (FILETIME*)&ft->creation, (FILETIME*)&ft->lastAccess, (FILETIME*)&ft->lastWrite) ); - return 1; - } - } else if ( guid == file_lowLevelIO::guid_setFileTimes ) { - if (arg2size == sizeof(file_lowLevelIO::filetimes_t)) { - if (!canWrite) { - PFC_ASSERT(!"File opened for reading, not writing"); - throw exception_io_denied(); - } - WIN32_IO_OP(::FlushFileBuffers(hFile)); - auto ft = reinterpret_cast(arg2); - static_assert(sizeof(t_filetimestamp) == sizeof(FILETIME), "struct sanity"); - const FILETIME * pCreation = nullptr; - const FILETIME * pLastAccess = nullptr; - const FILETIME * pLastWrite = nullptr; - if ( ft->creation != filetimestamp_invalid ) pCreation = (const FILETIME*)&ft->creation; - if ( ft->lastAccess != filetimestamp_invalid ) pLastAccess = (const FILETIME*)&ft->lastAccess; - if ( ft->lastWrite != filetimestamp_invalid ) pLastWrite = (const FILETIME*)&ft->lastWrite; - WIN32_IO_OP( SetFileTime(hFile, pCreation, pLastAccess, pLastWrite) ); - return 1; - } - } - return 0; - } - } #endif // _WIN32 diff --git a/foobar2000/helpers/file_win32_wrapper.h b/foobar2000/helpers/file_win32_wrapper.h index ffb3818..1b692d8 100644 --- a/foobar2000/helpers/file_win32_wrapper.h +++ b/foobar2000/helpers/file_win32_wrapper.h @@ -1,7 +1,5 @@ #pragma once -#include - #ifdef _WIN32 namespace file_win32_helpers { t_filesize get_size(HANDLE p_handle); @@ -14,11 +12,10 @@ namespace file_win32_helpers { size_t readOverlapped(HANDLE handle, HANDLE myEvent, t_filesize & position, void * out, size_t outBytes, abort_callback & abort); size_t readStreamOverlapped(HANDLE handle, HANDLE myEvent, void * out, size_t outBytes, abort_callback & abort); HANDLE createFile(LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile, abort_callback & abort); - size_t lowLevelIO(HANDLE hFile, const GUID & guid, size_t arg1, void * arg2, size_t arg2size, bool canWrite, abort_callback & abort); }; template -class file_win32_wrapper_t : public service_multi_inherit { +class file_win32_wrapper_t : public file { public: file_win32_wrapper_t(HANDLE p_handle) : m_handle(p_handle), m_position(0) { @@ -142,7 +139,7 @@ public: t_filetimestamp get_timestamp(abort_callback & p_abort) { p_abort.check_e(); - if (p_writeable) FlushFileBuffers(m_handle); + FlushFileBuffers(m_handle); SetLastError(ERROR_SUCCESS); t_filetimestamp temp; if (!GetFileTime(m_handle,0,0,(FILETIME*)&temp)) exception_io_from_win32(GetLastError()); @@ -151,17 +148,13 @@ public: bool is_remote() {return false;} ~file_win32_wrapper_t() {CloseHandle(m_handle);} - - size_t lowLevelIO(const GUID & guid, size_t arg1, void * arg2, size_t arg2size, abort_callback & abort) override { - return file_win32_helpers::lowLevelIO(m_handle, guid, arg1, arg2, arg2size, p_writeable, abort); - } protected: HANDLE m_handle; t_filesize m_position; }; template -class file_win32_wrapper_overlapped_t : public service_multi_inherit< file, file_lowLevelIO > { +class file_win32_wrapper_overlapped_t : public file { public: file_win32_wrapper_overlapped_t(HANDLE file) : m_handle(file), m_position() { WIN32_OP( (m_event = CreateEvent(NULL, TRUE, FALSE, NULL)) != NULL ); @@ -215,7 +208,7 @@ public: t_filetimestamp get_timestamp(abort_callback & p_abort) { p_abort.check_e(); - if (p_writeable) FlushFileBuffers(m_handle); + FlushFileBuffers(m_handle); SetLastError(ERROR_SUCCESS); t_filetimestamp temp; if (!GetFileTime(m_handle,0,0,(FILETIME*)&temp)) exception_io_from_win32(GetLastError()); @@ -243,10 +236,6 @@ public: return new service_impl_t >(p_handle); } - size_t lowLevelIO(const GUID & guid, size_t arg1, void * arg2, size_t arg2size, abort_callback & abort) override { - return file_win32_helpers::lowLevelIO(m_handle, guid, arg1, arg2, arg2size, p_writeable, abort); - } - protected: HANDLE m_event, m_handle; t_filesize m_position; diff --git a/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj b/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj index 380d208..d251783 100644 --- a/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj +++ b/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj @@ -13,20 +13,21 @@ {EE47764E-A202-4F85-A767-ABDAB4AFF35F} foobar2000_sdk_helpers + 7.0 StaticLibrary false Unicode - v141 + v141_xp StaticLibrary false Unicode true - v141 + v141_xp @@ -44,6 +45,7 @@ MinSpace + WIN32;NDEBUG;_WINDOWS;_WIN32_WINNT=0x501;%(PreprocessorDefinitions) true false Fast @@ -54,12 +56,12 @@ true ProgramDatabase MultiThreadedDLL + NoExtensions ../.. /d2notypeopt %(AdditionalOptions) 4715 true true - NDEBUG;_UNICODE;UNICODE;%(PreprocessorDefinitions) NDEBUG;%(PreprocessorDefinitions) @@ -72,6 +74,7 @@ Disabled + WIN32;_DEBUG;_WINDOWS;_WIN32_WINNT=0x501;%(PreprocessorDefinitions) EnableFastChecks Use stdafx.h @@ -82,6 +85,7 @@ ../.. 4715 true + NoExtensions _DEBUG;%(PreprocessorDefinitions) @@ -92,12 +96,12 @@ - + + Disabled EnableFastChecks - Disabled @@ -128,15 +132,18 @@ - - + - + + Disabled + EnableFastChecks + + Disabled EnableFastChecks @@ -151,12 +158,8 @@ Disabled EnableFastChecks - - - - Disabled EnableFastChecks @@ -169,27 +172,21 @@ - - - - - + - - - + @@ -204,16 +201,14 @@ + - - + - - - + @@ -226,22 +221,18 @@ + - - - - - + - diff --git a/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj.filters b/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj.filters index 02d7065..d9206d8 100644 --- a/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj.filters +++ b/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj.filters @@ -11,6 +11,9 @@ + + Source Files + Source Files @@ -47,9 +50,15 @@ Source Files + + Source Files + Source Files + + Source Files + Source Files @@ -80,6 +89,9 @@ Source Files + + Source Files + Source Files @@ -89,39 +101,15 @@ Source Files + + Source Files + Source Files Source Files - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - @@ -133,6 +121,9 @@ Header Files + + Header Files + Header Files @@ -181,9 +172,15 @@ Header Files + + Header Files + Header Files + + Header Files + Header Files @@ -232,6 +229,9 @@ Header Files + + Header Files + Header Files @@ -247,12 +247,18 @@ Header Files + + Header Files + Header Files Header Files + + Header Files + Header Files @@ -268,6 +274,12 @@ Header Files + + Header Files + + + Header Files + Header Files @@ -286,65 +298,5 @@ Header Files - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - \ No newline at end of file diff --git a/foobar2000/helpers/gdiplus_helpers.h b/foobar2000/helpers/gdiplus_helpers.h new file mode 100644 index 0000000..e2ab34f --- /dev/null +++ b/foobar2000/helpers/gdiplus_helpers.h @@ -0,0 +1,119 @@ +#pragma once +#include + +#include "win32_op.h" + +class GdiplusErrorHandler { +public: + void operator<<(Gdiplus::Status p_code) { + if (p_code != Gdiplus::Ok) { + throw pfc::exception(pfc::string_formatter() << "Gdiplus error (" << (unsigned) p_code << ")"); + } + } +}; + +class GdiplusScope { +public: + GdiplusScope() { + Gdiplus::GdiplusStartupInput input; + Gdiplus::GdiplusStartupOutput output; + GdiplusErrorHandler() << Gdiplus::GdiplusStartup(&m_token,&input,&output); + } + ~GdiplusScope() { + Gdiplus::GdiplusShutdown(m_token); + } + + PFC_CLASS_NOT_COPYABLE_EX(GdiplusScope); +private: + ULONG_PTR m_token; +}; + +static HBITMAP GdiplusLoadBitmap(UINT id, const TCHAR * resType, CSize size) { + using namespace Gdiplus; + try { + + + pfc::ptrholder_t resource = LoadResourceEx(core_api::get_my_instance(),MAKEINTRESOURCE(id),resType); + if (resource.is_empty()) throw pfc::exception_bug_check(); + + pfc::com_ptr_t stream; stream.attach( SHCreateMemStream((const BYTE*)resource->GetPointer(), resource->GetSize()) ); + if ( stream.is_empty() ) throw std::bad_alloc(); + + GdiplusErrorHandler EH; + pfc::ptrholder_t source = new Image(stream.get_ptr()); + + EH << source->GetLastStatus(); + pfc::ptrholder_t resized = new Bitmap(size.cx, size.cy, PixelFormat32bppARGB); + EH << resized->GetLastStatus(); + + { + pfc::ptrholder_t target = new Graphics(resized.get_ptr()); + EH << target->GetLastStatus(); + EH << target->SetInterpolationMode(InterpolationModeHighQuality); + EH << target->Clear(Color(0,0,0,0)); + EH << target->DrawImage(source.get_ptr(), Rect(0,0,size.cx,size.cy)); + } + + HBITMAP bmp = NULL; + EH << resized->GetHBITMAP(Gdiplus::Color::White, & bmp ); + return bmp; + } catch(...) { + PFC_ASSERT( !"Should not get here"); + return NULL; + } +} + +static HICON GdiplusLoadIcon(UINT id, const TCHAR * resType, CSize size) { + using namespace Gdiplus; + try { + + + pfc::ptrholder_t resource = LoadResourceEx(core_api::get_my_instance(),MAKEINTRESOURCE(id),resType); + if (resource.is_empty()) throw pfc::exception_bug_check(); + + pfc::com_ptr_t stream; stream.attach( SHCreateMemStream((const BYTE*)resource->GetPointer(), resource->GetSize()) ); + if (stream.is_empty()) throw std::bad_alloc(); + + GdiplusErrorHandler EH; + pfc::ptrholder_t source = new Image(stream.get_ptr()); + + EH << source->GetLastStatus(); + pfc::ptrholder_t resized = new Bitmap(size.cx, size.cy, PixelFormat32bppARGB); + EH << resized->GetLastStatus(); + + { + pfc::ptrholder_t target = new Graphics(resized.get_ptr()); + EH << target->GetLastStatus(); + EH << target->SetInterpolationMode(InterpolationModeHighQuality); + EH << target->Clear(Color(0,0,0,0)); + EH << target->DrawImage(source.get_ptr(), Rect(0,0,size.cx,size.cy)); + } + + HICON icon = NULL; + EH << resized->GetHICON(&icon); + return icon; + } catch(...) { + PFC_ASSERT( !"Should not get here"); + return NULL; + } +} +static HICON GdiplusLoadPNGIcon(UINT id, CSize size) {return GdiplusLoadIcon(id, _T("PNG"), size);} + +static HICON LoadPNGIcon(UINT id, CSize size) { + GdiplusScope scope; + return GdiplusLoadPNGIcon(id, size); +} + +static void GdiplusLoadButtonPNG(CIcon & icon, HWND btn_, UINT image) { + CButton btn(btn_); + if (icon == NULL) { + CRect client; WIN32_OP_D( btn.GetClientRect(client) ); + CSize size = client.Size(); + int v = MulDiv(pfc::min_t(size.cx, size.cy), 3, 4); + if (v < 8) v = 8; + icon = GdiplusLoadPNGIcon(image, CSize(v,v)); + } + btn.SetIcon(icon); +} + +#pragma comment(lib, "gdiplus.lib") diff --git a/foobar2000/helpers/helpers.h b/foobar2000/helpers/helpers.h index 83f947c..a4e62ab 100644 --- a/foobar2000/helpers/helpers.h +++ b/foobar2000/helpers/helpers.h @@ -13,6 +13,7 @@ #include "cue_parser.h" #include "text_file_loader.h" #include "file_list_helper.h" +#include "listview_helper.h" #include "stream_buffer_helper.h" #include "file_info_const_impl.h" #include "dynamic_bitrate_helper.h" @@ -28,6 +29,8 @@ #include "metadb_io_hintlist.h" #include "meta_table_builder.h" #include "icon_remapping_wildcard.h" +#include "clipboard.h" +#include "IDataObjectUtils.h" #include "CallForwarder.h" #include "playlist_position_reference_tracker.h" #include "ThreadUtils.h" @@ -37,5 +40,7 @@ #include "ProfileCache.h" #include "file_win32_wrapper.h" #include "fullFileBuffer.h" +#include "CPowerRequest.h" #include "writer_wav.h" +#include "TypeFind.h" #include "readers.h" \ No newline at end of file diff --git a/foobar2000/helpers/image_load_save.cpp b/foobar2000/helpers/image_load_save.cpp deleted file mode 100644 index 29f3b02..0000000 --- a/foobar2000/helpers/image_load_save.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include "StdAfx.h" -#include "image_load_save.h" -#include -#include "../SDK/imageLoaderLite.h" - -namespace fb2k { - bool imageSaveDialog(album_art_data_ptr content, HWND wndParent, const char* initDir, bool bAsync) { - pfc::string8 fileTypes = "All files|*.*"; - pfc::string8 ext; - - try { - auto info = fb2k::imageLoaderLite::get()->getInfo(content); - if (info.formatName) { - pfc::string8 nameCapitalized = pfc::stringToUpper( info.formatName ); - ext = pfc::stringToLower( info.formatName ); - if (nameCapitalized == "WEBP") nameCapitalized = "WebP"; - pfc::string8 extmask; - if (ext == "jpeg") { - ext = "jpg"; - extmask = "*.jpg;*.jpeg"; - } else { - extmask << "*." << ext; - } - fileTypes.reset(); - fileTypes << nameCapitalized << " files|" << extmask; - } - } catch (...) {} - pfc::string8 fn; - - if (!uGetOpenFileName(wndParent, fileTypes, 0, ext.length() > 0 ? ext.c_str() : nullptr, "Export picture file", initDir, fn, TRUE)) return false; - - auto bErrord = std::make_shared(false); - auto work = [content, fn, bErrord] { - try { - auto f = fileOpenWriteNew(fn, fb2k::noAbort, 0.5); - f->write(content->get_ptr(), content->get_size(), fb2k::noAbort); - } catch(std::exception const & e) { - * bErrord = true; - pfc::string8 msg; - msg << "Image file could not be written: " << e; - fb2k::inMainThread([msg] { - popup_message::g_show(msg, "Information"); - }); - } - }; - if (bAsync) { - fb2k::splitTask(work); - return true; - } else { - work(); - return ! *bErrord; - } - } - - bool imageLoadDialog(pfc::string_base& outFN, HWND wndParent, const char* initDir) { - return !!uGetOpenFileName(wndParent, FB2K_GETOPENFILENAME_PICTUREFILES_ALL, 0, nullptr, "Import picture file", initDir, outFN, FALSE); - } - album_art_data::ptr imageLoadDialog(HWND wndParent, const char* initDir) { - album_art_data::ptr ret; - pfc::string8 fn; - if (imageLoadDialog(fn, wndParent, initDir)) { - try { - ret = readPictureFile(fn, fb2k::noAbort); - } catch (std::exception const& e) { - popup_message::g_show(PFC_string_formatter() << "Image file could not be read: " << e, "Information"); - } - } - return ret; - } - - album_art_data_ptr readPictureFile(const char* p_path, abort_callback& p_abort) { - PFC_ASSERT(p_path != nullptr); - PFC_ASSERT(*p_path != 0); - p_abort.check(); - - // Pointless, not a media file, path often from openfiledialog and not canonical - // file_lock_ptr lock = file_lock_manager::get()->acquire_read(p_path, p_abort); - - file_ptr l_file; - filesystem::g_open_timeout(l_file, p_path, filesystem::open_mode_read, 0.5, p_abort); - service_ptr_t instance = new service_impl_t(); - t_filesize size = l_file->get_size_ex(p_abort); - if (size > 1024 * 1024 * 64) throw std::runtime_error("File too large"); - instance->from_stream(l_file.get_ptr(), (t_size)size, p_abort); - return instance; - } - -} \ No newline at end of file diff --git a/foobar2000/helpers/image_load_save.h b/foobar2000/helpers/image_load_save.h deleted file mode 100644 index 7b71bf3..0000000 --- a/foobar2000/helpers/image_load_save.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -namespace fb2k { - bool imageLoadDialog( pfc::string_base & outFN, HWND wndParent, const char * initDir ); - - album_art_data::ptr imageLoadDialog( HWND wndParent, const char * initDir ); - - //! bAllowAsync: run file writing offthread. In such case the caller will not be made aware if writing failed. \n - //! Error popup is shown if actual file writing fails. - bool imageSaveDialog(album_art_data_ptr content, HWND wndParent, const char * initDir , bool bAllowAsync = true ); - - album_art_data::ptr readPictureFile( const char * path, abort_callback & a); -} \ No newline at end of file diff --git a/foobar2000/helpers/inplace_edit.cpp b/foobar2000/helpers/inplace_edit.cpp deleted file mode 100644 index 41d6eb9..0000000 --- a/foobar2000/helpers/inplace_edit.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "stdafx.h" -#include "inplace_edit.h" - -// Functionality moved to libPPUI - -namespace InPlaceEdit { - static reply_t wrapCN( completion_notify::ptr cn ) { - return [cn](unsigned code) { cn->on_completion(code); }; - } - HWND Start(HWND p_parentwnd, const RECT & p_rect, bool p_multiline, pfc::rcptr_t p_content, completion_notify_ptr p_notify) { - return Start(p_parentwnd, p_rect, p_multiline, p_content, wrapCN(p_notify) ); - } - - HWND StartEx(HWND p_parentwnd, const RECT & p_rect, unsigned p_flags, pfc::rcptr_t p_content, completion_notify_ptr p_notify, IUnknown * ACData, DWORD ACOpts ) { - return StartEx(p_parentwnd, p_rect, p_flags, p_content, wrapCN(p_notify), ACData, ACOpts ); - } - - void Start_FromListView(HWND p_listview, unsigned p_item, unsigned p_subitem, unsigned p_linecount, pfc::rcptr_t p_content, completion_notify_ptr p_notify) { - Start_FromListView(p_listview,p_item, p_subitem, p_linecount, p_content, wrapCN(p_notify) ); - } - void Start_FromListViewEx(HWND p_listview, unsigned p_item, unsigned p_subitem, unsigned p_linecount, unsigned p_flags, pfc::rcptr_t p_content, completion_notify_ptr p_notify) { - Start_FromListViewEx(p_listview, p_item, p_subitem, p_linecount, p_flags, p_content, wrapCN(p_notify) ); - } - -} \ No newline at end of file diff --git a/foobar2000/helpers/inplace_edit.h b/foobar2000/helpers/inplace_edit.h deleted file mode 100644 index 5d72bcb..0000000 --- a/foobar2000/helpers/inplace_edit.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include - -namespace InPlaceEdit { - - HWND Start(HWND p_parentwnd,const RECT & p_rect,bool p_multiline,pfc::rcptr_t p_content,completion_notify_ptr p_notify); - - HWND StartEx(HWND p_parentwnd,const RECT & p_rect,unsigned p_flags,pfc::rcptr_t p_content,completion_notify_ptr p_notify, IUnknown * ACData = NULL, DWORD ACOpts = 0); - - void Start_FromListView(HWND p_listview,unsigned p_item,unsigned p_subitem,unsigned p_linecount,pfc::rcptr_t p_content,completion_notify_ptr p_notify); - void Start_FromListViewEx(HWND p_listview,unsigned p_item,unsigned p_subitem,unsigned p_linecount,unsigned p_flags,pfc::rcptr_t p_content,completion_notify_ptr p_notify); -} diff --git a/foobar2000/helpers/input_helper_cue.cpp b/foobar2000/helpers/input_helper_cue.cpp deleted file mode 100644 index 02ce69e..0000000 --- a/foobar2000/helpers/input_helper_cue.cpp +++ /dev/null @@ -1,221 +0,0 @@ -#include "stdafx.h" -#include "input_helper_cue.h" -#include "../SDK/mem_block_container.h" - - -namespace { - class input_dec_binary : public input_decoder_v2 { - enum { - m_rate = 44100, - m_bps = 16, - m_channels = 2, - m_channelMask = audio_chunk::channel_config_stereo, - m_sampleBytes = (m_bps/8)*m_channels, - m_readAtOnce = 588, - m_readAtOnceBytes = m_readAtOnce * m_sampleBytes - }; - public: - input_dec_binary( file::ptr f ) : m_file(f) {} - t_uint32 get_subsong_count() override {return 0;} - t_uint32 get_subsong(t_uint32 p_index) override {return 0;} - - void get_info(t_uint32 p_subsong,file_info & p_info,abort_callback & p_abort) override { - p_info.reset(); - p_info.info_set_int("samplerate", m_rate); - p_info.info_set_int("channels", m_channels); - p_info.info_set_int("bitspersample", m_bps); - p_info.info_set("encoding","lossless"); - p_info.info_set_bitrate((m_bps * m_channels * m_rate + 500 /* rounding for bps to kbps*/ ) / 1000 /* bps to kbps */); - p_info.info_set("codec", "PCM"); - - try { - auto stats = get_file_stats(p_abort); - if ( stats.m_size != filesize_invalid ) { - p_info.set_length( audio_math::samples_to_time( stats.m_size / 4, 44100 ) ); - } - } catch(exception_io) {} - } - - - t_filestats get_file_stats(abort_callback & p_abort) override { - return m_file->get_stats(p_abort); - } - void initialize(t_uint32 p_subsong,unsigned p_flags,abort_callback & p_abort) override { - m_file->reopen( p_abort ); - } - bool run(audio_chunk & p_chunk,abort_callback & p_abort) override { - mem_block_container_impl stfu; - return run_raw(p_chunk, stfu, p_abort); - } - bool run_raw(audio_chunk & out, mem_block_container & outRaw, abort_callback & abort) override { - size_t bytes = m_readAtOnceBytes; - outRaw.set_size( bytes ); - size_t got = m_file->read(outRaw.get_ptr(), bytes, abort); - got -= got % m_sampleBytes; - if ( got == 0 ) return false; - if ( got < bytes ) outRaw.set_size( got ); - out.set_data_fixedpoint_signed( outRaw.get_ptr(), got, m_rate, m_channels, m_bps, m_channelMask); - return true; - } - void seek(double p_seconds,abort_callback & p_abort) override { - m_file->seek( audio_math::time_to_samples( p_seconds, m_rate ) * m_sampleBytes, p_abort ); - } - bool can_seek() override { - return m_file->can_seek(); - } - bool get_dynamic_info(file_info & p_out, double & p_timestamp_delta) override {return false;} - bool get_dynamic_info_track(file_info & p_out, double & p_timestamp_delta) override {return false;} - void on_idle(abort_callback & p_abort) override {} - void set_logger(event_logger::ptr ptr) override {} - private: - const file::ptr m_file; - }; -} - - -void input_helper_cue::get_info_binary( const char * path, file_info & out, abort_callback & abort ) { - auto f = fileOpenReadExisting( path, abort ); - auto obj = fb2k::service_new< input_dec_binary > ( f ); - obj->get_info( 0, out, abort ); -} - -void input_helper_cue::open(service_ptr_t p_filehint,const playable_location & p_location,unsigned p_flags,abort_callback & p_abort,double p_start,double p_length, bool binary) { - p_abort.check(); - - m_start = p_start; - m_position = 0; - m_dynamic_info_trigger = false; - m_dynamic_info_track_trigger = false; - - if ( binary ) { - { - const char * path = p_location.get_path(); - auto f = fileOpenReadExisting( path, p_abort ); - auto obj = fb2k::service_new< input_dec_binary > ( f ); - - m_input.attach( obj, path ); - m_input.open_decoding( 0, p_flags, p_abort ); - } - } else { - m_input.open(p_filehint,p_location,p_flags,p_abort,true,true); - } - - - if (!m_input.can_seek()) throw exception_io_object_not_seekable(); - - if (m_start > 0) { - m_input.seek(m_start,p_abort); - } - - if (p_length > 0) { - m_length = p_length; - } else { - file_info_impl temp; - m_input.get_info(0,temp,p_abort); - double ref_length = temp.get_length(); - if (ref_length <= 0) throw exception_io_data(); - m_length = ref_length - m_start + p_length /* negative or zero */; - if (m_length <= 0) throw exception_io_data(); - } -} - -void input_helper_cue::close() {m_input.close();} -bool input_helper_cue::is_open() {return m_input.is_open();} - -bool input_helper_cue::_m_input_run(audio_chunk & p_chunk, mem_block_container * p_raw, abort_callback & p_abort) { - if (p_raw == NULL) { - return m_input.run(p_chunk, p_abort); - } else { - return m_input.run_raw(p_chunk, *p_raw, p_abort); - } -} -bool input_helper_cue::_run(audio_chunk & p_chunk, mem_block_container * p_raw, abort_callback & p_abort) { - p_abort.check(); - - if (m_length > 0) { - if (m_position >= m_length) return false; - - if (!_m_input_run(p_chunk, p_raw, p_abort)) return false; - - m_dynamic_info_trigger = true; - m_dynamic_info_track_trigger = true; - - t_uint64 max = (t_uint64)audio_math::time_to_samples(m_length - m_position, p_chunk.get_sample_rate()); - if (max == 0) - {//handle rounding accidents, this normally shouldn't trigger - m_position = m_length; - return false; - } - - t_size samples = p_chunk.get_sample_count(); - if ((t_uint64)samples > max) - { - p_chunk.set_sample_count((unsigned)max); - if (p_raw != NULL) { - const t_size rawSize = p_raw->get_size(); - PFC_ASSERT(rawSize % samples == 0); - p_raw->set_size((t_size)((t_uint64)rawSize * max / samples)); - } - m_position = m_length; - } - else - { - m_position += p_chunk.get_duration(); - } - return true; - } - else - { - if (!_m_input_run(p_chunk, p_raw, p_abort)) return false; - m_position += p_chunk.get_duration(); - return true; - } -} -bool input_helper_cue::run_raw(audio_chunk & p_chunk, mem_block_container & p_raw, abort_callback & p_abort) { - return _run(p_chunk, &p_raw, p_abort); -} - -bool input_helper_cue::run(audio_chunk & p_chunk, abort_callback & p_abort) { - return _run(p_chunk, NULL, p_abort); -} - -void input_helper_cue::seek(double p_seconds, abort_callback & p_abort) -{ - m_dynamic_info_trigger = false; - m_dynamic_info_track_trigger = false; - if (m_length <= 0 || p_seconds < m_length) { - m_input.seek(p_seconds + m_start, p_abort); - m_position = p_seconds; - } - else { - m_position = m_length; - } -} - -bool input_helper_cue::can_seek() { return true; } - -void input_helper_cue::on_idle(abort_callback & p_abort) { m_input.on_idle(p_abort); } - -bool input_helper_cue::get_dynamic_info(file_info & p_out, double & p_timestamp_delta) { - if (m_dynamic_info_trigger) { - m_dynamic_info_trigger = false; - return m_input.get_dynamic_info(p_out, p_timestamp_delta); - } - else { - return false; - } -} - -bool input_helper_cue::get_dynamic_info_track(file_info & p_out, double & p_timestamp_delta) { - if (m_dynamic_info_track_trigger) { - m_dynamic_info_track_trigger = false; - return m_input.get_dynamic_info_track(p_out, p_timestamp_delta); - } - else { - return false; - } -} - -const char * input_helper_cue::get_path() const { return m_input.get_path(); } - -void input_helper_cue::get_info(t_uint32 p_subsong, file_info & p_info, abort_callback & p_abort) { m_input.get_info(p_subsong, p_info, p_abort); } diff --git a/foobar2000/helpers/input_helper_cue.h b/foobar2000/helpers/input_helper_cue.h deleted file mode 100644 index 10d9916..0000000 --- a/foobar2000/helpers/input_helper_cue.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include "input_helpers.h" - - -class input_helper_cue { -public: - void open(service_ptr_t p_filehint,const playable_location & p_location,unsigned p_flags,abort_callback & p_abort,double p_start,double p_length, bool binary = false); - static void get_info_binary( const char * path, file_info & out, abort_callback & abort ); - - void close(); - bool is_open(); - bool run(audio_chunk & p_chunk,abort_callback & p_abort); - bool run_raw(audio_chunk & p_chunk, mem_block_container & p_raw, abort_callback & p_abort); - void seek(double seconds,abort_callback & p_abort); - bool can_seek(); - void on_idle(abort_callback & p_abort); - bool get_dynamic_info(file_info & p_out,double & p_timestamp_delta); - bool get_dynamic_info_track(file_info & p_out,double & p_timestamp_delta); - void set_logger(event_logger::ptr ptr) {m_input.set_logger(ptr);} - - const char * get_path() const; - - void get_info(t_uint32 p_subsong,file_info & p_info,abort_callback & p_abort); - -private: - bool _run(audio_chunk & p_chunk, mem_block_container * p_raw, abort_callback & p_abort); - bool _m_input_run(audio_chunk & p_chunk, mem_block_container * p_raw, abort_callback & p_abort); - input_helper m_input; - double m_start,m_length,m_position; - bool m_dynamic_info_trigger,m_dynamic_info_track_trigger; - bool m_binary; -}; diff --git a/foobar2000/helpers/input_helpers.cpp b/foobar2000/helpers/input_helpers.cpp index f8ea6ee..cf77505 100644 --- a/foobar2000/helpers/input_helpers.cpp +++ b/foobar2000/helpers/input_helpers.cpp @@ -5,7 +5,6 @@ #include "file_list_helper.h" #include "fileReadAhead.h" - input_helper::ioFilter_t input_helper::ioFilter_full_buffer(t_filesize val ) { if (val == 0) return nullptr; return [val] ( file_ptr & f, const char * path, abort_callback & aborter) { @@ -78,44 +77,34 @@ bool input_helper::need_file_reopen(const char * newPath) const { bool input_helper::open_path(const char * path, abort_callback & abort, decodeOpen_t const & other) { abort.check(); - m_logger = other.m_logger; - - if (!need_file_reopen(path)) { - if ( other.m_logger.is_valid() ) { - input_decoder_v2::ptr v2; - if (m_input->service_query_t(v2)) v2->set_logger(other.m_logger); - } - return false; - } + if (!need_file_reopen(path)) return false; m_input.release(); - service_ptr_t l_file = other.m_hint; - fileOpenTools(l_file, path, other.m_ioFilters, abort); +service_ptr_t l_file = other.m_hint; +fileOpenTools(l_file, path, other.m_ioFilters, abort); - TRACK_CODE("input_entry::g_open_for_decoding", - m_input ^= input_entry::g_open(input_decoder::class_guid, l_file, path, m_logger, abort, other.m_from_redirect ); - ); +TRACK_CODE("input_entry::g_open_for_decoding", + input_entry::g_open_for_decoding(m_input, l_file, path, abort, other.m_from_redirect) +); #ifndef FOOBAR2000_MODERN - if (!other.m_skip_hints) { - try { - metadb_io::get()->hint_reader(m_input.get_ptr(), path, abort); - } - catch (exception_io_data) { - //Don't fail to decode when this barfs, might be barfing when reading info from another subsong than the one we're trying to decode etc. - m_input.release(); - if (l_file.is_valid()) l_file->reopen(abort); - TRACK_CODE("input_entry::g_open_for_decoding", - m_input ^= input_entry::g_open(input_decoder::class_guid, l_file, path, m_logger, abort, other.m_from_redirect); - ); - } +if (!other.m_skip_hints) { + try { + metadb_io::get()->hint_reader(m_input.get_ptr(), path, abort); } + catch (exception_io_data) { + //Don't fail to decode when this barfs, might be barfing when reading info from another subsong than the one we're trying to decode etc. + m_input.release(); + if (l_file.is_valid()) l_file->reopen(abort); + TRACK_CODE("input_entry::g_open_for_decoding", + input_entry::g_open_for_decoding(m_input, l_file, path, abort, other.m_from_redirect) + ); + } +} #endif - if (other.m_shim) m_input = other.m_shim(m_input, path, abort); - - m_path = path; - return true; +m_path = path; +return true; } void input_helper::open_decoding(t_uint32 subsong, t_uint32 flags, abort_callback & p_abort) { @@ -125,18 +114,11 @@ void input_helper::open_decoding(t_uint32 subsong, t_uint32 flags, abort_callbac void input_helper::open(const playable_location & location, abort_callback & abort, decodeOpen_t const & other) { open_path(location.get_path(), abort, other); - if (other.m_setSampleRate != 0) { - this->extended_param(input_params::set_preferred_sample_rate, other.m_setSampleRate, nullptr, 0); - } + set_logger(other.m_logger); open_decoding(location.get_subsong(), other.m_flags, abort); } -void input_helper::attach(input_decoder::ptr dec, const char * path) { - m_input = dec; - m_path = path; -} - void input_helper::open(service_ptr_t p_filehint, const playable_location & p_location, unsigned p_flags, abort_callback & p_abort, bool p_from_redirect, bool p_skip_hints) { decodeOpen_t o; o.m_hint = p_filehint; @@ -167,7 +149,6 @@ bool input_helper::flush_on_pause() { void input_helper::set_logger(event_logger::ptr ptr) { - m_logger = ptr; input_decoder_v2::ptr v2; if (m_input->service_query_t(v2)) v2->set_logger(ptr); } @@ -189,11 +170,7 @@ void input_helper::seek(double seconds, abort_callback & p_abort) { bool input_helper::can_seek() { return m_input->can_seek(); } - -bool input_helper::query_position( double & val ) { - return extended_param(input_params::query_position, 0, &val, sizeof(val) ) != 0; -} - +#ifdef FOOBAR2000_MODERN size_t input_helper::extended_param(const GUID & type, size_t arg1, void * arg2, size_t arg2size) { input_decoder_v4::ptr v4; if (v4 &= m_input) { @@ -201,14 +178,17 @@ size_t input_helper::extended_param(const GUID & type, size_t arg1, void * arg2, } return 0; } +#endif input_helper::decodeInfo_t input_helper::decode_info() { decodeInfo_t ret = {}; if (m_input.is_valid()) { ret.m_can_seek = can_seek(); ret.m_flush_on_pause = flush_on_pause(); +#ifdef FOOBAR2000_MODERN if (ret.m_can_seek) { ret.m_seeking_expensive = extended_param(input_params::seeking_expensive, 0, nullptr, 0) != 0; } +#endif } return ret; } @@ -292,7 +272,7 @@ bool dead_item_filter::run(const pfc::list_base_const_t & p_l valid_handles.sort_by_pointer(); for(t_size listidx=0;listidx & } void input_info_read_helper::open(const char * p_path,abort_callback & p_abort) { - if (m_input.is_empty() || playable_location::path_compare(m_path,p_path) != 0) + if (m_input.is_empty() || metadb::path_compare(m_path,p_path) != 0) { TRACK_CODE("input_entry::g_open_for_info_read",input_entry::g_open_for_info_read(m_input,0,p_path,p_abort)); @@ -352,6 +332,142 @@ void input_info_read_helper::get_info_check(const playable_location & p_location + + +void input_helper_cue::open(service_ptr_t p_filehint,const playable_location & p_location,unsigned p_flags,abort_callback & p_abort,double p_start,double p_length) { + p_abort.check(); + + m_start = p_start; + m_position = 0; + m_dynamic_info_trigger = false; + m_dynamic_info_track_trigger = false; + + m_input.open(p_filehint,p_location,p_flags,p_abort,true,true); + + if (!m_input.can_seek()) throw exception_io_object_not_seekable(); + + if (m_start > 0) { + m_input.seek(m_start,p_abort); + } + + if (p_length > 0) { + m_length = p_length; + } else { + file_info_impl temp; + m_input.get_info(0,temp,p_abort); + double ref_length = temp.get_length(); + if (ref_length <= 0) throw exception_io_data(); + m_length = ref_length - m_start + p_length /* negative or zero */; + if (m_length <= 0) throw exception_io_data(); + } +} + +void input_helper_cue::close() {m_input.close();} +bool input_helper_cue::is_open() {return m_input.is_open();} + +bool input_helper_cue::_m_input_run(audio_chunk & p_chunk, mem_block_container * p_raw, abort_callback & p_abort) { + if (p_raw == NULL) { + return m_input.run(p_chunk, p_abort); + } else { + return m_input.run_raw(p_chunk, *p_raw, p_abort); + } +} +bool input_helper_cue::_run(audio_chunk & p_chunk, mem_block_container * p_raw, abort_callback & p_abort) { + p_abort.check(); + + if (m_length > 0) { + if (m_position >= m_length) return false; + +if (!_m_input_run(p_chunk, p_raw, p_abort)) return false; + +m_dynamic_info_trigger = true; +m_dynamic_info_track_trigger = true; + +t_uint64 max = (t_uint64)audio_math::time_to_samples(m_length - m_position, p_chunk.get_sample_rate()); +if (max == 0) +{//handle rounding accidents, this normally shouldn't trigger + m_position = m_length; + return false; +} + +t_size samples = p_chunk.get_sample_count(); +if ((t_uint64)samples > max) +{ + p_chunk.set_sample_count((unsigned)max); + if (p_raw != NULL) { + const t_size rawSize = p_raw->get_size(); + PFC_ASSERT(rawSize % samples == 0); + p_raw->set_size((t_size)((t_uint64)rawSize * max / samples)); + } + m_position = m_length; +} +else +{ + m_position += p_chunk.get_duration(); +} +return true; + } + else + { + if (!_m_input_run(p_chunk, p_raw, p_abort)) return false; + m_position += p_chunk.get_duration(); + return true; + } +} +bool input_helper_cue::run_raw(audio_chunk & p_chunk, mem_block_container & p_raw, abort_callback & p_abort) { + return _run(p_chunk, &p_raw, p_abort); +} + +bool input_helper_cue::run(audio_chunk & p_chunk, abort_callback & p_abort) { + return _run(p_chunk, NULL, p_abort); +} + +void input_helper_cue::seek(double p_seconds, abort_callback & p_abort) +{ + m_dynamic_info_trigger = false; + m_dynamic_info_track_trigger = false; + if (m_length <= 0 || p_seconds < m_length) { + m_input.seek(p_seconds + m_start, p_abort); + m_position = p_seconds; + } + else { + m_position = m_length; + } +} + +bool input_helper_cue::can_seek() { return true; } + +void input_helper_cue::on_idle(abort_callback & p_abort) { m_input.on_idle(p_abort); } + +bool input_helper_cue::get_dynamic_info(file_info & p_out, double & p_timestamp_delta) { + if (m_dynamic_info_trigger) { + m_dynamic_info_trigger = false; + return m_input.get_dynamic_info(p_out, p_timestamp_delta); + } + else { + return false; + } +} + +bool input_helper_cue::get_dynamic_info_track(file_info & p_out, double & p_timestamp_delta) { + if (m_dynamic_info_track_trigger) { + m_dynamic_info_track_trigger = false; + return m_input.get_dynamic_info_track(p_out, p_timestamp_delta); + } + else { + return false; + } +} + +const char * input_helper_cue::get_path() const { return m_input.get_path(); } + +void input_helper_cue::get_info(t_uint32 p_subsong, file_info & p_info, abort_callback & p_abort) { m_input.get_info(p_subsong, p_info, p_abort); } + + + + + + // openAudioData code namespace { @@ -361,7 +477,11 @@ namespace { void init(const playable_location & loc, input_helper::decodeOpen_t const & arg, abort_callback & aborter) { m_length = -1; m_lengthKnown = false; m_subsong = loc.get_subsong(); - m_decoder ^= input_entry::g_open( input_decoder::class_guid, arg.m_hint, loc.get_path(), arg.m_logger, aborter, arg.m_from_redirect); + input_entry::g_open_for_decoding(m_decoder, arg.m_hint, loc.get_path(), aborter, arg.m_from_redirect); + if (arg.m_logger.is_valid()) { + input_decoder_v2::ptr v2; + if ( v2 &= m_decoder ) v2->set_logger(arg.m_logger); + } m_seekable = ( arg.m_flags & input_flag_no_seeking ) == 0 && m_decoder->can_seek(); reopenDecoder(aborter); readChunk(aborter, true); @@ -558,4 +678,4 @@ openAudioData_t openAudioData(playable_location const & loc, bool bSeekable, fil oad.audioData = f; oad.audioSpec = f->get_spec(); return oad; -} +} \ No newline at end of file diff --git a/foobar2000/helpers/input_helpers.h b/foobar2000/helpers/input_helpers.h index 3253426..682dd5f 100644 --- a/foobar2000/helpers/input_helpers.h +++ b/foobar2000/helpers/input_helpers.h @@ -7,32 +7,29 @@ class input_helper { public: input_helper(); - typedef std::function shim_t; - typedef std::function< bool ( file::ptr &, const char *, abort_callback & ) > ioFilter_t; typedef std::list ioFilters_t; struct decodeInfo_t { bool m_flush_on_pause; bool m_can_seek; +#ifdef FOOBAR2000_MODERN bool m_seeking_expensive; +#endif }; struct decodeOpen_t { - bool m_from_redirect = false; - bool m_skip_hints = false; - unsigned m_flags = 0; - file::ptr m_hint; - unsigned m_setSampleRate = 0; - - ioFilters_t m_ioFilters; + decodeOpen_t() : m_from_redirect(), m_skip_hints(), m_flags() {} event_logger::ptr m_logger; - shim_t m_shim; + bool m_from_redirect; + bool m_skip_hints; + unsigned m_flags; + file::ptr m_hint; + ioFilters_t m_ioFilters; }; void open(service_ptr_t p_filehint,metadb_handle_ptr p_location,unsigned p_flags,abort_callback & p_abort,bool p_from_redirect = false,bool p_skip_hints = false); void open(service_ptr_t p_filehint,const playable_location & p_location,unsigned p_flags,abort_callback & p_abort,bool p_from_redirect = false,bool p_skip_hints = false); - void attach(input_decoder::ptr dec, const char * path); void open(const playable_location & location, abort_callback & abort, decodeOpen_t const & other); void open(metadb_handle_ptr location, abort_callback & abort, decodeOpen_t const & other) {this->open(location->get_location(), abort, other);} @@ -54,7 +51,9 @@ public: bool run_raw(audio_chunk & p_chunk, mem_block_container & p_raw, abort_callback & p_abort); void seek(double seconds,abort_callback & p_abort); bool can_seek(); +#ifdef FOOBAR2000_MODERN size_t extended_param( const GUID & type, size_t arg1, void * arg2, size_t arg2size); +#endif static ioFilter_t ioFilter_full_buffer(t_filesize val ); static ioFilter_t ioFilter_block_buffer(size_t val); static ioFilter_t ioFilter_remote_read_ahead( size_t val ); @@ -67,11 +66,6 @@ public: void set_pause(bool state); bool flush_on_pause(); - //! If this decoder has its own special position reporting, decoder-signaled logical decoding position will be returned. \n - //! Otherwise, position calculated from returned audio duration should be assumed. \n - //! Very few special-purpose decoders do this. - bool query_position( double & val ); - //! Retrieves path of currently open file. const char * get_path() const; @@ -88,7 +82,6 @@ private: void fileOpenTools(service_ptr_t & p_file,const char * p_path, ioFilters_t const & filters, abort_callback & p_abort); service_ptr_t m_input; pfc::string8 m_path; - event_logger::ptr m_logger; }; class NOVTABLE dead_item_filter : public abort_callback { @@ -112,6 +105,32 @@ private: +class input_helper_cue { +public: + void open(service_ptr_t p_filehint,const playable_location & p_location,unsigned p_flags,abort_callback & p_abort,double p_start,double p_length); + + void close(); + bool is_open(); + bool run(audio_chunk & p_chunk,abort_callback & p_abort); + bool run_raw(audio_chunk & p_chunk, mem_block_container & p_raw, abort_callback & p_abort); + void seek(double seconds,abort_callback & p_abort); + bool can_seek(); + void on_idle(abort_callback & p_abort); + bool get_dynamic_info(file_info & p_out,double & p_timestamp_delta); + bool get_dynamic_info_track(file_info & p_out,double & p_timestamp_delta); + void set_logger(event_logger::ptr ptr) {m_input.set_logger(ptr);} + + const char * get_path() const; + + void get_info(t_uint32 p_subsong,file_info & p_info,abort_callback & p_abort); + +private: + bool _run(audio_chunk & p_chunk, mem_block_container * p_raw, abort_callback & p_abort); + bool _m_input_run(audio_chunk & p_chunk, mem_block_container * p_raw, abort_callback & p_abort); + input_helper m_input; + double m_start,m_length,m_position; + bool m_dynamic_info_trigger,m_dynamic_info_track_trigger; +}; //! openAudioData return value, see openAudioData() struct openAudioData_t { diff --git a/foobar2000/helpers/input_logging.h b/foobar2000/helpers/input_logging.h deleted file mode 100644 index 13d5cc7..0000000 --- a/foobar2000/helpers/input_logging.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - - -class input_logging : public input_stubs { -public: - input_logging() { - set_logger(nullptr); - } - - event_logger_recorder::ptr log_record( std::function f ) { - auto rec = event_logger_recorder::create(); - { - pfc::vartoggle_t< event_logger::ptr > toggle( m_logger, rec ); - f(); - } - return rec; - } - - void set_logger( event_logger::ptr logger ) { - if ( logger.is_valid() ) { - m_haveCustomLogger = true; - m_logger = logger; - } else { - m_haveCustomLogger = false; - m_logger = new service_impl_t(); - } - } -protected: - event_logger::ptr m_logger; - bool m_haveCustomLogger = false; -}; - -#define FB2K_INPUT_LOG_STATUS(X) FB2K_LOG_STATUS(m_logger, X) -#define FB2K_INPUT_LOG_WARNING(X) FB2K_LOG_WARNING(m_logger, X) -#define FB2K_INPUT_LOG_ERROR(X) FB2K_LOG_ERROR(m_logger, X) diff --git a/libPPUI/listview_helper.cpp b/foobar2000/helpers/listview_helper.cpp similarity index 53% rename from libPPUI/listview_helper.cpp rename to foobar2000/helpers/listview_helper.cpp index b00882d..47cdf36 100644 --- a/libPPUI/listview_helper.cpp +++ b/foobar2000/helpers/listview_helper.cpp @@ -1,10 +1,9 @@ #include "stdafx.h" -#include "win32_utility.h" -#include "win32_op.h" +#ifdef FOOBAR2000_DESKTOP_WINDOWS + +#include "win32_misc.h" #include "listview_helper.h" -#include "CListViewCtrlEx.h" -#include "CHeaderCtrlEx.h" namespace listview_helper { @@ -20,7 +19,7 @@ namespace listview_helper { item.lParam = p_param; item.pszText = const_cast(os_string_temp.get_ptr()); - LRESULT ret = SendMessage(p_listview,LVM_INSERTITEM,0,(LPARAM)&item); + LRESULT ret = uSendMessage(p_listview,LVM_INSERTITEM,0,(LPARAM)&item); if (ret < 0) return ~0; else return (unsigned) ret; } @@ -55,8 +54,8 @@ namespace listview_helper { data.cx = rect.right; data.pszText = const_cast(os_string_temp.get_ptr()); - LRESULT ret = SendMessage(p_listview,LVM_INSERTCOLUMN,p_index,(LPARAM)&data); - if (ret < 0) return UINT_MAX; + LRESULT ret = uSendMessage(p_listview,LVM_INSERTCOLUMN,p_index,(LPARAM)&data); + if (ret < 0) return ~0; else return (unsigned) ret; } @@ -77,7 +76,7 @@ namespace listview_helper { item.iItem = p_index; item.iSubItem = p_column; item.pszText = const_cast(os_string_temp.get_ptr()); - return SendMessage(p_listview,LVM_SETITEM,0,(LPARAM)&item) ? true : false; + return uSendMessage(p_listview,LVM_SETITEM,0,(LPARAM)&item) ? true : false; } bool is_item_selected(HWND p_listview,unsigned p_index) @@ -86,7 +85,7 @@ namespace listview_helper { item.mask = LVIF_STATE; item.iItem = p_index; item.stateMask = LVIS_SELECTED; - if (!SendMessage(p_listview,LVM_GETITEM,0,(LPARAM)&item)) return false; + if (!uSendMessage(p_listview,LVM_GETITEM,0,(LPARAM)&item)) return false; return (item.state & LVIS_SELECTED) ? true : false; } @@ -114,7 +113,7 @@ namespace listview_helper { bool ensure_visible(HWND p_listview,unsigned p_index) { - return SendMessage(p_listview,LVM_ENSUREVISIBLE,p_index,FALSE) ? true : false; + return uSendMessage(p_listview,LVM_ENSUREVISIBLE,p_index,FALSE) ? true : false; } } @@ -153,132 +152,42 @@ void ListView_GetContextMenuPoint(HWND p_list,POINT p_coords,POINT & p_point,int } } +#if 0 +static bool ProbeColumn(HWND view, int index) { + LVCOLUMN col = {LVCF_ORDER}; + return !! ListView_GetColumn(view, index, &col); +} +int ListView_GetColumnCount(HWND listView) { + if (!ProbeColumn(listView, 0)) return 0; + int hi = 1; + for(;;) { + if (!ProbeColumn(listView, hi)) break; + hi <<= 1; + if (hi <= 0) { + PFC_ASSERT(!"Shouldn't get here!"); + return -1; + } + } + int lo = hi >> 1; + //lo is the highest known valid column, hi is the lowest known invalid, let's bsearch thru + while(lo + 1 < hi) { + PFC_ASSERT( lo < hi ); + const int mid = lo + (hi - lo) / 2; + PFC_ASSERT( lo < mid && mid < hi ); + if (ProbeColumn(listView, mid)) { + lo = mid; + } else { + hi = mid; + } + } + return hi; +} +#else int ListView_GetColumnCount(HWND listView) { HWND header = ListView_GetHeader(listView); PFC_ASSERT(header != NULL); return Header_GetItemCount(header); } +#endif -void ListView_FixContextMenuPoint(CListViewCtrl list, CPoint & coords) { - if (coords == CPoint(-1, -1)) { - int selWalk = -1; - CRect rcClient; WIN32_OP_D(list.GetClientRect(rcClient)); - for (;;) { - selWalk = list.GetNextItem(selWalk, LVNI_SELECTED); - if (selWalk < 0) { - CRect rc; - WIN32_OP_D(list.GetWindowRect(&rc)); - coords = rc.CenterPoint(); - return; - } - CRect rcItem, rcVisible; - WIN32_OP_D(list.GetItemRect(selWalk, &rcItem, LVIR_BOUNDS)); - if (rcVisible.IntersectRect(rcItem, rcClient)) { - coords = rcVisible.CenterPoint(); - WIN32_OP_D(list.ClientToScreen(&coords)); - return; - } - } - } -} - -unsigned CListViewCtrlEx::GetColunnCount() { - return (unsigned) ListView_GetColumnCount( *this ); -} -unsigned CListViewCtrlEx::AddColumnEx(const wchar_t * name, unsigned widthDLU) { - return InsertColumnEx( GetColunnCount(), name, widthDLU ); -} -unsigned CListViewCtrlEx::InsertColumnEx(unsigned index, const wchar_t * name, unsigned widthDLU) { - - RECT rect = { 0,0,(LONG)widthDLU,0 }; - MapDialogRect(GetParent(), &rect); - - LVCOLUMN data = {}; - data.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_FMT; - data.fmt = LVCFMT_LEFT; - data.cx = rect.right; - data.pszText = const_cast(name); - - auto ret = this->InsertColumn(index, & data ); - if (ret < 0) return UINT_MAX; - else return (unsigned)ret; -} - -void CListViewCtrlEx::FixContextMenuPoint(CPoint & pt) { - ListView_FixContextMenuPoint(*this, pt); -} - - - -unsigned CListViewCtrlEx::InsertString(unsigned index, const wchar_t * str) { - LVITEM item = {}; - - item.mask = LVIF_TEXT; - item.iItem = index; - item.pszText = const_cast(str); - - auto ret = InsertItem(&item); - if ( ret < 0 ) return UINT_MAX; - else return (unsigned) ret; -} -unsigned CListViewCtrlEx::InsertString8(unsigned index, const char * str) { - return InsertString(index, pfc::stringcvt::string_os_from_utf8( str ) ); -} -unsigned CListViewCtrlEx::AddString(const wchar_t * str) { - return InsertString(GetItemCount(), str); -} -unsigned CListViewCtrlEx::AddString8(const char * str) { - return AddString(pfc::stringcvt::string_os_from_utf8( str ) ); -} -void CListViewCtrlEx::SetItemText(unsigned iItem, unsigned iSubItem, const wchar_t * str) { - LVITEM item = {}; - item.mask = LVIF_TEXT; - item.iItem = iItem; - item.iSubItem = iSubItem; - item.pszText = const_cast(str); - SetItem(&item); -} -void CListViewCtrlEx::SetItemText8(unsigned item, unsigned subItem, const char * str) { - SetItemText( item, subItem, pfc::stringcvt::string_os_from_utf8( str ) ); -} - - -DWORD CHeaderCtrlEx::GetItemFormat(int iItem) { - HDITEM item = {}; - item.mask = HDI_FORMAT; - if (!this->GetItem(iItem, &item)) return 0; - return item.fmt; -} -void CHeaderCtrlEx::SetItemFormat(int iItem, DWORD flags) { - HDITEM item = {}; - item.mask = HDI_FORMAT; - item.fmt = flags; - SetItem(iItem, &item); -} - -void CHeaderCtrlEx::SetItemSort(int iItem, int direction) { - DWORD fmtWas = GetItemFormat(iItem); - DWORD fmt = fmtWas & ~(HDF_SORTDOWN | HDF_SORTUP); - if (direction > 0) fmt |= HDF_SORTDOWN; - else if (direction < 0) fmt |= HDF_SORTUP; - if (fmt != fmtWas) SetItemFormat(iItem, fmt); -} - -void CHeaderCtrlEx::SetSingleItemSort(int iItem, int direction) { - const int total = GetItemCount(); - for (int walk = 0; walk < total; ++walk) { - SetItemSort(walk, walk == iItem ? direction : 0); - } -} - -void CHeaderCtrlEx::ClearSort() { - SetSingleItemSort(-1,0); -} - -int CListViewCtrlEx::AddGroup(int iGroupID, const wchar_t * header) { - LVGROUP g = { sizeof(g) }; - g.mask = LVGF_HEADER | LVGF_GROUPID; - g.pszHeader = const_cast( header ); - g.iGroupId = iGroupID; - return __super::AddGroup(&g); -} +#endif // FOOBAR2000_DESKTOP_WINDOWS diff --git a/libPPUI/listview_helper.h b/foobar2000/helpers/listview_helper.h similarity index 96% rename from libPPUI/listview_helper.h rename to foobar2000/helpers/listview_helper.h index 1e115dd..1876b50 100644 --- a/libPPUI/listview_helper.h +++ b/foobar2000/helpers/listview_helper.h @@ -1,5 +1,7 @@ #pragma once +#ifdef FOOBAR2000_DESKTOP_WINDOWS + namespace listview_helper { unsigned insert_item(HWND p_listview,unsigned p_index,const char * p_name,LPARAM p_param);//returns index of new item on success, infinite on failure @@ -46,4 +48,4 @@ void ListView_GetContextMenuPoint(HWND p_list,POINT p_coords,POINT & p_point,int int ListView_GetColumnCount(HWND listView); -void ListView_FixContextMenuPoint(CListViewCtrl list, CPoint & coords); \ No newline at end of file +#endif // FOOBAR2000_DESKTOP_WINDOWS \ No newline at end of file diff --git a/foobar2000/helpers/metadb_handle_set.h b/foobar2000/helpers/metadb_handle_set.h deleted file mode 100644 index 3543d35..0000000 --- a/foobar2000/helpers/metadb_handle_set.h +++ /dev/null @@ -1,71 +0,0 @@ -#pragma once -#include -class metadb_handle; - -// Roughly same as pfc::avltree_t or std::set, but optimized for use with large amounts of items -class metadb_handle_set { -public: - metadb_handle_set() {} - template - bool add_item_check(ptr_t const & item) { return add_item_check_(&*item); } - template - bool remove_item(ptr_t const & item) { return remove_item_(&*item); } - - bool add_item_check_(metadb_handle * p) { - bool rv = m_content.insert(p).second; - if (rv) p->service_add_ref(); - return rv; - } - bool remove_item_(metadb_handle * p) { - bool rv = m_content.erase(p) != 0; - if (rv) p->service_release(); - return rv; - } - - size_t get_count() const { - return m_content.size(); - } - template - bool contains(ptr_t const & item) const { - return m_content.count(&*item) != 0; - } - template - bool have_item(ptr_t const & item) const { - return m_content.count(&*item) != 0; - } - void operator+=(metadb_handle::ptr const & item) { - add_item_check_(item.get_ptr()); - } - void operator-=(metadb_handle::ptr const & item) { - remove_item_(item.get_ptr()); - } - void operator+=(metadb_handle::ptr && item) { - auto p = item.detach(); - bool added = m_content.insert(p).second; - if (!added) p->service_release(); - } - void remove_all() { - for (auto iter = m_content.begin(); iter != m_content.end(); ++iter) { - metadb_handle * p = (*iter); - p->service_release(); - } - m_content.clear(); - } - template - void enumerate(callback_t & cb) const { - for (auto iter = m_content.begin(); iter != m_content.end(); ++iter) { - cb(*iter); - } - } - typedef std::set impl_t; - typedef impl_t::const_iterator const_iterator; - const_iterator begin() const { return m_content.begin(); } - const_iterator end() const { return m_content.end(); } -private: - - std::set m_content; - -private: - metadb_handle_set(const metadb_handle_set &) = delete; - void operator=(const metadb_handle_set&) = delete; -}; diff --git a/foobar2000/helpers/packet_decoder_aac_common.cpp b/foobar2000/helpers/packet_decoder_aac_common.cpp index 4b987fb..c3b0990 100644 --- a/foobar2000/helpers/packet_decoder_aac_common.cpp +++ b/foobar2000/helpers/packet_decoder_aac_common.cpp @@ -3,78 +3,8 @@ #include "packet_decoder_aac_common.h" #include "../SDK/filesystem_helper.h" -#include "bitreader_helper.h" -size_t packet_decoder_aac_common::skipADTSHeader( const uint8_t * data,size_t size ) { - if ( size < 7 ) throw exception_io_data(); - PFC_ASSERT( bitreader_helper::extract_int(data, 0, 12) == 0xFFF); - if (bitreader_helper::extract_bit(data, 12+1+2)) { - return 7; // ABSENT flag - } - if (size < 9) throw exception_io_data(); - return 9; -} -pfc::array_t packet_decoder_aac_common::parseDecoderSetup( const GUID & p_owner,t_size p_param1,const void * p_param2,t_size p_param2size) { - - if ( p_owner == owner_ADTS ) { - pfc::array_t ret; - ret.resize( 2 ); - ret[0] = 0; ret[1] = 0; - // ret: - // 5 bits AOT - // 4 bits freqindex - // 4 bits channelconfig - - // source: - // 12 bits 0xFFF - // 4 bits disregard - // 2 bits AOT-1 @ 16 - // 4 bits freqindex @ 18 - // 1 bit disregard - // 3 bits channelconfig @ 23 - // 26 bits total, 4 bytes minimum - - - if ( p_param2size < 4 ) throw exception_io_data(); - const uint8_t * source = (const uint8_t*) p_param2; - if ( bitreader_helper::extract_int(source, 0, 12) != 0xFFF ) throw exception_io_data(); - size_t aot = bitreader_helper::extract_int(source, 16, 2) + 1; - if ( aot >= 31 ) throw exception_io_data(); - size_t freqindex = bitreader_helper::extract_int(source, 18, 4); - if ( freqindex > 12 ) throw exception_io_data(); - size_t channelconfig = bitreader_helper::extract_bits( source, 23, 3); - - bitreader_helper::write_int(ret.get_ptr(), 0, 5, aot); - bitreader_helper::write_int(ret.get_ptr(), 5, 4, freqindex); - bitreader_helper::write_int(ret.get_ptr(), 9, 4, channelconfig); - return ret; - } else if ( p_owner == owner_ADIF ) { - // bah - } else if ( p_owner == owner_MP4 ) - { - if ( p_param1 == 0x40 || p_param1 == 0x66 || p_param1 == 0x67 || p_param1 == 0x68 ) { - pfc::array_t ret; - ret.set_data_fromptr( (const uint8_t*) p_param2, p_param2size); - return ret; - } - } - else if ( p_owner == owner_matroska ) - { - const matroska_setup * setup = ( const matroska_setup * ) p_param2; - if ( p_param2size == sizeof(*setup) ) - { - if ( !strcmp(setup->codec_id, "A_AAC") || !strncmp(setup->codec_id, "A_AAC/", 6) ) { - pfc::array_t ret; - ret.set_data_fromptr( (const uint8_t*) setup->codec_private, setup->codec_private_size ); - return ret; - } - } - } - throw exception_io_data(); -} - -#if 0 bool packet_decoder_aac_common::parseDecoderSetup(const GUID &p_owner, t_size p_param1, const void *p_param2, t_size p_param2size, const void *&outCodecPrivate, size_t &outCodecPrivateSize) { outCodecPrivate = NULL; outCodecPrivateSize = 0; @@ -103,31 +33,16 @@ bool packet_decoder_aac_common::parseDecoderSetup(const GUID &p_owner, t_size p_ return false; } -#endif bool packet_decoder_aac_common::testDecoderSetup( const GUID & p_owner, t_size p_param1, const void * p_param2, t_size p_param2size ) { - if ( p_owner == owner_ADTS ) { return true; } - else if ( p_owner == owner_ADIF ) { return true; } - else if ( p_owner == owner_MP4 ) - { - if ( p_param1 == 0x40 || p_param1 == 0x66 || p_param1 == 0x67 || p_param1 == 0x68 ) { - return true; - } - } - else if ( p_owner == owner_matroska ) - { - const matroska_setup * setup = ( const matroska_setup * ) p_param2; - if ( p_param2size == sizeof(*setup) ) - { - if ( !strcmp(setup->codec_id, "A_AAC") || !strncmp(setup->codec_id, "A_AAC/", 6) ) { - return true; - } - } - } - return false; + const void * dummy1; size_t dummy2; + return parseDecoderSetup(p_owner, p_param1, p_param2, p_param2size, dummy1, dummy2); } + + + namespace { class esds_maker : public stream_writer_buffer_simple { public: @@ -152,8 +67,8 @@ namespace { void packet_decoder_aac_common::make_ESDS( pfc::array_t & outESDS, const void * inCodecPrivate, size_t inCodecPrivateSize ) { if (inCodecPrivateSize > 1024*1024) throw exception_io_data(); // sanity - auto & p_abort = fb2k::noAbort; - + abort_callback_dummy p_abort; + esds_maker esds4; const uint8_t crap[] = {0x40, 0x15, 0x00, 0x00, 0x00, 0x00, 0x05, 0x34, 0x08, 0x00, 0x02, 0x3D, 0x55}; @@ -191,57 +106,3 @@ void packet_decoder_aac_common::make_ESDS( pfc::array_t & outESDS, cons // For: 12 30 56 E5 00 } - -const uint32_t aac_sample_rates[] = { - 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350 -}; - -static unsigned readSamplingFreq(bitreader_helper::bitreader_limited& r) { - unsigned samplingRateIndex = (unsigned)r.read(4); - if (samplingRateIndex == 15) { - return (unsigned)r.read(24); - } else { - if (samplingRateIndex >= PFC_TABSIZE(aac_sample_rates)) throw exception_io_data(); - return aac_sample_rates[samplingRateIndex]; - } -} - -packet_decoder_aac_common::audioSpecificConfig_t packet_decoder_aac_common::parseASC(const void * p_, size_t s) { - // Source: https://wiki.multimedia.cx/index.php?title=MPEG-4_Audio - bitreader_helper::bitreader_limited r((const uint8_t*)p_, 0, s * 8); - - audioSpecificConfig_t cfg = {}; - cfg.m_objectType = (unsigned) r.read(5); - if (cfg.m_objectType == 31) { - cfg.m_objectType = 32 + (unsigned) r.read(6); - } - - cfg.m_sampleRate = readSamplingFreq(r); - - cfg.m_channels = (unsigned) r.read( 4 ); - - if (cfg.m_objectType == 5 || cfg.m_objectType == 29) { - cfg.m_explicitSBR = true; - cfg.m_explicitPS = (cfg.m_objectType == 29); - cfg.m_sbrRate = readSamplingFreq(r); - cfg.m_objectType = (unsigned)r.read(5); - } - - switch (cfg.m_objectType) { - case 1: case 2: case 3: case 4: case 17: case 23: - cfg.m_shortWindow = (r.read(1) != 0); - break; - } - - return cfg; -} - -unsigned packet_decoder_aac_common::get_ASC_object_type(const void * p_, size_t s) { - // Source: https://wiki.multimedia.cx/index.php?title=MPEG-4_Audio - bitreader_helper::bitreader_limited r((const uint8_t*)p_, 0, s * 8); - unsigned objectType = (unsigned) r.read(5); - if (objectType == 31) { - objectType = 32 + (unsigned) r.read(6); - } - return objectType; -} diff --git a/foobar2000/helpers/packet_decoder_aac_common.h b/foobar2000/helpers/packet_decoder_aac_common.h index e123902..7f1b2d0 100644 --- a/foobar2000/helpers/packet_decoder_aac_common.h +++ b/foobar2000/helpers/packet_decoder_aac_common.h @@ -7,10 +7,9 @@ Helper code with common AAC packet_decoder functionality. Primarily meant for fo class packet_decoder_aac_common : public packet_decoder { public: - static pfc::array_t parseDecoderSetup( const GUID & p_owner,t_size p_param1,const void * p_param2,t_size p_param2size); + static bool parseDecoderSetup( const GUID & p_owner,t_size p_param1,const void * p_param2,t_size p_param2size, const void * &outCodecPrivate, size_t & outCodecPrivateSize ); static bool testDecoderSetup( const GUID & p_owner, t_size p_param1, const void * p_param2, t_size p_param2size ); - static size_t skipADTSHeader( const uint8_t * data,size_t size ); - + static unsigned get_max_frame_dependency_() { return 2; @@ -21,17 +20,4 @@ public: } static void make_ESDS( pfc::array_t & outESDS, const void * inCodecPrivate, size_t inCodecPrivateSize ); - - struct audioSpecificConfig_t { - unsigned m_objectType; - unsigned m_sampleRate; - unsigned m_channels; - unsigned m_sbrRate; - bool m_shortWindow; - bool m_explicitSBR, m_explicitPS; - }; - - static audioSpecificConfig_t parseASC(const void *, size_t); - - static unsigned get_ASC_object_type(const void *, size_t); }; diff --git a/foobar2000/helpers/reader_pretend_nonseekable.h b/foobar2000/helpers/reader_pretend_nonseekable.h index f281acc..05f2ebb 100644 --- a/foobar2000/helpers/reader_pretend_nonseekable.h +++ b/foobar2000/helpers/reader_pretend_nonseekable.h @@ -38,13 +38,6 @@ public: t_filetimestamp get_timestamp(abort_callback & p_abort) { return m_file->get_timestamp(p_abort); } void reopen(abort_callback & p_abort) { -#if PFC_DEBUG - auto pos = get_position(p_abort); - FB2K_console_formatter() << "pretend nonseekable reader reopen @ " << pos; - if ( pos > 0 ) { - pfc::nop(); - } -#endif m_file->reopen(p_abort); } diff --git a/foobar2000/helpers/readers.cpp b/foobar2000/helpers/readers.cpp index 99a95ef..02802a1 100644 --- a/foobar2000/helpers/readers.cpp +++ b/foobar2000/helpers/readers.cpp @@ -33,17 +33,15 @@ file::ptr fullFileBuffer::open(const char * path, abort_callback & abort, file:: file::ptr f; if (hint.is_valid()) f = hint; else filesystem::g_open_read(f, path, abort); - - if (sizeMax != filesize_invalid) { - t_filesize fs = f->get_size(abort); - if (fs > sizeMax) return f; + t_filesize fs = f->get_size(abort); + if (fs < sizeMax) /*rejects size-unknown too*/ { + try { + service_ptr_t r = new service_impl_t(); + r->init(f, abort); + f = r; + } + catch (std::bad_alloc) {} } - try { - service_ptr_t r = new service_impl_t(); - r->init(f, abort); - f = r; - } - catch (std::bad_alloc) {} return f; } @@ -68,7 +66,7 @@ namespace { }; struct readAheadInstance_t { file::ptr m_file; - size_t m_readAhead, m_wakeUpThreschold; + size_t m_readAhead; pfc::array_t m_buffer; size_t m_bufferBegin, m_bufferEnd; @@ -78,7 +76,6 @@ namespace { t_filesize m_seekto; abort_callback_impl m_abort; bool m_remote; - bool m_atEOF = false; bool m_haveDynamicInfo; std::list m_dynamicInfo; @@ -107,7 +104,6 @@ namespace { i->m_file = chain; i->m_remote = chain->is_remote(); i->m_readAhead = readAhead; - i->m_wakeUpThreschold = readAhead * 3 / 4; i->m_buffer.set_size_discard( readAhead * 2 ); i->m_bufferBegin = 0; i->m_bufferEnd = 0; i->m_canWrite.set_state(true); @@ -122,55 +118,41 @@ namespace { } } - fb2k::splitTask( [i] { -#ifdef PFC_SET_THREAD_DESCRIPTION - PFC_SET_THREAD_DESCRIPTION("Fb2k Read-Ahead Thread"); -#endif + pfc::splitThread( [i] { worker(*i); } ); } + static void waitHelper( pfc::event & evt, abort_callback & aborter ) { + pfc::event::g_twoEventWait( evt.get_handle(), aborter.get_abort_event(), -1); + aborter.check(); + } t_size read(void * p_buffer,t_size p_bytes,abort_callback & p_abort) { auto & i = * m_instance; size_t done = 0; - bool initial = true; while( done < p_bytes ) { - if ( !initial ) { - // Do not invoke waiting with common case read with lots of data in the buffer - pfc::event::g_twoEventWait( i.m_canRead.get_handle(), p_abort.get_abort_event(), -1); - } - p_abort.check(); + waitHelper( i.m_canRead, p_abort ); pfc::mutexScope guard ( i.m_guard ); size_t got = i.m_bufferEnd - i.m_bufferBegin; if (got == 0) { i.m_error.rethrow(); - if ( initial && ! i.m_atEOF ) { - initial = false; continue; // proceed to wait for more data - } break; // EOF } size_t delta = pfc::min_t( p_bytes - done, got ); - const bool wakeUpBefore = got < i.m_wakeUpThreschold; - auto bufptr = i.m_buffer.get_ptr(); - if ( p_buffer != nullptr ) memcpy( (uint8_t*) p_buffer + done, bufptr + i.m_bufferBegin, delta ); + memcpy( (uint8_t*) p_buffer + done, bufptr + i.m_bufferBegin, delta ); done += delta; i.m_bufferBegin += delta; got -= delta; m_position += delta; - if (!i.m_error.didFail() && !i.m_atEOF) { + if (!i.m_error.didFail()) { if ( got == 0 ) i.m_canRead.set_state( false ); - const bool wakeUpNow = got < i.m_wakeUpThreschold; - // Only set the event when *crossing* the boundary - // we will get a lot of wakeUpNow when nearing EOF - if ( wakeUpNow && ! wakeUpBefore ) i.m_canWrite.set_state( true ); + if ( got < 3 * i.m_readAhead / 4 ) i.m_canWrite.set_state( true ); } - initial = false; - if ( i.m_atEOF ) break; // go no further + } - // FB2K_console_formatter() << "ReadAhead read: " << p_bytes << " => " << done; return done; } t_filesize get_size(abort_callback & p_abort) { @@ -187,16 +169,6 @@ namespace { if (!m_canSeek) throw exception_io_object_not_seekable(); if ( m_stats.m_size != filesize_invalid && p_position > m_stats.m_size ) throw exception_io_seek_out_of_range(); - auto posNow = get_position(p_abort); - - if ( p_position >= posNow && p_position < posNow + m_instance->m_readAhead ) { - // FB2K_console_formatter() << "ReadAhead skip: " << posNow << " => " << p_position; - auto toSkip = p_position - posNow; - if ( toSkip > 0 ) read(nullptr, (size_t) toSkip, p_abort); - return; - } - // FB2K_console_formatter() << "ReadAhead seek: " << posNow << " => " << p_position; - seekInternal( p_position ); } bool can_seek() { @@ -220,23 +192,19 @@ namespace { } void reopen( abort_callback & p_abort ) { - if ( get_position( p_abort ) == 0 ) return; + p_abort.check(); seekInternal( seek_reopen ); } bool get_static_info(class file_info & p_out) { if ( ! m_haveStaticInfo ) return false; - mergeInfo(p_out, m_staticInfo); + p_out = m_staticInfo; return true; } bool is_dynamic_info_enabled() { return m_instance->m_haveDynamicInfo; } - static void mergeInfo( file_info & out, const file_info & in ) { - out.copy_meta(in); - out.overwrite_info(in); - } bool get_dynamic_info_v2(class file_info & out, t_filesize & outOffset) { auto & i = * m_instance; if ( ! i.m_haveDynamicInfo ) return false; @@ -252,10 +220,8 @@ namespace { if ( ptr == i.m_dynamicInfo.begin() ) return false; auto iter = ptr; --iter; - mergeInfo(out, iter->m_info); - outOffset = iter->m_offset; + out = iter->m_info; outOffset = iter->m_offset; i.m_dynamicInfo.erase( i.m_dynamicInfo.begin(), ptr ); - return true; } private: @@ -266,7 +232,6 @@ namespace { i.m_bufferBegin = i.m_bufferEnd = 0; i.m_canWrite.set_state(true); i.m_seekto = p_position; - i.m_atEOF = false; i.m_canRead.set_state(false); m_position = ( p_position == seek_reopen ) ? 0 : p_position; @@ -274,9 +239,8 @@ namespace { static void worker( readAheadInstance_t & i ) { ThreadUtils::CRethrow err; err.exec( [&i] { - bool atEOF = false; uint8_t* bufptr = i.m_buffer.get_ptr(); - const size_t readAtOnceLimit = i.m_remote ? 256 : 4*1024; + const size_t readAtOnceLimit = i.m_remote ? 256 : 64*1024; for ( ;; ) { i.m_canWrite.wait_for(-1); size_t readHowMuch = 0, readOffset = 0; @@ -291,7 +255,6 @@ namespace { } i.m_seekto = filesize_invalid; - atEOF = false; } size_t got = i.m_bufferEnd - i.m_bufferBegin; @@ -317,8 +280,6 @@ namespace { if ( readHowMuch > 0 ) { readHowMuch = i.m_file->read( bufptr + readOffset, readHowMuch, i.m_abort ); - if ( readHowMuch == 0 ) atEOF = true; - if ( i.m_haveDynamicInfo ) { file_dynamicinfo::ptr dyn; if ( dyn &= i.m_file ) { @@ -337,16 +298,14 @@ namespace { { pfc::mutexScope guard( i.m_guard ); - i.m_abort.check(); if ( i.m_seekto != filesize_invalid ) { // Seek request happened while we were reading - discard and continue continue; } - i.m_atEOF = atEOF; i.m_canRead.set_state( true ); i.m_bufferEnd += readHowMuch; size_t got = i.m_bufferEnd - i.m_bufferBegin; - if ( atEOF || got >= i.m_readAhead ) i.m_canWrite.set_state(false); + if ( got >= i.m_readAhead ) i.m_canWrite.set_state(false); if ( dynInfoGot ) { i.m_dynamicInfo.push_back( std::move(dynInfo) ); diff --git a/foobar2000/helpers/tag_write_callback_impl.h b/foobar2000/helpers/tag_write_callback_impl.h index a012c64..2693dd3 100644 --- a/foobar2000/helpers/tag_write_callback_impl.h +++ b/foobar2000/helpers/tag_write_callback_impl.h @@ -21,7 +21,7 @@ public: service_ptr_t l_tempfile; try { openTempFile(l_tempfile, p_abort); - } catch(exception_io) {return false;} + } catch(exception_io_denied) {return false;} p_out = m_tempfile = l_tempfile; return true; } @@ -31,14 +31,6 @@ public: //WARNING: if this errors out, it may leave caller with null file pointer; take appropriate measures not to crash in such cases void finalize(service_ptr_t & p_owner,abort_callback & p_abort) { if (m_tempfile.is_valid()) { - m_tempfile->flushFileBuffers_(p_abort); - - if (p_owner.is_valid()) { - try { - file::g_copy_creation_time(p_owner, m_tempfile, p_abort); - } catch (exception_io) {} - } - m_tempfile.release(); p_owner.release(); handleFileMove(m_temppath, m_origpath, p_abort); @@ -48,7 +40,6 @@ public: // Alternate finalizer without owner file object, caller takes responsibility for closing the source file before calling void finalize_no_reopen( abort_callback & p_abort ) { if (m_tempfile.is_valid()) { - m_tempfile->flushFileBuffers_(p_abort); m_tempfile.release(); handleFileMove(m_temppath, m_origpath, p_abort); } @@ -57,8 +48,9 @@ public: if (m_tempfile.is_valid()) { m_tempfile.release(); try { - retryOnSharingViolation( 1, fb2k::noAbort, [&] { - m_fs->remove(m_temppath, fb2k::noAbort); + abort_callback_dummy noAbort; + retryOnSharingViolation( 1, noAbort, [&] { + m_fs->remove(m_temppath, noAbort); } ); } catch(...) {} } @@ -70,7 +62,7 @@ private: void handleFileMove(const char * from, const char * to, abort_callback & abort) { PFC_ASSERT(m_fs->is_our_path(from)); PFC_ASSERT(m_fs->is_our_path(to)); - FB2K_RETRY_FILE_MOVE(m_fs->replace_file(from, to, abort), abort, 10 ); + retryOnSharingViolation(10, abort, [&] { m_fs->replace_file(from, to, abort); } ); } pfc::string8 m_origpath; pfc::string8 m_temppath; diff --git a/foobar2000/helpers/text_file_loader.cpp b/foobar2000/helpers/text_file_loader.cpp index 0f3e6bb..0b8f7ee 100644 --- a/foobar2000/helpers/text_file_loader.cpp +++ b/foobar2000/helpers/text_file_loader.cpp @@ -59,7 +59,6 @@ namespace text_file_loader return; } if (!memcmp(utf8_header, temp, 3)) is_utf8 = true; - else if (is_utf8) p_out.add_string(temp,3); else ansitemp.add_string(temp, 3); mem.set_size(delta); @@ -90,7 +89,7 @@ namespace text_file_loader char * asdf = mem.get_ptr(); p_file->read_object(asdf,size,p_abort); asdf[size]=0; - if (size>=3 && !memcmp(utf8_header,asdf,3)) { + if (size>3 && !memcmp(utf8_header,asdf,3)) { is_utf8 = true; p_out.add_string(asdf+3); } else if (forceUTF8) { diff --git a/foobar2000/helpers/text_file_loader_v2.cpp b/foobar2000/helpers/text_file_loader_v2.cpp deleted file mode 100644 index a0f2e90..0000000 --- a/foobar2000/helpers/text_file_loader_v2.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "StdAfx.h" -#include "text_file_loader_v2.h" -#include "text_file_loader.h" - -void text_file_loader_v2::load(file::ptr f, abort_callback & abort) { - m_lines.clear(); - bool dummy; - text_file_loader::read_v2(f, abort, m_data, dummy, m_forceUTF8); - - m_lines.reserve(128); - - char * p = const_cast(m_data.get_ptr()); - bool line = false; - const size_t len = m_data.length(); - for (size_t walk = 0; walk < len; ++walk) { - char & c = p[walk]; - if (c == '\n' || c == '\r') { - c = 0; - line = false; - } else if (!line) { - m_lines.push_back(&c); - line = true; - } - } -} \ No newline at end of file diff --git a/foobar2000/helpers/text_file_loader_v2.h b/foobar2000/helpers/text_file_loader_v2.h deleted file mode 100644 index a0147e6..0000000 --- a/foobar2000/helpers/text_file_loader_v2.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once -#include -#include - -class text_file_loader_v2 { -public: - bool m_forceUTF8 = false; - - void load(file::ptr f, abort_callback & abort); - - std::vector< const char * > m_lines; - - pfc::string8 m_data; -}; \ No newline at end of file diff --git a/foobar2000/helpers/track_property_callback_impl.cpp b/foobar2000/helpers/track_property_callback_impl.cpp deleted file mode 100644 index 10a2609..0000000 --- a/foobar2000/helpers/track_property_callback_impl.cpp +++ /dev/null @@ -1,124 +0,0 @@ -#include "StdAfx.h" - -#include -#include - -#include "track_property_callback_impl.h" - - -void track_property_callback_impl::set_property(const char * p_group, double p_sortpriority, const char * p_name, const char * p_value) { - propertyname_container temp; - temp.m_name = p_name; - temp.m_priority = p_sortpriority; - - pfc::string8 fixEOL; - if (m_cutMultiLine && strchr(p_value, '\n') != nullptr) { - fixEOL = p_value; fixEOL.fix_eol(); p_value = fixEOL; - } - - m_entries.find_or_add(p_group).set(temp, p_value); -} - -bool track_property_callback_impl::is_group_wanted(const char * p_group) { - if (m_groupFilter) return m_groupFilter(p_group); - return true; -} - -void track_property_callback_impl::merge(track_property_callback_impl const & other) { - for (auto iterGroup = other.m_entries.first(); iterGroup.is_valid(); ++iterGroup) { - auto & in = iterGroup->m_value; - auto & out = m_entries[iterGroup->m_key]; - for (auto iterEntry = in.first(); iterEntry.is_valid(); ++iterEntry) { - out.set(iterEntry->m_key, iterEntry->m_value); - } - } -} - -static bool is_filtered_info_field(const char * p_name) { - service_ptr_t ptr; - service_enum_t e; - while (e.next(ptr)) { - if (ptr->is_our_tech_info(p_name)) return true; - } - return false; -} - -static const char strGroupOther[] = "Other"; - -static void enumOtherHere(track_property_callback_impl & callback, metadb_info_container::ptr info_) { - const file_info * infoptr = &info_->info(); - for (t_size n = 0, m = infoptr->info_get_count(); n < m; n++) { - const char * name = infoptr->info_enum_name(n); - if (!is_filtered_info_field(name)) { - pfc::string_formatter temp; - temp << "<"; - uAddStringUpper(temp, name); - temp << ">"; - callback.set_property("Other", 0, temp, infoptr->info_enum_value(n)); - } - } -} - -static void enumOther( track_property_callback_impl & callback, metadb_handle_list_cref items, track_property_provider_v3_info_source * infoSource ) { - if (items.get_count() == 1 ) { - enumOtherHere(callback, infoSource->get_info(0) ); - } -} - -void enumerateTrackProperties( track_property_callback_impl & callback, std::function< metadb_handle_list_cref () > itemsSource, std::function infoSource, std::function abortSource) { - - - if ( core_api::is_main_thread() ) { - // should not get here like this - // but that does make our job easier - auto & items = itemsSource(); - auto info = infoSource(); - track_property_provider::ptr ptr; - service_enum_t e; - while (e.next(ptr)) { - ptr->enumerate_properties_helper(items, info, callback, abortSource() ); - } - if ( callback.is_group_wanted( strGroupOther ) ) { - enumOther(callback, items, info ); - } - return; - } - - std::list > lstWaitFor; - std::list > lstMerge; - track_property_provider::ptr ptr; - service_enum_t e; - while (e.next(ptr)) { - auto evt = std::make_shared(); - auto cb = std::make_shared< track_property_callback_impl >(callback); // clone watched group info - auto work = [ptr, itemsSource, evt, cb, infoSource, abortSource] { - try { - ptr->enumerate_properties_helper(itemsSource(), infoSource(), *cb, abortSource()); - } catch (...) {} - evt->set_state(true); - }; - - track_property_provider_v4::ptr v4; - if (v4 &= ptr) { - // Supports v4 = split a worker thread, work in parallel - pfc::splitThread(work); - } else { - // No v4 = delegate to main thread. Ugly but gets the job done. - fb2k::inMainThread(work); - } - - lstWaitFor.push_back(std::move(evt)); - lstMerge.push_back(std::move(cb)); - } - - if (callback.is_group_wanted(strGroupOther)) { - enumOther(callback, itemsSource(), infoSource()); - } - - for (auto i = lstWaitFor.begin(); i != lstWaitFor.end(); ++i) { - abortSource().waitForEvent(**i, -1); - } - for (auto i = lstMerge.begin(); i != lstMerge.end(); ++i) { - callback.merge(** i); - } -} \ No newline at end of file diff --git a/foobar2000/helpers/track_property_callback_impl.h b/foobar2000/helpers/track_property_callback_impl.h deleted file mode 100644 index 7b2e30c..0000000 --- a/foobar2000/helpers/track_property_callback_impl.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include - -class groupname_comparator { -public: - static int compare(pfc::stringp p_name1,pfc::stringp p_name2) { - int temp = uStringCompare(p_name1,p_name2); - if (temp != 0) return temp; - return strcmp(p_name1,p_name2); - } -}; - -struct propertyname_container { - pfc::string m_name; - double m_priority; -}; - -class propertyname_comparator { -public: - static int compare(const propertyname_container & p_item1,const propertyname_container & p_item2) { - int state = pfc::compare_t(p_item1.m_priority,p_item2.m_priority); - if (state != 0) return state; - return uStringCompare(p_item1.m_name.ptr(),p_item2.m_name.ptr()); - } -}; - -typedef pfc::map_t property_group; - -typedef pfc::map_t t_property_group_list; - -class track_property_callback_impl : public track_property_callback_v2 { -public: - void set_property(const char * p_group,double p_sortpriority,const char * p_name,const char * p_value) override; - bool is_group_wanted(const char * p_group) override; - - void merge( track_property_callback_impl const & other ); - - t_property_group_list m_entries; - - bool m_cutMultiLine = false; - typedef std::function groupFilter_t; - groupFilter_t m_groupFilter; -}; - -// Helper function to walk all track property providers in an optimized multithread manner -// Various *source arguments have been std::function'd so you can reference your own data structures gracefully -// If the function is aborted, it returns immediately - while actual worker threads may not yet have completed, and may still reference *source arguments. -// You must ensure - by means of std::shared_ptr<> or such - that all of the *source arguments remain accessible even after enumerateTrackProperties() returns, until the std::functions are released. -// Legacy track property providers that do not support off main thread operation will be invoked via main_thread_callback in main thread, and the function will stall until they have returned (unless aborted). -void enumerateTrackProperties(track_property_callback_impl & callback, std::function< metadb_handle_list_cref() > itemsSource, std::function infoSource, std::function abortSource); diff --git a/foobar2000/helpers/win32_misc.cpp b/foobar2000/helpers/win32_misc.cpp index bc9ecfc..6b05196 100644 --- a/foobar2000/helpers/win32_misc.cpp +++ b/foobar2000/helpers/win32_misc.cpp @@ -1,5 +1,7 @@ #include "stdafx.h" #include "win32_misc.h" +#include "TypeFind.h" +#include "SmartStrStr.h" #ifdef FOOBAR2000_MOBILE_WINDOWS #include @@ -119,6 +121,153 @@ void registerclass_scope_delayed::toggle_off() { } } +unsigned QueryScreenDPI(HWND wnd) { + HDC dc = GetDC(wnd); + unsigned ret = GetDeviceCaps(dc,LOGPIXELSY); + ReleaseDC(wnd,dc); + return ret; +} +unsigned QueryScreenDPI_X(HWND wnd) { + HDC dc = GetDC(wnd); + unsigned ret = GetDeviceCaps(dc,LOGPIXELSX); + ReleaseDC(wnd,dc); + return ret; +} +unsigned QueryScreenDPI_Y(HWND wnd) { + HDC dc = GetDC(wnd); + unsigned ret = GetDeviceCaps(dc,LOGPIXELSY); + ReleaseDC(wnd,dc); + return ret; +} + +SIZE QueryScreenDPIEx(HWND wnd) { + HDC dc = GetDC(wnd); + SIZE ret = { GetDeviceCaps(dc,LOGPIXELSX), GetDeviceCaps(dc,LOGPIXELSY) }; + ReleaseDC(wnd,dc); + return ret; +} + + +bool IsMenuNonEmpty(HMENU menu) { + unsigned n,m=GetMenuItemCount(menu); + for(n=0;n msgFormatted; msgFormatted.set_size(pfc::strlen_t(_Message) + 64); + wsprintfW(msgFormatted.get_ptr(), L"%s (code: %u)", _Message, code); + if (IsDebuggerPresent()) { + OutputDebugString(TEXT("WIN32_OP_D() failure:\n")); + OutputDebugString(msgFormatted.get_ptr()); + OutputDebugString(TEXT("\n")); + pfc::crash(); + } + _wassert(msgFormatted.get_ptr(),_File,_Line); +} +#endif + + +void GetOSVersionString(pfc::string_base & out) { + out.reset(); GetOSVersionStringAppend(out); +} + +static bool running_under_wine(void) { + HMODULE module = GetModuleHandle(_T("ntdll.dll")); + if (!module) return false; + return GetProcAddress(module, "wine_server_call") != NULL; +} +static bool FetchWineInfoAppend(pfc::string_base & out) { + typedef const char *(__cdecl *t_wine_get_build_id)(void); + typedef void (__cdecl *t_wine_get_host_version)( const char **sysname, const char **release ); + const HMODULE ntdll = GetModuleHandle(_T("ntdll.dll")); + if (ntdll == NULL) return false; + t_wine_get_build_id wine_get_build_id; + t_wine_get_host_version wine_get_host_version; + wine_get_build_id = (t_wine_get_build_id)GetProcAddress(ntdll, "wine_get_build_id"); + wine_get_host_version = (t_wine_get_host_version)GetProcAddress(ntdll, "wine_get_host_version"); + if (wine_get_build_id == NULL || wine_get_host_version == NULL) { + if (GetProcAddress(ntdll, "wine_server_call") != NULL) { + out << "wine (unknown version)"; + return true; + } + return false; + } + const char * sysname = NULL; const char * release = NULL; + wine_get_host_version(&sysname, &release); + out << wine_get_build_id() << ", on: " << sysname << " / " << release; + return true; +} +void GetOSVersionStringAppend(pfc::string_base & out) { + + if (FetchWineInfoAppend(out)) return; + + OSVERSIONINFO ver = {}; ver.dwOSVersionInfoSize = sizeof(ver); + WIN32_OP( GetVersionEx(&ver) ); + SYSTEM_INFO info = {}; + GetNativeSystemInfo(&info); + + out << "Windows " << (int)ver.dwMajorVersion << "." << (int)ver.dwMinorVersion << "." << (int)ver.dwBuildNumber; + if (ver.szCSDVersion[0] != 0) out << " " << pfc::stringcvt::string_utf8_from_os(ver.szCSDVersion, PFC_TABSIZE(ver.szCSDVersion)); + + switch(info.wProcessorArchitecture) { + case PROCESSOR_ARCHITECTURE_AMD64: + out << " x64"; break; + case PROCESSOR_ARCHITECTURE_IA64: + out << " IA64"; break; + case PROCESSOR_ARCHITECTURE_INTEL: + out << " x86"; break; + } +} + + +void SetDefaultMenuItem(HMENU p_menu,unsigned p_id) { + MENUITEMINFO info = {sizeof(info)}; + info.fMask = MIIM_STATE; + GetMenuItemInfo(p_menu,p_id,FALSE,&info); + info.fState |= MFS_DEFAULT; + SetMenuItemInfo(p_menu,p_id,FALSE,&info); +} + +bool SetClipboardDataBlock(UINT p_format, const void * p_block, t_size p_block_size) { + bool success = false; + if (OpenClipboard(NULL)) { + EmptyClipboard(); + HANDLE handle = GlobalAlloc(GMEM_MOVEABLE, p_block_size); + if (handle == NULL) { + CloseClipboard(); + throw std::bad_alloc(); + } + {CGlobalLock lock(handle);memcpy(lock.GetPtr(), p_block, p_block_size);} + if (SetClipboardData(p_format, handle) == NULL) { + GlobalFree(handle);//todo? + } + else { + success = true; + } + CloseClipboard(); + } + return success; +} + void CModelessDialogEntry::Set(HWND p_new) { auto api = modeless_dialog_manager::get(); if (m_wnd) api->remove(m_wnd); @@ -183,6 +332,16 @@ void winLocalFileScope::close() { m_path.clear(); } +LRESULT RelayEraseBkgnd(HWND p_from, HWND p_to, HDC p_dc) { + LRESULT status; + POINT pt = { 0, 0 }, pt_old = { 0,0 }; + MapWindowPoints(p_from, p_to, &pt, 1); + OffsetWindowOrgEx(p_dc, pt.x, pt.y, &pt_old); + status = SendMessage(p_to, WM_ERASEBKGND, (WPARAM)p_dc, 0); + SetWindowOrgEx(p_dc, pt_old.x, pt_old.y, 0); + return status; +} + bool IsWindowsS() { bool ret = false; #if FB2K_TARGET_MICROSOFT_STORE @@ -208,8 +367,58 @@ bool IsWindowsS() { return ret; } -WORD GetOSVersion() { - // wrap libPPUI function - return ::GetOSVersionCode(); + +// TYPEFIND IMPLEMENTATION + +namespace TypeFindImpl { + + static size_t _ItemCount(HWND wnd) { + return ListView_GetItemCount(wnd); + } + static const wchar_t * _ItemText(HWND wnd, size_t index, int subItem = 0) { + NMLVDISPINFO info = {}; + info.hdr.code = LVN_GETDISPINFO; + info.hdr.idFrom = GetDlgCtrlID(wnd); + info.hdr.hwndFrom = wnd; + info.item.iItem = index; + info.item.iSubItem = subItem; + info.item.mask = LVIF_TEXT; + ::SendMessage(::GetParent(wnd), WM_NOTIFY, info.hdr.idFrom, reinterpret_cast(&info)); + if (info.item.pszText == NULL) return L""; + return info.item.pszText; + } + +}; + +LRESULT TypeFind::Handler(NMHDR* hdr, int subItemFrom, int subItemCnt) { + using namespace TypeFindImpl; + NMLVFINDITEM * info = reinterpret_cast(hdr); + const HWND wnd = hdr->hwndFrom; + if (info->lvfi.flags & LVFI_NEARESTXY) return -1; + const size_t count = _ItemCount(wnd); + if (count == 0) return -1; + const size_t base = (size_t)info->iStart % count; + + static SmartStrStr tool; + + for (size_t walk = 0; walk < count; ++walk) { + const size_t index = (walk + base) % count; + for (int subItem = subItemFrom; subItem < subItemFrom + subItemCnt; ++subItem) { + if (tool.matchHereW(_ItemText(wnd, index, subItem), info->lvfi.psz)) return (LRESULT)index; + } + } + for (size_t walk = 0; walk < count; ++walk) { + const size_t index = (walk + base) % count; + for (int subItem = subItemFrom; subItem < subItemFrom + subItemCnt; ++subItem) { + if ( tool.strStrEndW(_ItemText(wnd, index, subItem), info->lvfi.psz) ) return (LRESULT)index; + } + } + return -1; } + + + #endif // FOOBAR2000_DESKTOP_WINDOWS + + + diff --git a/foobar2000/helpers/win32_misc.h b/foobar2000/helpers/win32_misc.h index 1e6267f..60f98e7 100644 --- a/foobar2000/helpers/win32_misc.h +++ b/foobar2000/helpers/win32_misc.h @@ -3,8 +3,19 @@ #ifdef _WIN32 -#include -#include +#include "win32_op.h" + +class CloseHandleScope { +public: + CloseHandleScope(HANDLE handle) throw() : m_handle(handle) {} + ~CloseHandleScope() throw() { CloseHandle(m_handle); } + HANDLE Detach() throw() { return pfc::replace_t(m_handle, INVALID_HANDLE_VALUE); } + HANDLE Get() const throw() { return m_handle; } + void Close() throw() { CloseHandle(Detach()); } + PFC_CLASS_NOT_COPYABLE_EX(CloseHandleScope) +private: + HANDLE m_handle; +}; class mutexScope { @@ -20,7 +31,8 @@ private: class registerclass_scope_delayed { public: - registerclass_scope_delayed() {} + registerclass_scope_delayed() : m_class(0) {} + bool is_registered() const {return m_class != 0;} void toggle_on(UINT p_style,WNDPROC p_wndproc,int p_clsextra,int p_wndextra,HICON p_icon,HCURSOR p_cursor,HBRUSH p_background,const TCHAR * p_classname,const TCHAR * p_menuname); void toggle_off(); @@ -28,14 +40,51 @@ public: ~registerclass_scope_delayed() {toggle_off();} private: - registerclass_scope_delayed(const registerclass_scope_delayed &) = delete; - const registerclass_scope_delayed & operator=(const registerclass_scope_delayed &) = delete; + registerclass_scope_delayed(const registerclass_scope_delayed &) {throw pfc::exception_not_implemented();} + const registerclass_scope_delayed & operator=(const registerclass_scope_delayed &) {throw pfc::exception_not_implemented();} - ATOM m_class = 0; + ATOM m_class; }; -typedef CGlobalLockScope CGlobalLock; // compatibility + +typedef CGlobalLockScope CGlobalLock;//for compatibility, implementation moved elsewhere + +bool SetClipboardDataBlock(UINT p_format, const void * p_block, t_size p_block_size); + +template +static bool SetClipboardDataBlock(UINT p_format,const t_array & p_array) { + PFC_STATIC_ASSERT( sizeof(p_array[0]) == 1 ); + return SetClipboardDataBlock(p_format,p_array.get_ptr(),p_array.get_size()); +} + +template +static bool GetClipboardDataBlock(UINT p_format,t_array & p_array) { + PFC_STATIC_ASSERT( sizeof(p_array[0]) == 1 ); + if (OpenClipboard(NULL)) { + HANDLE handle = GetClipboardData(p_format); + if (handle == NULL) { + CloseClipboard(); + return false; + } + { + CGlobalLock lock(handle); + const t_size size = lock.GetSize(); + try { + p_array.set_size(size); + } catch(...) { + CloseClipboard(); + throw; + } + memcpy(p_array.get_ptr(),lock.GetPtr(),size); + } + CloseClipboard(); + return true; + } else { + return false; + } +} + class OleInitializeScope { public: @@ -55,7 +104,17 @@ private: PFC_CLASS_NOT_COPYABLE_EX(CoInitializeScope) }; -WORD GetOSVersion(); + +unsigned QueryScreenDPI(HWND wnd = NULL); +unsigned QueryScreenDPI_X(HWND wnd = NULL); +unsigned QueryScreenDPI_Y(HWND wnd = NULL); + +SIZE QueryScreenDPIEx(HWND wnd = NULL); + +static WORD GetOSVersion() { + const DWORD ver = GetVersion(); + return (WORD)HIBYTE(LOWORD(ver)) | ((WORD)LOBYTE(LOWORD(ver)) << 8); +} #if _WIN32_WINNT >= 0x501 #define WS_EX_COMPOSITED_Safe() WS_EX_COMPOSITED @@ -66,6 +125,26 @@ static DWORD WS_EX_COMPOSITED_Safe() { #endif + + + +class EnableWindowScope { +public: + EnableWindowScope(HWND p_window,BOOL p_state) throw() : m_window(p_window) { + m_oldState = IsWindowEnabled(m_window); + EnableWindow(m_window,p_state); + } + ~EnableWindowScope() throw() { + EnableWindow(m_window,m_oldState); + } + +private: + BOOL m_oldState; + HWND m_window; +}; + +bool IsMenuNonEmpty(HMENU menu); + class CModelessDialogEntry { public: CModelessDialogEntry() : m_wnd() {} @@ -78,6 +157,12 @@ private: HWND m_wnd; }; +void GetOSVersionString(pfc::string_base & out); +void GetOSVersionStringAppend(pfc::string_base & out); + +void SetDefaultMenuItem(HMENU p_menu,unsigned p_id); + + class CDLL { public: #ifdef _DEBUG @@ -120,7 +205,7 @@ public: void open(const char * inPath, file::ptr inReader, abort_callback & aborter); void close(); - winLocalFileScope() {} + winLocalFileScope() : m_isTemp() {} winLocalFileScope(const char * inPath, file::ptr inReader, abort_callback & aborter) : m_isTemp() { open(inPath, inReader, aborter); } @@ -130,9 +215,8 @@ public: } const wchar_t * Path() const { return m_path.c_str(); } - bool isTemp() const { return m_isTemp; } private: - bool m_isTemp = false; + bool m_isTemp; std::wstring m_path; }; @@ -163,6 +247,8 @@ private: CMutex & m_mutex; }; +LRESULT RelayEraseBkgnd(HWND p_from, HWND p_to, HDC p_dc); + bool IsWindowsS(); #endif // _WIN32 diff --git a/libPPUI/win32_op.h b/foobar2000/helpers/win32_op.h similarity index 100% rename from libPPUI/win32_op.h rename to foobar2000/helpers/win32_op.h diff --git a/foobar2000/helpers/window_placement_helper.cpp b/foobar2000/helpers/window_placement_helper.cpp index 2583c2e..9ec27be 100644 --- a/foobar2000/helpers/window_placement_helper.cpp +++ b/foobar2000/helpers/window_placement_helper.cpp @@ -40,7 +40,7 @@ static bool test_rect(const RECT * rc) { } -bool cfg_window_placement_common::read_from_window(HWND window) +bool cfg_window_placement::read_from_window(HWND window) { WINDOWPLACEMENT wp = {}; if (g_is_enabled()) { @@ -53,8 +53,6 @@ bool cfg_window_placement_common::read_from_window(HWND window) /*if (wp.showCmd == SW_SHOWNORMAL) { GetWindowRect(window, &wp.rcNormalPosition); }*/ - - if ( !IsWindowVisible( window ) ) wp.showCmd = SW_HIDE; } /*else { @@ -65,26 +63,23 @@ bool cfg_window_placement_common::read_from_window(HWND window) return m_data.length == sizeof(m_data); } -bool cfg_window_placement_common::apply_to_window(HWND window, bool allowHidden) { +void cfg_window_placement::on_window_creation_silent(HWND window) { + PFC_ASSERT(!m_windows.have_item(window)); + m_windows.add_item(window); +} +bool cfg_window_placement::on_window_creation(HWND window) +{ bool ret = false; + PFC_ASSERT(!m_windows.have_item(window)); + m_windows.add_item(window); + if (g_is_enabled()) { - if (m_data.length == sizeof(m_data) && test_rect(&m_data.rcNormalPosition)) + if (m_data.length==sizeof(m_data) && test_rect(&m_data.rcNormalPosition)) { - if (allowHidden || m_data.showCmd != SW_HIDE) { - if (m_data.showCmd == SW_HIDE && (m_data.flags & WPF_RESTORETOMAXIMIZED)) { - // Special case of hidden-from-maximized - auto fix = m_data; - fix.showCmd = SW_SHOWMINIMIZED; - if (SetWindowPlacement(window, &fix)) { - ShowWindow(window, SW_HIDE); - ret = true; - } - } else { - if (SetWindowPlacement(window, &m_data)) { - ret = true; - } - } + if (SetWindowPlacement(window,&m_data)) + { + ret = true; } } } @@ -92,17 +87,6 @@ bool cfg_window_placement_common::apply_to_window(HWND window, bool allowHidden) return ret; } -void cfg_window_placement::on_window_creation_silent(HWND window) { - PFC_ASSERT(!m_windows.have_item(window)); - m_windows.add_item(window); -} -bool cfg_window_placement::on_window_creation(HWND window, bool allowHidden) { - - PFC_ASSERT(!m_windows.have_item(window)); - m_windows.add_item(window); - return apply_to_window(window, allowHidden); -} - void cfg_window_placement::on_window_destruction(HWND window) { @@ -113,12 +97,6 @@ void cfg_window_placement::on_window_destruction(HWND window) } } -void cfg_window_placement_common::get_data_raw(stream_writer* p_stream, abort_callback& p_abort) { - if (m_data.length == sizeof(m_data)) { - p_stream->write_object(&m_data, sizeof(m_data), p_abort); - } -} - void cfg_window_placement::get_data_raw(stream_writer * p_stream,abort_callback & p_abort) { if (g_is_enabled()) { { @@ -130,16 +108,25 @@ void cfg_window_placement::get_data_raw(stream_writer * p_stream,abort_callback } } - cfg_window_placement_common::get_data_raw(p_stream, p_abort); + if (m_data.length == sizeof(m_data)) { + p_stream->write_object(&m_data,sizeof(m_data),p_abort); + } } } -void cfg_window_placement_common::set_data_raw(stream_reader * p_stream,t_size p_sizehint,abort_callback & p_abort) { +void cfg_window_placement::set_data_raw(stream_reader * p_stream,t_size p_sizehint,abort_callback & p_abort) { + if (p_sizehint == 0) return; WINDOWPLACEMENT temp; - if (p_sizehint == sizeof(temp)) { - p_stream->read_object(&temp, sizeof(temp), p_abort); - if (temp.length == sizeof(temp)) m_data = temp; - } + try { + p_stream->read_object(&temp,sizeof(temp),p_abort); + } catch(exception_io_data) {return;} + if (temp.length == sizeof(temp)) m_data = temp; +} + + +cfg_window_placement::cfg_window_placement(const GUID & p_guid) : cfg_var(p_guid) +{ + memset(&m_data,0,sizeof(m_data)); } diff --git a/foobar2000/helpers/window_placement_helper.h b/foobar2000/helpers/window_placement_helper.h index 5813036..0ed373f 100644 --- a/foobar2000/helpers/window_placement_helper.h +++ b/foobar2000/helpers/window_placement_helper.h @@ -2,38 +2,21 @@ #ifdef FOOBAR2000_DESKTOP_WINDOWS -class cfg_window_placement_common : public cfg_var { -public: - cfg_window_placement_common(const GUID& guid) : cfg_var(guid) {} - bool read_from_window(HWND window); - bool apply_to_window(HWND window, bool allowHidden); -protected: - void get_data_raw(stream_writer* p_stream, abort_callback& p_abort) override; - void set_data_raw(stream_reader* p_stream, t_size p_sizehint, abort_callback& p_abort) override; - WINDOWPLACEMENT m_data = {}; -}; - -class cfg_window_placement : public cfg_window_placement_common +class cfg_window_placement : public cfg_var { public: - bool on_window_creation(HWND window, bool allowHidden = false);//returns true if window position has been changed, false if not + bool on_window_creation(HWND window);//returns true if window position has been changed, false if not void on_window_creation_silent(HWND window); void on_window_destruction(HWND window); - cfg_window_placement(const GUID& guid) : cfg_window_placement_common(guid) {} -protected: - void get_data_raw(stream_writer* p_stream, abort_callback& p_abort) override; + bool read_from_window(HWND window); + void get_data_raw(stream_writer * p_stream,abort_callback & p_abort); + void set_data_raw(stream_reader * p_stream,t_size p_sizehint,abort_callback & p_abort); + cfg_window_placement(const GUID & p_guid); private: pfc::list_hybrid_t m_windows; + WINDOWPLACEMENT m_data; }; -class cfg_window_placement_v2 : public cfg_window_placement_common { -public: - cfg_window_placement_v2(const GUID& guid) : cfg_window_placement_common(guid) {} - // All already in cfg_window_placement_common -}; - - - class cfg_window_size : public cfg_var { public: @@ -48,4 +31,4 @@ private: t_uint32 m_width,m_height; }; -#endif // FOOBAR2000_DESKTOP_WINDOWS +#endif // FOOBAR2000_DESKTOP_WINDOWS \ No newline at end of file diff --git a/foobar2000/helpers/winmm-types.h b/foobar2000/helpers/winmm-types.h deleted file mode 100644 index 0a416b3..0000000 --- a/foobar2000/helpers/winmm-types.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once - -// Blank header for source compatibility -// WAVEFORMATEX and such are declared here on non Windows \ No newline at end of file diff --git a/foobar2000/helpers/writer_wav.cpp b/foobar2000/helpers/writer_wav.cpp index bdceccb..832cfaa 100644 --- a/foobar2000/helpers/writer_wav.cpp +++ b/foobar2000/helpers/writer_wav.cpp @@ -376,11 +376,12 @@ static std::vector makeWavHeader( const wavWriterSetup_t & setup, t_fil temp->seek( 0, aborter ); temp->read_object( &ret[0], s, aborter ); } - return ret; + return std::move(ret); } file::ptr makeLiveWAVFile( const wavWriterSetup_t & setup, file::ptr data ) { - t_filesize size = data->get_size( fb2k::noAbort ); - auto vec = makeWavHeader( setup, size, fb2k::noAbort ); + abort_callback_dummy aborter; + t_filesize size = data->get_size( aborter ); + auto vec = makeWavHeader( setup, size, aborter ); return new service_impl_t< fileWav >( std::move(vec), data ); } diff --git a/foobar2000/shared/fb2kdebug.h b/foobar2000/shared/fb2kdebug.h index 0faa478..29a4f87 100644 --- a/foobar2000/shared/fb2kdebug.h +++ b/foobar2000/shared/fb2kdebug.h @@ -1,20 +1,3 @@ -#pragma once - -// since fb2k 1.5 -namespace fb2k { - class panicHandler { - public: - virtual void onPanic() = 0; - }; -} - -// since fb2k 1.5 -extern "C" -{ - void SHARED_EXPORT uAddPanicHandler(fb2k::panicHandler*); - void SHARED_EXPORT uRemovePanicHandler(fb2k::panicHandler*); -} - extern "C" { LPCSTR SHARED_EXPORT uGetCallStackPath(); @@ -81,7 +64,6 @@ static void fb2kWaitForCompletion(HANDLE hEvent) { } static void fb2kWaitForThreadCompletion(HANDLE hWaitFor, DWORD threadID) { - (void) threadID; switch(WaitForSingleObject(hWaitFor, INFINITE)) { case WAIT_OBJECT_0: return; @@ -91,7 +73,6 @@ static void fb2kWaitForThreadCompletion(HANDLE hWaitFor, DWORD threadID) { } static void fb2kWaitForThreadCompletion2(HANDLE hWaitFor, HANDLE hThread, DWORD threadID) { - (void) threadID; switch(WaitForSingleObject(hWaitFor, INFINITE)) { case WAIT_OBJECT_0: return; @@ -117,14 +98,13 @@ static void _InvalidParameter( unsigned int line, uintptr_t pReserved ) { - (void)pReserved; (void) line; (void) file; (void) function; (void) expression; RaiseException(0xd142b808 /* random GUID */, EXCEPTION_NONCONTINUABLE, 0, 0); } static void OverrideCrtAbort() { const int signals[] = {SIGINT, SIGTERM, SIGBREAK, SIGABRT}; for(size_t i=0; i<_countof(signals); i++) signal(signals[i], _OverrideCrtAbort_handler); - _set_abort_behavior(0, UINT_MAX); + _set_abort_behavior(0, ~0); _set_purecall_handler(_PureCallHandler); _set_invalid_parameter_handler(_InvalidParameter); diff --git a/foobar2000/shared/shared.h b/foobar2000/shared/shared.h index 6313520..542e483 100644 --- a/foobar2000/shared/shared.h +++ b/foobar2000/shared/shared.h @@ -277,6 +277,7 @@ HMODULE SHARED_EXPORT LoadSystemLibrary(const TCHAR * name); }//extern "C" static inline void uAddDebugEvent(const char * msg) {uPrintCrashInfo_OnEvent(msg, strlen(msg));} +static inline void uAddDebugEvent(pfc::string_formatter const & msg) {uPrintCrashInfo_OnEvent(msg, msg.length());} inline char * uCharNext(char * src) {return src+uCharLength(src);} inline const char * uCharNext(const char * src) {return src+uCharLength(src);} diff --git a/foobar2000/shared/shared.lib b/foobar2000/shared/shared.lib index 0a61b8c..9546a68 100644 Binary files a/foobar2000/shared/shared.lib and b/foobar2000/shared/shared.lib differ diff --git a/libPPUI/AutoComplete.cpp b/libPPUI/AutoComplete.cpp deleted file mode 100644 index 4f29168..0000000 --- a/libPPUI/AutoComplete.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include "stdafx.h" -#include "AutoComplete.h" -#include "pp-COM-macros.h" - -#include // CLSID_AutoComplete - -#include "CEnumString.h" -using PP::CEnumString; - -HRESULT InitializeSimpleAC(HWND edit, IUnknown * vals, DWORD opts) { - pfc::com_ptr_t ac; - HRESULT hr; - hr = CoCreateInstance(CLSID_AutoComplete, NULL, CLSCTX_ALL, IID_IAutoComplete, (void**)ac.receive_ptr()); - if (FAILED(hr)) { - PFC_ASSERT(!"Should not get here - CoCreateInstance/IAutoComplete fail!"); return hr; - } - hr = ac->Init(edit, vals, NULL, NULL); - if (FAILED(hr)) { - PFC_ASSERT(!"Should not get here - ac->Init fail!"); return hr; - } - - pfc::com_ptr_t ac2; - hr = ac->QueryInterface(ac2.receive_ptr()); - if (FAILED(hr)) { - PFC_ASSERT(!"Should not get here - ac->QueryInterface fail!"); return hr; - } - hr = ac2->SetOptions(opts); - if (FAILED(hr)) { - PFC_ASSERT(!"Should not get here - ac2->SetOptions fail!"); return hr; - } - return S_OK; -} - -pfc::com_ptr_t CreateACList(pfc::const_iterator valueEnum) { - pfc::com_ptr_t acl = new CEnumString::TImpl(); - while (valueEnum.is_valid()) { - acl->AddStringU(*valueEnum); ++valueEnum; - } - return acl; -} -pfc::com_ptr_t CreateACList(pfc::const_iterator valueEnum) { - pfc::com_ptr_t acl = new CEnumString::TImpl(); - while (valueEnum.is_valid()) { - acl->AddStringU(*valueEnum); ++valueEnum; - } - return acl; -} -pfc::com_ptr_t CreateACList(pfc::const_iterator valueEnum) { - pfc::com_ptr_t acl = new CEnumString::TImpl(); - while (valueEnum.is_valid()) { - acl->AddStringU(valueEnum->ptr()); ++valueEnum; - } - return acl; -} - -pfc::com_ptr_t CreateACList() { - return new CEnumString::TImpl(); -} - -void CreateACList_AddItem(IUnknown * theList, const char * item) { - static_cast(theList)->AddStringU(item); -} - -HRESULT InitializeEditAC(HWND edit, pfc::const_iterator valueEnum, DWORD opts) { - pfc::com_ptr_t acl = CreateACList(valueEnum); - return InitializeSimpleAC(edit, acl.get_ptr(), opts); -} -HRESULT InitializeEditAC(HWND edit, const char * values, DWORD opts) { - pfc::com_ptr_t acl = new CEnumString::TImpl(); - for (const char * walk = values;;) { - const char * next = strchr(walk, '\n'); - if (next == NULL) { acl->AddStringU(walk, ~0); break; } - acl->AddStringU(walk, next - walk); - walk = next + 1; - } - return InitializeSimpleAC(edit, acl.get_ptr(), opts); -} diff --git a/libPPUI/CDialogResizeHelper.cpp b/libPPUI/CDialogResizeHelper.cpp deleted file mode 100644 index 172105f..0000000 --- a/libPPUI/CDialogResizeHelper.cpp +++ /dev/null @@ -1,194 +0,0 @@ -#include "stdafx.h" -#include "CDialogResizeHelper.h" - -#include "win32_op.h" - -static BOOL GetChildWindowRect2(HWND wnd, HWND wndChild, RECT* child) { - RECT temp; - if (wndChild == NULL) return FALSE; - if (!GetWindowRect(wndChild, &temp)) return FALSE; - if (!MapWindowPoints(NULL, wnd, (POINT*)&temp, 2)) return FALSE; - *child = temp; - return TRUE; -} - -static BOOL GetChildWindowRect(HWND wnd, UINT id, RECT* child) { - return GetChildWindowRect2(wnd, GetDlgItem(wnd, id), child); -} - - -bool CDialogResizeHelper::EvalRect(UINT id, CRect & out) const { - for( auto iter = m_runtime.begin(); iter != m_runtime.end(); ++ iter ) { - if ( iter->initData.id == id ) { - out = _EvalRect(*iter, this->CurrentSize() ); - return true; - } - } - return false; -} - -CRect CDialogResizeHelper::_EvalRect(runtime_t const & rt, CSize wndSize) const { - CRect rc = rt.origRect; - int delta_x = wndSize.cx - rt.origWindowSize.cx, - delta_y = wndSize.cy - rt.origWindowSize.cy; - - const Param & e = rt.initData; - rc.left += pfc::rint32(e.snapLeft * delta_x); - rc.right += pfc::rint32(e.snapRight * delta_x); - rc.top += pfc::rint32(e.snapTop * delta_y); - rc.bottom += pfc::rint32(e.snapBottom * delta_y); - - return rc; -} - -CWindow CDialogResizeHelper::ResolveWnd(runtime_t const & rt) const { - if ( rt.userHWND != NULL ) return rt.userHWND; - return m_thisWnd.GetDlgItem( rt.initData.id ); -} - -CSize CDialogResizeHelper::CurrentSize() const { - CRect rc; - WIN32_OP_D( m_thisWnd.GetClientRect(rc) ); - return rc.Size(); -} - -void CDialogResizeHelper::OnSize(UINT, CSize newSize) -{ - if (m_thisWnd != NULL) { - HDWP hWinPosInfo = BeginDeferWindowPos((int)(m_runtime.size() + (m_sizeGrip != NULL ? 1 : 0))); - for (auto iter = m_runtime.begin(); iter != m_runtime.end(); ++ iter) { - CRect rc = _EvalRect(*iter, newSize); - hWinPosInfo = DeferWindowPos(hWinPosInfo, ResolveWnd(*iter), 0, rc.left, rc.top, rc.Width(), rc.Height(), SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS); - } - if (m_sizeGrip != NULL) - { - RECT rc, rc_grip; - if (m_thisWnd.GetClientRect(&rc) && m_sizeGrip.GetWindowRect(&rc_grip)) { - DWORD flags = SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOCOPYBITS; - if (IsZoomed(m_thisWnd)) flags |= SWP_HIDEWINDOW; - else flags |= SWP_SHOWWINDOW; - hWinPosInfo = DeferWindowPos(hWinPosInfo, m_sizeGrip, NULL, rc.right - (rc_grip.right - rc_grip.left), rc.bottom - (rc_grip.bottom - rc_grip.top), 0, 0, flags); - } - } - EndDeferWindowPos(hWinPosInfo); - //RedrawWindow(m_thisWnd, NULL, NULL, RDW_UPDATENOW | RDW_ALLCHILDREN); - } - SetMsgHandled(FALSE); -} - -void CDialogResizeHelper::OnGetMinMaxInfo(LPMINMAXINFO info) const { - CRect r; - const DWORD dwStyle = m_thisWnd.GetWindowLong(GWL_STYLE); - const DWORD dwExStyle = m_thisWnd.GetWindowLong(GWL_EXSTYLE); - if (max_x && max_y) - { - r.left = 0; r.right = max_x; - r.top = 0; r.bottom = max_y; - MapDialogRect(m_thisWnd, &r); - AdjustWindowRectEx(&r, dwStyle, FALSE, dwExStyle); - info->ptMaxTrackSize.x = r.right - r.left; - info->ptMaxTrackSize.y = r.bottom - r.top; - } - if (min_x && min_y) - { - r.left = 0; r.right = min_x; - r.top = 0; r.bottom = min_y; - MapDialogRect(m_thisWnd, &r); - AdjustWindowRectEx(&r, dwStyle, FALSE, dwExStyle); - info->ptMinTrackSize.x = r.right - r.left; - info->ptMinTrackSize.y = r.bottom - r.top; - } -} - -void CDialogResizeHelper::OnInitDialog(CWindow thisWnd) { - - m_thisWnd = thisWnd; - const auto origSize = CurrentSize(); - for( auto initIter = m_initData.begin(); initIter != m_initData.end(); ++ initIter ) { - CRect rc; - if (GetChildWindowRect(m_thisWnd, initIter->id, &rc)) { - runtime_t rt; - rt.origRect = rc; - rt.initData = * initIter; - rt.origWindowSize = origSize; - m_runtime.push_back( std::move(rt) ); - } - } - AddSizeGrip(); - SetMsgHandled(FALSE); -} -void CDialogResizeHelper::OnDestroy() { - m_runtime.clear(); - m_sizeGrip = NULL; m_thisWnd = NULL; - SetMsgHandled(FALSE); -} - -void CDialogResizeHelper::AddSizeGrip() -{ - if (m_thisWnd != NULL && m_sizeGrip == NULL) - { - if (m_thisWnd.GetWindowLong(GWL_STYLE) & WS_POPUP) { - m_sizeGrip = CreateWindowEx(0, WC_SCROLLBAR, _T(""), WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN, - 0, 0, CW_USEDEFAULT, CW_USEDEFAULT, - m_thisWnd, (HMENU)0, NULL, NULL); - if (m_sizeGrip != NULL) - { - RECT rc, rc_grip; - if (m_thisWnd.GetClientRect(&rc) && m_sizeGrip.GetWindowRect(&rc_grip)) { - m_sizeGrip.SetWindowPos(NULL, rc.right - (rc_grip.right - rc_grip.left), rc.bottom - (rc_grip.bottom - rc_grip.top), 0, 0, SWP_NOZORDER | SWP_NOSIZE); - } - } - } - } -} - - -void CDialogResizeHelper::InitTable(const Param* table, size_t tableSize) { - m_initData.assign( table, table+tableSize ); -} -void CDialogResizeHelper::InitTable(const ParamOld * table, size_t tableSize) { - m_initData.resize(tableSize); - for (size_t walk = 0; walk < tableSize; ++walk) { - const ParamOld in = table[walk]; - Param entry = {}; - entry.id = table[walk].id; - if (in.flags & CDialogResizeHelperCompat::X_MOVE) entry.snapLeft = entry.snapRight = 1; - else if (in.flags & CDialogResizeHelperCompat::X_SIZE) entry.snapRight = 1; - if (in.flags & CDialogResizeHelperCompat::Y_MOVE) entry.snapTop = entry.snapBottom = 1; - else if (in.flags & CDialogResizeHelperCompat::Y_SIZE) entry.snapBottom = 1; - m_initData[walk] = entry; - } -} -void CDialogResizeHelper::InitMinMax(const CRect & range) { - min_x = range.left; min_y = range.top; max_x = range.right; max_y = range.bottom; -} - -void CDialogResizeHelper::AddControl(Param const & initData, CWindow wnd) { - CRect rc; - if ( wnd == NULL ) { - PFC_ASSERT( initData.id != 0 ); - WIN32_OP_D(GetChildWindowRect(m_thisWnd, initData.id, rc)); - } else { - WIN32_OP_D(GetChildWindowRect2(m_thisWnd, wnd, rc)); - } - - runtime_t rt; - rt.initData = initData; - rt.userHWND = wnd; - rt.origRect = rc; - rt.origWindowSize = this->CurrentSize(); - m_runtime.push_back( std::move(rt) ); -} - -bool CDialogResizeHelper::RemoveControl(CWindow wnd) { - return pfc::remove_if_t( m_runtime, [wnd] (runtime_t const & rt) { - return rt.userHWND == wnd; - } ) > 0; -} - -bool CDialogResizeHelper::HaveControl(CWindow wnd) const { - for( auto i = m_runtime.begin(); i != m_runtime.end(); ++ i ) { - if ( i->userHWND == wnd ) return true; - } - return false; -} diff --git a/libPPUI/CDialogResizeHelper.h b/libPPUI/CDialogResizeHelper.h deleted file mode 100644 index e81e687..0000000 --- a/libPPUI/CDialogResizeHelper.h +++ /dev/null @@ -1,67 +0,0 @@ -#pragma once - -#include "CDialogResizeHelperCompat.h" -#include - -class CDialogResizeHelper : public CMessageMap { -public: - - typedef CDialogResizeHelperCompat::param ParamOld; - - struct Param { - uint32_t id; - float snapLeft, snapTop, snapRight, snapBottom; - }; -private: - void AddSizeGrip(); -public: - inline void set_min_size(unsigned x, unsigned y) { min_x = x; min_y = y; } - inline void set_max_size(unsigned x, unsigned y) { max_x = x; max_y = y; } - - - BEGIN_MSG_MAP_EX(CDialogResizeHelper) - if (uMsg == WM_INITDIALOG) OnInitDialog(hWnd); - MSG_WM_SIZE(OnSize) - MSG_WM_DESTROY(OnDestroy) - MSG_WM_GETMINMAXINFO(OnGetMinMaxInfo) - END_MSG_MAP() - - template CDialogResizeHelper(const TParam(&src)[paramCount], CRect const& minMaxRange = CRect(0, 0, 0, 0)) { - InitTable(src, paramCount); - InitMinMax(minMaxRange); - } - - void InitTable(const Param* table, size_t tableSize); - void InitTable(const ParamOld * table, size_t tableSize); - void InitMinMax(const CRect & range); - - bool EvalRect(UINT id, CRect & out) const; - - //! initData.id may be null, if so specify a non null window handle. - void AddControl( Param const & initData, CWindow wnd = NULL ); - bool RemoveControl( CWindow wnd ); - bool HaveControl(CWindow wnd) const; -private: - struct runtime_t { - HWND userHWND = 0; - CRect origRect; - CSize origWindowSize; - Param initData = {}; - }; - - CSize CurrentSize() const; - CWindow ResolveWnd( runtime_t const & rt ) const; - - CRect _EvalRect(runtime_t const & rt, CSize wndSize) const; - void OnGetMinMaxInfo(LPMINMAXINFO lpMMI) const; - void OnSize(UINT nType, CSize size); - void OnInitDialog(CWindow thisWnd); - void OnDestroy(); - - - std::vector m_runtime; - std::vector m_initData; - - CWindow m_thisWnd, m_sizeGrip; - unsigned min_x, min_y, max_x, max_y; -}; \ No newline at end of file diff --git a/libPPUI/CDialogResizeHelperCompat.h b/libPPUI/CDialogResizeHelperCompat.h deleted file mode 100644 index 90bf10c..0000000 --- a/libPPUI/CDialogResizeHelperCompat.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -class CDialogResizeHelperCompat { -public: - struct param { - unsigned short id; - unsigned short flags; - }; - - enum { - X_MOVE = 1, X_SIZE = 2, Y_MOVE = 4, Y_SIZE = 8, - XY_MOVE = X_MOVE | Y_MOVE, XY_SIZE = X_SIZE | Y_SIZE, - X_MOVE_Y_SIZE = X_MOVE | Y_SIZE, X_SIZE_Y_MOVE = X_SIZE | Y_MOVE, - }; - -}; \ No newline at end of file diff --git a/libPPUI/CEditWithButtons.cpp b/libPPUI/CEditWithButtons.cpp deleted file mode 100644 index ecc4936..0000000 --- a/libPPUI/CEditWithButtons.cpp +++ /dev/null @@ -1,178 +0,0 @@ -#include "stdafx.h" -#include "CEditWithButtons.h" - - -void CEditWithButtons::AddMoreButton(std::function f) { - AddButton(L"more", f, nullptr, L"\x2026"); -} -void CEditWithButtons::AddClearButton(const wchar_t * clearVal, bool bHandleEsc) { - std::wstring clearValCopy(clearVal); - auto handler = [this, clearValCopy] { - this->SetWindowText(clearValCopy.c_str()); - }; - auto condition = [clearValCopy](const wchar_t * txt) -> bool { - return clearValCopy != txt; - }; - // Present "clear" to accessibility APIs but actually draw a multiplication x sign - AddButton(L"clear", handler, condition, L"\x00D7"); - - if (bHandleEsc) { - this->onEscKey = handler; - } - -} - -void CEditWithButtons::AddButton(const wchar_t * str, handler_t handler, condition_t condition, const wchar_t * drawAlternateText) { - Button_t btn; - btn.handler = handler; - btn.title = str; - btn.condition = condition; - btn.visible = EvalCondition(btn, nullptr); - - if (drawAlternateText != nullptr) { - btn.titleDraw = drawAlternateText; - } - - m_buttons.push_back(std::move(btn)); - RefreshButtons(); -} - -CRect CEditWithButtons::RectOfButton(const wchar_t * text) { - for (auto i = m_buttons.begin(); i != m_buttons.end(); ++i) { - if (i->title == text && i->wnd != NULL) { - CRect rc; - if (i->wnd.GetWindowRect(rc)) return rc; - } - } - return CRect(); -} - -void CEditWithButtons::TabCycleButtons(HWND wnd) { - for (auto i = m_buttons.begin(); i != m_buttons.end(); ++i) { - if (i->wnd == wnd) { - if (IsShiftPressed()) { - // back - for (;; ) { - if (i == m_buttons.begin()) { - TabFocusThis(m_hWnd); break; - } else { - --i; - if (i->visible) { - TabFocusThis(i->wnd); - break; - } - } - } - } else { - // forward - for (;; ) { - ++i; - if (i == m_buttons.end()) { - TabFocusThis(m_hWnd); - TabFocusPrevNext(false); - break; - } else { - if (i->visible) { - TabFocusThis(i->wnd); - break; - } - } - } - } - - return; - } - } -} - - -bool CEditWithButtons::ButtonWantTab(HWND wnd) { - if (IsShiftPressed()) return true; - if (m_buttons.size() == 0) return false; // should not be possible - auto last = m_buttons.rbegin(); - if (wnd == last->wnd) return false; // not for last button - return true; -} -bool CEditWithButtons::EvalCondition(Button_t & btn, const wchar_t * newText) { - if (!btn.condition) return true; - if (newText != nullptr) return btn.condition(newText); - TCHAR text[256] = {}; - GetWindowText(text, 256); - text[255] = 0; - return btn.condition(text); -} -void CEditWithButtons::RefreshConditions(const wchar_t * newText) { - bool changed = false; - for (auto i = m_buttons.begin(); i != m_buttons.end(); ++i) { - bool status = EvalCondition(*i, newText); - if (status != i->visible) { - i->visible = status; changed = true; - } - } - if (changed) { - Layout(); - } -} - -void CEditWithButtons::Layout(CSize size, CFontHandle fontSetMe) { - if (m_buttons.size() == 0) return; - - int walk = size.cx; - - HDWP dwp = BeginDeferWindowPos((int)m_buttons.size()); - for (auto iter = m_buttons.rbegin(); iter != m_buttons.rend(); ++iter) { - if (!iter->visible) { - if (::GetFocus() == iter->wnd) { - this->SetFocus(); - } - ::DeferWindowPos(dwp, iter->wnd, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_HIDEWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_NOCOPYBITS); - continue; - } - - if (iter->wnd == NULL) { - auto b = std::make_shared< CButtonLite >(); - iter->buttonImpl = b; - b->Create(*this, NULL, iter->title.c_str()); - if (iter->titleDraw.length() > 0) b->DrawAlternateText(iter->titleDraw.c_str()); - CFontHandle font = fontSetMe; - if (font == NULL) font = GetFont(); - b->SetFont(font); - b->ClickHandler = iter->handler; - b->CtlColorHandler = [=](CDCHandle dc) -> HBRUSH { - return this->OnColorBtn(dc, NULL); - }; - b->TabCycleHandler = [=](HWND wnd) { - TabCycleButtons(wnd); - }; - b->WantTabCheck = [=](HWND wnd) -> bool { - return ButtonWantTab(wnd); - }; - if (!IsWindowEnabled()) b->EnableWindow(FALSE); - iter->wnd = *b; - } else if (fontSetMe) { - iter->wnd.SetFont(fontSetMe); - } - - unsigned delta = MeasureButton(*iter); - int left = walk - delta; - - if (iter->wnd != NULL) { - CRect rc; - rc.top = 0; - rc.bottom = size.cy; - rc.left = left; - rc.right = walk; - ::DeferWindowPos(dwp, iter->wnd, NULL, rc.left, rc.top, rc.Width(), rc.Height(), SWP_NOZORDER | SWP_SHOWWINDOW | SWP_NOCOPYBITS); - } - - walk = left; - } - EndDeferWindowPos(dwp); - this->SetMargins(0, size.cx - walk, EC_RIGHTMARGIN); -} - -unsigned CEditWithButtons::MeasureButton(Button_t const & button) { - if (m_fixedWidth != 0) return m_fixedWidth; - - return button.buttonImpl->Measure(); -} diff --git a/libPPUI/CEnumString.h b/libPPUI/CEnumString.h deleted file mode 100644 index eb456c3..0000000 --- a/libPPUI/CEnumString.h +++ /dev/null @@ -1,99 +0,0 @@ -#pragma once -#include -#include "pp-COM-macros.h" - -namespace PP { - - class CEnumString : public IEnumString { - public: - typedef pfc::chain_list_v2_t > t_data; - typedef std::shared_ptr shared_t; - - CEnumString(t_data && in) { - m_shared = std::make_shared(std::move(in)); - Reset(); - } - CEnumString(const t_data & in) { - m_shared = std::make_shared(in); - Reset(); - } - CEnumString() { - m_shared = std::make_shared< t_data >(); - } - - void SetStrings(t_data && data) { - *m_shared = std::move(data); - Reset(); - } - - static pfc::array_t stringToBuffer(const char * in) { - pfc::array_t arr; - arr.set_size(pfc::stringcvt::estimate_utf8_to_wide(in)); - pfc::stringcvt::convert_utf8_to_wide_unchecked(arr.get_ptr(), in); - return arr; - } - - void AddString(const TCHAR * in) { - m_shared->insert_last()->set_data_fromptr(in, _tcslen(in) + 1); - Reset(); - } - void AddStringU(const char * in, t_size len) { - pfc::array_t & arr = *m_shared->insert_last(); - arr.set_size(pfc::stringcvt::estimate_utf8_to_wide(in, len)); - pfc::stringcvt::convert_utf8_to_wide(arr.get_ptr(), arr.get_size(), in, len); - Reset(); - } - void AddStringU(const char * in) { - *m_shared->insert_last() = stringToBuffer(in); - Reset(); - } - void ResetStrings() { - m_shared->remove_all(); - Reset(); - } - - typedef ImplementCOMRefCounter TImpl; - COM_QI_BEGIN() - COM_QI_ENTRY(IUnknown) - COM_QI_ENTRY(IEnumString) - COM_QI_END() - - HRESULT STDMETHODCALLTYPE Next(ULONG celt, LPOLESTR *rgelt, ULONG *pceltFetched) { - if (rgelt == NULL) return E_INVALIDARG; - ULONG done = 0; - while (done < celt && m_walk.is_valid()) { - rgelt[done] = CoStrDup(m_walk->get_ptr()); - ++m_walk; ++done; - } - if (pceltFetched != NULL) *pceltFetched = done; - return done == celt ? S_OK : S_FALSE; - } - - static TCHAR * CoStrDup(const TCHAR * in) { - const size_t lenBytes = (_tcslen(in) + 1) * sizeof(TCHAR); - TCHAR * out = reinterpret_cast(CoTaskMemAlloc(lenBytes)); - if (out) memcpy(out, in, lenBytes); - return out; - } - - HRESULT STDMETHODCALLTYPE Skip(ULONG celt) { - while (celt > 0) { - if (m_walk.is_empty()) return S_FALSE; - --celt; ++m_walk; - } - return S_OK; - } - - HRESULT STDMETHODCALLTYPE Reset() { - m_walk = m_shared->first(); - return S_OK; - } - - HRESULT STDMETHODCALLTYPE Clone(IEnumString **ppenum) { - *ppenum = new TImpl(*this); return S_OK; - } - private: - shared_t m_shared; - t_data::const_iterator m_walk; - }; -} diff --git a/libPPUI/CHeaderCtrlEx.h b/libPPUI/CHeaderCtrlEx.h deleted file mode 100644 index 9b13569..0000000 --- a/libPPUI/CHeaderCtrlEx.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -class CHeaderCtrlEx : public CHeaderCtrl { -public: - CHeaderCtrlEx(HWND wnd = NULL) : CHeaderCtrl(wnd) {} - CHeaderCtrlEx const & operator=(HWND wnd) { m_hWnd = wnd; return *this; } - - // Column sort marker operations - // If they appear to have no effect, you're probably missing Common Controls 6 manifest, see link-CommonControls6.h - DWORD GetItemFormat(int iItem); - void SetItemFormat(int iItem, DWORD flags); - void SetItemSort(int iItem, int direction); - void SetSingleItemSort(int iItem, int direction); - void ClearSort(); -}; diff --git a/libPPUI/CListAccessible.cpp b/libPPUI/CListAccessible.cpp deleted file mode 100644 index c9e2e8b..0000000 --- a/libPPUI/CListAccessible.cpp +++ /dev/null @@ -1,744 +0,0 @@ -#include "stdafx.h" -#include "CListAccessible.h" - -#include "pp-COM-macros.h" - -static size_t IndexFromChildId(LONG id) {return (size_t)(id-1);} -static LONG ChildIdFromIndex(size_t index) {return (LONG)(index+1);} - -class IEnumVARIANT_selection : public ImplementCOMRefCounter { -public: - IEnumVARIANT_selection(const LONG * data,size_t dataCount, ULONG pos = 0) : m_pos(pos) { - m_data.set_data_fromptr(data,dataCount); - } - - COM_QI_BEGIN() - COM_QI_ENTRY(IEnumVARIANT) - COM_QI_ENTRY(IUnknown) - COM_QI_END() - - // IEnumVARIANT methods - STDMETHOD(Next)(ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched); - STDMETHOD(Skip)(ULONG celt); - STDMETHOD(Reset)(); - STDMETHOD(Clone)(IEnumVARIANT **ppEnum); -private: - pfc::array_t m_data; - ULONG m_pos; -}; - - -HRESULT IEnumVARIANT_selection::Next(ULONG celt, VARIANT *rgVar, ULONG *pceltFetched) { - if (rgVar == NULL) return E_INVALIDARG; - - if (pceltFetched) *pceltFetched = 0; - - ULONG n; - for (n = 0; n < celt; n++) VariantInit(&rgVar[n]); - - for (n = 0; n < celt && m_pos+n < m_data.get_size(); n++) { - rgVar[n].vt = VT_I4; - rgVar[n].lVal = m_data[m_pos+n]; - } - - if (pceltFetched) *pceltFetched = n; - - m_pos += n; - - return n == celt ? S_OK : S_FALSE; -} - -HRESULT IEnumVARIANT_selection::Skip(ULONG celt) { - m_pos += celt; - if (m_pos > m_data.get_size()) { - m_pos = (ULONG)m_data.get_size(); - return S_FALSE; - } - return S_OK; -} - -HRESULT IEnumVARIANT_selection::Reset() { - m_pos = 0; - return S_OK; -} - -HRESULT IEnumVARIANT_selection::Clone(IEnumVARIANT **ppEnum) -{ - if (ppEnum == NULL) - return E_INVALIDARG; - - IEnumVARIANT * var; - try { - var = new IEnumVARIANT_selection(m_data.get_ptr(), m_data.get_size(), m_pos); - } catch(std::bad_alloc) {return E_OUTOFMEMORY;} - - var->AddRef(); - *ppEnum = var; - - return S_OK; -} - -namespace { - class WeakRef { - public: - WeakRef( CListAccessible * ptr_, std::shared_ptr ks_ ) : ptr(ptr_), ks(ks_) {} - - CListAccessible * operator->() const { return ptr; } - - bool IsEmpty() const { - return * ks; - } - private: - CListAccessible * ptr; - std::shared_ptr ks; - }; -} - -class IAccessible_CListControl : public ImplementCOMRefCounter { -public: - IAccessible_CListControl(WeakRef owner) : m_owner(owner) {} - COM_QI_BEGIN() - COM_QI_ENTRY(IUnknown) - COM_QI_ENTRY(IDispatch) - COM_QI_ENTRY(IAccessible) - COM_QI_END() - - //IDispatch - STDMETHOD(GetTypeInfoCount)(UINT * pcTInfo); - STDMETHOD(GetTypeInfo)(UINT iTInfo, LCID lcid, ITypeInfo ** ppTInfo); - STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId); - STDMETHOD(Invoke)(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS * pDispParams, VARIANT * pVarResult, EXCEPINFO * pExcepInfo, UINT * puArgErr); - //IAccessible - STDMETHOD(get_accParent)(IDispatch **ppdispParent); // required - STDMETHOD(get_accChildCount)(long *pcountChildren); - STDMETHOD(get_accChild)(VARIANT varChild, IDispatch **ppdispChild); - STDMETHOD(get_accName)(VARIANT varChild, BSTR *pszName); // required - STDMETHOD(get_accValue)(VARIANT varChild, BSTR *pszValue); - STDMETHOD(get_accDescription)(VARIANT varChild, BSTR *pszDescription); - STDMETHOD(get_accRole)(VARIANT varChild, VARIANT *pvarRole); // required - STDMETHOD(get_accState)(VARIANT varChild, VARIANT *pvarState); // required - STDMETHOD(get_accHelp)(VARIANT varChild, BSTR *pszHelp); - STDMETHOD(get_accHelpTopic)(BSTR *pszHelpFile, VARIANT varChild, long *pidTopic); - STDMETHOD(get_accKeyboardShortcut)(VARIANT varChild, BSTR *pszKeyboardShortcut); - STDMETHOD(get_accFocus)(VARIANT *pvarChild); - STDMETHOD(get_accSelection)(VARIANT *pvarChildren); - STDMETHOD(get_accDefaultAction)(VARIANT varChild, BSTR *pszDefaultAction); - STDMETHOD(accSelect)(long flagsSelect, VARIANT varChild); - STDMETHOD(accLocation)(long *pxLeft, long *pyTop, long *pcxWidth, long *pcyHeight, VARIANT varChild); // required - STDMETHOD(accNavigate)(long navDir, VARIANT varStart, VARIANT *pvarEndUpAt); - STDMETHOD(accHitTest)(long xLeft, long yTop, VARIANT *pvarChild); - STDMETHOD(accDoDefaultAction)(VARIANT varChild); - STDMETHOD(put_accName)(VARIANT varChild, BSTR szName); - STDMETHOD(put_accValue)(VARIANT varChild, BSTR szValue); -private: - const WeakRef m_owner; -}; - -void CListAccessible::AccInitialize(CWindow wnd) { - m_wnd = wnd; -} -void CListAccessible::AccCleanup() { - if (m_interface.is_valid()) { - NotifyWinEvent(EVENT_OBJECT_DESTROY, m_wnd, OBJID_CLIENT, CHILDID_SELF); - m_interface.release(); - } - m_wnd = NULL; -} - -LRESULT CListAccessible::AccGetObject(WPARAM wp,LPARAM lp) { - const WPARAM dwFlags = wp; - const LPARAM dwObjId = lp; - - if (dwObjId == OBJID_CLIENT) - { - if (m_interface.is_empty()) - { - try { - m_interface = new IAccessible_CListControl( WeakRef(this, m_killSwitch) ); - } catch(...) { - //bah - return DefWindowProc(m_wnd,WM_GETOBJECT,wp,lp); - } - NotifyWinEvent(EVENT_OBJECT_CREATE, m_wnd, OBJID_CLIENT, CHILDID_SELF); - } - return LresultFromObject(IID_IAccessible, dwFlags, m_interface.get_ptr()); - } - else return DefWindowProc(m_wnd,WM_GETOBJECT,wp,lp); -} - -void CListAccessible::AccItemNamesChanged(pfc::bit_array const & mask) { - this->AccRefreshItems(mask, EVENT_OBJECT_NAMECHANGE); -} -void CListAccessible::AccReloadItems(pfc::bit_array const & mask) { - this->AccRefreshItems(mask, EVENT_OBJECT_NAMECHANGE); -} -void CListAccessible::AccStateChange(pfc::bit_array const & mask) { - this->AccRefreshItems(mask, EVENT_OBJECT_STATECHANGE); -} -void CListAccessible::AccStateChange(size_t index) { - this->AccStateChange(pfc::bit_array_one(index)); -} -void CListAccessible::AccRefreshItems(pfc::bit_array const & affected, UINT what) { - if (m_wnd == NULL || m_interface.is_empty()) return; - //if (GetFocus() != m_hWnd) return; - const size_t total = AccGetItemCount(); - for (size_t walk = affected.find_first(true, 0, total); walk < total; walk = affected.find_next(true, walk, total)) { - NotifyWinEvent(what, m_wnd, OBJID_CLIENT, ChildIdFromIndex(walk)); - } -} -void CListAccessible::AccItemLayoutChanged() { - if (m_wnd == NULL || m_interface.is_empty()) return; - NotifyWinEvent(EVENT_OBJECT_REORDER, m_wnd, OBJID_CLIENT, CHILDID_SELF); -} -void CListAccessible::AccFocusItemChanged(size_t index) { - if (m_wnd == NULL || m_interface.is_empty()) return; - if (GetFocus() != m_wnd) return; - NotifyWinEvent(EVENT_OBJECT_FOCUS, m_wnd, OBJID_CLIENT, index != SIZE_MAX ? ChildIdFromIndex(index) : CHILDID_SELF); -} -void CListAccessible::AccFocusOtherChanged(size_t index) { - if (m_wnd == NULL || m_interface.is_empty()) return; - if (GetFocus() != m_wnd) return; - const size_t itemCount = this->AccGetItemCount(); - index += itemCount; - NotifyWinEvent(EVENT_OBJECT_FOCUS, m_wnd, OBJID_CLIENT, index != SIZE_MAX ? ChildIdFromIndex(index) : CHILDID_SELF); -} -void CListAccessible::AccSelectionChanged(const pfc::bit_array & affected, const pfc::bit_array & state) { - if (m_wnd == NULL || m_interface.is_empty()) return; - //if (GetFocus() != m_wnd) return; - const size_t itemCount = this->AccGetItemCount(); - - const size_t limit = 20; - if (affected.calc_count(true, 0, itemCount, limit) == limit) { - NotifyWinEvent(EVENT_OBJECT_SELECTIONWITHIN, m_wnd, OBJID_CLIENT, CHILDID_SELF); - } else for(size_t walk = affected.find_first(true,0,itemCount); walk < itemCount; walk = affected.find_next(true,walk,itemCount)) { - NotifyWinEvent(state[walk] ? EVENT_OBJECT_SELECTIONADD : EVENT_OBJECT_SELECTIONREMOVE, m_wnd, OBJID_CLIENT, ChildIdFromIndex(walk)); - } -} -void CListAccessible::AccLocationChange() { - if (m_wnd == NULL || m_interface.is_empty()) return; - NotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE,m_wnd,OBJID_CLIENT, CHILDID_SELF); -} - -HRESULT IAccessible_CListControl::GetTypeInfoCount(UINT * pcTInfo) { - return E_NOTIMPL; -} - -HRESULT IAccessible_CListControl::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo ** ppTInfo) { - return E_NOTIMPL; -} - -HRESULT IAccessible_CListControl::GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) { - return E_NOTIMPL; -} - -HRESULT IAccessible_CListControl::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS * pDispParams, VARIANT * pVarResult, EXCEPINFO * pExcepInfo, UINT * puArgErr) { - return E_NOTIMPL; -} - -HRESULT IAccessible_CListControl::get_accParent(IDispatch **ppdispParent) // required -{ - if (ppdispParent == NULL) return E_INVALIDARG; - if (m_owner.IsEmpty()) return E_FAIL; - - *ppdispParent = NULL; - HRESULT hResult = AccessibleObjectFromWindow(m_owner->AccGetWnd(), OBJID_WINDOW, IID_IDispatch, (void**)ppdispParent); - return (hResult == S_OK) ? S_OK : S_FALSE; -} - -HRESULT IAccessible_CListControl::get_accChildCount(long *pcountChildren) { - if (pcountChildren == NULL) return E_INVALIDARG; - if (m_owner.IsEmpty()) return E_FAIL; - *pcountChildren = (long)( m_owner->AccGetItemCount() + m_owner->AccGetOtherCount() ); - return S_OK; -} -HRESULT IAccessible_CListControl::get_accChild(VARIANT varChild, IDispatch **ppdispChild) { - if (varChild.vt != VT_I4) return E_INVALIDARG; - if (ppdispChild == NULL) return E_INVALIDARG; - if (varChild.lVal == CHILDID_SELF) { - *ppdispChild = this; AddRef(); - return S_OK; - } else { - if (m_owner.IsEmpty()) return E_FAIL; - const size_t index = IndexFromChildId(varChild.lVal); - const size_t itemCount = m_owner->AccGetItemCount(); - if (index < itemCount) { - return S_FALSE; - } else if (index < itemCount + m_owner->AccGetOtherCount()) { - CWindow wnd = m_owner->AccGetOtherChildWnd(index - itemCount); - if (wnd == NULL) return S_FALSE; - if (AccessibleObjectFromWindow(wnd, OBJID_WINDOW, IID_IDispatch, (void**)ppdispChild) != S_OK) return S_FALSE; - return S_OK; - } else { - return E_INVALIDARG; - } - } -} - - -HRESULT IAccessible_CListControl::get_accName(VARIANT varChild, BSTR *pszName) // required -{ - if (varChild.vt != VT_I4) return E_INVALIDARG; - if (pszName == NULL) return E_INVALIDARG; - if (m_owner.IsEmpty()) return E_FAIL; - pfc::string8_fastalloc name; - if (varChild.lVal == CHILDID_SELF) { - m_owner->AccGetName(name); - } else { - const size_t index = IndexFromChildId(varChild.lVal); - const size_t itemCount = m_owner->AccGetItemCount(); - if (index < itemCount) { - m_owner->AccGetItemName(index,name); - } else if (index < itemCount + m_owner->AccGetOtherCount()) { - m_owner->AccGetOtherName(index - itemCount, name); - } else { - return E_INVALIDARG; - } - } - *pszName = SysAllocString(pfc::stringcvt::string_wide_from_utf8(name)); - return S_OK; -} -HRESULT IAccessible_CListControl::get_accValue(VARIANT varChild, BSTR *pszValue) { - if (varChild.vt != VT_I4) - return E_INVALIDARG; - if (pszValue == NULL) - return E_INVALIDARG; - - return S_FALSE; -} -HRESULT IAccessible_CListControl::get_accDescription(VARIANT varChild, BSTR *pszDescription) { - if (varChild.vt != VT_I4) return E_INVALIDARG; - if (pszDescription == NULL) return E_INVALIDARG; - if (varChild.lVal == CHILDID_SELF) return S_FALSE; - if (m_owner.IsEmpty()) return E_FAIL; - - *pszDescription = NULL; - - const size_t itemCount = m_owner->AccGetItemCount(); - const size_t index = IndexFromChildId(varChild.lVal); - - pfc::string_formatter temp; - if (index < itemCount) { - if (!m_owner->AccGetItemDescription(index, temp)) return S_FALSE; - } else if (index < itemCount + m_owner->AccGetOtherCount()) { - if (!m_owner->AccGetOtherDescription(index - itemCount, temp)) return S_FALSE; - } else { - return E_INVALIDARG; - } - *pszDescription = SysAllocString(pfc::stringcvt::string_os_from_utf8(temp)); - return S_OK; -} - -HRESULT IAccessible_CListControl::get_accRole(VARIANT varChild, VARIANT *pvarRole) // required -{ - if (varChild.vt != VT_I4) return E_INVALIDARG; - if (pvarRole == NULL) return E_INVALIDARG; - if (m_owner.IsEmpty()) return E_FAIL; - VariantClear(pvarRole); - pvarRole->vt = VT_I4; - if (varChild.lVal == CHILDID_SELF) { - pvarRole->lVal = ROLE_SYSTEM_LIST; - } else { - const size_t itemCount = m_owner->AccGetItemCount(); - const size_t index = IndexFromChildId(varChild.lVal); - if (index < itemCount) { - pvarRole->lVal = m_owner->AccGetItemRole( index ); - } else if (index < itemCount + m_owner->AccGetOtherCount()) { - pvarRole->lVal = m_owner->AccGetOtherRole(index - itemCount); - } else { - return E_INVALIDARG; - } - } - return S_OK; -} - -HRESULT IAccessible_CListControl::get_accState(VARIANT varChild, VARIANT *pvarState) // required -{ - if (varChild.vt != VT_I4) return E_INVALIDARG; - if (pvarState == NULL) return E_INVALIDARG; - if (m_owner.IsEmpty()) return E_FAIL; - - VariantClear(pvarState); - pvarState->vt = VT_I4; - - if (varChild.lVal == CHILDID_SELF) { - pvarState->lVal = /*STATE_SYSTEM_NORMAL*/ 0; - if (GetFocus() == m_owner->AccGetWnd()) - pvarState->lVal |= STATE_SYSTEM_FOCUSED; - } - else - { - const size_t index = IndexFromChildId(varChild.lVal); - const size_t itemCount = m_owner->AccGetItemCount(); - if (index < itemCount) { - pvarState->lVal = STATE_SYSTEM_MULTISELECTABLE | STATE_SYSTEM_SELECTABLE; - if (GetFocus() == m_owner->AccGetWnd()) { - pvarState->lVal |= STATE_SYSTEM_FOCUSABLE; - if (m_owner->AccGetFocusItem() == index) pvarState->lVal |= STATE_SYSTEM_FOCUSED; - } - if (m_owner->AccIsItemSelected(index)) pvarState->lVal |= STATE_SYSTEM_SELECTED; - if (!m_owner->AccIsItemVisible(index)) pvarState->lVal |= STATE_SYSTEM_OFFSCREEN | STATE_SYSTEM_INVISIBLE; - if (m_owner->AccIsItemChecked(index)) pvarState->lVal |= STATE_SYSTEM_CHECKED; - } else if (index < itemCount + m_owner->AccGetOtherCount()) { - const size_t indexO = index - itemCount; - pvarState->lVal = 0; - if (m_owner->AccIsOtherFocusable(indexO) && GetFocus() == m_owner->AccGetWnd()) { - pvarState->lVal |= STATE_SYSTEM_FOCUSABLE; - if (m_owner->AccGetFocusOther() == indexO) pvarState->lVal |= STATE_SYSTEM_FOCUSED; - } - if (!m_owner->AccIsOtherVisible(indexO)) pvarState->lVal |= STATE_SYSTEM_OFFSCREEN | STATE_SYSTEM_INVISIBLE; - } else { - return E_INVALIDARG; - } - } - return S_OK; -} -HRESULT IAccessible_CListControl::get_accHelp(VARIANT varChild, BSTR *pszHelp) -{ - if (varChild.vt != VT_I4) - return E_INVALIDARG; - if (pszHelp == NULL) - return E_INVALIDARG; - return S_FALSE; -} -HRESULT IAccessible_CListControl::get_accHelpTopic(BSTR *pszHelpFile, VARIANT varChild, long *pidTopic) -{ - if (varChild.vt != VT_I4) - return E_INVALIDARG; - if (pszHelpFile == NULL) - return E_INVALIDARG; - if (pidTopic == NULL) - return E_INVALIDARG; - return S_FALSE; -} -HRESULT IAccessible_CListControl::get_accKeyboardShortcut(VARIANT varChild, BSTR *pszKeyboardShortcut) -{ - if (pszKeyboardShortcut == NULL) - return E_INVALIDARG; - return S_FALSE; -} -HRESULT IAccessible_CListControl::get_accFocus(VARIANT *pvarChild) -{ - if (pvarChild == NULL) return E_INVALIDARG; - if (m_owner.IsEmpty()) return E_FAIL; - VariantClear(pvarChild); - if (GetFocus() != m_owner->AccGetWnd()) - pvarChild->vt = VT_EMPTY; - else { - pvarChild->vt = VT_I4; - size_t index = m_owner->AccGetFocusItem(); - if (index != ~0) { - pvarChild->lVal = ChildIdFromIndex(index); - } else { - index = m_owner->AccGetFocusOther(); - if (index != ~0) { - pvarChild->lVal = ChildIdFromIndex(index + m_owner->AccGetItemCount()); - } else { - pvarChild->lVal = CHILDID_SELF; - } - } - } - return S_OK; -} -HRESULT IAccessible_CListControl::get_accSelection(VARIANT *pvarChildren) -{ - if (pvarChildren == NULL) return E_INVALIDARG; - if (m_owner.IsEmpty()) return E_FAIL; - VariantClear(pvarChildren); - try { - - const size_t itemCount = m_owner->AccGetItemCount(); - size_t selCount = 0; - pfc::bit_array_bittable mask(itemCount); - for(size_t walk = 0; walk < itemCount; ++walk) { - bool state = m_owner->AccIsItemSelected(walk); - mask.set(walk,state); - if (state) selCount++; - } - - if (selCount == 0) { - pvarChildren->vt = VT_EMPTY; - } else if (selCount == 1) { - pvarChildren->vt = VT_I4; - pvarChildren->lVal = ChildIdFromIndex(mask.find_first(true, 0, itemCount)); - } else { - pfc::array_t data; data.set_size(selCount); size_t dataWalk = 0; - for(size_t walk = mask.find_first(true,0,itemCount); walk < itemCount; walk = mask.find_next(true,walk,itemCount)) { - data[dataWalk++] = ChildIdFromIndex(walk); - } - IEnumVARIANT * ptr = new IEnumVARIANT_selection(data.get_ptr(),data.get_size()); - ptr->AddRef(); - pvarChildren->vt = VT_UNKNOWN; - pvarChildren->punkVal = ptr; - } - } catch(std::bad_alloc) { - return E_OUTOFMEMORY; - } - return S_OK; -} -HRESULT IAccessible_CListControl::get_accDefaultAction(VARIANT varChild, BSTR *pszDefaultAction) -{ - if (varChild.vt != VT_I4) return E_INVALIDARG; - if (pszDefaultAction == NULL) return E_INVALIDARG; - if (m_owner.IsEmpty()) return E_FAIL; - *pszDefaultAction = NULL; - if (varChild.lVal == CHILDID_SELF) { - return S_FALSE; - } else { - pfc::string_formatter temp; - const size_t index = IndexFromChildId(varChild.lVal); - const size_t itemCount = m_owner->AccGetItemCount(); - if (index < itemCount) { - if (!m_owner->AccGetItemDefaultAction(temp)) return S_FALSE; - } else if (index < itemCount + m_owner->AccGetOtherCount()) { - if (!m_owner->AccGetOtherDefaultAction(index - itemCount, temp)) return false; - } else { - return E_INVALIDARG; - } - - *pszDefaultAction = SysAllocString(pfc::stringcvt::string_os_from_utf8(temp)); - return S_OK; - } -} -HRESULT IAccessible_CListControl::accSelect(long flagsSelect, VARIANT varChild) -{ - if (varChild.vt != VT_EMPTY && varChild.vt != VT_I4) return E_INVALIDARG; - if (m_owner.IsEmpty()) return E_FAIL; - if (varChild.vt == VT_EMPTY || varChild.lVal == CHILDID_SELF) - { - switch (flagsSelect) - { - case SELFLAG_TAKEFOCUS: - m_owner->AccGetWnd().SetFocus(); - return S_OK; - default: - return DISP_E_MEMBERNOTFOUND; - } - } - else - { - const size_t count = m_owner->AccGetItemCount(); - const size_t index = IndexFromChildId(varChild.lVal); - if (index < count) { - if (flagsSelect & SELFLAG_TAKESELECTION) - { - if (flagsSelect & (SELFLAG_ADDSELECTION | SELFLAG_REMOVESELECTION | SELFLAG_EXTENDSELECTION)) - return E_INVALIDARG; - m_owner->AccSetSelection(pfc::bit_array_true(), pfc::bit_array_one(index)); - } - else if (flagsSelect & SELFLAG_EXTENDSELECTION) - { - if (flagsSelect & SELFLAG_TAKESELECTION) - return E_INVALIDARG; - size_t focus = m_owner->AccGetFocusItem(); - if (focus == ~0) return S_FALSE; - bool state; - if (flagsSelect & SELFLAG_ADDSELECTION) - { - if (flagsSelect & SELFLAG_REMOVESELECTION) - return E_INVALIDARG; - state = true; - } - else if (flagsSelect & SELFLAG_REMOVESELECTION) - { - if (flagsSelect & SELFLAG_ADDSELECTION) - return E_INVALIDARG; - state = false; - } - else - { - state = m_owner->AccIsItemSelected(focus); - } - m_owner->AccSetSelection(pfc::bit_array_range(min(index, focus), max(index, focus)-min(index, focus)+1), pfc::bit_array_val(state)); - } - else if (flagsSelect & SELFLAG_ADDSELECTION) - { - if (flagsSelect & (SELFLAG_REMOVESELECTION | SELFLAG_EXTENDSELECTION)) - return E_INVALIDARG; - m_owner->AccSetSelection(pfc::bit_array_one(index), pfc::bit_array_true()); - } - else if (flagsSelect & SELFLAG_REMOVESELECTION) - { - if (flagsSelect & (SELFLAG_ADDSELECTION | SELFLAG_EXTENDSELECTION)) - return E_INVALIDARG; - m_owner->AccSetSelection(pfc::bit_array_one(index), pfc::bit_array_false()); - } - - if (flagsSelect & SELFLAG_TAKEFOCUS) { - m_owner->AccSetFocusItem(index); - } - } else if (index < count + m_owner->AccGetOtherCount()) { - const size_t indexO = index - count; - if (flagsSelect & SELFLAG_TAKEFOCUS) { - m_owner->AccSetFocusOther(indexO); - } - } else { - return E_INVALIDARG; - } - return S_OK; - } -} -HRESULT IAccessible_CListControl::accLocation(long *pxLeft, long *pyTop, long *pcxWidth, long *pcyHeight, VARIANT varChild) // required -{ - if (varChild.vt != VT_I4) return E_INVALIDARG; - if (pxLeft == NULL || pyTop == NULL || pcxWidth == NULL || pcyHeight == NULL) return E_INVALIDARG; - if (m_owner.IsEmpty()) return E_FAIL; - CRect rc; - const CWindow ownerWnd = m_owner->AccGetWnd(); - if (varChild.lVal == CHILDID_SELF) { - if (!ownerWnd.GetClientRect(&rc)) return E_FAIL; - } else { - const size_t index = IndexFromChildId(varChild.lVal); - const size_t itemCount = m_owner->AccGetItemCount(); - if (index < itemCount) { - if (!m_owner->AccGetItemRect(index,rc)) return S_FALSE; - } else if (index < itemCount + m_owner->AccGetOtherCount()) { - if (!m_owner->AccGetOtherRect(index - itemCount, rc)) return S_FALSE; - } else { - return E_INVALIDARG; - } - } - - if (!ownerWnd.ClientToScreen(rc)) return E_FAIL; - *pxLeft = rc.left; - *pyTop = rc.top; - *pcxWidth = rc.right-rc.left; - *pcyHeight = rc.bottom-rc.top; - return S_OK; -} -HRESULT IAccessible_CListControl::accNavigate(long navDir, VARIANT varStart, VARIANT *pvarEndUpAt) -{ - if (varStart.vt != VT_I4 && varStart.vt != VT_EMPTY) return E_INVALIDARG; - if (pvarEndUpAt == NULL) return E_INVALIDARG; - if (m_owner.IsEmpty()) return E_FAIL; - VariantClear(pvarEndUpAt); - pvarEndUpAt->vt = VT_EMPTY; - if (varStart.vt == VT_EMPTY || varStart.lVal == CHILDID_SELF) - { - switch (navDir) - { - case NAVDIR_LEFT: - case NAVDIR_RIGHT: - case NAVDIR_UP: - case NAVDIR_DOWN: - case NAVDIR_PREVIOUS: - case NAVDIR_NEXT: - // leave empty - break; - case NAVDIR_FIRSTCHILD: - if (m_owner->AccGetItemCount() > 0) - { - pvarEndUpAt->vt = VT_I4; - pvarEndUpAt->lVal = ChildIdFromIndex(0); - } - break; - case NAVDIR_LASTCHILD: - if (m_owner->AccGetItemCount() > 0) - { - pvarEndUpAt->vt = VT_I4; - pvarEndUpAt->lVal = ChildIdFromIndex(m_owner->AccGetItemCount()-1); - } - break; - } - } - else - { - const size_t index = IndexFromChildId(varStart.lVal); - const size_t itemCount = m_owner->AccGetItemCount(); - if (index >= itemCount) { - if (index < itemCount + m_owner->AccGetOtherCount()) return S_FALSE; - else return E_INVALIDARG; - } - switch (navDir) - { - case NAVDIR_LEFT: - case NAVDIR_RIGHT: - case NAVDIR_FIRSTCHILD: - case NAVDIR_LASTCHILD: - // leave empty - break; - case NAVDIR_UP: - case NAVDIR_PREVIOUS: - if (index > 0) - { - pvarEndUpAt->vt = VT_I4; - pvarEndUpAt->lVal = ChildIdFromIndex(index-1); - } - break; - case NAVDIR_DOWN: - case NAVDIR_NEXT: - if (index+1 < itemCount) - { - pvarEndUpAt->vt = VT_I4; - pvarEndUpAt->lVal = ChildIdFromIndex(index+1); - } - break; - } - } - return (pvarEndUpAt->vt != VT_EMPTY) ? S_OK : S_FALSE; -} -HRESULT IAccessible_CListControl::accHitTest(long xLeft, long yTop, VARIANT *pvarChild) -{ - if (pvarChild == NULL) return E_INVALIDARG; - if (m_owner.IsEmpty()) return E_FAIL; - VariantClear(pvarChild); - CPoint pt (xLeft, yTop); - const CWindow ownerWnd = m_owner->AccGetWnd(); - if (!ownerWnd.ScreenToClient(&pt)) return E_FAIL; - CRect rcClient; - if (!ownerWnd.GetClientRect(&rcClient)) return E_FAIL; - if (PtInRect(&rcClient, pt)) { - size_t index = m_owner->AccItemHitTest(pt); - if (index != ~0) { - pvarChild->vt = VT_I4; - pvarChild->lVal = ChildIdFromIndex(index); - } else { - index = m_owner->AccOtherHitTest(pt); - if (index != ~0) { - pvarChild->vt = VT_I4; - pvarChild->lVal = ChildIdFromIndex(m_owner->AccGetItemCount() + index); - CWindow wnd = m_owner->AccGetOtherChildWnd(index); - if (wnd != NULL) { - IDispatch * obj; - if (AccessibleObjectFromWindow(wnd,OBJID_WINDOW, IID_IDispatch, (void**)&obj) == S_OK) { - pvarChild->vt = VT_DISPATCH; - pvarChild->pdispVal = obj; - } - } - } else { - pvarChild->vt = VT_I4; - pvarChild->lVal = CHILDID_SELF; - } - } - } else { - pvarChild->vt = VT_EMPTY; - } - return S_OK; -} -HRESULT IAccessible_CListControl::accDoDefaultAction(VARIANT varChild) -{ - if (varChild.vt != VT_I4) return E_INVALIDARG; - if (m_owner.IsEmpty()) return E_FAIL; - if (varChild.lVal == CHILDID_SELF) return S_FALSE; - const size_t index = IndexFromChildId(varChild.lVal); - const size_t itemCount = m_owner->AccGetItemCount(); - if (index < itemCount) { - if (!m_owner->AccExecuteItemDefaultAction(index)) return S_FALSE; - } else if (index < itemCount + m_owner->AccGetOtherCount()) { - if (!m_owner->AccExecuteOtherDefaultAction(index - itemCount)) return S_FALSE; - } else { - return E_INVALIDARG; - } - return S_OK; -} -HRESULT IAccessible_CListControl::put_accName(VARIANT varChild, BSTR szName) { - return DISP_E_MEMBERNOTFOUND; -} -HRESULT IAccessible_CListControl::put_accValue(VARIANT varChild, BSTR szValue) { - return DISP_E_MEMBERNOTFOUND; -} - -void CListAccessible::AccGetName(pfc::string_base & out) const { - auto str = pfc::getWindowText(m_wnd); - if ( str.length() > 0 ) out = str; - else out = "List Control"; -} diff --git a/libPPUI/CListAccessible.h b/libPPUI/CListAccessible.h deleted file mode 100644 index a1dad3d..0000000 --- a/libPPUI/CListAccessible.h +++ /dev/null @@ -1,292 +0,0 @@ -#pragma once - -#include - -#pragma comment(lib, "oleacc.lib") - -#include "CListControl-Cell.h" -#include "CListControlWithSelection.h" - -//! Internal class interfacing with Windows accessibility APIs. \n -//! This class is not tied to any specific control and requires most of its methods to be overridden. \n -//! With CListControl you want to use CListControlAccImpl<> template instead of using CListAccessible directly. -class CListAccessible { -public: - void AccInitialize(CWindow wnd); - void AccCleanup(); - LRESULT AccGetObject(WPARAM wp,LPARAM lp); - CWindow AccGetWnd() const {return m_wnd;} - virtual size_t AccGetItemCount() const {return 0;} - virtual LONG AccGetItemRole( size_t index ) const {return ROLE_SYSTEM_LISTITEM;} - virtual void AccGetItemName(size_t index, pfc::string_base & out) const {out = "";} - virtual void AccGetName(pfc::string_base & out) const; - virtual size_t AccGetFocusItem() const {return ~0;} - virtual bool AccIsItemSelected(size_t index) const {return false;} - virtual bool AccIsItemChecked( size_t index ) const { return false; } - virtual bool AccIsItemVisible(size_t index) const {return false;} - virtual bool AccGetItemDefaultAction(pfc::string_base & out) const {return false;} - virtual bool AccExecuteItemDefaultAction(size_t index) {return false;} - virtual void AccSetSelection(pfc::bit_array const & affected, pfc::bit_array const & state) {} - virtual void AccSetFocusItem(size_t index) {} - virtual bool AccGetItemRect(size_t index, CRect & out) const {return false;} - virtual bool AccGetItemDescription(size_t index, pfc::string_base & out) const {return false;} - virtual size_t AccItemHitTest(CPoint const & pt) const {return ~0;} - - virtual DWORD AccGetOtherRole(size_t index) {return 0;} - virtual size_t AccGetOtherCount() const {return 0;} - virtual void AccGetOtherName(size_t index, pfc::string_base & out) const {out = "";} - virtual size_t AccGetFocusOther() const {return ~0;} - virtual void AccSetFocusOther(size_t index) {} - virtual bool AccIsOtherVisible(size_t index) const {return false;} - virtual bool AccGetOtherDescription(size_t index, pfc::string_base & out) const {return false;} - virtual size_t AccOtherHitTest(CPoint const & pt) const {return ~0;} - virtual bool AccIsOtherFocusable(size_t index) const {return false;} - virtual bool AccGetOtherDefaultAction(size_t index, pfc::string_base & out) const {return false;} - virtual bool AccExecuteOtherDefaultAction(size_t index) {return false;} - virtual bool AccGetOtherRect(size_t index, CRect & out) const {return false;} - virtual CWindow AccGetOtherChildWnd(size_t index) const {return NULL;} - - void AccItemNamesChanged( pfc::bit_array const & mask); - void AccReloadItems(pfc::bit_array const & mask ); - void AccRefreshItems(pfc::bit_array const & mask, UINT what); - void AccStateChange(pfc::bit_array const & mask); - void AccStateChange(size_t index); - void AccItemLayoutChanged(); - void AccFocusItemChanged(size_t index); - void AccFocusOtherChanged(size_t index); - void AccSelectionChanged(const pfc::bit_array & affected, const pfc::bit_array & status); - void AccLocationChange(); -protected: - ~CListAccessible() { * m_killSwitch = true; } -private: - CWindow m_wnd; - std::shared_ptr m_killSwitch = std::make_shared(); - pfc::com_ptr_t m_interface; -}; - -//! Basic wrapper implementing CListAccessible methods on top of CListControl. Leaves many methods to be overridden by calle -template class CListControlAccImpl : public TBaseClass, protected CListAccessible { -public: - template CListControlAccImpl( arg_t && ... arg ) : TBaseClass(std::forward(arg) ... ) {} - - BEGIN_MSG_MAP_EX(CListControlAccImpl) - MESSAGE_HANDLER(WM_GETOBJECT,OnGetObject) - MESSAGE_HANDLER(WM_DESTROY,OnDestroyPassThru) - MESSAGE_HANDLER(WM_CREATE,OnCreatePassThru) - CHAIN_MSG_MAP(TBaseClass) - END_MSG_MAP() -public: - void ReloadData() { - TBaseClass::ReloadData(); - AccItemLayoutChanged(); - } - void ReloadItems(pfc::bit_array const & mask) { - TBaseClass::ReloadItems(mask); - AccReloadItems(mask); - } -protected: - size_t AccGetItemCount() const {return this->GetItemCount();} - size_t AccGetFocusItem() const {return this->GetFocusItem();} - bool AccIsItemSelected(size_t index) const {return this->IsItemSelected(index);} - bool AccIsItemVisible(size_t index) const { - if (index >= AccGetItemCount()) return false; - return this->IsRectVisible(this->GetItemRect(index)); - } - bool AccExecuteItemDefaultAction(size_t index) {if (index < AccGetItemCount()) {this->ExecuteDefaultAction(index);return true;} else return false;} - bool AccGetItemRect(size_t index, CRect & out) const { - if (index >= AccGetItemCount()) return false; - out = this->GetItemRect(index); - return true; - } - size_t AccItemHitTest(CPoint const & pt) const { - size_t item; - if (!this->ItemFromPoint(pt,item)) return ~0; - return item; - } - - void OnViewOriginChange(CPoint p_delta) override { - TBaseClass::OnViewOriginChange(p_delta); - AccLocationChange(); - } - - /* overrideme, optional - void AccGetName(pfc::string_base & out) const; - bool AccGetItemDefaultAction(pfc::string_base & out) const; - */ - - LONG AccRoleAt(size_t idx, size_t sub) const { - auto cell = this->GetCellType(idx, sub); - if (cell == nullptr) return 0; - return cell->AccRole(); - } - bool isCellText(size_t idx, size_t sub) const { - switch (AccRoleAt(idx, sub)) { - case ROLE_SYSTEM_TEXT: - case ROLE_SYSTEM_STATICTEXT: - case ROLE_SYSTEM_LISTITEM: - return true; - default: - return false; - } - } - bool useCellForDescription(size_t idx, size_t sub) const { - return sub > 0 && isCellText(idx, sub); - } - bool AccGetItemDescription(size_t index, pfc::string_base& out) const { - pfc::string_formatter ret, temp, temp2; - const size_t total = this->GetColumnCount(); - for (size_t walk = 0; walk < total; ) { - if (useCellForDescription(index, walk) && this->GetSubItemText(index, walk, temp) && temp.length() > 0) { - if (ret.length() > 0) ret << "; "; - this->GetColumnText(walk, temp2); - if (temp2.length() > 0) ret << temp2 << ": "; - ret << temp; - } - size_t d = this->GetSubItemSpan(index, walk); - if (d < 1) d = 1; - walk += d; - } - bool rv = (ret.length() > 0); - if (rv) out = ret; - return ret; - } - - void AccGetItemNameAlt(size_t index, pfc::string_base & out) const { - pfc::string_formatter ret, temp; - const size_t total = this->GetColumnCount(); - for (size_t walk = 0; walk < total; ) { - if (this->isCellText(index, walk) && this->GetSubItemText(index, walk, temp) && temp.length() > 0) { - if (ret.length() > 0) ret << "; "; - ret << temp; - } - size_t d = this->GetSubItemSpan(index, walk); - if (d < 1) d = 1; - walk += d; - } - out = ret; - } - - // Item name by default taken from column 0, override this if you supply another - void AccGetItemName(size_t index, pfc::string_base & out) const { - this->GetSubItemText(index, 0, out); - } - - void AccSetSelection(pfc::bit_array const & affected, pfc::bit_array const & state) override { - this->SetSelection(affected, state); -} - void AccSetFocusItem(size_t index) override { - this->SetFocusItem(index); - } - - void OnFocusChangedGroup(int iGroup) override { - TBaseClass::OnFocusChangedGroup(iGroup); - AccFocusOtherChanged((size_t)iGroup); - } - void OnFocusChanged(size_t f) override { - TBaseClass::OnFocusChanged(f); - AccFocusItemChanged(f); - } - - void OnSelectionChanged(pfc::bit_array const & affected, pfc::bit_array const & status) override { - TBaseClass::OnSelectionChanged(affected, status); - AccSelectionChanged(affected, status); - } - - CWindow AccGetOtherChildWnd(size_t index) const {return index == 0 ? CWindow(this->GetHeaderCtrl()) : CWindow(NULL) ;} - virtual DWORD AccGetOtherRole(size_t index) {return index > 0 ? ROLE_SYSTEM_GROUPING : ROLE_SYSTEM_WINDOW;}//FIXME? - virtual bool AccGetOtherDescription(size_t index, pfc::string_base & out) const {return false;}//FIXME?? - - size_t AccGetOtherCount() const {return 1 + this->GetGroupCount();} - void AccGetOtherName(size_t index, pfc::string_base & out) const override { - if (index == 0) out = "Columns Header"; - else if (!this->GetGroupHeaderText((int)index, out)) out = ""; - } - size_t AccGetFocusOther() const override { - int focus = this->GetGroupFocus(); - if (focus > 0) return (size_t) focus; - else return SIZE_MAX; - } - void AccSetFocusOther(size_t index) override { - if (index > 0) this->SetGroupFocus((int)index); - } - bool AccIsOtherVisible(size_t index) const override { - if (index == 0) return true; - CRect rc; - if (!this->GetGroupHeaderRect((int)index,rc)) return false; - return IsRectVisible(rc); - } - - size_t AccOtherHitTest(CPoint const & pt) const { - { - CPoint s(pt); - if (this->ClientToScreen(&s)) { - CRect rc; - auto hdr = this->GetHeaderCtrl(); - if (hdr != NULL && hdr.GetWindowRect(rc)) { - if (rc.PtInRect(s)) { - return 0; - } - } - } - } - int group; - if (this->GroupHeaderFromPoint(pt,group)) return (size_t) group; - return ~0; - } - bool AccIsOtherFocusable(size_t index) const {return index > 0;} - bool AccGetOtherDefaultAction(size_t index, pfc::string_base & out) const {return false;} - bool AccExecuteOtherDefaultAction(size_t index) {return false;} - bool AccGetOtherRect(size_t index, CRect & out) const { - if (index == 0) { - CRect rc, client; - - auto hdr = this->GetHeaderCtrl(); - if ( hdr == NULL ) return false; - if (!hdr.GetWindowRect(rc)) return false; - if (!this->ScreenToClient(rc)) return false; - if (!this->GetClientRect(client)) return false; - return !! out.IntersectRect(rc, client); - } else { - return this->GetGroupHeaderRect((int)index, out); - } - } - LONG AccGetItemRole( size_t index ) const override { - auto type = this->GetCellType( index, 0 ); - if ( type != nullptr ) { - return type->AccRole(); - } - return ROLE_SYSTEM_LISTITEM; - } - void SetCellCheckState(size_t item, size_t subItem, bool value) override { - __super::SetCellCheckState(item, subItem, value); - this->AccStateChange(item); - } - bool AccIsItemChecked( size_t index ) const override { - auto type = this->GetCellType( index, 0 ); - if ( type != nullptr && type->IsToggle() ) { - return this->GetCellCheckState( index, 0 ); - } - return false; - } -private: - bool IsRectVisible(CRect const & rc) const { - return !!CRect().IntersectRect(this->GetClientRectHook(),rc); - } - LRESULT OnCreatePassThru(UINT,WPARAM,LPARAM,BOOL& bHandled) { - bHandled = FALSE; - try { AccInitialize(*this); } catch(...) {AccCleanup();} - return 0; - } - LRESULT OnDestroyPassThru(UINT,WPARAM,LPARAM,BOOL& bHandled) { - bHandled = FALSE; - AccCleanup(); - return 0; - } - LRESULT OnGetObject(UINT,WPARAM wp, LPARAM lp, BOOL & ) { - return this->AccGetObject(wp,lp); - } - -}; - -class CListControlWithSelectionImpl; -typedef CListControlAccImpl< CListControlWithSelectionImpl > CListControlWithSelectionAccImpl; diff --git a/libPPUI/CListControl-Cell.h b/libPPUI/CListControl-Cell.h deleted file mode 100644 index 8fe163f..0000000 --- a/libPPUI/CListControl-Cell.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once -#include // HTHEME - -class CListCell { -public: - typedef uint32_t cellState_t; - enum { - cellState_none = 0, - cellState_hot = 1 << 0, - cellState_pressed = 1 << 1, - cellState_disabled = 1 << 2, - }; - - struct DrawContentArg_t { - DWORD hdrFormat; - cellState_t cellState = 0; - CRect subItemRect; - CDCHandle dc; - const wchar_t * text = nullptr; - bool allowColors = true; - CRect rcHot; - CRect rcText; - HTHEME theme = NULL; - uint32_t colorHighlight = 0; - CWindow thisWnd; - }; - virtual void DrawContent( DrawContentArg_t const & arg ) = 0; - virtual const char * Theme() { return nullptr; } - virtual bool ApplyTextStyle( LOGFONT & font, double scale, uint32_t state ); - virtual bool IsInteractive() { return false; } - virtual bool SuppressRowSelect() { return false; } - virtual bool IsToggle() { return false; } - virtual bool IsRadioToggle() { return false; } - virtual bool AllowTypeFind() { return true; } - virtual CRect HotRect( CRect rc ) { return rc; } - virtual HCURSOR HotCursor() { return NULL; } - virtual bool AllowDrawThemeText() { return false; } - virtual LONG AccRole(); -}; diff --git a/libPPUI/CListControl-Cells-Compat.h b/libPPUI/CListControl-Cells-Compat.h deleted file mode 100644 index ca2379b..0000000 --- a/libPPUI/CListControl-Cells-Compat.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include "CListControl-Cells.h" - -// Wrapper for old code using cell type enum constants - -#define cell_text &PFC_SINGLETON(CListCell_Text) -#define cell_multitext &PFC_SINGLETON(CListCell_MultiText) -#define cell_hyperlink &PFC_SINGLETON(CListCell_Hyperlink) -#define cell_button &PFC_SINGLETON(CListCell_Button) -#define cell_button_lite &PFC_SINGLETON(CListCell_ButtonLite) -#define cell_button_glyph &PFC_SINGLETON(CListCell_ButtonGlyph) -#define cell_checkbox &PFC_SINGLETON(CListCell_Checkbox) -#define cell_radiocheckbox &PFC_SINGLETON(CListCell_RadioCheckbox) diff --git a/libPPUI/CListControl-Cells.cpp b/libPPUI/CListControl-Cells.cpp deleted file mode 100644 index 89cfd7d..0000000 --- a/libPPUI/CListControl-Cells.cpp +++ /dev/null @@ -1,298 +0,0 @@ -#include "stdafx.h" -#include "CListControl.h" -#include "CListControlHeaderImpl.h" -#include "CListControl-Cells.h" -#include "PaintUtils.h" -#include "GDIUtils.h" -#include - -LONG CListCell::AccRole() { - return ROLE_SYSTEM_LISTITEM; -} - -void RenderCheckbox( HTHEME theme, CDCHandle dc, CRect rcCheckBox, unsigned stateFlags, bool bRadio ) { - - const int part = bRadio ? BP_RADIOBUTTON : BP_CHECKBOX; - - const bool bDisabled = (stateFlags & CListCell::cellState_disabled) != 0; - const bool bPressed = (stateFlags & CListCell::cellState_pressed ) != 0; - const bool bHot = ( stateFlags & CListCell::cellState_hot ) != 0; - - if (theme != NULL && IsThemePartDefined(theme, part, 0)) { - int state = 0; - if (bDisabled) { - state = bPressed ? CBS_CHECKEDDISABLED : CBS_DISABLED; - } else if ( bHot ) { - state = bPressed ? CBS_CHECKEDHOT : CBS_HOT; - } else { - state = bPressed ? CBS_CHECKEDNORMAL : CBS_NORMAL; - } - - CSize size; - if (SUCCEEDED(GetThemePartSize(theme, dc, part, state, rcCheckBox, TS_TRUE, &size))) { - if (size.cx <= rcCheckBox.Width() && size.cy <= rcCheckBox.Height()) { - CRect rc = rcCheckBox; - rc.left += ( rc.Width() - size.cx ) / 2; - rc.top += ( rc.Height() - size.cy ) / 2; - rc.right = rc.left + size.cx; - rc.bottom = rc.top + size.cy; - DrawThemeBackground(theme, dc, part, state, rc, &rc); - return; - } - } - } - int stateEx = bRadio ? DFCS_BUTTONRADIO : DFCS_BUTTONCHECK; - if ( bPressed ) stateEx |= DFCS_CHECKED; - if ( bDisabled ) stateEx |= DFCS_INACTIVE; - else if ( bHot ) stateEx |= DFCS_HOT; - DrawFrameControl(dc, rcCheckBox, DFC_BUTTON, stateEx); -} - -void RenderButton( HTHEME theme, CDCHandle dc, CRect rcButton, CRect rcUpdate, uint32_t cellState ) { - - const int part = BP_PUSHBUTTON; - - enum { - stNormal = PBS_NORMAL, - stHot = PBS_HOT, - stDisabled = PBS_DISABLED, - stPressed = PBS_PRESSED, - }; - - int state = 0; - if (cellState & CListCell::cellState_disabled) state = stDisabled; - if ( cellState & CListCell::cellState_pressed ) state = stPressed; - else if ( cellState & CListCell::cellState_hot ) state = stHot; - else state = stNormal; - - CRect rcClient = rcButton; - - if (theme != NULL && IsThemePartDefined(theme, part, 0)) { - DrawThemeBackground(theme, dc, part, state, rcClient, &rcUpdate); - } else { - int stateEx = DFCS_BUTTONPUSH; - switch (state) { - case stPressed: stateEx |= DFCS_PUSHED; break; - case stDisabled: stateEx |= DFCS_INACTIVE; break; - } - DrawFrameControl(dc, rcClient, DFC_BUTTON, stateEx); - } -} - -bool CListCell::ApplyTextStyle( LOGFONT & font, double scale, uint32_t ) { - if ( scale != 1.0 ) { - font.lfHeight = pfc::rint32( font.lfHeight * scale ); - return true; - } else { - return false; - } -} - -void CListCell_Text::DrawContent( DrawContentArg_t const & arg ) { - const auto fgWas = arg.dc.GetTextColor(); - CDCHandle dc = arg.dc; - if (arg.cellState & cellState_disabled) { - dc.SetTextColor(GetSysColor(COLOR_GRAYTEXT)); - } - - - CRect clip = arg.rcText; - - const t_uint32 format = PaintUtils::DrawText_TranslateHeaderAlignment(arg.hdrFormat); - dc.DrawText( arg.text, (int)wcslen(arg.text), clip, format | DT_NOPREFIX | DT_END_ELLIPSIS | DT_SINGLELINE | DT_VCENTER ); - - dc.SetTextColor(fgWas); -} - -void CListCell_TextColors::DrawContent( DrawContentArg_t const & arg ) { - CDCHandle dc = arg.dc; - - CRect clip = arg.rcText; - - const uint32_t fgWas = dc.GetTextColor(); - - const t_uint32 format = PaintUtils::DrawText_TranslateHeaderAlignment(arg.hdrFormat); - const t_uint32 bk = dc.GetBkColor(); - const t_uint32 fg = fgWas; - const t_uint32 hl = (arg.allowColors ? arg.colorHighlight : fg); - const t_uint32 colors[3] = { PaintUtils::BlendColor(bk, fg, 33), fg, hl }; - - PaintUtils::TextOutColorsEx(dc, arg.text, clip, format, colors); - - dc.SetTextColor(fgWas); -} - -void CListCell_MultiText::DrawContent( DrawContentArg_t const & arg ) { - CDCHandle dc = arg.dc; - - const int textLen = (int) wcslen( arg.text ); - - CRect clip = arg.rcText; - - const t_uint32 format = PaintUtils::DrawText_TranslateHeaderAlignment(arg.hdrFormat) | DT_NOPREFIX | DT_VCENTER ; - - CRect rcDraw = clip; - dc.DrawText(arg.text, textLen, rcDraw, format | DT_CALCRECT); - auto txSize = rcDraw.Size(); - rcDraw = clip; - if ( txSize.cy < rcDraw.Height() ) { - int sub = rcDraw.Height() - txSize.cy; - rcDraw.top += sub/2; - rcDraw.bottom = rcDraw.top + txSize.cy; - } - dc.DrawText(arg.text, textLen, rcDraw, format); -} - -bool CListCell_Hyperlink::ApplyTextStyle( LOGFONT & font, double scale, uint32_t state ) { - bool rv = __super::ApplyTextStyle(font, scale, state); - - if ( state & cellState_hot ) { - font.lfUnderline = TRUE; - rv = true; - } - - return rv; -} - -HCURSOR CListCell_Hyperlink::HotCursor() { - return LoadCursor(NULL, IDC_HAND); -} - -LONG CListCell_Hyperlink::AccRole() { - return ROLE_SYSTEM_LINK; -} - -void CListCell_Hyperlink::DrawContent( DrawContentArg_t const & arg ) { - - CDCHandle dc = arg.dc; - - const uint32_t fgWas = dc.GetTextColor(); - - const t_uint32 format = PaintUtils::DrawText_TranslateHeaderAlignment(arg.hdrFormat); - if (arg.allowColors) dc.SetTextColor( arg.colorHighlight ); - const t_uint32 bk = dc.GetBkColor(); - - CRect rc = arg.rcText; - dc.DrawText(arg.text, (int) wcslen(arg.text), rc, format | DT_NOPREFIX | DT_END_ELLIPSIS | DT_SINGLELINE | DT_VCENTER ); - - dc.SetTextColor(fgWas); -} - -LONG CListCell_Button::AccRole() { - return ROLE_SYSTEM_PUSHBUTTON; -} - -void CListCell_Button::DrawContent( DrawContentArg_t const & arg ) { - - CDCHandle dc = arg.dc; - - const bool bPressed = (arg.cellState & cellState_pressed) != 0; - const bool bHot = (arg.cellState & cellState_hot) != 0; - - - if ( !m_lite || bHot || bPressed ) { - RenderButton( arg.theme, dc, arg.rcHot, arg.rcHot, arg.cellState ); - } - - CRect clip = arg.rcText; - - dc.DrawText(arg.text, (int) wcslen(arg.text), clip, DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER | DT_CENTER); -} - -bool CListCell_ButtonGlyph::ApplyTextStyle( LOGFONT & font, double scale, uint32_t state ) { - return __super::ApplyTextStyle(font, scale * 1.3, state); -} - -static CRect CheckBoxRect(CRect rc) { - if (rc.Width() > rc.Height()) { - rc.right = rc.left + rc.Height(); - } - return rc; -} - -LONG CListCell_Checkbox::AccRole() { - return m_radio ? ROLE_SYSTEM_RADIOBUTTON : ROLE_SYSTEM_CHECKBUTTON; -} - -CRect CListCell_Checkbox::HotRect( CRect rc ) { - return CheckBoxRect( rc ); -} - -void CListCell_Checkbox::DrawContent( DrawContentArg_t const & arg ) { - - CDCHandle dc = arg.dc; - - const bool bPressed = (arg.cellState & cellState_pressed) != 0; - const bool bHot = (arg.cellState & cellState_hot) != 0; - - - CRect clip = arg.rcText; - - const uint32_t fgWas = dc.GetTextColor(); - - if (arg.subItemRect.Width() > arg.subItemRect.Height() ) { - CRect rcCheckbox = arg.subItemRect; - rcCheckbox.right = rcCheckbox.left + rcCheckbox.Height(); - RenderCheckbox(arg.theme, dc, rcCheckbox, arg.cellState, m_radio ); - CRect rcText = arg.subItemRect; - rcText.left = rcCheckbox.right; - if (arg.cellState & cellState_disabled) { - dc.SetTextColor(GetSysColor(COLOR_GRAYTEXT)); - } - dc.DrawText(arg.text, (int) wcslen(arg.text), rcText, DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER | DT_LEFT); - } else { - RenderCheckbox(arg.theme, dc, arg.subItemRect, arg.cellState, m_radio ); - } - - dc.SetTextColor(fgWas); -} - -void CListCell_Text_FixedColor::DrawContent(DrawContentArg_t const & arg) { - if (arg.allowColors) { - SetTextColorScope scope(arg.dc, m_col); - __super::DrawContent(arg); - } else { - __super::DrawContent(arg); - } -} - -void CListCell_Combo::DrawContent(DrawContentArg_t const & arg) { - CDCHandle dc = arg.dc; - - const bool bDisabled = (arg.cellState & CListCell::cellState_disabled) != 0; - const bool bPressed = (arg.cellState & cellState_pressed) != 0; - const bool bHot = (arg.cellState & cellState_hot) != 0; - - const int part = CP_DROPDOWNBUTTONRIGHT; - - const HTHEME theme = arg.theme; - - if (theme != NULL && IsThemePartDefined(theme, part, 0)) { - int state = CBXSR_NORMAL; - if (bDisabled) { - state = CBXSR_DISABLED; - } else if (bPressed) { - state = CBXSR_PRESSED; - } else if (bHot) { - state = CBXSR_HOT; - } - - CSize size; - CRect rcCombo = arg.subItemRect; - CRect rcText = arg.rcText; - int w = rcCombo.Height()*3/4; - if (w < rcCombo.Width()) { - rcCombo.left = rcCombo.right - w; - DrawThemeBackground(theme, dc, part, state, rcCombo, &rcCombo); - if (rcCombo.left < rcText.right ) rcText.right = rcCombo.left; - } - - DrawContentArg_t arg2 = arg; - arg2.rcText = rcText; - PFC_SINGLETON(CListCell_Text).DrawContent(arg2); - } -} - -LONG CListCell_Combo::AccRole() { - return ROLE_SYSTEM_DROPLIST; -} \ No newline at end of file diff --git a/libPPUI/CListControl-Cells.h b/libPPUI/CListControl-Cells.h deleted file mode 100644 index 39d8e86..0000000 --- a/libPPUI/CListControl-Cells.h +++ /dev/null @@ -1,94 +0,0 @@ -#pragma once - -#include "CListControl-Cell.h" - - -class CListCell_Interactive : public CListCell { -public: - bool IsInteractive() override { return true; } -}; - -class CListCell_Text : public CListCell { -public: - void DrawContent( DrawContentArg_t const & ) override; - bool AllowDrawThemeText() override { return true; } -}; - -class CListCell_TextColors : public CListCell_Text { -public: - void DrawContent( DrawContentArg_t const & ) override; -}; - -class CListCell_MultiText : public CListCell { -public: - void DrawContent( DrawContentArg_t const & ) override; -}; - -class CListCell_Hyperlink : public CListCell_Interactive { -public: - void DrawContent( DrawContentArg_t const & ) override; - bool ApplyTextStyle( LOGFONT & font, double scale, uint32_t state ) override; - HCURSOR HotCursor() override; - LONG AccRole() override; - bool SuppressRowSelect() override { return true; } -}; - -class CListCell_Button : public CListCell_Interactive { -public: - void DrawContent( DrawContentArg_t const & ) override; - const char * Theme() override { return "BUTTON"; } - bool AllowTypeFind() override { return false; } - LONG AccRole() override; - bool SuppressRowSelect() override { return true; } - -protected: - bool m_lite = false; -}; - -class CListCell_ButtonLite : public CListCell_Button { -public: - CListCell_ButtonLite() { m_lite = true; } -}; - -class CListCell_ButtonGlyph : public CListCell_ButtonLite { -public: - bool ApplyTextStyle( LOGFONT & font, double scale, uint32_t state ) override; -}; - -class CListCell_Checkbox : public CListCell_Interactive { -public: - void DrawContent( DrawContentArg_t const & ) override; - const char * Theme() override { return "BUTTON"; } - bool IsToggle() override { return true; } - CRect HotRect( CRect rc ) override; - bool IsRadioToggle() override { return m_radio; } - LONG AccRole() override; - -protected: - bool m_radio = false; -}; - -class CListCell_RadioCheckbox : public CListCell_Checkbox { -public: - CListCell_RadioCheckbox() { m_radio = true; } - - static CListCell_RadioCheckbox instance; -}; - -class CListCell_Combo : public CListCell_Interactive { -public: - void DrawContent(DrawContentArg_t const &) override; - const char * Theme() override { return "COMBOBOX"; } - LONG AccRole() override; -}; - -void RenderButton( HTHEME theme, CDCHandle dc, CRect rcButton, CRect rcUpdate, uint32_t cellState ); -void RenderCheckbox( HTHEME theme, CDCHandle dc, CRect rcCheckBox, unsigned stateFlags, bool bRadio ); - - -class CListCell_Text_FixedColor : public CListCell_Text { - const COLORREF m_col; -public: - CListCell_Text_FixedColor(COLORREF col) : m_col(col) {} - void DrawContent(DrawContentArg_t const & arg) override; -}; diff --git a/libPPUI/CListControl.cpp b/libPPUI/CListControl.cpp deleted file mode 100644 index 2acda60..0000000 --- a/libPPUI/CListControl.cpp +++ /dev/null @@ -1,989 +0,0 @@ -#include "stdafx.h" -#include "CListControl.h" -#include "PaintUtils.h" -#include "CListControlUserOptions.h" -#include "GDIUtils.h" - -CListControlUserOptions * CListControlUserOptions::instance = nullptr; - -CRect CListControlImpl::GetClientRectHook() const { - CRect temp; if (!GetClientRect(temp)) temp.SetRectEmpty(); return temp; -} - -bool CListControlImpl::UserEnabledSmoothScroll() const { - auto i = CListControlUserOptions::instance; - if ( i != nullptr ) return i->useSmoothScroll(); - return false; -} - -LRESULT CListControlImpl::SetFocusPassThru(UINT,WPARAM,LPARAM,BOOL& bHandled) { - SetFocus(); - bHandled = FALSE; - return 0; -} - -void CListControlImpl::EnsureVisibleRectAbs(const CRect & p_rect) { - const CRect rcView = GetVisibleRectAbs(); - const CRect rcItem = p_rect; - int deltaX = 0, deltaY = 0; - - const bool centerOnItem = m_ensureVisibleUser; - - if (rcItem.top < rcView.top || rcItem.bottom > rcView.bottom) { - if (rcItem.Height() > rcView.Height()) { - deltaY = rcItem.top - rcView.top; - } else { - if (centerOnItem) { - deltaY = rcItem.CenterPoint().y - rcView.CenterPoint().y; - } else { - if (rcItem.bottom > rcView.bottom) deltaY = rcItem.bottom - rcView.bottom; - else deltaY = rcItem.top - rcView.top; - - } - } - } - if (rcItem.left < rcView.left || rcItem.right > rcView.right) { - if (rcItem.Width() > rcView.Width()) { - if (rcItem.left > rcView.left || rcItem.right < rcView.right) deltaX = rcItem.left - rcView.left; - } else { - if (centerOnItem) { - deltaX = rcItem.CenterPoint().x - rcView.CenterPoint().x; - } else { - if (rcItem.right > rcView.right) deltaX = rcItem.right - rcView.right; - else deltaX = rcItem.left - rcView.left; - } - } - } - - if (deltaX != 0 || deltaY != 0) { - MoveViewOriginDelta(CPoint(deltaX,deltaY)); - } -} -void CListControlImpl::EnsureItemVisible(t_size p_item, bool bUser) { - m_ensureVisibleUser = bUser; - EnsureVisibleRectAbs(GetItemRectAbs(p_item)); - m_ensureVisibleUser = false; -} -void CListControlImpl::EnsureHeaderVisible(int p_group) { - CRect rect; - if (GetGroupHeaderRectAbs(p_group,rect)) EnsureVisibleRectAbs(rect); -} - -void CListControlImpl::RefreshSlider(bool p_vertical) { - const CRect viewArea = GetViewAreaRectAbs(); - const CRect rcVisible = GetVisibleRectAbs(); - SCROLLINFO si = {}; - si.cbSize = sizeof(si); - si.fMask = SIF_PAGE|SIF_RANGE|SIF_POS; - - - if (AllowScrollbar(p_vertical)) { - if (p_vertical) { - si.nPage = rcVisible.Height(); - si.nMin = viewArea.top; - si.nMax = viewArea.bottom - 1; - si.nPos = rcVisible.top; - } else { - si.nPage = rcVisible.Width(); - si.nMin = viewArea.left; - si.nMax = viewArea.right - 1; - si.nPos = rcVisible.left; - } - } - - SetScrollInfo(p_vertical ? SB_VERT : SB_HORZ, &si); -} - -void CListControlImpl::RefreshSliders() { - //PROBLEM: while lots of data can be reused across those, it has to be recalculated inbetween because view area etc may change when scroll info changes - RefreshSlider(false); RefreshSlider(true); -} - -int CListControlImpl::GetScrollThumbPos(int which) { - SCROLLINFO si = {}; - si.cbSize = sizeof(si); - si.fMask = SIF_TRACKPOS; - GetScrollInfo(which,&si); - return si.nTrackPos; -} - -namespace { - class ResolveGroupHelper { - public: - ResolveGroupHelper(const CListControlImpl & p_control) : m_control(p_control) {} - int operator[](t_size p_index) const {return m_control.GetItemGroup(p_index);} - private: - const CListControlImpl & m_control; - }; -} - -bool CListControlImpl::ResolveGroupRange(int p_id,t_size & p_base,t_size & p_count) const { - - return pfc::binarySearch<>::runGroup(ResolveGroupHelper(*this),0,GetItemCount(),p_id,p_base,p_count); - - - //return pfc::bsearch_range_t(GetItemCount(),ResolveGroupHelper(*this),pfc::compare_t,p_id,p_base,p_count); -} - -static int HandleScroll(WORD p_code,int p_offset,int p_page, int p_line, int p_bottom, int p_thumbpos) { - switch(p_code) { - case SB_LINEUP: - return p_offset - p_line; - case SB_LINEDOWN: - return p_offset + p_line; - case SB_BOTTOM: - return p_bottom - p_page; - case SB_TOP: - return 0; - case SB_PAGEUP: - return p_offset - p_page; - case SB_PAGEDOWN: - return p_offset + p_page; - case SB_THUMBPOSITION: - return p_thumbpos; - case SB_THUMBTRACK: - return p_thumbpos; - default: - return p_offset; - } -} - -static CPoint ClipPointToRect(CPoint const & p_pt,CRect const & p_rect) { - return CPoint(pfc::clip_t(p_pt.x,p_rect.left,p_rect.right),pfc::clip_t(p_pt.y,p_rect.top,p_rect.bottom)); -} - -void CListControlImpl::MoveViewOriginNoClip(CPoint p_target) { - UpdateWindow(); - const CPoint old = m_viewOrigin; - m_viewOrigin = p_target; - - if (m_viewOrigin != old) { - if (m_viewOrigin.x != old.x) SetScrollPos(SB_HORZ,m_viewOrigin.x); - if (m_viewOrigin.y != old.y) SetScrollPos(SB_VERT,m_viewOrigin.y); - - const CPoint delta = old - m_viewOrigin; - if (FixedOverlayPresent()) Invalidate(); - else { - DWORD flags = SW_INVALIDATE | SW_ERASE; - const DWORD smoothScrollMS = 50; - if (this->UserEnabledSmoothScroll() && this->CanSmoothScroll()) { - flags |= SW_SMOOTHSCROLL | (smoothScrollMS << 16); - } - - ScrollWindowEx(delta.x,delta.y,GetClientRectHook(),NULL,0,0,flags ); - } - - OnViewOriginChange(m_viewOrigin - old); - } -} - -CPoint CListControlImpl::ClipViewOrigin(CPoint p_origin) const { - return ClipPointToRect(p_origin,GetValidViewOriginArea()); -} -void CListControlImpl::MoveViewOrigin(CPoint p_target) { - MoveViewOriginNoClip(ClipViewOrigin(p_target)); -} - -#ifndef SPI_GETWHEELSCROLLCHARS -#define SPI_GETWHEELSCROLLCHARS 0x006C -#endif -int CListControlImpl::HandleWheel(int & p_accum,int p_delta, bool bHoriz) { - if ( m_suppressMouseWheel ) return 0; - UINT scrollLines = 1; - SystemParametersInfo(bHoriz ? SPI_GETWHEELSCROLLCHARS : SPI_GETWHEELSCROLLLINES,0,&scrollLines,0); - if (scrollLines == ~0) { - p_accum = 0; - int rv = -pfc::sgn_t(p_delta); - CRect client = GetClientRectHook(); - if (bHoriz) rv *= client.Width(); - else rv *= client.Height(); - return rv; - } - - const int itemHeight = GetItemHeight(); - const int extraScale = 10000; - - p_accum += p_delta * extraScale; - if ((int)scrollLines < 1) scrollLines = 1; - int multiplier = (WHEEL_DELTA * extraScale) / (scrollLines * itemHeight); - if (multiplier<1) multiplier = 1; - - int delta = pfc::rint32( (double) p_accum / (double) multiplier ); - p_accum -= delta * multiplier; - return -delta; - - /* - if (p_accum<=-multiplier || p_accum>=multiplier) { - int direction; - int ov = p_accum; - if (ov<0) { - direction = -1; - ov = -ov; - p_accum = - ((-p_accum)%multiplier); - } else { - p_accum %= multiplier; - direction = 1; - } - - return - (direction * (ov + multiplier - 1) ) / multiplier; - } else { - return 0; - } - */ -} - -LRESULT CListControlImpl::OnVWheel(UINT,WPARAM p_wp,LPARAM p_lp,BOOL&) { - const CRect client = GetClientRectHook(), view = this->GetViewAreaRectAbs(); - int deltaPixels = HandleWheel(m_wheelAccumY,(short)HIWORD(p_wp), false); - - const bool canVScroll = client.Height() < view.Height(); - const bool canHScroll = client.Width() < view.Width(); - - CPoint ptDelta; - if ( canVScroll && canHScroll && GetHotkeyModifierFlags() == MOD_SHIFT) { - ptDelta = CPoint(deltaPixels, 0); // default to horizontal scroll if shift is pressed - } else if (canVScroll) { - ptDelta = CPoint(0,deltaPixels); - } else if (canHScroll) { - ptDelta = CPoint(deltaPixels,0); - } - - if ( ptDelta != CPoint(0,0) ) { - MoveViewOriginDelta(ptDelta); - } - return 0; -} -LRESULT CListControlImpl::OnHWheel(UINT,WPARAM p_wp,LPARAM p_lp,BOOL&) { - const CRect client = GetClientRectHook(); - int deltaPixels = HandleWheel(m_wheelAccumX,(short)HIWORD(p_wp), true); - MoveViewOriginDelta(CPoint(-deltaPixels,0)); - return 0; -} - -LRESULT CListControlImpl::OnVScroll(UINT,WPARAM p_wp,LPARAM,BOOL&) { - int target = HandleScroll(LOWORD(p_wp),m_viewOrigin.y,GetVisibleRectAbs().Height(),GetItemHeight(),GetViewAreaRectAbs().bottom,GetScrollThumbPos(SB_VERT)); - MoveViewOrigin(CPoint(m_viewOrigin.x,target)); - return 0; -} -LRESULT CListControlImpl::OnHScroll(UINT,WPARAM p_wp,LPARAM,BOOL&) { - int target = HandleScroll(LOWORD(p_wp),m_viewOrigin.x,GetVisibleRectAbs().Width(),GetItemHeight() /*fixme*/,GetViewAreaRectAbs().right,GetScrollThumbPos(SB_HORZ)); - MoveViewOrigin(CPoint(target,m_viewOrigin.y)); - return 0; -} - -LRESULT CListControlImpl::OnGesture(UINT,WPARAM,LPARAM lParam,BOOL& bHandled) { - if (!this->m_gestureAPI.IsAvailable()) { - bHandled = FALSE; - return 0; - } - HGESTUREINFO hGesture = (HGESTUREINFO) lParam; - GESTUREINFO gestureInfo = {sizeof(gestureInfo)}; - if (m_gestureAPI.GetGestureInfo(hGesture, &gestureInfo)) { - //console::formatter() << "WM_GESTURE " << pfc::format_hex( gestureInfo.dwFlags ) << " " << (int)gestureInfo.dwID << " X:" << gestureInfo.ptsLocation.x << " Y:" << gestureInfo.ptsLocation.y << " arg:" << (__int64) gestureInfo.ullArguments; - CPoint pt( gestureInfo.ptsLocation.x, gestureInfo.ptsLocation.y ); - switch(gestureInfo.dwID) { - case GID_BEGIN: - m_gesturePoint = pt; - break; - case GID_END: - break; - case GID_PAN: - MoveViewOriginDelta( this->m_gesturePoint - pt); - m_gesturePoint = pt; - break; - } - } - - m_gestureAPI.CloseGestureInfoHandle(hGesture); - bHandled = TRUE; - return 0; -} - -LRESULT CListControlImpl::OnSize(UINT,WPARAM,LPARAM p_lp,BOOL&) { - OnSizeAsync_Trigger(); - RefreshSliders(); - return 0; -} - - -void CListControlImpl::RenderBackground( CDCHandle dc, CRect const & rc ) { - PaintUtils::FillRectSimple(dc,rc,GetSysColorHook(colorBackground)); -} - -void CListControlImpl::PaintContent(CRect rcPaint, HDC dc) { - CDCHandle renderDC(dc); - - CMemoryDC bufferDC(renderDC,rcPaint); - renderDC = bufferDC; - this->RenderBackground(renderDC, rcPaint); - - { - const CPoint pt = GetViewOffset(); - OffsetWindowOrgScope offsetScope(renderDC, pt); - CRect renderRect = rcPaint; renderRect.OffsetRect(pt); - RenderRect(renderRect,renderDC); - } -} - -void CListControlImpl::OnPrintClient(HDC dc, UINT uFlags) { - CRect rcClient; this->GetClientRect( rcClient ); - PaintContent( rcClient, dc ); -} - -LRESULT CListControlImpl::OnPaint(UINT,WPARAM,LPARAM,BOOL&) { - CPaintDC paintDC(*this); - - PaintContent( paintDC.m_ps.rcPaint, paintDC.m_hDC ); - - return 0; -} - -namespace { - class comparator_rect { - public: - static int compare(const CRect & p_rect1,const CRect & p_rect2) { - if (p_rect1.bottom <= p_rect2.top) return -1; - else if (p_rect1.top >= p_rect2.bottom) return 1; - else return 0; - } - }; - - static int RectPointCompare(const CRect & p_item1,const int p_y) { - if (p_item1.bottom <= p_y) return -1; - else if (p_item1.top > p_y) return 1; - else return 0; - } - - class RectSearchHelper_Items { - public: - RectSearchHelper_Items(const CListControlImpl & p_control) : m_control(p_control) {} - CRect operator[](t_size p_index) const { - return m_control.GetItemRectAbs(p_index); - } - private: - const CListControlImpl & m_control; - }; - class RectSearchHelper_Groups { - public: - RectSearchHelper_Groups(const CListControlImpl & p_control) : m_control(p_control) {} - CRect operator[](t_size p_index) const { - CRect rect; - if (!m_control.GetGroupHeaderRectAbs((int)(p_index + 1),rect)) rect.SetRectEmpty(); - return rect; - } - private: - const CListControlImpl & m_control; - }; -} - -bool CListControlImpl::GetItemRange(const CRect & p_rect,t_size & p_base,t_size & p_count) const { - CRect temp(p_rect); temp.OffsetRect( GetViewOffset() ); - return GetItemRangeAbs(temp, p_base, p_count); -} - - - -bool CListControlImpl::GetItemRangeAbsInclHeaders(const CRect & p_rect,t_size & p_base,t_size & p_count) const { - CRect temp(p_rect); - temp.bottom += this->GetGroupHeaderHeight(); - return GetItemRangeAbs(temp, p_base, p_count); -} - -bool CListControlImpl::GetItemRangeAbs(const CRect & p_rect,t_size & p_base,t_size & p_count) const { - if (p_rect.right < 0 || p_rect.left >= GetItemWidth()) return false; - - return pfc::binarySearch::runGroup(RectSearchHelper_Items(*this),0,GetItemCount(),p_rect,p_base,p_count); -} - -void CListControlImpl::RenderRect(const CRect & p_rect,CDCHandle p_dc) { - const CRect rectAbs = p_rect; - - t_size base, count; - if (GetItemRangeAbs(rectAbs,base,count)) { - for(t_size walk = 0; walk < count; ++walk) { - CRect rcUpdate, rcItem = GetItemRectAbs(base+walk); - if (rcUpdate.IntersectRect(rcItem,p_rect)) { - DCStateScope dcState(p_dc); - if (p_dc.IntersectClipRect(rcUpdate) != NULLREGION) { - try { - RenderItem(base+walk,rcItem,rcUpdate,p_dc); - } catch(std::exception const & e) { - (void) e; - // console::complain("List Control: Item rendering failure", e); - } - } - } - } - } - - if (pfc::binarySearch::runGroup(RectSearchHelper_Groups(*this),0,GetGroupCount(),rectAbs,base,count)) { - for(t_size walk = 0; walk < count; ++walk) { - CRect rcHeader, rcUpdate; - const int id = (int)(base+walk+1); - if (GetGroupHeaderRectAbs(id,rcHeader) && rcUpdate.IntersectRect(rcHeader,p_rect)) { - DCStateScope dcState(p_dc); - if (p_dc.IntersectClipRect(rcUpdate) != NULLREGION) { - try { - RenderGroupHeader(id,rcHeader,rcUpdate,p_dc); - } catch(std::exception const & e) { - (void) e; - // console::complain("List Control: Group header rendering failure", e); - } - } - } - } - } - - RenderOverlay(p_rect,p_dc); -} - -CRect CListControlImpl::GetItemRect(t_size p_item) const { - CRect rcItem = GetItemRectAbs(p_item); - rcItem.OffsetRect( - GetViewOffset() ); - return rcItem; -} -bool CListControlImpl::GetGroupHeaderRect(int p_group,CRect & p_rect) const { - if (!GetGroupHeaderRectAbs(p_group,p_rect)) return false; - p_rect.OffsetRect( - GetViewOffset() ); - return true; -} - -int CListControlImpl::GetViewAreaHeight() const { - const t_size itemCount = GetItemCount(); - int subAreaBase = 0; - if (itemCount > 0) { - subAreaBase = GetItemRectAbs(itemCount - 1).bottom; - } - return subAreaBase; -} - -CRect CListControlImpl::GetItemRectAbs(t_size p_item) const { - CRect rcItem; - const int itemHeight = GetItemHeight(), itemWidth = GetItemWidth(), groupHeight = GetGroupHeaderHeight(), itemGroup = GetItemGroup(p_item); - rcItem.top = (int)p_item * itemHeight + groupHeight * itemGroup; - rcItem.bottom = rcItem.top + itemHeight; - rcItem.left = 0; - rcItem.right = rcItem.left + itemWidth; - return rcItem; -} -bool CListControlImpl::GetGroupHeaderRectAbs(int p_group,CRect & p_rect) const { - if (p_group == 0) return false; - t_size itemBase, itemCount; - if (!ResolveGroupRange(p_group,itemBase,itemCount)) return false; - const int itemHeight = GetItemHeight(), itemWidth = GetItemWidth(), groupHeight = GetGroupHeaderHeight(); - p_rect.bottom = (int) itemBase * itemHeight + groupHeight * p_group; - p_rect.top = p_rect.bottom - groupHeight; - p_rect.left = 0; - p_rect.right = p_rect.left + itemWidth; - return true; -} - -CRect CListControlImpl::GetViewAreaRectAbs() const { - return CRect(0,0,GetViewAreaWidth(),GetViewAreaHeight()); -} - -CRect CListControlImpl::GetViewAreaRect() const { - CRect rc = GetViewAreaRectAbs(); - rc.OffsetRect( - GetViewOffset() ); - CRect ret; ret.IntersectRect(rc,GetClientRectHook()); - return ret; -} - -t_size CListControlImpl::GetGroupCount() const { - const t_size itemCount = GetItemCount(); - if (itemCount > 0) { - return (t_size) GetItemGroup(itemCount-1); - } else { - return 0; - } -} - -void CListControlImpl::UpdateGroupHeader(int p_id) { - CRect rect; - if (GetGroupHeaderRect(p_id,rect)) { - InvalidateRect(rect); - } -} -static void AddUpdateRect(HRGN p_rgn,CRect const & p_rect) { - CRgn temp; temp.CreateRectRgnIndirect(p_rect); - CRgnHandle(p_rgn).CombineRgn(temp,RGN_OR); -} - -void CListControlImpl::OnItemsReordered( const size_t * order, size_t count ) { - PFC_ASSERT( count == GetItemCount() ); - ReloadItems( pfc::bit_array_order_changed(order) ); -} -void CListControlImpl::UpdateItems(const pfc::bit_array & p_mask) { - t_size base,count; - if (GetItemRangeAbs(GetVisibleRectAbs(),base,count)) { - const t_size max = base+count; - CRgn updateRgn; updateRgn.CreateRectRgn(0,0,0,0); - bool found = false; - for(t_size walk = p_mask.find_first(true,base,max); walk < max; walk = p_mask.find_next(true,walk,max)) { - found = true; - AddUpdateRect(updateRgn,GetItemRect(walk)); - } - if (found) { - InvalidateRgn(updateRgn); - } - } -} - -void CListControlImpl::UpdateItemsAndHeaders(const pfc::bit_array & p_mask) { - t_size base,count; - int groupWalk = 0; - if (GetItemRangeAbsInclHeaders(GetVisibleRectAbs(),base,count)) { - const t_size max = base+count; - CRgn updateRgn; updateRgn.CreateRectRgn(0,0,0,0); - bool found = false; - for(t_size walk = p_mask.find_first(true,base,max); walk < max; walk = p_mask.find_next(true,walk,max)) { - found = true; - const int groupId = GetItemGroup(walk); - if (groupId != groupWalk) { - if (groupId > 0) { - CRect rect; - if (GetGroupHeaderRect(groupId,rect)) { - AddUpdateRect(updateRgn,rect); - } - } - groupWalk = groupId; - } - AddUpdateRect(updateRgn,GetItemRect(walk)); - } - if (found) { - InvalidateRgn(updateRgn); - } - } -} - - -CRect CListControlImpl::GetValidViewOriginArea() const { - const CRect rcView = GetViewAreaRectAbs(); - const CRect rcClient = GetClientRectHook(); - CRect rcArea = rcView; - rcArea.right -= pfc::min_t(rcView.Width(),rcClient.Width()); - rcArea.bottom -= pfc::min_t(rcView.Height(),rcClient.Height()); - return rcArea; -} - -void CListControlImpl::OnViewAreaChanged(CPoint p_originOverride) { - const CPoint oldViewOrigin = m_viewOrigin; - m_viewOrigin = ClipPointToRect(p_originOverride,GetValidViewOriginArea()); - - RefreshSliders(); - - Invalidate(); - - if (oldViewOrigin != m_viewOrigin) { - OnViewOriginChange(m_viewOrigin - oldViewOrigin); - } -} - -bool CListControlImpl::ItemFromPointAbs(CPoint const & p_pt,t_size & p_item) const { - if (p_pt.x < 0 || p_pt.x >= GetItemWidth()) return false; - t_size dummy; - return GetItemRangeAbs(CRect(p_pt,p_pt + CPoint(1,1)),p_item,dummy); -} - -bool CListControlImpl::GroupHeaderFromPointAbs(CPoint const & p_pt,int & p_group) const { - if (p_pt.x < 0 || p_pt.x >= GetItemWidth()) return false; - t_size result; - - if (!pfc::binarySearch::run(RectSearchHelper_Groups(*this),0,GetGroupCount(),CRect(p_pt,p_pt + CSize(1,1)),result)) return false; - - - //if (!pfc::bsearch_t(GetGroupCount(),RectSearchHelper_Groups(*this),RectCompare,CRect(p_pt,p_pt),result)) return false; - p_group = (int) (result + 1); - return true; -} - -void CListControlImpl::OnThemeChanged() { - m_themeCache.remove_all(); -} - -CTheme & CListControlImpl::themeFor(const char * what) { - bool bNew; - auto & ret = this->m_themeCache.find_or_add_ex( what, bNew ); - if (bNew) ret.OpenThemeData(*this, pfc::stringcvt::string_wide_from_utf8(what)); - return ret; -} - -LRESULT CListControlImpl::OnCreatePassThru(UINT,WPARAM,LPARAM,BOOL& bHandled) { - ::SetWindowTheme(*this, _T("explorer"), NULL); - OnViewAreaChanged(); - - if (m_gestureAPI.IsAvailable()) { - GESTURECONFIG config = {GID_PAN, GC_PAN_WITH_SINGLE_FINGER_VERTICALLY|GC_PAN_WITH_INERTIA, GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY | GC_PAN_WITH_GUTTER}; - m_gestureAPI.SetGestureConfig( *this, 0, 1, &config, sizeof(GESTURECONFIG)); - } - - bHandled = FALSE; - return 0; -} -bool CListControlImpl::IsSameItemOrHeaderAbs(const CPoint & p_point1, const CPoint & p_point2) const { - t_size item1, item2; int group1, group2; - if (ItemFromPointAbs(p_point1, item1)) { - if (ItemFromPointAbs(p_point2,item2)) { - return item1 == item2; - } else { - return false; - } - } - if (GroupHeaderFromPointAbs(p_point1, group1)) { - if (GroupHeaderFromPointAbs(p_point2, group2)) { - return group1 == group2; - } else { - return false; - } - } - return false; -} - -void CListControlImpl::OnSizeAsync_Trigger() { - if (!m_sizeAsyncPending) { - if (PostMessage(MSG_SIZE_ASYNC,0,0)) { - m_sizeAsyncPending = true; - } else { - PFC_ASSERT(!"Shouldn't get here!"); - //should not happen - ListHandleResize(); - } - } -} - -void CListControlImpl::ListHandleResize() { - MoveViewOriginDelta(CPoint(0,0)); - m_sizeAsyncPending = false; -} - -void CListControlImpl::AddGroupHeaderToUpdateRgn(HRGN p_rgn, int id) const { - if (id > 0) { - CRect rcHeader; - if (GetGroupHeaderRect(id,rcHeader)) AddUpdateRect(p_rgn,rcHeader); - } -} -void CListControlImpl::AddItemToUpdateRgn(HRGN p_rgn, t_size p_index) const { - if (p_index < this->GetItemCount()) { - AddUpdateRect(p_rgn,GetItemRect(p_index)); - } -} - -COLORREF CListControlImpl::GetSysColorHook(int colorIndex) const { - return GetSysColor(colorIndex); -} - -LRESULT CListControlImpl::OnEraseBkgnd(UINT,WPARAM wp,LPARAM,BOOL&) { -#ifndef CListControl_ScrollWindowFix - const CRect rcClient = GetClientRectHook(); - PaintUtils::FillRectSimple((HDC)wp,rcClient,GetColor(ui_color_background)); -#endif - return 1; -} - -t_size CListControlImpl::InsertIndexFromPointEx(const CPoint & pt, bool & bInside) const { - bInside = false; - t_size insertMark = ~0; - t_size itemIdx; int groupId; - CPoint test(pt); test += GetViewOffset(); - test.x = GetItemWidth() / 2; - if (test.y >= GetViewAreaHeight()) { - return GetItemCount(); - } else if (ItemFromPointAbs(test,itemIdx)) { - const CRect rc = GetItemRectAbs(itemIdx); - if (test.y > rc.top + MulDiv(rc.Height(),2,3)) itemIdx++; - else if (test.y >= rc.top + MulDiv(rc.Height(),1,3)) bInside = true; - return itemIdx; - } else if (GroupHeaderFromPointAbs(test,groupId)) { - t_size base,count; - if (ResolveGroupRange(groupId,base,count)) { - return base; - } - } - return ~0; -} -t_size CListControlImpl::InsertIndexFromPoint(const CPoint & pt) const { - bool dummy; return InsertIndexFromPointEx(pt,dummy); -} - -COLORREF CListControlImpl::BlendGridColor( COLORREF bk ) { - return BlendGridColor( bk, PaintUtils::DetermineTextColor( bk ) ); -} - -COLORREF CListControlImpl::BlendGridColor( COLORREF bk, COLORREF tx ) { - return PaintUtils::BlendColor(bk, tx, 10); -} - -COLORREF CListControlImpl::GridColor() { - return BlendGridColor( GetSysColorHook(colorBackground), GetSysColorHook(colorText) ); -} - -void CListControlImpl::RenderItemBackground(CDCHandle p_dc,const CRect & p_itemRect,size_t p_item, uint32_t bkColor) { - switch( this->m_rowStyle ) { - case rowStylePlaylistDelimited: - PaintUtils::RenderItemBackground(p_dc,p_itemRect,p_item+GetItemGroup(p_item),bkColor); - { - auto blend = BlendGridColor(bkColor); - CDCPen pen(p_dc, blend); - SelectObjectScope scope(p_dc, pen); - - p_dc.MoveTo( p_itemRect.right-1, p_itemRect.top ); - p_dc.LineTo( p_itemRect.right-1, p_itemRect.bottom ); - } - break; - case rowStylePlaylist: - PaintUtils::RenderItemBackground(p_dc,p_itemRect,p_item+GetItemGroup(p_item),bkColor); - break; - case rowStyleGrid: - PaintUtils::FillRectSimple(p_dc, p_itemRect, bkColor ); - { - auto blend = BlendGridColor(bkColor); - CDCBrush brush(p_dc, blend); - p_dc.FrameRect(&p_itemRect, brush); - - } - break; - case rowStyleFlat: - PaintUtils::FillRectSimple(p_dc, p_itemRect, bkColor ); - break; - } -} - -void CListControlImpl::RenderGroupHeaderBackground(CDCHandle p_dc,const CRect & p_headerRect,int p_group) { - const t_uint32 bkColor = GetSysColorHook(colorBackground); - t_size index = 0; - t_size base, count; - if (p_group > 0 && ResolveGroupRange(p_group,base,count)) { - index = base + (t_size) p_group - 1; - } - switch( this->m_rowStyle ) { - default: - PaintUtils::FillRectSimple( p_dc, p_headerRect, bkColor ); - break; - case rowStylePlaylistDelimited: - case rowStylePlaylist: - PaintUtils::RenderItemBackground(p_dc,p_headerRect,index,bkColor); - break; - } -} - -void CListControlImpl::RenderItem(t_size p_item,const CRect & p_itemRect,const CRect & p_updateRect,CDCHandle p_dc) { - this->RenderItemBackground(p_dc, p_itemRect, p_item, GetSysColorHook(colorBackground) ); - - DCStateScope backup(p_dc); - p_dc.SetBkMode(TRANSPARENT); - p_dc.SetBkColor(GetSysColorHook(colorBackground)); - p_dc.SetTextColor(GetSysColorHook(colorText)); - - RenderItemText(p_item,p_itemRect,p_updateRect,p_dc, true); -} - -void CListControlImpl::RenderGroupHeader(int p_group,const CRect & p_headerRect,const CRect & p_updateRect,CDCHandle p_dc) { - this->RenderGroupHeaderBackground(p_dc, p_headerRect, p_group ); - - DCStateScope backup(p_dc); - p_dc.SetBkMode(TRANSPARENT); - p_dc.SetBkColor(GetSysColorHook(colorBackground)); - p_dc.SetTextColor(GetSysColorHook(colorHighlight)); - - RenderGroupHeaderText(p_group,p_headerRect,p_updateRect,p_dc); -} - - -CListControlFontOps::CListControlFontOps() : m_font((HFONT)::GetStockObject(DEFAULT_GUI_FONT)), m_itemHeight(), m_groupHeaderHeight() { - UpdateGroupHeaderFont(); - CalculateHeights(); -} - -void CListControlFontOps::UpdateGroupHeaderFont() { - try { - m_groupHeaderFont = NULL; - LOGFONT lf = {}; - WIN32_OP_D( m_font.GetLogFont(lf) ); - lf.lfHeight = pfc::rint32( (double) lf.lfHeight * GroupHeaderFontScale() ); - lf.lfWeight = GroupHeaderFontWeight(lf.lfWeight); - WIN32_OP_D( m_groupHeaderFont.CreateFontIndirect(&lf) != NULL ); - } catch(std::exception const & e) { - (void) e; - // console::print(e.what()); - m_groupHeaderFont = (HFONT)::GetStockObject(DEFAULT_GUI_FONT); - } -} - -void CListControlFontOps::CalculateHeights() { - const t_uint32 spacing = MulDiv(4, m_dpi.cy, 96); - m_itemHeight = GetFontHeight( m_font ) + spacing; - m_groupHeaderHeight = GetFontHeight( m_groupHeaderFont ) + spacing; -} - -void CListControlFontOps::SetFont(HFONT font,bool bUpdateView) { - m_font = font; - UpdateGroupHeaderFont(); CalculateHeights(); - OnSetFont(bUpdateView); - if (bUpdateView && m_hWnd != NULL) OnViewAreaChanged(); - -} - -LRESULT CListControlFontOps::OnSetFont(UINT,WPARAM wp,LPARAM,BOOL&) { - SetFont((HFONT)wp); - return 0; -} - -LRESULT CListControlFontOps::OnGetFont(UINT,WPARAM,LPARAM,BOOL&) { - return (LRESULT)(HFONT)m_font; -} - -void CListControlImpl::SetCaptureEx(CaptureProc_t proc) { - this->m_captureProc = proc; SetCapture(); -} - -LRESULT CListControlImpl::MousePassThru(UINT msg, WPARAM wp, LPARAM lp) { - auto p = m_captureProc; // create local ref in case something in mid-captureproc clears it - if ( p ) { - CPoint pt(lp); - if (!p(msg, (DWORD) wp, pt ) ) { - ReleaseCapture(); - m_captureProc = nullptr; - } - return 0; - } - - SetMsgHandled(FALSE); - return 0; -} - -LRESULT CListControlImpl::OnGetDlgCode(UINT, WPARAM wp, LPARAM) { - switch(wp) { - case VK_RETURN: - return m_dlgWantEnter ? DLGC_WANTMESSAGE : 0; - default: - SetMsgHandled(FALSE); - return 0; - } -} - -void CListControlImpl::CreateInDialog(CWindow wndDialog, UINT replaceControlID ) { - CWindow lstReplace = wndDialog.GetDlgItem(replaceControlID); - PFC_ASSERT( lstReplace != NULL ); - auto status = lstReplace.SendMessage(WM_GETDLGCODE, VK_RETURN ); - m_dlgWantEnter = (status & DLGC_WANTMESSAGE); - CRect rc; - CWindow wndPrev = wndDialog.GetNextDlgTabItem(lstReplace, TRUE); - WIN32_OP_D( lstReplace.GetWindowRect(&rc) ); - WIN32_OP_D( wndDialog.ScreenToClient(rc) ); - WIN32_OP_D( lstReplace.DestroyWindow() ); - WIN32_OP_D( this->Create(wndDialog, &rc, 0, 0, WS_EX_STATICEDGE, replaceControlID) ); - if (wndPrev != NULL ) this->SetWindowPos(wndPrev, 0,0,0,0, SWP_NOSIZE | SWP_NOMOVE ); - this->SetFont(wndDialog.GetFont()); -} - - -void CListControlImpl::defer(std::function f) { - m_deferred.push_back( f ); - if (!m_defferredMsgPending) { - if ( PostMessage(MSG_EXEC_DEFERRED) ) m_defferredMsgPending = true; - } -} - -LRESULT CListControlImpl::OnExecDeferred(UINT, WPARAM, LPARAM) { - - for ( ;; ) { - auto i = m_deferred.begin(); - if ( i == m_deferred.end() ) break; - auto op = std::move(*i); - m_deferred.erase(i); // erase first, execute later - avoid erratic behavior if op alters the list - op(); - } - - m_defferredMsgPending = false; - return 0; -} - -// ======================================================================================== -// Mouse wheel vs drag&drop hacks -// Install MouseHookProc for the duration of DoDragDrop and handle the input from there -// ======================================================================================== -static HHOOK g_hook = NULL; -static CListControlImpl * g_dragDropInstance = nullptr; -LRESULT CALLBACK CListControlImpl::MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) { - if (nCode == HC_ACTION && g_dragDropInstance != nullptr) { - switch (wParam) { - case WM_MOUSEWHEEL: - case WM_MOUSEHWHEEL: - g_dragDropInstance->MouseWheelFromHook((UINT)wParam, lParam); - break; - } - } - return CallNextHookEx(g_hook, nCode, wParam, lParam); -} - -bool CListControlImpl::MouseWheelFromHook(UINT msg, LPARAM data) { - MOUSEHOOKSTRUCTEX const * mhs = reinterpret_cast ( data ); - if ( ::WindowFromPoint(mhs->pt) != m_hWnd ) return false; - LRESULT dummyResult = 0; - WPARAM wp = mhs->mouseData; - LPARAM lp = MAKELPARAM( mhs->pt.x, mhs->pt.y ); - // If we get here, m_suppressMouseWheel should be true per our DoDragDrop() - pfc::vartoggle_t scope(m_suppressMouseWheel, false); - this->ProcessWindowMessage( m_hWnd, msg, wp, lp, dummyResult ); - return true; -} - -HRESULT CListControlImpl::DoDragDrop(LPDATAOBJECT pDataObj, LPDROPSOURCE pDropSource, DWORD dwOKEffects, LPDWORD pdwEffect) { - HRESULT ret = E_FAIL; - // Should not get here with non null g_dragDropInstance - means we have a recursive call - PFC_ASSERT(g_dragDropInstance == nullptr); - if ( g_dragDropInstance == nullptr ) { - // futureproofing: kill mouse wheel message processing if we get them delivered the regular way while this is in progress - pfc::vartoggle_t scope(m_suppressMouseWheel, true); - g_dragDropInstance = this; - g_hook = SetWindowsHookEx(WH_MOUSE, MouseHookProc, NULL, GetCurrentThreadId()); - try { - ret = ::DoDragDrop(pDataObj, pDropSource, dwOKEffects, pdwEffect); - } catch (...) { - } - g_dragDropInstance = nullptr; - UnhookWindowsHookEx(pfc::replace_null_t(g_hook)); - } - return ret; -} - -void CListControlImpl::OnKillFocus(CWindow) { - if (m_captureProc) { - ReleaseCapture(); - m_captureProc = nullptr; - } - SetMsgHandled(FALSE); -} - -void CListControlImpl::OnWindowPosChanged(LPWINDOWPOS arg) { - if ( arg->flags & SWP_HIDEWINDOW ) { - if (m_captureProc) { - ReleaseCapture(); - m_captureProc = nullptr; - } - } - SetMsgHandled(FALSE); -} - -void CListControlHeaderImpl::RenderItemBackground(CDCHandle p_dc,const CRect & p_itemRect,size_t item, uint32_t bkColor) { - if ( ! this->DelimitColumns() ) { - __super::RenderItemBackground(p_dc, p_itemRect, item, bkColor); - } else { - auto cnt = this->GetColumnCount(); - uint32_t x = 0; - for( size_t walk = 0; walk < cnt; ) { - auto span = this->GetSubItemSpan( item, walk ); - PFC_ASSERT( span > 0 ); - uint32_t width = 0; - for( size_t walk2 = 0; walk2 < span; ++ walk2 ) { - width += this->GetSubItemWidth( walk + walk2 ); - } - CRect rc = p_itemRect; - rc.left = x; - x += width; - rc.right = x; - __super::RenderItemBackground(p_dc, rc, item, bkColor); - walk += span; - } - } -} diff --git a/libPPUI/CListControl.h b/libPPUI/CListControl.h deleted file mode 100644 index 8cecb4f..0000000 --- a/libPPUI/CListControl.h +++ /dev/null @@ -1,328 +0,0 @@ -#pragma once - -// ================================================================================ -// Main CListControl implementation -// -// For ready-to-use CListControl specializations, -// see CListControlSimple.h and CListControlOwnerData.h -// ================================================================================ - - -#pragma comment(lib, "uxtheme.lib") - -#include -#include -#include -#include -#include -#include "CMiddleDragImpl.h" -#include "wtl-pp.h" -#include "gesture.h" -#include "gdiplus_helpers.h" - -#define CListControl_ScrollWindowFix - -#ifdef CListControl_ScrollWindowFix -#define WS_EX_COMPOSITED_CListControl 0 -#else -#define WS_EX_COMPOSITED_CListControl WS_EX_COMPOSITED -#endif - - -typedef std::function< bool ( UINT, DWORD, CPoint ) > CaptureProc_t; - -typedef CWinTraits CListControlTraits; - -class CListControlImpl : public CWindowImpl { -public: - CListControlImpl() {} - - DECLARE_WND_CLASS_EX(TEXT("{4B94B650-C2D8-40de-A0AD-E8FADF62D56C}"),CS_DBLCLKS,COLOR_WINDOW); - - // Wrapper around CWindowImpl::Create(). - // Creates CListControl replacing another dialog control with the specified ID. - // Note that m_dlgWantEnter is set to false by this method, as it's typically unwanted in dialogs. - void CreateInDialog( CWindow wndDialog, UINT replaceControlID ); - - enum { - MSG_SIZE_ASYNC = WM_USER + 13, - MSG_EXEC_DEFERRED, - UserMsgBase - }; - - BEGIN_MSG_MAP_EX(CListControlImpl) - MESSAGE_RANGE_HANDLER_EX(WM_MOUSEFIRST, WM_MOUSELAST, MousePassThru); - MESSAGE_HANDLER_EX(MSG_EXEC_DEFERRED, OnExecDeferred); - MESSAGE_HANDLER(WM_PAINT,OnPaint); - MSG_WM_PRINTCLIENT(OnPrintClient); - MESSAGE_HANDLER(WM_VSCROLL,OnVScroll); - MESSAGE_HANDLER(WM_HSCROLL,OnHScroll); - MESSAGE_HANDLER(WM_SIZE,OnSize); - MESSAGE_HANDLER(WM_MOUSEHWHEEL,OnHWheel); - MESSAGE_HANDLER(WM_MOUSEWHEEL,OnVWheel); - MESSAGE_HANDLER(WM_LBUTTONDOWN,SetFocusPassThru); - MESSAGE_HANDLER(WM_RBUTTONDOWN,SetFocusPassThru); - MESSAGE_HANDLER(WM_MBUTTONDOWN,SetFocusPassThru); - MESSAGE_HANDLER(WM_LBUTTONDBLCLK,SetFocusPassThru); - MESSAGE_HANDLER(WM_RBUTTONDBLCLK,SetFocusPassThru); - MESSAGE_HANDLER(WM_MBUTTONDBLCLK,SetFocusPassThru); - MESSAGE_HANDLER(WM_CREATE,OnCreatePassThru); - MESSAGE_HANDLER(WM_ERASEBKGND,OnEraseBkgnd); - MESSAGE_HANDLER(MSG_SIZE_ASYNC,OnSizeAsync); - MESSAGE_HANDLER(WM_GESTURE, OnGesture) - MSG_WM_THEMECHANGED(OnThemeChanged) - MSG_WM_KILLFOCUS(OnKillFocus) - MSG_WM_WINDOWPOSCHANGED(OnWindowPosChanged) - MESSAGE_HANDLER_EX( WM_GETDLGCODE, OnGetDlgCode ) - END_MSG_MAP() - - virtual void ReloadData() { OnViewAreaChanged(); } - virtual void ReloadItems( pfc::bit_array const & mask ) { UpdateItems( mask); } - - //! Hookable function called in response to reordering of items. Redraws the view and updates internal data to reflect the change. - virtual void OnItemsReordered( const size_t * order, size_t count ); - //! Hookable function called in response to removal of items. Redraws the view and updates internal data to reflect the change. - virtual void OnItemsRemoved( pfc::bit_array const & mask, size_t oldCount ) { ReloadData(); } - //! Hookable function called in response to insertion of items. Redraws the view and updates internal data to reflect the change. - virtual void OnItemsInserted( size_t at, size_t count, bool bSelect ) { ReloadData(); } - - void ReloadItem(size_t i) { ReloadItems( pfc::bit_array_one(i) ); } - void OnViewAreaChanged() {OnViewAreaChanged(GetViewOrigin());} - void OnViewAreaChanged(CPoint p_originOverride); - void UpdateGroupHeader(int p_id); - void UpdateItems(const pfc::bit_array & p_mask); - void UpdateItemsAndHeaders(const pfc::bit_array & p_mask); - void UpdateItem(t_size p_item) {UpdateItems(pfc::bit_array_one(p_item));} - void UpdateItemsAll() {Invalidate();} - void EnsureItemVisible(t_size p_item, bool bUser = false); - void EnsureHeaderVisible(int p_group); - virtual void EnsureVisibleRectAbs(const CRect & p_rect); - CRect GetItemRect(t_size p_item) const; - bool GetGroupHeaderRect(int p_group,CRect & p_rect) const; - CRect GetItemRectAbs(t_size p_item) const; - bool GetGroupHeaderRectAbs(int p_group,CRect & p_rect) const; - CPoint GetViewOrigin() const {return m_viewOrigin;} - CPoint GetViewOffset() const {return GetViewOrigin() - GetClientOrigin();} - int GetViewAreaWidth() const {return GetItemWidth();} - int GetViewAreaHeight() const; - CRect GetViewAreaRectAbs() const; - CRect GetViewAreaRect() const; - CRect GetValidViewOriginArea() const; - t_size GetGroupCount() const; - bool GetItemRangeAbs(const CRect & p_rect,t_size & p_base,t_size & p_count) const; - bool GetItemRangeAbsInclHeaders(const CRect & p_rect,t_size & p_base,t_size & p_count) const; - bool GetItemRange(const CRect & p_rect,t_size & p_base,t_size & p_count) const; - void MoveViewOriginNoClip(CPoint p_target); - void MoveViewOrigin(CPoint p_target); - CPoint ClipViewOrigin(CPoint p_origin) const; - void MoveViewOriginDelta(CPoint p_delta) {MoveViewOrigin( GetViewOrigin() + p_delta );} - void MoveViewOriginDeltaNoClip(CPoint p_delta) {MoveViewOriginNoClip( GetViewOrigin() + p_delta );} - bool ItemFromPoint(CPoint const & p_pt,t_size & p_item) const {return ItemFromPointAbs(p_pt + GetViewOffset(),p_item);} - bool GroupHeaderFromPoint(CPoint const & p_pt,int & p_group) const {return GroupHeaderFromPointAbs(p_pt + GetViewOffset(),p_group);} - bool ItemFromPointAbs(CPoint const & p_pt,t_size & p_item) const; - bool GroupHeaderFromPointAbs(CPoint const & p_pt,int & p_group) const; - - bool ResolveGroupRange(int p_id,t_size & p_base,t_size & p_count) const; - - virtual int GetGroupHeaderHeight() const {return 0;} - virtual int GetItemHeight() const {return 0;} - virtual int GetItemWidth() const {return 0;} - virtual t_size GetItemCount() const {return 0;} - virtual int GetItemGroup(t_size p_item) const {return 0;} - //override optionally - virtual void RenderItem(t_size p_item,const CRect & p_itemRect,const CRect & p_updateRect,CDCHandle p_dc); - //override optionally - virtual void RenderGroupHeader(int p_group,const CRect & p_headerRect,const CRect & p_updateRect,CDCHandle p_dc); - - //called by default RenderItem implementation - virtual void RenderItemText(t_size p_item,const CRect & p_itemRect,const CRect & p_updateRect,CDCHandle p_dc, bool allowColors) {} - //called by default RenderItem implementation - virtual void RenderGroupHeaderText(int p_group,const CRect & p_headerRect,const CRect & p_updateRect,CDCHandle p_dc) {} - - virtual void RenderItemBackground(CDCHandle p_dc,const CRect & p_itemRect,size_t item, uint32_t bkColor); - virtual void RenderGroupHeaderBackground(CDCHandle p_dc,const CRect & p_headerRect,int iGroup); - - virtual void RenderBackground( CDCHandle dc, CRect const & rc ); - - virtual void OnViewOriginChange(CPoint p_delta) {} - virtual void RenderOverlay(const CRect & p_updaterect,CDCHandle p_dc) {} - virtual bool FixedOverlayPresent() {return false;} - - virtual CRect GetClientRectHook() const; - - enum { - colorText = COLOR_WINDOWTEXT, - colorBackground = COLOR_WINDOW, - colorHighlight = COLOR_HOTLIGHT, - colorSelection = COLOR_HIGHLIGHT, - }; - - virtual COLORREF GetSysColorHook( int colorIndex ) const; - - //! Called by CListControlWithSelectionBase. - virtual void OnItemClicked(t_size item, CPoint pt) {} - //! Called by CListControlWithSelectionBase. - virtual void OnGroupHeaderClicked(int groupId, CPoint pt) {} - - //! Return true to indicate that some area of the control has a special purpose and clicks there should not trigger changes in focus/selection. - virtual bool OnClickedSpecialHitTest(CPoint pt) { return false; } - virtual bool OnClickedSpecial(DWORD status, CPoint pt) {return false;} - - virtual bool AllowScrollbar(bool vertical) const {return true;} - - CPoint GetClientOrigin() const {return GetClientRectHook().TopLeft();} - CRect GetVisibleRectAbs() const { - CRect view = GetClientRectHook(); - view.OffsetRect( GetViewOrigin() - view.TopLeft() ); - return view; - } - - bool IsSameItemOrHeaderAbs(const CPoint & p_point1, const CPoint & p_point2) const; - - void AddItemToUpdateRgn(HRGN p_rgn, t_size p_index) const; - void AddGroupHeaderToUpdateRgn(HRGN p_rgn, int id) const; - - t_size InsertIndexFromPoint(const CPoint & p_pt) const; - //! Translate point to insert location for drag and drop. \n - //! Made virtual so it can be specialized to allow only specific drop locations. - virtual t_size InsertIndexFromPointEx(const CPoint & pt, bool & bInside) const; - - virtual void ListHandleResize(); - - //! Can smooth-scroll *now* ? Used to suppress smooth scroll on temporary basis due to specific user operations in progress - virtual bool CanSmoothScroll() const { return true; } - //! Is smooth scroll enabled by user? - virtual bool UserEnabledSmoothScroll() const; - virtual bool ToggleSelectedItemsHook(pfc::bit_array const & mask) { return false; } - - void SetCaptureEx(CaptureProc_t proc); - void SetCaptureMsgHandled(BOOL v) { this->SetMsgHandled(v); } - - SIZE GetDPI() const { return this->m_dpi;} - - // Should this control take enter key in dialogs or not? - // Default to true for compatibility with existing code - but when used in dialogs, you'll want it set to false to hit [OK] with enter. - // Note that CreateInDialog() sets this to false. Change it later if you want enter key presses to reach this control in a dialog. - bool m_dlgWantEnter = true; - - bool WantReturn() const { return m_dlgWantEnter; } - void SetWantReturn(bool v) { m_dlgWantEnter = v; } - - enum { - rowStyleGrid = 0, - rowStyleFlat, - rowStylePlaylist, - rowStylePlaylistDelimited, - }; - void SetPlaylistStyle() {SetRowStyle(rowStylePlaylist);} - void SetRowStyle(unsigned v) { this->m_rowStyle = v; if (m_hWnd) Invalidate(); } - void SetFlatStyle() {SetRowStyle(rowStyleFlat);} - unsigned m_rowStyle = rowStylePlaylistDelimited; - bool DelimitColumns() const { return m_rowStyle == rowStyleGrid || m_rowStyle == rowStylePlaylistDelimited; } - - static COLORREF BlendGridColor( COLORREF bk, COLORREF tx ); - static COLORREF BlendGridColor( COLORREF bk ); - COLORREF GridColor(); - -private: - void RenderRect(const CRect & p_rect,CDCHandle p_dc); - int HandleWheel(int & p_accum,int p_delta, bool bHoriz); - - void OnKillFocus(CWindow); - void OnWindowPosChanged(LPWINDOWPOS); - void PaintContent(CRect rcPaint, HDC dc); - void OnPrintClient(HDC dc, UINT uFlags); - LRESULT OnPaint(UINT,WPARAM,LPARAM,BOOL&); - LRESULT OnVScroll(UINT,WPARAM,LPARAM,BOOL&); - LRESULT OnHScroll(UINT,WPARAM,LPARAM,BOOL&); - LRESULT OnSize(UINT,WPARAM,LPARAM,BOOL&); - LRESULT OnSizeAsync(UINT,WPARAM,LPARAM,BOOL&) {ListHandleResize();return 0;} - LRESULT OnVWheel(UINT,WPARAM,LPARAM,BOOL&); - LRESULT OnHWheel(UINT,WPARAM,LPARAM,BOOL&); - LRESULT OnGesture(UINT,WPARAM,LPARAM,BOOL&); - LRESULT SetFocusPassThru(UINT,WPARAM,LPARAM,BOOL&); - LRESULT OnCreatePassThru(UINT,WPARAM,LPARAM,BOOL&); - LRESULT OnEraseBkgnd(UINT,WPARAM,LPARAM,BOOL&); - LRESULT MousePassThru(UINT, WPARAM, LPARAM); - LRESULT OnGetDlgCode(UINT, WPARAM, LPARAM); - - void OnThemeChanged(); - int GetScrollThumbPos(int which); - void RefreshSliders(); - void RefreshSlider(bool p_vertical); - - void OnSizeAsync_Trigger(); - static LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam); - bool MouseWheelFromHook(UINT msg, LPARAM data); - - bool m_suppressMouseWheel = false; - int m_wheelAccumX = 0, m_wheelAccumY = 0; - CPoint m_viewOrigin = CPoint(0,0); - bool m_sizeAsyncPending = false; - CPoint m_gesturePoint; - -protected: - pfc::map_t m_themeCache; - CTheme & themeFor( const char * what ); - CTheme & theme() { return themeFor("LISTVIEW");} - - const SIZE m_dpi = QueryScreenDPIEx(); - CGestureAPI m_gestureAPI; - bool m_ensureVisibleUser = false; - CaptureProc_t m_captureProc; - void defer( std::function f ); - LRESULT OnExecDeferred(UINT, WPARAM, LPARAM); - - - // Overlays our stuff on top of generic DoDragDrop call. - // Currently catches mouse wheel messages in mid-drag&drop and handles them in our view. - HRESULT DoDragDrop(LPDATAOBJECT pDataObj, LPDROPSOURCE pDropSource, DWORD dwOKEffects, LPDWORD pdwEffect); - -private: - bool m_defferredMsgPending = false; - std::list > m_deferred; -}; - -class CListControlFontOps : public CListControlImpl { -private: - typedef CListControlImpl TParent; -public: - CListControlFontOps(); - BEGIN_MSG_MAP_EX(CListControlFontOps) - MESSAGE_HANDLER(WM_GETFONT,OnGetFont); - MESSAGE_HANDLER(WM_SETFONT,OnSetFont); - CHAIN_MSG_MAP(TParent); - END_MSG_MAP() - CFontHandle GetFont() const { return m_font; } - void SetFont(HFONT font, bool bUpdateView = true); -protected: - CFontHandle GetGroupHeaderFont() const {return (HFONT)m_groupHeaderFont;} - virtual double GroupHeaderFontScale() const { return 1.25; } - virtual int GroupHeaderFontWeight(int origVal) const { - //return pfc::min_t(FW_BLACK, origVal + 200); - return origVal; - } - - //! Overridden implementations should always forward the call to the base class. - virtual void OnSetFont(bool bUpdatingView) {} - - int GetGroupHeaderHeight() const {return m_groupHeaderHeight;} - int GetItemHeight() const {return m_itemHeight;} - -private: - LRESULT OnSetFont(UINT,WPARAM,LPARAM,BOOL&); - LRESULT OnGetFont(UINT,WPARAM,LPARAM,BOOL&); - void UpdateGroupHeaderFont(); - void CalculateHeights(); - int m_itemHeight, m_groupHeaderHeight; - CFontHandle m_font; - CFont m_groupHeaderFont; -}; - -#include "CListControlHeaderImpl.h" -#include "CListControlTruncationTooltipImpl.h" - - - -typedef CMiddleDragImpl CListControl; - diff --git a/libPPUI/CListControlComplete.h b/libPPUI/CListControlComplete.h deleted file mode 100644 index ea8968e..0000000 --- a/libPPUI/CListControlComplete.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -// ================================================================================ -// CListControlComplete -// ================================================================================ -// Simplified declaration of the base class that most CListControl users will need. -// The other base classes are used directly mainly by old code predating libPPUI. -// ================================================================================ - -#include "CListControlWithSelection.h" -#include "CListControl_EditImpl.h" -#include "CListAccessible.h" - -// ================================================================================ -// CListControlWithSelectionImpl = list control with selection/focus -// CListControl_EditImpl = inplace editbox implementation -// CListControlAccImpl = accessibility API implementation (screen reader interop) -// ================================================================================ -typedef CListControlAccImpl > CListControlComplete; - -// CListControlReadOnly : no inplace edit functionality (CListControl_EditImpl) -typedef CListControlAccImpl CListControlReadOnly; diff --git a/libPPUI/CListControlHeaderImpl.cpp b/libPPUI/CListControlHeaderImpl.cpp deleted file mode 100644 index 3709164..0000000 --- a/libPPUI/CListControlHeaderImpl.cpp +++ /dev/null @@ -1,1078 +0,0 @@ -#include "stdafx.h" -#include "CListControl.h" -#include "CListControlHeaderImpl.h" // redundant but makes intelisense quit showing false errors -#include "CListControl-Cells.h" -#include "PaintUtils.h" -#include "GDIUtils.h" -#include "win32_utility.h" - -enum { - lineBelowHeaderCY = 1 -}; - -static bool testDrawLineBelowHeader() { - // Win10 - return GetOSVersionCode() >= 0xA00; -} - -void CListControlHeaderImpl::InitializeHeaderCtrl(DWORD flags) { - PFC_ASSERT(!IsHeaderEnabled()); - WIN32_OP_D( m_header.Create(*this,NULL,NULL,WS_CHILD | flags) != NULL ); - m_header.SetFont( GetFont() ); - - if (testDrawLineBelowHeader()) { - WIN32_OP_D( m_headerLine.Create( *this, NULL, NULL, WS_CHILD ) != NULL ); - } - - UpdateHeaderLayout(); -} - -void CListControlHeaderImpl::UpdateHeaderLayout() { - CRect client; WIN32_OP_D( GetClientRect(client) ); - m_clientWidth = client.Width(); - if (IsHeaderEnabled()) { - auto rc = client; - rc.left -= GetViewOffset().x; - WINDOWPOS wPos = {}; - HDLAYOUT layout = {&rc, &wPos}; - if (m_header.Layout(&layout)) { - m_header.SetWindowPos(wPos.hwndInsertAfter,wPos.x,wPos.y,wPos.cx,wPos.cy,wPos.flags | SWP_SHOWWINDOW); - if (m_headerLine != NULL) m_headerLine.SetWindowPos(m_header, wPos.x, wPos.y + wPos.cy, wPos.cx, lineBelowHeaderCY, wPos.flags | SWP_SHOWWINDOW); - } else { - m_header.ShowWindow(SW_HIDE); - if (m_headerLine != NULL) m_headerLine.ShowWindow(SW_HIDE); - } - } -} - -int CListControlHeaderImpl::GetItemWidth() const { - if (IsHeaderEnabled()) return m_itemWidth; - else return m_clientWidth; -} - -LRESULT CListControlHeaderImpl::OnSizePassThru(UINT,WPARAM,LPARAM p_lp) { - UpdateHeaderLayout(); - - ProcessAutoWidth(); - - SetMsgHandled(FALSE); - return 0; -} - -void CListControlHeaderImpl::OnViewOriginChange(CPoint p_delta) { - TParent::OnViewOriginChange(p_delta); - if (p_delta.x != 0) UpdateHeaderLayout(); -} - -void CListControlHeaderImpl::SetHeaderFont(HFONT font) { - if (IsHeaderEnabled()) { - m_header.SetFont(font); UpdateHeaderLayout(); - } -} - -LRESULT CListControlHeaderImpl::OnDividerDoubleClick(int,LPNMHDR hdr,BOOL&) { - const NMHEADER * info = (const NMHEADER *) hdr; - if (info->iButton == 0) { - AutoColumnWidth((t_size)info->iItem); - } - return 0; -} - -LRESULT CListControlHeaderImpl::OnHeaderItemClick(int,LPNMHDR p_hdr,BOOL&) { - const NMHEADER * info = (const NMHEADER *) p_hdr; - if (info->iButton == 0) { - OnColumnHeaderClick((t_uint32)info->iItem); - } - return 0; -} - -LRESULT CListControlHeaderImpl::OnHeaderItemChanged(int,LPNMHDR p_hdr,BOOL&) { - const NMHEADER * info = (const NMHEADER*) p_hdr; - if (info->pitem->mask & (HDI_WIDTH | HDI_ORDER)) { - if(!m_ownColumnsChange) ProcessColumnsChange(); - } - return 0; -} - -LRESULT CListControlHeaderImpl::OnHeaderEndDrag(int,LPNMHDR hdr,BOOL&) { - NMHEADER * info = (NMHEADER*) hdr; - return OnColumnHeaderDrag(info->iItem,info->pitem->iOrder) ? TRUE : FALSE; -} - -bool CListControlHeaderImpl::OnColumnHeaderDrag(t_size index, t_size newPos) { - index = GetSubItemOrder(index); - const t_size count = this->GetColumnCount(); - if ( count == 0 ) return false; - std::vector perm; perm.resize(count); pfc::create_move_items_permutation(&perm[0],count, pfc::bit_array_one(index), (int) newPos - (int) index ); - std::vector order, newOrder; order.resize(count); newOrder.resize(count); - WIN32_OP_D(m_header.GetOrderArray((int)count, &order[0])); - for(t_size walk = 0; walk < count; ++walk) newOrder[walk] = order[perm[walk]]; - WIN32_OP_D(m_header.SetOrderArray((int)count, &newOrder[0])); - OnColumnsChanged(); - return true; -} -t_size CListControlHeaderImpl::SubItemFromPointAbs(CPoint pt) const { - - auto order = GetColumnOrderArray(); - const t_size colCount = order.size(); - - size_t item; - if (! ItemFromPointAbs(pt, item ) ) item = pfc_infinite; - - long xWalk = 0; - for(t_size _walk = 0; _walk < colCount; ) { - const t_size walk = (t_size) order[_walk]; - - size_t span = 1; - if (item != pfc_infinite) span = this->GetSubItemSpan(item, walk); - - PFC_ASSERT( span == 1 || _walk == walk ); - - if ( walk + span > colCount ) span = colCount - walk; - - long width = 0; - for( size_t sub = 0; sub < span; ++ sub ) { - width += (long)this->GetSubItemWidth(walk + sub); - } - - if (xWalk + width > pt.x) return walk; - xWalk += width; - _walk += span; - } - return pfc_infinite; -} - -bool CListControlHeaderImpl::OnClickedSpecial(DWORD status, CPoint pt) { - - const DWORD maskButtons = MK_LBUTTON | MK_RBUTTON | MK_MBUTTON | MK_XBUTTON1 | MK_XBUTTON2; - - if ( (status & maskButtons) != MK_LBUTTON ) return false; - - if (!GetCellTypeSupported()) return false; - - size_t item; size_t subItem; - if (! this->GetItemAtPointAbsEx( pt + GetViewOffset(), item, subItem ) ) { - return false; - } - - bool bCapture = false; - auto cellType = GetCellType(item, subItem); - if ( !CellTypeReactsToMouseOver( cellType ) ) return false; - auto rcHot = CellHotRect( item, subItem, cellType ); - if (!rcHot.PtInRect( pt )) return false; - - SetPressedItem(item, subItem); - SetCaptureEx([=](UINT, DWORD newStatus, CPoint pt) { - - { - CRect rc = this->GetClientRectHook(); - if (!rc.PtInRect(pt)) { - ClearPressedItem(); return false; - } - } - - size_t newItem, newSubItem; - if (!this->GetItemAtPointAbsEx(pt + GetViewOffset(), newItem, newSubItem) || newItem != item || newSubItem != subItem) { - ClearPressedItem(); return false; - } - - DWORD buttons = newStatus & maskButtons; - if (buttons == 0) { - // button released? - this->defer( [=] { - OnSubItemClicked(item, subItem, pt); - } ); - ClearPressedItem(); return false; - } - if (buttons != MK_LBUTTON) { - // another button pressed? - ClearPressedItem(); return false; - } - - return true; - }); - return true; -} - -bool CListControlHeaderImpl::CellTypeUsesSpecialHitTests( cellType_t ct ) { - if ( ct == nullptr ) return false; - return ct->SuppressRowSelect(); -} - -bool CListControlHeaderImpl::OnClickedSpecialHitTest(CPoint pt) { - if ( ! GetCellTypeSupported() ) return false; - auto ct = GetCellTypeAtPointAbs( pt + GetViewOffset() ); - return CellTypeUsesSpecialHitTests(ct); -} - -void CListControlHeaderImpl::OnItemClicked(t_size item, CPoint pt) { - t_size subItem = SubItemFromPointAbs(pt + GetViewOffset()); - if (subItem != ~0) { - if ( this->GetCellTypeSupported() ) { - auto ct = this->GetCellType(item, subItem ); - // we don't handle hyperlink & button clicks thru here - if (CellTypeUsesSpecialHitTests(ct)) return; - } - OnSubItemClicked(item, subItem, pt); - } -} - -std::vector CListControlHeaderImpl::GetColumnOrderArray() const { - const size_t cCount = this->GetColumnCount(); - std::vector order; - if ( cCount > 0 ) { - order.resize(cCount); - if (IsHeaderEnabled()) { - WIN32_OP_D(m_header.GetOrderArray((int)cCount, &order[0])); - } else { - for (size_t c = 0; c < cCount; ++c) order[c] = (int)c; - } - } - return order; -} - -void CListControlHeaderImpl::RenderItemText(t_size item,const CRect & itemRect,const CRect & updateRect,CDCHandle dc, bool allowColors) { - - t_uint32 xWalk = itemRect.left; - CRect subItemRect(itemRect); - auto order = GetColumnOrderArray(); - const size_t cCount = order.size(); - SelectObjectScope fontScope(dc,GetFont()); - for(t_size _walk = 0; _walk < cCount; ) { - const t_size walk = order[_walk]; - - size_t span = GetSubItemSpan(item, walk); - - PFC_ASSERT( walk == _walk || span == 1 ); - - t_uint32 width = GetSubItemWidth(walk); - - if ( span > 1 ) { - if ( walk + span > cCount ) span = cCount - walk; - for( size_t extraWalk = 1; extraWalk < span; ++ extraWalk ) { - width += GetSubItemWidth(walk + extraWalk); - } - } - - subItemRect.left = xWalk; subItemRect.right = xWalk + width; - CRect subUpdate; - if (subUpdate.IntersectRect(subItemRect, updateRect)) { - DCStateScope scope(dc); - if (dc.IntersectClipRect(subItemRect) != NULLREGION) { - RenderSubItemText(item,walk,subItemRect,subUpdate,dc, allowColors); - } - } - xWalk += width; - - _walk += span; - } -} - -t_size CListControlHeaderImpl::GetSubItemOrder(t_size subItem) const { - if ( ! IsHeaderEnabled( ) ) return subItem; - HDITEM hditem = {}; - hditem.mask = HDI_ORDER; - WIN32_OP_D( m_header.GetItem( (int) subItem, &hditem ) ); - return (t_size) hditem.iOrder; -} - -size_t CListControlHeaderImpl::GetSubItemSpan(size_t row, size_t column) const { - return 1; -} - -uint32_t CListControlHeaderImpl::GetSubItemWidth(t_size subItem) const { - if ( ! IsHeaderEnabled( ) ) { - // Should be overridden for custom columns layout - PFC_ASSERT( GetColumnCount() == 1 ); - PFC_ASSERT( subItem == 0 ); - return GetItemWidth(); - } - - if ( subItem < m_colRuntime.size() ) return m_colRuntime[subItem].m_widthPixels; - PFC_ASSERT( !"bad column idx"); - return 0; -} - -int CListControlHeaderImpl::GetHeaderItemWidth( int which ) { - HDITEM hditem = {}; - hditem.mask = HDI_WIDTH; - WIN32_OP_D( m_header.GetItem( which, &hditem) ); - return hditem.cxy; -} - -void CListControlHeaderImpl::OnColumnsChanged() { - if ( IsHeaderEnabled() ) { - for( size_t walk = 0; walk < m_colRuntime.size(); ++ walk ) { - m_colRuntime[walk].m_widthPixels = GetHeaderItemWidth( (int) walk ); - } - RecalcItemWidth(); - } - this->OnViewAreaChanged(); -} - -void CListControlHeaderImpl::ResetColumns(bool update) { - m_colRuntime.clear(); - m_itemWidth = 0; - PFC_ASSERT(IsHeaderEnabled()); - for(;;) { - int count = m_header.GetItemCount(); - if (count <= 0) break; - m_header.DeleteItem(count - 1); - } - if (update) OnColumnsChanged(); -} - -void CListControlHeaderImpl::SetColumn( size_t which, const char * label, DWORD fmtFlags, bool updateView) { - PFC_ASSERT( IsHeaderEnabled() ); - pfc::stringcvt::string_os_from_utf8 labelOS(label); - - HDITEM item = {}; - item.mask = HDI_TEXT | HDI_FORMAT; - item.fmt = fmtFlags | HDF_STRING; - item.pszText = const_cast(labelOS.get_ptr()); - m_header.SetItem( (int) which, &item ); - - if (which < m_colRuntime.size()) m_colRuntime[which].m_text = label; - - if (updateView) OnColumnsChanged(); -} - -void CListControlHeaderImpl::GetColumnText(size_t which, pfc::string_base & out) const { - if (which < m_colRuntime.size()) { - out = m_colRuntime[which].m_text.c_str(); - } else { - out = ""; - } -} - -void CListControlHeaderImpl::ResizeColumn(t_size index, t_uint32 widthPixels, bool updateView) { - PFC_ASSERT( IsHeaderEnabled() ); - PFC_ASSERT( index < m_colRuntime.size() ); - HDITEM item = {}; - item.mask = HDI_WIDTH; - item.cxy = widthPixels; - { pfc::vartoggle_t scope(m_ownColumnsChange, true); m_header.SetItem( (int) index, &item ); } - m_colRuntime[index].m_widthPixels = widthPixels; - RecalcItemWidth(); - if (updateView) OnColumnsChanged(); -} - -void CListControlHeaderImpl::DeleteColumns( pfc::bit_array const & mask, bool updateView ) { - int nDeleted = 0; - const size_t oldCount = GetColumnCount(); - mask.for_each(true, 0, oldCount, [&] (size_t idx) { - int iDelete = (int) idx - nDeleted; - bool bDeleted = m_header.DeleteItem( iDelete ); - PFC_ASSERT( bDeleted ); - if ( bDeleted ) ++ nDeleted; - } ); - - pfc::remove_mask_t( m_colRuntime, mask ); - - ColumnWidthFix(); - - if (updateView) { - OnColumnsChanged(); - } - -} - -bool CListControlHeaderImpl::DeleteColumn(size_t index, bool update) { - PFC_ASSERT( IsHeaderEnabled() ); - - if (!m_header.DeleteItem( (int) index )) return false; - - pfc::remove_mask_t( m_colRuntime, pfc::bit_array_one( index ) ); - - ColumnWidthFix(); - - if (update) { - OnColumnsChanged(); - } - - return true; -} - -void CListControlHeaderImpl::SetSortIndicator( size_t whichColumn, bool isUp ) { - HeaderControl_SetSortIndicator( GetHeaderCtrl(), (int) whichColumn, isUp ); -} - -void CListControlHeaderImpl::ClearSortIndicator() { - HeaderControl_SetSortIndicator(GetHeaderCtrl(), -1, false); -} - -bool CListControlHeaderImpl::HaveAutoWidthContentColumns() const { - for( auto i = m_colRuntime.begin(); i != m_colRuntime.end(); ++ i ) { - if ( i->autoWidthContent() ) return true; - } - return false; -} -bool CListControlHeaderImpl::HaveAutoWidthColumns() const { - for( auto i = m_colRuntime.begin(); i != m_colRuntime.end(); ++ i ) { - if ( i->autoWidth() ) return true; - } - return false; -} -void CListControlHeaderImpl::AddColumnEx( const char * label, uint32_t widthPixelsAt96DPI, DWORD fmtFlags, bool update ) { - uint32_t w = widthPixelsAt96DPI; - if ( w <= columnWidthMax ) { - w = MulDiv( w, m_dpi.cx, 96 ); - } - AddColumn( label, w, fmtFlags, update ); -} - -void CListControlHeaderImpl::AddColumnDLU( const char * label, uint32_t widthDLU, DWORD fmtFlags, bool update ) { - uint32_t w = widthDLU; - if ( w <= columnWidthMax ) { - w = ::MapDialogWidth( GetParent(), w ); - } - AddColumn( label, w, fmtFlags, update ); -} -void CListControlHeaderImpl::AddColumnF( const char * label, float widthF, DWORD fmtFlags, bool update) { - uint32_t w = columnWidthMax; - if ( widthF >= 0 ) { - w = pfc::rint32( widthF * m_dpi.cx / 96.0f ); - } - AddColumn( label, w, fmtFlags, update ); -} -void CListControlHeaderImpl::AddColumn(const char * label, uint32_t width, DWORD fmtFlags,bool update) { - if (! IsHeaderEnabled( ) ) InitializeHeaderCtrl(); - - pfc::stringcvt::string_os_from_utf8 labelOS(label); - HDITEM item = {}; - item.mask = HDI_TEXT | HDI_FORMAT; - if ( width != UINT32_MAX ) { - item.cxy = width; - item.mask |= HDI_WIDTH; - } - - item.pszText = const_cast(labelOS.get_ptr()); - item.fmt = HDF_STRING | fmtFlags; - int iColumn; - WIN32_OP_D( (iColumn = m_header.InsertItem(m_header.GetItemCount(),&item) ) >= 0 ); - colRuntime_t rt; - rt.m_text = label; - rt.m_userWidth = width; - if ( width <= columnWidthMax ) { - m_itemWidth += width; - rt.m_widthPixels = width; - } - m_colRuntime.push_back( std::move(rt) ); - - if (update) OnColumnsChanged(); - - ProcessAutoWidth(); -} - -float CListControlHeaderImpl::GetColumnWidthF(size_t subItem) const { - auto w = GetSubItemWidth(subItem); - return (float) w * 96.0f / (float)m_dpi.cx; -} - -void CListControlHeaderImpl::RenderBackground(CDCHandle dc, CRect const& rc) { - __super::RenderBackground(dc,rc); -#if 0 - if ( m_drawLineBelowHeader && IsHeaderEnabled()) { - CRect rcHeader; - if (m_header.GetWindowRect(rcHeader)) { - // Draw a grid line below header - int y = rcHeader.Height(); - if ( y >= rc.top && y < rc.bottom ) { - CDCPen pen(dc, GridColor()); - SelectObjectScope scope(dc, pen); - dc.MoveTo(rc.left, y); - dc.LineTo(rc.right, y); - } - } - } -#endif -} - -CRect CListControlHeaderImpl::GetClientRectHook() const { - CRect rcClient = __super::GetClientRectHook(); - if (m_header != NULL) { - PFC_ASSERT( m_header.IsWindow() ); - CRect rcHeader; - if (m_header.GetWindowRect(rcHeader)) { - int h = rcHeader.Height(); - if ( m_headerLine != NULL ) h += lineBelowHeaderCY; - rcClient.top = pfc::min_t(rcClient.bottom,rcClient.top + h); - } - } - return rcClient; -} - -CRect CListControlHeaderImpl::GetItemTextRectHook(size_t, size_t, CRect const & rc) const { - return GetItemTextRect( rc ); -} - -CRect CListControlHeaderImpl::GetItemTextRect(const CRect & itemRect) const { - CRect rc ( itemRect ); - rc.DeflateRect(GetColumnSpacing(),0); - return rc; -} - -void CListControlHeaderImpl::SetColumnSort(t_size which, bool isUp) { - HeaderControl_SetSortIndicator(m_header,(int)which,isUp); -} - -void CListControlHeaderImpl::SetColumnFormat(t_size which, DWORD format) { - HDITEM item = {}; - item.mask = HDI_FORMAT; - item.fmt = HDF_STRING | format; - WIN32_OP_D( m_header.SetItem((int)which,&item) ); -} - -DWORD CListControlHeaderImpl::GetColumnFormat(t_size which) const { - if (!IsHeaderEnabled()) return HDF_LEFT; - HDITEM hditem = {}; - hditem.mask = HDI_FORMAT; - WIN32_OP_D( m_header.GetItem( (int) which, &hditem) ); - return hditem.fmt; -} - -BOOL CListControlHeaderImpl::OnSetCursor(CWindow wnd, UINT nHitTest, UINT message) { -#if 0 - // no longer meaningful since SetCapture on mouse over was added to track hot status - if ( message != 0 && GetCellTypeSupported() ) { - CPoint pt( (LPARAM) GetMessagePos() ); - WIN32_OP_D( ScreenToClient( &pt ) ); - if ( GetCellTypeAtPointAbs( pt + GetViewOffset() ) == cell_hyperlink ) { - SetCursor(LoadCursor(NULL, IDC_HAND)); return TRUE; - } - } -#endif - SetMsgHandled(FALSE); return FALSE; -} - -bool CListControlHeaderImpl::GetItemAtPointAbsEx(CPoint pt, size_t & outItem, size_t & outSubItem) const { - size_t item, subItem; - if (ItemFromPointAbs(pt, item)) { - subItem = SubItemFromPointAbs(pt); - if (subItem != pfc_infinite) { - outItem = item; outSubItem = subItem; return true; - } - } - return false; -} - -CListControlHeaderImpl::cellType_t CListControlHeaderImpl::GetCellTypeAtPointAbs(CPoint pt) const { - size_t item, subItem; - if ( GetItemAtPointAbsEx( pt, item, subItem) ) { - return GetCellType( item, subItem ); - } - return nullptr; -} - -void CListControlHeaderImpl::RenderSubItemTextInternal(t_size subItem, const CRect & subItemRect, CDCHandle dc, const char * text, bool allowColors) { - pfc::stringcvt::string_os_from_utf8 cvt(text); - CRect clip = GetItemTextRect(subItemRect); - const t_uint32 format = PaintUtils::DrawText_TranslateHeaderAlignment(GetColumnFormat(subItem)); - if (true) { - const t_uint32 bk = dc.GetBkColor(); - const t_uint32 fg = dc.GetTextColor(); - const t_uint32 hl = (allowColors ? GetSysColorHook(colorHighlight) : fg); - const t_uint32 colors[3] = {PaintUtils::BlendColor(bk, fg, 33), fg, hl}; - - PaintUtils::TextOutColorsEx(dc, cvt, clip, format, colors); - - dc.SetTextColor(fg); - } else { - dc.DrawText(cvt,(int)cvt.length(),clip,DT_NOPREFIX | DT_END_ELLIPSIS | DT_SINGLELINE | DT_VCENTER | format ); - } -} -CListCell * CListControlHeaderImpl::GetCellType( size_t item, size_t subItem ) const { - return &PFC_SINGLETON(CListCell_Text); -} -void CListControlHeaderImpl::RenderSubItemText(t_size item, t_size subItem,const CRect & subItemRect,const CRect & updateRect,CDCHandle dc, bool allowColors) { - const auto cellType = GetCellType( item, subItem ); - if ( cellType == nullptr ) { - PFC_ASSERT( !"Should not get here" ); - return; - } - pfc::string_formatter label; - const bool bHaveText = GetSubItemText(item,subItem,label); - if (! bHaveText ) { - label = ""; //sanity - } - - pfc::stringcvt::string_os_from_utf8_fast labelOS ( label ); - CListCell::DrawContentArg_t arg; - arg.hdrFormat = GetColumnFormat( subItem ); - arg.subItemRect = subItemRect; - arg.dc = dc; - arg.text = labelOS.get_ptr(); - arg.allowColors = allowColors; - bool bPressed; - if ( cellType->IsToggle() ) bPressed = this->GetCellCheckState(item, subItem); - else bPressed = (item == m_pressedItem) && (subItem == m_pressedSubItem); - bool bHot = (item == m_hotItem) && ( subItem == m_hotSubItem ); - if ( bPressed ) arg.cellState |= CListCell::cellState_pressed; - if ( bHot ) arg.cellState|= CListCell::cellState_hot; - arg.rcText = GetItemTextRectHook(item, subItem, subItemRect); - arg.rcHot = CellHotRect(item, subItem, cellType, subItemRect); - - auto strTheme = cellType->Theme(); - if ( strTheme != nullptr ) { - arg.theme = themeFor( strTheme ).m_theme; - } - arg.colorHighlight = GetSysColorHook(colorHighlight); - - arg.thisWnd = m_hWnd; - - if (this->IsSubItemGrayed( item, subItem ) ) { - arg.cellState |= CListCell::cellState_disabled; - } - - CFontHandle fontRestore; - CFont fontOverride; - - LOGFONT data; - if (dc.GetCurrentFont().GetLogFont(&data)) { - if ( cellType->ApplyTextStyle( data, CellTextScale(item, subItem ), arg.cellState ) ) { - if (fontOverride.CreateFontIndirect( & data )) { - fontRestore = dc.SelectFont( fontOverride ); - } - } - } - cellType->DrawContent( arg ); - - if ( fontRestore != NULL ) dc.SelectFont( fontRestore ); -} - -void CListControlHeaderImpl::RenderGroupHeaderText(int id,const CRect & headerRect,const CRect & updateRect,CDCHandle dc) { - pfc::string_formatter label; - if (GetGroupHeaderText(id,label)) { - SelectObjectScope fontScope(dc,GetGroupHeaderFont()); - pfc::stringcvt::string_os_from_utf8 cvt(label); - CRect contentRect(GetItemTextRect(headerRect)); - dc.DrawText(cvt,(int)cvt.length(),contentRect,DT_NOPREFIX | DT_END_ELLIPSIS | DT_SINGLELINE | DT_VCENTER | DT_LEFT ); - SIZE txSize; - const int lineSpacing = contentRect.Height() / 2; - if (dc.GetTextExtent(cvt,(int)cvt.length(),&txSize)) { - if (txSize.cx + lineSpacing < contentRect.Width()) { - const CPoint center = contentRect.CenterPoint(); - const CPoint pt1(contentRect.left + txSize.cx + lineSpacing, center.y), pt2(contentRect.right, center.y); - const COLORREF lineColor = PaintUtils::BlendColor(dc.GetTextColor(),dc.GetBkColor(),25); - -#ifndef CListControl_ScrollWindowFix -#error FIXME CMemoryDC needed -#endif - PaintUtils::DrawSmoothedLine(dc, pt1, pt2, lineColor, 1.0 * (double)m_dpi.cy / 96.0); - } - } - } -} - -uint32_t CListControlHeaderImpl::GetOptimalColumnWidthFixed(const char * fixedText) const { - CWindowDC dc(*this); - SelectObjectScope fontScope(dc, GetFont()); - GetOptimalWidth_Cache cache; - cache.m_dc = dc; - cache.m_stringTemp = fixedText; - return cache.GetStringTempWidth() + this->GetColumnSpacing() * 2; -} - -t_uint32 CListControlHeaderImpl::GetOptimalSubItemWidth(t_size item, t_size subItem, GetOptimalWidth_Cache & cache) const { - const t_uint32 base = this->GetColumnSpacing() * 2; - if (GetSubItemText(item,subItem,cache.m_stringTemp)) { - return base + cache.GetStringTempWidth(); - } else { - return base; - } -} - -t_uint32 CListControlHeaderImpl::GetOptimalWidth_Cache::GetStringTempWidth() { - if (m_stringTemp.replace_string_ex(m_stringTempUnfuckAmpersands, "&", "&&") > 0) { - m_convertTemp.convert(m_stringTempUnfuckAmpersands); - } else { - m_convertTemp.convert(m_stringTemp); - } - return PaintUtils::TextOutColors_CalcWidth(m_dc, m_convertTemp); -} - -t_uint32 CListControlHeaderImpl::GetOptimalColumnWidth(t_size which, GetOptimalWidth_Cache & cache) const { - const t_size totalItems = GetItemCount(); - t_uint32 val = 0; - for(t_size item = 0; item < totalItems; ++item) { - pfc::max_acc( val, GetOptimalSubItemWidth( item, which, cache ) ); - } - return val; -} - -t_uint32 CListControlHeaderImpl::GetOptimalSubItemWidthSimple(t_size item, t_size subItem) const { - CWindowDC dc(*this); - SelectObjectScope fontScope(dc, GetFont() ); - GetOptimalWidth_Cache cache; - cache.m_dc = dc; - return GetOptimalSubItemWidth(item, subItem, cache); -} - -LRESULT CListControlHeaderImpl::OnKeyDown(UINT,WPARAM wp,LPARAM,BOOL& bHandled) { - switch(wp) { - case VK_ADD: - if (IsKeyPressed(VK_CONTROL)) { - AutoColumnWidths(); - return 0; - } - break; - } - bHandled = FALSE; - return 0; -} - -uint32_t CListControlHeaderImpl::GetOptimalColumnWidth(size_t colIndex) const { - CWindowDC dc(*this); - SelectObjectScope fontScope(dc, GetFont()); - GetOptimalWidth_Cache cache; - cache.m_dc = dc; - uint32_t ret = 0; - const auto itemCount = GetItemCount(); - for (t_size walk = 0; walk < itemCount; ++walk) { - pfc::max_acc(ret, GetOptimalSubItemWidth(walk, colIndex, cache)); - } - return ret; -} - -void CListControlHeaderImpl::AutoColumnWidths(const pfc::bit_array & mask, bool expandLast) { - PFC_ASSERT( IsHeaderEnabled() ); - if (!IsHeaderEnabled()) return; - const t_size itemCount = GetItemCount(); - if (itemCount == 0) return; - const t_size columnCount = (t_size) m_header.GetItemCount(); - if (columnCount == 0) return; - pfc::array_t widths; widths.set_size(columnCount); widths.fill_null(); - { - CWindowDC dc(*this); - SelectObjectScope fontScope(dc,GetFont()); - GetOptimalWidth_Cache cache; - cache.m_dc = dc; - for(t_size walk = 0; walk < itemCount; ++walk) { - for(t_size colWalk = mask.find_first(true,0,columnCount); colWalk < columnCount; colWalk = mask.find_next(true,colWalk,columnCount)) { - pfc::max_acc(widths[colWalk], GetOptimalSubItemWidth(walk,colWalk,cache)); - } - } - } - - if (expandLast) { - uint32_t usedWidth = 0; size_t lastCol = SIZE_MAX; - pfc::array_t order; order.set_size(columnCount); - WIN32_OP_D( m_header.GetOrderArray((int)columnCount,order.get_ptr()) ); - for(size_t _walk = 0; _walk < columnCount; ++_walk) { - const size_t colWalk = (size_t) order[_walk]; - PFC_ASSERT( colWalk < columnCount ); - if (mask[colWalk]) { - lastCol = colWalk; - usedWidth += widths[colWalk]; - } else { - usedWidth += GetSubItemWidth(colWalk); - } - } - if (lastCol != SIZE_MAX) { - t_uint32 clientWidth = this->GetClientRectHook().Width(); - if (clientWidth > 0) --clientWidth; // $!@# scrollbar hack - if (usedWidth < clientWidth) { - widths[lastCol] += clientWidth - usedWidth; - } - } - } - for(t_size colWalk = mask.find_first(true,0,columnCount); colWalk < columnCount; colWalk = mask.find_next(true,colWalk,columnCount)) { - ResizeColumn(colWalk,widths[colWalk],false); - } - ProcessColumnsChange(); -} - -t_uint32 CListControlHeaderImpl::GetOptimalGroupHeaderWidth(int which) const { - CWindowDC dc(*this); - SelectObjectScope fontScope(dc,GetGroupHeaderFont()); - GetOptimalWidth_Cache cache; cache.m_dc = dc; - const t_uint32 base = this->GetColumnSpacing() * 2; - if (GetGroupHeaderText(which,cache.m_stringTemp)) { - return base + cache.GetStringTempWidth(); - } else { - return base; - } -} - -size_t CListControlHeaderImpl::GetColumnCount() const { - if ( ! IsHeaderEnabled() ) return 1; -#if PFC_DEBUG - int iHeaderCount = m_header.GetItemCount(); - PFC_ASSERT( m_colRuntime.size() == (size_t) iHeaderCount ); -#endif - return m_colRuntime.size(); -} - -void CListControlHeaderImpl::ColumnWidthFix() { - if ( this->HaveAutoWidthColumns() ) { - ProcessAutoWidth(); - } else { - RecalcItemWidth(); - } -} - -void CListControlHeaderImpl::ProcessAutoWidth() { - if ( HaveAutoWidthColumns() ) { - const int clientWidth = this->GetClientRectHook().Width(); - - if ( ! this->HaveAutoWidthContentColumns( ) && clientWidth == m_itemWidth) return; - - const size_t count = GetColumnCount(); - uint32_t totalNonAuto = 0; - size_t numAutoWidth = 0; - for(size_t walk = 0; walk < count; ++ walk ) { - if ( m_colRuntime[walk].autoWidth() ) { - ++ numAutoWidth; - } else { - totalNonAuto += GetSubItemWidth(walk); - } - } - int toDivide = clientWidth - totalNonAuto; - if ( toDivide < 0 ) toDivide = 0; - - size_t numLeft = numAutoWidth; - auto worker = [&] ( size_t iCol ) { - auto & rt = m_colRuntime[iCol]; - int lo = this->GetOptimalColumnWidthFixed( rt.m_text.c_str() ); - if ( rt.autoWidthContent() ) { - int lo2 = this->GetOptimalColumnWidth( iCol ); - if ( lo < lo2 ) lo = lo2; - } - int width = (int)(toDivide / numLeft); - if ( width < lo ) width = lo; - - HDITEM item = {}; - item.mask = HDI_WIDTH; - item.cxy = width; - WIN32_OP_D( m_header.SetItem( iCol, &item ) ); - rt.m_widthPixels = width; - - if ( toDivide > width ) { - toDivide -= width; - } else { - toDivide = 0; - } - -- numLeft; - - }; - for( size_t iCol = 0; iCol < count; ++ iCol ) { - if (m_colRuntime[iCol].autoWidthContent() ) worker(iCol); - } - for( size_t iCol = 0; iCol < count; ++ iCol ) { - if ( m_colRuntime[iCol].autoWidthPlain() ) worker(iCol); - } - - RecalcItemWidth(); - OnColumnsChanged(); - m_header.Invalidate(); - } -} - -void CListControlHeaderImpl::RecalcItemWidth() { - int total = 0; - const t_size count = GetColumnCount(); - for(t_size walk = 0; walk < count; ++walk) total += GetSubItemWidth(walk); - m_itemWidth = total; -} - -CRect CListControlHeaderImpl::GetSubItemRectAbs(t_size item,t_size subItem) const { - CRect rc = GetItemRectAbs(item); - auto order = GetColumnOrderArray(); - const t_size colCount = order.size(); - for(t_size _walk = 0; _walk < colCount; ++_walk) { - const t_size walk = (t_size) order[_walk]; - - t_size width = this->GetSubItemWidth(walk); - if (subItem == walk) { - - size_t span = GetSubItemSpan(item, walk); - if ( walk + span > colCount ) span = colCount - walk; - for( size_t extra = 1; extra < span; ++ extra ) { - width += GetSubItemWidth( walk + extra); - } - - rc.right = rc.left + (long)width; - - return rc; - } else { - rc.left += (long)width; - } - } - throw pfc::exception_invalid_params(); -} - -CRect CListControlHeaderImpl::GetSubItemRect(t_size item,t_size subItem) const { - CRect rc = GetSubItemRectAbs(item,subItem); rc.OffsetRect(-GetViewOffset()); return rc; -} - -void CListControlHeaderImpl::SetHotItem(size_t row, size_t column) { - if ( m_hotItem != row || m_hotSubItem != column ) { - if (m_hotItem != pfc_infinite) InvalidateRect(GetSubItemRect(m_hotItem, m_hotSubItem)); - m_hotItem = row; m_hotSubItem = column; - if (m_hotItem != pfc_infinite) InvalidateRect(GetSubItemRect(m_hotItem, m_hotSubItem)); - } -} - -void CListControlHeaderImpl::SetPressedItem(size_t row, size_t column) { - if (m_pressedItem != row || m_pressedSubItem != column) { - if (m_pressedItem != pfc_infinite) InvalidateRect(GetSubItemRect(m_pressedItem, m_pressedSubItem)); - m_pressedItem = row; m_pressedSubItem = column; - if (m_pressedItem != pfc_infinite) InvalidateRect(GetSubItemRect(m_pressedItem, m_pressedSubItem)); - } -} - -void CListControlHeaderImpl::SetCellCheckState(size_t item, size_t subItem, bool value) { - ReloadItem(item); (void)subItem; (void)value; - // Subclass deals with keeping track of state -} - -bool CListControlHeaderImpl::ToggleSelectedItemsHook(const pfc::bit_array & mask) { - if (this->GetCellTypeSupported() ) { - bool handled = false; - bool setTo = true; - - mask.walk(GetItemCount(), [&](size_t idx) { - auto ct = this->GetCellType(idx, 0); - if ( ct != nullptr && ct->IsToggle() ) { - if ( ct->IsRadioToggle() ) { - if (!handled) { - handled = true; - setTo = !this->GetCellCheckState(idx, 0); - this->SetCellCheckState(idx, 0, setTo); - } - } else { - if (!handled) { - handled = true; - setTo = ! this->GetCellCheckState(idx,0); - } - this->SetCellCheckState(idx,0,setTo); - } - } - }); - - if (handled) return true; - } - return __super::ToggleSelectedItemsHook(mask); -} - -void CListControlHeaderImpl::OnSubItemClicked(t_size item, t_size subItem, CPoint pt) { - auto ct = GetCellType(item, subItem); - if ( ct != nullptr && ct->IsToggle() ) { - if ( ct->HotRect(GetSubItemRect(item, subItem)).PtInRect(pt) ) { - this->SetCellCheckState( item, subItem, ! GetCellCheckState( item, subItem ) ); - } - } -} - - -bool CListControlHeaderImpl::AllowTypeFindInCell(size_t item, size_t subItem) const { - auto cell = GetCellType( item, subItem ); - if ( cell == nullptr ) return false; - return cell->AllowTypeFind(); -} - -bool CListControlHeaderImpl::CellTypeReactsToMouseOver(cellType_t ct) { - return ct != nullptr && ct->IsInteractive(); -} - -CRect CListControlHeaderImpl::CellHotRect( size_t, size_t, cellType_t ct, CRect rcCell) { - if ( ct != nullptr ) { - return ct->HotRect(rcCell); - } - return rcCell; -} -CRect CListControlHeaderImpl::CellHotRect(size_t item, size_t subItem, cellType_t ct) { - return CellHotRect( item, subItem, ct, GetSubItemRect( item, subItem ) ); -} -void CListControlHeaderImpl::OnMouseMove(UINT nFlags, CPoint pt) { - const DWORD maskButtons = MK_LBUTTON | MK_RBUTTON | MK_MBUTTON | MK_XBUTTON1 | MK_XBUTTON2; - if (GetCellTypeSupported() && (nFlags & maskButtons) == 0 ) { - size_t item; size_t subItem; - if (this->GetItemAtPointAbsEx(pt + GetViewOffset(), item, subItem)) { - auto ct = this->GetCellType( item, subItem ); - if (CellTypeReactsToMouseOver(ct) ) { - auto rc = CellHotRect( item, subItem, ct ); - if ( PtInRect( rc, pt ) ) { - { - auto c = ct->HotCursor(); - if ( c != NULL ) SetCursor(c); - } - SetHotItem(item, subItem); - SetCaptureEx([=](UINT msg, DWORD newStatus, CPoint pt) { - if ((newStatus & maskButtons) != 0 || msg == WM_MOUSEWHEEL || msg == WM_MOUSEHWHEEL ) { - // A button has been pressed or wheel has been moved - this->ClearHotItem(); - SetCaptureMsgHandled(FALSE); - return false; - } - - if ( ! PtInRect( rc, pt ) ) { - // Left the rect - this->ClearHotItem(); - SetCaptureMsgHandled(FALSE); - return false; - } - - return true; - }); - } - } - } - } - SetMsgHandled(FALSE); -} - -bool CListControlHeaderImpl::AllowScrollbar(bool vertical) const { - if ( vertical ) { - // vertical - return true; - } else { - // horizontal - if (! IsHeaderEnabled( ) ) return false; // no header? - return true; - } -} - -void CListControlHeaderImpl::OnDestroy() { - m_colRuntime.clear(); - m_header = NULL; - m_headerLine = NULL; - SetMsgHandled(FALSE); -} - - -uint32_t CListControlHeaderImpl::GetColumnsBlankWidth( size_t colExclude ) const { - auto client = this->GetClientRectHook().Width(); - int item = GetItemWidth(); - if (colExclude) item -= GetSubItemWidth(colExclude); - if ( item < 0 ) item = 0; - if ( item < client ) return (uint32_t)( client - item ); - else return 0; -} - -void CListControlHeaderImpl::SizeColumnToContent( size_t which, uint32_t minWidth ) { - auto width = this->GetOptimalColumnWidth( which ); - if ( width < minWidth ) width = minWidth; - this->ResizeColumn( which, width ); -} - -void CListControlHeaderImpl::SizeColumnToContentFillBlank( size_t which ) { - this->SizeColumnToContent( which, this->GetColumnsBlankWidth(which) ); -} - -HBRUSH CListControlHeaderImpl::OnCtlColorStatic(CDCHandle dc, CStatic wndStatic) { - if ( wndStatic == m_headerLine ) { - COLORREF col = GridColor(); - dc.SetDCBrushColor( col ); - return (HBRUSH) GetStockObject(DC_BRUSH); - } - SetMsgHandled(FALSE); - return NULL; -} - -void CListControlHeaderImpl::ReloadData() { - __super::ReloadData(); - if ( this->HaveAutoWidthContentColumns( ) ) { - this->ColumnWidthFix(); - } -} diff --git a/libPPUI/CListControlHeaderImpl.h b/libPPUI/CListControlHeaderImpl.h deleted file mode 100644 index 3938a89..0000000 --- a/libPPUI/CListControlHeaderImpl.h +++ /dev/null @@ -1,224 +0,0 @@ -#pragma once - -class CListCell; - -class CListControlHeaderImpl : public CListControlFontOps { -private: - typedef CListControlFontOps TParent; -public: - CListControlHeaderImpl() {} - - BEGIN_MSG_MAP_EX(CListControlHeaderImpl) - MSG_WM_CTLCOLORSTATIC(OnCtlColorStatic); - MESSAGE_HANDLER(WM_KEYDOWN,OnKeyDown); - MESSAGE_HANDLER(WM_SYSKEYDOWN,OnKeyDown); - MESSAGE_HANDLER_EX(WM_SIZE,OnSizePassThru); - NOTIFY_CODE_HANDLER(HDN_ITEMCHANGED,OnHeaderItemChanged); - NOTIFY_CODE_HANDLER(HDN_ENDDRAG,OnHeaderEndDrag); - NOTIFY_CODE_HANDLER(HDN_ITEMCLICK,OnHeaderItemClick); - NOTIFY_CODE_HANDLER(HDN_DIVIDERDBLCLICK,OnDividerDoubleClick); - MSG_WM_SETCURSOR(OnSetCursor); - MSG_WM_MOUSEMOVE(OnMouseMove) - MSG_WM_DESTROY(OnDestroy) - MSG_WM_ENABLE(OnEnable) - CHAIN_MSG_MAP(TParent) - END_MSG_MAP() - - typedef uint32_t cellState_t; - typedef CListCell * cellType_t; - - int GetHeaderItemWidth( int which ); - void InitializeHeaderCtrl(DWORD flags = HDS_FULLDRAG); - void InitializeHeaderCtrlSortable() {InitializeHeaderCtrl(HDS_FULLDRAG | HDS_BUTTONS);} - CHeaderCtrl GetHeaderCtrl() const {return m_header;} - void SetSortIndicator( size_t whichColumn, bool isUp ); - void ClearSortIndicator(); - - bool IsHeaderEnabled() const {return m_header.m_hWnd != NULL;} - void ResetColumns(bool update = true); - - enum { - columnWidthMax = (uint32_t)INT32_MAX, - columnWidthAuto = UINT32_MAX, - columnWidthAutoUseContent = UINT32_MAX-1, - }; - void AddColumn(const char * label, uint32_t widthPixels, DWORD fmtFlags = HDF_LEFT,bool update = true); - //! Extended AddColumn, specifies width in pixels @ 96DPI instead of screen-specific pixels - void AddColumnEx( const char * label, uint32_t widthPixelsAt96DPI, DWORD fmtFlags = HDF_LEFT, bool update = true ); - //! Extended AddColumn, specifies width in Dialog Length Units (DLU), assumes parent of this list to be a dialog window. - void AddColumnDLU( const char * label, uint32_t widthDLU, DWORD fmtFlags = HDF_LEFT, bool update = true ); - //! Extended AddColumn, specifies width as floating-point value of pixels at 96DPI. \n - //! For DPI-safe storage of user's column widths. - void AddColumnF( const char * label, float widthF, DWORD fmtFlags = HDF_LEFT, bool update = true ); - void AddColumnAutoWidth( const char * label, DWORD fmtFlags = HDF_LEFT, bool bUpdate = true) { AddColumn(label, columnWidthAuto, fmtFlags, bUpdate); } - bool DeleteColumn(size_t index, bool updateView = true); - void DeleteColumns( pfc::bit_array const & mask, bool updateView = true); - void ResizeColumn(t_size index, t_uint32 widthPixels, bool updateView = true); - void SetColumn( size_t which, const char * title, DWORD fmtFlags = HDF_LEFT, bool updateView = true); - void GetColumnText(size_t which, pfc::string_base & out) const; - - uint32_t GetOptimalColumnWidth( size_t index ) const; - uint32_t GetOptimalColumnWidthFixed( const char * fixedText) const; - uint32_t GetColumnsBlankWidth( size_t colExclude = SIZE_MAX ) const; - void SizeColumnToContent( size_t which, uint32_t minWidth ); - void SizeColumnToContentFillBlank( size_t which ); - - //! If creating a custom headerless multi column scheme, override these to manipulate your columns - virtual size_t GetColumnCount() const; - virtual uint32_t GetSubItemWidth(size_t subItem) const; - //! Returns column width as a floating-point value of pixels at 96DPI. \n - //! For DPI-safe storage of user's column widths. - float GetColumnWidthF( size_t subItem ) const; - //! Indicate how many columns a specific row/column cell spans\n - //! This makes sense only if the columns can't be user-reordered - virtual size_t GetSubItemSpan(size_t row, size_t column) const; - - t_size GetSubItemOrder(t_size subItem) const; - int GetItemWidth() const override; -protected: - CRect GetClientRectHook() const override; - void RenderBackground(CDCHandle dc, CRect const& rc) override; - - struct GetOptimalWidth_Cache { - //! For temporary use. - pfc::string8_fastalloc m_stringTemp, m_stringTempUnfuckAmpersands; - //! For temporary use. - pfc::stringcvt::string_wide_from_utf8_t m_convertTemp; - //! Our DC for measuring text. Correct font pre-selected. - CDCHandle m_dc; - - t_uint32 GetStringTempWidth(); - }; - - void UpdateHeaderLayout(); - void OnViewOriginChange(CPoint p_delta); - void SetHeaderFont(HFONT font); - void RenderItemText(t_size item,const CRect & itemRect,const CRect & updateRect,CDCHandle dc, bool allowColors); - void RenderGroupHeaderText(int id,const CRect & headerRect,const CRect & updateRect,CDCHandle dc); - - //! Converts an item/subitem rect to a rect in which the text should be rendered, removing spacing to the left/right of the text. - virtual CRect GetItemTextRectHook(size_t item, size_t subItem, CRect const & itemRect) const; - CRect GetItemTextRect(CRect const & itemRect) const; - //! Override for custom spacing to the left/right of the text in each column. - virtual t_uint32 GetColumnSpacing() const {return MulDiv(4,m_dpi.cx,96);} - //! Override for column-header-click sorting. - virtual void OnColumnHeaderClick(t_size index) {} - //! Override to supply item labels. - virtual bool GetSubItemText(t_size item, t_size subItem, pfc::string_base & out) const {return false;} - //! Override if you support groups. - virtual bool GetGroupHeaderText(int id, pfc::string_base & out) const {return false;} - //! Override optionally. - virtual void RenderSubItemText(t_size item, t_size subItem,const CRect & subItemRect,const CRect & updateRect,CDCHandle dc, bool allowColors); - - virtual void OnColumnsChanged(); - - virtual t_uint32 GetOptimalSubItemWidth(t_size item, t_size subItem, GetOptimalWidth_Cache & cache) const; - - virtual t_uint32 GetOptimalGroupHeaderWidth(int which) const; - - - bool GetItemAtPointAbsEx( CPoint pt, size_t & outItem, size_t & outSubItem ) const; - cellType_t GetCellTypeAtPointAbs( CPoint pt ) const; - virtual cellType_t GetCellType( size_t item, size_t subItem ) const; - virtual bool AllowTypeFindInCell( size_t item, size_t subItem ) const; - virtual bool GetCellTypeSupported() const { return false; } // optimization hint, some expensive checks can be suppressed if cell types are not used for this view - virtual bool GetCellCheckState( size_t item, size_t subItem ) const { return false; } - virtual void SetCellCheckState(size_t item, size_t subItem, bool value); - virtual bool ToggleSelectedItemsHook(const pfc::bit_array & mask); - - void RenderSubItemTextInternal(size_t subItem, const CRect & subItemRect, CDCHandle dc, const char * text, bool allowColors); - - t_uint32 GetOptimalColumnWidth(t_size which, GetOptimalWidth_Cache & cache) const; - t_uint32 GetOptimalSubItemWidthSimple(t_size item, t_size subItem) const; - - void AutoColumnWidths(const pfc::bit_array & mask,bool expandLast = false); - void AutoColumnWidths() {AutoColumnWidths(pfc::bit_array_true());} - void AutoColumnWidth(t_size which) {AutoColumnWidths(pfc::bit_array_one(which));} - - virtual bool OnColumnHeaderDrag(t_size index, t_size newOrder); - - void OnItemClicked(t_size item, CPoint pt) override; - virtual void OnSubItemClicked(t_size item, t_size subItem,CPoint pt); - bool OnClickedSpecialHitTest(CPoint pt) override; - bool OnClickedSpecial(DWORD status, CPoint pt) override; - static bool CellTypeUsesSpecialHitTests( cellType_t ct ); - - - CRect GetSubItemRectAbs(t_size item,t_size subItem) const; - CRect GetSubItemRect(t_size item,t_size subItem) const; - - t_size SubItemFromPointAbs(CPoint pt) const; - - static bool CellTypeReactsToMouseOver( cellType_t ct ); - virtual CRect CellHotRect( size_t item, size_t subItem, cellType_t ct, CRect rcCell ); - CRect CellHotRect( size_t item, size_t subItem, cellType_t ct ); - virtual double CellTextScale(size_t item, size_t subItem) { return 1; } - virtual bool IsSubItemGrayed(size_t item, size_t subItem) { return !this->IsWindowEnabled(); } - - // HDF_* constants for this column, override when not using list header control. Used to control text alignment. - virtual DWORD GetColumnFormat(t_size which) const; - void SetColumnFormat(t_size which,DWORD format); - void SetColumnSort(t_size which, bool isUp); - - std::vector GetColumnOrderArray() const; - - bool AllowScrollbar(bool vertical) const override; - - void RenderItemBackground(CDCHandle p_dc,const CRect & p_itemRect,size_t item, uint32_t bkColor) override; - - void ColumnWidthFix(); // Call RecalcItemWidth() / ProcessAutoWidth() - - void ReloadData() override; -private: - void OnEnable(BOOL) { Invalidate(); } - HBRUSH OnCtlColorStatic(CDCHandle dc, CStatic wndStatic); - void ProcessColumnsChange() { OnColumnsChanged();} - LRESULT OnSizePassThru(UINT,WPARAM,LPARAM); - LRESULT OnHeaderItemClick(int,LPNMHDR,BOOL&); - LRESULT OnDividerDoubleClick(int,LPNMHDR,BOOL&); - LRESULT OnHeaderItemChanged(int,LPNMHDR,BOOL&); - LRESULT OnHeaderEndDrag(int,LPNMHDR,BOOL&); - LRESULT OnKeyDown(UINT,WPARAM,LPARAM,BOOL&); - void OnDestroy(); - BOOL OnSetCursor(CWindow wnd, UINT nHitTest, UINT message); - void OnMouseMove(UINT nFlags, CPoint point); - - void RecalcItemWidth(); // FIXED width math - void ProcessAutoWidth(); // DYNAMIC width math - - bool m_ownColumnsChange = false; - - int m_itemWidth = 0; - int m_clientWidth = 0; - CHeaderCtrl m_header; - CStatic m_headerLine; - - bool HaveAutoWidthColumns() const; - bool HaveAutoWidthContentColumns() const; - - struct colRuntime_t { - bool m_autoWidth = false; - bool m_autoWidthContent = false; - int m_widthPixels = 0; - uint32_t m_userWidth = 0; - std::string m_text; - - bool autoWidth() const { return m_userWidth > columnWidthMax; } - bool autoWidthContent() const { return m_userWidth == columnWidthAutoUseContent; } - bool autoWidthPlain() const { return m_userWidth == columnWidthAuto; } - }; - - std::vector m_colRuntime; - - - //for group headers - GdiplusScope m_gdiPlusScope; - - void SetPressedItem(size_t row, size_t column); - void ClearPressedItem() {SetPressedItem(SIZE_MAX, SIZE_MAX);} - void SetHotItem( size_t row, size_t column ); - void ClearHotItem() { SetHotItem(SIZE_MAX, SIZE_MAX); } - - size_t m_pressedItem = SIZE_MAX, m_pressedSubItem = SIZE_MAX; - size_t m_hotItem = SIZE_MAX, m_hotSubItem = SIZE_MAX; -}; diff --git a/libPPUI/CListControlOwnerData.h b/libPPUI/CListControlOwnerData.h deleted file mode 100644 index ad3ded9..0000000 --- a/libPPUI/CListControlOwnerData.h +++ /dev/null @@ -1,206 +0,0 @@ -#pragma once - -// ================================================================================ -// CListControlOwnerData -// ================================================================================ -// Forwards all list data retrieval and manipulation calls to a host object. -// Not intended for subclassing, just implement IListControlOwnerDataSource methods -// in your class. -// ================================================================================ - -#include "CListControlComplete.h" - -class CListControlOwnerData; - -class IListControlOwnerDataSource { -public: - typedef const CListControlOwnerData * ctx_t; - - - virtual size_t listGetItemCount( ctx_t ) = 0; - virtual pfc::string8 listGetSubItemText( ctx_t, size_t item, size_t subItem ) = 0; - virtual bool listCanReorderItems( ctx_t ) { return false; } - virtual bool listReorderItems( ctx_t, const size_t*, size_t) {return false;} - virtual bool listRemoveItems( ctx_t, pfc::bit_array const & ) {return false;} - virtual void listItemAction(ctx_t, size_t) {} - virtual void listSubItemClicked( ctx_t, size_t, size_t ) {} - virtual bool listCanSelectItem( ctx_t, size_t ) { return true; } - virtual pfc::string8 listGetEditField(ctx_t ctx, size_t item, size_t subItem, size_t & lineCount) { - lineCount = 1; return listGetSubItemText( ctx, item, subItem); - } - virtual void listSetEditField(ctx_t ctx, size_t item, size_t subItem, const char * val) {} - virtual uint32_t listGetEditFlags(ctx_t ctx, size_t item, size_t subItem) {return 0;} - typedef InPlaceEdit::CTableEditHelperV2::autoComplete_t autoComplete_t; - typedef InPlaceEdit::CTableEditHelperV2::combo_t combo_t; - virtual autoComplete_t listGetAutoComplete(ctx_t, size_t item, size_t subItem) {return autoComplete_t();} - virtual combo_t listGetCombo(ctx_t, size_t item, size_t subItem) { return combo_t(); } - - virtual bool listIsColumnEditable( ctx_t, size_t ) { return false; } - virtual bool listKeyDown(ctx_t, UINT nChar, UINT nRepCnt, UINT nFlags) { return false; } - virtual bool listKeyUp(ctx_t, UINT nChar, UINT nRepCnt, UINT nFlags) { return false; } - - // Allow type-find in this view? - // Called prior to a typefind pass attempt, you can either deny entirely, or prepare any necessary data and allow it. - virtual bool listAllowTypeFind( ctx_t ) { return true; } - // Allow type-find in a specific item/column? - virtual bool listAllowTypeFindHere( ctx_t, size_t item, size_t subItem ) { return true ;} - - virtual void listColumnHeaderClick(ctx_t, size_t subItem) {} - - virtual void listBeforeDrawItemText( ctx_t, size_t item, CDCHandle dc ) {} - virtual bool listIsSubItemGrayed(ctx_t, size_t item, size_t subItem) { return false; } - - virtual void listSelChanged(ctx_t) {} - virtual void listFocusChanged(ctx_t) {} - - virtual void listColumnsChanged(ctx_t) {} - - virtual bool listEditCanAdvanceHere(ctx_t, size_t item, size_t subItem, uint32_t whatHappened) {(void) item; (void) subItem, (void) whatHappened; return true;} -}; - -class IListControlOwnerDataCells { -public: - typedef const CListControlOwnerData * cellsCtx_t; - virtual CListControl::cellType_t listCellType( cellsCtx_t, size_t item, size_t subItem ) = 0; - virtual size_t listCellSpan( cellsCtx_t, size_t item, size_t subItem ) {return 1;} - virtual bool listCellCheckState( cellsCtx_t, size_t item, size_t subItem ) {return false; } - virtual void listCellSetCheckState( cellsCtx_t, size_t item, size_t subItem, bool state ) {} -}; - -class CListControlOwnerData : public CListControlComplete { - IListControlOwnerDataSource * const m_host; -public: - - CListControlOwnerData( IListControlOwnerDataSource * h) : m_host(h) {} - - BEGIN_MSG_MAP_EX(CListControlOwnerData) - MSG_WM_KEYDOWN(OnKeyDown) - MSG_WM_KEYUP(OnKeyUp) - MSG_WM_SYSKEYDOWN(OnKeyDown) - MSG_WM_SYSKEYUP(OnKeyUp) - CHAIN_MSG_MAP(CListControlComplete) - END_MSG_MAP() - - using CListControl_EditImpl::TableEdit_Abort; - using CListControl_EditImpl::TableEdit_Start; - using CListControl_EditImpl::TableEdit_IsActive; - - bool CanSelectItem( size_t idx ) const override { - return m_host->listCanSelectItem( this, idx ); - } - size_t GetItemCount() const override { - return m_host->listGetItemCount( this ); - } - bool GetSubItemText(size_t item, size_t subItem, pfc::string_base & out) const override { - out = m_host->listGetSubItemText( this, item, subItem ); - return true; - } - void OnSubItemClicked( size_t item, size_t subItem, CPoint pt ) override { - __super::OnSubItemClicked(item, subItem, pt); // needed to toggle checkboxes etc - m_host->listSubItemClicked( this, item, subItem ); - } - - uint32_t QueryDragDropTypes() const override { - return (m_host->listCanReorderItems(this)) ? dragDrop_reorder : 0; - } - - void RequestReorder( const size_t * order, size_t count) override { - if ( ! m_host->listReorderItems( this, order, count )) return; - this->OnItemsReordered( order, count ); - } - void RequestRemoveSelection() override { - auto mask = this->GetSelectionMask(); - size_t oldCount = GetItemCount(); - if ( ! m_host->listRemoveItems( this, mask ) ) return; - this->OnItemsRemoved( mask, oldCount ); - } - void ExecuteDefaultAction( size_t idx ) override { - m_host->listItemAction( this, idx ); - } - size_t EvalTypeFind() override { - if (! m_host->listAllowTypeFind(this) ) return SIZE_MAX; - return __super::EvalTypeFind(); - } - bool AllowTypeFindInCell( size_t item, size_t subItem ) const { - return __super::AllowTypeFindInCell( item, subItem ) && m_host->listAllowTypeFindHere( this, item, subItem ); - } - -protected: - void OnFocusChanged(size_t newFocus) override { - __super::OnFocusChanged(newFocus); - m_host->listFocusChanged(this); - } - void OnSelectionChanged(pfc::bit_array const & affected, pfc::bit_array const & status) { - __super::OnSelectionChanged(affected, status); - m_host->listSelChanged(this); - } - - void RenderItemText(t_size p_item,const CRect & p_itemRect,const CRect & p_updateRect,CDCHandle p_dc, bool allowColors) { - m_host->listBeforeDrawItemText(this, p_item, p_dc ); - __super::RenderItemText(p_item, p_itemRect, p_updateRect, p_dc, allowColors); - } - void TableEdit_SetField(t_size item, t_size subItem, const char * value) override { - m_host->listSetEditField(this, item, subItem, value); - } - void TableEdit_GetField(t_size item, t_size subItem, pfc::string_base & out, t_size & lineCount) override { - lineCount = 1; - out = m_host->listGetEditField(this, item, subItem, lineCount); - } - - t_uint32 TableEdit_GetEditFlags(t_size item, t_size subItem) const override { - return m_host->listGetEditFlags( this, item, subItem ); - } - - combo_t TableEdit_GetCombo(size_t item, size_t subItem) override { - return m_host->listGetCombo(this, item, subItem); - } - autoComplete_t TableEdit_GetAutoCompleteEx(t_size item, t_size subItem) override { - return m_host->listGetAutoComplete( this, item, subItem ); - } - bool TableEdit_IsColumnEditable(t_size subItem) const override { - return m_host->listIsColumnEditable( this, subItem ); - } - void OnColumnHeaderClick(t_size index) override { - m_host->listColumnHeaderClick(this, index); - } - void OnColumnsChanged() override { - __super::OnColumnsChanged(); - m_host->listColumnsChanged(this); - } - bool IsSubItemGrayed(size_t item, size_t subItem) override { - return __super::IsSubItemGrayed(item, subItem) || m_host->listIsSubItemGrayed(this, item, subItem); - } -private: - bool TableEdit_CanAdvanceHere( size_t item, size_t subItem, uint32_t whatHappened ) const override { - return m_host->listEditCanAdvanceHere(this, item, subItem, whatHappened); - } - void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { - bool handled = m_host->listKeyDown(this, nChar, nRepCnt, nFlags); - SetMsgHandled( !! handled ); - } - void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) { - bool handled = m_host->listKeyUp(this, nChar, nRepCnt, nFlags); - SetMsgHandled( !! handled ); - } -}; - -class CListControlOwnerDataCells : public CListControlOwnerData { - IListControlOwnerDataCells * const m_cells; -public: - CListControlOwnerDataCells( IListControlOwnerDataSource * source, IListControlOwnerDataCells * cells ) : CListControlOwnerData(source), m_cells(cells) {} - - bool GetCellTypeSupported() const override {return true; } - bool GetCellCheckState( size_t item, size_t subItem ) const override { - return m_cells->listCellCheckState( this, item, subItem ); - } - void SetCellCheckState( size_t item, size_t subItem, bool value ) override { - m_cells->listCellSetCheckState( this, item, subItem, value ); - __super::SetCellCheckState(item, subItem, value); - } - cellType_t GetCellType( size_t item, size_t subItem ) const override { - return m_cells->listCellType( this, item, subItem ); - } - size_t GetSubItemSpan(size_t row, size_t column) const override { - return m_cells->listCellSpan( this, row, column ); - } -}; \ No newline at end of file diff --git a/libPPUI/CListControlSimple.h b/libPPUI/CListControlSimple.h deleted file mode 100644 index 4d42336..0000000 --- a/libPPUI/CListControlSimple.h +++ /dev/null @@ -1,137 +0,0 @@ -#pragma once - -// ================================================================================ -// CListControlSimple -// Simplified CListControl interface; a ready-to-use class that can be instantiated -// without subclassing. -// Use when you don't need advanced features such as buttons or editing. -// Maintains its own data. -// ================================================================================ - -#include "CListControlComplete.h" - -#include -#include -#include -#include - - -class CListControlSimple : public CListControlReadOnly { -public: - // Events - std::function onReordered; // if not set, list reordering is disabled - std::function onRemoved; // if not set, list item removal is disabled - std::function onItemAction; - std::function onSelChange; - - size_t GetItemCount() const override { - return m_lines.size(); - } - void SetItemCount( size_t count ) { - m_lines.resize( count ); - ReloadData(); - } - void SetItemText(size_t item, size_t subItem, const char * text, bool bRedraw = true) { - if ( item < m_lines.size() ) { - m_lines[item].text[subItem] = text; - if ( bRedraw ) ReloadItem( item ); - } - } - bool GetSubItemText(size_t item, size_t subItem, pfc::string_base & out) const override { - if ( item < m_lines.size() ) { - auto & l = m_lines[item].text; - auto iter = l.find( subItem ); - if ( iter != l.end() ) { - out = iter->second.c_str(); - return true; - } - } - return false; - } - - uint32_t QueryDragDropTypes() const override { - return (onReordered != nullptr) ? dragDrop_reorder : 0; - } - - void RequestReorder( const size_t * order, size_t count) override { - if ( onReordered == nullptr ) return; - pfc::reorder_t( m_lines, order, count ); - this->OnItemsReordered( order, count ); - onReordered(); - } - void RequestRemoveSelection() override { - if (onRemoved == nullptr) return; - auto mask = this->GetSelectionMask(); - size_t oldCount = m_lines.size(); - pfc::remove_mask_t( m_lines, mask ); - this->OnItemsRemoved( mask, oldCount ); - onRemoved(); - } - void ExecuteDefaultAction( size_t idx ) override { - if (onItemAction != nullptr) onItemAction(idx); - } - - void SetItemUserData( size_t item, size_t user ) { - if ( item < m_lines.size() ) { - m_lines[item].user = user; - } - } - size_t GetItemUserData( size_t item ) const { - size_t ret = 0; - if ( item < m_lines.size() ) { - ret = m_lines[item].user; - } - return ret; - } - void RemoveAllItems() { - RemoveItems(pfc::bit_array_true()); - } - void RemoveItems( pfc::bit_array const & mask ) { - const auto oldCount = m_lines.size(); - pfc::remove_mask_t( m_lines, mask ); - this->OnItemsRemoved( mask, oldCount ); - } - void RemoveItem( size_t which ) { - RemoveItems( pfc::bit_array_one( which ) ); - } - - size_t InsertItem( size_t insertAt, const char * textCol0 = nullptr ) { - if ( insertAt > m_lines.size() ) { - insertAt = m_lines.size(); - } - { - line_t data; - if ( textCol0 != nullptr ) data.text[0] = textCol0; - m_lines.insert( m_lines.begin() + insertAt, std::move(data) ); - } - this->OnItemsInserted( insertAt, 1, false ); - return insertAt; - } - size_t AddItem( const char * textCol0 = nullptr ) { - return InsertItem( SIZE_MAX, textCol0 ); - } - size_t InsertItems( size_t insertAt, size_t count ) { - if ( insertAt > m_lines.size() ) { - insertAt = m_lines.size(); - } - - { - line_t val; - m_lines.insert( m_lines.begin(), count, val ); - } - - this->OnItemsInserted( insertAt, count, false ); - return insertAt; - } -protected: - void OnSelectionChanged(pfc::bit_array const & affected, pfc::bit_array const & status) { - __super::OnSelectionChanged(affected, status); - if ( onSelChange ) onSelChange(); - } -private: - struct line_t { - std::map text; - size_t user = 0; - }; - std::vector m_lines; -}; diff --git a/libPPUI/CListControlTruncationTooltipImpl.cpp b/libPPUI/CListControlTruncationTooltipImpl.cpp deleted file mode 100644 index 62727a4..0000000 --- a/libPPUI/CListControlTruncationTooltipImpl.cpp +++ /dev/null @@ -1,209 +0,0 @@ -#include "stdafx.h" -#include "CListControl.h" -#include "PaintUtils.h" - -LRESULT CListControlTruncationTooltipImpl::OnTTShow(int,LPNMHDR,BOOL&) { - SetTimer(KTooltipTimer,KTooltipTimerDelay); - return 0; -} -LRESULT CListControlTruncationTooltipImpl::OnTTPop(int,LPNMHDR,BOOL&) { - KillTimer(KTooltipTimer); - return 0; -} -LRESULT CListControlTruncationTooltipImpl::OnTTGetDispInfo(int,LPNMHDR p_hdr,BOOL&) { - LPNMTTDISPINFO info = (LPNMTTDISPINFO)p_hdr; - - info->lpszText = const_cast(this->m_tooltipText.get_ptr()); - info->hinst = 0; - info->uFlags = 0; - - return 0; -} - -LRESULT CListControlTruncationTooltipImpl::OnDestroyPassThru(UINT,WPARAM,LPARAM,BOOL& bHandled) { - if (m_tooltip.m_hWnd != NULL) m_tooltip.DestroyWindow(); - KillTimer(KTooltipTimer); - bHandled = FALSE; return 0; -} - -CListControlTruncationTooltipImpl::CListControlTruncationTooltipImpl() - : m_toolinfo() - , m_tooltipRect(0,0,0,0) -{ -} - - - -void CListControlTruncationTooltipImpl::TooltipRemove() { - m_tooltipRect = CRect(0,0,0,0); - if (m_tooltip.m_hWnd != NULL) { - m_tooltip.TrackActivate(&m_toolinfo,FALSE); - } -} - -void CListControlTruncationTooltipImpl::TooltipRemoveCheck() { - CPoint pt = GetCursorPos(); - if (ScreenToClient(&pt)) { - TooltipRemoveCheck( MAKELPARAM( pt.x, pt.y ) ); - } -} -void CListControlTruncationTooltipImpl::TooltipRemoveCheck(LPARAM pos) { - if (!m_tooltipRect.IsRectEmpty()) { - CPoint pt(pos); - if (!GetClientRectHook().PtInRect(pt)) { - TooltipRemove(); - } else { - ClientToScreen(&pt); - if (!m_tooltipRect.PtInRect(pt)) { - TooltipRemove(); - } - } - } -} - -LRESULT CListControlTruncationTooltipImpl::OnTimer(UINT,WPARAM wp,LPARAM,BOOL& bHandled) { - switch(wp) { - case KTooltipTimer: - TooltipRemoveCheck(); - return 0; - default: - bHandled = FALSE; - return 0; - } -} - -LRESULT CListControlTruncationTooltipImpl::OnMouseMovePassThru(UINT,WPARAM,LPARAM lp,BOOL& bHandled) { - TooltipRemoveCheck(lp); - { - TRACKMOUSEEVENT ev = {sizeof(ev)}; - ev.dwFlags = TME_HOVER; - ev.hwndTrack = *this; - ev.dwHoverTime = HOVER_DEFAULT; - TrackMouseEvent(&ev); - } - bHandled = FALSE; - return 0; -} - - -bool CListControlTruncationTooltipImpl::IsRectPartiallyObscuredAbs(CRect const & r) const { - CRect cl = this->GetClientRectHook(); cl.OffsetRect( this->GetViewOffset() ); - return r.right > cl.right || r.top < cl.top || r.bottom > cl.bottom; -} - -bool CListControlTruncationTooltipImpl::IsRectFullyVisibleAbs(CRect const & r) { - CRect cl = this->GetClientRectHook(); cl.OffsetRect( this->GetViewOffset() ); - return r.left >= cl.left && r.right <= cl.right && r.top >= cl.top && r.bottom <= cl.bottom; -} - -bool CListControlTruncationTooltipImpl::GetTooltipData(CPoint pt, pfc::string_base & outText, CRect & outRC, CFontHandle & outFont) const { - t_size item; int group; - if (ItemFromPointAbs(pt, item)) { - const CRect itemRectAbs = this->GetItemRectAbs(item); - /*if (this->IsHeaderEnabled()) */{ - t_uint32 cbase = 0; - auto orderArray = this->GetColumnOrderArray(); - for (t_size _cwalk = 0; _cwalk < orderArray.size(); ++_cwalk) { - const t_size cwalk = orderArray[_cwalk]; - //const TColumnRuntime & col = m_columns[cwalk]; - - const t_uint32 width = GetSubItemWidth(cwalk); - if ((t_uint32)pt.x < cbase + width) { - t_uint32 estWidth = GetOptimalSubItemWidthSimple(item, cwalk); - CRect rc = itemRectAbs; rc.left = cbase; rc.right = cbase + estWidth; - if (estWidth > width || (IsRectPartiallyObscuredAbs(rc) && rc.PtInRect(pt))) { - pfc::string_formatter label, ccTemp; - if (GetSubItemText(item, cwalk, label)) { - PaintUtils::TextOutColors_StripCodes(ccTemp, label); - outFont = GetFont(); outRC = rc; outText = ccTemp; - return true; - } - } - break; - } - cbase += width; - } - } - } else if (GroupHeaderFromPointAbs(pt, group)) { - CRect rc; - if (GetGroupHeaderRectAbs(group, rc) && rc.PtInRect(pt)) { - const t_uint32 estWidth = GetOptimalGroupHeaderWidth(group); - CRect rcText = rc; rcText.right = rcText.left + estWidth; - if (estWidth > (t_uint32)rc.Width() || (IsRectPartiallyObscuredAbs(rcText) && rcText.PtInRect(pt))) { - pfc::string_formatter label; - if (GetGroupHeaderText(group, label)) { - outFont = GetGroupHeaderFont(); outRC = rc; outText = label; - return true; - } - } - } - } - return false; -} -LRESULT CListControlTruncationTooltipImpl::OnHover(UINT,WPARAM wp,LPARAM lp,BOOL&) { - if (!m_tooltipRect.IsRectEmpty()) { - return 0; - } - if (wp & (MK_LBUTTON | MK_RBUTTON | MK_MBUTTON)) return 0; - const CPoint viewOffset = GetViewOffset(); - CPoint pt ( lp ); pt += viewOffset; - - CFontHandle font; - CRect rc; - pfc::string8 text; - if ( this->GetTooltipData(pt, text, rc, font) ) { - this->m_tooltipFont = font; - // Gets stuck if the text is very long! - if (text.length() < 4096) { - TooltipActivateAbs(text, rc); - } - } - return 0; -} - -void CListControlTruncationTooltipImpl::TooltipActivateAbs(const char * label, const CRect & rect) { - CRect temp(rect); - temp.OffsetRect( - GetViewOffset() ); - ClientToScreen(temp); - TooltipActivate(label,temp); -} -void CListControlTruncationTooltipImpl::TooltipActivate(const char * label, const CRect & rect) { - if (rect.IsRectEmpty()) return; - if (m_tooltip.m_hWnd == NULL) { - try { - InitTooltip(); - } catch(std::exception const & e) { - (void) e; - // console::complain("Tooltip initialization failure", e); - return; - } - } - - m_tooltipText.convert( EscapeTooltipText( label ) ); - - m_tooltipRect = rect; - - TooltipUpdateFont(); - m_tooltip.TrackPosition(rect.left,rect.top); - m_tooltip.TrackActivate(&m_toolinfo,TRUE); -} - -void CListControlTruncationTooltipImpl::TooltipUpdateFont() { - if (m_tooltip.m_hWnd != NULL) { - if (m_tooltipFont) { - m_tooltip.SetFont(m_tooltipFont); - } - } -} - -void CListControlTruncationTooltipImpl::InitTooltip() { - m_tooltipRect = CRect(0,0,0,0); - WIN32_OP( m_tooltip.Create(NULL,NULL,NULL,WS_POPUP,WS_EX_TRANSPARENT) ); - m_toolinfo.cbSize = sizeof(m_toolinfo); - m_toolinfo.uFlags = TTF_TRACK | TTF_IDISHWND | TTF_ABSOLUTE | TTF_TRANSPARENT; - m_toolinfo.hwnd = *this; - m_toolinfo.uId = 0; - m_toolinfo.lpszText = LPSTR_TEXTCALLBACK; - m_toolinfo.hinst = GetThisModuleHandle(); - WIN32_OP_D( m_tooltip.AddTool(&m_toolinfo) ); -} diff --git a/libPPUI/CListControlTruncationTooltipImpl.h b/libPPUI/CListControlTruncationTooltipImpl.h deleted file mode 100644 index b55d2f4..0000000 --- a/libPPUI/CListControlTruncationTooltipImpl.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -class CListControlTruncationTooltipImpl : public CListControlHeaderImpl { -private: - typedef CListControlHeaderImpl TParent; -public: - CListControlTruncationTooltipImpl(); - - BEGIN_MSG_MAP_EX(CListControlTruncationTooltipImpl) - MESSAGE_HANDLER(WM_MOUSEHOVER,OnHover); - MESSAGE_HANDLER(WM_MOUSEMOVE,OnMouseMovePassThru); - MESSAGE_HANDLER(WM_TIMER,OnTimer); - MESSAGE_HANDLER(WM_DESTROY,OnDestroyPassThru); - CHAIN_MSG_MAP(TParent) - NOTIFY_CODE_HANDLER(TTN_GETDISPINFO,OnTTGetDispInfo); - NOTIFY_CODE_HANDLER(TTN_POP,OnTTPop); - NOTIFY_CODE_HANDLER(TTN_SHOW,OnTTShow); - END_MSG_MAP() - - void OnViewOriginChange(CPoint p_delta) {TParent::OnViewOriginChange(p_delta);TooltipRemove();} - void TooltipRemove(); -protected: - virtual bool GetTooltipData( CPoint ptAbs, pfc::string_base & text, CRect & rc, CFontHandle & font) const; -private: - enum { - KTooltipTimer = 0x51dbee9e, - KTooltipTimerDelay = 50, - }; - LRESULT OnHover(UINT,WPARAM,LPARAM,BOOL&); - LRESULT OnMouseMovePassThru(UINT,WPARAM,LPARAM,BOOL&); - LRESULT OnTimer(UINT,WPARAM,LPARAM,BOOL&); - LRESULT OnTTGetDispInfo(int,LPNMHDR,BOOL&); - LRESULT OnTTShow(int,LPNMHDR,BOOL&); - LRESULT OnTTPop(int,LPNMHDR,BOOL&); - LRESULT OnDestroyPassThru(UINT,WPARAM,LPARAM,BOOL&); - - void InitTooltip(); - void TooltipActivateAbs(const char * label, const CRect & rect); - void TooltipActivate(const char * label, const CRect & rect); - void TooltipRemoveCheck(LPARAM pos); - void TooltipRemoveCheck(); - void TooltipUpdateFont(); - void OnSetFont(bool) {TooltipUpdateFont();} - bool IsRectFullyVisibleAbs(CRect const & r); - bool IsRectPartiallyObscuredAbs(CRect const & r) const; - CRect m_tooltipRect; - CToolTipCtrl m_tooltip; - TOOLINFO m_toolinfo; - pfc::stringcvt::string_os_from_utf8 m_tooltipText; - CFontHandle m_tooltipFont; -}; diff --git a/libPPUI/CListControlUserOptions.h b/libPPUI/CListControlUserOptions.h deleted file mode 100644 index 1e07db5..0000000 --- a/libPPUI/CListControlUserOptions.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -class CListControlUserOptions { -public: - CListControlUserOptions() { instance = this; } - virtual bool useSmoothScroll() = 0; - - static CListControlUserOptions * instance; -}; \ No newline at end of file diff --git a/libPPUI/CListControlWithSelection.cpp b/libPPUI/CListControlWithSelection.cpp deleted file mode 100644 index 3a2ec31..0000000 --- a/libPPUI/CListControlWithSelection.cpp +++ /dev/null @@ -1,1587 +0,0 @@ -#include "stdafx.h" -#include -#include -#include "ppresources.h" -#include "CListControlWithSelection.h" -#include "PaintUtils.h" -#include "IDataObjectUtils.h" -#include "SmartStrStr.h" -#include "CListControl-Cells.h" - -namespace { - class bit_array_selection_CListControl : public pfc::bit_array { - public: - bit_array_selection_CListControl(CListControlWithSelectionBase const & list) : m_list(list) {} - bool get(t_size n) const {return m_list.IsItemSelected(n);} - private: - CListControlWithSelectionBase const & m_list; - }; -} - -bool CListControlWithSelectionBase::SelectAll() { - SetSelection(pfc::bit_array_true(), pfc::bit_array_true() ); - return true; -} -void CListControlWithSelectionBase::SelectNone() { - SetSelection(pfc::bit_array_true(), pfc::bit_array_false() ); -} - -void CListControlWithSelectionBase::SelectSingle(size_t which) { - this->SetFocusItem( which ); - SetSelection(pfc::bit_array_true(), pfc::bit_array_one( which ) ); -} - -LRESULT CListControlWithSelectionBase::OnFocus(UINT msg,WPARAM,LPARAM,BOOL& bHandled) { - UpdateItems(pfc::bit_array_or(bit_array_selection_CListControl(*this), pfc::bit_array_one(GetFocusItem()))); - bHandled = FALSE; - return 0; -} - -void CListControlWithSelectionBase::OnKeyDown_SetIndexDeltaPageHelper(int p_delta, int p_keys) { - const CRect rcClient = GetClientRectHook(); - int itemHeight = GetItemHeight(); - if (itemHeight > 0) { - int delta = rcClient.Height() / itemHeight; - if (delta < 1) delta = 1; - OnKeyDown_SetIndexDeltaHelper(delta * p_delta,p_keys); - } -} - -void CListControlWithSelectionBase::OnKeyDown_HomeEndHelper(bool isEnd, int p_keys) { - if (!isEnd) { - //SPECIAL FIX - ensure first group header visibility. - MoveViewOrigin(CPoint(GetViewOrigin().x,0)); - } - - const t_size itemCount = GetItemCount(); - if (itemCount == 0) return;//don't bother - - if ((p_keys & (MK_SHIFT|MK_CONTROL)) == (MK_SHIFT|MK_CONTROL)) { - RequestMoveSelection( isEnd ? (int)itemCount : -(int)itemCount ); - } else { - OnKeyDown_SetIndexHelper(isEnd ? (int)(itemCount-1) : 0,p_keys); - } -} -void CListControlWithSelectionBase::OnKeyDown_SetIndexHelper(int p_index, int p_keys) { - const t_size count = GetItemCount(); - if (count > 0) { - t_size idx = (t_size)pfc::clip_t(p_index,0,(int)(count - 1)); - const t_size oldFocus = GetFocusItem(); - if (p_keys & MK_CONTROL) { - SetFocusItem(idx); - } else if ((p_keys & MK_SHIFT) != 0 && this->AllowRangeSelect() ) { - t_size selStart = GetSelectionStart(); - if (selStart == pfc_infinite) selStart = oldFocus; - if (selStart == pfc_infinite) selStart = idx; - t_size selFirst, selCount; - selFirst = pfc::min_t(selStart,idx); - selCount = pfc::max_t(selStart,idx) + 1 - selFirst; - SetSelection(pfc::bit_array_true(), pfc::bit_array_range(selFirst,selCount)); - SetFocusItem(idx); - SetSelectionStart(selStart); - } else { - SetFocusItem(idx); - SetSelection(pfc::bit_array_true(), pfc::bit_array_one(idx)); - } - } -} - -void CListControlWithSelectionBase::SelectGroupHelper(int p_group,int p_keys) { - t_size base, count; - if (ResolveGroupRange(p_group,base,count)) { - if (p_keys & MK_CONTROL) { - SetGroupFocusByItem(base); - } /*else if (p_keys & MK_SHIFT) { - } */else { - SetGroupFocusByItem(base); - SetSelection(pfc::bit_array_true(), pfc::bit_array_range(base,count)); - } - } -} - -void CListControlWithSelectionBase::OnKeyDown_SetIndexDeltaLineHelper(int p_delta, int p_keys) { - if ((p_keys & (MK_SHIFT | MK_CONTROL)) == (MK_SHIFT|MK_CONTROL)) { - this->RequestMoveSelection(p_delta); - return; - } - const t_size total = GetItemCount(); - t_size current = GetFocusItem(); - const int focusGroup = this->GetGroupFocus(); - if (focusGroup >= 0) { - t_size dummy; - if (!ResolveGroupRange(focusGroup,current,dummy)) current = pfc_infinite; - } - - if (current == pfc_infinite) { - OnKeyDown_SetIndexDeltaHelper(p_delta,p_keys); - return; - } - - const int currentGroup = GetItemGroup(current); - if (GroupFocusActive()) { - if (p_delta < 0) { - int targetGroup = currentGroup - 1; - t_size base, count; - if (ResolveGroupRange(targetGroup, base, count)) { - OnKeyDown_SetIndexHelper((int)(base + count - 1), p_keys); - } - } else if (p_delta > 0) { - t_size base, count; - if (ResolveGroupRange(currentGroup,base,count)) { - OnKeyDown_SetIndexHelper((int) base, p_keys); - } - } - } else { - if ((p_keys & MK_SHIFT) != 0) { - OnKeyDown_SetIndexDeltaHelper(p_delta,p_keys); - } else if (p_delta < 0) { - if (currentGroup == 0 || (current > 0 && currentGroup == GetItemGroup(current - 1))) { - OnKeyDown_SetIndexDeltaHelper(p_delta,p_keys); - } else { - SelectGroupHelper(currentGroup, p_keys); - } - } else if (p_delta > 0) { - if (current + 1 >= total || currentGroup == GetItemGroup(current + 1)) { - OnKeyDown_SetIndexDeltaHelper(p_delta,p_keys); - } else { - SelectGroupHelper(GetItemGroup(current + 1), p_keys); - } - } - } -} - -LRESULT CListControlWithSelectionBase::OnLButtonDblClk(UINT,WPARAM p_wp,LPARAM p_lp,BOOL& bHandled) { - CPoint pt(p_lp); - if (OnClickedSpecialHitTest(pt)) { - return OnButtonDown(WM_LBUTTONDOWN, p_wp, p_lp, bHandled); - } - t_size item; int groupId; - if (ItemFromPoint(pt,item)) { - ExecuteDefaultAction(item); - return 0; - } else if (GroupHeaderFromPoint(pt,groupId)) { - t_size count; - if (ResolveGroupRange(groupId,item,count)) { - ExecuteDefaultActionGroup(item,count); - } - return 0; - } else if (ExecuteCanvasDefaultAction(pt)) { - return 0; - } else { - return OnButtonDown(WM_LBUTTONDOWN,p_wp,p_lp,bHandled); - } -} -void CListControlWithSelectionBase::ExecuteDefaultActionByFocus() { - const int groupId = this->GetGroupFocus(); - if (groupId >= 0) { - t_size item,count; - if (ResolveGroupRange(groupId,item,count)) { - ExecuteDefaultActionGroup(item,count); - } - } else { - t_size index = this->GetFocusItem(); - if (index != ~0) this->ExecuteDefaultAction(index); - } -} - -t_size CListControlWithSelectionBase::GetSingleSel() const { - t_size total = GetItemCount(); - t_size first = ~0; - for(t_size walk = 0; walk < total; ++walk) { - if (IsItemSelected(walk)) { - if (first == ~0) first = walk; - else return ~0; - } - } - return first; -} - -t_size CListControlWithSelectionBase::GetSelectedCount(pfc::bit_array const & mask,t_size max) const { - const t_size itemCount = this->GetItemCount(); - t_size found = 0; - for(t_size walk = mask.find_first(true,0,itemCount); walk < itemCount && found < max; walk = mask.find_next(true,walk,itemCount)) { - if (IsItemSelected(walk)) ++found; - } - return found; -} -LRESULT CListControlWithSelectionBase::OnButtonDown(UINT p_msg,WPARAM p_wp,LPARAM p_lp,BOOL&) { - pfc::vartoggle_t l_noEnsureVisible(m_noEnsureVisible,true); - if (m_selectDragMode) { - AbortSelectDragMode(); - return 0; - } - - CPoint pt(p_lp); - - if (OnClickedSpecial( (DWORD) p_wp, pt)) { - return 0; - } - - - int groupId; t_size item; - const bool isRightClick = (p_msg == WM_RBUTTONDOWN || p_msg == WM_RBUTTONDBLCLK); - const bool gotCtrl = (p_wp & MK_CONTROL) != 0 && !isRightClick; - const bool gotShift = (p_wp & MK_SHIFT) != 0 && !isRightClick; - - - - const bool bCanSelect = !OnClickedSpecialHitTest( pt ); - - const bool instaDrag = false; - const bool ddSupported = IsDragDropSupported(); - - if (GroupHeaderFromPoint(pt,groupId)) { - t_size base,count; - if (AllowRangeSelect() && ResolveGroupRange(groupId,base,count)) { - SetGroupFocusByItem(base); - pfc::bit_array_range groupRange(base,count); - bool instaDragOverride = false; - if (gotCtrl) { - ToggleRangeSelection(groupRange); - } else if (gotShift) { - SetSelection(groupRange, pfc::bit_array_true()); - } else { - if (GetSelectedCount(groupRange) == count) instaDragOverride = true; - else SetSelection(pfc::bit_array_true(),groupRange); - } - if (ddSupported && (instaDrag || instaDragOverride)) { - PrepareDragDrop(pt,isRightClick); - } else { - InitSelectDragMode(pt, isRightClick); - } - } - } else if (ItemFromPoint(pt,item)) { - const t_size oldFocus = GetFocusItem(); - const t_size selStartBefore = GetSelectionStart(); - if ( bCanSelect ) SetFocusItem(item); - if (gotShift && AllowRangeSelect() ) { - if (bCanSelect) { - t_size selStart = selStartBefore; - if (selStart == pfc_infinite) selStart = oldFocus; - if (selStart == pfc_infinite) selStart = item; - SetSelectionStart(selStart); - t_size selFirst, selCount; - selFirst = pfc::min_t(selStart, item); - selCount = pfc::max_t(selStart, item) + 1 - selFirst; - pfc::bit_array_range rangeMask(selFirst, selCount); - pfc::bit_array_true trueMask; - SetSelection(gotCtrl ? pfc::implicit_cast(rangeMask) : pfc::implicit_cast(trueMask), rangeMask); - //if (!instaDrag) InitSelectDragMode(pt, isRightClick); - } - } else { - if (gotCtrl) { - if (bCanSelect) SetSelection(pfc::bit_array_one(item), pfc::bit_array_val(!IsItemSelected(item))); - if (!instaDrag) InitSelectDragMode(pt, isRightClick); - } else { - if (!IsItemSelected(item)) { - if (bCanSelect) SetSelection(pfc::bit_array_true(), pfc::bit_array_one(item)); - if (ddSupported && instaDrag) { - PrepareDragDrop(pt,isRightClick); - } else { - InitSelectDragMode(pt, isRightClick); - } - } else { - if (ddSupported) { - PrepareDragDrop(pt,isRightClick); - } else { - InitSelectDragMode(pt, isRightClick); - } - } - } - } - } else { - if (!gotShift && !gotCtrl && bCanSelect) SelectNone(); - InitSelectDragMode(pt, isRightClick); - } - return 0; -} - - -void CListControlWithSelectionBase::ToggleRangeSelection(pfc::bit_array const & mask) { - SetSelection(mask, pfc::bit_array_val(GetSelectedCount(mask,1) == 0)); -} -void CListControlWithSelectionBase::ToggleGroupSelection(int p_group) { - t_size base, count; - if (ResolveGroupRange(p_group,base,count)) ToggleRangeSelection(pfc::bit_array_range(base,count)); -} - -LRESULT CListControlWithSelectionBase::OnRButtonUp(UINT,WPARAM p_wp,LPARAM p_lp,BOOL& bHandled) { - bHandled = FALSE; - AbortPrepareDragDropMode(); - AbortSelectDragMode(); - return 0; -} - -LRESULT CListControlWithSelectionBase::OnMouseMove(UINT,WPARAM p_wp,LPARAM p_lp,BOOL&) { - if (m_prepareDragDropMode) { - if (CPoint(p_lp) != m_prepareDragDropOrigin) { - AbortPrepareDragDropMode(); - if (!m_ownDDActive) { - pfc::vartoggle_t ownDD(m_ownDDActive,true); - RunDragDrop(m_prepareDragDropOrigin + GetViewOffset(),m_prepareDragDropModeRightClick); - } - } - } else if (m_selectDragMode) { - HandleDragSel(CPoint(p_lp)); - } - return 0; -} -LRESULT CListControlWithSelectionBase::OnLButtonUp(UINT,WPARAM p_wp,LPARAM p_lp,BOOL&) { - const bool wasPreparingDD = m_prepareDragDropMode; - AbortPrepareDragDropMode(); - CPoint pt(p_lp); - const bool gotCtrl = (p_wp & MK_CONTROL) != 0; - const bool gotShift = (p_wp & MK_SHIFT) != 0; - bool click = false; - bool processSel = wasPreparingDD; - if (m_selectDragMode) { - processSel = !m_selectDragMoved; - AbortSelectDragMode(); - } - if (processSel) { - click = true; - if (!OnClickedSpecialHitTest(pt) ) { - int groupId; t_size item; - if (GroupHeaderFromPoint(pt, groupId)) { - t_size base, count; - if (ResolveGroupRange(groupId, base, count)) { - if (gotCtrl) { - } else { - SetSelection(pfc::bit_array_true(), pfc::bit_array_range(base, count)); - } - } - } else if (ItemFromPoint(pt, item)) { - const t_size selStartBefore = GetSelectionStart(); - if (gotCtrl) { - } else if (gotShift) { - SetSelectionStart(selStartBefore); - } else { - SetSelection(pfc::bit_array_true(), pfc::bit_array_one(item)); - } - } - } - } - if (click && !gotCtrl && !gotShift) { - int groupId; t_size item; - if (GroupHeaderFromPoint(pt,groupId)) { - OnGroupHeaderClicked(groupId,pt); - } else if (ItemFromPoint(pt,item)) { - OnItemClicked(item,pt); - } - } - return 0; -} - -void CListControlWithSelectionBase::OnKeyDown_SetIndexDeltaHelper(int p_delta, int p_keys) { - t_size focus = pfc_infinite; - if (this->GroupFocusActive()) { - t_size base,count; - if (this->ResolveGroupRange(this->GetGroupFocus(),base,count)) { - focus = base; - } - } else { - focus = GetFocusItem(); - } - int target = 0; - if (focus != pfc_infinite) target = (int) focus + p_delta; - OnKeyDown_SetIndexHelper(target,p_keys); -} - - -static int _get_keyflags() { - int ret = 0; - if (IsKeyPressed(VK_CONTROL)) ret |= MK_CONTROL; - if (IsKeyPressed(VK_SHIFT)) ret |= MK_SHIFT; - return ret; -} - -LRESULT CListControlWithSelectionBase::OnKeyDown(UINT p_msg,WPARAM p_wp,LPARAM p_lp,BOOL& bHandled) { - switch(p_wp) { - case VK_NEXT: - OnKeyDown_SetIndexDeltaPageHelper(1,_get_keyflags()); - return 0; - case VK_PRIOR: - OnKeyDown_SetIndexDeltaPageHelper(-1,_get_keyflags()); - return 0; - case VK_DOWN: - OnKeyDown_SetIndexDeltaLineHelper(1,_get_keyflags()); - return 0; - case VK_UP: - OnKeyDown_SetIndexDeltaLineHelper(-1,_get_keyflags()); - return 0; - case VK_HOME: - OnKeyDown_HomeEndHelper(false,_get_keyflags()); - return 0; - case VK_END: - OnKeyDown_HomeEndHelper(true,_get_keyflags()); - return 0; - case VK_SPACE: - if (!TypeFindCheck()) { - ToggleSelectedItems(); - } - return 0; - case VK_RETURN: - ExecuteDefaultActionByFocus(); - return 0; - case VK_DELETE: - if (GetHotkeyModifierFlags() == 0) { - RequestRemoveSelection(); - return 0; - } - break; - case 'A': - if (GetHotkeyModifierFlags() == MOD_CONTROL) { - if (SelectAll()) { - return 0; - } - // otherwise unhandled - } - break; - } - - bHandled = FALSE; - return 0; -} - -void CListControlWithSelectionBase::ToggleSelectedItems() { - if (ToggleSelectedItemsHook(bit_array_selection_CListControl(*this))) return; - if (GroupFocusActive()) { - ToggleGroupSelection(this->GetGroupFocus()); - } else { - const t_size focus = GetFocusItem(); - if (focus != pfc_infinite) { - ToggleRangeSelection(pfc::bit_array_range(focus, 1)); - } - } -} - -LRESULT CListControlWithSelectionBase::OnTimer(UINT,WPARAM p_wp,LPARAM,BOOL& bHandled) { - switch((DWORD)p_wp) { - case (DWORD)KSelectionTimerID: - if (m_selectDragMode) { - CPoint pt(GetCursorPos()); ScreenToClient(&pt); - const CRect client = GetClientRectHook(); - CPoint delta(0,0); - if (pt.x < client.left) { - delta.x = pt.x - client.left; - } else if (pt.x > client.right) { - delta.x = pt.x - client.right; - } - if (pt.y < client.top) { - delta.y = pt.y - client.top; - } else if (pt.y > client.bottom) { - delta.y = pt.y - client.bottom; - } - - MoveViewOriginDelta(delta); - HandleDragSel(pt); - } - return 0; - case TDDScrollControl::KTimerID: - HandleDDScroll(); - return 0; - default: - bHandled = FALSE; - return 0; - } -} - -bool CListControlWithSelectionBase::MoveSelectionProbe(int delta) { - pfc::array_t order; order.set_size(GetItemCount()); - { - bit_array_selection_CListControl sel(*this); - pfc::create_move_items_permutation(order.get_ptr(), order.get_size(), sel, delta); - } - for( size_t w = 0; w < order.get_size(); ++w ) if ( order[w] != w ) return true; - return false; -} -void CListControlWithSelectionBase::RequestMoveSelection(int delta) { - pfc::array_t order; order.set_size(GetItemCount()); - { - bit_array_selection_CListControl sel(*this); - pfc::create_move_items_permutation(order.get_ptr(), order.get_size(), sel, delta); - } - - this->RequestReorder(order.get_ptr(), order.get_size()); - - if (delta < 0) { - size_t idx = GetFirstSelected(); - if (idx != pfc_infinite) EnsureItemVisible(idx); - } else { - size_t idx = GetLastSelected(); - if (idx != pfc_infinite) EnsureItemVisible(idx); - } -} - -void CListControlWithSelectionBase::ToggleSelection(pfc::bit_array const & mask) { - const t_size count = GetItemCount(); - pfc::bit_array_bittable table(count); - for(t_size walk = mask.find_first(true,0,count); walk < count; walk = mask.find_next(true,walk,count)) { - table.set(walk,!IsItemSelected(walk)); - } - this->SetSelection(mask,table); -} - -static HRGN FrameRectRgn(const CRect & rect) { - CRect exterior(rect); exterior.InflateRect(1,1); - CRgn rgn; rgn.CreateRectRgnIndirect(exterior); - CRect interior(rect); interior.DeflateRect(1,1); - if (!interior.IsRectEmpty()) { - CRgn rgn2; rgn2.CreateRectRgnIndirect(interior); - rgn.CombineRgn(rgn2,RGN_DIFF); - } - return rgn.Detach(); -} - -void CListControlWithSelectionBase::HandleDragSel(const CPoint & p_pt) { - CPoint pt(p_pt); pt += GetViewOffset(); - if (pt != m_selectDragCurrentAbs) { - - if (!this->AllowRangeSelect()) { - // simplified - m_selectDragCurrentAbs = pt; - if (pt != m_selectDragOriginAbs) m_selectDragMoved = true; - return; - } - - CRect rcOld(m_selectDragOriginAbs,m_selectDragCurrentAbs); rcOld.NormalizeRect(); - m_selectDragCurrentAbs = pt; - CRect rcNew(m_selectDragOriginAbs,m_selectDragCurrentAbs); rcNew.NormalizeRect(); - - - { - CRgn rgn = FrameRectRgn(rcNew); - CRgn rgn2 = FrameRectRgn(rcOld); - rgn.CombineRgn(rgn2,RGN_OR); - rgn.OffsetRgn( - GetViewOffset() ); - InvalidateRgn(rgn); - } - - if (pt != m_selectDragOriginAbs) m_selectDragMoved = true; - - if (m_selectDragChanged || !IsSameItemOrHeaderAbs(pt,m_selectDragOriginAbs)) { - m_selectDragChanged = true; - const int keys = _get_keyflags(); - t_size base,count, baseOld, countOld; - if (!GetItemRangeAbs(rcNew,base,count)) base = count = 0; - if (!GetItemRangeAbs(rcOld,baseOld,countOld)) baseOld = countOld = 0; - { - pfc::bit_array_range rangeNew(base,count), rangeOld(baseOld,countOld); - if (keys & MK_CONTROL) { - ToggleSelection(pfc::bit_array_xor(rangeNew,rangeOld)); - } else if (keys & MK_SHIFT) { - SetSelection(pfc::bit_array_or(rangeNew,rangeOld),rangeNew); - } else { - SetSelection(pfc::bit_array_true(),rangeNew); - } - } - int groupId; - if (ItemFromPointAbs(pt,base)) { - const CRect rcVisible = GetVisibleRectAbs(), rcItem = GetItemRectAbs(base); - if (rcItem.top >= rcVisible.top && rcItem.bottom <= rcVisible.bottom) { - SetFocusItem(base); - } - } else if (GroupHeaderFromPointAbs(pt,groupId)) { - const CRect rcVisible = GetVisibleRectAbs(); - CRect rcGroup; - if (GetGroupHeaderRectAbs(groupId,rcGroup)) { - if (rcGroup.top >= rcVisible.top && rcGroup.bottom <= rcVisible.bottom) { - SetGroupFocus(groupId); - } - } - } - } - } -} - -void CListControlWithSelectionBase::InitSelectDragMode(const CPoint & p_pt,bool p_rightClick) { - // Perform the bookkeeping even if multiple selection is disabled, detection of clicks relies on it - SetTimer(KSelectionTimerID,KSelectionTimerPeriod); - m_selectDragMode = true; - m_selectDragOriginAbs = m_selectDragCurrentAbs = p_pt + GetViewOffset(); - m_selectDragChanged = false; m_selectDragMoved = false; - SetCapture(); -} - -void CListControlWithSelectionBase::AbortSelectDragMode(bool p_lostCapture) { - if (m_selectDragMode) { - m_selectDragMode = false; - CRect rcSelect(m_selectDragOriginAbs,m_selectDragCurrentAbs); rcSelect.NormalizeRect(); - rcSelect.OffsetRect( - GetViewOffset() ); - if (!p_lostCapture) ::SetCapture(NULL); - rcSelect.InflateRect(1,1); - InvalidateRect(rcSelect); - KillTimer(KSelectionTimerID); - } -} - - -LRESULT CListControlWithSelectionBase::OnCaptureChanged(UINT,WPARAM,LPARAM,BOOL&) { - AbortPrepareDragDropMode(true); - AbortSelectDragMode(true); - return 0; -} - -void CListControlWithSelectionBase::RenderOverlay(const CRect & p_updaterect,CDCHandle p_dc) { - if (m_selectDragMode && this->AllowRangeSelect() ) { - CRect rcSelect(m_selectDragOriginAbs,m_selectDragCurrentAbs); - rcSelect.NormalizeRect(); - PaintUtils::FocusRect(p_dc,rcSelect); - } - if (m_dropMark != pfc_infinite) { - RenderDropMarkerClipped(p_dc, p_updaterect, m_dropMark, m_dropMarkInside); - } - TParent::RenderOverlay(p_updaterect,p_dc); -} - -void CListControlWithSelectionBase::SetDropMark(size_t mark, bool inside) { - if (mark != m_dropMark || inside != m_dropMarkInside) { - CRgn updateRgn; updateRgn.CreateRectRgn(0, 0, 0, 0); - AddDropMarkToUpdateRgn(updateRgn, m_dropMark, m_dropMarkInside); - m_dropMark = mark; - m_dropMarkInside = inside; - AddDropMarkToUpdateRgn(updateRgn, m_dropMark, m_dropMarkInside); - RedrawWindow(NULL, updateRgn); - } -} - -static int transformDDScroll(int p_value,int p_width, int p_dpi) { - if (p_dpi <= 0) p_dpi = 96; - const double dpiMul = 96.0 / (double) p_dpi; - double val = (double)(p_width - p_value); - val *= dpiMul; - val = pow(val,1.1) * 0.33; - val /= dpiMul; - return pfc::rint32(val); -} - -void CListControlWithSelectionBase::HandleDDScroll() { - if (m_ddScroll.m_timerActive) { - const CPoint position( GetCursorPos() ); - CRect client = GetClientRectHook(); - CPoint delta (0,0); - if (ClientToScreen(client)) { - const CSize DPI = QueryScreenDPIEx(); - const int scrollZoneWidthBase = GetItemHeight() * 2; - const int scrollZoneHeight = pfc::min_t( scrollZoneWidthBase, client.Height() / 4 ); - const int scrollZoneWidth = pfc::min_t( scrollZoneWidthBase, client.Width() / 4 ); - - if (position.y >= client.top && position.y < client.top + scrollZoneHeight) { - delta.y -= transformDDScroll(position.y - client.top, scrollZoneHeight, DPI.cy); - } else if (position.y >= client.bottom - scrollZoneHeight && position.y < client.bottom) { - delta.y += transformDDScroll(client.bottom - position.y, scrollZoneHeight, DPI.cy); - } - - if (position.x >= client.left && position.x < client.left + scrollZoneWidth) { - delta.x -= transformDDScroll(position.x - client.left, scrollZoneWidth, DPI.cx); - } else if (position.x >= client.right - scrollZoneWidth && position.x < client.right) { - delta.x += transformDDScroll(client.right - position.x, scrollZoneWidth, DPI.cx); - } - } - - if (delta != CPoint(0,0)) MoveViewOriginDelta(delta); - } -} - -void CListControlWithSelectionBase::ToggleDDScroll(bool p_state) { - if (p_state != m_ddScroll.m_timerActive) { - if (p_state) { - SetTimer(m_ddScroll.KTimerID,m_ddScroll.KTimerPeriod); - } else { - KillTimer(m_ddScroll.KTimerID); - } - m_ddScroll.m_timerActive = p_state; - } -} - -void CListControlWithSelectionBase::PrepareDragDrop(const CPoint & p_point,bool p_isRightClick) { - m_prepareDragDropMode = true; - m_prepareDragDropOrigin = p_point; - m_prepareDragDropModeRightClick = p_isRightClick; - SetCapture(); -} -void CListControlWithSelectionBase::AbortPrepareDragDropMode(bool p_lostCapture) { - if (m_prepareDragDropMode) { - m_prepareDragDropMode = false; - if (!p_lostCapture) ::SetCapture(NULL); - } -} - - -void CListControlWithSelectionBase::RenderItem(t_size p_item,const CRect & p_itemRect,const CRect & p_updateRect,CDCHandle p_dc) { - //console::formatter() << "RenderItem: " << p_item; - const bool weHaveFocus = ::GetFocus() == m_hWnd; - const bool isSelected = this->IsItemSelected(p_item); - - const t_uint32 bkColor = GetSysColorHook(colorBackground); - const t_uint32 hlColor = GetSysColorHook(colorSelection); - const t_uint32 bkColorUsed = isSelected ? (weHaveFocus ? hlColor : PaintUtils::BlendColor(hlColor,bkColor)) : bkColor; - - bool alternateTextColor = false, dtt = false; - auto & m_theme = theme(); - if (m_theme != NULL && isSelected && hlColor == GetSysColor(COLOR_HIGHLIGHT) && /*bkColor == GetSysColor(COLOR_WINDOW) && */ IsThemePartDefined(m_theme, LVP_LISTITEM, 0)) { - //PaintUtils::RenderItemBackground(p_dc,p_itemRect,p_item+GetItemGroup(p_item),bkColor); - DrawThemeBackground(m_theme, p_dc, LVP_LISTITEM, weHaveFocus ? LISS_SELECTED : LISS_SELECTEDNOTFOCUS , p_itemRect, p_updateRect); - dtt = true; - } else { - this->RenderItemBackground(p_dc, p_itemRect, p_item, bkColorUsed ); - // PaintUtils::RenderItemBackground(p_dc,p_itemRect,p_item+GetItemGroup(p_item),bkColorUsed); - if (isSelected) alternateTextColor = true; - } - - { - DCStateScope backup(p_dc); - p_dc.SetBkMode(TRANSPARENT); - p_dc.SetBkColor(bkColorUsed); - p_dc.SetTextColor(alternateTextColor ? PaintUtils::DetermineTextColor(bkColorUsed) : this->GetSysColorHook(colorText)); - pfc::vartoggle_t toggle(m_drawThemeText, dtt); - RenderItemText(p_item,p_itemRect,p_updateRect,p_dc, !alternateTextColor); - } - - if (IsItemFocused(p_item) && weHaveFocus) { - PaintUtils::FocusRect2(p_dc,p_itemRect, bkColorUsed); - } -} -void CListControlWithSelectionBase::RenderSubItemText(t_size item, t_size subItem,const CRect & subItemRect,const CRect & updateRect,CDCHandle dc, bool allowColors) { - auto ct = GetCellType(item, subItem); - if ( ct == nullptr ) return; - - if (m_drawThemeText && ct->AllowDrawThemeText() && !this->IsSubItemGrayed(item, subItem)) for(;;) { - pfc::string_formatter label; - if (!GetSubItemText(item,subItem,label)) return; - const bool weHaveFocus = ::GetFocus() == m_hWnd; - const bool isSelected = this->IsItemSelected(item); - pfc::stringcvt::string_os_from_utf8 cvt(label); - if (PaintUtils::TextContainsCodes(cvt)) break; - CRect clip = GetItemTextRect(subItemRect); - const t_uint32 format = PaintUtils::DrawText_TranslateHeaderAlignment(GetColumnFormat(subItem)); - DrawThemeText(theme(), dc, LVP_LISTITEM, weHaveFocus ? LISS_SELECTED : LISS_SELECTEDNOTFOCUS, cvt, (int)cvt.length(), DT_NOPREFIX | DT_END_ELLIPSIS | DT_SINGLELINE | DT_VCENTER | format, 0, clip); - return; - } - __super::RenderSubItemText(item, subItem, subItemRect, updateRect, dc, allowColors); -} -void CListControlWithSelectionBase::RenderGroupHeader(int p_group,const CRect & p_headerRect,const CRect & p_updateRect,CDCHandle p_dc) { - TParent::RenderGroupHeader(p_group,p_headerRect,p_updateRect,p_dc); - if (IsGroupHeaderFocused(p_group)) { - PaintUtils::FocusRect(p_dc,p_headerRect); - } -} -CRect CListControlWithSelectionBase::DropMarkerUpdateRect(t_size index,bool bInside) const { - if (index != ~0) { - CRect rect; - if (bInside) { - rect = GetItemRect(index); - rect.InflateRect(DropMarkerMargin()); - } else { - rect = DropMarkerRect(DropMarkerOffset(index)); - } - return rect; - } else { - return CRect(0,0,0,0); - } -} -void CListControlWithSelectionBase::AddDropMarkToUpdateRgn(HRGN p_rgn, t_size p_index, bool bInside) const { - CRect rect = DropMarkerUpdateRect(p_index,bInside); - if (!rect.IsRectEmpty()) PaintUtils::AddRectToRgn(p_rgn,rect); -} - -CRect CListControlWithSelectionBase::DropMarkerRect(int offset) const { - const int delta = MulDiv(5,m_dpi.cy,96); - CRect rc(0,offset - delta,GetViewAreaWidth(), offset + delta); - rc.InflateRect(DropMarkerMargin()); - return rc; -} - -int CListControlWithSelectionBase::DropMarkerOffset(t_size marker) const { - return (marker > 0 ? this->GetItemRectAbs(marker-1).bottom : 0) - GetViewOffset().y; -} -bool CListControlWithSelectionBase::RenderDropMarkerClipped(CDCHandle dc, const CRect & update, t_size item, bool bInside) { - CRect markerRect = DropMarkerUpdateRect(item,bInside); markerRect.OffsetRect( GetViewOffset() ); - CRect affected; - if (affected.IntersectRect(markerRect,update)) { - DCStateScope state(dc); - if (dc.IntersectClipRect(affected)) { - RenderDropMarker(dc,item,bInside); - return true; - } - } - return false; -} -void CListControlWithSelectionBase::RenderDropMarker(CDCHandle dc, t_size item, bool bInside) { - if (item != ~0) { - if (bInside) { - CPen pen; MakeDropMarkerPen(pen); - SelectObjectScope penScope(dc,pen); - const CRect rc = GetItemRectAbs(item); - dc.MoveTo(rc.left,rc.top); - dc.LineTo(rc.right,rc.top); - dc.LineTo(rc.right,rc.bottom); - dc.LineTo(rc.left,rc.bottom); - dc.LineTo(rc.left,rc.top); - } else { - RenderDropMarkerByOffset(DropMarkerOffset(item) + GetViewOffset().y,dc); - } - } -} - -SIZE CListControlWithSelectionBase::DropMarkerMargin() const { - const int penDeltaX = MulDiv(5 /* we don't know how to translate CreatePen units... */,m_dpi.cx,96); - const int penDeltaY = MulDiv(5 /* we don't know how to translate CreatePen units... */,m_dpi.cy,96); - SIZE s = {penDeltaX,penDeltaY}; - return s; -} -void CListControlWithSelectionBase::MakeDropMarkerPen(CPen & out) const { - WIN32_OP_D( out.CreatePen(PS_SOLID,3,GetSysColorHook(colorText)) != NULL ); -} - -void CListControlWithSelectionBase::RenderDropMarkerByOffset(int offset,CDCHandle p_dc) { - CPen pen; MakeDropMarkerPen(pen); - const int delta = MulDiv(5,m_dpi.cy,96); - SelectObjectScope penScope(p_dc,pen); - const int width = GetViewAreaWidth(); - if (width > 0) { - p_dc.MoveTo(0,offset); - p_dc.LineTo(width-1,offset); - p_dc.MoveTo(0,offset-delta); - p_dc.LineTo(0,offset+delta); - p_dc.MoveTo(width-1,offset-delta); - p_dc.LineTo(width-1,offset+delta); - } -} - -void CListControlWithSelectionBase::FocusToUpdateRgn(HRGN rgn) { - t_size focusItem = GetFocusItem(); - if (focusItem != ~0) AddItemToUpdateRgn(rgn,focusItem); - else { - int focusGroup = GetGroupFocus(); - if (focusGroup >= 0) AddGroupHeaderToUpdateRgn(rgn,focusGroup); - } -} - -void CListControlWithSelectionImpl::ReloadData() { - if ( GetItemCount() != m_selection.get_size() ) { - this->SelHandleReset(); - } - __super::ReloadData(); -} - -void CListControlWithSelectionImpl::SetGroupFocus(int group) { - t_size base,total; - if (this->ResolveGroupRange(group,base,total)) { - SetGroupFocusByItem(base); - } -} - -int CListControlWithSelectionImpl::GetGroupFocus() const { - return (m_groupFocus && m_focus < GetItemCount()) ? GetItemGroup(m_focus) : -1; -} - -void CListControlWithSelectionImpl::SetSelectionImpl(pfc::bit_array const & affected, pfc::bit_array const & status) { - const t_size total = m_selection.get_size(); - pfc::bit_array_flatIndexList toUpdate; - - // Only fire UpdateItems for stuff that's both on-screen and actually changed - // Firing for whole affected mask will repaint everything when selecting one item - t_size base, count; - if (!GetItemRangeAbs(GetVisibleRectAbs(), base, count)) { base = count = 0; } - - affected.walk( total, [&] (size_t idx) { - if ( m_selection[idx] != status[idx] && this->CanSelectItem(idx) ) { - m_selection[idx] = status[idx]; - if ( idx >= base && idx < base+count ) toUpdate.add(idx); - } - } ); - - if ( toUpdate.get_count() > 0 ) { - UpdateItems(toUpdate); - } - - this->OnSelectionChanged( affected, status ); -} - -void CListControlWithSelectionImpl::SetSelection(pfc::bit_array const & affected, pfc::bit_array const & status) { - RefreshSelectionSize(); - - - if ( m_selectionSupport == selectionSupportNone ) return; - - if ( m_selectionSupport == selectionSupportSingle ) { - size_t single = SIZE_MAX; - bool selNone = true; - const size_t total = m_selection.get_size(); - for( size_t walk = 0; walk < total; ++ walk ) { - if ( affected.get(walk) ) { - if ( status.get(walk) && single == SIZE_MAX ) { - single = walk; - } - } else if ( IsItemSelected( walk ) ) { - selNone = false; - } - } - if ( single < total ) { - SetSelectionImpl( pfc::bit_array_true(), pfc::bit_array_one( single ) ); - } else if ( selNone ) { - this->SetSelectionImpl( pfc::bit_array_true(), pfc::bit_array_false() ); - } - } else { - SetSelectionImpl( affected, status ); - } - -} - -void CListControlWithSelectionImpl::RefreshSelectionSize() { - RefreshSelectionSize(GetItemCount()); -} -void CListControlWithSelectionImpl::RefreshSelectionSize(t_size total) { - const t_size oldSize = m_selection.get_size(); - if (total != oldSize) { - m_selection.set_size(total); - for(t_size walk = oldSize; walk < total; ++walk) m_selection[walk] = false; - } -} - -void CListControlWithSelectionImpl::SetGroupFocusByItem(t_size item) { - CRgn update; update.CreateRectRgn(0,0,0,0); - FocusToUpdateRgn(update); - m_groupFocus = true; m_focus = item; - FocusToUpdateRgn(update); - InvalidateRgn(update); - - const int iGroup = GetItemGroup(item); - CRect header; - if (GetGroupHeaderRectAbs(iGroup,header)) EnsureVisibleRectAbs(header); - - this->OnFocusChangedGroup( iGroup ); -} - -void CListControlWithSelectionImpl::SetFocusItem(t_size index) { - CRgn update; update.CreateRectRgn(0,0,0,0); - FocusToUpdateRgn(update); - m_groupFocus = false; m_focus = index; - FocusToUpdateRgn(update); - InvalidateRgn(update); - - EnsureVisibleRectAbs(GetItemRectAbs(index)); - - SetSelectionStart(index); - - this->OnFocusChanged( index ); -} - -static void UpdateIndexOnReorder(t_size & index, const t_size * order, t_size count) { - index = pfc::permutation_find_reverse(order,count,index); -} -static void UpdateIndexOnRemoval(t_size & index, const pfc::bit_array & mask, t_size oldCount, t_size newCount) { - if (index >= oldCount || newCount == 0) {index = ~0; return;} - for(t_size walk = mask.find_first(true,0,oldCount); walk < newCount; ++walk) { - if (walk < index) --index; - else break; - } - if (index >= newCount) index = newCount - 1; -} -static void UpdateIndexOnInsert(t_size & index, t_size base, t_size count) { - if (index != ~0 && index >= base) index += count; -} - -void CListControlWithSelectionImpl::SelHandleReorder(const t_size * order, t_size count) { - RefreshSelectionSize(); - UpdateIndexOnReorder(m_focus,order,count); - UpdateIndexOnReorder(m_selectionStart,order,count); - pfc::array_t newSel; newSel.set_size(m_selection.get_size()); - for(t_size walk = 0; walk < m_selection.get_size(); ++walk) newSel[walk] = m_selection[order[walk]]; - m_selection = newSel; -} - -void CListControlWithSelectionImpl::SelHandleReset() { - RefreshSelectionSize(GetItemCount()); - for(t_size walk = 0; walk < m_selection.get_size(); walk++) m_selection[walk] = false; - m_focus = ~0; - m_groupFocus = false; - -} -void CListControlWithSelectionImpl::SelHandleRemoval(const pfc::bit_array & mask, t_size oldCount) { - RefreshSelectionSize(oldCount); - const t_size newCount = GetItemCount(); - UpdateIndexOnRemoval(m_focus,mask,oldCount,newCount); - UpdateIndexOnRemoval(m_selectionStart,mask,oldCount,newCount); - pfc::remove_mask_t(m_selection,mask); -} - -void CListControlWithSelectionImpl::SelHandleInsertion(t_size base, t_size count, bool select) { - UpdateIndexOnInsert(m_focus,base,count); - UpdateIndexOnInsert(m_selectionStart,base,count); - RefreshSelectionSize(GetItemCount() - count); - - // To behave sanely in single-select mode, we'd have to alter selection of other items from here - // Let caller worry and outright deny select requests in modes other than multisel - if ( m_selectionSupport != selectionSupportMulti ) select = false; - - m_selection.insert_multi(select,base,count); -} - - -LRESULT CListControlWithSelectionBase::OnGetDlgCode(UINT,WPARAM,LPARAM p_lp,BOOL& bHandled) { - if (p_lp == 0) { - return DLGC_WANTALLKEYS | DLGC_WANTCHARS | DLGC_WANTARROWS; - } else { - const MSG * pmsg = reinterpret_cast(p_lp); - switch(pmsg->message) { - case WM_KEYDOWN: - case WM_KEYUP: - switch(pmsg->wParam) { - case VK_ESCAPE: - case VK_TAB: - bHandled = FALSE; - return 0; - default: - return DLGC_WANTMESSAGE; - } - case WM_CHAR: - return DLGC_WANTMESSAGE; - default: - bHandled = FALSE; - return 0; - } - } -} - - -bool CListControlWithSelectionBase::GetFocusRect(CRect & p_rect) { - if (!GetFocusRectAbs(p_rect)) return false; - p_rect.OffsetRect( - GetViewOffset() ); - return true; -} -bool CListControlWithSelectionBase::GetFocusRectAbs(CRect & p_rect) { - t_size item = this->GetFocusItem(); - if (item != ~0) { - p_rect = this->GetItemRectAbs(item); - return true; - } - int group = this->GetGroupFocus(); - if (group >= 0) { - return GetGroupHeaderRectAbs(group,p_rect); - } - - return false; -} - -CPoint CListControlWithSelectionBase::GetContextMenuPoint(CPoint ptGot) { - CPoint pt; - if (ptGot.x == -1 && ptGot.y == -1) { - CRect rect; - if (!GetFocusRectAbs(rect)) return 0; - EnsureVisibleRectAbs(rect); - pt = rect.CenterPoint() - GetViewOffset(); - ClientToScreen(&pt); - } else { - pt = ptGot; - } - return pt; -} - -CPoint CListControlWithSelectionBase::GetContextMenuPoint(LPARAM lp) { - CPoint pt; - if (lp == -1) { - CRect rect; - if (!GetFocusRectAbs(rect)) return 0; - EnsureVisibleRectAbs(rect); - pt = rect.CenterPoint() - GetViewOffset(); - ClientToScreen(&pt); - } else { - pt = lp; - } - return pt; -} - -bool CListControlWithSelectionBase::MakeDropReorderPermutation(pfc::array_t & out, CPoint ptDrop) const { - t_size insertMark = InsertIndexFromPoint(ptDrop); - /*if (insertMark != this->GetFocusItem())*/ { - const t_size count = GetItemCount(); - if (insertMark > count) insertMark = count; - { - t_size selBefore = 0; - for(t_size walk = 0; walk < insertMark; ++walk) { - if (IsItemSelected(walk)) selBefore++; - } - insertMark -= selBefore; - } - { - pfc::array_t permutation, selected, nonselected; - const t_size selcount = this->GetSelectedCount(); - selected.set_size(selcount); nonselected.set_size(count - selcount); - permutation.set_size(count); - if (insertMark > nonselected.get_size()) insertMark = nonselected.get_size(); - for(t_size walk = 0, swalk = 0, nwalk = 0; walk < count; ++walk) { - if (IsItemSelected(walk)) { - selected[swalk++] = walk; - } else { - nonselected[nwalk++] = walk; - } - } - for(t_size walk = 0; walk < insertMark; ++walk) { - permutation[walk] = nonselected[walk]; - } - for(t_size walk = 0; walk < selected.get_size(); ++walk) { - permutation[insertMark + walk] = selected[walk]; - } - for(t_size walk = insertMark; walk < nonselected.get_size(); ++walk) { - permutation[selected.get_size() + walk] = nonselected[walk]; - } - for(t_size walk = 0; walk < permutation.get_size(); ++walk) { - if (permutation[walk] != walk) { - out = permutation; - return true; - } - } - } - } - return false; -} - -void CListControlWithSelectionBase::EnsureVisibleRectAbs(const CRect & p_rect) { - if (!m_noEnsureVisible) TParent::EnsureVisibleRectAbs(p_rect); -} - -bool CListControlWithSelectionBase::TypeFindCheck(DWORD ts) const { - if (m_typeFindTS == 0) return false; - return ts - m_typeFindTS < 1000; -} - -void CListControlWithSelectionBase::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) { - if (nChar < 32) { - m_typeFindTS = 0; - return; - } - - const DWORD ts = GetTickCount(); - if (!TypeFindCheck(ts)) m_typeFind.reset(); - - if (nChar == ' ' && m_typeFind.is_empty()) { - m_typeFindTS = 0; - return; - } - - m_typeFindTS = ts; - if (m_typeFindTS == 0) m_typeFindTS = ~0; - char temp[10] = {}; - pfc::utf8_encode_char(nChar, temp); - m_typeFind += temp; - RunTypeFind(); -} - -static unsigned detectRepetition( pfc::string8 const & str ) { - size_t count = 0; - size_t walk = 0; - uint32_t first; - - while( walk < str.length() ) { - uint32_t current; - auto delta = pfc::utf8_decode_char( str.c_str() + walk, current, str.length() - walk ); - if ( delta == 0 ) break; - walk += delta; - - if ( count == 0 ) first = current; - else if ( first != current ) return 0; - - ++ count; - } - - if ( count > 1 ) return first; - return 0; -} - -size_t CListControlWithSelectionBase::EvalTypeFind() { - if ( GetItemCount() == 0 ) return SIZE_MAX; - - static SmartStrStr tool; - - const size_t itemCount = GetItemCount(); - const size_t colCount = GetColumnCount(); - pfc::string_formatter temp; - t_size searchBase = this->GetFocusItem(); - if (searchBase >= itemCount) searchBase = 0; - - size_t partial = SIZE_MAX; - size_t repetition = SIZE_MAX; - bool useRepetition = false; - pfc::string8 strRepetitionChar; - unsigned repChar = detectRepetition( m_typeFind ); - if ( repChar != 0 ) { - useRepetition = true; - strRepetitionChar.add_char( repChar ); - } - - for(t_size walk = 0; walk < itemCount; ++walk) { - t_size index = (walk + searchBase) % itemCount; - for(size_t cWalk = 0; cWalk < colCount; ++cWalk) { - - temp.reset(); - - if (AllowTypeFindInCell( index, cWalk )) { - this->GetSubItemText(index, cWalk, temp); - } - - if ( temp.length() == 0 ) { - continue; - } - if (partial == SIZE_MAX) { - size_t matchAt; - if (tool.strStrEnd( temp, m_typeFind, & matchAt ) != nullptr) { - if ( matchAt == 0 ) return index; - partial = index; - } - } else { - if ( tool.matchHere( temp, m_typeFind ) ) return index; - } - if (useRepetition && index != searchBase) { - if ( tool.matchHere( temp, strRepetitionChar ) ) { - useRepetition = false; - repetition = index; - } - } - } - } - if (partial < itemCount) return partial; - if (repetition < itemCount) return repetition; - return SIZE_MAX; -} - -void CListControlWithSelectionBase::RunTypeFind() { - size_t index = EvalTypeFind(); - if (index < GetItemCount() ) { - this->SetFocusItem( index ); - this->SetSelection(pfc::bit_array_true(), pfc::bit_array_one(index) ); - } else { - MessageBeep(0); - } -} - -CRect CListControlWithSelectionBase::GetWholeSelectionRectAbs() const { - CRect rcTotal; - const size_t count = GetItemCount(); - for( size_t w = 0; w < count; ++w ) { - if ( IsItemSelected( w ) ) { - CRect rcItem = GetItemRectAbs(w); - if ( rcTotal.IsRectNull( ) ) rcTotal = rcItem; - else rcTotal|=rcItem; - } - } - return rcTotal; -} - -size_t CListControlWithSelectionBase::GetFirstSelected() const { - const size_t count = GetItemCount(); - for( size_t w = 0; w < count; ++w ) { - if ( IsItemSelected(w) ) return w; - } - return pfc_infinite; -} -size_t CListControlWithSelectionBase::GetLastSelected() const { - const size_t count = GetItemCount(); - for( size_t w = count - 1; (t_ssize) w >= 0; --w ) { - if ( IsItemSelected(w) ) return w; - } - return pfc_infinite; -} - -namespace { - class CDropTargetImpl : public ImplementCOMRefCounter { - public: - COM_QI_BEGIN() - COM_QI_ENTRY(IUnknown) - COM_QI_ENTRY(IDropTarget) - COM_QI_END() - - bool valid = true; - std::function Track; - std::function HookAccept; - std::function HookDrop; - std::function HookLeave; - - DWORD m_effect = DROPEFFECT_NONE; - - HRESULT STDMETHODCALLTYPE DragEnter(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { - if (pDataObj == NULL || pdwEffect == NULL) return E_INVALIDARG; - if (!valid) return E_FAIL; - if ( HookAccept ) { - m_effect = HookAccept(pDataObj); - } else { - m_effect = DROPEFFECT_MOVE; - } - *pdwEffect = m_effect; - return S_OK; - } - HRESULT STDMETHODCALLTYPE DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { - if (pdwEffect == NULL) return E_INVALIDARG; - if (!valid) return E_FAIL; - if ( m_effect != DROPEFFECT_NONE ) Track(CPoint(pt.x, pt.y)); - *pdwEffect = m_effect; - return S_OK; - } - HRESULT STDMETHODCALLTYPE DragLeave() { - if (HookLeave) HookLeave(); - return S_OK; - } - HRESULT STDMETHODCALLTYPE Drop(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { - if ( HookDrop && m_effect != DROPEFFECT_NONE ) { - HookDrop( pDataObj, CPoint(pt.x, pt.y) ); - } - return S_OK; - } - }; - - class CDropSourceImpl : public ImplementCOMRefCounter { - public: - CPoint droppedAt; - bool droppedAtValid = false; - bool allowReorder = false; - - bool allowDragOutside = false; - CWindow wndOrigin; - - COM_QI_BEGIN() - COM_QI_ENTRY(IUnknown) - COM_QI_ENTRY(IDropSource) - COM_QI_END() - - HRESULT STDMETHODCALLTYPE GiveFeedback(DWORD dwEffect) { - m_effect = dwEffect; - return DRAGDROP_S_USEDEFAULTCURSORS; - } - - HRESULT STDMETHODCALLTYPE QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState) { - - if (fEscapePressed || (grfKeyState & MK_RBUTTON) != 0) { - return DRAGDROP_S_CANCEL; - } else if (!(grfKeyState & MK_LBUTTON)) { - if (m_effect == DROPEFFECT_NONE) return DRAGDROP_S_CANCEL; - - const CPoint pt(GetCursorPos()); - bool bInside = false; - if (wndOrigin) { - CRect rc; - WIN32_OP_D(wndOrigin.GetWindowRect(rc)); - bInside = rc.PtInRect(pt); - } - if (!allowDragOutside && !bInside) return DRAGDROP_S_CANCEL; - - if ( allowReorder && bInside) { - droppedAt = pt; - droppedAtValid = true; - return DRAGDROP_S_CANCEL; - } - return DRAGDROP_S_DROP; - - } else { - return S_OK; - } - } - private: - DWORD m_effect = 0; - }; -} - -void CListControlWithSelectionBase::RunDragDrop(const CPoint & p_origin, bool p_isRightClick) { - - uint32_t flags = this->QueryDragDropTypes(); - if ( flags == 0 ) { - PFC_ASSERT(!"How did we get here?"); - return; - } - if ( flags == dragDrop_reorder ) { - if ( p_isRightClick ) return; - CPoint ptDrop; - if ( RunReorderDragDrop( p_origin, ptDrop ) ) { - pfc::array_t order; - if (MakeDropReorderPermutation(order, ptDrop)) { - this->RequestReorder(order.get_ptr(), order.get_size()); - } - } - return; - } - - auto obj = this->MakeDataObject(); - if (obj.is_empty()) { - PFC_ASSERT(!"How did we get here? No IDataObject"); - return; - } - - pfc::com_ptr_t source = new CDropSourceImpl(); - source->wndOrigin = *this; - source->allowDragOutside = true; - source->allowReorder = (flags & dragDrop_reorder) != 0; - - DWORD outEffect = DROPEFFECT_NONE; - HRESULT status = DoDragDrop(obj.get_ptr(), source.get_ptr(), DragDropSourceEffects() , &outEffect); - - if ( source->droppedAtValid ) { - CPoint ptDrop = source->droppedAt; - WIN32_OP_D(this->ScreenToClient(&ptDrop)); - pfc::array_t order; - if (MakeDropReorderPermutation(order, ptDrop)) { - this->RequestReorder(order.get_ptr(), order.get_size()); - } - } else if (status == DRAGDROP_S_DROP) { - DragDropSourceSucceeded(outEffect); - } -} - -pfc::com_ptr_t CListControlWithSelectionBase::MakeDataObject() { - // return dummy IDataObject, presume derived transmits drag and drop payload by other means - using namespace IDataObjectUtils; - return new ImplementCOMRefCounter< CDataObjectBase >(); -} - -bool CListControlWithSelectionBase::RunReorderDragDrop(CPoint ptOrigin, CPoint & ptDrop) { - pfc::com_ptr_t source = new CDropSourceImpl(); - pfc::com_ptr_t target = new CDropTargetImpl(); - - source->wndOrigin = *this; - source->allowDragOutside = false; - source->allowReorder = true; - - target->Track = [this](CPoint pt) { - WIN32_OP_D(this->ScreenToClient(&pt)); - size_t idx = this->InsertIndexFromPoint(pt); - this->SetDropMark(idx, false); - }; - - if ( FAILED(RegisterDragDrop(*this, target.get_ptr())) ) { - // OleInitialize not called? - PFC_ASSERT( !"Should not get here" ); - return false; - } - - pfc::onLeaving scope([=] { target->valid = false; RevokeDragDrop(*this); }); - - using namespace IDataObjectUtils; - pfc::com_ptr_t dataobject = new ImplementCOMRefCounter< CDataObjectBase >(); - DWORD outeffect = 0; - - ToggleDDScroll(true); - DoDragDrop(dataobject.get_ptr(), source.get_ptr(), DROPEFFECT_MOVE, &outeffect); - ClearDropMark(); - ToggleDDScroll(false); - if (source->droppedAtValid ) { - CPoint pt = source->droppedAt; - WIN32_OP_D( this->ScreenToClient( &pt ) ); - ptDrop = pt; - return true; - } - return false; -} - -int CListControlWithSelectionBase::OnCreatePassThru(LPCREATESTRUCT lpCreateStruct) { - const uint32_t flags = this->QueryDragDropTypes(); - if ( flags & dragDrop_external ) { - - pfc::com_ptr_t target = new CDropTargetImpl(); - - std::shared_ptr showDropMark = std::make_shared(); - - target->HookAccept = [this, flags, showDropMark] ( IDataObject * obj ) { - *showDropMark = true; - if (this->m_ownDDActive) { - // Do not generate OnDrop for reorderings - if (flags & dragDrop_reorder) return (DWORD)DROPEFFECT_MOVE; - } - return this->DragDropAccept(obj, *showDropMark); - }; - target->HookDrop = [this, flags] ( IDataObject * obj, CPoint pt ) { - this->ClearDropMark(); - if ( this->m_ownDDActive ) { - // Do not generate OnDrop for reorderings - if ( flags & dragDrop_reorder ) return; - } - this->OnDrop( obj, pt ); - }; - target->HookLeave = [this] { - this->ClearDropMark(); - }; - - target->Track = [this, showDropMark](CPoint pt) { - if ( *showDropMark ) { - WIN32_OP_D(this->ScreenToClient(&pt)); - size_t idx = this->InsertIndexFromPoint(pt); - this->SetDropMark(idx, false); - } else { - this->ClearDropMark(); - } - }; - - RegisterDragDrop(*this, target.get_ptr() ); - } - SetMsgHandled(FALSE); return 0; -} - -void CListControlWithSelectionBase::OnDestroyPassThru() { - AbortSelectDragMode(); - ToggleDDScroll(false); - RevokeDragDrop(*this); - SetMsgHandled(FALSE); -} - -size_t CListControlWithSelectionBase::GetPasteTarget(const CPoint * ptPaste) const { - size_t target = ~0; - if (ptPaste != nullptr) { - CPoint pt(*ptPaste); WIN32_OP_D(ScreenToClient(&pt)); - int iGroup; - if (GroupHeaderFromPoint(pt, iGroup)) { - t_size base, count; - if (ResolveGroupRange(iGroup, base, count)) { - target = base; - } - } else if (ItemFromPoint(pt, target)) { - auto rc = GetItemRect(target); - auto height = rc.Height(); - if (height > 0) { - double posInItem = (double)(pt.y - rc.top) / (double)height; - if (posInItem >= 0.5) ++target; - } - } - } else if (GroupFocusActive()) { - t_size base, count; - if (ResolveGroupRange(GetGroupFocus(), base, count)) { - target = base; - } - } else { - target = GetFocusItem(); - } - return target; -} - - -pfc::bit_array_table CListControlWithSelectionImpl::GetSelectionMaskRef() { - return pfc::bit_array_table(this->GetSelectionArray(), this->GetItemCount()); -} -pfc::bit_array_bittable CListControlWithSelectionImpl::GetSelectionMask() { - pfc::bit_array_bittable ret; - const auto count = GetItemCount(); - ret.resize( GetItemCount() ); - for( size_t walk = 0; walk < count; ++ walk ) { - ret.set(walk, IsItemSelected(walk)); - } - return ret; -} - -void CListControlWithSelectionImpl::OnItemsReordered( const size_t * order, size_t count) { - PFC_ASSERT( count == GetItemCount() ); - - SelHandleReorder( order, count ); - __super::OnItemsReordered(order, count); -} - -void CListControlWithSelectionImpl::OnItemsRemoved( pfc::bit_array const & mask, size_t oldCount) { - SelHandleRemoval(mask, oldCount); - __super::OnItemsRemoved( mask, oldCount ); -} - -void CListControlWithSelectionImpl::OnItemsInserted( size_t at, size_t count, bool bSelect ) { - SelHandleInsertion( at, count, bSelect); - __super::OnItemsInserted( at, count, bSelect ); -} - -bool CListControlWithSelectionImpl::SelectAll() { - if ( m_selectionSupport != selectionSupportMulti ) return false; - return __super::SelectAll(); -} diff --git a/libPPUI/CListControlWithSelection.h b/libPPUI/CListControlWithSelection.h deleted file mode 100644 index f666069..0000000 --- a/libPPUI/CListControlWithSelection.h +++ /dev/null @@ -1,265 +0,0 @@ -#pragma once - -#include "CListControl.h" - -//! Implementation of focus/selection handling. Leaves maintaining focus/selection info to the derived class. \n -//! Most classes should derive from CListControlWithSelectionImpl instead. -class CListControlWithSelectionBase : public CListControl { -public: - typedef CListControl TParent; - CListControlWithSelectionBase() : m_selectDragMode(), m_prepareDragDropMode(), m_prepareDragDropModeRightClick(), m_ownDDActive(), m_noEnsureVisible(), m_drawThemeText(), m_typeFindTS() {} - BEGIN_MSG_MAP_EX(CListControlWithSelectionBase) - MSG_WM_CREATE(OnCreatePassThru); - MSG_WM_DESTROY(OnDestroyPassThru); - CHAIN_MSG_MAP(TParent) - MESSAGE_HANDLER(WM_LBUTTONDBLCLK,OnLButtonDblClk) - MESSAGE_HANDLER(WM_LBUTTONDOWN,OnButtonDown) - MESSAGE_HANDLER(WM_RBUTTONDOWN,OnButtonDown) - MESSAGE_HANDLER(WM_RBUTTONDBLCLK,OnButtonDown) - MESSAGE_HANDLER(WM_RBUTTONUP,OnRButtonUp) - MESSAGE_HANDLER(WM_MOUSEMOVE,OnMouseMove) - MESSAGE_HANDLER(WM_LBUTTONUP,OnLButtonUp) - MESSAGE_HANDLER(WM_KEYDOWN,OnKeyDown); - MESSAGE_HANDLER(WM_SYSKEYDOWN,OnKeyDown); - MESSAGE_HANDLER(WM_SETFOCUS,OnFocus); - MESSAGE_HANDLER(WM_KILLFOCUS,OnFocus); - MESSAGE_HANDLER(WM_TIMER,OnTimer); - MESSAGE_HANDLER(WM_CAPTURECHANGED,OnCaptureChanged); - MESSAGE_HANDLER(WM_GETDLGCODE,OnGetDlgCode); - MSG_WM_CHAR(OnChar) - END_MSG_MAP() - - virtual void SetFocusItem(t_size index) = 0; - virtual t_size GetFocusItem() const = 0; - virtual void SetGroupFocus(int group) = 0; - virtual void SetGroupFocusByItem(t_size item) = 0; - virtual int GetGroupFocus() const = 0; - virtual bool IsItemSelected(t_size index) const = 0; - virtual void SetSelection(pfc::bit_array const & affected,pfc::bit_array const & status) = 0; - void SelectSingle(size_t which); - virtual bool SelectAll(); - void SelectNone(); - virtual void RequestMoveSelection(int delta); - bool MoveSelectionProbe(int delta); - virtual void RequestReorder( size_t const * order, size_t count ) = 0; - virtual void RequestRemoveSelection() = 0; - virtual void ExecuteDefaultAction(t_size index) = 0; - virtual void ExecuteDefaultActionGroup(t_size base, t_size count) {} - virtual bool ExecuteCanvasDefaultAction(CPoint pt) { return false; } - - virtual t_size GetSelectionStart() const = 0; - virtual void SetSelectionStart(t_size val) = 0; - //! Full hook for drag-drop loop - virtual void RunDragDrop(const CPoint & p_origin,bool p_isRightClick); - - //! Should RunDragDrop() be called at all? - virtual bool IsDragDropSupported() {return QueryDragDropTypes() != 0;} - - //! Notification, mandatory to call by SetFocusItem() implementation. \n - //! If overridden by subclass, must call parent. - virtual void OnFocusChanged(size_t newFocus) {} - virtual void OnFocusChangedGroup(int inGroup) {} - //! Notification, mandatory to call by SetSelection() implementation. \n - //! If overridden by subclass, must call parent. - virtual void OnSelectionChanged(pfc::bit_array const & affected, pfc::bit_array const & status) {} - - enum { - dragDrop_reorder = 1 << 0, - dragDrop_external = 1 << 1, - }; - - virtual uint32_t QueryDragDropTypes() const { return 0; } - virtual DWORD DragDropAccept(IDataObject * obj, bool & showDropMark) { return DROPEFFECT_NONE; } - virtual pfc::com_ptr_t MakeDataObject(); - virtual void OnDrop(IDataObject * obj, CPoint pt ) {} - virtual DWORD DragDropSourceEffects() { return DROPEFFECT_MOVE | DROPEFFECT_COPY;} - virtual void DragDropSourceSucceeded( DWORD effect ) {} - - bool GroupFocusActive() const {return GetGroupFocus() >= 0;} - - void RenderOverlay(const CRect & p_updaterect,CDCHandle p_dc); - - bool IsItemFocused(t_size index) const {return GetFocusItem() == index;} - bool IsGroupHeaderFocused(int p_id) const {return GetGroupFocus() == p_id;} - void ToggleSelection(pfc::bit_array const & mask); - - size_t GetSelectedCount(pfc::bit_array const & mask,size_t max = SIZE_MAX) const; - size_t GetSelectedCount() const {return GetSelectedCount(pfc::bit_array_true());} - size_t GetSingleSel() const; - size_t GetFirstSelected() const; - size_t GetLastSelected() const; - - //! Execute default action per focus or selection depending on what's focused/selected - virtual void ExecuteDefaultActionByFocus(); - - void FocusToUpdateRgn(HRGN rgn); - - - //! Self-contained minimal drag and drop implementation for reordering list items only; dummy IDataObject presented. \n - //! Call from your override of RunDragDrop(), if p_isRightClick is false / left button clicked, never with right button clicked. \n - //! On success, use MakeDropReorderPermutation() to fetch the permutation to apply to your content. - bool RunReorderDragDrop(CPoint ptOrigin, CPoint & ptDrop); - - bool MakeDropReorderPermutation(pfc::array_t & out, CPoint ptDrop) const; - - size_t GetPasteTarget( const CPoint * ptPaste = nullptr ) const; - - CPoint GetContextMenuPoint(LPARAM lp); - CPoint GetContextMenuPoint(CPoint ptGot); - -protected: - void ToggleDDScroll(bool p_state); - void AbortSelectDragMode() {AbortSelectDragMode(false);} - void RenderDropMarkerByOffset(int offset,CDCHandle p_dc); - void RenderDropMarker(CDCHandle dc, t_size item, bool bInside); - bool RenderDropMarkerClipped(CDCHandle dc, const CRect & update, t_size item, bool bInside); - CRect DropMarkerRect(int offset) const; - int DropMarkerOffset(t_size marker) const; - void AddDropMarkToUpdateRgn(HRGN p_rgn, t_size p_index, bool bInside = false) const; - CRect DropMarkerUpdateRect(t_size index,bool bInside) const; - bool GetFocusRect(CRect & p_rect); - bool GetFocusRectAbs(CRect & p_rect); - bool IsOwnDDActive() const {return m_ownDDActive;} - - SIZE DropMarkerMargin() const; - void MakeDropMarkerPen(CPen & out) const; - - virtual void EnsureVisibleRectAbs(const CRect & p_rect); - virtual size_t EvalTypeFind(); - - virtual bool AllowRangeSelect() const { return true; } - - CRect GetWholeSelectionRectAbs() const; - - size_t GetDropMark( ) const { return m_dropMark; } - bool IsDropMarkInside( ) const { return m_dropMarkInside; } - void SetDropMark( size_t idx, bool bInside ); - void ClearDropMark() { SetDropMark(pfc_infinite, false); } -private: - int OnCreatePassThru(LPCREATESTRUCT lpCreateStruct); - void OnDestroyPassThru(); - - struct TDDScrollControl { - bool m_timerActive = false; - - enum {KTimerID = 0x35bb25af,KTimerPeriod = 25}; - }; - - enum { - KSelectionTimerID = 0xad8abd04, - KSelectionTimerPeriod = 50, - }; - - LRESULT OnFocus(UINT,WPARAM,LPARAM,BOOL&); - LRESULT OnKeyDown(UINT,WPARAM,LPARAM,BOOL&); - LRESULT OnLButtonDblClk(UINT,WPARAM,LPARAM,BOOL&); - LRESULT OnButtonDown(UINT,WPARAM,LPARAM,BOOL&); - LRESULT OnRButtonUp(UINT,WPARAM,LPARAM,BOOL&); - LRESULT OnMouseMove(UINT,WPARAM,LPARAM,BOOL&); - LRESULT OnLButtonUp(UINT,WPARAM,LPARAM,BOOL&); - LRESULT OnTimer(UINT,WPARAM,LPARAM,BOOL&); - LRESULT OnCaptureChanged(UINT,WPARAM,LPARAM,BOOL&); - LRESULT OnGetDlgCode(UINT,WPARAM,LPARAM,BOOL&); - void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags); - void RunTypeFind(); - - void OnKeyDown_HomeEndHelper(bool isEnd, int p_keys); - void OnKeyDown_SetIndexHelper(int p_index, int p_keys); - void OnKeyDown_SetIndexDeltaHelper(int p_delta, int p_keys); - void OnKeyDown_SetIndexDeltaLineHelper(int p_delta, int p_keys); - void OnKeyDown_SetIndexDeltaPageHelper(int p_delta, int p_keys); - void SelectGroupHelper(int p_group,int p_keys); - void HandleDragSel(const CPoint & p_pt); - void AbortSelectDragMode(bool p_lostCapture); - void InitSelectDragMode(const CPoint & p_pt,bool p_rightClick = false); - - void ToggleRangeSelection(pfc::bit_array const & mask); - void ToggleGroupSelection(int p_group); - - void HandleDDScroll(); - - void PrepareDragDrop(const CPoint & p_point,bool p_isRightClick); - void AbortPrepareDragDropMode(bool p_lostCapture = false); - - bool TypeFindCheck(DWORD ts = GetTickCount()) const; - - -protected: - // Spacebar handler - void ToggleSelectedItems(); - - void RenderItem(t_size p_item,const CRect & p_itemRect,const CRect & p_updateRect,CDCHandle p_dc); - void RenderGroupHeader(int p_group,const CRect & p_headerRect,const CRect & p_updateRect,CDCHandle p_dc); - void RenderSubItemText(t_size item, t_size subItem,const CRect & subItemRect,const CRect & updateRect,CDCHandle dc, bool allowColors); -private: - bool m_selectDragMode; - CPoint m_selectDragOriginAbs, m_selectDragCurrentAbs; - bool m_selectDragChanged, m_selectDragMoved; - TDDScrollControl m_ddScroll; - - bool m_prepareDragDropMode, m_prepareDragDropModeRightClick; - bool m_noEnsureVisible; - CPoint m_prepareDragDropOrigin; - - bool m_ownDDActive; - bool m_drawThemeText; - pfc::string8 m_typeFind; DWORD m_typeFindTS; - - size_t m_dropMark = SIZE_MAX; bool m_dropMarkInside = false; -}; - -//! CListControlWithSelectionImpl implements virtual methods of CListControlWithSelectionBase, -//! maintaining focus/selection info for you. -class CListControlWithSelectionImpl : public CListControlWithSelectionBase { -public: - - enum { selectionSupportNone = 0, selectionSupportSingle, selectionSupportMulti }; - unsigned m_selectionSupport = selectionSupportMulti; - - void SetSelectionModeNone() { m_selectionSupport = selectionSupportNone; } - void SetSelectionModeSingle() { m_selectionSupport = selectionSupportSingle; } - void SetSelectionModeMulti() { m_selectionSupport = selectionSupportMulti; } - - - CListControlWithSelectionImpl() {} - void SetFocusItem(t_size index); - t_size GetFocusItem() const {return m_groupFocus ? SIZE_MAX : m_focus;} - void SetGroupFocus(int group); - void SetGroupFocusByItem(t_size item); - int GetGroupFocus() const; - bool IsItemSelected(t_size index) const {return index < m_selection.get_size() ? m_selection[index] : false;} - void SetSelection(pfc::bit_array const & affected,pfc::bit_array const & status); - virtual bool CanSelectItem( size_t index ) const { return true; } - t_size GetSelectionStart() const {return m_selectionStart;} - void SetSelectionStart(t_size val) {m_selectionStart = val;} - - void SelHandleReorder(const t_size * order, t_size count); - void SelHandleRemoval(const pfc::bit_array & mask, t_size oldCount); - void SelHandleInsertion(t_size base, t_size count, bool select); - void SelHandleReset(); - - void ReloadData() override; - size_t _DebugGetItemCountSel() const { return m_selection.get_size(); } - - virtual void OnItemsReordered( const size_t* order, size_t count ) override; - virtual void OnItemsRemoved( pfc::bit_array const & mask, size_t oldCount ) override; - virtual void OnItemsInserted( size_t at, size_t count, bool bSelect ) override; - - pfc::bit_array_bittable GetSelectionMask(); // returns an standalone object holding a copy of the state - - bool SelectAll() override; - -protected: - const bool * GetSelectionArray() {RefreshSelectionSize();return m_selection.get_ptr();} - pfc::bit_array_table GetSelectionMaskRef(); // returns a *temporary* object referencing internal data structures - - bool AllowRangeSelect() const override { return m_selectionSupport == selectionSupportMulti; } - -private: - void SetSelectionImpl(pfc::bit_array const & affected,pfc::bit_array const & status); - void RefreshSelectionSize(); - void RefreshSelectionSize(t_size size); - pfc::array_t m_selection; - size_t m_focus = SIZE_MAX, m_selectionStart = SIZE_MAX; - bool m_groupFocus = false; -}; diff --git a/libPPUI/CListControl_EditImpl.h b/libPPUI/CListControl_EditImpl.h deleted file mode 100644 index 26b5961..0000000 --- a/libPPUI/CListControl_EditImpl.h +++ /dev/null @@ -1,62 +0,0 @@ -#pragma once - -#include "InPlaceEditTable.h" -#include "GDIUtils.h" // MakeTempBrush() - -//! Implements inplace-edit functionality on top of TParent class. Must derive from CListControlHeaderImpl. -template class CListControl_EditImpl : public T_CListControl_EditImpl_Parent, protected InPlaceEdit::CTableEditHelperV2 { -public: - BEGIN_MSG_MAP_EX(CListControl_EditImpl) - CHAIN_MSG_MAP(T_CListControl_EditImpl_Parent) - MESSAGE_HANDLER(WM_CTLCOLOREDIT,OnCtlColor); - MESSAGE_HANDLER(WM_CTLCOLORSTATIC,OnCtlColor); - END_MSG_MAP() - - // IMPLEMENT ME - // virtual void TableEdit_SetField(t_size item, t_size subItem, const char * value) = 0; -protected: - RECT TableEdit_GetItemRect(t_size item, t_size subItem) const override { - return this->GetSubItemRect(item,subItem); - } - void TableEdit_GetField(t_size item, t_size subItem, pfc::string_base & out, t_size & lineCount) override { - lineCount = 1; - if (!this->GetSubItemText(item,subItem,out)) { - PFC_ASSERT(!"Should not get here."); out = ""; - } - } - HWND TableEdit_GetParentWnd() const override {return this->m_hWnd;} - t_size TableEdit_GetItemCount() const override {return this->GetItemCount();} - t_size TableEdit_GetColumnCount() const override {return this->GetColumnCount();} - void TableEdit_SetItemFocus(t_size item, t_size subItem) override { - this->TooltipRemove(); - this->SetFocusItem(item); this->SetSelection(pfc::bit_array_true(), pfc::bit_array_one(item)); - auto rcView = this->GetVisibleRectAbs(); - auto rcEdit = this->GetSubItemRectAbs(item,subItem); - CRect rcTest; - if (!rcTest.IntersectRect(rcView, rcEdit)) { - // Only scroll to subitem if entirely invisible - this->EnsureVisibleRectAbs( rcEdit ); - } - } - void TableEdit_GetColumnOrder(t_size * out, t_size count) const override { - PFC_ASSERT( count == this->GetColumnCount() ); - if ( this->IsHeaderEnabled() ) { - pfc::array_t temp; temp.set_size(count); - WIN32_OP_D( this->GetHeaderCtrl().GetOrderArray(temp.get_size(), temp.get_ptr()) ); - for(t_size walk = 0; walk < count; ++walk) out[walk] = (t_size) temp[walk]; - } else { - for(t_size walk = 0; walk < count; ++walk) out[walk] = walk; - } - } - - void TableEdit_OnColorsChanged() {} -private: - LRESULT OnCtlColor(UINT,WPARAM wp,LPARAM lp,BOOL&) { - CDCHandle dc((HDC)wp); - const COLORREF bkgnd = this->GetSysColorHook(CListControlImpl::colorBackground); - dc.SetTextColor(this->GetSysColorHook(CListControlImpl::colorText)); - dc.SetBkColor(bkgnd); - - return (LRESULT) MakeTempBrush(dc, bkgnd); - } -}; diff --git a/libPPUI/CListViewCtrlEx.h b/libPPUI/CListViewCtrlEx.h deleted file mode 100644 index 82e5d69..0000000 --- a/libPPUI/CListViewCtrlEx.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -class CListViewCtrlEx : public CListViewCtrl { -public: - CListViewCtrlEx( HWND wnd = NULL ) : CListViewCtrl(wnd) {} - CListViewCtrlEx const & operator=( HWND wnd ) { m_hWnd = wnd; return *this; } - unsigned InsertColumnEx(unsigned index, const wchar_t * name, unsigned widthDLU); - unsigned AddColumnEx( const wchar_t * name, unsigned widthDLU ); - void FixContextMenuPoint( CPoint & pt ); - unsigned GetColunnCount(); - - unsigned InsertString( unsigned index, const wchar_t * str ); - unsigned InsertString8( unsigned index, const char * str ); - unsigned AddString( const wchar_t * str ); - unsigned AddString8(const char * str); - void SetItemText(unsigned item, unsigned subItem, const wchar_t * str ); - void SetItemText8(unsigned item, unsigned subItem, const char * str ); - - void AutoSizeColumn( int iCol ) { SetColumnWidth(iCol, LVSCW_AUTOSIZE) ;} - int AddGroup(int iGroupID, const wchar_t * header); -}; - -// BOOL HandleLVKeyDownMod() -#define LVN_KEYDOWN_MOD_HANDLER(id, key, mod, func) \ - if (uMsg == WM_NOTIFY && LVN_KEYDOWN == ((LPNMHDR)lParam)->code && id == ((LPNMHDR)lParam)->idFrom && ((LPNMLVKEYDOWN)lParam)->wVKey == (key) && GetHotkeyModifierFlags() == (mod)) \ - { \ - SetMsgHandled(TRUE); \ - lResult = func()?1:0; \ - if(IsMsgHandled()) \ - return TRUE; \ - } - -// BOOL HandleLVCopy() -#define LVN_COPY_HANDLER(id, func) LVN_KEYDOWN_MOD_HANDLER(id, 'C', MOD_CONTROL, func) diff --git a/libPPUI/CMiddleDragImpl.cpp b/libPPUI/CMiddleDragImpl.cpp deleted file mode 100644 index 424da28..0000000 --- a/libPPUI/CMiddleDragImpl.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "stdafx.h" -#include "CMiddleDragImpl.h" - -double CMiddleDragCommon::myPow(double p_val, double p_exp) { - if (p_val < 0) { - return -pow(-p_val, p_exp); - } else { - return pow(p_val, p_exp); - } -} - -double CMiddleDragCommon::ProcessMiddleDragDeltaInternal(double p_delta) { - p_delta *= (double)KTimerPeriod / 25; /*originally calculated for 25ms timer interval*/ - return myPow(p_delta * 0.05, 2.0); -} - -double CMiddleDragCommon::radiusHelper(double p_x, double p_y) { - return sqrt(p_x * p_x + p_y * p_y); -} -int CMiddleDragCommon::mySGN(LONG v) { - if (v > 0) return 1; - else if (v < 0) return -1; - else return 0; -} - -int32_t CMiddleDragCommon::Round(double val, double & acc) { - val += acc; - int32_t ret = (int32_t)floor(val + 0.5); - acc = val - ret; - return ret; -} - -LONG CMiddleDragCommon::LineToPixelsHelper(LONG & p_overflow, LONG p_pixels, LONG p_dpi, LONG p_lineWidth) { - const int lineWidth = MulDiv(p_lineWidth, p_dpi, 96); - if (lineWidth == 0) return 0; - p_overflow += p_pixels; - LONG ret = p_overflow / lineWidth; - p_overflow -= ret * lineWidth; - return ret; -} diff --git a/libPPUI/CPopupTooltipMessage.h b/libPPUI/CPopupTooltipMessage.h deleted file mode 100644 index b9a6c86..0000000 --- a/libPPUI/CPopupTooltipMessage.h +++ /dev/null @@ -1,101 +0,0 @@ -#pragma once - -#include "win32_op.h" -#include "wtl-pp.h" - -class CPopupTooltipMessage { -public: - CPopupTooltipMessage(DWORD style = TTS_BALLOON | TTS_NOPREFIX) : m_style(style | WS_POPUP), m_toolinfo(), m_shutDown() {} - void ShowFocus(const TCHAR * message, CWindow wndParent) { - Show(message, wndParent); wndParent.SetFocus(); - } - void Show(const TCHAR * message, CWindow wndParent) { - if (m_shutDown || (message == NULL && m_tooltip.m_hWnd == NULL)) return; - Initialize(); - Hide(); - - if (message != NULL) { - CRect rect; - WIN32_OP_D(wndParent.GetWindowRect(rect)); - ShowInternal(message, wndParent, rect); - } - } - void ShowEx(const TCHAR * message, CWindow wndParent, CRect rect) { - if (m_shutDown) return; - Initialize(); - Hide(); - ShowInternal(message, wndParent, rect); - } - void Hide() { - if (m_tooltip.m_hWnd != NULL && m_tooltip.GetToolCount() > 0) { - m_tooltip.TrackActivate(&m_toolinfo, FALSE); - m_tooltip.DelTool(&m_toolinfo); - } - } - - void CleanUp() { - if (m_tooltip.m_hWnd != NULL) { - m_tooltip.DestroyWindow(); - } - } - void ShutDown() { - m_shutDown = true; CleanUp(); - } -private: - void ShowInternal(const TCHAR * message, CWindow wndParent, CRect rect) { - - PFC_ASSERT(!m_shutDown); - PFC_ASSERT(message != NULL); - PFC_ASSERT(wndParent != NULL); - - if (_tcschr(message, '\n') != nullptr) { - m_tooltip.SetMaxTipWidth(rect.Width()); - } - m_toolinfo.cbSize = sizeof(m_toolinfo); - m_toolinfo.uFlags = TTF_TRACK | TTF_IDISHWND | TTF_ABSOLUTE | TTF_TRANSPARENT | TTF_CENTERTIP; - m_toolinfo.hwnd = wndParent; - m_toolinfo.uId = 0; - m_toolinfo.lpszText = const_cast(message); - m_toolinfo.hinst = NULL; //core_api::get_my_instance(); - if (m_tooltip.AddTool(&m_toolinfo)) { - m_tooltip.TrackPosition(rect.CenterPoint().x, rect.bottom); - m_tooltip.TrackActivate(&m_toolinfo, TRUE); - } - } - void Initialize() { - if (m_tooltip.m_hWnd == NULL) { - WIN32_OP(m_tooltip.Create(NULL, NULL, NULL, m_style)); - } - } - CContainedWindowSimpleT m_tooltip; - TOOLINFO m_toolinfo; - const DWORD m_style; - bool m_shutDown; -}; - - -template class CDialogWithTooltip : public CDialogImpl { -public: - BEGIN_MSG_MAP_EX(CDialogWithTooltip) - MSG_WM_DESTROY(OnDestroy) - END_MSG_MAP() - - void ShowTip(UINT id, const TCHAR * label) { - m_tip.Show(label, this->GetDlgItem(id)); - } - void ShowTip(HWND child, const TCHAR * label) { - m_tip.Show(label, child); - } - - void ShowTipF(UINT id, const TCHAR * label) { - m_tip.ShowFocus(label, this->GetDlgItem(id)); - } - void ShowTipF(HWND child, const TCHAR * label) { - m_tip.ShowFocus(label, child); - } - void HideTip() { m_tip.Hide(); } -private: - void OnDestroy() { m_tip.ShutDown(); this->SetMsgHandled(FALSE); } - CPopupTooltipMessage m_tip; -}; - diff --git a/libPPUI/CPropVariant.h b/libPPUI/CPropVariant.h deleted file mode 100644 index c94d97b..0000000 --- a/libPPUI/CPropVariant.h +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once - -class CPropVariant : public PROPVARIANT { -public: - CPropVariant() {init();} - ~CPropVariant() {clear();} - CPropVariant( const CPropVariant & other ) { - init(); - PropVariantCopy( this, &other ); - } - const CPropVariant& operator=( const CPropVariant & other ) { - clear(); - PropVariantCopy(this, &other); - return *this; - } - - bool toInt64(int64_t & out) const { - switch( vt ) { - case VT_I1: out = (int64_t) cVal; return true; - case VT_I2: out = (int64_t) iVal; return true; - case VT_I4: out = (int64_t) lVal; return true; - case VT_I8: out = (int64_t) hVal.QuadPart; return true; - case VT_INT: out = (int64_t) intVal; return true; - default: return false; - } - } - bool toUint64(uint64_t & out) const { - switch( vt ) { - case VT_UI1: out = (uint64_t) bVal; return true; - case VT_UI2: out = (uint64_t) uiVal; return true; - case VT_UI4: out = (uint64_t) ulVal; return true; - case VT_UI8: out = (uint64_t) uhVal.QuadPart; return true; - case VT_UINT: out = (uint64_t) uintVal; return true; - default: return false; - } - } - bool toString( pfc::string_base & out ) const { - switch( vt ) { - case VT_LPSTR: - out = pfc::stringcvt::string_utf8_from_ansi( pszVal ); return true; - case VT_LPWSTR: - out = pfc::stringcvt::string_utf8_from_wide( pwszVal ); return true; - default: return false; - } - } -private: - void clear() { - PropVariantClear( this ); - } - void init() { - PROPVARIANT * pv = this; - PropVariantInit( pv ); - } -}; diff --git a/libPPUI/CWindowCreateAndDelete.h b/libPPUI/CWindowCreateAndDelete.h deleted file mode 100644 index 3de2d5f..0000000 --- a/libPPUI/CWindowCreateAndDelete.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include "win32_op.h" - -template -class CWindowCreateAndDelete : public TClass { -public: - template CWindowCreateAndDelete(HWND parent, arg_t && ... arg) : TClass(std::forward(arg) ...) { WIN32_OP(this->Create(parent) != NULL); } -private: - void OnFinalMessage(HWND wnd) { PFC_ASSERT_NO_EXCEPTION(TClass::OnFinalMessage(wnd)); PFC_ASSERT_NO_EXCEPTION(delete this); } -}; diff --git a/libPPUI/Controls.cpp b/libPPUI/Controls.cpp deleted file mode 100644 index 0c3f29a..0000000 --- a/libPPUI/Controls.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "stdafx.h" -#include -#include "Controls.h" -#include "PaintUtils.h" - -void CStaticSeparator::OnPaint(CDCHandle) { - PaintUtils::PaintSeparatorControl(*this); -} - -void CSeparator::OnPaint(CDCHandle dc) { - PaintUtils::PaintSeparatorControl(*this); -} - -CStaticMainInstruction::CStaticMainInstruction() { - SetThemePart(TEXT_MAININSTRUCTION); -} - -void CStaticThemed::OnPaint(CDCHandle) { - if (m_fallback) { - SetMsgHandled(FALSE); return; - } - if (m_theme == NULL) { - m_theme.OpenThemeData(*this, L"TextStyle"); - if (m_theme == NULL) { - m_fallback = true; SetMsgHandled(FALSE); return; - } - } - CPaintDC dc(*this); - TCHAR buffer[512] = {}; - GetWindowText(buffer, _countof(buffer)); - const int txLen = (int) pfc::strlen_max_t(buffer, _countof(buffer)); - CRect contentRect; - WIN32_OP_D(GetClientRect(contentRect)); - SelectObjectScope scopeFont(dc, GetFont()); - dc.SetTextColor(GetSysColor(COLOR_WINDOWTEXT)); - dc.SetBkMode(TRANSPARENT); - - if (txLen > 0) { - CRect rcText(contentRect); - DWORD flags = 0; - DWORD style = GetStyle(); - if (style & SS_LEFT) flags |= DT_LEFT; - else if (style & SS_RIGHT) flags |= DT_RIGHT; - else if (style & SS_CENTER) flags |= DT_CENTER; - if (style & SS_ENDELLIPSIS) flags |= DT_END_ELLIPSIS; - - HRESULT retval = DrawThemeText(m_theme, dc, m_id, 0, buffer, txLen, flags, 0, rcText); - PFC_ASSERT(SUCCEEDED(retval)); - } -} diff --git a/libPPUI/Controls.h b/libPPUI/Controls.h deleted file mode 100644 index fb44d68..0000000 --- a/libPPUI/Controls.h +++ /dev/null @@ -1,101 +0,0 @@ -#pragma once - -#pragma comment(lib, "uxtheme.lib") - -#include "wtl-pp.h" -#include "win32_op.h" - -// Separator-in-dialog tool: subclass a static control on init -class CStaticSeparator : public CContainedWindowT, private CMessageMap { -public: - CStaticSeparator() : CContainedWindowT(this, 0) {} - BEGIN_MSG_MAP_EX(CSeparator) - MSG_WM_PAINT(OnPaint) - MSG_WM_SETTEXT(OnSetText) - END_MSG_MAP() -private: - int OnSetText(LPCTSTR lpstrText) { - Invalidate(); - SetMsgHandled(FALSE); - return 0; - } - void OnPaint(CDCHandle); -}; - -// CWindowRegistered with font & text functionality, for creating custom text label classes -template -class CTextControl : public CWindowRegisteredT { -public: - BEGIN_MSG_MAP_EX(CTextControl) - MSG_WM_SETFONT(OnSetFont) - MSG_WM_GETFONT(OnGetFont) - MSG_WM_SETTEXT(OnSetText) - CHAIN_MSG_MAP(__super) - END_MSG_MAP() -private: - HFONT OnGetFont() { - return m_font; - } - void OnSetFont(HFONT font, BOOL bRedraw) { - m_font = font; - if (bRedraw) this->Invalidate(); - } - int OnSetText(LPCTSTR lpstrText) { - this->Invalidate();this->SetMsgHandled(FALSE); return 0; - } - CFontHandle m_font; -}; - - -// Static control subclass with override for theme part used for rendering -class CStaticThemed : public CContainedWindowT, private CMessageMap { -public: - CStaticThemed() : CContainedWindowT(this, 0), m_id(), m_fallback() {} - BEGIN_MSG_MAP_EX(CStaticThemed) - MSG_WM_PAINT(OnPaint) - MSG_WM_THEMECHANGED(OnThemeChanged) - MSG_WM_SETTEXT(OnSetText) - END_MSG_MAP() - - void SetThemePart(int id) {m_id = id; if (m_hWnd != NULL) Invalidate();} -private: - int OnSetText(LPCTSTR lpstrText) { - Invalidate(); - SetMsgHandled(FALSE); - return 0; - } - void OnThemeChanged() { - m_theme.Release(); - m_fallback = false; - } - void OnPaint(CDCHandle); - int m_id; - CTheme m_theme; - bool m_fallback; -}; - -class CStaticMainInstruction : public CStaticThemed { -public: - CStaticMainInstruction(); -}; - - - -class CSeparator : public CTextControl { -public: - BEGIN_MSG_MAP_EX(CSeparator) - MSG_WM_PAINT(OnPaint) - MSG_WM_ENABLE(OnEnable) - CHAIN_MSG_MAP(__super) - END_MSG_MAP() - - static const TCHAR * GetClassName() { - return _T("foobar2000:separator"); - } -private: - void OnEnable(BOOL bEnable) { - Invalidate(); - } - void OnPaint(CDCHandle dc); -}; - diff --git a/libPPUI/IDI_SCROLL.ico b/libPPUI/IDI_SCROLL.ico deleted file mode 100644 index 23e279b..0000000 Binary files a/libPPUI/IDI_SCROLL.ico and /dev/null differ diff --git a/libPPUI/IDI_SCROLL.txt b/libPPUI/IDI_SCROLL.txt deleted file mode 100644 index 4a5dc87..0000000 --- a/libPPUI/IDI_SCROLL.txt +++ /dev/null @@ -1,3 +0,0 @@ -Icon needed by CMiddleDragImpl and things that use it - such as CListControl. -Include IDI_SCROLL.ico in your resources, with identifier set to IDI_SCROLL. -To get libPPUI to recognize your resource, include your resource.h before libPPUI headers in at least one of your source files. \ No newline at end of file diff --git a/libPPUI/InPlaceCombo.cpp b/libPPUI/InPlaceCombo.cpp deleted file mode 100644 index 41b8057..0000000 --- a/libPPUI/InPlaceCombo.cpp +++ /dev/null @@ -1,349 +0,0 @@ -#include "stdafx.h" - -#include "InPlaceEdit.h" -#include "wtl-pp.h" -#include "win32_op.h" - -#include "AutoComplete.h" -#include "CWindowCreateAndDelete.h" -#include "win32_utility.h" -#include "listview_helper.h" // ListView_GetColumnCount -#include "clipboard.h" - -#include - -#ifndef WM_MOUSEHWHEEL -#define WM_MOUSEHWHEEL 0x20E -#endif - -using namespace InPlaceEdit; - - -namespace { - - enum { - MSG_COMPLETION = WM_USER, - MSG_DISABLE_EDITING - }; - - - // Rationale: more than one HWND on the list is extremely uncommon, hence forward_list - static std::forward_list g_editboxes; - static HHOOK g_hook = NULL /*, g_keyHook = NULL*/; - - static void GAbortEditing(HWND edit, t_uint32 code) { - CWindow parent = ::GetParent(edit); - parent.SendMessage(MSG_DISABLE_EDITING); - parent.PostMessage(MSG_COMPLETION, code, 0); - } - - static void GAbortEditing(t_uint32 code) { - for (auto walk = g_editboxes.begin(); walk != g_editboxes.end(); ++walk) { - GAbortEditing(*walk, code); - } - } - - static bool IsSamePopup(CWindow wnd1, CWindow wnd2) { - return pfc::findOwningPopup(wnd1) == pfc::findOwningPopup(wnd2); - } - - static void MouseEventTest(HWND target, CPoint pt, bool isWheel) { - for (auto walk = g_editboxes.begin(); walk != g_editboxes.end(); ++walk) { - CWindow edit(*walk); - bool cancel = false; - if (target != edit && IsSamePopup(target, edit)) { - cancel = true; - } else if (isWheel) { - CWindow target2 = WindowFromPoint(pt); - if (target2 != edit && IsSamePopup(target2, edit)) { - cancel = true; - } - } - - if (cancel) GAbortEditing(edit, KEditLostFocus); - } - } - - static LRESULT CALLBACK GMouseProc(int nCode, WPARAM wParam, LPARAM lParam) { - if (nCode == HC_ACTION) { - const MOUSEHOOKSTRUCT * mhs = reinterpret_cast(lParam); - switch (wParam) { - case WM_NCLBUTTONDOWN: - case WM_NCRBUTTONDOWN: - case WM_NCMBUTTONDOWN: - case WM_NCXBUTTONDOWN: - case WM_LBUTTONDOWN: - case WM_RBUTTONDOWN: - case WM_MBUTTONDOWN: - case WM_XBUTTONDOWN: - MouseEventTest(mhs->hwnd, mhs->pt, false); - break; - case WM_MOUSEWHEEL: - case WM_MOUSEHWHEEL: - MouseEventTest(mhs->hwnd, mhs->pt, true); - break; - } - } - return CallNextHookEx(g_hook, nCode, wParam, lParam); - } - - static void on_editbox_creation(HWND p_editbox) { - // PFC_ASSERT(core_api::is_main_thread()); - g_editboxes.push_front(p_editbox); - if (g_hook == NULL) { - g_hook = SetWindowsHookEx(WH_MOUSE, GMouseProc, NULL, GetCurrentThreadId()); - } - /*if (g_keyHook == NULL) { - g_keyHook = SetWindowsHookEx(WH_KEYBOARD, GKeyboardProc, NULL, GetCurrentThreadId()); - }*/ - } - static void UnhookHelper(HHOOK & hook) { - HHOOK v = pfc::replace_null_t(hook); - if (v != NULL) UnhookWindowsHookEx(v); - } - static void on_editbox_destruction(HWND p_editbox) { - // PFC_ASSERT(core_api::is_main_thread()); - g_editboxes.remove(p_editbox); - if (g_editboxes.empty()) { - UnhookHelper(g_hook); /*UnhookHelper(g_keyHook);*/ - } - } - - class CInPlaceComboBox : public CContainedWindowSimpleT { - public: - BEGIN_MSG_MAP_EX(CInPlaceComboBox) - //MSG_WM_CREATE(OnCreate) - MSG_WM_DESTROY(OnDestroy) - MSG_WM_GETDLGCODE(OnGetDlgCode) - // MSG_WM_KILLFOCUS(OnKillFocus) - MSG_WM_KEYDOWN(OnKeyDown) - END_MSG_MAP() - - void OnCreation() { - on_editbox_creation(m_hWnd); - } - private: - void OnDestroy() { - m_selfDestruct = true; - on_editbox_destruction(m_hWnd); - SetMsgHandled(FALSE); - } - int OnCreate(LPCREATESTRUCT lpCreateStruct) { - OnCreation(); - SetMsgHandled(FALSE); - return 0; - } - UINT OnGetDlgCode(LPMSG lpMsg) { - if (lpMsg == NULL) { - SetMsgHandled(FALSE); return 0; - } else { - switch (lpMsg->message) { - case WM_KEYDOWN: - case WM_SYSKEYDOWN: - switch (lpMsg->wParam) { - case VK_TAB: - case VK_ESCAPE: - case VK_RETURN: - return DLGC_WANTMESSAGE; - default: - SetMsgHandled(FALSE); return 0; - } - default: - SetMsgHandled(FALSE); return 0; - - } - } - } - void OnKillFocus(CWindow wndFocus) { - if ( wndFocus != NULL ) ForwardCompletion(KEditLostFocus); - SetMsgHandled(FALSE); - } - - void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { - m_suppressChar = nFlags & 0xFF; - switch (nChar) { - case VK_TAB: - ForwardCompletion(IsKeyPressed(VK_SHIFT) ? KEditShiftTab : KEditTab); - return; - case VK_ESCAPE: - ForwardCompletion(KEditAborted); - return; - } - m_suppressChar = 0; - SetMsgHandled(FALSE); - } - - void ForwardCompletion(t_uint32 code) { - if (IsWindowEnabled()) { - CWindow owner = GetParent(); - owner.SendMessage(MSG_DISABLE_EDITING); - owner.PostMessage(MSG_COMPLETION, code, 0); - EnableWindow(FALSE); - } - } - - bool m_selfDestruct = false; - UINT m_suppressChar = 0; - }; - - class InPlaceComboContainer : public CWindowImpl { - public: - DECLARE_WND_CLASS_EX(_T("{18D85006-0CDB-49AB-A563-6A42014309A3}"), 0, -1); - - const pfc::string_list_const * m_initData; - const unsigned m_iDefault; - - HWND Create(CWindow parent) { - - RECT rect_cropped; - { - RECT client; - WIN32_OP_D(parent.GetClientRect(&client)); - IntersectRect(&rect_cropped, &client, &m_initRect); - } - const DWORD containerStyle = WS_BORDER | WS_CHILD; - AdjustWindowRect(&rect_cropped, containerStyle, FALSE); - - - - WIN32_OP(__super::Create(parent, rect_cropped, NULL, containerStyle) != NULL); - - try { - CRect rcClient; - WIN32_OP_D(GetClientRect(rcClient)); - - - DWORD style = WS_CHILD | WS_VISIBLE;//parent is invisible now - - style |= CBS_DROPDOWNLIST; - - - CComboBox edit; - - WIN32_OP(edit.Create(*this, rcClient, NULL, style, 0, ID_MYEDIT) != NULL); - edit.SetFont(parent.GetFont()); - - m_edit.SubclassWindow(edit); - m_edit.OnCreation(); - - -#if 0 // doesn't quite work - if (m_flags & (KFlagAlignCenter | KFlagAlignRight)) { - COMBOBOXINFO info = {sizeof(info)}; - if (m_edit.GetComboBoxInfo(&info)) { - CEdit edit2 = info.hwndList; - if (edit2) { - if (m_flags & KFlagAlignCenter) edit2.ModifyStyle(0, ES_CENTER); - else if (m_flags & KFlagAlignRight) edit2.ModifyStyle(0, ES_RIGHT); - } - } - } -#endif - - - if (m_initData != nullptr) { - const size_t count = m_initData->get_count(); - for (size_t walk = 0; walk < count; ++walk) { - m_edit.AddString(pfc::stringcvt::string_os_from_utf8(m_initData->get_item(walk))); - } - if (m_iDefault < count) m_edit.SetCurSel(m_iDefault); - } - } catch (...) { - PostMessage(MSG_COMPLETION, InPlaceEdit::KEditAborted, 0); - return m_hWnd; - } - - ShowWindow(SW_SHOW); - m_edit.SetFocus(); - - m_initialized = true; - - m_edit.ShowDropDown(); - - PFC_ASSERT(m_hWnd != NULL); - - return m_hWnd; - } - - InPlaceComboContainer(const RECT & p_rect, unsigned p_flags, pfc::string_list_const * initData, unsigned iDefault, comboReply_t p_notify) : m_notify(p_notify), m_initData(initData), m_iDefault(iDefault), m_initRect(p_rect), m_flags(p_flags) { } - - enum { ID_MYEDIT = 666 }; - - BEGIN_MSG_MAP_EX(InPlaceEditContainer) - MESSAGE_HANDLER_EX(WM_CTLCOLOREDIT, MsgForwardToParent) - MESSAGE_HANDLER_EX(WM_CTLCOLORSTATIC, MsgForwardToParent) - MESSAGE_HANDLER_EX(WM_MOUSEWHEEL, MsgLostFocus) - MESSAGE_HANDLER_EX(WM_MOUSEHWHEEL, MsgLostFocus) - MESSAGE_HANDLER_SIMPLE(MSG_DISABLE_EDITING, OnMsgDisableEditing) - MESSAGE_HANDLER_EX(MSG_COMPLETION, OnMsgCompletion) - COMMAND_ID_HANDLER_EX(ID_MYEDIT, OnComboMsg) - MSG_WM_DESTROY(OnDestroy) - END_MSG_MAP() - - HWND GetEditBox() const { return m_edit; } - - private: - void OnDestroy() { m_selfDestruct = true; } - - LRESULT MsgForwardToParent(UINT msg, WPARAM wParam, LPARAM lParam) { - return GetParent().SendMessage(msg, wParam, lParam); - } - LRESULT MsgLostFocus(UINT, WPARAM, LPARAM) { - PostMessage(MSG_COMPLETION, InPlaceEdit::KEditLostFocus, 0); - return 0; - } - void OnMsgDisableEditing() { - ShowWindow(SW_HIDE); - GetParent().UpdateWindow(); - } - LRESULT OnMsgCompletion(UINT, WPARAM wParam, LPARAM lParam) { - PFC_ASSERT(m_initialized); - if ((wParam & KEditMaskReason) != KEditLostFocus) { - GetParent().SetFocus(); - } - OnCompletion((unsigned) wParam ); - if (!m_selfDestruct) { - m_selfDestruct = true; - DestroyWindow(); - } - return 0; - } - void OnComboMsg(UINT code, int, CWindow source) { - if (m_initialized && (code == CBN_SELENDOK || code == CBN_SELENDCANCEL) ) { - PostMessage(MSG_COMPLETION, InPlaceEdit::KEditLostFocus, 0); - } - } - - private: - - void OnCompletion(unsigned p_status) { - if (!m_completed) { - m_completed = true; - if (m_notify) m_notify( p_status, m_edit.GetCurSel() ); - } - } - - const comboReply_t m_notify; - bool m_completed = false; - bool m_initialized = false; - bool m_selfDestruct = false; - const CRect m_initRect; - CInPlaceComboBox m_edit; - const unsigned m_flags; - }; - -} - -static void fail(comboReply_t p_notify) { - p_notify(KEditAborted, UINT_MAX); -} - -HWND InPlaceEdit::StartCombo(HWND p_parentwnd, const RECT & p_rect, unsigned p_flags, pfc::string_list_const & data, unsigned iDefault, comboReply_t p_notify) { - try { - PFC_ASSERT((CWindow(p_parentwnd).GetWindowLong(GWL_STYLE) & WS_CLIPCHILDREN) != 0); - return (new CWindowCreateAndDelete(p_parentwnd, p_rect, p_flags, &data, iDefault, p_notify))->GetEditBox(); - } catch (...) { - fail(p_notify); - return NULL; - } -} diff --git a/libPPUI/InPlaceEdit.cpp b/libPPUI/InPlaceEdit.cpp deleted file mode 100644 index b402769..0000000 --- a/libPPUI/InPlaceEdit.cpp +++ /dev/null @@ -1,520 +0,0 @@ -#include "stdafx.h" - -#include "InPlaceEdit.h" -#include "wtl-pp.h" -#include "win32_op.h" - -#include "AutoComplete.h" -#include "CWindowCreateAndDelete.h" -#include "win32_utility.h" -#include "listview_helper.h" // ListView_GetColumnCount -#include "clipboard.h" - -#include - -#ifndef WM_MOUSEHWHEEL -#define WM_MOUSEHWHEEL 0x20E -#endif - -using namespace InPlaceEdit; - - -namespace { - - enum { - MSG_COMPLETION = WM_USER, - MSG_DISABLE_EDITING - }; - - - // Rationale: more than one HWND on the list is extremely uncommon, hence forward_list - static std::forward_list g_editboxes; - static HHOOK g_hook = NULL /*, g_keyHook = NULL*/; - - static void GAbortEditing(HWND edit, t_uint32 code) { - CWindow parent = ::GetParent(edit); - parent.SendMessage(MSG_DISABLE_EDITING); - parent.PostMessage(MSG_COMPLETION, code, 0); - } - - static void GAbortEditing(t_uint32 code) { - for (auto walk = g_editboxes.begin(); walk != g_editboxes.end(); ++walk) { - GAbortEditing(*walk, code); - } - } - - static bool IsSamePopup(CWindow wnd1, CWindow wnd2) { - return pfc::findOwningPopup(wnd1) == pfc::findOwningPopup(wnd2); - } - - static void MouseEventTest(HWND target, CPoint pt, bool isWheel) { - for (auto walk = g_editboxes.begin(); walk != g_editboxes.end(); ++walk) { - CWindow edit(*walk); - bool cancel = false; - if (target != edit && IsSamePopup(target, edit)) { - cancel = true; - } else if (isWheel) { - CWindow target2 = WindowFromPoint(pt); - if (target2 != edit && IsSamePopup(target2, edit)) { - cancel = true; - } - } - - if (cancel) GAbortEditing(edit, KEditLostFocus); - } - } - - static LRESULT CALLBACK GMouseProc(int nCode, WPARAM wParam, LPARAM lParam) { - if (nCode == HC_ACTION) { - const MOUSEHOOKSTRUCT * mhs = reinterpret_cast(lParam); - switch (wParam) { - case WM_NCLBUTTONDOWN: - case WM_NCRBUTTONDOWN: - case WM_NCMBUTTONDOWN: - case WM_NCXBUTTONDOWN: - case WM_LBUTTONDOWN: - case WM_RBUTTONDOWN: - case WM_MBUTTONDOWN: - case WM_XBUTTONDOWN: - MouseEventTest(mhs->hwnd, mhs->pt, false); - break; - case WM_MOUSEWHEEL: - case WM_MOUSEHWHEEL: - MouseEventTest(mhs->hwnd, mhs->pt, true); - break; - } - } - return CallNextHookEx(g_hook, nCode, wParam, lParam); - } - - static void on_editbox_creation(HWND p_editbox) { - // PFC_ASSERT(core_api::is_main_thread()); - g_editboxes.push_front(p_editbox); - if (g_hook == NULL) { - g_hook = SetWindowsHookEx(WH_MOUSE, GMouseProc, NULL, GetCurrentThreadId()); - } - /*if (g_keyHook == NULL) { - g_keyHook = SetWindowsHookEx(WH_KEYBOARD, GKeyboardProc, NULL, GetCurrentThreadId()); - }*/ - } - static void UnhookHelper(HHOOK & hook) { - HHOOK v = pfc::replace_null_t(hook); - if (v != NULL) UnhookWindowsHookEx(v); - } - static void on_editbox_destruction(HWND p_editbox) { - // PFC_ASSERT(core_api::is_main_thread()); - g_editboxes.remove(p_editbox); - if (g_editboxes.empty()) { - UnhookHelper(g_hook); /*UnhookHelper(g_keyHook);*/ - } - } - - class CInPlaceEditBox : public CContainedWindowSimpleT { - public: - CInPlaceEditBox(uint32_t flags) : m_flags(flags) {} - BEGIN_MSG_MAP_EX(CInPlaceEditBox) - //MSG_WM_CREATE(OnCreate) - MSG_WM_DESTROY(OnDestroy) - MSG_WM_GETDLGCODE(OnGetDlgCode) - MSG_WM_KILLFOCUS(OnKillFocus) - MSG_WM_CHAR(OnChar) - MSG_WM_KEYDOWN(OnKeyDown) - MSG_WM_PASTE(OnPaste) - END_MSG_MAP() - - void OnCreation() { - on_editbox_creation(m_hWnd); - } - private: - void OnDestroy() { - m_selfDestruct = true; - on_editbox_destruction(m_hWnd); - SetMsgHandled(FALSE); - } - int OnCreate(LPCREATESTRUCT lpCreateStruct) { - OnCreation(); - SetMsgHandled(FALSE); - return 0; - } - UINT OnGetDlgCode(LPMSG lpMsg) { - if (lpMsg == NULL) { - SetMsgHandled(FALSE); return 0; - } else { - switch (lpMsg->message) { - case WM_KEYDOWN: - case WM_SYSKEYDOWN: - switch (lpMsg->wParam) { - case VK_TAB: - case VK_ESCAPE: - case VK_RETURN: - return DLGC_WANTMESSAGE; - default: - SetMsgHandled(FALSE); return 0; - } - default: - SetMsgHandled(FALSE); return 0; - - } - } - } - void OnKillFocus(CWindow wndFocus) { - if ( wndFocus != NULL ) ForwardCompletion(KEditLostFocus); - SetMsgHandled(FALSE); - } - - bool testPaste(const char* str) { - if (m_flags & InPlaceEdit::KFlagNumberSigned) { - if (pfc::string_is_numeric(str)) return true; - if (str[0] == '-' && pfc::string_is_numeric(str + 1) && GetWindowTextLength() == 0) return true; - return false; - } - if (m_flags & InPlaceEdit::KFlagNumber) { - return pfc::string_is_numeric(str); - } - return true; - } - - void OnPaste() { - if (m_flags & (InPlaceEdit::KFlagNumber | InPlaceEdit::KFlagNumberSigned)) { - pfc::string8 temp; - ClipboardHelper::OpenScope scope; scope.Open(m_hWnd); - if (ClipboardHelper::GetString(temp)) { - if (!testPaste(temp)) return; - } - } - // Let edit box handle it - SetMsgHandled(FALSE); - } - bool testChar(UINT nChar) { - // Allow various non text characters - if (nChar < ' ') return true; - - if (m_flags & InPlaceEdit::KFlagNumberSigned) { - if (pfc::char_is_numeric(nChar)) return true; - if (nChar == '-') { - return GetWindowTextLength() == 0; - } - return false; - } - if (m_flags & InPlaceEdit::KFlagNumber) { - return pfc::char_is_numeric(nChar); - } - return true; - } - void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) { - if (m_suppressChar != 0) { - UINT code = nFlags & 0xFF; - if (code == m_suppressChar) return; - } - - if (!testChar(nChar)) { - MessageBeep(0); - return; - } - - SetMsgHandled(FALSE); - } - void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { - m_suppressChar = nFlags & 0xFF; - switch (nChar) { - case VK_BACK: - if (GetHotkeyModifierFlags() == MOD_CONTROL) { - CEditPPHooks::DeleteLastWord(*this); - return; - } - break; - case 'A': - if (GetHotkeyModifierFlags() == MOD_CONTROL) { - this->SetSelAll(); return; - } - break; - case VK_RETURN: - if (!IsKeyPressed(VK_LCONTROL) && !IsKeyPressed(VK_RCONTROL)) { - ForwardCompletion(KEditEnter); - return; - } - break; - case VK_TAB: - ForwardCompletion(IsKeyPressed(VK_SHIFT) ? KEditShiftTab : KEditTab); - return; - case VK_ESCAPE: - ForwardCompletion(KEditAborted); - return; - } - m_suppressChar = 0; - SetMsgHandled(FALSE); - } - - void ForwardCompletion(t_uint32 code) { - if (IsWindowEnabled()) { - CWindow owner = GetParent(); - owner.SendMessage(MSG_DISABLE_EDITING); - owner.PostMessage(MSG_COMPLETION, code, 0); - EnableWindow(FALSE); - } - } - - const uint32_t m_flags; - bool m_selfDestruct = false; - UINT m_suppressChar = 0; - }; - - class InPlaceEditContainer : public CWindowImpl { - public: - DECLARE_WND_CLASS_EX(_T("{54340C80-248C-4b8e-8CD4-D624A8E9377B}"), 0, -1); - - - HWND Create(CWindow parent) { - - RECT rect_cropped; - { - RECT client; - WIN32_OP_D(parent.GetClientRect(&client)); - IntersectRect(&rect_cropped, &client, &m_initRect); - } - const DWORD containerStyle = WS_BORDER | WS_CHILD; - AdjustWindowRect(&rect_cropped, containerStyle, FALSE); - - - - WIN32_OP(__super::Create(parent, rect_cropped, NULL, containerStyle) != NULL); - - try { - CRect rcClient; - WIN32_OP_D(GetClientRect(rcClient)); - - - DWORD style = WS_CHILD | WS_VISIBLE;//parent is invisible now - if (m_flags & KFlagMultiLine) style |= WS_VSCROLL | ES_MULTILINE; - else style |= ES_AUTOHSCROLL; - if (m_flags & KFlagReadOnly) style |= ES_READONLY; - if (m_flags & KFlagAlignCenter) style |= ES_CENTER; - else if (m_flags & KFlagAlignRight) style |= ES_RIGHT; - else style |= ES_LEFT; - - // ES_NUMBER is buggy in many ways (repaint glitches after balloon popup) and does not allow signed numbers. - // We implement number handling by filtering WM_CHAR instead. - // if (m_flags & KFlagNumber) style |= ES_NUMBER; - - - CEdit edit; - - WIN32_OP(edit.Create(*this, rcClient, NULL, style, 0, ID_MYEDIT) != NULL); - edit.SetFont(parent.GetFont()); - - if (m_ACData.is_valid()) InitializeSimpleAC(edit, m_ACData.get_ptr(), m_ACOpts); - m_edit.SubclassWindow(edit); - m_edit.OnCreation(); - - pfc::setWindowText(m_edit, *m_content); - m_edit.SetSelAll(); - } catch (...) { - PostMessage(MSG_COMPLETION, InPlaceEdit::KEditAborted, 0); - return m_hWnd; - } - - ShowWindow(SW_SHOW); - m_edit.SetFocus(); - - m_initialized = true; - - PFC_ASSERT(m_hWnd != NULL); - - return m_hWnd; - } - - InPlaceEditContainer(const RECT & p_rect, t_uint32 p_flags, pfc::rcptr_t p_content, reply_t p_notify, IUnknown * ACData, DWORD ACOpts) - : m_content(p_content), m_notify(p_notify), m_completed(false), m_initialized(false), m_changed(false), m_disable_editing(false), m_initRect(p_rect), - m_flags(p_flags), m_selfDestruct(), m_ACData(ACData), m_ACOpts(ACOpts), - m_edit(p_flags) - { - } - - enum { ID_MYEDIT = 666 }; - - BEGIN_MSG_MAP_EX(InPlaceEditContainer) - MESSAGE_HANDLER_EX(WM_CTLCOLOREDIT, MsgForwardToParent) - MESSAGE_HANDLER_EX(WM_CTLCOLORSTATIC, MsgForwardToParent) - MESSAGE_HANDLER_EX(WM_MOUSEWHEEL, MsgLostFocus) - MESSAGE_HANDLER_EX(WM_MOUSEHWHEEL, MsgLostFocus) - MESSAGE_HANDLER_SIMPLE(MSG_DISABLE_EDITING, OnMsgDisableEditing) - MESSAGE_HANDLER_EX(MSG_COMPLETION, OnMsgCompletion) - COMMAND_HANDLER_EX(ID_MYEDIT, EN_CHANGE, OnEditChange) - MSG_WM_DESTROY(OnDestroy) - END_MSG_MAP() - - HWND GetEditBox() const { return m_edit; } - - private: - void OnDestroy() { m_selfDestruct = true; } - - LRESULT MsgForwardToParent(UINT msg, WPARAM wParam, LPARAM lParam) { - return GetParent().SendMessage(msg, wParam, lParam); - } - LRESULT MsgLostFocus(UINT, WPARAM, LPARAM) { - PostMessage(MSG_COMPLETION, InPlaceEdit::KEditLostFocus, 0); - return 0; - } - void OnMsgDisableEditing() { - ShowWindow(SW_HIDE); - GetParent().UpdateWindow(); - m_disable_editing = true; - } - LRESULT OnMsgCompletion(UINT, WPARAM wParam, LPARAM lParam) { - PFC_ASSERT(m_initialized); - if ((wParam & KEditMaskReason) != KEditLostFocus) { - GetParent().SetFocus(); - } - if ( m_changed && m_edit != NULL ) { - *m_content = pfc::getWindowText(m_edit); - } - OnCompletion((unsigned)wParam); - if (!m_selfDestruct) { - m_selfDestruct = true; - DestroyWindow(); - } - return 0; - } - void OnEditChange(UINT, int, CWindow source) { - if (m_initialized && !m_disable_editing) { - *m_content = pfc::getWindowText(source); - m_changed = true; - } - } - - private: - - void OnCompletion(unsigned p_status) { - if (!m_completed) { - m_completed = true; - p_status &= KEditMaskReason; - unsigned code = p_status; - if (m_changed && p_status != KEditAborted) code |= KEditFlagContentChanged; - if (m_notify) m_notify(code); - } - } - - const pfc::rcptr_t m_content; - const reply_t m_notify; - bool m_completed; - bool m_initialized, m_changed; - bool m_disable_editing; - bool m_selfDestruct; - const CRect m_initRect; - const t_uint32 m_flags; - CInPlaceEditBox m_edit; - - const pfc::com_ptr_t m_ACData; - const DWORD m_ACOpts; - }; - -} - -static void fail(reply_t p_notify) { - p_notify(KEditAborted); - // completion_notify::g_signal_completion_async(p_notify, KEditAborted); -} - -HWND InPlaceEdit::Start(HWND p_parentwnd, const RECT & p_rect, bool p_multiline, pfc::rcptr_t p_content, reply_t p_notify) { - return StartEx(p_parentwnd, p_rect, p_multiline ? KFlagMultiLine : 0, p_content, p_notify); -} - -void InPlaceEdit::Start_FromListView(HWND p_listview, unsigned p_item, unsigned p_subitem, unsigned p_linecount, pfc::rcptr_t p_content, reply_t p_notify) { - Start_FromListViewEx(p_listview, p_item, p_subitem, p_linecount, 0, p_content, p_notify); -} - -bool InPlaceEdit::TableEditAdvance_ListView(HWND p_listview, unsigned p_column_base, unsigned & p_item, unsigned & p_column, unsigned p_item_count, unsigned p_column_count, unsigned p_whathappened) { - if (p_column >= p_column_count) return false; - - - pfc::array_t orderRev; - { - pfc::array_t order; - const unsigned orderExCount = /*p_column_base + p_column_count*/ ListView_GetColumnCount(p_listview); - PFC_ASSERT(orderExCount >= p_column_base + p_column_count); - pfc::array_t orderEx; orderEx.set_size(orderExCount); - if (!ListView_GetColumnOrderArray(p_listview, orderExCount, orderEx.get_ptr())) { - PFC_ASSERT(!"Should not get here - probably mis-calculated column count"); - return false; - } - order.set_size(p_column_count); - for (unsigned walk = 0; walk < p_column_count; ++walk) order[walk] = orderEx[p_column_base + walk]; - - orderRev.set_size(p_column_count); order_helper::g_fill(orderRev); - pfc::sort_get_permutation_t(order, pfc::compare_t, p_column_count, orderRev.get_ptr()); - } - - unsigned columnVisible = (unsigned)orderRev[p_column]; - - - if (!TableEditAdvance(p_item, columnVisible, p_item_count, p_column_count, p_whathappened)) return false; - - p_column = (unsigned)order_helper::g_find_reverse(orderRev.get_ptr(), columnVisible); - - return true; -} - -bool InPlaceEdit::TableEditAdvance(unsigned & p_item, unsigned & p_column, unsigned p_item_count, unsigned p_column_count, unsigned p_whathappened) { - if (p_item >= p_item_count || p_column >= p_column_count) return false; - int delta = 0; - - switch (p_whathappened & KEditMaskReason) { - case KEditEnter: - delta = (int)p_column_count; - break; - case KEditTab: - delta = 1; - break; - case KEditShiftTab: - delta = -1; - break; - default: - return false; - } - while (delta > 0) { - p_column++; - if (p_column >= p_column_count) { - p_column = 0; - p_item++; - if (p_item >= p_item_count) return false; - } - delta--; - } - while (delta < 0) { - if (p_column == 0) { - if (p_item == 0) return false; - p_item--; - p_column = p_column_count; - } - p_column--; - delta++; - } - return true; -} - -HWND InPlaceEdit::StartEx(HWND p_parentwnd, const RECT & p_rect, unsigned p_flags, pfc::rcptr_t p_content, reply_t p_notify, IUnknown * ACData, DWORD ACOpts) { - try { - PFC_ASSERT((CWindow(p_parentwnd).GetWindowLong(GWL_STYLE) & WS_CLIPCHILDREN) != 0); - return (new CWindowCreateAndDelete(p_parentwnd, p_rect, p_flags, p_content, p_notify, ACData, ACOpts))->GetEditBox(); - } catch (...) { - fail(p_notify); - return NULL; - } -} - -void InPlaceEdit::Start_FromListViewEx(HWND p_listview, unsigned p_item, unsigned p_subitem, unsigned p_linecount, unsigned p_flags, pfc::rcptr_t p_content, reply_t p_notify) { - try { - ListView_EnsureVisible(p_listview, p_item, FALSE); - RECT itemrect; - WIN32_OP_D(ListView_GetSubItemRect(p_listview, p_item, p_subitem, LVIR_LABEL, &itemrect)); - - const bool multiline = p_linecount > 1; - if (multiline) { - itemrect.bottom = itemrect.top + (itemrect.bottom - itemrect.top) * p_linecount; - } - - StartEx(p_listview, itemrect, p_flags | (multiline ? KFlagMultiLine : 0), p_content, p_notify); - } catch (...) { - fail(p_notify); - } -} diff --git a/libPPUI/InPlaceEdit.h b/libPPUI/InPlaceEdit.h deleted file mode 100644 index 63a50e1..0000000 --- a/libPPUI/InPlaceEdit.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include - -namespace InPlaceEdit { - - enum { - KEditAborted = 0, - KEditTab, - KEditShiftTab, - KEditEnter, - KEditLostFocus, - - KEditMaskReason = 0xFF, - KEditFlagContentChanged = 0x100, - - KFlagReadOnly = 1 << 0, - KFlagMultiLine = 1 << 1, - KFlagAlignCenter = 1 << 2, - KFlagAlignRight = 1 << 3, - KFlagNumber = 1 << 4, - KFlagNumberSigned = 1 << 5, - - KFlagCombo = 1 << 8, // FOR INTERNAL USE - }; - - typedef std::function< void (unsigned) > reply_t; - - typedef std::function< void(unsigned, unsigned) > comboReply_t; // status, index (UINT_MAX if n/a) - - HWND Start(HWND p_parentwnd, const RECT & p_rect, bool p_multiline, pfc::rcptr_t p_content, reply_t p_notify); - - HWND StartEx(HWND p_parentwnd, const RECT & p_rect, unsigned p_flags, pfc::rcptr_t p_content, reply_t p_notify, IUnknown * ACData = NULL, DWORD ACOpts = 0); - - - HWND StartCombo(HWND p_parentwnd, const RECT & p_rect, unsigned p_flags, pfc::string_list_const & data, unsigned iDefault, comboReply_t p_notify); - - void Start_FromListView(HWND p_listview, unsigned p_item, unsigned p_subitem, unsigned p_linecount, pfc::rcptr_t p_content, reply_t p_notify); - void Start_FromListViewEx(HWND p_listview, unsigned p_item, unsigned p_subitem, unsigned p_linecount, unsigned p_flags, pfc::rcptr_t p_content, reply_t p_notify); - - bool TableEditAdvance(unsigned & p_item, unsigned & p_column, unsigned p_item_count, unsigned p_column_count, unsigned p_whathappened); - bool TableEditAdvance_ListView(HWND p_listview, unsigned p_column_base, unsigned & p_item, unsigned & p_column, unsigned p_item_count, unsigned p_column_count, unsigned p_whathappened); - -} diff --git a/libPPUI/InPlaceEditTable.cpp b/libPPUI/InPlaceEditTable.cpp deleted file mode 100644 index 2363ea7..0000000 --- a/libPPUI/InPlaceEditTable.cpp +++ /dev/null @@ -1,221 +0,0 @@ -#include "stdafx.h" -#include "InPlaceEditTable.h" - -#include "win32_op.h" -#include "win32_utility.h" -#include "AutoComplete.h" - -#include "listview_helper.h" - -namespace InPlaceEdit { - - bool CTableEditHelperV2::tableEdit_cancel_task() { - bool rv = false; - if (m_taskKill) { - *m_taskKill = true; m_taskKill = nullptr; - rv = true; - } - return rv; - } - reply_t CTableEditHelperV2::tableEdit_create_task() { - tableEdit_cancel_task(); - auto ks = std::make_shared(false); - m_taskKill = ks; - return [ks,this](unsigned code) { - if ( ! * ks ) { - this->tableEdit_on_task_completion( code ); - } - }; - } - t_size CTableEditHelperV2::ColumnToPosition(t_size col) const { - PFC_ASSERT(TableEdit_IsColumnEditable(col)); - pfc::array_t colOrder; GrabColumnOrder(colOrder); - t_size skipped = 0; - for (t_size walk = 0; walk < colOrder.get_size(); ++walk) { - const t_size curCol = colOrder[walk]; - if (TableEdit_IsColumnEditable(curCol)) { - if (curCol == col) return skipped; - ++skipped; - } - } - PFC_ASSERT(!"Should not get here."); - return ~0; - } - t_size CTableEditHelperV2::PositionToColumn(t_size pos) const { - pfc::array_t colOrder; GrabColumnOrder(colOrder); - t_size skipped = 0; - for (t_size walk = 0; walk < colOrder.get_size(); ++walk) { - const t_size curCol = colOrder[walk]; - if (TableEdit_IsColumnEditable(curCol)) { - if (skipped == pos) return curCol; - ++skipped; - } - } - PFC_ASSERT(!"Should not get here."); - return ~0; - } - t_size CTableEditHelperV2::EditableColumnCount() const { - const t_size total = TableEdit_GetColumnCount(); - t_size found = 0; - for (t_size walk = 0; walk < total; ++walk) { - if (TableEdit_IsColumnEditable(walk)) found++; - } - return found; - } - - bool CTableEditHelperV2::TableEdit_Advance(t_size & p_item, t_size & p_subItem, t_uint32 whathappened) { - size_t guardItem = SIZE_MAX, guardSubItem = SIZE_MAX; // infinite loop guard - size_t item = p_item, subItem = p_subItem; - for ( ;; ) { - unsigned _item((unsigned)item), _subItem((unsigned)ColumnToPosition(subItem)); - if (!InPlaceEdit::TableEditAdvance(_item, _subItem, (unsigned)TableEdit_GetItemCount(), (unsigned)EditableColumnCount(), whathappened)) return false; - item = _item; subItem = PositionToColumn(_subItem); - - if ( guardItem == SIZE_MAX ) { - guardItem = item; guardSubItem = subItem; - } else { - // infinite loop guard - if ( item == guardItem && subItem == guardSubItem ) return false; - } - - if (TableEdit_CanAdvanceHere(item, subItem, whathappened)) break; - } - p_item = item; - p_subItem = subItem; - return true; - } - - void CTableEditHelperV2::TableEdit_Abort(bool forwardContent) { - if (tableEdit_cancel_task()) { - if (forwardContent && (m_editFlags & KFlagReadOnly) == 0) { - if (m_editData.is_valid()) { - pfc::string8 temp(*m_editData); - TableEdit_SetField(m_editItem, m_editSubItem, temp); - } - } - m_editData.release(); - m_editDataCombo.reset(); - ::SetFocus(TableEdit_GetParentWnd()); - TableEdit_Finished(); - } - - } - - void CTableEditHelperV2::TableEdit_Start(t_size item, t_size subItem) { - PFC_ASSERT(TableEdit_IsColumnEditable(subItem)); - m_editItem = item; m_editSubItem = subItem; - _ReStart(); - } - - void CTableEditHelperV2::_ReStart() { - PFC_ASSERT(m_editItem < TableEdit_GetItemCount()); - PFC_ASSERT(m_editSubItem < TableEdit_GetColumnCount()); - - TableEdit_SetItemFocus(m_editItem, m_editSubItem); - - m_editFlags = TableEdit_GetEditFlags(m_editItem, m_editSubItem); - - m_editData.release(); - m_editDataCombo.reset(); - - if (m_editFlags & InPlaceEdit::KFlagCombo) { - auto combo = TableEdit_GetCombo(m_editItem, m_editSubItem); - RECT rc = TableEdit_GetItemRect(m_editItem, m_editSubItem); - - auto data = std::make_shared< combo_t >(combo); - m_editDataCombo = data; - - auto task = tableEdit_create_task(); - auto comboTask = [data, task](unsigned status, unsigned sel) { - data->iDefault = sel; - task(status); - }; - - InPlaceEdit::StartCombo(TableEdit_GetParentWnd(), rc, m_editFlags, combo.strings, combo.iDefault, comboTask ); - return; - } - - m_editData.new_t(); - t_size lineCount = 1; - TableEdit_GetField(m_editItem, m_editSubItem, *m_editData, lineCount); - - RECT rc = TableEdit_GetItemRect(m_editItem, m_editSubItem); - if (lineCount > 1) { - rc.bottom = (LONG)( rc.top + (rc.bottom - rc.top) * lineCount ); - m_editFlags |= KFlagMultiLine; - } - auto ac = this->TableEdit_GetAutoCompleteEx(m_editItem, m_editSubItem ); - InPlaceEdit::StartEx(TableEdit_GetParentWnd(), rc, m_editFlags, m_editData, tableEdit_create_task(), ac.data.get_ptr(), ac.options); - } - - CTableEditHelperV2::combo_t CTableEditHelperV2::TableEdit_GetCombo(size_t item, size_t sub) { - return combo_t(); - } - CTableEditHelperV2::autoComplete_t CTableEditHelperV2::TableEdit_GetAutoCompleteEx( size_t item, size_t sub ) { - autoComplete_t ret; - if ( this->TableEdit_GetAutoComplete( item, sub, ret.data ) ) ret.options = ret.optsDefault; - return ret; - } - - void CTableEditHelperV2::tableEdit_on_task_completion(unsigned status) { - tableEdit_cancel_task(); - if (m_editData.is_valid()) { - if (status & InPlaceEdit::KEditFlagContentChanged) { - TableEdit_SetField(m_editItem, m_editSubItem, *m_editData); - } - m_editData.release(); - } - if (m_editDataCombo != nullptr) { - unsigned idx = m_editDataCombo->iDefault; - if ( idx < m_editDataCombo->strings.get_count()) { - const char * text = m_editDataCombo->strings.get_item(idx); - TableEdit_SetField(m_editItem, m_editSubItem, text); - } - - m_editDataCombo.reset(); - } - - if (TableEdit_Advance(m_editItem, m_editSubItem, status)) { - _ReStart(); - } else { - TableEdit_Finished(); - } - } - - - - - - void CTableEditHelperV2_ListView::TableEdit_GetColumnOrder(t_size * out, t_size count) const { - pfc::array_t temp; temp.set_size(count); - WIN32_OP_D(ListView_GetColumnOrderArray(TableEdit_GetParentWnd(), count, temp.get_ptr())); - for (t_size walk = 0; walk < count; ++walk) out[walk] = temp[walk]; - } - - RECT CTableEditHelperV2_ListView::TableEdit_GetItemRect(t_size item, t_size subItem) const { - RECT rc; - WIN32_OP_D(ListView_GetSubItemRect(TableEdit_GetParentWnd(), (int)item, (int)subItem, LVIR_LABEL, &rc)); - return rc; - } - - void CTableEditHelperV2_ListView::TableEdit_GetField(t_size item, t_size subItem, pfc::string_base & out, t_size & lineCount) { - listview_helper::get_item_text(TableEdit_GetParentWnd(), (int)item, (int)subItem, out); - lineCount = pfc::is_multiline(out) ? 5 : 1; - } - void CTableEditHelperV2_ListView::TableEdit_SetField(t_size item, t_size subItem, const char * value) { - WIN32_OP_D(listview_helper::set_item_text(TableEdit_GetParentWnd(), (int)item, (int)subItem, value)); - } - t_size CTableEditHelperV2_ListView::TableEdit_GetItemCount() const { - LRESULT temp; - WIN32_OP_D((temp = ListView_GetItemCount(TableEdit_GetParentWnd())) >= 0); - return (t_size)temp; - } - void CTableEditHelperV2_ListView::TableEdit_SetItemFocus(t_size item, t_size subItem) { - WIN32_OP_D(listview_helper::select_single_item(TableEdit_GetParentWnd(), (int) item)); - } - - t_size CTableEditHelperV2_ListView::TableEdit_GetColumnCount() const { - return (t_size)ListView_GetColumnCount(TableEdit_GetParentWnd()); - } - -} diff --git a/libPPUI/InPlaceEditTable.h b/libPPUI/InPlaceEditTable.h deleted file mode 100644 index 9697478..0000000 --- a/libPPUI/InPlaceEditTable.h +++ /dev/null @@ -1,87 +0,0 @@ -#pragma once - -#include -#include "InPlaceEdit.h" - -namespace InPlaceEdit { - class NOVTABLE CTableEditHelperV2 { - public: - virtual RECT TableEdit_GetItemRect(t_size item, t_size subItem) const = 0; - virtual void TableEdit_GetField(t_size item, t_size subItem, pfc::string_base & out, t_size & lineCount) = 0; - virtual void TableEdit_SetField(t_size item, t_size subItem, const char * value) = 0; - virtual HWND TableEdit_GetParentWnd() const = 0; - virtual bool TableEdit_Advance(t_size & item, t_size & subItem, t_uint32 whathappened); - virtual bool TableEdit_CanAdvanceHere( size_t item, size_t subItem, uint32_t whatHappened ) const { return true; } - virtual void TableEdit_Finished() {} - virtual t_size TableEdit_GetItemCount() const = 0; - virtual t_size TableEdit_GetColumnCount() const = 0; - virtual void TableEdit_SetItemFocus(t_size item, t_size subItem) = 0; - virtual bool TableEdit_IsColumnEditable(t_size subItem) const { return true; } - virtual void TableEdit_GetColumnOrder(t_size * out, t_size count) const { order_helper::g_fill(out, count); } - virtual t_uint32 TableEdit_GetEditFlags(t_size item, t_size subItem) const { return 0; } - virtual bool TableEdit_GetAutoComplete(t_size item, t_size subItem, pfc::com_ptr_t & out) { return false; } - - struct autoComplete_t { - pfc::com_ptr_t data; - enum { // ACO_* equivalents - optsNone = 0, - optsDefault = 1, - optsAutoSuggest = 1, - optsAutoAppend = 3, - }; - DWORD options = optsNone; - }; - virtual autoComplete_t TableEdit_GetAutoCompleteEx( size_t item, size_t sub ); - - struct combo_t { - unsigned iDefault = 0; - pfc::string_list_impl strings; - }; - - virtual combo_t TableEdit_GetCombo(size_t item, size_t sub); - - void TableEdit_Start(t_size item, t_size subItem); - void TableEdit_Abort(bool forwardContent); - bool TableEdit_IsActive() const { return !!m_taskKill; } - protected: - ~CTableEditHelperV2() { tableEdit_cancel_task(); } - CTableEditHelperV2() {} - private: - void tableEdit_on_task_completion(unsigned p_status); - reply_t tableEdit_create_task(); - bool tableEdit_cancel_task(); - - t_size ColumnToPosition(t_size col) const; - t_size PositionToColumn(t_size pos) const; - t_size EditableColumnCount() const; - void GrabColumnOrder(pfc::array_t & buffer) const { buffer.set_size(TableEdit_GetColumnCount()); TableEdit_GetColumnOrder(buffer.get_ptr(), buffer.get_size()); } - void _ReStart(); - - t_size m_editItem, m_editSubItem; - t_uint32 m_editFlags; - pfc::rcptr_t m_editData; - std::shared_ptr< combo_t > m_editDataCombo; - - std::shared_ptr m_taskKill; - - CTableEditHelperV2( const CTableEditHelperV2 & ) = delete; - void operator=( const CTableEditHelperV2 & ) = delete; - }; - - - - - class NOVTABLE CTableEditHelperV2_ListView : public CTableEditHelperV2 { - public: - RECT TableEdit_GetItemRect(t_size item, t_size subItem) const override; - void TableEdit_GetField(t_size item, t_size subItem, pfc::string_base & out, t_size & lineCount) override; - void TableEdit_SetField(t_size item, t_size subItem, const char * value) override; - - t_size TableEdit_GetColumnCount() const override; - - t_size TableEdit_GetItemCount() const override; - void TableEdit_SetItemFocus(t_size item, t_size subItem) override; - - void TableEdit_GetColumnOrder(t_size * out, t_size count) const override; - }; -} diff --git a/libPPUI/PaintUtils.cpp b/libPPUI/PaintUtils.cpp deleted file mode 100644 index a8ae2cb..0000000 --- a/libPPUI/PaintUtils.cpp +++ /dev/null @@ -1,502 +0,0 @@ -#include "stdafx.h" -#include - -#include "PaintUtils.h" -#include "gdiplus_helpers.h" -// #include -// #include - -#include "GDIUtils.h" -#include "win32_op.h" -#include "wtl-pp.h" - -namespace PaintUtils { - static t_uint16 extractChannel16(t_uint32 p_color,int p_which) throw() { - return (t_uint16)( ((p_color >> (p_which * 8)) & 0xFF) << 8 ); - } - - static t_uint8 extractbyte(t_uint32 p_val,t_size p_which) throw() { - return (t_uint8) ( (p_val >> (p_which * 8)) & 0xFF ); - } - - t_uint32 BlendColorEx(t_uint32 p_color1, t_uint32 p_color2, double mix) throw() { - PFC_ASSERT(mix >= 0 && mix <= 1); - t_uint32 ret = 0; - for(t_size walk = 0; walk < 3; ++walk) { - int val1 = extractbyte(p_color1,walk), val2 = extractbyte(p_color2,walk); - int val = val1 + pfc::rint32((val2 - val1) * mix); - ret |= (t_uint32)val << (walk * 8); - } - return ret; - } - t_uint32 BlendColor(t_uint32 p_color1, t_uint32 p_color2, int p_percentage) throw() { - PFC_ASSERT(p_percentage <= 100); - t_uint32 ret = 0; - for(t_size walk = 0; walk < 3; ++walk) { - int val1 = extractbyte(p_color1,walk), val2 = extractbyte(p_color2,walk); - int val = val1 + MulDiv(val2 - val1,p_percentage,100); - ret |= (t_uint32)val << (walk * 8); - } - return ret; - } - t_uint32 DriftColor(t_uint32 p_color,unsigned p_delta,bool p_direction) throw() { - t_uint32 ret = 0; - for(t_size walk = 0; walk < 3; ++walk) { - unsigned val = extractbyte(p_color,walk); - if (p_direction) val = 0xFF - val; - if (val < p_delta) val = p_delta; - val += p_delta; - if (val > 0xFF) val = 0xFF; - if (p_direction) val = 0xFF - val; - ret |= (t_uint32)val << (walk * 8); - } - return ret; - } - - void FillVertexColor(TRIVERTEX & p_vertex,t_uint32 p_color,t_uint16 p_alpha) throw() { - p_vertex.Red = extractChannel16(p_color,0); - p_vertex.Green = extractChannel16(p_color,1); - p_vertex.Blue = extractChannel16(p_color,2); - p_vertex.Alpha = p_alpha; - } - - void FillRectSimple(CDCHandle p_dc,const CRect & p_rect,t_uint32 p_color) throw() { - p_dc.FillSolidRect(p_rect, p_color); - } - - void GradientFillRect(CDCHandle p_dc,const CRect & p_rect,t_uint32 p_color1, t_uint32 p_color2, bool p_horizontal) throw() { - TRIVERTEX verticies[2]; - GRADIENT_RECT element = {0,1}; - FillVertexColor(verticies[0],p_color1); - FillVertexColor(verticies[1],p_color2); - verticies[0].x = p_rect.left; verticies[0].y = p_rect.top; - verticies[1].x = p_rect.right; verticies[1].y = p_rect.bottom; - WIN32_OP_D( p_dc.GradientFill(verticies,tabsize(verticies),&element,1,p_horizontal ? GRADIENT_FILL_RECT_H : GRADIENT_FILL_RECT_V) ); - } - - void GradientSplitRect(CDCHandle p_dc,const CRect & p_rect,t_uint32 p_bkColor, t_uint32 p_gradientColor,int p_splitPercent) throw() { - const long split = p_rect.top + MulDiv(p_rect.Height(),p_splitPercent,100); - CRect rcTemp; - rcTemp = p_rect; - rcTemp.bottom = split; - GradientFillRect(p_dc,rcTemp,p_bkColor,p_gradientColor,false); - rcTemp = p_rect; - rcTemp.top = split; - GradientFillRect(p_dc,rcTemp,p_gradientColor,p_bkColor,false); - } - - void GradientBar(CDCHandle p_dc,const CRect & p_rect,t_uint32 p_exterior, t_uint32 p_interior, int p_percentage) throw() { - const int gradientPix = MulDiv(p_rect.Height(),p_percentage,100); - CRect rcTemp; - - rcTemp = p_rect; - rcTemp.bottom = rcTemp.top + gradientPix; - GradientFillRect(p_dc,rcTemp,p_exterior,p_interior,false); - - rcTemp = p_rect; - rcTemp.top += gradientPix; rcTemp.bottom -= gradientPix; - FillRectSimple(p_dc,rcTemp,p_interior); - - rcTemp = p_rect; - rcTemp.top = rcTemp.bottom - gradientPix; - GradientFillRect(p_dc,rcTemp,p_interior,p_exterior,false); - } - - void RenderItemBackground(CDCHandle p_dc,const CRect & p_itemRect,t_size p_item,t_uint32 p_color) throw() { - const DWORD bkColor_base = p_color; - const DWORD bkColor = DriftColor(bkColor_base,3, (p_item&1) != 0); - - //GradientSplitRect(p_dc,p_itemRect,bkColor,BlendColor(bkColor,textColor,7),80); - GradientBar(p_dc,p_itemRect,bkColor_base,bkColor,10); - } - - double Luminance(t_uint32 color) throw() { - double r = extractbyte(color,0), g = extractbyte(color,1), b = extractbyte(color,2); - return (0.2126 * r + 0.7152 * g + 0.0722 * b) / 255.0; - //return (r * 0.3 + g * 0.59 + b * 0.11) / 255.0; - } - t_uint32 DetermineTextColor(t_uint32 bk) throw() { - double l = Luminance(bk); - if ( l > 0.6 ) { - return 0; // black - } else { - return 0xFFFFFF; // white - } - } - - void AddRectToRgn(HRGN p_rgn,CRect const & p_rect) throw() { - CRgn temp; - WIN32_OP_D( temp.CreateRectRgnIndirect(p_rect) != NULL ); - CRgnHandle(p_rgn).CombineRgn(temp,RGN_OR); - } - - void FocusRect2(CDCHandle dc, CRect const & rect, COLORREF bkColor) throw() { - COLORREF txColor = DetermineTextColor( bkColor ); - COLORREF useColor = BlendColor(bkColor, txColor, 50); - CDCBrush brush(dc, useColor); - WIN32_OP_D( dc.FrameRect(rect,brush) ); - } - void FocusRect(CDCHandle dc, CRect const & rect) throw() { - CDCBrush brush(dc, 0x7F7F7F); - WIN32_OP_D( dc.FrameRect(rect,brush) ); - //dc.DrawFocusRect(rect); - } - - namespace TrackBar { - void DrawThumb(HTHEME theme,HDC dc,int state,const RECT * rcThumb, const RECT * rcUpdate) { - if (theme == NULL) { - RECT blah = *rcThumb; - int flags = DFCS_BUTTONPUSH; - switch(state) { - case TUS_NORMAL: - break; - case TUS_DISABLED: - flags |= DFCS_INACTIVE; - break; - case TUS_PRESSED: - flags |= DFCS_PUSHED; - break; - } - DrawFrameControl(dc,&blah,DFC_BUTTON,flags); - } else { - DrawThemeBackground(theme,dc,TKP_THUMB,state,rcThumb,rcUpdate); - } - } - void DrawTrack(HTHEME theme,HDC dc,const RECT * rcTrack, const RECT * rcUpdate) { - if (theme == NULL) { - RECT blah = *rcTrack; - DrawFrameControl(dc,&blah,DFC_BUTTON,DFCS_BUTTONPUSH|DFCS_PUSHED); - } else { - DrawThemeBackground(theme,dc,TKP_TRACK,TKS_NORMAL,rcTrack,rcUpdate); - } - } - - void DrawTrackVolume(HTHEME theme,HDC p_dc,const RECT * rcTrack, const RECT * rcUpdate) { - CMemoryDC dc(p_dc,CRect(rcUpdate)); - CRect rc(*rcTrack); - CRect update(*rcUpdate); - - WIN32_OP_D( dc.BitBlt(update.left,update.top,update.Width(),update.Height(),p_dc,update.left,update.top,SRCCOPY) ); - - - - /*CDCHandle dc(p_dc); - CPen pen; pen.CreatePen(PS_SOLID,1, GetSysColor(COLOR_GRAYTEXT)); - SelectObjectScope scope(dc, pen); - dc.MoveTo(rc.left,rc.bottom); - dc.LineTo(rc.right,rc.bottom); - dc.LineTo(rc.right,rc.top); - dc.LineTo(rc.left,rc.bottom);*/ - - //DrawTrack(theme,dc,rcTrack,rcUpdate); - - try { - Gdiplus::Point points[] = { Gdiplus::Point(rc.left, rc.bottom), Gdiplus::Point(rc.right, rc.bottom), Gdiplus::Point(rc.right, rc.top) } ; - GdiplusErrorHandler eh; - Gdiplus::Graphics graphics(dc); - eh << graphics.GetLastStatus(); - Gdiplus::Color c; - c.SetFromCOLORREF( GetSysColor(COLOR_BTNHIGHLIGHT) ); - Gdiplus::Pen penHL(c); - c.SetFromCOLORREF( GetSysColor(COLOR_BTNSHADOW) ); - Gdiplus::Pen penSH(c); - eh << graphics.SetSmoothingMode(Gdiplus::SmoothingModeHighQuality); - //graphics.DrawPolygon(&pen,points,tabsize(points)); - eh << graphics.DrawLine(&penSH, points[0], points[0] + Gdiplus::Point(0,-1)); - eh << graphics.DrawLine(&penHL, points[0], points[1]); - eh << graphics.DrawLine(&penHL, points[1], points[2]); - eh << graphics.DrawLine(&penSH, points[2], points[0] + Gdiplus::Point(0,-1)); - } catch(std::exception const & e) { - (void) e; - // console::print(e.what()); - } - } - } - - void DrawSmoothedLine(HDC dc, CPoint pt1, CPoint pt2, COLORREF col, double width) { - try { - Gdiplus::Point points[] = { Gdiplus::Point(pt1.x,pt1.y), Gdiplus::Point(pt2.x,pt2.y) }; - GdiplusErrorHandler eh; - Gdiplus::Graphics graphics(dc); - eh << graphics.GetLastStatus(); - Gdiplus::Color c; - c.SetFromCOLORREF( col ); - Gdiplus::Pen pen(c, (Gdiplus::REAL)( width )); - eh << graphics.SetSmoothingMode(Gdiplus::SmoothingModeHighQuality); - //graphics.DrawPolygon(&pen,points,tabsize(points)); - eh << graphics.DrawLine(&pen, points[0], points[1]); - } catch(std::exception const & e) { - (void) e; - // console::print(e.what()); - } - } - - - - static int get_text_width(HDC dc,const TCHAR * src,int len) { - if (len<=0) return 0; - else { - SIZE goatse; - GetTextExtentPoint32(dc,src,len,&goatse); - return goatse.cx; - } - } - - static t_uint32 TextOutColors_TranslateColor(const t_uint32 colors[3], int offset) { - const double v = (double)offset / 3.0; - if (v <= -1) return colors[0]; - else if (v < 0) return BlendColorEx(colors[0], colors[1], v + 1); - else if (v == 0) return colors[1]; - else if (v < 1) return BlendColorEx(colors[1], colors[2], v); - else return colors[2]; - } - - void TextOutColors_StripCodesAppend(pfc::string_formatter & out, const char * in) { - t_size done = 0, walk = 0; - for(;;) { - if (in[walk] == 0) { - if (walk > done) out.add_string_nc(in + done, walk - done); - return; - } - if ((unsigned)in[walk] < 32) { - if (walk > done) {out.add_string_nc(in + done, walk - done);} - done = walk + 1; - } - ++walk; - } - } - void TextOutColors_StripCodes(pfc::string_formatter & out, const char * in) { - out.reset(); TextOutColors_StripCodesAppend(out, in); - } - - static bool IsControlChar(TCHAR c) { - return (unsigned)c < 32; - } - static int MatchTruncat(HDC dc, int & pixels, const TCHAR * text, int textLen) { - int min = 0, max = textLen; - int minWidth = 0; - while(min + 1 < max) { - const int probe = (min + max) / 2; - CSize size; - WIN32_OP( GetTextExtentPoint32(dc, text, probe, &size) ); - if (size.cx <= pixels) {min = probe; minWidth = size.cx;} - else max = probe; - } - pixels = minWidth; - return min; - } - static int TruncatHeadroom(HDC dc) { - CSize size; - WIN32_OP( GetTextExtentPoint32(dc, _T("\x2026"), 1, &size) ); - return size.cx; - } - static void ExtTextOut_Truncat(HDC dc, int x, int y, CRect const & clip, const TCHAR * text, int textLen) { - int width = pfc::max_t(0, clip.right - x - TruncatHeadroom(dc)); - int truncat = MatchTruncat(dc, width, text, textLen); - WIN32_OP( ExtTextOut(dc, x, y, ETO_CLIPPED, &clip, text, truncat, NULL) ); - WIN32_OP( ExtTextOut(dc, x + width, y, ETO_CLIPPED, &clip, _T("\x2026"), 1, NULL) ); - - - } - bool TextContainsCodes(const TCHAR * src) { - for(;;) { - if (*src == 0) return false; - if ((unsigned)*src < 32) return true; - ++src; - } - } - void TextOutColorsEx(HDC dc,const TCHAR * src,const CRect & target,DWORD flags,const t_uint32 colors[3]) { - if (!TextContainsCodes(src)) { - SetTextColorScope cs(dc, colors[1]); - CRect rc(target); - CDCHandle(dc).DrawText(src,(int)_tcslen(src),rc,DT_NOPREFIX | DT_END_ELLIPSIS | DT_SINGLELINE | DT_VCENTER | flags); - } else { - const CSize textSize = PaintUtils::TextOutColors_CalcSize(dc, src); - CPoint origin = target.TopLeft(); - origin.y = (target.top + target.bottom - textSize.cy) / 2; - switch(flags & (DT_LEFT | DT_RIGHT | DT_CENTER)) { - case DT_LEFT: - break; - case DT_RIGHT: - if (textSize.cx < target.Width()) origin.x = target.right - textSize.cx; - break; - case DT_CENTER: - if (textSize.cx < target.Width()) origin.x = (target.right + target.left - textSize.cx) / 2; - break; - } - TextOutColors(dc, src, (int)_tcslen(src), origin, target, colors); - } - } - void TextOutColors(HDC dc,const TCHAR * src,int len,CPoint offset,const CRect & clip,const t_uint32 colors[3], int tabWidthTotal, int tabWidthDiv) { - SetTextAlign(dc,TA_LEFT); - SetBkMode(dc,TRANSPARENT); - - - int walk = 0; - int position = offset.x; - int colorOffset = 0; - int tabs = 0; - int positionTabDelta = 0; - - for(;;) { - int base = walk; - while(walk < len && !IsControlChar(src[walk])) ++walk; - if (walk>base) { - SetTextColor(dc,TextOutColors_TranslateColor(colors, colorOffset)); - int width = get_text_width(dc,src+base,walk-base); - if (position + width > clip.right) { - ExtTextOut_Truncat(dc, position, offset.y, clip, src + base, walk - base); - return; - } - WIN32_OP( ExtTextOut(dc,position,offset.y,ETO_CLIPPED,&clip,src+base,walk-base,0) ); - position += width; - } - if (walk>=len) break; - - while(walk < len && IsControlChar(src[walk])) { - if (src[walk] == TextOutColors_Dim) --colorOffset; - else if (src[walk] == TextOutColors_Highlight) ++colorOffset; - else if (src[walk] == '\t') { - int newDelta = MulDiv(++tabs, tabWidthTotal, tabWidthDiv); - position += newDelta - positionTabDelta; - positionTabDelta = newDelta; - } - walk++; - } - } - } - - CSize TextOutColors_CalcSize(HDC dc, const TCHAR * src) { - CSize acc(0,0); - for(int walk = 0;;) { - const int done = walk; - while(!IsControlChar(src[walk])) ++walk; - if (walk > done) { - CSize temp; - WIN32_OP( GetTextExtentPoint32(dc,src + done, walk - done, &temp) ); - acc.cx += temp.cx; pfc::max_acc(acc.cy, temp.cy); - } - if (src[walk] == 0) return acc; - while(src[walk] != 0 && IsControlChar(src[walk])) ++walk; - } - } - t_uint32 TextOutColors_CalcWidth(HDC dc, const TCHAR * src) { - t_uint32 acc = 0; - for(int walk = 0;;) { - const int done = walk; - while(!IsControlChar(src[walk])) ++walk; - acc += get_text_width(dc, src + done, walk - done); - if (src[walk] == 0) return acc; - while(src[walk] != 0 && IsControlChar(src[walk])) ++walk; - } - } - static const unsigned Marker_Dim = '<', Marker_Highlight = '>'; - - pfc::string TextOutColors_ImportScript(pfc::string script) { - pfc::string_formatter temp; TextOutColors_ImportScript(temp, script.ptr()); return temp.get_ptr(); - } - void TextOutColors_ImportScript(pfc::string_base & out, const char * in) { - out.reset(); - for(;;) { - t_size delta; t_uint32 c; - delta = pfc::utf8_decode_char(in, c); - if (delta == 0) break; - switch(c) { - case '>': - c = PaintUtils::TextOutColors_Highlight; - break; - case '<': - c = PaintUtils::TextOutColors_Dim; - break; - } - out.add_char(c); - in += delta; - } - } - t_uint32 DrawText_TranslateHeaderAlignment(t_uint32 val) { - switch(val & HDF_JUSTIFYMASK) { - case HDF_LEFT: - default: - return DT_LEFT; - case HDF_RIGHT: - return DT_RIGHT; - case HDF_CENTER: - return DT_CENTER; - } - } - - void RenderButton(HWND wnd_, HDC dc_, CRect rcUpdate, bool bPressed) { - CDCHandle dc(dc_); CWindow wnd(wnd_); - CTheme theme; theme.OpenThemeData(wnd, L"BUTTON"); - - RelayEraseBkgnd(wnd, wnd.GetParent(), dc); - - const int part = BP_PUSHBUTTON; - - enum { - stNormal = PBS_NORMAL, - stHot = PBS_HOT, - stDisabled = PBS_DISABLED, - stPressed = PBS_PRESSED, - }; - - int state = 0; - if (!wnd.IsWindowEnabled()) state = stDisabled; - else if (bPressed) state = stPressed; - else state = stNormal; - - CRect rcClient; WIN32_OP_D( wnd.GetClientRect(rcClient) ); - - if (theme != NULL && IsThemePartDefined(theme, part, 0)) { - DrawThemeBackground(theme, dc, part, state, rcClient, &rcUpdate); - } else { - int stateEx = DFCS_BUTTONPUSH; - switch(state) { - case stPressed: stateEx |= DFCS_PUSHED; break; - case stDisabled: stateEx |= DFCS_INACTIVE; break; - } - DrawFrameControl(dc, rcClient, DFC_BUTTON, stateEx); - } - } - - - void PaintSeparatorControl(HWND wnd_) { - CWindow wnd(wnd_); - CPaintDC dc(wnd); - TCHAR buffer[512] = {}; - wnd.GetWindowText(buffer, _countof(buffer)); - const int txLen = (int) pfc::strlen_max_t(buffer, _countof(buffer)); - CRect contentRect; - WIN32_OP_D(wnd.GetClientRect(contentRect)); - - dc.SetTextColor(GetSysColor(COLOR_WINDOWTEXT)); - dc.SetBkMode(TRANSPARENT); - - { - CBrushHandle brush = (HBRUSH)wnd.GetParent().SendMessage(WM_CTLCOLORSTATIC, (WPARAM)(HDC)dc, (LPARAM)wnd.m_hWnd); - if (brush != NULL) dc.FillRect(contentRect, brush); - } - SelectObjectScope scopeFont(dc, wnd.GetFont()); - - if (txLen > 0) { - CRect rcText(contentRect); - if (!wnd.IsWindowEnabled()) { - dc.SetTextColor(GetSysColor(COLOR_GRAYTEXT)); - } - WIN32_OP_D(dc.DrawText(buffer, txLen, rcText, DT_NOPREFIX | DT_END_ELLIPSIS | DT_SINGLELINE | DT_VCENTER | DT_LEFT) > 0); - // WIN32_OP_D( dc.GrayString(NULL, NULL, (LPARAM) buffer, txLen, rcText.left, rcText.top, rcText.Width(), rcText.Height() ) ); - } - - SIZE txSize, probeSize; - const TCHAR probe[] = _T("#"); - if (dc.GetTextExtent(buffer, txLen, &txSize) && dc.GetTextExtent(probe, _countof(probe), &probeSize)) { - int spacing = txSize.cx > 0 ? (probeSize.cx / 4) : 0; - if (txSize.cx + spacing < contentRect.Width()) { - const CPoint center = contentRect.CenterPoint(); - CRect rcEdge(contentRect.left + txSize.cx + spacing, center.y, contentRect.right, contentRect.bottom); - WIN32_OP_D(dc.DrawEdge(rcEdge, EDGE_ETCHED, BF_TOP)); - } - } - } -} - diff --git a/libPPUI/PaintUtils.h b/libPPUI/PaintUtils.h deleted file mode 100644 index 995826b..0000000 --- a/libPPUI/PaintUtils.h +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once - -#include - -namespace PaintUtils { - t_uint32 BlendColor(t_uint32 p_color1, t_uint32 p_color2, int p_percentage = 50) throw(); - t_uint32 BlendColorEx(t_uint32 p_color1, t_uint32 p_color2, double mix = 0.5) throw(); - t_uint32 DriftColor(t_uint32 p_color,unsigned p_delta,bool p_direction) throw(); - void FillVertexColor(TRIVERTEX & p_vertex,t_uint32 p_color,t_uint16 p_alpha = 0) throw(); - void FillRectSimple(CDCHandle p_dc,const CRect & p_rect,t_uint32 p_color) throw(); - void GradientFillRect(CDCHandle p_dc,const CRect & p_rect,t_uint32 p_color1, t_uint32 p_color2, bool p_horizontal) throw(); - void GradientSplitRect(CDCHandle p_dc,const CRect & p_rect,t_uint32 p_bkColor, t_uint32 p_gradientColor,int p_splitPercent) throw(); - void GradientBar(CDCHandle p_dc,const CRect & p_rect,t_uint32 p_exterior, t_uint32 p_interior, int p_percentage) throw(); - void RenderItemBackground(CDCHandle p_dc,const CRect & p_itemRect,t_size p_item,t_uint32 p_color) throw(); - - t_uint32 DetermineTextColor(t_uint32 background) throw(); - double Luminance(t_uint32 color) throw(); - - void AddRectToRgn(HRGN rgn, CRect const & rect) throw(); - - void FocusRect(CDCHandle dc, CRect const & rect) throw(); - void FocusRect2(CDCHandle dc, CRect const & rect, COLORREF bkColor) throw(); - - namespace TrackBar { - void DrawThumb(HTHEME theme,HDC dc,int state,const RECT * rcThumb, const RECT * rcUpdate); - void DrawTrack(HTHEME theme,HDC dc,const RECT * rcTrack, const RECT * rcUpdate); - void DrawTrackVolume(HTHEME theme,HDC dc,const RECT * rcTrack, const RECT * rcUpdate); - }; - - void DrawSmoothedLine(HDC dc, CPoint p1, CPoint p2, COLORREF col, double width); - - enum { - TextOutColors_Dim = 21, - TextOutColors_Highlight = 22, - }; - void TextOutColors(HDC dc,const TCHAR * src,int len,CPoint offset,const CRect & clip,const t_uint32 colors[3], int tabWidthTotal = 0, int tabWidthDiv = 1); - void TextOutColorsEx(HDC dc,const TCHAR * src,const CRect & target,DWORD flags,const t_uint32 colors[3]); - void TextOutColors_StripCodesAppend(pfc::string_formatter & out, const char * in); - void TextOutColors_StripCodes(pfc::string_formatter & out, const char * in); - - t_uint32 TextOutColors_CalcWidth(HDC dc, const TCHAR * src); - CSize TextOutColors_CalcSize(HDC dc, const TCHAR * src); - - pfc::string TextOutColors_ImportScript(pfc::string script); - void TextOutColors_ImportScript(pfc::string_base & out, const char * in); - - bool TextContainsCodes(const TCHAR * src); - - t_uint32 DrawText_TranslateHeaderAlignment(t_uint32 val); - - void RenderButton(HWND wnd_, HDC dc_, CRect rcUpdate, bool bPressed); - void PaintSeparatorControl(HWND wnd_); -} diff --git a/libPPUI/TreeMultiSel.h b/libPPUI/TreeMultiSel.h deleted file mode 100644 index aa031e0..0000000 --- a/libPPUI/TreeMultiSel.h +++ /dev/null @@ -1,397 +0,0 @@ -#pragma once - -// ================================================================================ -// CTreeMultiSel -// Implementation of multi-selection in a tree view ctrl -// Instantiate with dialog ID of your treeview, -// plug into your dialog's message map. -// Doesn't work correctly with explorer-themed tree controls (glitches happen). -// ================================================================================ - -#include -#include - -class CTreeMultiSel : public CMessageMap { -public: - typedef std::set selection_t; - typedef std::vector selectionOrdered_t; - - CTreeMultiSel(unsigned ID) : m_ID(ID) {} - - BEGIN_MSG_MAP_EX(CTreeMultiSel) - NOTIFY_HANDLER_EX(m_ID, TVN_ITEMEXPANDED, OnItemExpanded) - NOTIFY_HANDLER_EX(m_ID, NM_CLICK, OnClick) - NOTIFY_HANDLER_EX(m_ID, TVN_DELETEITEM, OnItemDeleted) - NOTIFY_HANDLER_EX(m_ID, TVN_SELCHANGING, OnSelChanging) - NOTIFY_HANDLER_EX(m_ID, TVN_SELCHANGED, OnSelChangedFilter) - NOTIFY_HANDLER_EX(m_ID, NM_SETFOCUS, OnFocus) - NOTIFY_HANDLER_EX(m_ID, NM_KILLFOCUS, OnFocus) - END_MSG_MAP() - - const unsigned m_ID; - - // Retrieves selected items - on order of appearance in the view - selectionOrdered_t GetSelectionOrdered(CTreeViewCtrl tree) const { - HTREEITEM first = tree.GetRootItem(); - selectionOrdered_t ret; ret.reserve( m_selection.size() ); - for(HTREEITEM walk = first; walk != NULL; walk = tree.GetNextVisibleItem(walk)) { - if (m_selection.count(walk) > 0) ret.push_back( walk ); - } - return ret; - } - - //! Undefined order! Use only when order of selected items is not relevant. - selection_t GetSelection() const { return m_selection; } - selection_t const & GetSelectionRef() const { return m_selection; } - bool IsItemSelected(HTREEITEM item) const {return m_selection.count(item) > 0;} - size_t GetSelCount() const {return m_selection.size();} - //! Retrieves a single-selection item. Null if nothing or more than one item is selected. - HTREEITEM GetSingleSel() const { - if (m_selection.size() != 1) return NULL; - return *m_selection.begin(); - } - - void OnContextMenu_FixSelection(CTreeViewCtrl tree, CPoint pt) { - if (pt != CPoint(-1, -1)) { - WIN32_OP_D(tree.ScreenToClient(&pt)); - UINT flags = 0; - const HTREEITEM item = tree.HitTest(pt, &flags); - if (item != NULL && (flags & TVHT_ONITEM) != 0) { - if (!IsItemSelected(item)) { - SelectSingleItem(tree, item); - } - CallSelectItem(tree, item); - } - } - } - - void OnLButtonDown(CTreeViewCtrl tree, WPARAM wp, LPARAM lp) { - if (!IsKeyPressed(VK_CONTROL)) { - UINT flags = 0; - HTREEITEM item = tree.HitTest(CPoint(lp), &flags); - if (item != NULL && (flags & TVHT_ONITEM) != 0) { - if (!IsItemSelected(item)) tree.SelectItem(item); - } - } - } - static bool IsNavKey(UINT vk) { - switch(vk) { - case VK_UP: - case VK_DOWN: - case VK_RIGHT: - case VK_LEFT: - case VK_PRIOR: - case VK_NEXT: - case VK_HOME: - case VK_END: - return true; - default: - return false; - } - } - BOOL OnChar(CTreeViewCtrl tree, WPARAM code) { - switch(code) { - case ' ': - if (IsKeyPressed(VK_CONTROL) || !IsTypingInProgress()) { - HTREEITEM item = tree.GetSelectedItem(); - if (item != NULL) SelectToggleItem(tree, item); - return TRUE; - } - break; - } - m_lastTypingTime = GetTickCount(); m_lastTypingTimeValid = true; - return FALSE; - } - BOOL OnKeyDown(CTreeViewCtrl tree, UINT vKey) { - if (IsNavKey(vKey)) m_lastTypingTimeValid = false; - switch(vKey) { - case VK_UP: - if (IsKeyPressed(VK_CONTROL)) { - HTREEITEM item = tree.GetSelectedItem(); - if (item != NULL) { - HTREEITEM prev = tree.GetPrevVisibleItem(item); - if (prev != NULL) { - CallSelectItem(tree, prev); - if (IsKeyPressed(VK_SHIFT)) { - if (m_selStart == NULL) m_selStart = item; - SelectItemRange(tree, prev); - } - } - } - return TRUE; - } - break; - case VK_DOWN: - if (IsKeyPressed(VK_CONTROL)) { - HTREEITEM item = tree.GetSelectedItem(); - if (item != NULL) { - HTREEITEM next = tree.GetNextVisibleItem(item); - if (next != NULL) { - CallSelectItem(tree, next); - if (IsKeyPressed(VK_SHIFT)) { - if (m_selStart == NULL) m_selStart = item; - SelectItemRange(tree, next); - } - } - } - return TRUE; - } - break; - /*case VK_LEFT: - if (IsKeyPressed(VK_CONTROL)) { - tree.SendMessage(WM_HSCROLL, SB_LINEUP, 0); - } - break; - case VK_RIGHT: - if (IsKeyPressed(VK_CONTROL)) { - tree.SendMessage(WM_HSCROLL, SB_LINEDOWN, 0); - } - break;*/ - } - return FALSE; - } -private: - LRESULT OnFocus(LPNMHDR hdr) { - if ( m_selection.size() > 100 ) { - CTreeViewCtrl tree(hdr->hwndFrom); - tree.RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_ERASE); - } else if (m_selection.size() > 0) { - CTreeViewCtrl tree(hdr->hwndFrom); - CRgn rgn; rgn.CreateRectRgn(0,0,0,0); - for(auto walk = m_selection.begin(); walk != m_selection.end(); ++walk) { - CRect rc; - if (tree.GetItemRect(*walk, rc, TRUE)) { - CRgn temp; temp.CreateRectRgnIndirect(rc); - rgn.CombineRgn(temp, RGN_OR); - } - } - tree.RedrawWindow(NULL, rgn, RDW_INVALIDATE | RDW_ERASE); - } - SetMsgHandled(FALSE); - return 0; - } - void CallSelectItem(CTreeViewCtrl tree, HTREEITEM item) { - const bool was = m_ownSelChange; m_ownSelChange = true; - tree.SelectItem(item); - m_ownSelChange = was; - } - LRESULT OnSelChangedFilter(LPNMHDR) { - if (m_ownSelChangeNotify) SetMsgHandled(FALSE); - return 0; - } - LRESULT OnItemDeleted(LPNMHDR pnmh) { - const HTREEITEM item = reinterpret_cast(pnmh)->itemOld.hItem; - m_selection.erase( item ); - if (m_selStart == item) m_selStart = NULL; - SetMsgHandled(FALSE); - return 0; - } - LRESULT OnItemExpanded(LPNMHDR pnmh) { - NMTREEVIEW * info = reinterpret_cast(pnmh); - CTreeViewCtrl tree ( pnmh->hwndFrom ); - if ((info->itemNew.state & TVIS_EXPANDED) == 0) { - if (DeselectChildren( tree, info->itemNew.hItem )) { - SendOnSelChanged(tree); - } - } - SetMsgHandled(FALSE); - return 0; - } - - BOOL HandleClick(CTreeViewCtrl tree, CPoint pt) { - UINT htFlags = 0; - HTREEITEM item = tree.HitTest(pt, &htFlags); - if (item != NULL && (htFlags & TVHT_ONITEM) != 0) { - if (IsKeyPressed(VK_CONTROL)) { - SelectToggleItem(tree, item); - return TRUE; - } else if (item == tree.GetSelectedItem() && !IsItemSelected(item)) { - SelectToggleItem(tree, item); - return TRUE; - } else { - //tree.SelectItem(item); - return FALSE; - } - } else { - return FALSE; - } - } - - LRESULT OnClick(LPNMHDR pnmh) { - CPoint pt(GetMessagePos()); - CTreeViewCtrl tree ( pnmh->hwndFrom ); - WIN32_OP_D ( tree.ScreenToClient( &pt ) ); - return HandleClick(tree, pt) ? 1 : 0; - } - - LRESULT OnSelChanging(LPNMHDR pnmh) { - if (!m_ownSelChange) { - //console::formatter() << "OnSelChanging"; - NMTREEVIEW * info = reinterpret_cast(pnmh); - CTreeViewCtrl tree ( pnmh->hwndFrom ); - const HTREEITEM item = info->itemNew.hItem; - - if (IsTypingInProgress()) { - SelectSingleItem(tree, item); - } else if (IsKeyPressed(VK_SHIFT)) { - SelectItemRange(tree, item); - } else if (IsKeyPressed(VK_CONTROL)) { - SelectToggleItem(tree, item); - } else { - SelectSingleItem(tree, item); - } - } - return 0; - } - - void SelectItemRange(CTreeViewCtrl tree, HTREEITEM item) { - if (m_selStart == NULL || m_selStart == item) { - SelectSingleItem(tree, item); - return; - } - - selection_t newSel = GrabRange(tree, m_selStart, item ); - ApplySelection(tree, newSel); - } - static selection_t GrabRange(CTreeViewCtrl tree, HTREEITEM item1, HTREEITEM item2) { - selection_t range1, range2; - HTREEITEM walk1 = item1, walk2 = item2; - for(;;) { - if (walk1 != NULL) { - range1.insert( walk1 ); - if (walk1 == item2) { - return range1; - } - walk1 = tree.GetNextVisibleItem(walk1); - } - if (walk2 != NULL) { - range2.insert( walk2 ); - if (walk2 == item1) { - return range2; - } - walk2 = tree.GetNextVisibleItem(walk2); - } - if (walk1 == NULL && walk2 == NULL) { - // should not get here - return selection_t(); - } - } - } - void SelectToggleItem(CTreeViewCtrl tree, HTREEITEM item) { - m_selStart = item; - if ( IsItemSelected( item ) ) { - m_selection.erase( item ); - } else { - m_selection.insert( item ); - } - UpdateItem(tree, item); - } -public: - void SelectSingleItem(CTreeViewCtrl tree, HTREEITEM item) { - m_selStart = item; - if (m_selection.size() == 1 && *m_selection.begin() == item) return; - DeselectAll(tree); SelectItem(tree, item); - } - - void ApplySelection(CTreeViewCtrl tree, selection_t const & newSel) { - CRgn updateRgn; - bool changed = false; - if (newSel.size() != m_selection.size() && newSel.size() + m_selection.size() > 100) { - // don't bother with regions - changed = true; - } else { - WIN32_OP_D(updateRgn.CreateRectRgn(0, 0, 0, 0) != NULL); - for (auto walk = m_selection.begin(); walk != m_selection.end(); ++walk) { - if (newSel.count(*walk) == 0) { - changed = true; - CRect rc; - if (tree.GetItemRect(*walk, rc, TRUE)) { - CRgn temp; WIN32_OP_D(temp.CreateRectRgnIndirect(rc)); - WIN32_OP_D(updateRgn.CombineRgn(temp, RGN_OR) != ERROR); - } - } - } - for (auto walk = newSel.begin(); walk != newSel.end(); ++walk) { - if (m_selection.count(*walk) == 0) { - changed = true; - CRect rc; - if (tree.GetItemRect(*walk, rc, TRUE)) { - CRgn temp; WIN32_OP_D(temp.CreateRectRgnIndirect(rc)); - WIN32_OP_D(updateRgn.CombineRgn(temp, RGN_OR) != ERROR); - } - } - } - } - if (changed) { - m_selection = newSel; - tree.RedrawWindow(NULL, updateRgn); - SendOnSelChanged(tree); - } - } - - void DeselectItem(CTreeViewCtrl tree, HTREEITEM item) { - if (IsItemSelected(item)) { - m_selection.erase(item); UpdateItem(tree, item); - } - } - void SelectItem(CTreeViewCtrl tree, HTREEITEM item) { - if (!IsItemSelected(item)) { - m_selection.insert(item); UpdateItem(tree, item); - } - } - - void DeselectAll(CTreeViewCtrl tree) { - if (m_selection.size() == 0) return; - CRgn updateRgn; - if (m_selection.size() <= 100) { - WIN32_OP_D(updateRgn.CreateRectRgn(0, 0, 0, 0) != NULL); - for (auto walk = m_selection.begin(); walk != m_selection.end(); ++walk) { - CRect rc; - if (tree.GetItemRect(*walk, rc, TRUE)) { - CRgn temp; WIN32_OP_D(temp.CreateRectRgnIndirect(rc)); - WIN32_OP_D(updateRgn.CombineRgn(temp, RGN_OR) != ERROR); - } - } - } - m_selection.clear(); - tree.RedrawWindow(NULL, updateRgn); - } -private: - void UpdateItem(CTreeViewCtrl tree, HTREEITEM item) { - CRect rc; - if (tree.GetItemRect(item, rc, TRUE) ) { - tree.RedrawWindow(rc); - } - SendOnSelChanged(tree); - } - void SendOnSelChanged(CTreeViewCtrl tree) { - NMHDR hdr = {}; - hdr.code = TVN_SELCHANGED; - hdr.hwndFrom = tree; - hdr.idFrom = m_ID; - const bool was = m_ownSelChangeNotify; m_ownSelChangeNotify = true; - tree.GetParent().SendMessage(WM_NOTIFY, m_ID, (LPARAM) &hdr ); - m_ownSelChangeNotify = was; - } - - bool DeselectChildren( CTreeViewCtrl tree, HTREEITEM item ) { - bool state = false; - for(HTREEITEM walk = tree.GetChildItem( item ); walk != NULL; walk = tree.GetNextSiblingItem( walk ) ) { - if (m_selection.erase(walk) > 0) state = true; - if (m_selStart == walk) m_selStart = NULL; - if (tree.GetItemState( walk, TVIS_EXPANDED ) ) { - if (DeselectChildren( tree, walk )) state = true; - } - } - return state; - } - - bool IsTypingInProgress() const { - return m_lastTypingTimeValid && (GetTickCount() - m_lastTypingTime < 500); - } - - selection_t m_selection; - HTREEITEM m_selStart = NULL; - bool m_ownSelChangeNotify = false, m_ownSelChange = false; - DWORD m_lastTypingTime = 0; bool m_lastTypingTimeValid = false; -}; diff --git a/libPPUI/TypeFind.cpp b/libPPUI/TypeFind.cpp deleted file mode 100644 index 05205f1..0000000 --- a/libPPUI/TypeFind.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include "stdafx.h" -#include "TypeFind.h" -#include "SmartStrStr.h" - -static size_t _ItemCount(HWND wnd) { - return ListView_GetItemCount(wnd); -} - -static const wchar_t * _ItemText(wchar_t * buffer, int bufSize, HWND wnd, size_t index, int subItem) { - NMLVDISPINFO info = {}; - info.hdr.code = LVN_GETDISPINFO; - info.hdr.idFrom = GetDlgCtrlID(wnd); - info.hdr.hwndFrom = wnd; - info.item.iItem = (int) index; - info.item.iSubItem = subItem; - info.item.mask = LVIF_TEXT; - info.item.pszText = buffer; - info.item.cchTextMax = bufSize; - ::SendMessage(::GetParent(wnd), WM_NOTIFY, info.hdr.idFrom, reinterpret_cast(&info)); - if (info.item.pszText == NULL) return L""; - if ( bufSize > 0 && info.item.pszText == buffer ) buffer[ bufSize - 1 ] = 0; - return info.item.pszText; -} - -LRESULT TypeFind::Handler(NMHDR* hdr, int subItemFrom, int subItemCnt) { - NMLVFINDITEM * info = reinterpret_cast(hdr); - const HWND wnd = hdr->hwndFrom; - if (info->lvfi.flags & LVFI_NEARESTXY) return -1; - const size_t count = _ItemCount(wnd); - if (count == 0) return -1; - const size_t base = (size_t)info->iStart % count; - - static SmartStrStr tool; - - enum { - bufSize = 1024, - }; - wchar_t textBuf[bufSize]; - - for (size_t walk = 0; walk < count; ++walk) { - const size_t index = (walk + base) % count; - for (int subItem = subItemFrom; subItem < subItemFrom + subItemCnt; ++subItem) { - if (tool.matchHereW(_ItemText(textBuf, bufSize, wnd, index, subItem), info->lvfi.psz)) return (LRESULT)index; - } - } - for (size_t walk = 0; walk < count; ++walk) { - const size_t index = (walk + base) % count; - for (int subItem = subItemFrom; subItem < subItemFrom + subItemCnt; ++subItem) { - if (tool.strStrEndW(_ItemText(textBuf, bufSize, wnd, index, subItem), info->lvfi.psz)) return (LRESULT)index; - } - } - return -1; -} diff --git a/libPPUI/commandline_parser.cpp b/libPPUI/commandline_parser.cpp deleted file mode 100644 index 74db7a7..0000000 --- a/libPPUI/commandline_parser.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "stdafx.h" -#include "commandline_parser.h" - -commandline_parser::commandline_parser() { - init(pfc::stringcvt::string_utf8_from_os(GetCommandLine())); -} - -void commandline_parser::init(const char * cmd) -{ - pfc::string8_fastalloc temp; - pfc::chain_list_v2_t out; - while(*cmd) - { - temp.reset(); - while(*cmd && *cmd!=' ') - { - if (*cmd=='\"') - { - cmd++; - while(*cmd && *cmd!='\"') temp.add_byte(*(cmd++)); - if (*cmd == '\"') cmd++; - } - else temp.add_byte(*(cmd++)); - } - out.insert_last(temp); - while(*cmd==' ') cmd++; - } - pfc::list_to_array(m_data,out); -} - -size_t commandline_parser::find_param(const char * ptr) const { - for(size_t n=1;n m_data; -}; diff --git a/libPPUI/gdiplus-helpers-webp.h b/libPPUI/gdiplus-helpers-webp.h deleted file mode 100644 index d78f894..0000000 --- a/libPPUI/gdiplus-helpers-webp.h +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once - -#include "gdiplus_helpers.h" - -// Presumes prior #include of webp/decode.h - -static bool IsImageWebP(const void * ptr, size_t bytes) { - if (bytes < 12) return false; - return memcmp(ptr, "RIFF", 4) == 0 && memcmp((const char*)ptr + 8, "WEBP", 4) == 0; -} - - -// WebP-aware GdiplusImageFromMem -static Gdiplus::Image * GdiplusImageFromMem2(const void * ptr, size_t bytes) { - GdiplusErrorHandler EH; - using namespace Gdiplus; - if (IsImageWebP(ptr, bytes)) { - WebPBitstreamFeatures bs; - if (WebPGetFeatures((const uint8_t*)ptr, bytes, &bs) != VP8_STATUS_OK) { - throw std::runtime_error("WebP decoding failure"); - } - const Gdiplus::PixelFormat pf = bs.has_alpha ? PixelFormat32bppARGB : PixelFormat32bppRGB; - const int pfBytes = 4; // Gdiplus RGB is 4 bytes - int w = 0, h = 0; - // ALWAYS decode BGRA, Gdiplus will disregard alpha if was not originally present - uint8_t * decodedData = WebPDecodeBGRA((const uint8_t*)ptr, bytes, &w, &h); - pfc::onLeaving scope([decodedData] {WebPFree(decodedData); }); - if (decodedData == nullptr || w <= 0 || h <= 0) throw std::runtime_error("WebP decoding failure"); - - pfc::ptrholder_t ret = new Gdiplus::Bitmap(w, h, pf); - EH << ret->GetLastStatus(); - Rect rc(0, 0, w, h); - Gdiplus::BitmapData bitmapData; - EH << ret->LockBits(&rc, 0, pf, &bitmapData); - uint8_t * target = (uint8_t*)bitmapData.Scan0; - const uint8_t * source = decodedData; - for (int y = 0; y < h; ++y) { - memcpy(target, source, w * pfBytes); - target += bitmapData.Stride; - source += pfBytes * w; - } - EH << ret->UnlockBits(&bitmapData); - return ret.detach(); - } - return GdiplusImageFromMem(ptr, bytes); -} diff --git a/libPPUI/gdiplus_helpers.h b/libPPUI/gdiplus_helpers.h deleted file mode 100644 index e2d30a4..0000000 --- a/libPPUI/gdiplus_helpers.h +++ /dev/null @@ -1,233 +0,0 @@ -#pragma once -#include - -#include "win32_op.h" -#include "win32_utility.h" - -class GdiplusErrorHandler { -public: - void operator<<(Gdiplus::Status p_code) { - if (p_code != Gdiplus::Ok) { - throw pfc::exception(PFC_string_formatter() << "Gdiplus error (" << (unsigned) p_code << ")"); - } - } -}; - -class GdiplusScope { -public: - GdiplusScope() { - Gdiplus::GdiplusStartupInput input; - Gdiplus::GdiplusStartupOutput output; - GdiplusErrorHandler() << Gdiplus::GdiplusStartup(&m_token,&input,&output); - } - ~GdiplusScope() { - Gdiplus::GdiplusShutdown(m_token); - } - static void Once() { - static bool done = _Once(); - } -private: - static bool _Once() { - ULONG_PTR token = 0; - Gdiplus::GdiplusStartupInput input; - Gdiplus::GdiplusStartupOutput output; - GdiplusErrorHandler() << Gdiplus::GdiplusStartup(&token, &input, &output); - return true; - } - GdiplusScope( const GdiplusScope & ) = delete; - void operator=( const GdiplusScope & ) = delete; - - ULONG_PTR m_token = 0; -}; - -static HBITMAP GdiplusLoadBitmap(UINT id, const TCHAR * resType, CSize size) { - using namespace Gdiplus; - try { - auto stream = WinLoadResourceAsStream(GetThisModuleHandle(), MAKEINTRESOURCE(id), resType ); - - GdiplusErrorHandler EH; - pfc::ptrholder_t source = new Image(stream); - - EH << source->GetLastStatus(); - pfc::ptrholder_t resized = new Bitmap(size.cx, size.cy, PixelFormat32bppARGB); - EH << resized->GetLastStatus(); - - { - pfc::ptrholder_t target = new Graphics(resized.get_ptr()); - EH << target->GetLastStatus(); - EH << target->SetInterpolationMode(InterpolationModeHighQuality); - EH << target->Clear(Color(0,0,0,0)); - EH << target->DrawImage(source.get_ptr(), Rect(0,0,size.cx,size.cy)); - } - - HBITMAP bmp = NULL; - EH << resized->GetHBITMAP(Gdiplus::Color::White, & bmp ); - return bmp; - } catch(...) { - PFC_ASSERT( !"Should not get here"); - return NULL; - } -} - -static Gdiplus::Image * GdiplusImageFromMem(const void * ptr, size_t bytes) { - using namespace Gdiplus; - GdiplusErrorHandler EH; - pfc::ptrholder_t source; - - { - pfc::com_ptr_t stream; - stream.attach( SHCreateMemStream((const BYTE*)ptr, pfc::downcast_guarded(bytes)) ); - if (stream.is_empty()) throw std::bad_alloc(); - source = new Image(stream.get_ptr()); - } - - EH << source->GetLastStatus(); - return source.detach(); -} - -static Gdiplus::Bitmap * GdiplusResizeImage( Gdiplus::Image * source, CSize size ) { - using namespace Gdiplus; - GdiplusErrorHandler EH; - pfc::ptrholder_t resized = new Bitmap(size.cx, size.cy, PixelFormat32bppARGB); - EH << resized->GetLastStatus(); - pfc::ptrholder_t target = new Graphics(resized.get_ptr()); - EH << target->GetLastStatus(); - EH << target->SetInterpolationMode(InterpolationModeHighQuality); - EH << target->Clear(Color(0, 0, 0, 0)); - EH << target->DrawImage(source, Rect(0, 0, size.cx, size.cy)); - return resized.detach(); -} - -static HICON GdiplusLoadIconFromMem( const void * ptr, size_t bytes, CSize size ) { - using namespace Gdiplus; - try { - - GdiplusErrorHandler EH; - pfc::ptrholder_t source = GdiplusImageFromMem(ptr, bytes); - pfc::ptrholder_t resized = GdiplusResizeImage( source.get_ptr(), size ); - HICON icon = NULL; - EH << resized->GetHICON(&icon); - return icon; - } catch (...) { - PFC_ASSERT(!"Should not get here"); - return NULL; - } -} - -static HICON GdiplusLoadIcon(UINT id, const TCHAR * resType, CSize size) { - using namespace Gdiplus; - try { - auto stream = WinLoadResourceAsStream(GetThisModuleHandle(), MAKEINTRESOURCE(id), resType); - - GdiplusErrorHandler EH; - pfc::ptrholder_t source = new Image(stream); - - EH << source->GetLastStatus(); - pfc::ptrholder_t resized = new Bitmap(size.cx, size.cy, PixelFormat32bppARGB); - EH << resized->GetLastStatus(); - - { - pfc::ptrholder_t target = new Graphics(resized.get_ptr()); - EH << target->GetLastStatus(); - EH << target->SetInterpolationMode(InterpolationModeHighQuality); - EH << target->Clear(Color(0,0,0,0)); - EH << target->DrawImage(source.get_ptr(), Rect(0,0,size.cx,size.cy)); - } - - HICON icon = NULL; - EH << resized->GetHICON(&icon); - return icon; - } catch(...) { - PFC_ASSERT( !"Should not get here"); - return NULL; - } -} -static HICON GdiplusLoadPNGIcon(UINT id, CSize size) {return GdiplusLoadIcon(id, _T("PNG"), size);} - -static HICON LoadPNGIcon(UINT id, CSize size) { - GdiplusScope scope; - return GdiplusLoadPNGIcon(id, size); -} - -static void GdiplusLoadButtonPNG(CIcon & icon, HWND btn_, UINT image) { - CButton btn(btn_); - if (icon == NULL) { - CRect client; WIN32_OP_D( btn.GetClientRect(client) ); - CSize size = client.Size(); - int v = MulDiv(pfc::min_t(size.cx, size.cy), 3, 4); - if (v < 8) v = 8; - icon = GdiplusLoadPNGIcon(image, CSize(v,v)); - } - btn.SetIcon(icon); -} - -static Gdiplus::Bitmap * GdiplusLoadResource(UINT id, const TCHAR * resType) { - using namespace Gdiplus; - GdiplusErrorHandler EH; - - auto stream = WinLoadResourceAsStream(GetThisModuleHandle(), MAKEINTRESOURCE(id), resType); - pfc::ptrholder_t img = new Bitmap(stream); - EH << img->GetLastStatus(); - return img.detach(); -} - -static Gdiplus::Bitmap * GdiplusLoadResourceAsSize(UINT id, const TCHAR * resType, CSize size) { - using namespace Gdiplus; - GdiplusErrorHandler EH; - pfc::ptrholder_t source = GdiplusLoadResource(id, resType); - - pfc::ptrholder_t resized = new Bitmap(size.cx, size.cy, PixelFormat32bppARGB); - EH << resized->GetLastStatus(); - { - pfc::ptrholder_t target = new Graphics(resized.get_ptr()); - EH << target->GetLastStatus(); - EH << target->SetInterpolationMode(InterpolationModeHighQuality); - EH << target->DrawImage(source.get_ptr(), Rect(0, 0, size.cx, size.cy)); - } - return resized.detach(); -} - -static void GdiplusDimImage(Gdiplus::Bitmap * bmp) { - using namespace Gdiplus; - GdiplusErrorHandler EH; - Gdiplus::Rect r(0, 0, bmp->GetWidth(), bmp->GetHeight()); - BitmapData data = {}; - EH << bmp->LockBits(&r, ImageLockModeRead | ImageLockModeWrite, PixelFormat32bppARGB, &data); - - BYTE * scan = (BYTE*)data.Scan0; - for (UINT y = 0; y < data.Height; ++y) { - BYTE * px = scan; - for (UINT x = 0; x < data.Width; ++x) { - //px[0] = _dimPixel(px[0]); - //px[1] = _dimPixel(px[1]); - //px[2] = _dimPixel(px[2]); - px[3] /= 3; - px += 4; - } - scan += data.Stride; - } - - EH << bmp->UnlockBits(&data); -} -static void GdiplusInvertImage(Gdiplus::Bitmap * bmp) { - using namespace Gdiplus; - GdiplusErrorHandler EH; - Gdiplus::Rect r(0, 0, bmp->GetWidth(), bmp->GetHeight()); - BitmapData data = {}; - EH << bmp->LockBits(&r, ImageLockModeRead | ImageLockModeWrite, PixelFormat32bppARGB, &data); - - BYTE * scan = (BYTE*)data.Scan0; - for (UINT y = 0; y < data.Height; ++y) { - BYTE * px = scan; - for (UINT x = 0; x < data.Width; ++x) { - unsigned v = (unsigned)px[0] + (unsigned)px[1] + (unsigned)px[2]; - v /= 3; - px[0] = px[1] = px[2] = 255 - v; - px += 4; - } - scan += data.Stride; - } - - EH << bmp->UnlockBits(&data); -} -#pragma comment(lib, "gdiplus.lib") diff --git a/libPPUI/gesture.h b/libPPUI/gesture.h deleted file mode 100644 index a0b7e1b..0000000 --- a/libPPUI/gesture.h +++ /dev/null @@ -1,264 +0,0 @@ -#pragma once - -#ifndef WM_GESTURE - -#define WM_GESTURE 0x0119 -#define WM_GESTURENOTIFY 0x011A - - -DECLARE_HANDLE(HGESTUREINFO); - - -/* - * Gesture flags - GESTUREINFO.dwFlags - */ -#define GF_BEGIN 0x00000001 -#define GF_INERTIA 0x00000002 -#define GF_END 0x00000004 - -/* - * Gesture IDs - */ -#define GID_BEGIN 1 -#define GID_END 2 -#define GID_ZOOM 3 -#define GID_PAN 4 -#define GID_ROTATE 5 -#define GID_TWOFINGERTAP 6 -#define GID_PRESSANDTAP 7 -#define GID_ROLLOVER GID_PRESSANDTAP - -/* - * Gesture information structure - * - Pass the HGESTUREINFO received in the WM_GESTURE message lParam into the - * GetGestureInfo function to retrieve this information. - * - If cbExtraArgs is non-zero, pass the HGESTUREINFO received in the WM_GESTURE - * message lParam into the GetGestureExtraArgs function to retrieve extended - * argument information. - */ -typedef struct tagGESTUREINFO { - UINT cbSize; // size, in bytes, of this structure (including variable length Args field) - DWORD dwFlags; // see GF_* flags - DWORD dwID; // gesture ID, see GID_* defines - HWND hwndTarget; // handle to window targeted by this gesture - POINTS ptsLocation; // current location of this gesture - DWORD dwInstanceID; // internally used - DWORD dwSequenceID; // internally used - ULONGLONG ullArguments; // arguments for gestures whose arguments fit in 8 BYTES - UINT cbExtraArgs; // size, in bytes, of extra arguments, if any, that accompany this gesture -} GESTUREINFO, *PGESTUREINFO; -typedef GESTUREINFO const * PCGESTUREINFO; - - -/* - * Gesture notification structure - * - The WM_GESTURENOTIFY message lParam contains a pointer to this structure. - * - The WM_GESTURENOTIFY message notifies a window that gesture recognition is - * in progress and a gesture will be generated if one is recognized under the - * current gesture settings. - */ -typedef struct tagGESTURENOTIFYSTRUCT { - UINT cbSize; // size, in bytes, of this structure - DWORD dwFlags; // unused - HWND hwndTarget; // handle to window targeted by the gesture - POINTS ptsLocation; // starting location - DWORD dwInstanceID; // internally used -} GESTURENOTIFYSTRUCT, *PGESTURENOTIFYSTRUCT; - -/* - * Gesture argument helpers - * - Angle should be a double in the range of -2pi to +2pi - * - Argument should be an unsigned 16-bit value - */ -#define GID_ROTATE_ANGLE_TO_ARGUMENT(_arg_) ((USHORT)((((_arg_) + 2.0 * 3.14159265) / (4.0 * 3.14159265)) * 65535.0)) -#define GID_ROTATE_ANGLE_FROM_ARGUMENT(_arg_) ((((double)(_arg_) / 65535.0) * 4.0 * 3.14159265) - 2.0 * 3.14159265) - -/* - * Gesture information retrieval - * - HGESTUREINFO is received by a window in the lParam of a WM_GESTURE message. - */ -WINUSERAPI -BOOL -WINAPI -GetGestureInfo( - __in HGESTUREINFO hGestureInfo, - __out PGESTUREINFO pGestureInfo); - - - -/* - * Gesture extra arguments retrieval - * - HGESTUREINFO is received by a window in the lParam of a WM_GESTURE message. - * - Size, in bytes, of the extra argument data is available in the cbExtraArgs - * field of the GESTUREINFO structure retrieved using the GetGestureInfo function. - */ -WINUSERAPI -BOOL -WINAPI -GetGestureExtraArgs( - __in HGESTUREINFO hGestureInfo, - __in UINT cbExtraArgs, - __out_bcount(cbExtraArgs) PBYTE pExtraArgs); - -/* - * Gesture information handle management - * - If an application processes the WM_GESTURE message, then once it is done - * with the associated HGESTUREINFO, the application is responsible for - * closing the handle using this function. Failure to do so may result in - * process memory leaks. - * - If the message is instead passed to DefWindowProc, or is forwarded using - * one of the PostMessage or SendMessage class of API functions, the handle - * is transfered with the message and need not be closed by the application. - */ -WINUSERAPI -BOOL -WINAPI -CloseGestureInfoHandle( - __in HGESTUREINFO hGestureInfo); - - -/* - * Gesture configuration structure - * - Used in SetGestureConfig and GetGestureConfig - * - Note that any setting not included in either GESTURECONFIG.dwWant or - * GESTURECONFIG.dwBlock will use the parent window's preferences or - * system defaults. - */ -typedef struct tagGESTURECONFIG { - DWORD dwID; // gesture ID - DWORD dwWant; // settings related to gesture ID that are to be turned on - DWORD dwBlock; // settings related to gesture ID that are to be turned off -} GESTURECONFIG, *PGESTURECONFIG; - -/* - * Gesture configuration flags - GESTURECONFIG.dwWant or GESTURECONFIG.dwBlock - */ - -/* - * Common gesture configuration flags - set GESTURECONFIG.dwID to zero - */ -#define GC_ALLGESTURES 0x00000001 - -/* - * Zoom gesture configuration flags - set GESTURECONFIG.dwID to GID_ZOOM - */ -#define GC_ZOOM 0x00000001 - -/* - * Pan gesture configuration flags - set GESTURECONFIG.dwID to GID_PAN - */ -#define GC_PAN 0x00000001 -#define GC_PAN_WITH_SINGLE_FINGER_VERTICALLY 0x00000002 -#define GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY 0x00000004 -#define GC_PAN_WITH_GUTTER 0x00000008 -#define GC_PAN_WITH_INERTIA 0x00000010 - -/* - * Rotate gesture configuration flags - set GESTURECONFIG.dwID to GID_ROTATE - */ -#define GC_ROTATE 0x00000001 - -/* - * Two finger tap gesture configuration flags - set GESTURECONFIG.dwID to GID_TWOFINGERTAP - */ -#define GC_TWOFINGERTAP 0x00000001 - -/* - * PressAndTap gesture configuration flags - set GESTURECONFIG.dwID to GID_PRESSANDTAP - */ -#define GC_PRESSANDTAP 0x00000001 -#define GC_ROLLOVER GC_PRESSANDTAP - -#define GESTURECONFIGMAXCOUNT 256 // Maximum number of gestures that can be included - // in a single call to SetGestureConfig / GetGestureConfig - -WINUSERAPI -BOOL -WINAPI -SetGestureConfig( - __in HWND hwnd, // window for which configuration is specified - __in DWORD dwReserved, // reserved, must be 0 - __in UINT cIDs, // count of GESTURECONFIG structures - __in_ecount(cIDs) PGESTURECONFIG pGestureConfig, // array of GESTURECONFIG structures, dwIDs will be processed in the - // order specified and repeated occurances will overwrite previous ones - __in UINT cbSize); // sizeof(GESTURECONFIG) - - - - -#define GCF_INCLUDE_ANCESTORS 0x00000001 // If specified, GetGestureConfig returns consolidated configuration - // for the specified window and it's parent window chain - -WINUSERAPI -BOOL -WINAPI -GetGestureConfig( - __in HWND hwnd, // window for which configuration is required - __in DWORD dwReserved, // reserved, must be 0 - __in DWORD dwFlags, // see GCF_* flags - __in PUINT pcIDs, // *pcIDs contains the size, in number of GESTURECONFIG structures, - // of the buffer pointed to by pGestureConfig - __inout_ecount(*pcIDs) PGESTURECONFIG pGestureConfig, - // pointer to buffer to receive the returned array of GESTURECONFIG structures - __in UINT cbSize); // sizeof(GESTURECONFIG) - - - -typedef BOOL -(WINAPI *pGetGestureInfo_t)( - __in HGESTUREINFO hGestureInfo, - __out PGESTUREINFO pGestureInfo); - -typedef BOOL -(WINAPI * pCloseGestureInfoHandle_t)( - __in HGESTUREINFO hGestureInfo); - -typedef BOOL -(WINAPI * pSetGestureConfig_t) ( - __in HWND hwnd, // window for which configuration is specified - __in DWORD dwReserved, // reserved, must be 0 - __in UINT cIDs, // count of GESTURECONFIG structures - __in_ecount(cIDs) PGESTURECONFIG pGestureConfig, // array of GESTURECONFIG structures, dwIDs will be processed in the - // order specified and repeated occurances will overwrite previous ones - __in UINT cbSize); // sizeof(GESTURECONFIG) - -class CGestureAPI { -public: - CGestureAPI() { - HMODULE dll = GetModuleHandle(_T("user32.dll")); - - Bind(GetGestureInfo, dll, "GetGestureInfo"); - Bind(CloseGestureInfoHandle, dll, "CloseGestureInfoHandle"); - Bind(SetGestureConfig, dll, "SetGestureConfig"); - } - - bool IsAvailable() { - return this->GetGestureInfo != NULL; - } - - pGetGestureInfo_t GetGestureInfo; - pCloseGestureInfoHandle_t CloseGestureInfoHandle; - pSetGestureConfig_t SetGestureConfig; -private: - template static void Bind(func_t & f, HMODULE dll, const char * name) { - f = reinterpret_cast(GetProcAddress(dll, name)); - } -}; -#else - -class CGestureAPI { -public: - inline static bool IsAvailable() { return true; } - inline static BOOL GetGestureInfo(HGESTUREINFO hGestureInfo, PGESTUREINFO pGestureInfo) { - return ::GetGestureInfo(hGestureInfo, pGestureInfo); - } - inline static BOOL CloseGestureInfoHandle(HGESTUREINFO hGestureInfo) { - return ::CloseGestureInfoHandle(hGestureInfo); - } - - inline static BOOL SetGestureConfig(HWND hwnd, DWORD dwReserved, UINT cIDs, PGESTURECONFIG pGestureConfig, UINT cbSize) { - return ::SetGestureConfig(hwnd, dwReserved, cIDs, pGestureConfig, cbSize); - } -}; -#endif - diff --git a/libPPUI/libPPUI-license.txt b/libPPUI/libPPUI-license.txt deleted file mode 100644 index f7a9287..0000000 --- a/libPPUI/libPPUI-license.txt +++ /dev/null @@ -1,17 +0,0 @@ -Copyright (C) 2002-2021 Peter Pawlowski - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. -3. This notice may not be removed or altered from any source distribution. \ No newline at end of file diff --git a/libPPUI/libPPUI-readme.txt b/libPPUI/libPPUI-readme.txt deleted file mode 100644 index 72244ef..0000000 --- a/libPPUI/libPPUI-readme.txt +++ /dev/null @@ -1,3 +0,0 @@ -libPPUI - -A library of user interface classes used by foobar2000 codebase; freely available for anyone to use in their programming projects. diff --git a/libPPUI/libPPUI.vcxproj b/libPPUI/libPPUI.vcxproj deleted file mode 100644 index ef3f31f..0000000 --- a/libPPUI/libPPUI.vcxproj +++ /dev/null @@ -1,260 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {7729EB82-4069-4414-964B-AD399091A03F} - Win32Proj - libPPUI - 8.1 - - - - StaticLibrary - true - v141 - Unicode - - - StaticLibrary - false - v141 - true - Unicode - - - StaticLibrary - true - v141 - Unicode - - - StaticLibrary - false - v141 - true - Unicode - - - - - - - - - - - - - - - - - - - - - true - - - true - - - false - - - false - - - - Use - Level3 - Disabled - false - .. - ProgramDatabase - true - 4715 - false - Fast - - - Windows - true - - - - - Use - Level3 - Disabled - false - true - false - .. - - - Windows - true - - - - - Use - Level3 - MinSpace - true - true - false - .. - true - 4715 - false - Fast - true - /d2notypeopt %(AdditionalOptions) - NDEBUG;_UNICODE;UNICODE;%(PreprocessorDefinitions) - - - Windows - true - true - true - - - - - Use - Level3 - MaxSpeed - true - true - false - Fast - true - false - .. - /d2notypeopt %(AdditionalOptions) - NDEBUG;_UNICODE;UNICODE;%(PreprocessorDefinitions) - - - Windows - true - true - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/libPPUI/libPPUI.vcxproj.filters b/libPPUI/libPPUI.vcxproj.filters deleted file mode 100644 index 40cd268..0000000 --- a/libPPUI/libPPUI.vcxproj.filters +++ /dev/null @@ -1,260 +0,0 @@ - - - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;ipp;xsd - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {b5bb0d58-0b1e-442d-a84d-09288c375185} - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - - - Resources - - - - - Resources - - - \ No newline at end of file diff --git a/libPPUI/link-CommonControls6.h b/libPPUI/link-CommonControls6.h deleted file mode 100644 index 1934f7d..0000000 --- a/libPPUI/link-CommonControls6.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -#pragma comment(linker, "\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' processorArchitecture='*'\"") diff --git a/libPPUI/pp-COM-macros.h b/libPPUI/pp-COM-macros.h deleted file mode 100644 index 782a88c..0000000 --- a/libPPUI/pp-COM-macros.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#define COM_QI_BEGIN() HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid,void ** ppvObject) { if (ppvObject == NULL) return E_INVALIDARG; -#define COM_QI_ENTRY(IWhat) { if (iid == __uuidof(IWhat)) {IWhat * temp = this; temp->AddRef(); * ppvObject = temp; return S_OK;} } -#define COM_QI_ENTRY_(IWhat, IID) { if (iid == IID) {IWhat * temp = this; temp->AddRef(); * ppvObject = temp; return S_OK;} } -#define COM_QI_END() * ppvObject = NULL; return E_NOINTERFACE; } - -#define COM_QI_CHAIN(Parent) { HRESULT status = Parent::QueryInterface(iid, ppvObject); if (SUCCEEDED(status)) return status; } - -#define COM_QI_SIMPLE(IWhat) COM_QI_BEGIN() COM_QI_ENTRY(IUnknown) COM_QI_ENTRY(IWhat) COM_QI_END() - - -#define PP_COM_CATCH catch(exception_com const & e) {return e.get_code();} catch(std::bad_alloc) {return E_OUTOFMEMORY;} catch(pfc::exception_invalid_params) {return E_INVALIDARG;} catch(...) {return E_UNEXPECTED;} \ No newline at end of file diff --git a/libPPUI/ppresources.h b/libPPUI/ppresources.h deleted file mode 100644 index 2d52d1a..0000000 --- a/libPPUI/ppresources.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -class CPPUIResources { -public: - static UINT get_IDI_SCROLL() -#ifdef IDI_SCROLL - { return IDI_SCROLL; } -#endif - ; -}; \ No newline at end of file diff --git a/libPPUI/stdafx.cpp b/libPPUI/stdafx.cpp deleted file mode 100644 index fd4f341..0000000 --- a/libPPUI/stdafx.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "stdafx.h" diff --git a/libPPUI/stdafx.h b/libPPUI/stdafx.h deleted file mode 100644 index 230e535..0000000 --- a/libPPUI/stdafx.h +++ /dev/null @@ -1,21 +0,0 @@ -// stdafx.h : include file for standard system include files, -// or project specific include files that are used frequently, but -// are changed infrequently -// - -#pragma once - -#include "targetver.h" - -#define _SECURE_ATL 1 - -#include -#include -#include -#include -#include -#include -#include -#include - -#include diff --git a/libPPUI/targetver.h b/libPPUI/targetver.h deleted file mode 100644 index 809eaad..0000000 --- a/libPPUI/targetver.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0601 -#include -#endif \ No newline at end of file diff --git a/libPPUI/win32_op.cpp b/libPPUI/win32_op.cpp deleted file mode 100644 index 23bf8ba..0000000 --- a/libPPUI/win32_op.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "stdafx.h" -#include "win32_op.h" -#include - -PFC_NORETURN PFC_NOINLINE void WIN32_OP_FAIL() { - const DWORD code = GetLastError(); - PFC_ASSERT(code != NO_ERROR); - throw exception_win32(code); -} - -PFC_NORETURN PFC_NOINLINE void WIN32_OP_FAIL_CRITICAL(const char * what) { -#if PFC_DEBUG - const DWORD code = GetLastError(); - PFC_ASSERT(code != NO_ERROR); -#endif - pfc::crash(); -#if 0 - pfc::string_formatter msg; msg << what << " failure #" << (uint32_t)code; - TRACK_CODE(msg.get_ptr(), uBugCheck()); -#endif -} - -#if PFC_DEBUG -void WIN32_OP_D_FAIL(const wchar_t * _Message, const wchar_t *_File, unsigned _Line) { - const DWORD code = GetLastError(); - pfc::array_t msgFormatted; msgFormatted.set_size(pfc::strlen_t(_Message) + 64); - wsprintfW(msgFormatted.get_ptr(), L"%s (code: %u)", _Message, code); - if (IsDebuggerPresent()) { - OutputDebugString(TEXT("WIN32_OP_D() failure:\n")); - OutputDebugString(msgFormatted.get_ptr()); - OutputDebugString(TEXT("\n")); - pfc::crash(); - } - _wassert(msgFormatted.get_ptr(), _File, _Line); -} -#endif diff --git a/libPPUI/win32_utility.cpp b/libPPUI/win32_utility.cpp deleted file mode 100644 index dbfdcf4..0000000 --- a/libPPUI/win32_utility.cpp +++ /dev/null @@ -1,218 +0,0 @@ -#include "stdafx.h" -#include "win32_utility.h" -#include "win32_op.h" - -unsigned QueryScreenDPI(HWND wnd) { - HDC dc = GetDC(wnd); - unsigned ret = GetDeviceCaps(dc, LOGPIXELSY); - ReleaseDC(wnd, dc); - return ret; -} -unsigned QueryScreenDPI_X(HWND wnd) { - HDC dc = GetDC(wnd); - unsigned ret = GetDeviceCaps(dc, LOGPIXELSX); - ReleaseDC(wnd, dc); - return ret; -} -unsigned QueryScreenDPI_Y(HWND wnd) { - HDC dc = GetDC(wnd); - unsigned ret = GetDeviceCaps(dc, LOGPIXELSY); - ReleaseDC(wnd, dc); - return ret; -} - -SIZE QueryScreenDPIEx(HWND wnd) { - HDC dc = GetDC(wnd); - SIZE ret = { GetDeviceCaps(dc,LOGPIXELSX), GetDeviceCaps(dc,LOGPIXELSY) }; - ReleaseDC(wnd, dc); - return ret; -} - -void HeaderControl_SetSortIndicator(HWND header_, int column, bool isUp) { - CHeaderCtrl header(header_); - const int total = header.GetItemCount(); - for (int walk = 0; walk < total; ++walk) { - HDITEM item = {}; item.mask = HDI_FORMAT; - if (header.GetItem(walk, &item)) { - DWORD newFormat = item.fmt; - newFormat &= ~(HDF_SORTUP | HDF_SORTDOWN); - if (walk == column) { - newFormat |= isUp ? HDF_SORTUP : HDF_SORTDOWN; - } - if (newFormat != item.fmt) { - item.fmt = newFormat; - header.SetItem(walk, &item); - } - } - } -} - -HINSTANCE GetThisModuleHandle() { - return (HINSTANCE)_AtlBaseModule.m_hInst; -} - -WinResourceRef_t WinLoadResource(HMODULE hMod, const TCHAR * name, const TCHAR * type, WORD wLang) { - SetLastError(0); - HRSRC res = wLang ? FindResourceEx(hMod, type, name, wLang) : FindResource(hMod, name, type); - if ( res == NULL ) WIN32_OP_FAIL(); - SetLastError(0); - HGLOBAL hglob = LoadResource(hMod, res); - if ( hglob == NULL ) WIN32_OP_FAIL(); - SetLastError(0); - void * ptr = LockResource(hglob); - if ( ptr == nullptr ) WIN32_OP_FAIL(); - WinResourceRef_t ref; - ref.ptr = ptr; - ref.bytes = SizeofResource(hMod, res); - return ref; -} - -CComPtr WinLoadResourceAsStream(HMODULE hMod, const TCHAR * name, const TCHAR * type, WORD wLang) { - auto res = WinLoadResource(hMod, name, type, wLang ); - auto str = SHCreateMemStream( (const BYTE*) res.ptr, (UINT) res.bytes ); - if ( str == nullptr ) throw std::bad_alloc(); - CComPtr ret; - ret.Attach( str ); - return ret; -} - -UINT GetFontHeight(HFONT font) -{ - UINT ret; - HDC dc = CreateCompatibleDC(0); - SelectObject(dc, font); - ret = GetTextHeight(dc); - DeleteDC(dc); - return ret; -} - -UINT GetTextHeight(HDC dc) -{ - TEXTMETRIC tm; - POINT pt[2]; - GetTextMetrics(dc, &tm); - pt[0].x = 0; - pt[0].y = tm.tmHeight; - pt[1].x = 0; - pt[1].y = 0; - LPtoDP(dc, pt, 2); - - int ret = pt[0].y - pt[1].y; - return ret > 1 ? (unsigned)ret : 1; -} - - -LRESULT RelayEraseBkgnd(HWND p_from, HWND p_to, HDC p_dc) { - LRESULT status; - POINT pt = { 0, 0 }, pt_old = { 0,0 }; - MapWindowPoints(p_from, p_to, &pt, 1); - OffsetWindowOrgEx(p_dc, pt.x, pt.y, &pt_old); - status = SendMessage(p_to, WM_ERASEBKGND, (WPARAM)p_dc, 0); - SetWindowOrgEx(p_dc, pt_old.x, pt_old.y, 0); - return status; -} - -pfc::string8 EscapeTooltipText(const char * src) -{ - pfc::string8 out; - while (*src) - { - if (*src == '&') - { - out.add_string("&&&"); - src++; - while (*src == '&') - { - out.add_string("&&"); - src++; - } - } else out.add_byte(*(src++)); - } - return out; -} - -bool IsMenuNonEmpty(HMENU menu) { - unsigned n, m = GetMenuItemCount(menu); - for (n = 0; n < m; n++) { - if (GetSubMenu(menu, n)) return true; - if (!(GetMenuState(menu, n, MF_BYPOSITION)&MF_SEPARATOR)) return true; - } - return false; -} - -void SetDefaultMenuItem(HMENU p_menu, unsigned p_id) { - MENUITEMINFO info = { sizeof(info) }; - info.fMask = MIIM_STATE; - GetMenuItemInfo(p_menu, p_id, FALSE, &info); - info.fState |= MFS_DEFAULT; - SetMenuItemInfo(p_menu, p_id, FALSE, &info); -} - -static bool running_under_wine(void) { - HMODULE module = GetModuleHandle(_T("ntdll.dll")); - if (!module) return false; - return GetProcAddress(module, "wine_server_call") != NULL; -} -static bool FetchWineInfoAppend(pfc::string_base & out) { - typedef const char *(__cdecl *t_wine_get_build_id)(void); - typedef void(__cdecl *t_wine_get_host_version)(const char **sysname, const char **release); - const HMODULE ntdll = GetModuleHandle(_T("ntdll.dll")); - if (ntdll == NULL) return false; - t_wine_get_build_id wine_get_build_id; - t_wine_get_host_version wine_get_host_version; - wine_get_build_id = (t_wine_get_build_id)GetProcAddress(ntdll, "wine_get_build_id"); - wine_get_host_version = (t_wine_get_host_version)GetProcAddress(ntdll, "wine_get_host_version"); - if (wine_get_build_id == NULL || wine_get_host_version == NULL) { - if (GetProcAddress(ntdll, "wine_server_call") != NULL) { - out << "wine (unknown version)"; - return true; - } - return false; - } - const char * sysname = NULL; const char * release = NULL; - wine_get_host_version(&sysname, &release); - out << wine_get_build_id() << ", on: " << sysname << " / " << release; - return true; -} - -static void GetOSVersionStringAppend(pfc::string_base & out) { - - if (FetchWineInfoAppend(out)) return; - - OSVERSIONINFO ver = {}; ver.dwOSVersionInfoSize = sizeof(ver); - WIN32_OP(GetVersionEx(&ver)); - SYSTEM_INFO info = {}; - GetNativeSystemInfo(&info); - - out << "Windows " << (int)ver.dwMajorVersion << "." << (int)ver.dwMinorVersion << "." << (int)ver.dwBuildNumber; - if (ver.szCSDVersion[0] != 0) out << " " << pfc::stringcvt::string_utf8_from_os(ver.szCSDVersion, PFC_TABSIZE(ver.szCSDVersion)); - - switch (info.wProcessorArchitecture) { - case PROCESSOR_ARCHITECTURE_AMD64: - out << " x64"; break; - case PROCESSOR_ARCHITECTURE_IA64: - out << " IA64"; break; - case PROCESSOR_ARCHITECTURE_INTEL: - out << " x86"; break; - } -} - -void GetOSVersionString(pfc::string_base & out) { - out.reset(); GetOSVersionStringAppend(out); -} -WORD GetOSVersionCode() { - OSVERSIONINFO ver = {sizeof(ver)}; - WIN32_OP_D(GetVersionEx(&ver)); - - DWORD ret = ver.dwMinorVersion; - ret += ver.dwMajorVersion << 8; - - return (WORD)ret; -} - - -POINT GetCursorPos() { - POINT pt; - WIN32_OP_D( GetCursorPos(&pt) ); - return pt; -} diff --git a/libPPUI/win32_utility.h b/libPPUI/win32_utility.h deleted file mode 100644 index 6cda539..0000000 --- a/libPPUI/win32_utility.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include // CComPtr - -unsigned QueryScreenDPI(HWND wnd = NULL); -unsigned QueryScreenDPI_X(HWND wnd = NULL); -unsigned QueryScreenDPI_Y(HWND wnd = NULL); - -SIZE QueryScreenDPIEx(HWND wnd = NULL); - -void HeaderControl_SetSortIndicator(HWND header, int column, bool isUp); - -POINT GetCursorPos(); - -HINSTANCE GetThisModuleHandle(); - -struct WinResourceRef_t { - const void * ptr; - size_t bytes; -} ; - -WinResourceRef_t WinLoadResource(HMODULE hMod, const TCHAR * name, const TCHAR * type, WORD wLang = 0); -CComPtr WinLoadResourceAsStream(HMODULE hMod, const TCHAR * name, const TCHAR * type, WORD wLang = 0); - -UINT GetFontHeight(HFONT font); -UINT GetTextHeight(HDC dc); - -LRESULT RelayEraseBkgnd(HWND p_from, HWND p_to, HDC p_dc); - -pfc::string8 EscapeTooltipText(const char * text); - -class CloseHandleScope { -public: - CloseHandleScope(HANDLE handle) throw() : m_handle(handle) {} - ~CloseHandleScope() throw() { CloseHandle(m_handle); } - HANDLE Detach() throw() { return pfc::replace_t(m_handle, INVALID_HANDLE_VALUE); } - HANDLE Get() const throw() { return m_handle; } - void Close() throw() { CloseHandle(Detach()); } - PFC_CLASS_NOT_COPYABLE_EX(CloseHandleScope) -private: - HANDLE m_handle; -}; - -bool IsMenuNonEmpty(HMENU menu); -void SetDefaultMenuItem(HMENU p_menu, unsigned p_id); - -void GetOSVersionString(pfc::string_base & out); -WORD GetOSVersionCode(); diff --git a/pfc/array.h b/pfc/array.h index bff8b1a..2a11fd5 100644 --- a/pfc/array.h +++ b/pfc/array.h @@ -72,7 +72,6 @@ namespace pfc { t_size get_size() const {return m_size;} - t_size size() const {return m_size;} // std compat const t_item * get_ptr() const {return m_array;} t_item * get_ptr() {return m_array;} @@ -132,7 +131,6 @@ namespace pfc { const t_self & operator=(t_self && p_source) {move_from(p_source); return *this;} void set_size(t_size p_size) {m_alloc.set_size(p_size);} - void resize( size_t s ) { set_size(s); } // std compat template void set_size_fill(size_t p_size, fill_t const & filler) { @@ -159,7 +157,6 @@ namespace pfc { void set_size_discard(t_size p_size) {m_alloc.set_size(p_size);} void set_count(t_size p_count) {m_alloc.set_size(p_count);} t_size get_size() const {return m_alloc.get_size();} - size_t size() const {return m_alloc.get_size();} // std compat t_size get_count() const {return m_alloc.get_size();} void force_reset() {m_alloc.force_reset();} @@ -209,17 +206,11 @@ namespace pfc { set_size(new_size); } - template - void add_item( item_t && item ) { - const t_size base = get_size(); - increase_size(1); - m_alloc[base] = std::forward( item ); - } - template - void append_single_val( item_t && item ) { + template + void append_single_val( t_append item ) { const t_size base = get_size(); increase_size(1); - m_alloc[base] = std::forward( item ); + m_alloc[base] = item; } template diff --git a/pfc/autoref.h b/pfc/autoref.h deleted file mode 100644 index e0e6094..0000000 --- a/pfc/autoref.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once -#include - -namespace pfc { - - // autoref<> : turn arbitrary ptr that needs to be delete'd into a shared_ptr<> alike - template class autoref { - public: - autoref() {} - autoref(std::nullptr_t) {} - autoref(obj_t * source) { - attach(source); - } - void attach(obj_t * source) { - PFC_ASSERT( source != nullptr ); - m_obj = std::make_shared(source); - } - void reset() { - m_obj.reset(); - } - - obj_t * operator->() const { - return m_obj->get_ptr(); - } - - obj_t * get() const { - if (! m_obj ) return nullptr; - return m_obj->get_ptr(); - } - - operator bool() const { - return !!m_obj; - } - private: - typedef pfc::ptrholder_t< obj_t > holder_t; - std::shared_ptr< holder_t > m_obj; - }; -} \ No newline at end of file diff --git a/pfc/avltree.h b/pfc/avltree.h index ec75057..713df68 100644 --- a/pfc/avltree.h +++ b/pfc/avltree.h @@ -194,7 +194,6 @@ namespace pfc { int result = compare(p_base->m_content,p_search); if (result > 0) { t_node * ret = g_find_or_add_node(p_base->m_left,p_base.get_ptr(),p_search,p_new); - PFC_ASSERT(compare(ret->m_content, p_search) == 0); if (p_new) { recalc_depth(p_base); g_rebalance(p_base); @@ -202,7 +201,6 @@ namespace pfc { return ret; } else if (result < 0) { t_node * ret = g_find_or_add_node(p_base->m_right,p_base.get_ptr(),p_search,p_new); - PFC_ASSERT(compare(ret->m_content, p_search) == 0); if (p_new) { recalc_depth(p_base); g_rebalance(p_base); diff --git a/pfc/base64.cpp b/pfc/base64.cpp index bb2f0e5..d513878 100644 --- a/pfc/base64.cpp +++ b/pfc/base64.cpp @@ -55,6 +55,7 @@ namespace pfc { void base64_decode(const char * text, void * out) { size_t outWritePtr = 0; + size_t textWalk = 0; size_t inTemp = 0; uint8_t temp[3]; for ( size_t textWalk = 0 ; ; ++ textWalk ) { diff --git a/pfc/bit_array.cpp b/pfc/bit_array.cpp index 96de09a..c6b9eab 100644 --- a/pfc/bit_array.cpp +++ b/pfc/bit_array.cpp @@ -95,7 +95,7 @@ namespace pfc { if (count==0) return start; else if (count<0) { size_t idx; - if (!_findNearestDown( start, idx ) || (t_ssize)m_content[idx] < (t_ssize)start+count) return start + count; + if (!_findNearestDown( start, idx ) || m_content[idx] < start+count) return start + count; return m_content[idx]; } else { // count > 0 size_t idx; diff --git a/pfc/bit_array_impl.h b/pfc/bit_array_impl.h index 7c7a545..d244e25 100644 --- a/pfc/bit_array_impl.h +++ b/pfc/bit_array_impl.h @@ -111,7 +111,7 @@ namespace pfc { class bit_array_true : public bit_array { public: - bool get(t_size) const {return true;} + bool get(t_size n) const {return true;} t_size find(bool val,t_size start,t_ssize count) const {return val ? start : start+count;} }; @@ -119,7 +119,7 @@ namespace pfc { class bit_array_false : public bit_array { public: - bool get(t_size) const {return false;} + bool get(t_size n) const {return false;} t_size find(bool val,t_size start,t_ssize count) const {return val ? start+count : start;} }; @@ -129,7 +129,7 @@ namespace pfc { bool val; public: bit_array_val(bool v) : val(v) {} - bool get(t_size) const {return val;} + bool get(t_size n) const {return val;} t_size find(bool p_val,t_size start,t_ssize count) const {return val==p_val ? start : start+count;} }; @@ -178,8 +178,6 @@ namespace pfc { void set(t_size n, bool val); bool get(t_size n) const; - - size_t size() const {return m_count;} }; diff --git a/pfc/byte_order.h b/pfc/byte_order_helper.h similarity index 94% rename from pfc/byte_order.h rename to pfc/byte_order_helper.h index 920a56f..e8e3ea0 100644 --- a/pfc/byte_order.h +++ b/pfc/byte_order_helper.h @@ -234,23 +234,8 @@ namespace pfc { reverse_bytes(p_buffer+1); } - template<> inline void reverse_bytes<1>(t_uint8 * ) { } - template<> inline void reverse_bytes<0>(t_uint8 * ) { } + template<> inline void reverse_bytes<1>(t_uint8 * p_buffer) { } + template<> inline void reverse_bytes<0>(t_uint8 * p_buffer) { } - inline int32_t readInt24(const void * mem) { - const uint8_t * p = (const uint8_t*) mem; - int32_t ret; - if (byte_order_is_little_endian) { - ret = p[0]; - ret |= (uint32_t)p[1] << 8; - ret |= (int32_t)(int8_t)p[2] << 16; - return ret; - } else { - ret = p[2]; - ret |= (uint32_t)p[1] << 8; - ret |= (int32_t)(int8_t)p[0] << 16; - return ret; - } - } } diff --git a/pfc/cpuid.cpp b/pfc/cpuid.cpp index a4d4cfd..b98c34a 100644 --- a/pfc/cpuid.cpp +++ b/pfc/cpuid.cpp @@ -4,14 +4,7 @@ #if PFC_HAVE_CPUID namespace pfc { - bool query_cpu_feature_set(unsigned p_value) { -#if _M_IX86_FP >= 2 - // don't bother checking for SSE/SSE2 if compiled to use them - p_value &= ~(CPU_HAVE_SSE | CPU_HAVE_SSE2); - if (p_value == 0) return true; -#endif - #ifdef _MSC_VER __try { #endif diff --git a/pfc/event.h b/pfc/event.h index 8ce583f..dee0d73 100644 --- a/pfc/event.h +++ b/pfc/event.h @@ -2,8 +2,6 @@ namespace pfc { #ifdef _WIN32 typedef HANDLE eventHandle_t; - - static const eventHandle_t eventInvalid = NULL; class event : public win32_event { public: @@ -15,8 +13,6 @@ namespace pfc { typedef int eventHandle_t; - static const eventHandle_t eventInvalid = -1; - typedef nix_event event; #endif diff --git a/pfc/iterators.h b/pfc/iterators.h index ce98b91..25d457a 100644 --- a/pfc/iterators.h +++ b/pfc/iterators.h @@ -1,5 +1,4 @@ #pragma once -#include "ref_counter.h" namespace pfc { //! Base class for list nodes. Implemented by list implementers. @@ -7,7 +6,7 @@ namespace pfc { public: typedef _list_node t_self; - template _list_node(arg_t && ... arg) : m_content( std::forward(arg) ...) {} + TEMPLATE_CONSTRUCTOR_FORWARD_FLOOD(_list_node,m_content) t_item m_content; diff --git a/pfc/list.h b/pfc/list.h index 6e53a9f..9249dc1 100644 --- a/pfc/list.h +++ b/pfc/list.h @@ -12,8 +12,8 @@ public: inline t_size get_size() const {return get_count();} - inline T get_item(t_size n) const {T temp; get_item_ex(temp,n); return temp;} - inline T operator[](t_size n) const {T temp; get_item_ex(temp,n); return temp;} + inline T get_item(t_size n) const {T temp; get_item_ex(temp,n); return std::move(temp);} + inline T operator[](t_size n) const {T temp; get_item_ex(temp,n); return std::move(temp);} template t_size find_duplicates_sorted_t(t_compare p_compare,bit_array_var & p_out) const @@ -232,9 +232,9 @@ public: int compare(const T& p_item1,const T& p_item2) {return ::pfc::compare_t(p_item1,p_item2);} }; - void sort() {sort_callback_auto cb;sort(cb);} - template void sort_t(t_compare p_compare) {sort_callback_impl_t cb(p_compare);sort(cb);} - template void sort_stable_t(t_compare p_compare) {sort_callback_impl_t cb(p_compare); sort_stable(cb);} + void sort() {sort(sort_callback_auto());} + template void sort_t(t_compare p_compare) {sort(sort_callback_impl_t(p_compare));} + template void sort_stable_t(t_compare p_compare) {sort_stable(sort_callback_impl_t(p_compare));} template void sort_remove_duplicates_t(t_compare p_compare) { diff --git a/pfc/lockless.h b/pfc/lockless.h index 83b297c..f50956c 100644 --- a/pfc/lockless.h +++ b/pfc/lockless.h @@ -66,7 +66,7 @@ namespace pfc { } private: threadSafeInt m_once; - volatile bool m_done = false; + volatile bool m_done; }; } diff --git a/pfc/map.h b/pfc/map.h index 3105e62..4f53dad 100644 --- a/pfc/map.h +++ b/pfc/map.h @@ -148,13 +148,11 @@ namespace pfc { template bool get_first(_t_key & p_out) const { - t_retrieve_key<_t_key> wrap(p_out); - return m_data.get_first(wrap); + return m_data.get_first(t_retrieve_key<_t_key>(p_out)); } template bool get_last(_t_key & p_out) const { - t_retrieve_key<_t_key> wrap(p_out); - return m_data.get_last(wrap); + return m_data.get_last(t_retrieve_key<_t_key>(p_out)); } diff --git a/pfc/notifyList.h b/pfc/notifyList.h deleted file mode 100644 index 4e8565f..0000000 --- a/pfc/notifyList.h +++ /dev/null @@ -1,85 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace pfc { - class notifyList { - public: - - typedef size_t token_t; - - typedef std::function notify_t; - token_t add( notify_t f ) { - auto token = ++ m_increment; - m_notify[token] = f; - return token; - } - - void remove( token_t t ) { - m_notify.erase(t); - } - - void dispatch() { - // Safeguard against someone altering our state in mid-dispatch - auto temp = m_notify; - for( auto walk = temp.begin(); walk != temp.end(); ++ walk ) { - if ( m_notify.count( walk->first ) > 0 ) { // still there? - walk->second(); - } - } - } - - - static std::shared_ptr make() { - return std::make_shared(); - } - private: - token_t m_increment = 0; - - std::map m_notify; - }; - - typedef std::shared_ptr< notifyList > notifyListRef_t; - - class notifyEntry { - public: - notifyEntry() {} - - notifyEntry & operator<<( notifyList & l ) { - PFC_ASSERT( m_list == nullptr ); - m_list = &l; - return *this; - } - notifyEntry & operator<<( notifyListRef_t l ) { - PFC_ASSERT( m_list == nullptr ); - m_listShared = l; - m_list = &*l; - return *this; - } - notifyEntry & operator<<( notifyList::notify_t f ) { - PFC_ASSERT( m_list != nullptr ); - PFC_ASSERT( m_token == 0 ); - m_token = m_list->add( f ); - return *this; - } - void clear() { - if ( m_list != nullptr && m_token != 0 ) { - m_list->remove(m_token); - m_token = 0; - } - } - ~notifyEntry() { - clear(); - } - - private: - notifyListRef_t m_listShared; - notifyList * m_list = nullptr; - notifyList::token_t m_token = 0; - - notifyEntry( const notifyEntry & ) = delete; - void operator=( const notifyEntry & ) = delete; - }; -} \ No newline at end of file diff --git a/pfc/order_helper.h b/pfc/order_helper.h index 1670379..5f5a161 100644 --- a/pfc/order_helper.h +++ b/pfc/order_helper.h @@ -13,7 +13,6 @@ namespace pfc { void create_move_items_permutation(t_size * p_output,t_size p_count,const class bit_array & p_selection,int p_delta); void create_move_item_permutation( size_t * p_output, size_t p_count, size_t from, size_t to ); - bool create_drop_permutation(size_t * out, size_t itemCount, pfc::bit_array const & maskSelected, size_t insertMark ); } class order_helper diff --git a/pfc/other.cpp b/pfc/other.cpp index ac4c8b3..77f903e 100644 --- a/pfc/other.cpp +++ b/pfc/other.cpp @@ -13,8 +13,6 @@ #include -#include "pfc-fb2k-hooks.h" - namespace pfc { bool permutation_is_valid(t_size const * order, t_size count) { bit_array_bittable found(count); @@ -94,49 +92,6 @@ namespace pfc { } } } - bool create_drop_permutation(size_t * out, size_t itemCount, pfc::bit_array const & maskSelected, size_t insertMark ) { - const t_size count = itemCount; - if (insertMark > count) insertMark = count; - { - t_size selBefore = 0; - for(t_size walk = 0; walk < insertMark; ++walk) { - if (maskSelected[walk]) selBefore++; - } - insertMark -= selBefore; - } - { - pfc::array_t permutation, selected, nonselected; - - const t_size selcount = maskSelected.calc_count( true, 0, count ); - selected.set_size(selcount); nonselected.set_size(count - selcount); - permutation.set_size(count); - if (insertMark > nonselected.get_size()) insertMark = nonselected.get_size(); - for(t_size walk = 0, swalk = 0, nwalk = 0; walk < count; ++walk) { - if (maskSelected[walk]) { - selected[swalk++] = walk; - } else { - nonselected[nwalk++] = walk; - } - } - for(t_size walk = 0; walk < insertMark; ++walk) { - permutation[walk] = nonselected[walk]; - } - for(t_size walk = 0; walk < selected.get_size(); ++walk) { - permutation[insertMark + walk] = selected[walk]; - } - for(t_size walk = insertMark; walk < nonselected.get_size(); ++walk) { - permutation[selected.get_size() + walk] = nonselected[walk]; - } - for(t_size walk = 0; walk < permutation.get_size(); ++walk) { - if (permutation[walk] != walk) { - memcpy(out, permutation.get_ptr(), count * sizeof(size_t)); - return true; - } - } - } - return false; - } - } void order_helper::g_swap(t_size * data,t_size ptr1,t_size ptr2) @@ -170,7 +125,10 @@ void order_helper::g_reverse(t_size * order,t_size base,t_size count) namespace pfc { - +#ifdef PFC_FOOBAR2000_CLASSIC + void crashHook(); +#endif + void crashImpl() { #if defined(_MSC_VER) __debugbreak(); @@ -183,7 +141,11 @@ namespace pfc { } void crash() { +#ifdef PFC_FOOBAR2000_CLASSIC crashHook(); +#else + crashImpl(); +#endif } } // namespace pfc diff --git a/pfc/other.h b/pfc/other.h index 0c76026..af71a9e 100644 --- a/pfc/other.h +++ b/pfc/other.h @@ -12,17 +12,6 @@ namespace pfc { ~vartoggle_t() {var = oldval;} }; - template - class vartoggle_volatile_t { - T oldval; volatile T & var; - public: - vartoggle_volatile_t(volatile T & p_var,const T & val) : var(p_var) { - oldval = var; - var = val; - } - ~vartoggle_volatile_t() {var = oldval;} - }; - typedef vartoggle_t booltoggle; }; @@ -122,9 +111,6 @@ namespace pfc { //deprecated inline void set(T * p_ptr) {attach(p_ptr);} - - ptrholder_t(t_self&& other) { m_ptr = other.detach(); } - const t_self& operator=(t_self&& other) { attach(other.detach()); return this; } private: ptrholder_t(const t_self &) {throw pfc::exception_not_implemented();} const t_self & operator=(const t_self & ) {throw pfc::exception_not_implemented();} diff --git a/pfc/pathUtils.cpp b/pfc/pathUtils.cpp index 321820f..af08573 100644 --- a/pfc/pathUtils.cpp +++ b/pfc/pathUtils.cpp @@ -1,17 +1,15 @@ -#include "pfc.h" - -static_assert(L'Ö' == 0xD6, "Compile as Unicode!!!"); +#include "pfc.h" namespace pfc { namespace io { namespace path { #ifdef _WINDOWS -#define KPathSeparators "\\/|" +static const string g_pathSeparators ("\\/|"); #else -#define KPathSeparators "/" +static const string g_pathSeparators ("/"); #endif string getFileName(string path) { - t_size split = path.lastIndexOfAnyChar(KPathSeparators); + t_size split = path.lastIndexOfAnyChar(g_pathSeparators); if (split == ~0) return path; else return path.subString(split+1); } @@ -30,7 +28,7 @@ string getFileExtension(string path) { string getDirectory(string filePath) {return getParent(filePath);} string getParent(string filePath) { - t_size split = filePath.lastIndexOfAnyChar(KPathSeparators); + t_size split = filePath.lastIndexOfAnyChar(g_pathSeparators); if (split == ~0) return ""; #ifdef _WINDOWS if (split > 0 && getIllegalNameChars().contains(filePath[split-1])) { @@ -53,55 +51,27 @@ string combine(string basePath,string fileName) { } bool isSeparator(char c) { - return strchr(KPathSeparators, c) != nullptr; + return g_pathSeparators.indexOf(c) != ~0; } string getSeparators() { - return KPathSeparators; + return g_pathSeparators; } -const char * charReplaceDefault(char c) { - switch (c) { - case '*': - return "x"; - case '\"': - return "\'\'"; - case ':': - case '/': - case '\\': - return "-"; - case '?': - return ""; - default: - return "_"; +static string replaceIllegalChar(char c) { + switch(c) { + case '*': + return "x"; + case '\"': + return "\'\'"; + case ':': + case '/': + case '\\': + return "-"; + default: + return "_"; } } - -const char * charReplaceModern(char c) { - switch (c) { - case '*': - return u8"∗"; - case '\"': - return u8"''"; - case ':': - return u8"∶"; - case '/': - return u8"⁄"; - case '\\': - return u8"⧵"; - case '?': - return u8"?"; - case '<': - return u8"˂"; - case '>': - return u8"˃"; - case '|': - return u8"∣"; - default: - return "_"; - } -} - -string replaceIllegalPathChars(string fn, charReplace_t replaceIllegalChar) { +string replaceIllegalPathChars(string fn) { string illegal = getIllegalNameChars(); string separators = getSeparators(); string_formatter output; @@ -120,7 +90,7 @@ string replaceIllegalPathChars(string fn, charReplace_t replaceIllegalChar) { return output.toString(); } -string replaceIllegalNameChars(string fn, bool allowWC, charReplace_t replaceIllegalChar) { +string replaceIllegalNameChars(string fn, bool allowWC) { const string illegal = getIllegalNameChars(allowWC); string_formatter output; for(t_size walk = 0; walk < fn.length(); ++walk) { @@ -159,36 +129,37 @@ char getDefaultSeparator() { #endif } +static const string g_illegalNameChars(g_pathSeparators #ifdef _WINDOWS -#define KIllegalNameCharsEx ":<>\"" + + ":<>*?\"" #else -// Mac OS allows : in filenames but does funny things presenting them in Finder, so don't use it -#define KIllegalNameCharsEx ":" + + "*?" #endif - -#define KWildcardChars "*?" - -#define KIllegalNameChars KPathSeparators KIllegalNameCharsEx KWildcardChars -#define KIllegalNameChars_noWC KPathSeparators KIllegalNameCharsEx - -static string g_illegalNameChars ( KIllegalNameChars ); -static string g_illegalNameChars_noWC ( KIllegalNameChars_noWC ); - + ); + +static const string g_illegalNameChars_noWC(g_pathSeparators +#ifdef _WINDOWS + + ":<>?\"" +#endif + ); string getIllegalNameChars(bool allowWC) { return allowWC ? g_illegalNameChars_noWC : g_illegalNameChars; } #ifdef _WINDOWS +static bool isIllegalTrailingChar(char c) { + return c == ' ' || c == '.'; +} static const char * const specialIllegalNames[] = { "con", "aux", "lst", "prn", "nul", "eof", "inp", "out" }; enum { maxPathComponent = 255 }; -static size_t safeTruncat( const char * str, size_t maxLen ) { - size_t i = 0; - size_t ret = 0; +static unsigned safeTruncat( const char * str, unsigned maxLen ) { + unsigned i = 0; + unsigned ret = 0; for( ; i < maxLen; ++ i ) { - auto d = pfc::utf8_char_len( str + ret ); + unsigned d = pfc::utf8_char_len( str + ret ); if ( d == 0 ) break; ret += d; } @@ -198,7 +169,7 @@ static size_t safeTruncat( const char * str, size_t maxLen ) { static size_t utf8_length( const char * str ) { size_t ret = 0; for (; ++ret;) { - size_t d = pfc::utf8_char_len( str ); + unsigned d = pfc::utf8_char_len( str ); if ( d == 0 ) break; str += d; } @@ -222,64 +193,42 @@ static string truncatePathComponent( string name, bool preserveExt ) { } } - size_t truncat = safeTruncat( name.c_str(), maxPathComponent ); + unsigned truncat = safeTruncat( name.c_str(), maxPathComponent ); return name.subString(0, truncat); } -#endif // _WINDOWS -static string trailingSanity(string name, bool preserveExt, const char * lstIllegal) { +#endif - const auto isIllegalTrailingChar = [lstIllegal](char c) { - return strchr(lstIllegal, c) != nullptr; - }; - - t_size end = name.length(); - if (preserveExt) { - size_t offset = pfc::string_find_last(name.c_str(), '.'); - if (offset < end) end = offset; - } - const size_t endEx = end; - while (end > 0) { - if (!isIllegalTrailingChar(name[end - 1])) break; - --end; - } - t_size begin = 0; - while (begin < end) { - if (!isIllegalTrailingChar(name[begin])) break; - ++begin; - } - if (end < endEx || begin > 0) { - name = name.subString(begin, end - begin) + name.subString(endEx); - } - return name; -} -string validateFileName(string name, bool allowWC, bool preserveExt, charReplace_t replaceIllegalChar) { - if (!allowWC) { // special fix for filenames that consist only of question marks - size_t end = name.length(); - if (preserveExt) { - size_t offset = pfc::string_find_last(name.c_str(), '.'); - if (offset < end) end = offset; - } - bool unnamed = true; - for (size_t walk = 0; walk < end; ++walk) { - if (name[walk] != '?') unnamed = false; - } - if (unnamed) { - name = string("[unnamed]") + name.subString(end); +string validateFileName(string name, bool allowWC, bool preserveExt) { + for(t_size walk = 0; name[walk];) { + if (name[walk] == '?') { + t_size end = walk; + do { ++end; } while(name[end] == '?'); + if ( walk == 0 && name[end] == '.' ) { + name = string("[unnamed]") + name.subString(end); + } else { + name = name.subString(0, walk) + name.subString(end); + } + } else { + ++walk; } } - - // Trailing sanity AFTER replaceIllegalNameChars - // replaceIllegalNameChars may remove chars exposing illegal prefix/suffix chars - name = replaceIllegalNameChars(name, allowWC, replaceIllegalChar); - if (name.length() > 0 && !allowWC) { - pfc::string8 lstIllegal = " "; - if (!preserveExt) lstIllegal += "."; - - name = trailingSanity(name, preserveExt, lstIllegal); - } - #ifdef _WINDOWS + name = replaceIllegalNameChars(name, allowWC); + if (name.length() > 0) { + t_size end = name.length(); + while(end > 0) { + if (!isIllegalTrailingChar(name[end-1])) break; + --end; + } + t_size begin = 0; + while(begin < end) { + if (!isIllegalTrailingChar(name[begin])) break; + ++begin; + } + if (end < name.length() || begin > 0) name = name.subString(begin,end - begin); + } + name = truncatePathComponent(name, preserveExt); for( unsigned w = 0; w < _countof(specialIllegalNames); ++w ) { @@ -288,10 +237,12 @@ string validateFileName(string name, bool allowWC, bool preserveExt, charReplace break; } } -#endif if (name.isEmpty()) name = "_"; return name; +#else + return replaceIllegalNameChars(name); +#endif } -}}} // namespaces +}}} diff --git a/pfc/pathUtils.h b/pfc/pathUtils.h index e4b95fe..70428eb 100644 --- a/pfc/pathUtils.h +++ b/pfc/pathUtils.h @@ -1,8 +1,5 @@ #pragma once -#include -#include "stringNew.h" - namespace pfc { namespace io { namespace path { @@ -13,11 +10,6 @@ namespace pfc { #endif - typedef std::function charReplace_t; - - const char * charReplaceDefault(char); - const char * charReplaceModern(char); - string getFileName(string path); string getFileNameWithoutExtension(string path); string getFileExtension(string path); @@ -28,11 +20,11 @@ namespace pfc { string getSeparators(); bool isSeparator(char c); string getIllegalNameChars(bool allowWC = false); - string replaceIllegalNameChars(string fn, bool allowWC = false, charReplace_t replace = charReplaceDefault); - string replaceIllegalPathChars(string fn, charReplace_t replace = charReplaceDefault); + string replaceIllegalNameChars(string fn, bool allowWC = false); + string replaceIllegalPathChars(string fn); bool isInsideDirectory(pfc::string directory, pfc::string inside); bool isDirectoryRoot(string path); - string validateFileName(string name, bool allowWC = false, bool preserveExt = false, charReplace_t replace = charReplaceDefault);//removes various illegal things from the name, exact effect depends on the OS, includes removal of the invalid characters + string validateFileName(string name, bool allowWC = false, bool preserveExt = false);//removes various illegal things from the name, exact effect depends on the OS, includes removal of the invalid characters template inline bool equals(const t1 & v1, const t2 & v2) {return comparator::compare(v1,v2) == 0;} diff --git a/pfc/pfc-fb2k-hooks.cpp b/pfc/pfc-fb2k-hooks.cpp deleted file mode 100644 index 7dc8ede..0000000 --- a/pfc/pfc-fb2k-hooks.cpp +++ /dev/null @@ -1,4 +0,0 @@ -#include "pfc.h" -#include "pfc-fb2k-hooks.h" - -#include "suppress_fb2k_hooks.h" diff --git a/pfc/pfc-fb2k-hooks.h b/pfc/pfc-fb2k-hooks.h deleted file mode 100644 index 40a87ee..0000000 --- a/pfc/pfc-fb2k-hooks.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -namespace pfc { - void crashImpl(); - BOOL winFormatSystemErrorMessageImpl(pfc::string_base & p_out, DWORD p_code); - - void crashHook(); - BOOL winFormatSystemErrorMessageHook(pfc::string_base & p_out, DWORD p_code); -} diff --git a/pfc/pfc-license.txt b/pfc/pfc-license.txt index b806fb0..00d2e13 100644 --- a/pfc/pfc-license.txt +++ b/pfc/pfc-license.txt @@ -1,17 +1,24 @@ -Copyright (C) 2002-2021 Peter Pawlowski +This is free and unencumbered software released into the public domain. -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. -3. This notice may not be remove5d or altered from any source distribution. \ No newline at end of file +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to \ No newline at end of file diff --git a/pfc/pfc-readme.txt b/pfc/pfc-readme.txt index 8589ed0..958d16a 100644 --- a/pfc/pfc-readme.txt +++ b/pfc/pfc-readme.txt @@ -3,7 +3,3 @@ PFC : Peter's Foundation Classes A library of loosely connected classes used by foobar2000 codebase; freely available and reusable for other projects. PFC is not state-of-art code. Many parts of it exist only to keep old bits of foobar2000 codebase ( also third party foobar2000 components ) compiling without modification. For an example, certain classes predating 'pfc' namespace use exist outside the namespace. - -Regarding build configurations- -"Release FB2K" and "Debug FB2K" suppress the compilation of pfc-fb2k-hooks.cpp - which allows relevant calls to be redirected to shared.dll -These configurations should be used when compiling fb2k components. Regular configurations should be used for non fb2k apps instead. \ No newline at end of file diff --git a/pfc/pfc.h b/pfc/pfc.h index 49a4e71..7709d73 100644 --- a/pfc/pfc.h +++ b/pfc/pfc.h @@ -17,8 +17,13 @@ #endif +#define PFC_DLL_EXPORT + +// Suppress this line when using PFC outside classic foobar2000 +// When enabled, certain shared.dll methods are referenced +#define PFC_FOOBAR2000_CLASSIC + #ifdef _WINDOWS -#include "targetver.h" #ifndef STRICT #define STRICT @@ -62,7 +67,7 @@ inline bool operator!=(REFGUID guidOne, REFGUID guidOther) {return !__InlineIsEq #include -#else // not Windows +#else #include #include @@ -84,7 +89,7 @@ inline bool operator!=(const GUID & p_item1,const GUID & p_item2) { return memcmp(&p_item1,&p_item2,sizeof(GUID)) != 0; } -#endif // Windows vs not Windows +#endif @@ -109,11 +114,6 @@ inline bool operator!=(const GUID & p_item1,const GUID & p_item2) { #endif #if ! PFC_DEBUG - -#ifndef NDEBUG -#pragma message("WARNING: release build without NDEBUG") -#endif - #define PFC_ASSERT(_Expression) ((void)0) #define PFC_ASSERT_SUCCESS(_Expression) (void)( (_Expression), 0) #define PFC_ASSERT_NO_EXCEPTION(_Expression) { _Expression; } @@ -187,7 +187,7 @@ namespace pfc { #include "bit_array_impl_part2.h" #include "timers.h" #include "guid.h" -#include "byte_order.h" +#include "byte_order_helper.h" #include "other.h" #include "chain_list_v2.h" #include "rcptr.h" @@ -224,8 +224,4 @@ namespace pfc { #define PFC_INCLUDED 1 -#ifndef PFC_SET_THREAD_DESCRIPTION -#define PFC_SET_THREAD_DESCRIPTION(X) -#endif - #endif //___PFC_H___ diff --git a/pfc/pfc.vcxproj b/pfc/pfc.vcxproj index ff07a40..165a46b 100644 --- a/pfc/pfc.vcxproj +++ b/pfc/pfc.vcxproj @@ -5,84 +5,29 @@ Debug Win32 - - Debug - x64 - - - Debug FB2K - Win32 - - - Debug FB2K - x64 - - - Release FB2K - Win32 - - - Release FB2K - x64 - Release Win32 - - Release - x64 - {EBFFFB4E-261D-44D3-B89C-957B31A0BF9C} pfc - 8.1 + 7.0 StaticLibrary - true - v141 + false Unicode - - - StaticLibrary true - v141 - Unicode - - - StaticLibrary - true - v141 - Unicode - - - StaticLibrary - true - v141 - Unicode + v141_xp StaticLibrary - v141 - Unicode - - - StaticLibrary - v141 - Unicode - - - StaticLibrary - v141 - Unicode - - - StaticLibrary - v141 + false Unicode + v141_xp @@ -90,42 +35,21 @@ - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 $(SolutionDir)$(Configuration)\ - $(SolutionDir)$(Configuration)\ $(Configuration)\ - $(Configuration)\ $(SolutionDir)$(Configuration)\ - $(SolutionDir)$(Configuration)\ $(Configuration)\ - $(Configuration)\ Disabled + _WIN32_WINNT=0x501;WINVER=0x501;WIN32;_DEBUG;_WINDOWS;PFC_DLL_EXPORTS;%(PreprocessorDefinitions) EnableFastChecks Use pfc.h @@ -135,75 +59,7 @@ MultiThreadedDebugDLL 4715 true - false - Fast - - - _DEBUG;%(PreprocessorDefinitions) - 0x0409 - - - true - - - - - Disabled - EnableFastChecks - Use - pfc.h - Level3 - true - ProgramDatabase - MultiThreadedDebugDLL - 4715 - true - false - Fast - - - _DEBUG;%(PreprocessorDefinitions) - 0x0409 - - - true - - - - - Disabled - EnableFastChecks - Use - pfc.h - Level3 - true - ProgramDatabase - MultiThreadedDebugDLL - 4715 - true - false - - - _DEBUG;%(PreprocessorDefinitions) - 0x0409 - - - true - - - - - Disabled - EnableFastChecks - Use - pfc.h - Level3 - true - ProgramDatabase - MultiThreadedDebugDLL - 4715 - true - false + NoExtensions _DEBUG;%(PreprocessorDefinitions) @@ -216,58 +72,7 @@ MaxSpeed - true - false - Fast - false - Use - pfc.h - Level3 - true - ProgramDatabase - /d2notypeopt %(AdditionalOptions) - 4715 - true - true - NDEBUG;_UNICODE;UNICODE;%(PreprocessorDefinitions) - - - NDEBUG;%(PreprocessorDefinitions) - 0x0409 - - - true - - - - - MaxSpeed - true - false - Fast - false - Use - pfc.h - Level3 - true - ProgramDatabase - /d2notypeopt %(AdditionalOptions) - 4715 - true - true - NDEBUG;_UNICODE;UNICODE;%(PreprocessorDefinitions) - - - NDEBUG;%(PreprocessorDefinitions) - 0x0409 - - - true - - - - - MaxSpeed + _WIN32_WINNT=0x501;WINVER=0x501;WIN32;NDEBUG;_WINDOWS;PFC_DLL_EXPORTS;%(PreprocessorDefinitions) true false Fast @@ -278,38 +83,11 @@ true ProgramDatabase MultiThreadedDLL + NoExtensions /d2notypeopt %(AdditionalOptions) 4715 true true - NDEBUG;_UNICODE;UNICODE;%(PreprocessorDefinitions) - - - NDEBUG;%(PreprocessorDefinitions) - 0x0409 - - - true - - - - - MaxSpeed - true - false - Fast - false - Use - pfc.h - Level3 - true - ProgramDatabase - MultiThreadedDLL - /d2notypeopt %(AdditionalOptions) - 4715 - true - true - NDEBUG;_UNICODE;UNICODE;%(PreprocessorDefinitions) NDEBUG;%(PreprocessorDefinitions) @@ -323,7 +101,6 @@ - @@ -332,7 +109,7 @@ - + @@ -348,11 +125,9 @@ - - @@ -366,7 +141,6 @@ - @@ -376,12 +150,10 @@ - - @@ -391,103 +163,47 @@ - Disabled - Disabled - %(PreprocessorDefinitions) - %(PreprocessorDefinitions) + Disabled + %(PreprocessorDefinitions) EnableFastChecks - EnableFastChecks - EnableFastChecks - EnableFastChecks - MaxSpeed - MaxSpeed - %(PreprocessorDefinitions) - %(PreprocessorDefinitions) + MaxSpeed + %(PreprocessorDefinitions) - Disabled - Disabled - %(PreprocessorDefinitions) - %(PreprocessorDefinitions) + Disabled + %(PreprocessorDefinitions) EnableFastChecks - EnableFastChecks - EnableFastChecks - EnableFastChecks - MaxSpeed - MaxSpeed - %(PreprocessorDefinitions) - %(PreprocessorDefinitions) - - - true - true - true - true - true - true - true - true + MaxSpeed + %(PreprocessorDefinitions) + - Disabled - Disabled - %(PreprocessorDefinitions) - %(PreprocessorDefinitions) + Disabled + %(PreprocessorDefinitions) EnableFastChecks - EnableFastChecks - EnableFastChecks - EnableFastChecks - MaxSpeed - MaxSpeed - %(PreprocessorDefinitions) - %(PreprocessorDefinitions) + MaxSpeed + %(PreprocessorDefinitions) - - true - true - true - true - - Disabled - Disabled - %(PreprocessorDefinitions) - %(PreprocessorDefinitions) + Disabled + %(PreprocessorDefinitions) EnableFastChecks - EnableFastChecks - EnableFastChecks - EnableFastChecks - MaxSpeed - MaxSpeed - %(PreprocessorDefinitions) - %(PreprocessorDefinitions) + MaxSpeed + %(PreprocessorDefinitions) - Disabled - Disabled - %(PreprocessorDefinitions) - %(PreprocessorDefinitions) + Disabled + %(PreprocessorDefinitions) EnableFastChecks - EnableFastChecks - EnableFastChecks - EnableFastChecks Create - Create - Create - Create - MaxSpeed - MaxSpeed - %(PreprocessorDefinitions) - %(PreprocessorDefinitions) + MaxSpeed + %(PreprocessorDefinitions) Create - Create - Create - Create @@ -495,18 +211,11 @@ - Disabled - Disabled - %(PreprocessorDefinitions) - %(PreprocessorDefinitions) + Disabled + %(PreprocessorDefinitions) EnableFastChecks - EnableFastChecks - EnableFastChecks - EnableFastChecks - MaxSpeed - MaxSpeed - %(PreprocessorDefinitions) - %(PreprocessorDefinitions) + MaxSpeed + %(PreprocessorDefinitions) diff --git a/pfc/pfc.vcxproj.filters b/pfc/pfc.vcxproj.filters index fb812c1..a55b3b2 100644 --- a/pfc/pfc.vcxproj.filters +++ b/pfc/pfc.vcxproj.filters @@ -1,272 +1,89 @@  - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - + + + + + + + + + + + + + + + + + + + + + + + - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -280,11 +97,5 @@ {70b1137d-0c8f-4bb0-8adb-d406ad38bdd0} - - {225fc8b6-5fca-4e3f-b56e-1ad97e992841} - - - {e1ea3e94-74b7-464e-ab17-69508b52a4e6} - \ No newline at end of file diff --git a/pfc/primitives.h b/pfc/primitives.h index 15f35cf..12572fa 100644 --- a/pfc/primitives.h +++ b/pfc/primitives.h @@ -718,32 +718,11 @@ namespace pfc { - template - inline size_t remove_if_t( array_t & arr, pred_t pred ) { - const size_t inCount = arr.size(); - size_t walk = 0; - - - for( walk = 0; walk < inCount; ++ walk ) { - if ( pred(arr[walk]) ) break; - } - - size_t total = walk; - - for( ; walk < inCount; ++ walk ) { - if ( !pred(arr[walk] ) ) { - move_t(arr[total++], arr[walk]); - } - } - arr.resize(total); - - return total; - } template inline t_size remove_mask_t(t_array & p_array,const bit_array & p_mask)//returns amount of items left { - t_size n,count = p_array.size(), total = 0; + t_size n,count = p_array.get_size(), total = 0; n = total = p_mask.find(true,0,count); @@ -752,7 +731,7 @@ namespace pfc { for(n=p_mask.find(false,n+1,count-n-1);n void fill_array_t(t_array & p_array,const t_value & p_value); - // Generic no-op for breakpointing stuff - inline void nop() {} - class onLeaving { public: onLeaving() {} @@ -913,16 +889,7 @@ namespace pfc { onLeaving( const onLeaving & ) = delete; }; - template - class singleton { - public: - static obj_t instance; - }; - template - obj_t singleton::instance; - }; -#define PFC_SINGLETON(X) ::pfc::singleton::instance #define PFC_CLASS_NOT_COPYABLE(THISCLASSNAME,THISTYPE) \ diff --git a/pfc/printf.cpp b/pfc/printf.cpp index 3e65014..e236c40 100644 --- a/pfc/printf.cpp +++ b/pfc/printf.cpp @@ -77,7 +77,7 @@ void string_printf::g_run(string_base & out,const char * fmt,va_list list) } else if (*fmt=='x' || *fmt=='X') { - auto val = va_arg(list,unsigned); + int val = va_arg(list,int); if (force_sign && val>0) out.add_char('+'); pfc::format_uint temp(val, 0, 16); if (*fmt=='X') diff --git a/pfc/selftest.cpp b/pfc/selftest.cpp index ae3f5d4..7d7c9f5 100644 --- a/pfc/selftest.cpp +++ b/pfc/selftest.cpp @@ -43,16 +43,6 @@ namespace pfc { thread_selftest t; t.selftest(); } - { - pfc::map_t map; - map["1"] = 1; - map["2"] = 2; - map["3"] = 3; - PFC_ASSERT(map.get_count() == 3); - PFC_ASSERT(map["1"] == 1); - PFC_ASSERT(map["2"] == 2); - PFC_ASSERT(map["3"] == 3); - } } // Self test routines that fail at compile time if there's something seriously wrong void selftest_static() { diff --git a/pfc/stdsort.h b/pfc/stdsort.h deleted file mode 100644 index bbfe9d0..0000000 --- a/pfc/stdsort.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -// OPTIONAL pfc feature, include on need to use basis -// std sort interop methods - -#include -#include -#include - -namespace pfc { - - std::vector sort_identity( size_t count ) { - std::vector ret; ret.resize(count); - for( size_t walk = 0; walk < ret.size(); ++ walk) ret[walk] = walk; - return ret; - } - - template - std::vector sort_get_order(iterator_t i1, iterator_t i2, predicate_t pred ) { - auto ret = sort_identity( i2 - i1 ); - auto pred2 = [pred, i1] (size_t idx1, size_t idx2) { - return pred( *(i1+idx1), *(i1+idx2)); - }; - std::sort(ret.begin(), ret.end(), pred2); - return ret; - } - -} diff --git a/pfc/stringNew.h b/pfc/stringNew.h index 15e8a35..584e999 100644 --- a/pfc/stringNew.h +++ b/pfc/stringNew.h @@ -2,14 +2,14 @@ namespace pfc { //helper, const methods only - class _stringEmpty : public string_base { + class __stringEmpty : public string_base { public: const char * get_ptr() const {return "";} - void add_string(const char * ,t_size) {throw exception_not_implemented();} - void set_string(const char * ,t_size) {throw exception_not_implemented();} - void truncate(t_size) {throw exception_not_implemented();} + void add_string(const char * p_string,t_size p_length = ~0) {throw exception_not_implemented();} + void set_string(const char * p_string,t_size p_length = ~0) {throw exception_not_implemented();} + void truncate(t_size len) {throw exception_not_implemented();} t_size get_length() const {return 0;} - char * lock_buffer(t_size) {throw exception_not_implemented();} + char * lock_buffer(t_size p_requested_length) {throw exception_not_implemented();} void unlock_buffer() {throw exception_not_implemented();} }; @@ -23,7 +23,7 @@ namespace pfc { typedef rcptr_t t_data; typedef rcptr_t t_dataImpl; - string() : m_content(rcnew_t<_stringEmpty>()) {} + string() : m_content(rcnew_t<__stringEmpty>()) {} string(const char * p_source) : m_content(rcnew_t(p_source)) {} string(const char * p_source, t_size p_sourceLen) : m_content(rcnew_t(p_source,p_sourceLen)) {} string(char * p_source) : m_content(rcnew_t(p_source)) {} @@ -76,12 +76,12 @@ namespace pfc { string toLower() const { string8_fastalloc temp; temp.prealloc(128); - stringToLowerAppend(temp,ptr(),SIZE_MAX); + stringToLowerAppend(temp,ptr(),~0); return string(temp.get_ptr()); } string toUpper() const { string8_fastalloc temp; temp.prealloc(128); - stringToUpperAppend(temp,ptr(),SIZE_MAX); + stringToUpperAppend(temp,ptr(),~0); return string(temp.get_ptr()); } @@ -90,15 +90,15 @@ namespace pfc { //! @returns ~0 if not found. t_size indexOf(char c,t_size base = 0) const; //! @returns ~0 if not found. - t_size lastIndexOf(char c,t_size base = SIZE_MAX) const; + t_size lastIndexOf(char c,t_size base = ~0) const; //! @returns ~0 if not found. t_size indexOf(stringp s,t_size base = 0) const; //! @returns ~0 if not found. - t_size lastIndexOf(stringp s,t_size base = SIZE_MAX) const; + t_size lastIndexOf(stringp s,t_size base = ~0) const; //! @returns ~0 if not found. t_size indexOfAnyChar(stringp s,t_size base = 0) const; //! @returns ~0 if not found. - t_size lastIndexOfAnyChar(stringp s,t_size base = SIZE_MAX) const; + t_size lastIndexOfAnyChar(stringp s,t_size base = ~0) const; bool contains(char c) const; bool contains(stringp s) const; @@ -129,7 +129,7 @@ namespace pfc { t_size length() const {return m_content->get_length();} t_size get_length() const {return m_content->get_length();} - void set_string(const char * ptr, t_size len = SIZE_MAX) { + void set_string(const char * ptr, t_size len = ~0) { *this = string(ptr, len); } diff --git a/pfc/string_base.cpp b/pfc/string_base.cpp index f77893a..9433adb 100644 --- a/pfc/string_base.cpp +++ b/pfc/string_base.cpp @@ -1,5 +1,4 @@ #include "pfc.h" -#include namespace pfc { @@ -10,40 +9,6 @@ void string_receiver::add_char(t_uint32 p_char) if (len>0) add_string(temp,len); } -void string_base::skip_trailing_chars( const char * lstCharsStr ) { - std::set lstChars; - for ( ;; ) { - unsigned c; - auto delta = utf8_decode_char( lstCharsStr, c ); - if ( delta == 0 ) break; - lstCharsStr += delta; - lstChars.insert( c ); - } - - const char * str = get_ptr(); - t_size ptr,trunc = 0; - bool need_trunc = false; - for(ptr=0;str[ptr];) - { - unsigned c; - t_size delta = utf8_decode_char(str+ptr,c); - if (delta==0) break; - if ( lstChars.count( c ) > 0 ) - { - if (!need_trunc) { - need_trunc = true; - trunc = ptr; - } - } - else - { - need_trunc = false; - } - ptr += delta; - } - if (need_trunc) truncate(trunc); -} - void string_base::skip_trailing_char(unsigned skip) { const char * str = get_ptr(); @@ -965,7 +930,6 @@ double parse_timecode(const char * in) { } format_time_ex::format_time_ex(double p_seconds,unsigned p_extra) { - if (p_seconds < 0) {m_buffer << "-"; p_seconds = -p_seconds;} t_uint64 pow10 = pow10_helper(p_extra); t_uint64 ticks = pfc::rint64(pow10 * p_seconds); @@ -1029,7 +993,7 @@ int stringCompareCaseInsensitive(const char * s1, const char * s2) { } } -void format_file_size_short::format(t_uint64 size) { +format_file_size_short::format_file_size_short(t_uint64 size) { t_uint64 scale = 1; const char * unit = "B"; const char * const unitTable[] = {"B","KB","MB","GB","TB"}; @@ -1111,17 +1075,12 @@ void string_base::truncate_to_parent_path() { this->truncate( at ); } -size_t string_base::replace_string(const char * replace, const char * replaceWith, t_size start) { - string_formatter temp; - size_t ret = replace_string_ex(temp, replace, replaceWith, start); - if ( ret > 0 ) * this = temp; - return ret; -} -size_t string_base::replace_string_ex (string_base & temp, const char * replace, const char * replaceWith, t_size start) const { +t_size string_base::replace_string ( const char * replace, const char * replaceWith, t_size start) { + string_formatter temp; size_t srcDone = 0, walk = start; size_t occurances = 0; const char * const source = this->get_ptr(); - bool clear = false; + const size_t replaceLen = strlen( replace ); for(;;) { const char * ptr = strstr( source + walk, replace ); @@ -1135,18 +1094,15 @@ size_t string_base::replace_string_ex (string_base & temp, const char * replace, } ++occurances; walk = ptr - source; - if (! clear ) { - temp.reset(); - clear = true; - } temp.add_string( source + srcDone, walk - srcDone ); temp.add_string( replaceWith ); walk += replaceLen; srcDone = walk; } + this->set_string( temp ); return occurances; + } - void urlEncodeAppendRaw(pfc::string_base & out, const char * in, t_size inSize) { for(t_size walk = 0; walk < inSize; ++walk) { const char c = in[walk]; @@ -1190,7 +1146,7 @@ uint32_t charLower(uint32_t param) } #ifdef PFC_WINDOWS_DESKTOP_APP else if (param<0x10000) { - return (uint32_t)(size_t)CharLowerW((WCHAR*)(size_t)param); + return (unsigned)CharLowerW((WCHAR*)param); } #endif else return param; @@ -1204,7 +1160,7 @@ uint32_t charUpper(uint32_t param) } #ifdef PFC_WINDOWS_DESKTOP_APP else if (param<0x10000) { - return (uint32_t)(size_t)CharUpperW((WCHAR*)(size_t)param); + return (unsigned)CharUpperW((WCHAR*)param); } #endif else return param; @@ -1334,34 +1290,4 @@ void string_base::fix_dir_separator(char c) { return equals(make(str) ); } - string8 lineEndingsToWin(const char * str) { - string8 ret; - const char * walk = str; - for( ;; ) { - const char * eol = strchr( walk, '\n' ); - if ( eol == nullptr ) { - ret += walk; break; - } - const char * next = eol + 1; - if ( eol > walk ) { - if (eol[-1] == '\r') --eol; - if ( eol > walk ) ret.add_string_nc(walk, eol-walk); - } - ret.add_string_nc("\r\n",2); - walk = next; - } - return ret; - } - - string8 stringToUpper(const char * str, size_t len) { - string8 ret; - stringToUpperAppend(ret, str, len); - return ret; - } - string8 stringToLower(const char * str, size_t len) { - string8 ret; - stringToLowerAppend(ret, str, len); - return ret; - } - } //namespace pfc diff --git a/pfc/string_base.h b/pfc/string_base.h index 33aea19..e3951f7 100644 --- a/pfc/string_base.h +++ b/pfc/string_base.h @@ -28,7 +28,7 @@ namespace pfc { class NOVTABLE string_receiver { public: - virtual void add_string(const char * p_string,t_size p_string_size = SIZE_MAX) = 0; + virtual void add_string(const char * p_string,t_size p_string_size = ~0) = 0; inline void add_string_(const char * str) {add_string(str, _strParamLen(str));} void add_char(t_uint32 c);//adds unicode char to the string @@ -43,9 +43,9 @@ namespace pfc { bool is_path_separator(unsigned c); bool is_path_bad_char(unsigned c); - bool is_valid_utf8(const char * param,t_size max = SIZE_MAX); + bool is_valid_utf8(const char * param,t_size max = ~0); bool is_lower_ascii(const char * param); - bool is_multiline(const char * p_string,t_size p_len = SIZE_MAX); + bool is_multiline(const char * p_string,t_size p_len = ~0); bool has_path_bad_chars(const char * param); void recover_invalid_utf8(const char * src,char * out,unsigned replace);//out must be enough to hold strlen(char) + 1, or appropiately bigger if replace needs multiple chars void convert_to_lower_ascii(const char * src,t_size max,char * out,char replace = '?');//out should be at least strlen(src)+1 long @@ -54,14 +54,14 @@ namespace pfc { template inline char_t ascii_toupper(char_t c) {if (c >= 'a' && c <= 'z') c += 'A' - 'a'; return c;} t_size string_find_first(const char * p_string,char p_tofind,t_size p_start = 0); //returns infinite if not found - t_size string_find_last(const char * p_string,char p_tofind,t_size p_start = SIZE_MAX); //returns infinite if not found + t_size string_find_last(const char * p_string,char p_tofind,t_size p_start = ~0); //returns infinite if not found t_size string_find_first(const char * p_string,const char * p_tofind,t_size p_start = 0); //returns infinite if not found - t_size string_find_last(const char * p_string,const char * p_tofind,t_size p_start = SIZE_MAX); //returns infinite if not found + t_size string_find_last(const char * p_string,const char * p_tofind,t_size p_start = ~0); //returns infinite if not found t_size string_find_first_ex(const char * p_string,t_size p_string_length,char p_tofind,t_size p_start = 0); //returns infinite if not found - t_size string_find_last_ex(const char * p_string,t_size p_string_length,char p_tofind,t_size p_start = SIZE_MAX); //returns infinite if not found + t_size string_find_last_ex(const char * p_string,t_size p_string_length,char p_tofind,t_size p_start = ~0); //returns infinite if not found t_size string_find_first_ex(const char * p_string,t_size p_string_length,const char * p_tofind,t_size p_tofind_length,t_size p_start = 0); //returns infinite if not found - t_size string_find_last_ex(const char * p_string,t_size p_string_length,const char * p_tofind,t_size p_tofind_length,t_size p_start = SIZE_MAX); //returns infinite if not found + t_size string_find_last_ex(const char * p_string,t_size p_string_length,const char * p_tofind,t_size p_tofind_length,t_size p_start = ~0); //returns infinite if not found t_size string_find_first_nc(const char * p_string,t_size p_string_length,char c,t_size p_start = 0); // lengths MUST be valid, no checks are performed (faster than the other flavour) @@ -88,7 +88,7 @@ namespace pfc { inline t_size tcslen_max(const TCHAR * ptr,t_size max) {return strlen_max_t(ptr,max);} #endif - bool string_is_numeric(const char * p_string,t_size p_length = SIZE_MAX) throw(); + bool string_is_numeric(const char * p_string,t_size p_length = ~0) throw(); template inline bool char_is_numeric(char_t p_char) throw() {return p_char >= '0' && p_char <= '9';} inline bool char_is_hexnumeric(char p_char) throw() {return char_is_numeric(p_char) || (p_char >= 'a' && p_char <= 'f') || (p_char >= 'A' && p_char <= 'F');} inline bool char_is_ascii_alpha_upper(char p_char) throw() {return p_char >= 'A' && p_char <= 'Z';} @@ -124,8 +124,8 @@ namespace pfc { return ret; } - t_size strlen_utf8(const char * s,t_size num = SIZE_MAX) throw();//returns number of characters in utf8 string; num - no. of bytes (optional) - t_size utf8_char_len(const char * s,t_size max = SIZE_MAX) throw();//returns size of utf8 character pointed by s, in bytes, 0 on error + t_size strlen_utf8(const char * s,t_size num = ~0) throw();//returns number of characters in utf8 string; num - no. of bytes (optional) + t_size utf8_char_len(const char * s,t_size max = ~0) throw();//returns size of utf8 character pointed by s, in bytes, 0 on error t_size utf8_char_len_from_header(char c) throw(); t_size utf8_chars_to_bytes(const char * string,t_size count) throw(); @@ -141,15 +141,15 @@ namespace pfc { t_size utf8_encode_char(unsigned c,char * out) throw();//returns used length in bytes, max 6 - t_size utf16_decode_char(const char16_t * p_source,unsigned * p_out,t_size p_source_length = SIZE_MAX) throw(); + t_size utf16_decode_char(const char16_t * p_source,unsigned * p_out,t_size p_source_length = ~0) throw(); t_size utf16_encode_char(unsigned c,char16_t * out) throw(); #ifdef _MSC_VER - t_size utf16_decode_char(const wchar_t * p_source,unsigned * p_out,t_size p_source_length = SIZE_MAX) throw(); + t_size utf16_decode_char(const wchar_t * p_source,unsigned * p_out,t_size p_source_length = ~0) throw(); t_size utf16_encode_char(unsigned c,wchar_t * out) throw(); #endif - t_size wide_decode_char(const wchar_t * p_source,unsigned * p_out,t_size p_source_length = SIZE_MAX) throw(); + t_size wide_decode_char(const wchar_t * p_source,unsigned * p_out,t_size p_source_length = ~0) throw(); t_size wide_encode_char(unsigned c,wchar_t * out) throw(); @@ -188,8 +188,8 @@ namespace pfc { public: virtual const char * get_ptr() const = 0; const char * c_str() const { return get_ptr(); } - virtual void add_string(const char * p_string,t_size p_length = SIZE_MAX) = 0;//same as string_receiver method - virtual void set_string(const char * p_string,t_size p_length = SIZE_MAX) {reset();add_string(p_string,p_length);} + virtual void add_string(const char * p_string,t_size p_length = ~0) = 0;//same as string_receiver method + virtual void set_string(const char * p_string,t_size p_length = ~0) {reset();add_string(p_string,p_length);} virtual void truncate(t_size len)=0; virtual t_size get_length() const {return strlen(get_ptr());} virtual char * lock_buffer(t_size p_requested_length) = 0; @@ -203,11 +203,9 @@ namespace pfc { inline t_size length() const {return get_length();} inline void reset() {truncate(0);} - inline void clear() {truncate(0);} - + inline bool is_empty() const {return *get_ptr()==0;} - void skip_trailing_chars( const char * lstChars ); void skip_trailing_char(unsigned c = ' '); bool is_valid_utf8() const {return pfc::is_valid_utf8(get_ptr());} @@ -231,9 +229,9 @@ namespace pfc { t_size scan_filename() const {return pfc::scan_filename(get_ptr());} t_size find_first(char p_char,t_size p_start = 0) const {return pfc::string_find_first(get_ptr(),p_char,p_start);} - t_size find_last(char p_char,t_size p_start = SIZE_MAX) const {return pfc::string_find_last(get_ptr(),p_char,p_start);} + t_size find_last(char p_char,t_size p_start = ~0) const {return pfc::string_find_last(get_ptr(),p_char,p_start);} t_size find_first(const char * p_string,t_size p_start = 0) const {return pfc::string_find_first(get_ptr(),p_string,p_start);} - t_size find_last(const char * p_string,t_size p_start = SIZE_MAX) const {return pfc::string_find_last(get_ptr(),p_string,p_start);} + t_size find_last(const char * p_string,t_size p_start = ~0) const {return pfc::string_find_last(get_ptr(),p_string,p_start);} void fix_dir_separator(char c = '\\'); // Backwards compat function, "do what I mean" applied on non Windows void end_with(char c); @@ -252,12 +250,7 @@ namespace pfc { void truncate_to_parent_path(); void add_filename( const char * fn ) {end_with_slash(); *this += fn; } - //! Replaces one string with another. Returns the number of occurances - zero if the string was not altered. - size_t replace_string ( const char * replace, const char * replaceWith, t_size start = 0); - //! Replaces one string with another, writing the output to another string object. \n - //! Returns the number of occurances replaced. \n - //! Special: returns zero if no occurances were found - and the target string is NOT modified if so. Use with care! - size_t replace_string_ex( pfc::string_base & target, const char * replace, const char * replaceWith, t_size start = 0) const; + t_size replace_string ( const char * replace, const char * replaceWith, t_size start = 0); string_base & _formatter() const {return const_cast(*this);} @@ -384,8 +377,8 @@ namespace pfc { const char * get_ptr() const throw() {return _get_ptr();} - void add_string(const char * p_string,t_size p_length = SIZE_MAX); - void set_string(const char * p_string,t_size p_length = SIZE_MAX); + void add_string(const char * p_string,t_size p_length = ~0); + void set_string(const char * p_string,t_size p_length = ~0); void set_string(string_part_ref ref) {set_string_nc(ref.m_ptr, ref.m_len);} void add_string(string_part_ref ref) {add_string_nc(ref.m_ptr, ref.m_len);} @@ -545,7 +538,7 @@ namespace pfc { }; void float_to_string(char * out,t_size out_max,double val,unsigned precision,bool force_sign = false);//doesnt add E+X etc, has internal range limits, useful for storing float numbers as strings without having to bother with international coma/dot settings BS - double string_to_float(const char * src,t_size len = SIZE_MAX); + double string_to_float(const char * src,t_size len = ~0); template<> inline void swap_t(string8 & p_item1,string8 & p_item2) @@ -670,7 +663,7 @@ namespace pfc { template class format_pad_left { public: - format_pad_left(t_size p_chars,t_uint32 p_padding /* = ' ' */,const char * p_string,t_size p_string_length = SIZE_MAX) { + format_pad_left(t_size p_chars,t_uint32 p_padding /* = ' ' */,const char * p_string,t_size p_string_length = ~0) { t_size source_len = 0, source_walk = 0; while(source_walk < p_string_length && source_len < p_chars) { @@ -694,7 +687,7 @@ namespace pfc { template class format_pad_right { public: - format_pad_right(t_size p_chars,t_uint32 p_padding /* = ' ' */,const char * p_string,t_size p_string_length = SIZE_MAX) { + format_pad_right(t_size p_chars,t_uint32 p_padding /* = ' ' */,const char * p_string,t_size p_string_length = ~0) { t_size source_len = 0, source_walk = 0; while(source_walk < p_string_length && source_len < p_chars) { @@ -719,11 +712,9 @@ namespace pfc { class format_file_size_short : public string_formatter { public: - format_file_size_short(t_uint64 size) { format(size); } - format_file_size_short(t_uint64 size, uint64_t * usedScale) { format(size); *usedScale = m_scale; } + format_file_size_short(t_uint64 size); t_uint64 get_used_scale() const {return m_scale;} private: - void format(uint64_t size); t_uint64 m_scale; }; @@ -844,13 +835,13 @@ namespace pfc { inline static int compare(const wchar_t * item1, const wchar_t * item2) {return wcscmp(item1, item2);} static int compare(const char * p_item1, string_part_ref p_item2) { - return strcmp_ex(p_item1, SIZE_MAX, p_item2.m_ptr, p_item2.m_len); + return strcmp_ex(p_item1, ~0, p_item2.m_ptr, p_item2.m_len); } static int compare(string_part_ref p_item1, string_part_ref p_item2) { return strcmp_ex(p_item1.m_ptr, p_item1.m_len, p_item2.m_ptr, p_item2.m_len); } static int compare(string_part_ref p_item1, const char * p_item2) { - return strcmp_ex(p_item1.m_ptr, p_item1.m_len, p_item2, SIZE_MAX); + return strcmp_ex(p_item1.m_ptr, p_item1.m_len, p_item2, ~0); } }; @@ -877,7 +868,7 @@ namespace pfc { } template - void splitStringEx(t_output & p_output, const t_splitCheck & p_check, const char * p_string, t_size p_stringLen = SIZE_MAX) { + void splitStringEx(t_output & p_output, const t_splitCheck & p_check, const char * p_string, t_size p_stringLen = ~0) { t_size walk = 0, splitBase = 0; const t_size max = strlen_max(p_string,p_stringLen); for(;walk < max;) { @@ -960,7 +951,7 @@ namespace pfc { }; template - void splitStringSimple_toArray(t_array & p_output, t_split p_split, const char * p_string, t_size p_stringLen = SIZE_MAX) { + void splitStringSimple_toArray(t_array & p_output, t_split p_split, const char * p_string, t_size p_stringLen = ~0) { _splitStringSimple_check strCheck(p_split); { @@ -975,7 +966,7 @@ namespace pfc { } } template - void splitStringSimple_toList(t_list & p_output, t_split p_split, const char * p_string, t_size p_stringLen = SIZE_MAX) { + void splitStringSimple_toList(t_list & p_output, t_split p_split, const char * p_string, t_size p_stringLen = ~0) { _splitStringSimple_check strCheck(p_split); __splitStringSimple_listWrapper wrapper(p_output); @@ -1041,10 +1032,10 @@ namespace pfc { const char * get_ptr() const {return m_ptr;} t_size get_length() const {return m_len;} private: - void add_string(const char *,t_size) {throw pfc::exception_not_implemented();} - void set_string(const char *,t_size) {throw pfc::exception_not_implemented();} - void truncate(t_size) {throw pfc::exception_not_implemented();} - char * lock_buffer(t_size) {throw pfc::exception_not_implemented();} + void add_string(const char * p_string,t_size p_length = ~0) {throw pfc::exception_not_implemented();} + void set_string(const char * p_string,t_size p_length = ~0) {throw pfc::exception_not_implemented();} + void truncate(t_size len) {throw pfc::exception_not_implemented();} + char * lock_buffer(t_size p_requested_length) {throw pfc::exception_not_implemented();} void unlock_buffer() {throw pfc::exception_not_implemented();} private: const char * const m_ptr; @@ -1091,7 +1082,7 @@ namespace pfc { } template - int strcmp_partial_t(const t_char * p_string,const t_char * p_substring) throw() {return strcmp_partial_ex_t(p_string,SIZE_MAX,p_substring,SIZE_MAX);} + int strcmp_partial_t(const t_char * p_string,const t_char * p_substring) throw() {return strcmp_partial_ex_t(p_string,~0,p_substring,~0);} inline int strcmp_partial_ex(const char * str, t_size strLen, const char * substr, t_size substrLen) throw() {return strcmp_partial_ex_t(str, strLen, substr, substrLen); } inline int strcmp_partial(const char * str, const char * substr) throw() {return strcmp_partial_t(str, substr); } @@ -1104,9 +1095,4 @@ namespace pfc { char * strDup(const char * src); // POSIX strdup() clone, prevent MSVC complaining - - string8 lineEndingsToWin( const char * str ); - - string8 stringToUpper( const char * str, size_t len = SIZE_MAX ); - string8 stringToLower( const char * str, size_t len = SIZE_MAX ); } diff --git a/pfc/string_conv.cpp b/pfc/string_conv.cpp index dd63acd..8ba9607 100644 --- a/pfc/string_conv.cpp +++ b/pfc/string_conv.cpp @@ -469,7 +469,7 @@ namespace pfc { t_size convert_codepage_to_wide(unsigned p_codepage,wchar_t * p_out,t_size p_out_size,const char * p_source,t_size p_source_size) { if (p_out_size == 0) return 0; memset(p_out,0,p_out_size * sizeof(*p_out)); - MultiByteToWideChar(p_codepage,0,p_source, pfc::downcast_guarded(p_source_size),p_out, pfc::downcast_guarded(p_out_size)); + MultiByteToWideChar(p_codepage,0,p_source,p_source_size,p_out,p_out_size); p_out[p_out_size-1] = 0; return wcslen(p_out); } @@ -477,16 +477,16 @@ namespace pfc { t_size convert_wide_to_codepage(unsigned p_codepage,char * p_out,t_size p_out_size,const wchar_t * p_source,t_size p_source_size) { if (p_out_size == 0) return 0; memset(p_out,0,p_out_size * sizeof(*p_out)); - WideCharToMultiByte(p_codepage,0,p_source,pfc::downcast_guarded(p_source_size),p_out,pfc::downcast_guarded(p_out_size),0,FALSE); + WideCharToMultiByte(p_codepage,0,p_source,p_source_size,p_out,p_out_size,0,FALSE); p_out[p_out_size-1] = 0; return strlen(p_out); } t_size estimate_codepage_to_wide(unsigned p_codepage,const char * p_source,t_size p_source_size) { - return MultiByteToWideChar(p_codepage,0,p_source, pfc::downcast_guarded(strlen_max(p_source,p_source_size)),0,0) + 1; + return MultiByteToWideChar(p_codepage,0,p_source,strlen_max(p_source,p_source_size),0,0) + 1; } t_size estimate_wide_to_codepage(unsigned p_codepage,const wchar_t * p_source,t_size p_source_size) { - return WideCharToMultiByte(p_codepage,0,p_source, pfc::downcast_guarded(wcslen_max(p_source,p_source_size)),0,0,0,FALSE) + 1; + return WideCharToMultiByte(p_codepage,0,p_source,wcslen_max(p_source,p_source_size),0,0,0,FALSE) + 1; } } diff --git a/pfc/string_conv.h b/pfc/string_conv.h index f0d5adc..ebc3ce5 100644 --- a/pfc/string_conv.h +++ b/pfc/string_conv.h @@ -436,7 +436,7 @@ namespace pfc { void convert(unsigned p_codepage,const char * p_source,t_size p_source_size = ~0) { string_wide_from_utf8 temp; temp.convert(p_source,p_source_size); - t_size size = estimate_wide_to_codepage(p_codepage,temp,SIZE_MAX); + t_size size = estimate_wide_to_codepage(p_codepage,temp,~0); m_buffer.set_size(size); convert_wide_to_codepage(p_codepage,m_buffer.get_ptr_var(),size,temp,~0); } @@ -459,9 +459,9 @@ namespace pfc { void convert(unsigned p_codepage,const char * p_source,t_size p_source_size = ~0) { string_wide_from_codepage temp; temp.convert(p_codepage,p_source,p_source_size); - t_size size = estimate_wide_to_utf8(temp,SIZE_MAX); + t_size size = estimate_wide_to_utf8(temp,~0); m_buffer.set_size(size); - convert_wide_to_utf8( m_buffer.get_ptr_var(),size,temp,SIZE_MAX); + convert_wide_to_utf8( m_buffer.get_ptr_var(),size,temp,~0); } operator const char * () const {return get_ptr();} diff --git a/pfc/suppress_fb2k_hooks.h b/pfc/suppress_fb2k_hooks.h index 61d96ce..16486e1 100644 --- a/pfc/suppress_fb2k_hooks.h +++ b/pfc/suppress_fb2k_hooks.h @@ -1,19 +1,12 @@ #pragma once -/* -foobar2000 shared.dll hook implementations -If you're getting linker multiple-definition errors on these, change build configuration of PFC from "Debug" / "Release" to "Debug FB2K" / "Release FB2K" -Configurations with "FB2K" suffix disable compilation of pfc-fb2k-hooks.cpp allowing these methods to be redirected to shared.dll calls -*/ - namespace pfc { void crashImpl(); + void crashHook() {crashImpl();} + BOOL winFormatSystemErrorMessageImpl(pfc::string_base & p_out, DWORD p_code); - void crashHook() { - crashImpl(); - } BOOL winFormatSystemErrorMessageHook(pfc::string_base & p_out, DWORD p_code) { return winFormatSystemErrorMessageImpl(p_out, p_code); } -} +} \ No newline at end of file diff --git a/pfc/synchro.h b/pfc/synchro.h index 73fac72..2d0ecf5 100644 --- a/pfc/synchro.h +++ b/pfc/synchro.h @@ -1,16 +1,2 @@ #pragma once -// added for compatibility with fb2k mobile - -namespace pfc { - class dummyLock { - public: - void enterRead() {} - void enterWrite() {} - void leaveRead() {} - void leaveWrite() {} - void enter() {} - void leave() {} - void lock() {} - void unlock() {} - }; -} \ No newline at end of file +// added for compatibility with fb2k mobile \ No newline at end of file diff --git a/pfc/synchro_win.h b/pfc/synchro_win.h index fa0b5eb..af95686 100644 --- a/pfc/synchro_win.h +++ b/pfc/synchro_win.h @@ -15,7 +15,6 @@ public: #endif } inline void destroy() throw() {DeleteCriticalSection(&sec);} - inline bool tryEnter() throw() { return !!TryEnterCriticalSection(&sec); } private: _critical_section_base(const _critical_section_base&); void operator=(const _critical_section_base&); @@ -32,28 +31,24 @@ public: // Regular critical section, intended for any lifetime scopes class critical_section : public _critical_section_base { +private: + CRITICAL_SECTION sec; public: critical_section() {create();} ~critical_section() {destroy();} }; -template -class c_insync_ +class c_insync { private: - lock_t& m_section; + _critical_section_base & m_section; public: - c_insync_(lock_t * p_section) throw() : m_section(*p_section) {m_section.enter();} - c_insync_(lock_t & p_section) throw() : m_section(p_section) {m_section.enter();} - ~c_insync_() throw() {m_section.leave();} + c_insync(_critical_section_base * p_section) throw() : m_section(*p_section) {m_section.enter();} + c_insync(_critical_section_base & p_section) throw() : m_section(p_section) {m_section.enter();} + ~c_insync() throw() {m_section.leave();} }; -typedef c_insync_<_critical_section_base> c_insync; - -// Old typedef for backwards compat #define insync(X) c_insync blah____sync(X) -// New typedef -#define PFC_INSYNC(X) c_insync_ blah____sync(X) namespace pfc { @@ -61,6 +56,32 @@ namespace pfc { // Read write lock - Vista-and-newer friendly lock that allows concurrent reads from a resource that permits such // Warning, non-recursion proof +#if _WIN32_WINNT < 0x600 + +// Inefficient fallback implementation for pre Vista OSes +class readWriteLock { +public: + readWriteLock() {} + void enterRead() { + m_obj.enter(); + } + void enterWrite() { + m_obj.enter(); + } + void leaveRead() { + m_obj.leave(); + } + void leaveWrite() { + m_obj.leave(); + } +private: + critical_section m_obj; + + readWriteLock( const readWriteLock & ) = delete; + void operator=( const readWriteLock & ) = delete; +}; + +#else class readWriteLock { public: readWriteLock() : theLock() { @@ -85,6 +106,7 @@ private: SRWLOCK theLock; }; +#endif class _readWriteLock_scope_read { public: diff --git a/pfc/targetver.h b/pfc/targetver.h deleted file mode 100644 index 809eaad..0000000 --- a/pfc/targetver.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0601 -#include -#endif \ No newline at end of file diff --git a/pfc/threads.h b/pfc/threads.h index f06bfb0..3a27ae9 100644 --- a/pfc/threads.h +++ b/pfc/threads.h @@ -59,7 +59,6 @@ namespace pfc { //! Thread class using lambda entrypoint rather than function override class thread2 : public thread { public: - ~thread2() { waitTillDone(); } void startHereWithPriority(std::function e, int priority); void startHere(std::function e); void setEntry(std::function e); diff --git a/pfc/timers.cpp b/pfc/timers.cpp index 9bda731..835f86f 100644 --- a/pfc/timers.cpp +++ b/pfc/timers.cpp @@ -1,9 +1,5 @@ #include "pfc.h" -#if defined(_WIN32) && defined(PFC_HAVE_PROFILER) -#include -#endif - namespace pfc { #ifdef PFC_HAVE_PROFILER @@ -15,39 +11,6 @@ profiler_static::profiler_static(const char * p_name) num_called = 0; } -static void profilerMsg(const char* msg) { -#ifdef _WIN32 - if (!IsDebuggerPresent()) { - static HANDLE hWriteTo = INVALID_HANDLE_VALUE; - static bool initialized = false; - if (!initialized) { - initialized = true; - wchar_t path[1024] = {}; - if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_DESKTOP, NULL, SHGFP_TYPE_CURRENT, path))) { - size_t l = wcslen(path); - if (l > 0) { - if (path[l - 1] != '\\') { - wcscat_s(path, L"\\"); - } - wchar_t fn[256]; - wsprintf(fn, L"profiler-%u.txt", GetProcessId(GetCurrentProcess())); - wcscat_s(path, fn); - hWriteTo = CreateFile(path, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, 0, NULL); - } - } - } - if (hWriteTo != INVALID_HANDLE_VALUE) { - SetFilePointer(hWriteTo, 0, 0, SEEK_END); - pfc::string8 temp = msg; - temp += "\r\n"; - DWORD written = 0; - WriteFile(hWriteTo, temp.c_str(), temp.length(), &written, NULL); - } - } -#endif - outputDebugLine(msg); -} - profiler_static::~profiler_static() { try { @@ -58,7 +21,8 @@ profiler_static::~profiler_static() if (num_called > 0) { message << " (executed " << num_called << " times, " << (total_time / num_called) << " average)"; } - profilerMsg(message); + message << "\n"; + OutputDebugStringA(message); } catch(...) { //should never happen OutputDebugString(_T("unexpected profiler failure\n")); diff --git a/pfc/timers.h b/pfc/timers.h index 8163bf0..c412e7b 100644 --- a/pfc/timers.h +++ b/pfc/timers.h @@ -42,9 +42,14 @@ namespace pfc { #ifdef _WIN32 namespace pfc { - // ALWAYS define 64bit tickcount - don't cause mayhem if different modules are compiled for different Windows versions - typedef uint64_t tickcount_t; - inline tickcount_t getTickCount() { return GetTickCount64(); } +#if _WIN32_WINNT >= 0x600 +typedef uint64_t tickcount_t; +inline tickcount_t getTickCount() { return GetTickCount64(); } +#else +#define PFC_TICKCOUNT_32BIT +typedef uint32_t tickcount_t; +inline tickcount_t getTickCount() { return GetTickCount(); } +#endif class hires_timer { public: @@ -83,7 +88,7 @@ private: class lores_timer { public: - lores_timer() {} + lores_timer() : m_start() {} void start() { _start(getTickCount()); } @@ -102,12 +107,25 @@ public: } private: void _start(tickcount_t p_time) { +#ifdef PFC_TICKCOUNT_32BIT + m_last_seen = p_time; +#endif m_start = p_time; } double _query(tickcount_t p_time) const { +#ifdef PFC_TICKCOUNT_32BIT + t_uint64 time = p_time; + if (time < (m_last_seen & 0xFFFFFFFF)) time += 0x100000000; + m_last_seen = (m_last_seen & 0xFFFFFFFF00000000) + time; + return (double)(m_last_seen - m_start) / 1000.0; +#else return (double)(p_time - m_start) / 1000.0; +#endif } - t_uint64 m_start = 0; + t_uint64 m_start; +#ifdef PFC_TICKCOUNT_32BIT + mutable t_uint64 m_last_seen; +#endif }; } #else // not _WIN32 diff --git a/pfc/utf8.cpp b/pfc/utf8.cpp index 21ea3ca..783ede9 100644 --- a/pfc/utf8.cpp +++ b/pfc/utf8.cpp @@ -60,7 +60,7 @@ unsigned strcpy_utf8_truncate(const char * src,char * out,unsigned maxbytes) maxbytes--;//for null while(!check_end_of_string(src) && maxbytes>0) { - unsigned delta = (unsigned)utf8_char_len(src); + t_size delta = utf8_char_len(src); if (delta>maxbytes || delta==0) break; maxbytes -= delta; do diff --git a/pfc/wait_queue.h b/pfc/wait_queue.h index a8387d9..a4962ac 100644 --- a/pfc/wait_queue.h +++ b/pfc/wait_queue.h @@ -26,9 +26,7 @@ namespace pfc { m_eof = true; m_canRead.set_state(true); } - bool wait_read( double timeout ) { - return m_canRead.wait_for( timeout ); - } + eventHandle_t get_event_handle() { return m_canRead.get_handle(); } diff --git a/pfc/weakRef.h b/pfc/weakRef.h deleted file mode 100644 index 0c26686..0000000 --- a/pfc/weakRef.h +++ /dev/null @@ -1,71 +0,0 @@ -#pragma once - -// PFC weakRef class -// Create weak references to objects that automatically become invalidated upon destruction of the object -// Note that this is NOT thread safe and meant for single thread usage. If you require thread safety, provide your own means, such as mutexlocking of weakRef::get() and the destruction of your objects. - -#include // std::shared_ptr - -namespace pfc { - typedef std::shared_ptr weakRefKillSwitch_t; - - template - class weakRef { - typedef weakRef self_t; - public: - static self_t _make(target_t * target, weakRefKillSwitch_t ks) { - self_t ret; - ret.m_target = target; - ret.m_ks = ks; - return ret; - } - - - bool isValid() const { - return m_ks && !*m_ks; - } - - target_t * get() const { - if (!isValid()) return nullptr; - return m_target; - } - target_t * operator() () const { - return get(); - } - private: - target_t * m_target = nullptr; - weakRefKillSwitch_t m_ks; - }; - - template - class weakRefTarget { - public: - weakRefTarget() {} - - typedef weakRef weakRef_t; - - weakRef weakRef() { - PFC_ASSERT(!*m_ks); - class_t * ptr = static_cast(this); - return weakRef_t::_make(ptr, m_ks); - } - - // Optional: explicitly invalidates all weak references to this object. Called implicitly by the destructor, but you can do it yourself earlier. - void weakRefShutdown() { - *m_ks = true; - } - ~weakRefTarget() { - weakRefShutdown(); - } - - // Optional: obtain a reference to the killswitch if you wish to use it directly - weakRefKillSwitch_t weakRefKS() const { - return m_ks; - } - private: - std::shared_ptr m_ks = std::make_shared(false); - - weakRefTarget(const weakRefTarget &) = delete; - void operator=(const weakRefTarget &) = delete; - }; -} diff --git a/pfc/win-objects.cpp b/pfc/win-objects.cpp index 0939bb9..55a2bd6 100644 --- a/pfc/win-objects.cpp +++ b/pfc/win-objects.cpp @@ -4,9 +4,12 @@ #ifdef _WIN32 -#include "pfc-fb2k-hooks.h" namespace pfc { +#ifdef PFC_FOOBAR2000_CLASSIC + BOOL winFormatSystemErrorMessageHook(pfc::string_base & p_out, DWORD p_code); +#endif + BOOL winFormatSystemErrorMessageImpl(pfc::string_base & p_out,DWORD p_code) { switch(p_code) { @@ -74,13 +77,17 @@ void winPrefixPath(pfc::string_base & out, const char * p_path) { }; BOOL winFormatSystemErrorMessage(pfc::string_base & p_out, DWORD p_code) { +#ifdef PFC_FOOBAR2000_CLASSIC return winFormatSystemErrorMessageHook( p_out, p_code ); +#else + return winFormatSystemErrorMessageImpl( p_out, p_code ); +#endif } void winUnPrefixPath(pfc::string_base & out, const char * p_path) { const char * prepend_header = "\\\\?\\"; const char * prepend_header_net = "\\\\?\\UNC\\"; if (pfc::strcmp_partial(p_path, prepend_header_net) == 0) { - out = PFC_string_formatter() << "\\\\" << (p_path + strlen(prepend_header_net) ); + out = pfc::string_formatter() << "\\\\" << (p_path + strlen(prepend_header_net) ); return; } if (pfc::strcmp_partial(p_path, prepend_header) == 0) { @@ -120,43 +127,6 @@ void format_hresult::stamp_hex(HRESULT p_code) { #ifdef PFC_WINDOWS_DESKTOP_APP -namespace pfc { - HWND findOwningPopup(HWND p_wnd) - { - HWND walk = p_wnd; - while (walk != 0 && (GetWindowLong(walk, GWL_STYLE) & WS_CHILD) != 0) - walk = GetParent(walk); - return walk ? walk : p_wnd; - } - string8 getWindowClassName(HWND wnd) { - TCHAR temp[1024] = {}; - if (GetClassName(wnd, temp, PFC_TABSIZE(temp)) == 0) { - PFC_ASSERT(!"Should not get here"); - return ""; - } - return pfc::stringcvt::string_utf8_from_os(temp).get_ptr(); - } - void setWindowText(HWND wnd, const char * txt) { - SetWindowText(wnd, stringcvt::string_os_from_utf8(txt)); - } - string8 getWindowText(HWND wnd) { - PFC_ASSERT(wnd != NULL); - int len = GetWindowTextLength(wnd); - if (len >= 0) - { - len++; - pfc::array_t temp; - temp.set_size(len); - temp[0] = 0; - if (GetWindowText(wnd, temp.get_ptr(), len) > 0) - { - return stringcvt::string_utf8_from_os(temp.get_ptr(), len).get_ptr(); - } - } - return ""; - } -} - void uAddWindowStyle(HWND p_wnd,LONG p_style) { SetWindowLong(p_wnd,GWL_STYLE, GetWindowLong(p_wnd,GWL_STYLE) | p_style); } @@ -378,19 +348,6 @@ namespace pfc { bool isAltKeyPressed() { return IsKeyPressed(VK_MENU); } - - void winSetThreadDescription(HANDLE hThread, const wchar_t * desc) { -#if _WIN32_WINNT >= 0xA00 - SetThreadDescription(hThread, desc); -#else - auto proc = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "SetThreadDescription"); - if (proc != nullptr) { - typedef HRESULT(__stdcall * pSetThreadDescription_t)(HANDLE hThread, PCWSTR lpThreadDescription); - auto proc2 = reinterpret_cast(proc); - proc2(hThread, desc); - } -#endif - } } #else diff --git a/pfc/win-objects.h b/pfc/win-objects.h index df93d3a..d5ca70b 100644 --- a/pfc/win-objects.h +++ b/pfc/win-objects.h @@ -19,11 +19,6 @@ namespace pfc { private: const DWORD m_val; }; - - string8 getWindowText(HWND wnd); - void setWindowText(HWND wnd, const char * txt); - string8 getWindowClassName( HWND wnd ); - HWND findOwningPopup(HWND wnd); } @@ -50,8 +45,7 @@ private: pfc::string_formatter m_buffer; }; -class exception_win32 : public std::exception { -public: +struct exception_win32 : public std::exception { exception_win32(DWORD p_code) : std::exception(format_win32_error(p_code)), m_code(p_code) {} DWORD get_code() const {return m_code;} private: @@ -271,10 +265,10 @@ template class ImplementCOMRefCounter : public TBase { public: template ImplementCOMRefCounter(arg_t && ... arg) : TBase(std::forward(arg) ...) {} - ULONG STDMETHODCALLTYPE AddRef() override { + ULONG STDMETHODCALLTYPE AddRef() { return ++m_refcounter; } - ULONG STDMETHODCALLTYPE Release() override { + ULONG STDMETHODCALLTYPE Release() { long val = --m_refcounter; if (val == 0) delete this; return val; @@ -306,6 +300,7 @@ namespace pfc { bool isCtrlKeyPressed(); bool isAltKeyPressed(); + class winHandle { public: winHandle(HANDLE h_ = INVALID_HANDLE_VALUE) : h(h_) {} @@ -329,13 +324,5 @@ namespace pfc { void winSleep( double seconds ); void sleepSeconds(double seconds); void yield(); - -#ifdef PFC_WINDOWS_DESKTOP_APP - void winSetThreadDescription(HANDLE hThread, const wchar_t * desc); - -#if PFC_DEBUG -#define PFC_SET_THREAD_DESCRIPTION(msg) ::pfc::winSetThreadDescription(GetCurrentThread(), L##msg); -#define PFC_SET_THREAD_DESCRIPTION_SUPPORTED -#endif // PFC_DEBUG -#endif // PFC_WINDOWS_DESKTOP_APP } + diff --git a/sdk-license.txt b/sdk-license.txt index c1b6542..cc082a6 100644 --- a/sdk-license.txt +++ b/sdk-license.txt @@ -1,5 +1,5 @@ -foobar2000 1.6 SDK -Copyright (c) 2001-2021, Peter Pawlowski +foobar2000 1.4 SDK +Copyright (c) 2001-2018, Peter Pawlowski All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -9,4 +9,4 @@ Neither the name of the author nor the names of its contributors may be used to THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -Note that separate less restrictive licenses apply to the included 'pfc' and 'libPPUI' libraries. See license files included in respective folders for details. +Note that a separate less restrictive license applies to the included 'pfc' library. See pfc-license.txt for details. diff --git a/sdk-readme.html b/sdk-readme.html index f91d8b9..5c399dd 100644 --- a/sdk-readme.html +++ b/sdk-readme.html @@ -3,7 +3,7 @@ - + foobar2000 SDK Readme @@ -14,7 +14,7 @@
    -
  • +
  • -
  • - -
  • -
  • - -
    • @@ -70,16 +55,20 @@ -

      foobar2000 v1.6 SDK readme

      +

      foobar2000 v1.4 SDK readme

      - +

      Compatibility

      - Components built with this SDK are compatible with foobar2000 1.4 and newer. They are not compatible with any earlier versions (will fail to load), and not guaranteed to be compatible with any future versions, though upcoming releases will aim to maintain compatibility as far as possible without crippling newly added functionality. + Components built with this SDK are compatible with foobar2000 1.3 and 1.4 series. They are not compatible with any earlier versions (will fail to load), and not guaranteed to be compatible with any future versions, though upcoming releases will aim to maintain compatibility as far as possible without crippling newly added functionality. +

      + +

      +Note that components built with this SDK can provide foobar2000 1.4 functionality while maintaining compatibility with the 1.3 series.

      @@ -87,11 +76,15 @@ You can alter the targeted foobar2000 API 78 components load in foobar2000 1.3 and 1.4; API 79 components load in 1.4 only.

      - +

      Microsoft Visual Studio compatibility

      @@ -100,7 +93,7 @@ Currently supported values are 79 (for 1.4 series) and 80 (for 1.5 & 1.6 ser

      - +

      Ill behavior of Visual C whole program optimization

      @@ -113,7 +106,7 @@ If you're aware of a better workaround - such as a source code change rathe

      - +

      "virtual memory range for PCH exceeded" error

      @@ -126,101 +119,22 @@ The SDK has been changed to

      -If you run into this error, we recommend trimming down the #includes and only referencing specific headers from helpers instead of #including all of them (via old helpers.h). +If you run into this error, we recommend the following steps:

      +
        +
      • ATLHelpers: do not #include ATLHelpers/ATLHelpers.h - use ATLHelpersLean.h instead + additional ones on need-to-use basis.
        +
      • +
      • Helpers: do not #include helpers.h, #include individual ones as needed; most of the declare functionality needed for very specific components only.
        +
      • +
      - -

      Version 1.6 notes

      -
      - -
      - -

      Windows XP support

      -
      - -

      -The SDK project files are configured for targetting Windows 7 and newer, with SSE2 level instruction set. -

      - -

      -If you really must compile components that run on 20 years old computers, you can still change relevant settings, or use an older SDK. Please test your components on actual hardware if you do so, VS2017 compiler has been known to output SSE opcodes when specifically told not to. -

      - -
      - -

      Audio output API extensions

      -
      - -

      -New methods have been added to the output API, such as reporting whether your output is low-latency or high-latency, to interop with the new fading code. -

      - -

      -foobar2000 now provides a suite of special fixes for problematic output implementations (guarenteed update() calls in regular intervals, silence injected at the end); use flag_needs_shims to enable with your output. While such feature might seem unnecessary, it allowed individual outputs to be greatly simplified, removing a lot of other special fixes implemented per output. -

      - -
      - -

      WebP support, imageLoaderLite

      -
      - -

      -Use fb2k::imageLoaderLite API to load a Gdiplus image from a memory block, or to extract info without actually decoding the picture. It supports WebP payload and will be updated with any formats added in the future. -

      - -
      - -

      File cache utilities

      -
      - -

      -New interface has been introduced - read_ahead_tools - to access advanced playback settings for read-ahead cache; primarily needed if your decoder needs to open additional files over the internet. -

      - -
      - -

      Cuesheet wrapper fixes

      -
      - -

      -Wrapper code to support embedded cuesheets on arbitrary formats has been updated to deal with remote files gracefully, that is not present any chapters on such. -

      - -
      - -

      libPPUI

      -
      - -

      -Notable changes: * WebP vs Gdiplus interop (in case you want to load WebP into Gdiplus in your own app - in fb2k, use imageLoaderLite) * Fixed horrible GdiplusImageFromMem() bug * Combo boxes in CListControl * CListControl graying/disabling of individual items -

      - -
      - -

      Version 1.5 notes

      -
      - -
      - -

      libPPUI

      -
      - -

      -Various code from the helpers projects that was in no way foobar2000 specific became libPPUI. In addition, Default User Interface list control has been thrown in. libPPUI is released under a non-restrictive license. Reuse in other projects - including commercial projects - is encouraged. Credits in binary redistribution are not required. -

      - -

      -Existing foobar2000 components that reference SDK helpers/ATLHelpers will need updating to reference libPPUI instead. Separate helpers/ATLHelpers projects are no more, as all projects depend on libPPUI which requires ATL/WTL. -

      - -
      - +

      Version 1.4 notes

      - +

      Namespace cleanup

      @@ -229,7 +143,7 @@ Some very old inconsistencies in the code have been cleaned up. Various bit_arra

      - +

      Decoders

      @@ -261,7 +175,7 @@ The proper way to instantiate any input related classes is to call input_manager

      -If your component targets API level lower than 79, all your attempts to walk input_entry services return a shim service that redirects all your calls to input_manager. You cannot walk actual input_entry services. +If your component targets API level lower than 79 (this SDK comes configured for 78 by default), all your attempts to walk input_entry services return a shim service that redirects all your calls to input_manager. You cannot walk actual input_entry services.

      @@ -311,7 +225,7 @@ typedef input_info_writer_v2 interface_info_writer_t;

      - +

      Dynamic runtime

      @@ -320,11 +234,11 @@ As of version 1.4, foobar2000 is compiled with dynamic Visual C runtime and redi

      -This SDK comes configured for dynamic runtime by default. If you wish to support foobar2000 versions older than 1.4, change to static runtime or make sure that your users have the runtime installed. +This SDK comes configured for static runtime by default, for compatibility with foobar2000 version 1.3. If your component is for foobar2000 series 1.4 only, you can switch to using dynamic runtime instead - make sure to change the setting for all projects in your workspace.

      - +

      service_query()

      @@ -377,7 +291,7 @@ You can use it to avoid having to supply service_query() code yourself and possi

      - +

      Version 1.3 notes

      @@ -404,7 +318,7 @@ It is recommended that you change your existing code using these to obtain track

      - +

      Basic usage

      @@ -442,12 +356,14 @@ Component code should include the following header files:
      • foobar2000.h from SDK - do not include other headers from the SDK directory directly, they're meant to be referenced by foobar2000.h only; it also includes PFC headers and shared.dll helper declaration headers.
      • -
      • Necessary headers from libPPUI and helpers, which both contain various code commonly used by fb2k components.
        +
      • Optionally: helpers.h from helpers directory (foobar2000_SDK_helpers project) - a library of various helper code commonly used by foobar2000 components.
        +
      • +
      • Optionally: ATLHelpers.h from ATLHelpers directory (foobar2000_ATL_helpers project) - another library of various helper code commonly used by foobar2000 components; requires WTL. Note that ATLHelpers.h already includes SDK/foobar2000.h and helpers/helpers.h so you can replace your other include lines with a reference to ATLHelpers.h.
      - +

      Structure of a component

      @@ -456,7 +372,7 @@ Component code should include the following header files:

      - +

      Services

      @@ -473,7 +389,7 @@ Each service object provides reference counter features and (service_add_r

      - +

      Entrypoint services

      @@ -515,7 +431,7 @@ A typical entrypoint service implementation looks like this: }; static service_factory_single_t<myservice_impl> g_myservice_impl_factory;
      - +

      Service extensions

      @@ -533,7 +449,7 @@ service_ptr_t<myservice_v2> ptr_ex; if (ptr->service_query_t(ptr_ex)) { /* ptr_ex is a valid pointer to myservice_v2 interface of our myservice instance */ (...) } else {/* this myservice implementation does not implement myservice_v2 */ (...) }
      - +

      Autopointer template use

      @@ -550,7 +466,7 @@ When working with pointers to core fb2k services, just use C++11 auto
      - +

      Exception use

      @@ -567,7 +483,7 @@ Implementations of global callback services such as playlist_callback
      - +

      Storing configuration

      @@ -584,7 +500,7 @@ Note that cfg_var objects can only be instantiated statically (eith

      - +

      Use of global callback services

      @@ -634,7 +550,7 @@ You should also avoid firing a cross-thread SendMessage() inside global callback

      - +

      Service class design guidelines (advanced)

      @@ -643,7 +559,7 @@ You should also avoid firing a cross-thread SendMessage() inside global callback

      - +

      Cross-DLL safety

      @@ -652,7 +568,7 @@ You should also avoid firing a cross-thread SendMessage() inside global callback

      - +

      Entrypoint service efficiency

      @@ -719,6 +635,6 @@ service_ptr_t<myservice_instance> findservice((); }
      -
      +