mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-09-16 23:01:15 +00:00
From wxWidgets master 81570ae070b35c9d52de47b1f14897f3ff1a66c7. include/wx/defs.h -- __w64 warning disable patch by comex brought forward. include/wx/msw/window.h -- added GetContentScaleFactor() which was not implemented on Windows but is necessary for wxBitmap scaling on Mac OS X so it needs to work to avoid #ifdef-ing the code. src/gtk/window.cpp -- Modified DoSetClientSize() to direct call wxWindowGTK::DoSetSize() instead of using public wxWindowBase::SetSize() which now prevents derived classes (like wxAuiToolbar) intercepting the call and breaking it. This matches Windows which does NOT need to call DoSetSize internally. End result is this fixes Dolphin's debug tools toolbars on Linux. src/osx/window_osx.cpp -- Same fix as for GTK since it has the same issue. src/msw/radiobox.cpp -- Hacked to fix display in HiDPI (was clipping off end of text). Updated CMakeLists for Linux and Mac OS X. Small code changes to Dolphin to fix debug error boxes, deprecation warnings, and retain previous UI behavior on Windows.
317 lines
9.1 KiB
C++
317 lines
9.1 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: src/common/numformatter.cpp
|
|
// Purpose: wxNumberFormatter
|
|
// Author: Fulvio Senore, Vadim Zeitlin
|
|
// Created: 2010-11-06
|
|
// Copyright: (c) 2010 wxWidgets team
|
|
// Licence: wxWindows licence
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// headers
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// For compilers that support precompilation, includes "wx.h".
|
|
#include "wx/wxprec.h"
|
|
|
|
#ifdef __BORLANDC__
|
|
#pragma hdrstop
|
|
#endif
|
|
|
|
#include "wx/numformatter.h"
|
|
#include "wx/intl.h"
|
|
|
|
#include <locale.h> // for setlocale and LC_ALL
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// local helpers
|
|
// ----------------------------------------------------------------------------
|
|
|
|
namespace
|
|
{
|
|
|
|
// Contains information about the locale which was used to initialize our
|
|
// cached values of the decimal and thousands separators. Notice that it isn't
|
|
// enough to store just wxLocale because the user code may call setlocale()
|
|
// directly and storing just C locale string is not enough because we can use
|
|
// the OS API directly instead of the CRT ones on some platforms. So just store
|
|
// both.
|
|
class LocaleId
|
|
{
|
|
public:
|
|
LocaleId()
|
|
{
|
|
#if wxUSE_INTL
|
|
m_wxloc = NULL;
|
|
#endif // wxUSE_INTL
|
|
m_cloc = NULL;
|
|
}
|
|
|
|
~LocaleId()
|
|
{
|
|
Free();
|
|
}
|
|
|
|
#if wxUSE_INTL
|
|
// Return true if this is the first time this function is called for this
|
|
// object or if the program locale has changed since the last time it was
|
|
// called. Otherwise just return false indicating that updating locale-
|
|
// dependent information is not necessary.
|
|
bool NotInitializedOrHasChanged()
|
|
{
|
|
wxLocale * const wxloc = wxGetLocale();
|
|
const char * const cloc = setlocale(LC_ALL, NULL);
|
|
if ( m_wxloc || m_cloc )
|
|
{
|
|
if ( m_wxloc == wxloc && strcmp(m_cloc, cloc) == 0 )
|
|
return false;
|
|
|
|
Free();
|
|
}
|
|
//else: Not initialized yet.
|
|
|
|
m_wxloc = wxloc;
|
|
m_cloc = wxCRT_StrdupA(cloc);
|
|
|
|
return true;
|
|
}
|
|
#endif // wxUSE_INTL
|
|
|
|
private:
|
|
void Free()
|
|
{
|
|
#if wxUSE_INTL
|
|
free(m_cloc);
|
|
#endif // wxUSE_INTL
|
|
}
|
|
|
|
#if wxUSE_INTL
|
|
// Non-owned pointer to wxLocale which was used.
|
|
wxLocale *m_wxloc;
|
|
#endif // wxUSE_INTL
|
|
|
|
// Owned pointer to the C locale string.
|
|
char *m_cloc;
|
|
|
|
wxDECLARE_NO_COPY_CLASS(LocaleId);
|
|
};
|
|
|
|
} // anonymous namespace
|
|
|
|
// ============================================================================
|
|
// wxNumberFormatter implementation
|
|
// ============================================================================
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Locale information accessors
|
|
// ----------------------------------------------------------------------------
|
|
|
|
wxChar wxNumberFormatter::GetDecimalSeparator()
|
|
{
|
|
#if wxUSE_INTL
|
|
// Notice that while using static variable here is not MT-safe, the worst
|
|
// that can happen is that we redo the initialization if we're called
|
|
// concurrently from more than one thread so it's not a real problem.
|
|
static wxChar s_decimalSeparator = 0;
|
|
|
|
// Remember the locale which was current when we initialized, we must redo
|
|
// the initialization if the locale changed.
|
|
static LocaleId s_localeUsedForInit;
|
|
|
|
if ( s_localeUsedForInit.NotInitializedOrHasChanged() )
|
|
{
|
|
const wxString
|
|
s = wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER);
|
|
if ( s.empty() )
|
|
{
|
|
// We really must have something for decimal separator, so fall
|
|
// back to the C locale default.
|
|
s_decimalSeparator = '.';
|
|
}
|
|
else
|
|
{
|
|
// To the best of my knowledge there are no locales like this.
|
|
wxASSERT_MSG( s.length() == 1,
|
|
"Multi-character decimal separator?" );
|
|
|
|
s_decimalSeparator = s[0];
|
|
}
|
|
}
|
|
|
|
return s_decimalSeparator;
|
|
#else // !wxUSE_INTL
|
|
return wxT('.');
|
|
#endif // wxUSE_INTL/!wxUSE_INTL
|
|
}
|
|
|
|
bool wxNumberFormatter::GetThousandsSeparatorIfUsed(wxChar *sep)
|
|
{
|
|
#if wxUSE_INTL
|
|
static wxChar s_thousandsSeparator = 0;
|
|
static LocaleId s_localeUsedForInit;
|
|
|
|
if ( s_localeUsedForInit.NotInitializedOrHasChanged() )
|
|
{
|
|
const wxString
|
|
s = wxLocale::GetInfo(wxLOCALE_THOUSANDS_SEP, wxLOCALE_CAT_NUMBER);
|
|
if ( !s.empty() )
|
|
{
|
|
wxASSERT_MSG( s.length() == 1,
|
|
"Multi-character thousands separator?" );
|
|
|
|
s_thousandsSeparator = s[0];
|
|
}
|
|
//else: Unlike above it's perfectly fine for the thousands separator to
|
|
// be empty if grouping is not used, so just leave it as 0.
|
|
}
|
|
|
|
if ( !s_thousandsSeparator )
|
|
return false;
|
|
|
|
if ( sep )
|
|
*sep = s_thousandsSeparator;
|
|
|
|
return true;
|
|
#else // !wxUSE_INTL
|
|
wxUnusedVar(sep);
|
|
return false;
|
|
#endif // wxUSE_INTL/!wxUSE_INTL
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Conversion to string and helpers
|
|
// ----------------------------------------------------------------------------
|
|
|
|
wxString wxNumberFormatter::PostProcessIntString(wxString s, int style)
|
|
{
|
|
if ( style & Style_WithThousandsSep )
|
|
AddThousandsSeparators(s);
|
|
|
|
wxASSERT_MSG( !(style & Style_NoTrailingZeroes),
|
|
"Style_NoTrailingZeroes can't be used with integer values" );
|
|
|
|
return s;
|
|
}
|
|
|
|
wxString wxNumberFormatter::ToString(long val, int style)
|
|
{
|
|
return PostProcessIntString(wxString::Format("%ld", val), style);
|
|
}
|
|
|
|
#ifdef wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG
|
|
|
|
wxString wxNumberFormatter::ToString(wxLongLong_t val, int style)
|
|
{
|
|
return PostProcessIntString(wxString::Format("%" wxLongLongFmtSpec "d", val),
|
|
style);
|
|
}
|
|
|
|
#endif // wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG
|
|
|
|
wxString wxNumberFormatter::ToString(double val, int precision, int style)
|
|
{
|
|
wxString s = wxString::FromDouble(val,precision);
|
|
|
|
if ( style & Style_WithThousandsSep )
|
|
AddThousandsSeparators(s);
|
|
|
|
if ( style & Style_NoTrailingZeroes )
|
|
RemoveTrailingZeroes(s);
|
|
|
|
return s;
|
|
}
|
|
|
|
void wxNumberFormatter::AddThousandsSeparators(wxString& s)
|
|
{
|
|
// Thousands separators for numbers in scientific format are not relevant.
|
|
if ( s.find_first_of("eE") != wxString::npos )
|
|
return;
|
|
|
|
wxChar thousandsSep;
|
|
if ( !GetThousandsSeparatorIfUsed(&thousandsSep) )
|
|
return;
|
|
|
|
size_t pos = s.find(GetDecimalSeparator());
|
|
if ( pos == wxString::npos )
|
|
{
|
|
// Start grouping at the end of an integer number.
|
|
pos = s.length();
|
|
}
|
|
|
|
// End grouping at the beginning of the digits -- there could be at a sign
|
|
// before their start.
|
|
const size_t start = s.find_first_of("0123456789");
|
|
|
|
// We currently group digits by 3 independently of the locale. This is not
|
|
// the right thing to do and we should use lconv::grouping (under POSIX)
|
|
// and GetLocaleInfo(LOCALE_SGROUPING) (under MSW) to get information about
|
|
// the correct grouping to use. This is something that needs to be done at
|
|
// wxLocale level first and then used here in the future (TODO).
|
|
const size_t GROUP_LEN = 3;
|
|
|
|
while ( pos > start + GROUP_LEN )
|
|
{
|
|
pos -= GROUP_LEN;
|
|
s.insert(pos, thousandsSep);
|
|
}
|
|
}
|
|
|
|
void wxNumberFormatter::RemoveTrailingZeroes(wxString& s)
|
|
{
|
|
// If number is in scientific format, trailing zeroes belong to the exponent and cannot be removed.
|
|
if ( s.find_first_of("eE") != wxString::npos )
|
|
return;
|
|
|
|
const size_t posDecSep = s.find(GetDecimalSeparator());
|
|
// No decimal point => removing trailing zeroes irrelevant for integer number.
|
|
if ( posDecSep == wxString::npos )
|
|
return;
|
|
wxCHECK_RET( posDecSep, "Can't start with decimal separator" );
|
|
|
|
// Find the last character to keep.
|
|
size_t posLastNonZero = s.find_last_not_of("0");
|
|
|
|
// If it's the decimal separator itself, don't keep it neither.
|
|
if ( posLastNonZero == posDecSep )
|
|
posLastNonZero--;
|
|
|
|
s.erase(posLastNonZero + 1);
|
|
// Remove sign from orphaned zero.
|
|
if ( s.compare("-0") == 0 )
|
|
s = "0";
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Conversion from strings
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void wxNumberFormatter::RemoveThousandsSeparators(wxString& s)
|
|
{
|
|
wxChar thousandsSep;
|
|
if ( !GetThousandsSeparatorIfUsed(&thousandsSep) )
|
|
return;
|
|
|
|
s.Replace(wxString(thousandsSep), wxString());
|
|
}
|
|
|
|
bool wxNumberFormatter::FromString(wxString s, long *val)
|
|
{
|
|
RemoveThousandsSeparators(s);
|
|
return s.ToLong(val);
|
|
}
|
|
|
|
#ifdef wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG
|
|
|
|
bool wxNumberFormatter::FromString(wxString s, wxLongLong_t *val)
|
|
{
|
|
RemoveThousandsSeparators(s);
|
|
return s.ToLongLong(val);
|
|
}
|
|
|
|
#endif // wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG
|
|
|
|
bool wxNumberFormatter::FromString(wxString s, double *val)
|
|
{
|
|
RemoveThousandsSeparators(s);
|
|
return s.ToDouble(val);
|
|
}
|