123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389 |
- #pragma once
- #include "openmpt/all/BuildSettings.hpp"
- OPENMPT_NAMESPACE_BEGIN
- template <class T, int limit = _CVTBUFSIZE>
- class CDecimalSupport
- {
- protected:
-
- TCHAR m_DecimalSeparator[5];
-
- TCHAR m_NegativeSign[6];
- bool m_allowNegative = true, m_allowFractions = true;
- public:
- #ifdef BEGIN_MSG_MAP
- BEGIN_MSG_MAP(CDecimalSupport)
- ALT_MSG_MAP(8)
- MESSAGE_HANDLER(WM_CHAR, OnChar)
- MESSAGE_HANDLER(WM_PASTE, OnPaste)
- END_MSG_MAP()
- #endif
-
-
- CDecimalSupport()
- {
- InitDecimalSeparator();
- InitNegativeSign();
- }
-
-
-
-
- int InitDecimalSeparator(LCID Locale = LOCALE_USER_DEFAULT)
- {
- return ::GetLocaleInfo(Locale, LOCALE_SDECIMAL, m_DecimalSeparator, sizeof(m_DecimalSeparator) / sizeof(TCHAR));
- }
-
-
-
-
- int InitNegativeSign(LCID Locale = LOCALE_USER_DEFAULT)
- {
- return ::GetLocaleInfo(Locale, LOCALE_SNEGATIVESIGN, m_NegativeSign, sizeof(m_NegativeSign) / sizeof(TCHAR));
- }
-
-
-
-
-
-
-
- LRESULT OnPaste(UINT , WPARAM , LPARAM , bool &bHandled)
- {
- bHandled = false;
- int neg_sign = 0;
- int dec_point = 0;
- T* pT = static_cast<T*>(this);
- int nStartChar;
- int nEndChar;
- pT->GetSel(nStartChar, nEndChar);
- TCHAR buffer[limit];
- pT->GetWindowText(buffer, limit);
-
- for (TCHAR* x = buffer; *x; ++x)
- {
- if (x - buffer == nStartChar) x += nEndChar - nStartChar;
- if (*x == m_DecimalSeparator[0] || *x == _T('.')) ++dec_point;
- if (*x == m_NegativeSign[0] || *x == _T('-')) ++neg_sign;
- }
- #ifdef _UNICODE
- if (!IsClipboardFormatAvailable(CF_UNICODETEXT)) return 0;
- #else
- if (!IsClipboardFormatAvailable(CF_TEXT)) return 0;
- #endif
- if (!OpenClipboard((HWND) *pT)) return 0;
- #ifdef _UNICODE
- HGLOBAL hglb = GetClipboardData(CF_UNICODETEXT);
- #else
- HGLOBAL hglb = ::GetClipboardData(CF_TEXT);
- #endif
- if (hglb != NULL)
- {
- TCHAR *lptstr = static_cast<TCHAR *>(GlobalLock(hglb));
- if (lptstr != nullptr)
- {
- bHandled = true;
- for (TCHAR* s = lptstr; *s; ++s)
- {
- if ((*s == m_NegativeSign[0] ||*s == _T('-')) && m_allowNegative)
- {
- for (TCHAR* t = m_NegativeSign + 1; *t; ++t, ++s)
- {
- if (*t != *(s+1)) ++neg_sign;
- }
- if (neg_sign || nStartChar > 0)
- {
- bHandled = false;
- break;
- }
- ++neg_sign;
- continue;
- }
- if ((*s == m_DecimalSeparator[0] || *s == _T('.')) && m_allowFractions)
- {
- for (TCHAR* t = m_DecimalSeparator + 1; *t ; ++t, ++s)
- {
- if (*t != *(s+1)) ++dec_point;
- }
- if (dec_point)
- {
- bHandled = false;
- break;
- }
- ++dec_point;
- continue;
- }
- if (*s == _T('\r'))
- {
-
- *s = 0;
- break;
- }
- if (*s < _T('0') || *s > _T('9'))
- {
- bHandled = false;
- break;
- }
- }
- if(bHandled) pT->ReplaceSel(lptstr, true);
- GlobalUnlock(hglb);
- }
- }
- CloseClipboard();
- return 0;
- }
-
-
-
-
-
-
-
- LRESULT OnChar(UINT , WPARAM wParam, LPARAM , BOOL& bHandled)
- {
- bHandled = false;
- if ((static_cast<TCHAR>(wParam) == m_DecimalSeparator[0] || wParam == _T('.')) && m_allowFractions)
- {
- T* pT = static_cast<T*>(this);
- int nStartChar;
- int nEndChar;
- pT->GetSel(nStartChar, nEndChar);
- TCHAR buffer[limit];
- pT->GetWindowText(buffer, limit);
-
- for (TCHAR* x = buffer; *x; ++x)
- {
- if (x - buffer == nStartChar) x += nEndChar - nStartChar;
- if (*x == m_DecimalSeparator[0]) return 0;
- }
- pT->ReplaceSel(m_DecimalSeparator, true);
- bHandled = true;
- }
- if ((static_cast<TCHAR>(wParam) == m_NegativeSign[0] || wParam == _T('-')) && m_allowNegative)
- {
- T* pT = static_cast<T*>(this);
- int nStartChar;
- int nEndChar;
- pT->GetSel(nStartChar, nEndChar);
- if (nStartChar) return 0;
- TCHAR buffer[limit];
- pT->GetWindowText(buffer, limit);
-
- if (nEndChar == 0 && buffer[0] == m_NegativeSign[0]) return 0;
- pT->ReplaceSel(m_NegativeSign, true);
- bHandled = true;
- }
- return 0;
- }
-
-
-
- bool GetDecimalValue(double& d) const
- {
- TCHAR szBuff[limit];
- static_cast<const T*>(this)->GetWindowText(szBuff, limit);
- return TextToDouble(szBuff, d);
- }
-
-
-
-
-
- bool TextToDouble(TCHAR* szBuff, double& d) const
- {
-
- if (m_DecimalSeparator[0] != _T('.'))
- {
- for (TCHAR* x = szBuff; *x; ++x)
- {
- if (*x == m_DecimalSeparator[0])
- {
- *x = _T('.');
- break;
- }
- }
- }
- TCHAR* endPtr;
-
- if (szBuff[0] == m_NegativeSign[0]) szBuff[0] = _T('-');
- d = _tcstod(szBuff, &endPtr);
- return *endPtr == _T('\0');
- }
-
-
-
- void SetFixedValue(double d, int count)
- {
- int decimal_pos;
- int sign;
- char digits[limit];
- _fcvt_s(digits, d, count, &decimal_pos, &sign);
- return DisplayDecimalValue(digits, decimal_pos, sign);
- }
-
-
-
- void SetDecimalValue(double d, int count)
- {
- int decimal_pos;
- int sign;
- char digits[limit];
- _ecvt_s(digits, d, count, &decimal_pos, &sign);
- DisplayDecimalValue(digits, decimal_pos, sign);
- }
-
-
-
- void SetDecimalValue(double d)
- {
- SetDecimalValue(d, std::min(limit, static_cast<int>(static_cast<const T*>(this)->GetLimitText())) - 2);
- }
-
-
-
-
- void DisplayDecimalValue(const char* digits, int decimal_pos, int sign)
- {
- TCHAR szBuff[limit];
- DecimalToText(szBuff, limit, digits, decimal_pos, sign);
- static_cast<T*>(this)->SetWindowText(szBuff);
- }
-
-
-
-
-
-
- void DecimalToText(TCHAR* szBuff, size_t buflen, const char* digits, int decimal_pos, int sign) const
- {
- int i = 0;
- size_t pos = 0;
- if (sign)
- {
- for (const TCHAR *x = m_NegativeSign; *x ; ++x, ++pos) szBuff[pos] = *x;
- }
- for (; pos < buflen && digits[i] && i < decimal_pos ; ++i, ++pos) szBuff[pos] = digits[i];
- if (decimal_pos < 1) szBuff[pos++] = _T('0');
- size_t last_nonzero = pos;
- for (const TCHAR *x = m_DecimalSeparator; *x ; ++x, ++pos) szBuff[pos] = *x;
- for (; pos < buflen && decimal_pos < 0; ++decimal_pos, ++pos) szBuff[pos] = _T('0');
- for (; pos < buflen && digits[i]; ++i, ++pos)
- {
- szBuff[pos] = digits[i];
- if (digits[i] != '0') last_nonzero = pos+1;
- }
- szBuff[std::min(buflen - 1, last_nonzero)] = _T('\0');
- }
- void AllowNegative(bool allow)
- {
- m_allowNegative = allow;
- }
- void AllowFractions(bool allow)
- {
- m_allowFractions = allow;
- }
- };
- class CNumberEdit : public CEdit, public CDecimalSupport<CNumberEdit>
- {
- public:
- void SetTempoValue(const TEMPO &t);
- TEMPO GetTempoValue();
- protected:
- afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);
- afx_msg LPARAM OnPaste(WPARAM wParam, LPARAM lParam);
- DECLARE_MESSAGE_MAP()
- };
- OPENMPT_NAMESPACE_END
|