Difference between revisions of "Formatted Numeric Data"
(→Incorporating ICU within an existing project) |
|||
(24 intermediate revisions by 6 users not shown) | |||
Line 1: | Line 1: | ||
− | + | {{VersionBadge|0.6}} {{VersionBadge|0.5}} | |
− | + | International Components for Unicode (ICU) is a toolkit to internationalise applications. Initially developed for Java it has been ported to C/C++. There is a Java version of ICU called ICU4J, and there is a C/C++ version of ICU called ICU4C. Now ICU4C has been partially ported to CEGUI. Please use this [http://www.cegui.org.uk/phpBB2/viewtopic.php?p=8097#8097 thread] for discussion. | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | === | + | == International Components for Unicode == |
− | + | === Useful Links === | |
− | * | + | * [http://www.icu-project.org/ Home page] |
− | * | + | * [http://source.icu-project.org/repos/icu/icu/trunk/license.html Licence] |
− | * | + | * [http://www.icu-project.org/userguide/ Documentation] |
+ | * [http://www.icu-project.org/apiref/icu4c/ ICU4C API Reference] | ||
+ | * [http://www.loc.gov/standards/iso639-2/ ISO 639 Language Codes] | ||
+ | * [http://unicode.org/iso15924/iso15924-codes.html ISO 15924 Script Codes] | ||
+ | * [http://www.iso.org/iso/country_codes ISO 3166 Country Codes] | ||
+ | * [http://www.iso.org/iso/currency_codes ISO 4217 Currency Codes] | ||
+ | * [http://www.icu-project.org/apiref/icu4c/classDecimalFormat.html#_details ICU Decimal Format Syntax] | ||
+ | * [http://www.icu-project.org/userguide/formatDateTime.html ICU Date/Time Format Syntax] | ||
− | + | === Getting started === | |
− | + | Download these [http://www.icu-project.org/download/ files from the ICU web site] | |
− | *icu | + | * Source: icu-3.4.1.zip for Windows OR icu-3.4.1.tgz for Unix |
+ | * Documentation: icu-3.4-docs.zip | ||
+ | * User Guide: icu-3.4-userguide.zip | ||
− | + | Files of interest: | |
− | * | + | * Solution to compile: icu/source/allinone/allinone.sln |
− | * | + | * Instructions to compile and use ICU: icu/readme.html#HowToBuildWindows |
− | + | * ICU4C samples: icu/source/samples/ | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | * | + | |
− | + | ||
− | + | ||
− | + | ||
− | + | The instructions for building and setting up ICU are contained in the readme.html. If you have any problems, contact the icu-support mailing list or submit a bug report. | |
− | * | + | * [http://www.icu-project.org/contacts.html icu-support mailing list] |
− | + | * [http://www.icu-project.org/bugs.html ICU bug tracking tool] | |
− | * | + | |
− | + | === Incorporating ICU4C within an existing project === | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | ===Incorporating | + | |
Additional include directories: | Additional include directories: | ||
− | *$(ICU)\include | + | * $(ICU)\include |
Additional library directories: | Additional library directories: | ||
− | *$(ICU)\lib | + | * $(ICU)\lib |
Link with: | Link with: | ||
− | *debug: icuucd.lib icuind.lib | + | * debug: icuucd.lib icuind.lib |
− | *release: icuuc.lib icuin.lib | + | * release: icuuc.lib icuin.lib |
− | Make certain these DLLs are present with your executable: | + | Make certain these DLLs are present with your executable or in your PATH: |
− | *debug: icuuc34d.dll icuin34d.dll icudt34.dll | + | * debug: icuuc34d.dll icuin34d.dll icudt34.dll |
− | *release: icuuc34.dll icuin34.dll icudt34.dll | + | * release: icuuc34.dll icuin34.dll icudt34.dll |
− | ==CEGUI's ICU== | + | == CEGUI's ICU == |
− | + | ICU4C provides many features to support internationalisation. The class I've created encapsulates some (not all) of these features. | |
− | ===Locale=== | + | === Locale === |
− | A Locale describes the rules in effect within a country for a specific language. | + | A Locale is an identifier that describes the rules in effect within a country for a specific language. These rules specify the formatting of currencies, numeric values, dates, and others. Unfortunately these rules do not take into consideration the modifications that may have been applied within the Regional Settings of Window's Control Panel, unless the "@compat=host" locale is used, which is available in ICU 3.6 and later. However most functions accept a formatting mask. This allows applications to recreate some of the features of the control panel, allowing users to specify their desired formats. The setLocale() and setCurrency() functions will configure the class to adopt the rules specified by the specified language, country, and currency. |
− | ===formatNumber== | + | === formatNumber === |
− | The formatNumber() function formats a numeric value given the specified mask. | + | The formatNumber() function formats a numeric value given the specified mask. Three versions are available. The versions accepting a CEGUI::String has been customised to allow large numbers to be formatted: numbers having up to 18 integers and 7 decimals. The current implementation of this function is limited to accepting a single format for positive numbers. If the numeric value to be formatted is negative then a negative sign will precede the formatted value. However it is impossible to format a negative value within parentheses: formatting -1234.56 to (1,234.56). |
− | ===numberToText=== | + | === numberToText === |
− | The numberToText() function converts a numeric value into a textual representation. | + | The numberToText() function converts a numeric value into a textual representation. For example the numeric value 123 is converted into "one hundred twenty-three" in English and "cent vingt-trois" in French. |
− | ===numberToOrdinal=== | + | === numberToOrdinal === |
− | The numberToOrdinal() function converts a numeric value into an ordinal representation. | + | The numberToOrdinal() function converts a numeric value into an ordinal representation. For example the numeric value 1 is converted into "1st" in english. Support for other languages is either buggy or lacking (or I have improperly coded this feature). |
− | ===formatText=== | + | === formatText === |
− | The formatText() function will parse a numeric value and sprinkle digits into the slots specified by the formatting mask. | + | The formatText() function will parse a numeric value and sprinkle digits into the slots specified by the formatting mask. A North American telephone number of "12223334444" can be formatted into "1 (222) 333-4444" with the mask "0 (000) 000-0000". This non-localised function accepts three format specifier. A "0" represents a forced digit. If the numerical value possesses a digit at that position then the digit will be displayed, otherwise the place holder character(s) will be used. A "#" represents a potential digit. If the numerical value possesses a digit at that position the the digit will be displayed, otherwise nothing is displayed. Finally the apostrophe "'" allows the mask to specify the characters "0", "#", or "'", rather than using them as format specifiers. |
− | ===formatCurrency=== | + | === formatCurrency === |
− | The formatCurrency() function will format a numerical value according to the currently configured locale and currency. | + | The formatCurrency() function will format a numerical value according to the currently configured locale and currency. It will NOT convert the monetary value of one currency to another. |
− | ===formatDateTime=== | + | === formatDateTime === |
− | The formatDateTime() function will format a date, time, or date/time given the specified mask. | + | The formatDateTime() function will format a date, time, or date/time given the specified mask. The UDate variable type is a double. According to [http://www.icu-project.org/userguide/dateCalendar.html ICU's documentation] ''A UDate value is stored as UTC time in milliseconds, which means it is calendar and time zone independent. UDate is the most compact and portable way to store and transmit a date and time.'' |
− | ===localToGmt and gmtToLocal=== | + | === localToGmt and gmtToLocal === |
The localToGmt() and the gmtToLocal() functions convert a date and a time between a local and a GMT value. | The localToGmt() and the gmtToLocal() functions convert a date and a time between a local and a GMT value. | ||
− | ===CeguiStringToDateTime=== | + | === CeguiStringToDateTime === |
− | The CeguiStringToDateTime() function will parse a string specifying a date or a time into | + | The CeguiStringToDateTime() function will parse a string specifying a date or a time into its corresponding UDate value. Although it is possible to parse a string containing both a date and a time the resulting UDate value will be inaccurate, varying from its intended value by up to 1 minute 47 seconds. A better approach is to keep the date and time separated. |
+ | |||
+ | == Source Code == | ||
+ | |||
+ | === icu.h === | ||
+ | <source lang="cpp"> | ||
+ | #ifndef _ICU_h_ | ||
+ | #define _ICU_h_ | ||
+ | |||
+ | #include "unicode/utypes.h" | ||
+ | #include "unicode/unistr.h" | ||
+ | #include "unicode/numfmt.h" | ||
+ | #include "unicode/dcfmtsym.h" | ||
+ | #include "unicode/decimfmt.h" | ||
+ | #include "unicode/locid.h" | ||
+ | #include "unicode/uclean.h" | ||
+ | #include "unicode/calendar.h" | ||
+ | #include "unicode/datefmt.h" | ||
+ | #include "unicode/smpdtfmt.h" | ||
+ | #include "unicode/rbnf.h" | ||
+ | #include "CEGUI.h" | ||
+ | |||
+ | class ICU | ||
+ | { | ||
+ | public: | ||
+ | ICU(bool cleanupICU = true); | ||
+ | ~ICU(); | ||
+ | bool setLocale(const CEGUI::String& language, const CEGUI::String& country); | ||
+ | const Locale& getLocale(); | ||
+ | bool setCurrency(const char *currency); | ||
+ | |||
+ | bool formatNumber(const CEGUI::String& rawValue, const CEGUI::String& mask, CEGUI::String& formattedValue); | ||
+ | bool formatNumber(const double rawValue, const CEGUI::String& mask, CEGUI::String& formattedValue); | ||
+ | bool formatNumber(const int32_t rawValue, const CEGUI::String& mask, CEGUI::String& formattedValue); | ||
+ | |||
+ | bool numberToText(const double rawValue, CEGUI::String& formattedValue); | ||
+ | bool numberToText(const int32_t rawValue, CEGUI::String& formattedValue); | ||
+ | |||
+ | bool numberToOrdinal(const double rawValue, CEGUI::String& formattedValue); | ||
+ | bool numberToOrdinal(const int32_t rawValue, CEGUI::String& formattedValue); | ||
+ | |||
+ | bool formatText(const CEGUI::String& rawValue, const CEGUI::String& mask, const CEGUI::String& zeroPlaceHolder, CEGUI::String& formattedValue); | ||
+ | |||
+ | bool formatCurrency(const double& currency, CEGUI::String& formattedValue); | ||
+ | |||
+ | bool formatDateTime(UDate rawDateTime, const CEGUI::String& mask, CEGUI::String& formattedDateTime); | ||
+ | bool localToGmt(const UDate& localDate, const UDate& localTime, UDate& gmtDate, UDate& gmtTime); | ||
+ | bool gmtToLocal(const UDate& gmtDate, const UDate& gmtTime, UDate& localDate, UDate& localTime); | ||
+ | |||
+ | bool CeguiStringToDateTime(const CEGUI::String& stringDateTime, const CEGUI::String& mask, UDate& unicodeDateTime); | ||
+ | bool CeguiStringToInt32(const CEGUI::String& stringValue, int32_t& int32Value); | ||
+ | void UnicodeToCeguiString(const UnicodeString& unicodeString, CEGUI::String& ceguiString); | ||
+ | private: | ||
+ | void _splitIntegerDecimal(const CEGUI::String& combined, CEGUI::String& integerPart, CEGUI::String& decimalPart); | ||
+ | bool _convertLocalAndGmt(const UDate& localDate, const UDate& localTime, UDate& gmtDate, UDate& gmtTime, bool fromLocalToGMT); | ||
+ | bool _ruleBasedNumberFormat(const double rawValue, URBNFRuleSetTag tag, CEGUI::String& formattedValue); | ||
+ | bool _ruleBasedNumberFormat(const int32_t rawValue, URBNFRuleSetTag tag, CEGUI::String& formattedValue); | ||
+ | Locale m_locale; // Current locale of the computer | ||
+ | UChar m_currency[4]; // Currency code | ||
+ | bool m_cleanupICU; // Whether to call ICU's cleanup function | ||
+ | }; | ||
+ | |||
+ | #endif // _ICU_h_ | ||
+ | </source> | ||
+ | |||
+ | === icu.cpp === | ||
+ | |||
+ | <source lang="cpp"> | ||
+ | #include "ICU.h" | ||
+ | #include <vector> | ||
+ | |||
+ | ICU::ICU(bool cleanupICU) | ||
+ | { | ||
+ | m_cleanupICU = cleanupICU; | ||
+ | } | ||
+ | |||
+ | ICU::~ICU() | ||
+ | { | ||
+ | // http://www.icu-project.org/userguide/design.html#Init_and_Termination | ||
+ | // The paragraph "ICU Initialization and Termination" mentions that this function | ||
+ | // can be called to force the ICU library to release any allocated heap storage | ||
+ | // otherwise memory leak checking tools will falsely report leaks. | ||
+ | // My thinking with this m_cleanupICU variable is that the library should not release | ||
+ | // its memory allocation if it is also used outside of this class. This | ||
+ | // implementation grants you some control over when this cleanup occurs. | ||
+ | // You are not required to call u_cleanup(). It's dangerous if called at the wrong time. | ||
+ | if(m_cleanupICU) | ||
+ | u_cleanup(); | ||
+ | } | ||
+ | |||
+ | bool ICU::setLocale(const CEGUI::String& language, const CEGUI::String& country) | ||
+ | { | ||
+ | // Set the locale | ||
+ | Locale tempLocale = Locale::createFromName((language + "_" + country).c_str()); | ||
+ | if(tempLocale.isBogus()) | ||
+ | return false; | ||
+ | |||
+ | m_locale = tempLocale; | ||
+ | return true; | ||
+ | } | ||
+ | |||
+ | const Locale& ICU::getLocale() | ||
+ | { | ||
+ | // Retrive the locale | ||
+ | return m_locale; | ||
+ | } | ||
+ | |||
+ | bool ICU::setCurrency(const char *currency) | ||
+ | { | ||
+ | // Set the currency | ||
+ | if(currency==NULL || strlen(currency)!=3) | ||
+ | return false; | ||
+ | |||
+ | // Invariant-character conversion to UChars | ||
+ | u_charsToUChars(currency, m_currency, 4); | ||
+ | return true; | ||
+ | } | ||
+ | |||
+ | bool ICU::formatNumber(const CEGUI::String& rawValue, const CEGUI::String& mask, CEGUI::String& formattedValue) | ||
+ | { | ||
+ | // Format a unformatted number according to the rules specified within the mask | ||
+ | // An unformatted number only contains numeric digits and a period as the decimal point | ||
+ | // Note that a decimal value is broken down into two numbers, an | ||
+ | // integer and a decimal number for formatting and then reassembled | ||
+ | // into a single string. This makes it possible to handle numbers | ||
+ | // as large as 999,999,999,999,999,999.9999999 (18 integers and 7 decimals). | ||
+ | // However it makes it impossible to specify a positive mask as well as a | ||
+ | // negative mask; only one mask is supported. It is also impossible to | ||
+ | // format a negative value with a mask similar to "(#,##0.00)" | ||
+ | UErrorCode status = U_ZERO_ERROR; | ||
+ | formattedValue.clear(); | ||
+ | CEGUI::String formattedInteger, formattedDecimal; | ||
+ | CEGUI::String::size_type idx; | ||
+ | |||
+ | // Separate the integer and the decimal parts from the value | ||
+ | CEGUI::String maskInteger, maskDecimal, integerValue, decimalValue; | ||
+ | idx = rawValue.find("."); | ||
+ | if(idx == CEGUI::String::npos) | ||
+ | { | ||
+ | // If the value is empty then force the integer to 0, otherwise use the value | ||
+ | // Since there is no decimal point force a decimal value of .0 | ||
+ | integerValue = rawValue.empty() ? "0" : rawValue; | ||
+ | decimalValue = ".0"; | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | // If there is no integer portion then force an integer value of 0 | ||
+ | integerValue = idx == 0 ? "0" : rawValue.substr(0, idx); | ||
+ | decimalValue = rawValue.substr(idx); | ||
+ | } | ||
+ | |||
+ | // Separate the integer and the decimal parts from the mask | ||
+ | _splitIntegerDecimal(mask, maskInteger, maskDecimal); | ||
+ | |||
+ | // Prepare the numeric formatter | ||
+ | DecimalFormatSymbols* decimalFormatSymbols = new DecimalFormatSymbols(m_locale, status); | ||
+ | if( U_FAILURE(status) ) | ||
+ | return false; | ||
+ | |||
+ | if(!maskInteger.empty()) | ||
+ | { | ||
+ | // Prepare the integer parser | ||
+ | UnicodeString patternInteger(maskInteger.c_str()); | ||
+ | DecimalFormat* fmt = new DecimalFormat(patternInteger, *decimalFormatSymbols, status); | ||
+ | if( U_FAILURE(status) ) | ||
+ | { | ||
+ | delete decimalFormatSymbols; | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | // Parse the string value into an integer value | ||
+ | UnicodeString uIntegerValue(integerValue.c_str()); | ||
+ | Formattable fIntegerValue; | ||
+ | fmt->parse(uIntegerValue, fIntegerValue, status); | ||
+ | if( U_FAILURE(status) ) | ||
+ | { | ||
+ | status = U_ZERO_ERROR; | ||
+ | fIntegerValue.setInt64(0); | ||
+ | } | ||
+ | |||
+ | // Format the integer value | ||
+ | uIntegerValue = ""; | ||
+ | ((NumberFormat*)fmt)->format(fIntegerValue.getInt64(), uIntegerValue); | ||
+ | delete fmt; | ||
+ | |||
+ | UnicodeToCeguiString(uIntegerValue, formattedInteger); | ||
+ | } | ||
+ | |||
+ | if(!maskDecimal.empty()) | ||
+ | { | ||
+ | // Prepare the decimal parser | ||
+ | DecimalFormat* fmtParse = new DecimalFormat(status); | ||
+ | if( U_FAILURE(status) ) | ||
+ | { | ||
+ | delete decimalFormatSymbols; | ||
+ | return false; | ||
+ | } | ||
+ | fmtParse->applyLocalizedPattern("0.0000003", status); | ||
+ | |||
+ | // Parse the string value into a decimal value | ||
+ | UnicodeString uDecimalValue(decimalValue.c_str()); | ||
+ | Formattable fDecimalValue; | ||
+ | fmtParse->parse(uDecimalValue, fDecimalValue, status); | ||
+ | delete fmtParse; | ||
+ | if( U_FAILURE(status) ) | ||
+ | { | ||
+ | status = U_ZERO_ERROR; | ||
+ | fDecimalValue.setDouble(0.0); | ||
+ | } | ||
+ | |||
+ | // Prepare the decimal formatter | ||
+ | UnicodeString patternDecimal(maskDecimal.c_str()); | ||
+ | DecimalFormat* fmt = new DecimalFormat(patternDecimal, *decimalFormatSymbols, status); | ||
+ | if( U_FAILURE(status) ) | ||
+ | { | ||
+ | delete decimalFormatSymbols; | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | // Format the decimal value | ||
+ | uDecimalValue = ""; | ||
+ | fmt->format(fDecimalValue.getDouble(), uDecimalValue); | ||
+ | delete fmt; | ||
+ | |||
+ | UnicodeToCeguiString(uDecimalValue, formattedDecimal); | ||
+ | } | ||
+ | |||
+ | delete decimalFormatSymbols; | ||
+ | |||
+ | formattedValue = formattedInteger + formattedDecimal; | ||
+ | return true; | ||
+ | } | ||
+ | |||
+ | bool ICU::formatNumber(const double rawValue, const CEGUI::String& mask, CEGUI::String& formattedValue) | ||
+ | { | ||
+ | // Format a number using the appropriate locale rules | ||
+ | // Note that the use of a double limits the effective range | ||
+ | UErrorCode status = U_ZERO_ERROR; | ||
+ | formattedValue.clear(); | ||
+ | |||
+ | // Prepare the numeric formatter | ||
+ | DecimalFormatSymbols* symbols = new DecimalFormatSymbols(m_locale, status); | ||
+ | if( U_FAILURE(status) ) | ||
+ | return false; | ||
+ | |||
+ | // Create a number formatter for the current locale | ||
+ | UnicodeString pattern(mask.c_str()); | ||
+ | DecimalFormat* fmt = new DecimalFormat(pattern, *symbols, status); | ||
+ | if( U_FAILURE(status) ) | ||
+ | { | ||
+ | delete symbols; | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | // Format the number | ||
+ | UnicodeString uValue; | ||
+ | fmt->format(rawValue, uValue, status); | ||
+ | delete symbols; | ||
+ | delete fmt; | ||
+ | if( U_FAILURE(status) ) | ||
+ | return false; | ||
+ | |||
+ | UnicodeToCeguiString(uValue, formattedValue); | ||
+ | return true; | ||
+ | } | ||
+ | |||
+ | bool ICU::formatNumber(const int32_t rawValue, const CEGUI::String& mask, CEGUI::String& formattedValue) | ||
+ | { | ||
+ | // Format a number using the appropriate locale rules | ||
+ | // Note that the use of a double limits the effective range | ||
+ | UErrorCode status = U_ZERO_ERROR; | ||
+ | formattedValue.clear(); | ||
+ | |||
+ | // Prepare the numeric formatter | ||
+ | DecimalFormatSymbols* symbols = new DecimalFormatSymbols(m_locale, status); | ||
+ | if( U_FAILURE(status) ) | ||
+ | return false; | ||
+ | |||
+ | // Create a number formatter for the current locale | ||
+ | UnicodeString pattern(mask.c_str()); | ||
+ | DecimalFormat* fmt = new DecimalFormat(pattern, *symbols, status); | ||
+ | if( U_FAILURE(status) ) | ||
+ | { | ||
+ | delete symbols; | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | // Format the number | ||
+ | UnicodeString uValue; | ||
+ | fmt->format(rawValue, uValue, status); | ||
+ | delete symbols; | ||
+ | delete fmt; | ||
+ | if( U_FAILURE(status) ) | ||
+ | return false; | ||
+ | |||
+ | UnicodeToCeguiString(uValue, formattedValue); | ||
+ | return true; | ||
+ | } | ||
+ | |||
+ | bool ICU::numberToText(const double rawValue, CEGUI::String& formattedValue) | ||
+ | { | ||
+ | // Convert a number to a text | ||
+ | // "1.2" to "one point two" | ||
+ | return _ruleBasedNumberFormat(rawValue, URBNF_SPELLOUT, formattedValue); | ||
+ | } | ||
+ | |||
+ | bool ICU::numberToText(const int32_t rawValue, CEGUI::String& formattedValue) | ||
+ | { | ||
+ | // Convert a number to a text | ||
+ | // "12" to "twelve" | ||
+ | return _ruleBasedNumberFormat(rawValue, URBNF_SPELLOUT, formattedValue); | ||
+ | } | ||
+ | |||
+ | bool ICU::numberToOrdinal(const double rawValue, CEGUI::String& formattedValue) | ||
+ | { | ||
+ | // Convert a number to ordinal text | ||
+ | // "1.5" to "2nd" | ||
+ | return _ruleBasedNumberFormat(rawValue, URBNF_ORDINAL, formattedValue); | ||
+ | } | ||
+ | |||
+ | bool ICU::numberToOrdinal(const int32_t rawValue, CEGUI::String& formattedValue) | ||
+ | { | ||
+ | // Convert a number to ordinal text | ||
+ | // "1" to "1st" | ||
+ | return _ruleBasedNumberFormat(rawValue, URBNF_ORDINAL, formattedValue); | ||
+ | } | ||
+ | |||
+ | bool ICU::formatText(const CEGUI::String& rawValue, const CEGUI::String& mask, const CEGUI::String& zeroPlaceHolder, CEGUI::String& formattedValue) | ||
+ | { | ||
+ | /* Format a value according to a pattern | ||
+ | * Format specifiers: | ||
+ | * 0 forced digit: will be replaced by a digit or if there is no digit, by 'zeroPlaceHolder' | ||
+ | * # potential digit: will be replaced by a digit if there is one otherwise nothing | ||
+ | * ' literal character: the following character is to be treated as a character | ||
+ | * rather than a format specifier | ||
+ | * ex the value "1" with the format "'00" will result in the string "01" | ||
+ | * Note that if the value is larger than the pattern then it is truncated to the left | ||
+ | * ex the value "1234" with the format "#0" results in the string "34" | ||
+ | */ | ||
+ | formattedValue.clear(); | ||
+ | |||
+ | if(!rawValue.length() || !mask.length()) | ||
+ | return false; | ||
+ | |||
+ | // Parse the mask | ||
+ | std::vector<CEGUI::String> maskList; | ||
+ | CEGUI::String maskDigit; | ||
+ | for(CEGUI::String::size_type idxMask = 0; idxMask < mask.length(); ++idxMask) | ||
+ | { | ||
+ | if(!mask.compare(idxMask, 1, "0")) | ||
+ | { | ||
+ | maskDigit = "ForcedDigit"; | ||
+ | maskList.push_back(maskDigit); | ||
+ | } | ||
+ | else if(!mask.compare(idxMask, 1, "#")) | ||
+ | { | ||
+ | maskDigit = "PotentialDigit"; | ||
+ | maskList.push_back(maskDigit); | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | if(!mask.compare(idxMask, 1, "'") && idxMask < mask.length() - 1) | ||
+ | ++idxMask; // Literal specifier followed by a mask digit, so skip over the apostrophe | ||
+ | maskDigit = mask.at(idxMask); | ||
+ | maskList.push_back(maskDigit); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // Format the numeric value | ||
+ | CEGUI::String::size_type idxValue; | ||
+ | idxValue = rawValue.length(); | ||
+ | std::vector<CEGUI::String>::reverse_iterator itMask; | ||
+ | for(itMask = maskList.rbegin(); itMask != maskList.rend(); ++itMask) | ||
+ | { | ||
+ | if(!(*itMask).compare("ForcedDigit")) | ||
+ | { | ||
+ | if(idxValue) | ||
+ | { | ||
+ | // We have a digit remaining | ||
+ | --idxValue; | ||
+ | formattedValue = rawValue.at(idxValue) + formattedValue; | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | // We're out of digits | ||
+ | formattedValue = zeroPlaceHolder + formattedValue; | ||
+ | } | ||
+ | } | ||
+ | else if(!(*itMask).compare("PotentialDigit")) | ||
+ | { | ||
+ | if(idxValue) | ||
+ | { | ||
+ | // We have a digit remaining | ||
+ | --idxValue; | ||
+ | formattedValue = rawValue.at(idxValue) + formattedValue; | ||
+ | } | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | // Literal character | ||
+ | formattedValue = (*itMask) + formattedValue; | ||
+ | } | ||
+ | } | ||
+ | return true; | ||
+ | } | ||
+ | |||
+ | bool ICU::formatCurrency(const double& currency, CEGUI::String& formattedValue) | ||
+ | { | ||
+ | // Format a number using the appropriate locale rules | ||
+ | // Note that the use of a double limits the effective range | ||
+ | UErrorCode status = U_ZERO_ERROR; | ||
+ | formattedValue.clear(); | ||
+ | |||
+ | // Create a number formatter for the current locale | ||
+ | NumberFormat *fmt = NumberFormat::createCurrencyInstance(m_locale, status); | ||
+ | if( U_FAILURE(status) ) | ||
+ | return false; | ||
+ | |||
+ | // Format the currency | ||
+ | UnicodeString uValue; | ||
+ | fmt->format(currency, uValue); | ||
+ | delete fmt; | ||
+ | |||
+ | UnicodeToCeguiString(uValue, formattedValue); | ||
+ | return true; | ||
+ | } | ||
+ | |||
+ | bool ICU::formatDateTime(UDate rawDateTime, const CEGUI::String& mask, CEGUI::String& formattedDateTime) | ||
+ | { | ||
+ | // Format a date/time given the specified mask | ||
+ | // Note that although a UDate can support both date and time in | ||
+ | // realite the resolution is insufficient. In order to precisely | ||
+ | // represent a date/time value they should be processed separately | ||
+ | UErrorCode status = U_ZERO_ERROR; | ||
+ | formattedDateTime.clear(); | ||
+ | |||
+ | // Create a Date/Time formatter | ||
+ | DateFormat* fmt = DateFormat::createDateTimeInstance(DateFormat::kDefault, DateFormat::kDefault, m_locale); // kDefault is not really used | ||
+ | |||
+ | // Activate our pattern (overrides DateFormat::kDefault) | ||
+ | UnicodeString pattern(mask.c_str()); | ||
+ | ((SimpleDateFormat*) fmt)->applyPattern(pattern); | ||
+ | |||
+ | // Format the date/time | ||
+ | UnicodeString uValue; | ||
+ | fmt->format(rawDateTime, uValue, status); | ||
+ | delete fmt; | ||
+ | if( U_FAILURE(status) ) | ||
+ | return false; | ||
+ | |||
+ | UnicodeToCeguiString(uValue, formattedDateTime); | ||
+ | return true; | ||
+ | } | ||
+ | |||
+ | bool ICU::localToGmt(const UDate& localDate, const UDate& localTime, UDate& gmtDate, UDate& gmtTime) | ||
+ | { | ||
+ | // Convert a local date/time into a GMT date/time | ||
+ | return _convertLocalAndGmt(localDate, localTime, gmtDate, gmtTime, true); | ||
+ | } | ||
+ | |||
+ | bool ICU::gmtToLocal(const UDate& gmtDate, const UDate& gmtTime, UDate& localDate, UDate& localTime) | ||
+ | { | ||
+ | // Convert a GMT date/time into a local date/time string | ||
+ | return _convertLocalAndGmt(gmtDate, gmtTime, localDate, localTime, false); | ||
+ | } | ||
+ | |||
+ | bool ICU::CeguiStringToDateTime(const CEGUI::String& stringDateTime, const CEGUI::String& mask, UDate& unicodeDateTime) | ||
+ | { | ||
+ | // Convert a string date/time into a UDate | ||
+ | UErrorCode status = U_ZERO_ERROR; | ||
+ | unicodeDateTime = 0.0; | ||
+ | |||
+ | // Create a Date/Time formatter | ||
+ | DateFormat* fmt = DateFormat::createDateTimeInstance(DateFormat::kDefault, DateFormat::kDefault, m_locale); | ||
+ | |||
+ | // Activate our pattern | ||
+ | UnicodeString pattern(mask.c_str()); | ||
+ | ((SimpleDateFormat*) fmt)->applyPattern(pattern); | ||
+ | |||
+ | // Parse the string into a date/time | ||
+ | UnicodeString uValue(stringDateTime.c_str()); | ||
+ | unicodeDateTime = fmt->parse(uValue, status); | ||
+ | delete fmt; | ||
+ | if( U_FAILURE(status) ) | ||
+ | return false; | ||
+ | |||
+ | return true; | ||
+ | } | ||
+ | |||
+ | bool ICU::CeguiStringToInt32(const CEGUI::String& stringValue, int32_t& int32Value) | ||
+ | { | ||
+ | // Convert a string into an int32_t | ||
+ | UErrorCode status = U_ZERO_ERROR; | ||
+ | int32Value = 0; | ||
+ | |||
+ | // Create an integer formatter | ||
+ | NumberFormat *fmt = NumberFormat::createInstance(Locale::getUS(), status); | ||
+ | if( U_FAILURE(status) ) | ||
+ | return false; | ||
+ | |||
+ | // Activate our pattern | ||
+ | UnicodeString pattern("#,##0"); | ||
+ | ((DecimalFormat*) fmt)->applyPattern(pattern, status); | ||
+ | if( U_FAILURE(status) ) | ||
+ | { | ||
+ | delete fmt; | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | // Parse the string into a double | ||
+ | UnicodeString uValue(stringValue.c_str()); | ||
+ | Formattable result; | ||
+ | fmt->parse(uValue, result, status); | ||
+ | delete fmt; | ||
+ | if( U_FAILURE(status) ) | ||
+ | return false; | ||
+ | |||
+ | int32Value = result.getLong(); | ||
+ | |||
+ | return true; | ||
+ | } | ||
+ | |||
+ | void ICU::UnicodeToCeguiString(const UnicodeString& unicodeString, CEGUI::String& ceguiString) | ||
+ | { | ||
+ | // Convert a unicode string to a CEGUI string | ||
+ | ceguiString.clear(); | ||
+ | |||
+ | CEGUI::String digit; | ||
+ | for(int32_t i = 0; i < unicodeString.length(); ++i) | ||
+ | { | ||
+ | digit = unicodeString.charAt(i); | ||
+ | ceguiString.append(digit); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | void ICU::_splitIntegerDecimal(const CEGUI::String& combined, CEGUI::String& integerPart, CEGUI::String& decimalPart) | ||
+ | { | ||
+ | // Split a decimal value into its constituent integer and decimal parts | ||
+ | CEGUI::String::size_type idx = combined.find("."); | ||
+ | if(idx == CEGUI::String::npos) | ||
+ | { | ||
+ | integerPart = combined; | ||
+ | decimalPart.clear(); | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | integerPart = combined.substr(0, idx); | ||
+ | decimalPart = combined.substr(idx); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | bool ICU::_convertLocalAndGmt(const UDate& localDate, const UDate& localTime, UDate& gmtDate, UDate& gmtTime, bool fromLocalToGMT) | ||
+ | { | ||
+ | // Helper function to convert between a local and a GMT date/time | ||
+ | UErrorCode status = U_ZERO_ERROR; | ||
+ | gmtDate = gmtTime = 0.0; | ||
+ | |||
+ | // Create a calendar for the local date | ||
+ | Calendar* calLocalDate = Calendar::createInstance(m_locale, status); | ||
+ | if( U_FAILURE(status) ) | ||
+ | return false; | ||
+ | calLocalDate->clear(); | ||
+ | calLocalDate->setTime(localDate, status); | ||
+ | if( U_FAILURE(status) ) | ||
+ | { | ||
+ | delete calLocalDate; | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | // Create a calendar for the local time | ||
+ | Calendar* calLocalTime = Calendar::createInstance(m_locale, status); | ||
+ | if( U_FAILURE(status) ) | ||
+ | { | ||
+ | delete calLocalDate; | ||
+ | return false; | ||
+ | } | ||
+ | calLocalTime->clear(); | ||
+ | calLocalTime->setTime(localTime, status); | ||
+ | if( U_FAILURE(status) ) | ||
+ | { | ||
+ | delete calLocalDate; | ||
+ | delete calLocalTime; | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | // Retrieve the offset between this time zone and the GMT time zone | ||
+ | // The Daylight Saving Time offset is zero when DST is not in effect | ||
+ | // Note that adding the local date and time together introduces an | ||
+ | // inaccuracy of up to 1 minute 47 seconds. However the only impact | ||
+ | // of this inaccuracy is to advance/delay the activation or deactivation | ||
+ | // of daylight savings | ||
+ | int32_t rawOffset, dstOffset, gmtOffset; | ||
+ | calLocalDate->getTimeZone().getOffset(localDate + localTime, true, rawOffset, dstOffset, status); | ||
+ | gmtOffset = (rawOffset + dstOffset) / 1000 / 60 / 60; // Convert from milliseconds to hours | ||
+ | |||
+ | // Converting from local to GMT requires "reversing" the time zone | ||
+ | // EST is GMT-5 so it requires adding 5 hours to local time to obtain GMT | ||
+ | // Converting from GMT to local requires the opposite | ||
+ | int32_t hour = calLocalTime->get(UCAL_HOUR_OF_DAY, status); | ||
+ | if(fromLocalToGMT) | ||
+ | hour -= gmtOffset; | ||
+ | else | ||
+ | hour += gmtOffset; | ||
+ | |||
+ | // Adjust the time and date if necessary | ||
+ | if(hour >= 24) | ||
+ | { | ||
+ | // We've moved to the next day | ||
+ | hour -= 24; | ||
+ | calLocalDate->add(UCAL_DAY_OF_MONTH, 1, status); | ||
+ | if( U_FAILURE(status) ) | ||
+ | { | ||
+ | delete calLocalDate; | ||
+ | delete calLocalTime; | ||
+ | return false; | ||
+ | } | ||
+ | } | ||
+ | else if(hour < 0) | ||
+ | { | ||
+ | // We've moved to the previous day | ||
+ | hour += 24; | ||
+ | calLocalDate->add(UCAL_DAY_OF_MONTH, -1, status); | ||
+ | if( U_FAILURE(status) ) | ||
+ | { | ||
+ | delete calLocalDate; | ||
+ | delete calLocalTime; | ||
+ | return false; | ||
+ | } | ||
+ | } | ||
+ | calLocalTime->set(UCAL_HOUR_OF_DAY, hour); | ||
+ | |||
+ | // Retrieve the converted date and time | ||
+ | gmtDate = calLocalDate->getTime(status); | ||
+ | gmtTime = calLocalTime->getTime(status); | ||
+ | |||
+ | delete calLocalDate; | ||
+ | delete calLocalTime; | ||
+ | if( U_FAILURE(status) ) | ||
+ | return false; | ||
+ | |||
+ | return true; | ||
+ | } | ||
+ | |||
+ | bool ICU::_ruleBasedNumberFormat(const double rawValue, URBNFRuleSetTag tag, CEGUI::String& formattedValue) | ||
+ | { | ||
+ | UErrorCode status = U_ZERO_ERROR; | ||
+ | formattedValue.clear(); | ||
+ | |||
+ | // Create a rule based number formatter | ||
+ | RuleBasedNumberFormat* fmt = new RuleBasedNumberFormat(tag, m_locale, status); | ||
+ | if( U_FAILURE(status) ) | ||
+ | return false; | ||
+ | |||
+ | UnicodeString uValue; | ||
+ | fmt->format(rawValue, uValue); | ||
+ | delete fmt; | ||
+ | |||
+ | formattedValue.clear(); | ||
+ | UnicodeToCeguiString(uValue, formattedValue); | ||
+ | return true; | ||
+ | } | ||
+ | |||
+ | bool ICU::_ruleBasedNumberFormat(const int32_t rawValue, URBNFRuleSetTag tag, CEGUI::String& formattedValue) | ||
+ | { | ||
+ | UErrorCode status = U_ZERO_ERROR; | ||
+ | formattedValue.clear(); | ||
+ | |||
+ | // Create a rule based number formatter | ||
+ | RuleBasedNumberFormat* fmt = new RuleBasedNumberFormat(tag, m_locale, status); | ||
+ | if( U_FAILURE(status) ) | ||
+ | return false; | ||
+ | |||
+ | UnicodeString uValue; | ||
+ | Formattable fValue(rawValue); | ||
+ | fmt->format(fValue, uValue, status); | ||
+ | delete fmt; | ||
+ | if( U_FAILURE(status) ) | ||
+ | return false; | ||
+ | |||
+ | formattedValue.clear(); | ||
+ | UnicodeToCeguiString(uValue, formattedValue); | ||
+ | return true; | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | === FormattedData.h === | ||
+ | <source lang="cpp"> | ||
+ | #ifndef _FormattedData_h_ | ||
+ | #define _FormattedData_h_ | ||
+ | |||
+ | #include "CEGuiSample.h" | ||
+ | #include "CEGUI.h" | ||
+ | |||
+ | #include "ICU.h" | ||
+ | |||
+ | class DemoSample : public CEGuiSample | ||
+ | { | ||
+ | public: | ||
+ | bool initialiseSample() | ||
+ | { | ||
+ | using namespace CEGUI; | ||
+ | try | ||
+ | { | ||
+ | // Retrieve the window manager | ||
+ | WindowManager& winMgr = WindowManager::getSingleton(); | ||
+ | |||
+ | // Load the TaharezLook scheme and set up the default mouse cursor and font | ||
+ | SchemeManager::getSingleton().loadScheme("TaharezLook.scheme"); | ||
+ | System::getSingleton().setDefaultMouseCursor("TaharezLook", "MouseArrow"); | ||
+ | if(!FontManager::getSingleton().isFontPresent("Commonwealth-10")) | ||
+ | FontManager::getSingleton().createFont("Commonwealth-10.font"); | ||
+ | |||
+ | // Set the GUI Sheet | ||
+ | Window* sheet = winMgr.createWindow("DefaultWindow", "root_wnd"); | ||
+ | System::getSingleton().setGUISheet(sheet); | ||
+ | |||
+ | // Load a layout | ||
+ | Window* guiLayout = winMgr.loadWindowLayout("FormattedData.layout"); | ||
+ | sheet->addChildWindow(guiLayout); | ||
+ | |||
+ | /******** ICU Stuff ********/ | ||
+ | |||
+ | // Display one ISO country in a combo box | ||
+ | Combobox* countries = static_cast<Combobox*>(winMgr.getWindow("Countries")); | ||
+ | countries->setReadOnly(true); | ||
+ | ListboxTextItem* listboxTextItem; | ||
+ | listboxTextItem = new ListboxTextItem( Locale::getDefault().getCountry() ); | ||
+ | listboxTextItem->setSelectionBrushImage("TaharezLook", "MultiListSelectionBrush"); | ||
+ | countries->addItem(listboxTextItem); | ||
+ | countries->setText( Locale::getDefault().getCountry() ); | ||
+ | countries->subscribeEvent(Combobox::EventListSelectionAccepted, Event::Subscriber(&DemoSample::onLocaleChanged, this)); | ||
+ | |||
+ | // Display two ISO languages in a combo box | ||
+ | Combobox* languages = static_cast<Combobox*>(winMgr.getWindow("Languages")); | ||
+ | languages->subscribeEvent(Combobox::EventListSelectionAccepted, Event::Subscriber(&DemoSample::onLocaleChanged, this)); | ||
+ | languages->setReadOnly(true); | ||
+ | listboxTextItem = new ListboxTextItem("en"); | ||
+ | listboxTextItem->setSelectionBrushImage("TaharezLook", "MultiListSelectionBrush"); | ||
+ | languages->addItem(listboxTextItem); | ||
+ | listboxTextItem = new ListboxTextItem("fr"); | ||
+ | listboxTextItem->setSelectionBrushImage("TaharezLook", "MultiListSelectionBrush"); | ||
+ | languages->addItem(listboxTextItem); | ||
+ | languages->setText("en"); | ||
+ | languages->subscribeEvent(Combobox::EventListSelectionAccepted, Event::Subscriber(&DemoSample::onLocaleChanged, this)); | ||
+ | PushButton* everyISO = static_cast<PushButton*>(winMgr.getWindow("EveryISO")); | ||
+ | everyISO->subscribeEvent(PushButton::EventClicked, Event::Subscriber(&DemoSample::onLoadEveryISO, this)); | ||
+ | |||
+ | // Configure the currency widgets | ||
+ | Editbox* currencyValue = static_cast<Editbox*>(winMgr.getWindow("CurrencyValue")); | ||
+ | currencyValue->subscribeEvent(Editbox::EventTextChanged, Event::Subscriber(&DemoSample::onCurrencyChanged, this)); | ||
+ | RadioButton* radio; | ||
+ | radio = static_cast<RadioButton*>(winMgr.getWindow("RadioCAD")); | ||
+ | radio->subscribeEvent(RadioButton::EventSelectStateChanged, Event::Subscriber(&DemoSample::onCurrencySelected, this)); | ||
+ | radio->setID(1); | ||
+ | radio->setSelected(true); | ||
+ | radio = static_cast<RadioButton*>(winMgr.getWindow("RadioUSD")); | ||
+ | radio->subscribeEvent(RadioButton::EventSelectStateChanged, Event::Subscriber(&DemoSample::onCurrencySelected, this)); | ||
+ | radio->setID(2); | ||
+ | radio = static_cast<RadioButton*>(winMgr.getWindow("RadioEUR")); | ||
+ | radio->subscribeEvent(RadioButton::EventSelectStateChanged, Event::Subscriber(&DemoSample::onCurrencySelected, this)); | ||
+ | radio->setID(3); | ||
+ | radio = static_cast<RadioButton*>(winMgr.getWindow("RadioMRO")); | ||
+ | radio->subscribeEvent(RadioButton::EventSelectStateChanged, Event::Subscriber(&DemoSample::onCurrencySelected, this)); | ||
+ | radio->setID(4); | ||
+ | |||
+ | // Configure the numeric widgets | ||
+ | Editbox* numericValue = static_cast<Editbox*>(winMgr.getWindow("NumericValue")); | ||
+ | numericValue->subscribeEvent(Editbox::EventTextChanged, Event::Subscriber(&DemoSample::onNumericChanged, this)); | ||
+ | Editbox* numericFormat = static_cast<Editbox*>(winMgr.getWindow("NumericFormat")); | ||
+ | numericFormat->subscribeEvent(Editbox::EventTextChanged, Event::Subscriber(&DemoSample::onNumericChanged, this)); | ||
+ | PushButton* numericFormatButton = static_cast<PushButton*>(winMgr.getWindow("NumericFormatButton")); | ||
+ | numericFormatButton->subscribeEvent(PushButton::EventClicked, Event::Subscriber(&DemoSample::onNumericFormatClicked, this)); | ||
+ | |||
+ | // Configure the date/time widgets | ||
+ | Editbox* dateValue = static_cast<Editbox*>(winMgr.getWindow("DateValue")); | ||
+ | dateValue->subscribeEvent(Editbox::EventTextChanged, Event::Subscriber(&DemoSample::onDateTimeChanged, this)); | ||
+ | Editbox* timeValue = static_cast<Editbox*>(winMgr.getWindow("TimeValue")); | ||
+ | timeValue->subscribeEvent(Editbox::EventTextChanged, Event::Subscriber(&DemoSample::onDateTimeChanged, this)); | ||
+ | Editbox* dateFormat = static_cast<Editbox*>(winMgr.getWindow("DateFormat")); | ||
+ | dateFormat->subscribeEvent(Editbox::EventTextChanged, Event::Subscriber(&DemoSample::onDateTimeChanged, this)); | ||
+ | Editbox* timeFormat = static_cast<Editbox*>(winMgr.getWindow("TimeFormat")); | ||
+ | timeFormat->subscribeEvent(Editbox::EventTextChanged, Event::Subscriber(&DemoSample::onDateTimeChanged, this)); | ||
+ | PushButton* dateTimeFormatButton = static_cast<PushButton*>(winMgr.getWindow("DateTimeFormatButton")); | ||
+ | dateTimeFormatButton->subscribeEvent(PushButton::EventClicked, Event::Subscriber(&DemoSample::onDateTimeFormatClicked, this)); | ||
+ | |||
+ | // Configure the spinner | ||
+ | Spinner* spinner = static_cast<Spinner*>(winMgr.getWindow("Spinner")); | ||
+ | spinner->subscribeEvent(Spinner::EventValueChanged, Event::Subscriber(&DemoSample::onSpinnerValueChanged, this)); | ||
+ | static_cast<Editbox*>(winMgr.getWindow(spinner->getName() + "__auto_editbox__"))->setReadOnly(true); // We cannot handle manually specified values yet | ||
+ | spinner->setTextInputMode(Spinner::FloatingPoint); // FloatingPoint, Integer, Hexadecimal, Octal | ||
+ | spinner->setMinimumValue(-10.0f); | ||
+ | spinner->setMaximumValue(10.0f); | ||
+ | spinner->setStepSize(0.02f); | ||
+ | spinner->setCurrentValue(5.2f); | ||
+ | |||
+ | // Configure the character widgets | ||
+ | Editbox* characterValue = static_cast<Editbox*>(winMgr.getWindow("CharacterValue")); | ||
+ | characterValue->subscribeEvent(Editbox::EventTextChanged, Event::Subscriber(&DemoSample::onCharacterChanged, this)); | ||
+ | Editbox* characterFormat = static_cast<Editbox*>(winMgr.getWindow("CharacterFormat")); | ||
+ | characterFormat->subscribeEvent(Editbox::EventTextChanged, Event::Subscriber(&DemoSample::onCharacterChanged, this)); | ||
+ | PushButton* characterFormatButton = static_cast<PushButton*>(winMgr.getWindow("CharacterFormatButton")); | ||
+ | characterFormatButton->subscribeEvent(PushButton::EventClicked, Event::Subscriber(&DemoSample::onCharacterFormatClicked, this)); | ||
+ | EventArgs e; | ||
+ | onCharacterFormatClicked(e); | ||
+ | |||
+ | // Initialize the localise values | ||
+ | RefreshLocalisedValues(); | ||
+ | } | ||
+ | catch(Exception &e) | ||
+ | { | ||
+ | #if defined( __WIN32__ ) || defined( _WIN32 ) | ||
+ | MessageBox(NULL, e.getMessage().c_str(), "Error initializing the demo", MB_OK | MB_ICONERROR | MB_TASKMODAL); | ||
+ | #else | ||
+ | std::cerr << "Error initializing the demo:" << e.getMessage().c_str() << "\n"; | ||
+ | #endif | ||
+ | } | ||
+ | |||
+ | return true; | ||
+ | } | ||
+ | |||
+ | void cleanupSample(void) | ||
+ | { | ||
+ | CEGUI::FontManager::getSingleton().destroyAllFonts(); | ||
+ | } | ||
+ | private: | ||
+ | ICU icu; // International Components for Unicode | ||
+ | |||
+ | void RefreshLocalisedValues() | ||
+ | { | ||
+ | // Trigger changes in localised widgets to refresh their values accordingly | ||
+ | using namespace CEGUI; | ||
+ | WindowManager& winMgr = WindowManager::getSingleton(); | ||
+ | EventArgs eventArgs; | ||
+ | static_cast<RadioButton*>(winMgr.getWindow("RadioCAD"))->fireEvent(RadioButton::EventSelectStateChanged, eventArgs); | ||
+ | static_cast<PushButton*>(winMgr.getWindow("NumericFormatButton"))->fireEvent(PushButton::EventClicked, eventArgs); | ||
+ | static_cast<PushButton*>(winMgr.getWindow("DateTimeFormatButton"))->fireEvent(PushButton::EventClicked, eventArgs); | ||
+ | static_cast<Spinner*>(winMgr.getWindow("Spinner"))->fireEvent(Spinner::EventValueChanged, eventArgs); | ||
+ | } | ||
+ | |||
+ | bool onLocaleChanged(const CEGUI::EventArgs& e) | ||
+ | { | ||
+ | using namespace CEGUI; | ||
+ | WindowManager& winMgr = WindowManager::getSingleton(); | ||
+ | String country = static_cast<Combobox*>(winMgr.getWindow("Countries"))->getText(); | ||
+ | String language = static_cast<Combobox*>(winMgr.getWindow("Languages"))->getText(); | ||
+ | if(icu.setLocale(language.c_str(), country.c_str())) | ||
+ | RefreshLocalisedValues(); | ||
+ | else | ||
+ | MessageBox(NULL, | ||
+ | ("Error with setLocale(" + language + ", " + country + ")").c_str(), | ||
+ | "Error", | ||
+ | MB_OK | MB_ICONERROR | MB_TASKMODAL); | ||
+ | |||
+ | return true; | ||
+ | } | ||
+ | |||
+ | bool onLoadEveryISO(const CEGUI::EventArgs& e) | ||
+ | { | ||
+ | using namespace CEGUI; | ||
+ | WindowManager& winMgr = WindowManager::getSingleton(); | ||
+ | ListboxTextItem* listboxTextItem; | ||
+ | int32_t count; | ||
+ | |||
+ | // Change the label of the button | ||
+ | PushButton* everyISO = static_cast<PushButton*>(winMgr.getWindow("EveryISO")); | ||
+ | everyISO->setText("This will take a few seconds..."); | ||
+ | |||
+ | // Display every ISO countries in a combobox | ||
+ | Combobox* countries = static_cast<Combobox*>(winMgr.getWindow("Countries")); | ||
+ | const char * const * listCountries = Locale::getISOCountries(); | ||
+ | for(count = 0; listCountries[count]; count++) | ||
+ | { | ||
+ | listboxTextItem = new ListboxTextItem(listCountries[count]); | ||
+ | listboxTextItem->setSelectionBrushImage("TaharezLook", "MultiListSelectionBrush"); | ||
+ | countries->addItem(listboxTextItem); | ||
+ | } | ||
+ | countries->setText( Locale::getDefault().getCountry() ); | ||
+ | |||
+ | // Display every ISO languages in a combobox | ||
+ | Combobox* languages = static_cast<Combobox*>(winMgr.getWindow("Languages")); | ||
+ | const char * const * listLanguages = Locale::getISOLanguages(); | ||
+ | for(count = 0; listLanguages[count]; count++) | ||
+ | { | ||
+ | listboxTextItem = new ListboxTextItem(listLanguages[count]); | ||
+ | listboxTextItem->setSelectionBrushImage("TaharezLook", "MultiListSelectionBrush"); | ||
+ | languages->addItem(listboxTextItem); | ||
+ | } | ||
+ | languages->setText( Locale::getDefault().getLanguage() ); | ||
+ | |||
+ | // Remove this button since it is no longer useful | ||
+ | everyISO->setEnabled(false); | ||
+ | everyISO->setVisible(false); | ||
+ | |||
+ | return true; | ||
+ | } | ||
+ | |||
+ | bool onCurrencyChanged(const CEGUI::EventArgs& e) | ||
+ | { | ||
+ | using namespace CEGUI; | ||
+ | WindowManager& winMgr = WindowManager::getSingleton(); | ||
+ | EventArgs eventArgs; | ||
+ | static_cast<RadioButton*>(winMgr.getWindow("RadioCAD"))->fireEvent(RadioButton::EventSelectStateChanged, eventArgs); | ||
+ | return true; | ||
+ | } | ||
+ | |||
+ | bool onCurrencySelected(const CEGUI::EventArgs& e) | ||
+ | { | ||
+ | // Reformat the numeric value into a properly formatted currency | ||
+ | using namespace CEGUI; | ||
+ | WindowManager& winMgr = WindowManager::getSingleton(); | ||
+ | |||
+ | // Set the currency | ||
+ | CEGUI::uint id = static_cast<RadioButton*>(winMgr.getWindow("RadioCAD"))->getSelectedButtonInGroup()->getID(); | ||
+ | switch(id) | ||
+ | { | ||
+ | case 1: | ||
+ | icu.setCurrency("CAD"); | ||
+ | break; | ||
+ | case 2: | ||
+ | icu.setCurrency("USD"); | ||
+ | break; | ||
+ | case 3: | ||
+ | icu.setCurrency("EUR"); | ||
+ | break; | ||
+ | case 4: | ||
+ | // Mauritania does not use a decimal division of units | ||
+ | // and yet ICU still displays decimal units?? | ||
+ | icu.setCurrency("MRO"); | ||
+ | break; | ||
+ | } | ||
+ | |||
+ | CEGUI::String rawValue = static_cast<Editbox*>(winMgr.getWindow("CurrencyValue"))->getText(); | ||
+ | double currency = atof(rawValue.c_str()); | ||
+ | CEGUI::String formattedValue; | ||
+ | if( icu.formatCurrency(currency, formattedValue) ) | ||
+ | static_cast<Editbox*>(winMgr.getWindow("CurrencyFormattedValue"))->setText(formattedValue); | ||
+ | |||
+ | return true; | ||
+ | } | ||
+ | |||
+ | bool onNumericChanged(const CEGUI::EventArgs& e) | ||
+ | { | ||
+ | using namespace CEGUI; | ||
+ | WindowManager& winMgr = WindowManager::getSingleton(); | ||
+ | EventArgs eventArgs; | ||
+ | static_cast<PushButton*>(winMgr.getWindow("NumericFormatButton"))->fireEvent(PushButton::EventClicked, eventArgs); | ||
+ | |||
+ | return true; | ||
+ | } | ||
+ | |||
+ | bool onNumericFormatClicked(const CEGUI::EventArgs& e) | ||
+ | { | ||
+ | using namespace CEGUI; | ||
+ | WindowManager& winMgr = WindowManager::getSingleton(); | ||
+ | String formattedText; | ||
+ | if( icu.formatNumber(static_cast<Editbox*>(winMgr.getWindow("NumericValue"))->getText(), | ||
+ | static_cast<Editbox*>(winMgr.getWindow("NumericFormat"))->getText(), | ||
+ | formattedText) ) | ||
+ | static_cast<Editbox*>(winMgr.getWindow("NumericFormattedValue"))->setText(formattedText); | ||
+ | |||
+ | // Ordinal representation of an integer value | ||
+ | double doubleValue = atof(static_cast<Editbox*>(winMgr.getWindow("NumericValue"))->getText().c_str()); | ||
+ | if( icu.numberToOrdinal((int) doubleValue, formattedText) ) | ||
+ | static_cast<Editbox*>(winMgr.getWindow("NumericFormattedOrdinal"))->setText(formattedText); | ||
+ | |||
+ | // Textual representation of the numeric value | ||
+ | // Note that this value must be raw, containing only digits and a decimal point | ||
+ | // Since atof() is used to convert from a string to a double this numeric value is not localised | ||
+ | if( icu.numberToText(doubleValue, formattedText) ) | ||
+ | static_cast<Editbox*>(winMgr.getWindow("NumericFormattedText"))->setText(formattedText); | ||
+ | |||
+ | return true; | ||
+ | } | ||
+ | |||
+ | bool onDateTimeChanged(const CEGUI::EventArgs& e) | ||
+ | { | ||
+ | using namespace CEGUI; | ||
+ | WindowManager& winMgr = WindowManager::getSingleton(); | ||
+ | EventArgs eventArgs; | ||
+ | static_cast<PushButton*>(winMgr.getWindow("DateTimeFormatButton"))->fireEvent(PushButton::EventClicked, eventArgs); | ||
+ | |||
+ | return true; | ||
+ | } | ||
+ | |||
+ | bool onDateTimeFormatClicked(const CEGUI::EventArgs& e) | ||
+ | { | ||
+ | // Format the date and time according to their specified values and formats | ||
+ | // In theory a format can include both the date and the time: yyyy/MM/dd HH:mm:ss | ||
+ | // However in practice the resulting time is not accurate (within 1 minute 47 seconds) | ||
+ | using namespace CEGUI; | ||
+ | WindowManager& winMgr = WindowManager::getSingleton(); | ||
+ | UDate localDate, localTime, gmtDate, gmtTime, gmtDateTime; | ||
+ | if(icu.CeguiStringToDateTime( static_cast<Editbox*>(winMgr.getWindow("DateValue"))->getText(), | ||
+ | "yyyy/MM/dd", // Internal format | ||
+ | localDate) | ||
+ | && icu.CeguiStringToDateTime( static_cast<Editbox*>(winMgr.getWindow("TimeValue"))->getText(), | ||
+ | "HH:mm:ss", // Internal format | ||
+ | localTime) ) | ||
+ | { | ||
+ | String formattedDate, formattedTime; | ||
+ | if(icu.formatDateTime( localDate, | ||
+ | static_cast<Editbox*>(winMgr.getWindow("DateFormat"))->getText(), | ||
+ | formattedDate) | ||
+ | && icu.formatDateTime( localTime, | ||
+ | static_cast<Editbox*>(winMgr.getWindow("TimeFormat"))->getText(), | ||
+ | formattedTime) | ||
+ | ) | ||
+ | static_cast<Editbox*>(winMgr.getWindow("LocalDateTimeFormattedValue"))->setText(formattedDate + " " + formattedTime); | ||
+ | |||
+ | // GMT time | ||
+ | if( icu.CeguiStringToDateTime(static_cast<Editbox*>(winMgr.getWindow("LocalDateTimeFormattedValue"))->getText(), | ||
+ | "yyyy/MM/dd HH:mm:ss", | ||
+ | gmtDateTime) | ||
+ | && icu.localToGmt(localDate, localTime, gmtDate, gmtTime) | ||
+ | && icu.formatDateTime(gmtDate, "yyyy/MM/dd", formattedDate) | ||
+ | && icu.formatDateTime(gmtTime, "HH:mm:ss", formattedTime) | ||
+ | ) | ||
+ | static_cast<Editbox*>(winMgr.getWindow("GmtDateTimeFormattedValue"))->setText(formattedDate + " " + formattedTime); | ||
+ | } | ||
+ | |||
+ | return true; | ||
+ | } | ||
+ | |||
+ | bool onSpinnerValueChanged(const CEGUI::EventArgs& e) | ||
+ | { | ||
+ | // Reformat the displayed value into a locale appropriate format | ||
+ | using namespace CEGUI; | ||
+ | WindowManager& winMgr = WindowManager::getSingleton(); | ||
+ | Spinner* spinner = static_cast<Spinner*>(winMgr.getWindow("Spinner")); | ||
+ | |||
+ | String formattedValue; | ||
+ | if( icu.formatNumber(spinner->getCurrentValue(), "#0.00", formattedValue) ) | ||
+ | { | ||
+ | // Disable the Editbox events, especially the EventTextChanged that | ||
+ | // triggers Spinner::handleEditTextChange, which attempts to convert | ||
+ | // the textual value into a non-localised numeric value | ||
+ | Editbox* editbox = static_cast<Editbox*>(winMgr.getWindow(spinner->getName() + "__auto_editbox__")); | ||
+ | bool muted = editbox->isMuted(); | ||
+ | editbox->setMutedState(true); | ||
+ | spinner->setText(formattedValue); | ||
+ | editbox->setMutedState(muted); | ||
+ | } | ||
+ | |||
+ | return true; | ||
+ | } | ||
+ | |||
+ | bool onCharacterChanged(const CEGUI::EventArgs& e) | ||
+ | { | ||
+ | using namespace CEGUI; | ||
+ | WindowManager& winMgr = WindowManager::getSingleton(); | ||
+ | EventArgs eventArgs; | ||
+ | static_cast<PushButton*>(winMgr.getWindow("CharacterFormatButton"))->fireEvent(PushButton::EventClicked, eventArgs); | ||
+ | |||
+ | return true; | ||
+ | } | ||
+ | |||
+ | bool onCharacterFormatClicked(const CEGUI::EventArgs& e) | ||
+ | { | ||
+ | using namespace CEGUI; | ||
+ | WindowManager& winMgr = WindowManager::getSingleton(); | ||
+ | String formattedText; | ||
+ | if( icu.formatText(static_cast<Editbox*>(winMgr.getWindow("CharacterValue"))->getText(), | ||
+ | static_cast<Editbox*>(winMgr.getWindow("CharacterFormat"))->getText(), | ||
+ | "*", | ||
+ | formattedText) ) | ||
+ | static_cast<Editbox*>(winMgr.getWindow("CharacterFormattedValue"))->setText(formattedText); | ||
+ | |||
+ | return true; | ||
+ | } | ||
+ | |||
+ | }; | ||
+ | |||
+ | #endif // _FormattedData_h_ | ||
+ | </source> | ||
+ | |||
+ | === main.cpp === | ||
+ | <source lang="cpp"> | ||
+ | #if defined( __WIN32__ ) || defined( _WIN32 ) | ||
+ | #define WIN32_LEAN_AND_MEAN | ||
+ | #define NOMINMAX | ||
+ | #include "windows.h" | ||
+ | #endif | ||
+ | |||
+ | #include "FormattedNumericData.h" | ||
+ | |||
+ | #if defined( __WIN32__ ) || defined( _WIN32 ) | ||
+ | int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,int nCmdShow) | ||
+ | #else | ||
+ | int main(int argc, char *argv[]) | ||
+ | #endif | ||
+ | { | ||
+ | DemoSample app; | ||
+ | return app.run(); | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | === FormattedData.layout === | ||
+ | <source lang="xml"> | ||
+ | <?xml version="1.0" encoding="UTF-8"?> | ||
+ | |||
+ | <GUILayout > | ||
+ | <Window Type="DefaultWindow" Name="Root" > | ||
+ | <Property Name="InheritsAlpha" Value="False" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0,0},{0,0},{1,0},{1,0}}" /> | ||
+ | <Window Type="TaharezLook/FrameWindow" Name="FrameWindow" > | ||
+ | <Property Name="TitlebarFont" Value="Commonwealth-10" /> | ||
+ | <Property Name="CaptionColour" Value="00FFFFFF" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="TitlebarEnabled" Value="True" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.07125,0},{0.013335,0},{0.910001,0},{0.873733,0}}" /> | ||
+ | <Property Name="MouseCursorImage" Value="set:TaharezLook image:MouseTarget" /> | ||
+ | <Window Type="TaharezLook/Spinner" Name="Spinner" > | ||
+ | <Property Name="Text" Value="10.00" /> | ||
+ | <Property Name="StepSize" Value="1" /> | ||
+ | <Property Name="CurrentValue" Value="10" /> | ||
+ | <Property Name="MaximumValue" Value="32767" /> | ||
+ | <Property Name="MinimumValue" Value="-32768" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.8473,0},{0.731682,0},{0.951964,0},{0.790123,0}}" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/StaticText" Name="SpinnerLabel" > | ||
+ | <Property Name="Text" Value="Localised Spinner widget with 2 decimals:" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.395457,0},{0.731682,0},{0.836346,0},{0.790123,0}}" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/Editbox" Name="CurrencyFormattedValue" > | ||
+ | <Property Name="ReadOnly" Value="True" /> | ||
+ | <Property Name="MaxTextLength" Value="1073741823" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.616765,0},{0.203821,0},{0.954642,0},{0.262262,0}}" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/RadioButton" Name="RadioCAD" > | ||
+ | <Property Name="Text" Value="Canadian (CAD)" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.430655,0},{0.158378,0},{0.614153,0},{0.187144,0}}" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/RadioButton" Name="RadioMRO" > | ||
+ | <Property Name="Font" Value="Commonwealth-10" /> | ||
+ | <Property Name="Text" Value="Mauritania (MRO)" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.430655,0},{0.26902,0},{0.614153,0},{0.297787,0}}" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/RadioButton" Name="RadioUSD" > | ||
+ | <Property Name="Font" Value="Commonwealth-10" /> | ||
+ | <Property Name="Text" Value="US (USD)" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.430655,0},{0.195183,0},{0.5605,0},{0.22395,0}}" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/RadioButton" Name="RadioEUR" > | ||
+ | <Property Name="Font" Value="Commonwealth-10" /> | ||
+ | <Property Name="Text" Value="Euro (EUR)" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.430655,0},{0.232215,0},{0.5605,0},{0.260983,0}}" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/StaticText" Name="CountriesLabel" > | ||
+ | <Property Name="Text" Value="Countries:" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.022504,0},{0.069049,0},{0.132414,0},{0.117804,0}}" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/StaticText" Name="LanguagesLabel" > | ||
+ | <Property Name="Font" Value="Commonwealth-10" /> | ||
+ | <Property Name="Text" Value="Languages:" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.268405,0},{0.069049,0},{0.385766,0},{0.117804,0}}" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/Combobox" Name="Countries" > | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.142027,0},{0.069049,0},{0.245976,0},{0.902039,0}}" /> | ||
+ | <Property Name="MaxEditTextLength" Value="1073741823" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/Combobox" Name="Languages" > | ||
+ | <Property Name="Font" Value="Commonwealth-10" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.395379,0},{0.069049,0},{0.499329,0},{0.90204,0}}" /> | ||
+ | <Property Name="MaxEditTextLength" Value="1073741823" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/StaticText" Name="Separator1" > | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.013562,0},{0.141452,0},{0.995305,0},{0.150048,0}}" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/StaticText" Name="Separator2" > | ||
+ | <Property Name="Font" Value="Commonwealth-10" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.013562,0},{0.309408,0},{0.995305,0},{0.318004,0}}" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/StaticText" Name="Separator3" > | ||
+ | <Property Name="Font" Value="Commonwealth-10" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.013562,0},{0.553045,0},{0.995305,0},{0.561642,0}}" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/StaticText" Name="Separator5" > | ||
+ | <Property Name="Font" Value="Commonwealth-10" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.007601,0},{0.814139,0},{0.989344,0},{0.822736,0}}" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/StaticText" Name="NumericFormatLabel" > | ||
+ | <Property Name="Font" Value="Commonwealth-10" /> | ||
+ | <Property Name="Text" Value="Format:" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.036292,0},{0.403136,0},{0.141946,0},{0.461576,0}}" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/Editbox" Name="NumericFormat" > | ||
+ | <Property Name="Font" Value="Commonwealth-10" /> | ||
+ | <Property Name="Text" Value="#,##0.03" /> | ||
+ | <Property Name="MaxTextLength" Value="1073741823" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.150298,0},{0.403136,0},{0.421111,0},{0.461576,0}}" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/Button" Name="NumericFormatButton" > | ||
+ | <Property Name="Text" Value="Apply" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.473919,0},{0.370638,0},{0.603204,0},{0.429079,0}}" /> | ||
+ | <Property Name="MouseCursorImage" Value="set:TaharezLook image:MouseArrow" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/Editbox" Name="NumericFormattedValue" > | ||
+ | <Property Name="Font" Value="Commonwealth-10" /> | ||
+ | <Property Name="ReadOnly" Value="True" /> | ||
+ | <Property Name="MaxTextLength" Value="1073741823" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.616765,0},{0.339418,0},{0.954642,0},{0.397859,0}}" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/StaticText" Name="DateFormatLabel" > | ||
+ | <Property Name="Font" Value="Commonwealth-10" /> | ||
+ | <Property Name="Text" Value="Format:" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.036292,0},{0.63711,0},{0.141946,0},{0.695551,0}}" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/Editbox" Name="DateFormat" > | ||
+ | <Property Name="Font" Value="Commonwealth-10" /> | ||
+ | <Property Name="Text" Value="yyyy/MM/dd" /> | ||
+ | <Property Name="MaxTextLength" Value="1073741823" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.150298,0},{0.63711,0},{0.269099,0},{0.695551,0}}" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/StaticText" Name="DateValueLabel" > | ||
+ | <Property Name="Font" Value="Commonwealth-10" /> | ||
+ | <Property Name="Text" Value="Date:" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.036292,0},{0.574987,0},{0.141946,0},{0.633428,0}}" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/Editbox" Name="DateValue" > | ||
+ | <Property Name="Font" Value="Commonwealth-10" /> | ||
+ | <Property Name="Text" Value="2006/05/14" /> | ||
+ | <Property Name="MaxTextLength" Value="1073741823" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.150298,0},{0.574987,0},{0.267608,0},{0.633428,0}}" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/Button" Name="DateTimeFormatButton" > | ||
+ | <Property Name="Font" Value="Commonwealth-10" /> | ||
+ | <Property Name="Text" Value="Apply" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.473919,0},{0.610743,0},{0.603205,0},{0.669184,0}}" /> | ||
+ | <Property Name="MouseCursorImage" Value="set:TaharezLook image:MouseArrow" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/Editbox" Name="LocalDateTimeFormattedValue" > | ||
+ | <Property Name="Font" Value="Commonwealth-10" /> | ||
+ | <Property Name="ReadOnly" Value="True" /> | ||
+ | <Property Name="MaxTextLength" Value="1073741823" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.724067,0},{0.578862,0},{0.954642,0},{0.637303,0}}" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/Editbox" Name="TimeValue" > | ||
+ | <Property Name="Font" Value="Commonwealth-10" /> | ||
+ | <Property Name="Text" Value="12:00:01" /> | ||
+ | <Property Name="MaxTextLength" Value="1073741823" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.351492,0},{0.574987,0},{0.441976,0},{0.633428,0}}" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/StaticText" Name="TimeValueLabel" > | ||
+ | <Property Name="Font" Value="Commonwealth-10" /> | ||
+ | <Property Name="Text" Value="Time:" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.280703,0},{0.574987,0},{0.347609,0},{0.633428,0}}" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/Editbox" Name="TimeFormat" > | ||
+ | <Property Name="Font" Value="Commonwealth-10" /> | ||
+ | <Property Name="Text" Value="HH:mm:ss" /> | ||
+ | <Property Name="MaxTextLength" Value="1073741823" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.281446,0},{0.63711,0},{0.441976,0},{0.695551,0}}" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/StaticText" Name="NumericValueLabel" > | ||
+ | <Property Name="Font" Value="Commonwealth-10" /> | ||
+ | <Property Name="Text" Value="Numeric:" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.036292,0},{0.339418,0},{0.141946,0},{0.397857,0}}" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/Editbox" Name="NumericValue" > | ||
+ | <Property Name="Font" Value="Commonwealth-10" /> | ||
+ | <Property Name="Text" Value="123456.78" /> | ||
+ | <Property Name="MaxTextLength" Value="1073741823" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.150298,0},{0.339418,0},{0.421111,0},{0.397858,0}}" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/StaticText" Name="CurrencyValueLabel" > | ||
+ | <Property Name="Font" Value="Commonwealth-10" /> | ||
+ | <Property Name="Text" Value="Currency:" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.036292,0},{0.203821,0},{0.141946,0},{0.26226,0}}" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/Editbox" Name="CurrencyValue" > | ||
+ | <Property Name="Font" Value="Commonwealth-10" /> | ||
+ | <Property Name="Text" Value="123456.78" /> | ||
+ | <Property Name="MaxTextLength" Value="1073741823" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.150298,0},{0.203821,0},{0.421111,0},{0.262262,0}}" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/StaticText" Name="Separator4" > | ||
+ | <Property Name="Font" Value="Commonwealth-10" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.013562,0},{0.702202,0},{0.995305,0},{0.710798,0}}" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/Button" Name="EveryISO" > | ||
+ | <Property Name="Text" Value="Load every country and languages" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.559611,0},{0.069049,0},{0.94523,0},{0.12749,0}}" /> | ||
+ | <Property Name="MouseCursorImage" Value="set:TaharezLook image:MouseArrow" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/Editbox" Name="NumericFormattedText" > | ||
+ | <Property Name="Font" Value="Commonwealth-10" /> | ||
+ | <Property Name="ReadOnly" Value="True" /> | ||
+ | <Property Name="MaxTextLength" Value="1073741823" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.153278,0},{0.482989,0},{0.954642,0},{0.54143,0}}" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/Editbox" Name="CharacterFormattedValue" > | ||
+ | <Property Name="Font" Value="Commonwealth-10" /> | ||
+ | <Property Name="ReadOnly" Value="True" /> | ||
+ | <Property Name="MaxTextLength" Value="1073741823" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.616765,0},{0.883872,0},{0.954642,0},{0.942313,0}}" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/Editbox" Name="CharacterFormat" > | ||
+ | <Property Name="Font" Value="Commonwealth-10" /> | ||
+ | <Property Name="Text" Value="000 000 000" /> | ||
+ | <Property Name="MaxTextLength" Value="1073741823" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.150298,0},{0.908716,0},{0.421111,0},{0.967156,0}}" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/Button" Name="CharacterFormatButton" > | ||
+ | <Property Name="Font" Value="Commonwealth-10" /> | ||
+ | <Property Name="Text" Value="Apply" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.473919,0},{0.883872,0},{0.603205,0},{0.942313,0}}" /> | ||
+ | <Property Name="MouseCursorImage" Value="set:TaharezLook image:MouseArrow" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/Editbox" Name="CharacterValue" > | ||
+ | <Property Name="Font" Value="Commonwealth-10" /> | ||
+ | <Property Name="Text" Value="123456" /> | ||
+ | <Property Name="MaxTextLength" Value="1073741823" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.150298,0},{0.844998,0},{0.421111,0},{0.903438,0}}" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/StaticText" Name="LocalDateTimeFormattedLabel" > | ||
+ | <Property Name="Font" Value="Commonwealth-10" /> | ||
+ | <Property Name="Text" Value="Local:" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.641358,0},{0.578862,0},{0.718697,0},{0.637302,0}}" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/StaticText" Name="GmtDateTimeFormattedLabel" > | ||
+ | <Property Name="Font" Value="Commonwealth-10" /> | ||
+ | <Property Name="Text" Value="GMT:" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.641358,0},{0.63711,0},{0.718697,0},{0.69555,0}}" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/Editbox" Name="GmtDateTimeFormattedValue" > | ||
+ | <Property Name="Font" Value="Commonwealth-10" /> | ||
+ | <Property Name="ReadOnly" Value="True" /> | ||
+ | <Property Name="MaxTextLength" Value="1073741823" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.725558,0},{0.63711,0},{0.954642,0},{0.695551,0}}" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/StaticText" Name="NumericValueLabel1" > | ||
+ | <Property Name="Font" Value="Commonwealth-10" /> | ||
+ | <Property Name="Text" Value="Numeric:" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.036292,0},{0.844998,0},{0.141946,0},{0.903437,0}}" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/StaticText" Name="NumericFormatLabel1" > | ||
+ | <Property Name="Font" Value="Commonwealth-10" /> | ||
+ | <Property Name="Text" Value="Format:" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.036292,0},{0.908716,0},{0.141946,0},{0.967156,0}}" /> | ||
+ | </Window> | ||
+ | <Window Type="TaharezLook/Editbox" Name="NumericFormattedOrdinal" > | ||
+ | <Property Name="Font" Value="Commonwealth-10" /> | ||
+ | <Property Name="ReadOnly" Value="True" /> | ||
+ | <Property Name="MaxTextLength" Value="1073741823" /> | ||
+ | <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> | ||
+ | <Property Name="UnifiedAreaRect" Value="{{0.616765,0},{0.403136,0},{0.954642,0},{0.461577,0}}" /> | ||
+ | </Window> | ||
+ | </Window> | ||
+ | </Window> | ||
+ | </GUILayout> | ||
+ | </source> | ||
− | + | [[Category:Tutorials]] |
Latest revision as of 12:34, 28 February 2011
Written for CEGUI 0.6
Works with versions 0.6.x (obsolete)
Written for CEGUI 0.5
Works with versions 0.5.x (obsolete)
International Components for Unicode (ICU) is a toolkit to internationalise applications. Initially developed for Java it has been ported to C/C++. There is a Java version of ICU called ICU4J, and there is a C/C++ version of ICU called ICU4C. Now ICU4C has been partially ported to CEGUI. Please use this thread for discussion.
International Components for Unicode
Useful Links
- Home page
- Licence
- Documentation
- ICU4C API Reference
- ISO 639 Language Codes
- ISO 15924 Script Codes
- ISO 3166 Country Codes
- ISO 4217 Currency Codes
- ICU Decimal Format Syntax
- ICU Date/Time Format Syntax
Getting started
Download these files from the ICU web site
- Source: icu-3.4.1.zip for Windows OR icu-3.4.1.tgz for Unix
- Documentation: icu-3.4-docs.zip
- User Guide: icu-3.4-userguide.zip
Files of interest:
- Solution to compile: icu/source/allinone/allinone.sln
- Instructions to compile and use ICU: icu/readme.html#HowToBuildWindows
- ICU4C samples: icu/source/samples/
The instructions for building and setting up ICU are contained in the readme.html. If you have any problems, contact the icu-support mailing list or submit a bug report.
Incorporating ICU4C within an existing project
Additional include directories:
- $(ICU)\include
Additional library directories:
- $(ICU)\lib
Link with:
- debug: icuucd.lib icuind.lib
- release: icuuc.lib icuin.lib
Make certain these DLLs are present with your executable or in your PATH:
- debug: icuuc34d.dll icuin34d.dll icudt34.dll
- release: icuuc34.dll icuin34.dll icudt34.dll
CEGUI's ICU
ICU4C provides many features to support internationalisation. The class I've created encapsulates some (not all) of these features.
Locale
A Locale is an identifier that describes the rules in effect within a country for a specific language. These rules specify the formatting of currencies, numeric values, dates, and others. Unfortunately these rules do not take into consideration the modifications that may have been applied within the Regional Settings of Window's Control Panel, unless the "@compat=host" locale is used, which is available in ICU 3.6 and later. However most functions accept a formatting mask. This allows applications to recreate some of the features of the control panel, allowing users to specify their desired formats. The setLocale() and setCurrency() functions will configure the class to adopt the rules specified by the specified language, country, and currency.
formatNumber
The formatNumber() function formats a numeric value given the specified mask. Three versions are available. The versions accepting a CEGUI::String has been customised to allow large numbers to be formatted: numbers having up to 18 integers and 7 decimals. The current implementation of this function is limited to accepting a single format for positive numbers. If the numeric value to be formatted is negative then a negative sign will precede the formatted value. However it is impossible to format a negative value within parentheses: formatting -1234.56 to (1,234.56).
numberToText
The numberToText() function converts a numeric value into a textual representation. For example the numeric value 123 is converted into "one hundred twenty-three" in English and "cent vingt-trois" in French.
numberToOrdinal
The numberToOrdinal() function converts a numeric value into an ordinal representation. For example the numeric value 1 is converted into "1st" in english. Support for other languages is either buggy or lacking (or I have improperly coded this feature).
formatText
The formatText() function will parse a numeric value and sprinkle digits into the slots specified by the formatting mask. A North American telephone number of "12223334444" can be formatted into "1 (222) 333-4444" with the mask "0 (000) 000-0000". This non-localised function accepts three format specifier. A "0" represents a forced digit. If the numerical value possesses a digit at that position then the digit will be displayed, otherwise the place holder character(s) will be used. A "#" represents a potential digit. If the numerical value possesses a digit at that position the the digit will be displayed, otherwise nothing is displayed. Finally the apostrophe "'" allows the mask to specify the characters "0", "#", or "'", rather than using them as format specifiers.
formatCurrency
The formatCurrency() function will format a numerical value according to the currently configured locale and currency. It will NOT convert the monetary value of one currency to another.
formatDateTime
The formatDateTime() function will format a date, time, or date/time given the specified mask. The UDate variable type is a double. According to ICU's documentation A UDate value is stored as UTC time in milliseconds, which means it is calendar and time zone independent. UDate is the most compact and portable way to store and transmit a date and time.
localToGmt and gmtToLocal
The localToGmt() and the gmtToLocal() functions convert a date and a time between a local and a GMT value.
CeguiStringToDateTime
The CeguiStringToDateTime() function will parse a string specifying a date or a time into its corresponding UDate value. Although it is possible to parse a string containing both a date and a time the resulting UDate value will be inaccurate, varying from its intended value by up to 1 minute 47 seconds. A better approach is to keep the date and time separated.
Source Code
icu.h
#ifndef _ICU_h_ #define _ICU_h_ #include "unicode/utypes.h" #include "unicode/unistr.h" #include "unicode/numfmt.h" #include "unicode/dcfmtsym.h" #include "unicode/decimfmt.h" #include "unicode/locid.h" #include "unicode/uclean.h" #include "unicode/calendar.h" #include "unicode/datefmt.h" #include "unicode/smpdtfmt.h" #include "unicode/rbnf.h" #include "CEGUI.h" class ICU { public: ICU(bool cleanupICU = true); ~ICU(); bool setLocale(const CEGUI::String& language, const CEGUI::String& country); const Locale& getLocale(); bool setCurrency(const char *currency); bool formatNumber(const CEGUI::String& rawValue, const CEGUI::String& mask, CEGUI::String& formattedValue); bool formatNumber(const double rawValue, const CEGUI::String& mask, CEGUI::String& formattedValue); bool formatNumber(const int32_t rawValue, const CEGUI::String& mask, CEGUI::String& formattedValue); bool numberToText(const double rawValue, CEGUI::String& formattedValue); bool numberToText(const int32_t rawValue, CEGUI::String& formattedValue); bool numberToOrdinal(const double rawValue, CEGUI::String& formattedValue); bool numberToOrdinal(const int32_t rawValue, CEGUI::String& formattedValue); bool formatText(const CEGUI::String& rawValue, const CEGUI::String& mask, const CEGUI::String& zeroPlaceHolder, CEGUI::String& formattedValue); bool formatCurrency(const double& currency, CEGUI::String& formattedValue); bool formatDateTime(UDate rawDateTime, const CEGUI::String& mask, CEGUI::String& formattedDateTime); bool localToGmt(const UDate& localDate, const UDate& localTime, UDate& gmtDate, UDate& gmtTime); bool gmtToLocal(const UDate& gmtDate, const UDate& gmtTime, UDate& localDate, UDate& localTime); bool CeguiStringToDateTime(const CEGUI::String& stringDateTime, const CEGUI::String& mask, UDate& unicodeDateTime); bool CeguiStringToInt32(const CEGUI::String& stringValue, int32_t& int32Value); void UnicodeToCeguiString(const UnicodeString& unicodeString, CEGUI::String& ceguiString); private: void _splitIntegerDecimal(const CEGUI::String& combined, CEGUI::String& integerPart, CEGUI::String& decimalPart); bool _convertLocalAndGmt(const UDate& localDate, const UDate& localTime, UDate& gmtDate, UDate& gmtTime, bool fromLocalToGMT); bool _ruleBasedNumberFormat(const double rawValue, URBNFRuleSetTag tag, CEGUI::String& formattedValue); bool _ruleBasedNumberFormat(const int32_t rawValue, URBNFRuleSetTag tag, CEGUI::String& formattedValue); Locale m_locale; // Current locale of the computer UChar m_currency[4]; // Currency code bool m_cleanupICU; // Whether to call ICU's cleanup function }; #endif // _ICU_h_
icu.cpp
#include "ICU.h" #include <vector> ICU::ICU(bool cleanupICU) { m_cleanupICU = cleanupICU; } ICU::~ICU() { // http://www.icu-project.org/userguide/design.html#Init_and_Termination // The paragraph "ICU Initialization and Termination" mentions that this function // can be called to force the ICU library to release any allocated heap storage // otherwise memory leak checking tools will falsely report leaks. // My thinking with this m_cleanupICU variable is that the library should not release // its memory allocation if it is also used outside of this class. This // implementation grants you some control over when this cleanup occurs. // You are not required to call u_cleanup(). It's dangerous if called at the wrong time. if(m_cleanupICU) u_cleanup(); } bool ICU::setLocale(const CEGUI::String& language, const CEGUI::String& country) { // Set the locale Locale tempLocale = Locale::createFromName((language + "_" + country).c_str()); if(tempLocale.isBogus()) return false; m_locale = tempLocale; return true; } const Locale& ICU::getLocale() { // Retrive the locale return m_locale; } bool ICU::setCurrency(const char *currency) { // Set the currency if(currency==NULL || strlen(currency)!=3) return false; // Invariant-character conversion to UChars u_charsToUChars(currency, m_currency, 4); return true; } bool ICU::formatNumber(const CEGUI::String& rawValue, const CEGUI::String& mask, CEGUI::String& formattedValue) { // Format a unformatted number according to the rules specified within the mask // An unformatted number only contains numeric digits and a period as the decimal point // Note that a decimal value is broken down into two numbers, an // integer and a decimal number for formatting and then reassembled // into a single string. This makes it possible to handle numbers // as large as 999,999,999,999,999,999.9999999 (18 integers and 7 decimals). // However it makes it impossible to specify a positive mask as well as a // negative mask; only one mask is supported. It is also impossible to // format a negative value with a mask similar to "(#,##0.00)" UErrorCode status = U_ZERO_ERROR; formattedValue.clear(); CEGUI::String formattedInteger, formattedDecimal; CEGUI::String::size_type idx; // Separate the integer and the decimal parts from the value CEGUI::String maskInteger, maskDecimal, integerValue, decimalValue; idx = rawValue.find("."); if(idx == CEGUI::String::npos) { // If the value is empty then force the integer to 0, otherwise use the value // Since there is no decimal point force a decimal value of .0 integerValue = rawValue.empty() ? "0" : rawValue; decimalValue = ".0"; } else { // If there is no integer portion then force an integer value of 0 integerValue = idx == 0 ? "0" : rawValue.substr(0, idx); decimalValue = rawValue.substr(idx); } // Separate the integer and the decimal parts from the mask _splitIntegerDecimal(mask, maskInteger, maskDecimal); // Prepare the numeric formatter DecimalFormatSymbols* decimalFormatSymbols = new DecimalFormatSymbols(m_locale, status); if( U_FAILURE(status) ) return false; if(!maskInteger.empty()) { // Prepare the integer parser UnicodeString patternInteger(maskInteger.c_str()); DecimalFormat* fmt = new DecimalFormat(patternInteger, *decimalFormatSymbols, status); if( U_FAILURE(status) ) { delete decimalFormatSymbols; return false; } // Parse the string value into an integer value UnicodeString uIntegerValue(integerValue.c_str()); Formattable fIntegerValue; fmt->parse(uIntegerValue, fIntegerValue, status); if( U_FAILURE(status) ) { status = U_ZERO_ERROR; fIntegerValue.setInt64(0); } // Format the integer value uIntegerValue = ""; ((NumberFormat*)fmt)->format(fIntegerValue.getInt64(), uIntegerValue); delete fmt; UnicodeToCeguiString(uIntegerValue, formattedInteger); } if(!maskDecimal.empty()) { // Prepare the decimal parser DecimalFormat* fmtParse = new DecimalFormat(status); if( U_FAILURE(status) ) { delete decimalFormatSymbols; return false; } fmtParse->applyLocalizedPattern("0.0000003", status); // Parse the string value into a decimal value UnicodeString uDecimalValue(decimalValue.c_str()); Formattable fDecimalValue; fmtParse->parse(uDecimalValue, fDecimalValue, status); delete fmtParse; if( U_FAILURE(status) ) { status = U_ZERO_ERROR; fDecimalValue.setDouble(0.0); } // Prepare the decimal formatter UnicodeString patternDecimal(maskDecimal.c_str()); DecimalFormat* fmt = new DecimalFormat(patternDecimal, *decimalFormatSymbols, status); if( U_FAILURE(status) ) { delete decimalFormatSymbols; return false; } // Format the decimal value uDecimalValue = ""; fmt->format(fDecimalValue.getDouble(), uDecimalValue); delete fmt; UnicodeToCeguiString(uDecimalValue, formattedDecimal); } delete decimalFormatSymbols; formattedValue = formattedInteger + formattedDecimal; return true; } bool ICU::formatNumber(const double rawValue, const CEGUI::String& mask, CEGUI::String& formattedValue) { // Format a number using the appropriate locale rules // Note that the use of a double limits the effective range UErrorCode status = U_ZERO_ERROR; formattedValue.clear(); // Prepare the numeric formatter DecimalFormatSymbols* symbols = new DecimalFormatSymbols(m_locale, status); if( U_FAILURE(status) ) return false; // Create a number formatter for the current locale UnicodeString pattern(mask.c_str()); DecimalFormat* fmt = new DecimalFormat(pattern, *symbols, status); if( U_FAILURE(status) ) { delete symbols; return false; } // Format the number UnicodeString uValue; fmt->format(rawValue, uValue, status); delete symbols; delete fmt; if( U_FAILURE(status) ) return false; UnicodeToCeguiString(uValue, formattedValue); return true; } bool ICU::formatNumber(const int32_t rawValue, const CEGUI::String& mask, CEGUI::String& formattedValue) { // Format a number using the appropriate locale rules // Note that the use of a double limits the effective range UErrorCode status = U_ZERO_ERROR; formattedValue.clear(); // Prepare the numeric formatter DecimalFormatSymbols* symbols = new DecimalFormatSymbols(m_locale, status); if( U_FAILURE(status) ) return false; // Create a number formatter for the current locale UnicodeString pattern(mask.c_str()); DecimalFormat* fmt = new DecimalFormat(pattern, *symbols, status); if( U_FAILURE(status) ) { delete symbols; return false; } // Format the number UnicodeString uValue; fmt->format(rawValue, uValue, status); delete symbols; delete fmt; if( U_FAILURE(status) ) return false; UnicodeToCeguiString(uValue, formattedValue); return true; } bool ICU::numberToText(const double rawValue, CEGUI::String& formattedValue) { // Convert a number to a text // "1.2" to "one point two" return _ruleBasedNumberFormat(rawValue, URBNF_SPELLOUT, formattedValue); } bool ICU::numberToText(const int32_t rawValue, CEGUI::String& formattedValue) { // Convert a number to a text // "12" to "twelve" return _ruleBasedNumberFormat(rawValue, URBNF_SPELLOUT, formattedValue); } bool ICU::numberToOrdinal(const double rawValue, CEGUI::String& formattedValue) { // Convert a number to ordinal text // "1.5" to "2nd" return _ruleBasedNumberFormat(rawValue, URBNF_ORDINAL, formattedValue); } bool ICU::numberToOrdinal(const int32_t rawValue, CEGUI::String& formattedValue) { // Convert a number to ordinal text // "1" to "1st" return _ruleBasedNumberFormat(rawValue, URBNF_ORDINAL, formattedValue); } bool ICU::formatText(const CEGUI::String& rawValue, const CEGUI::String& mask, const CEGUI::String& zeroPlaceHolder, CEGUI::String& formattedValue) { /* Format a value according to a pattern * Format specifiers: * 0 forced digit: will be replaced by a digit or if there is no digit, by 'zeroPlaceHolder' * # potential digit: will be replaced by a digit if there is one otherwise nothing * ' literal character: the following character is to be treated as a character * rather than a format specifier * ex the value "1" with the format "'00" will result in the string "01" * Note that if the value is larger than the pattern then it is truncated to the left * ex the value "1234" with the format "#0" results in the string "34" */ formattedValue.clear(); if(!rawValue.length() || !mask.length()) return false; // Parse the mask std::vector<CEGUI::String> maskList; CEGUI::String maskDigit; for(CEGUI::String::size_type idxMask = 0; idxMask < mask.length(); ++idxMask) { if(!mask.compare(idxMask, 1, "0")) { maskDigit = "ForcedDigit"; maskList.push_back(maskDigit); } else if(!mask.compare(idxMask, 1, "#")) { maskDigit = "PotentialDigit"; maskList.push_back(maskDigit); } else { if(!mask.compare(idxMask, 1, "'") && idxMask < mask.length() - 1) ++idxMask; // Literal specifier followed by a mask digit, so skip over the apostrophe maskDigit = mask.at(idxMask); maskList.push_back(maskDigit); } } // Format the numeric value CEGUI::String::size_type idxValue; idxValue = rawValue.length(); std::vector<CEGUI::String>::reverse_iterator itMask; for(itMask = maskList.rbegin(); itMask != maskList.rend(); ++itMask) { if(!(*itMask).compare("ForcedDigit")) { if(idxValue) { // We have a digit remaining --idxValue; formattedValue = rawValue.at(idxValue) + formattedValue; } else { // We're out of digits formattedValue = zeroPlaceHolder + formattedValue; } } else if(!(*itMask).compare("PotentialDigit")) { if(idxValue) { // We have a digit remaining --idxValue; formattedValue = rawValue.at(idxValue) + formattedValue; } } else { // Literal character formattedValue = (*itMask) + formattedValue; } } return true; } bool ICU::formatCurrency(const double& currency, CEGUI::String& formattedValue) { // Format a number using the appropriate locale rules // Note that the use of a double limits the effective range UErrorCode status = U_ZERO_ERROR; formattedValue.clear(); // Create a number formatter for the current locale NumberFormat *fmt = NumberFormat::createCurrencyInstance(m_locale, status); if( U_FAILURE(status) ) return false; // Format the currency UnicodeString uValue; fmt->format(currency, uValue); delete fmt; UnicodeToCeguiString(uValue, formattedValue); return true; } bool ICU::formatDateTime(UDate rawDateTime, const CEGUI::String& mask, CEGUI::String& formattedDateTime) { // Format a date/time given the specified mask // Note that although a UDate can support both date and time in // realite the resolution is insufficient. In order to precisely // represent a date/time value they should be processed separately UErrorCode status = U_ZERO_ERROR; formattedDateTime.clear(); // Create a Date/Time formatter DateFormat* fmt = DateFormat::createDateTimeInstance(DateFormat::kDefault, DateFormat::kDefault, m_locale); // kDefault is not really used // Activate our pattern (overrides DateFormat::kDefault) UnicodeString pattern(mask.c_str()); ((SimpleDateFormat*) fmt)->applyPattern(pattern); // Format the date/time UnicodeString uValue; fmt->format(rawDateTime, uValue, status); delete fmt; if( U_FAILURE(status) ) return false; UnicodeToCeguiString(uValue, formattedDateTime); return true; } bool ICU::localToGmt(const UDate& localDate, const UDate& localTime, UDate& gmtDate, UDate& gmtTime) { // Convert a local date/time into a GMT date/time return _convertLocalAndGmt(localDate, localTime, gmtDate, gmtTime, true); } bool ICU::gmtToLocal(const UDate& gmtDate, const UDate& gmtTime, UDate& localDate, UDate& localTime) { // Convert a GMT date/time into a local date/time string return _convertLocalAndGmt(gmtDate, gmtTime, localDate, localTime, false); } bool ICU::CeguiStringToDateTime(const CEGUI::String& stringDateTime, const CEGUI::String& mask, UDate& unicodeDateTime) { // Convert a string date/time into a UDate UErrorCode status = U_ZERO_ERROR; unicodeDateTime = 0.0; // Create a Date/Time formatter DateFormat* fmt = DateFormat::createDateTimeInstance(DateFormat::kDefault, DateFormat::kDefault, m_locale); // Activate our pattern UnicodeString pattern(mask.c_str()); ((SimpleDateFormat*) fmt)->applyPattern(pattern); // Parse the string into a date/time UnicodeString uValue(stringDateTime.c_str()); unicodeDateTime = fmt->parse(uValue, status); delete fmt; if( U_FAILURE(status) ) return false; return true; } bool ICU::CeguiStringToInt32(const CEGUI::String& stringValue, int32_t& int32Value) { // Convert a string into an int32_t UErrorCode status = U_ZERO_ERROR; int32Value = 0; // Create an integer formatter NumberFormat *fmt = NumberFormat::createInstance(Locale::getUS(), status); if( U_FAILURE(status) ) return false; // Activate our pattern UnicodeString pattern("#,##0"); ((DecimalFormat*) fmt)->applyPattern(pattern, status); if( U_FAILURE(status) ) { delete fmt; return false; } // Parse the string into a double UnicodeString uValue(stringValue.c_str()); Formattable result; fmt->parse(uValue, result, status); delete fmt; if( U_FAILURE(status) ) return false; int32Value = result.getLong(); return true; } void ICU::UnicodeToCeguiString(const UnicodeString& unicodeString, CEGUI::String& ceguiString) { // Convert a unicode string to a CEGUI string ceguiString.clear(); CEGUI::String digit; for(int32_t i = 0; i < unicodeString.length(); ++i) { digit = unicodeString.charAt(i); ceguiString.append(digit); } } void ICU::_splitIntegerDecimal(const CEGUI::String& combined, CEGUI::String& integerPart, CEGUI::String& decimalPart) { // Split a decimal value into its constituent integer and decimal parts CEGUI::String::size_type idx = combined.find("."); if(idx == CEGUI::String::npos) { integerPart = combined; decimalPart.clear(); } else { integerPart = combined.substr(0, idx); decimalPart = combined.substr(idx); } } bool ICU::_convertLocalAndGmt(const UDate& localDate, const UDate& localTime, UDate& gmtDate, UDate& gmtTime, bool fromLocalToGMT) { // Helper function to convert between a local and a GMT date/time UErrorCode status = U_ZERO_ERROR; gmtDate = gmtTime = 0.0; // Create a calendar for the local date Calendar* calLocalDate = Calendar::createInstance(m_locale, status); if( U_FAILURE(status) ) return false; calLocalDate->clear(); calLocalDate->setTime(localDate, status); if( U_FAILURE(status) ) { delete calLocalDate; return false; } // Create a calendar for the local time Calendar* calLocalTime = Calendar::createInstance(m_locale, status); if( U_FAILURE(status) ) { delete calLocalDate; return false; } calLocalTime->clear(); calLocalTime->setTime(localTime, status); if( U_FAILURE(status) ) { delete calLocalDate; delete calLocalTime; return false; } // Retrieve the offset between this time zone and the GMT time zone // The Daylight Saving Time offset is zero when DST is not in effect // Note that adding the local date and time together introduces an // inaccuracy of up to 1 minute 47 seconds. However the only impact // of this inaccuracy is to advance/delay the activation or deactivation // of daylight savings int32_t rawOffset, dstOffset, gmtOffset; calLocalDate->getTimeZone().getOffset(localDate + localTime, true, rawOffset, dstOffset, status); gmtOffset = (rawOffset + dstOffset) / 1000 / 60 / 60; // Convert from milliseconds to hours // Converting from local to GMT requires "reversing" the time zone // EST is GMT-5 so it requires adding 5 hours to local time to obtain GMT // Converting from GMT to local requires the opposite int32_t hour = calLocalTime->get(UCAL_HOUR_OF_DAY, status); if(fromLocalToGMT) hour -= gmtOffset; else hour += gmtOffset; // Adjust the time and date if necessary if(hour >= 24) { // We've moved to the next day hour -= 24; calLocalDate->add(UCAL_DAY_OF_MONTH, 1, status); if( U_FAILURE(status) ) { delete calLocalDate; delete calLocalTime; return false; } } else if(hour < 0) { // We've moved to the previous day hour += 24; calLocalDate->add(UCAL_DAY_OF_MONTH, -1, status); if( U_FAILURE(status) ) { delete calLocalDate; delete calLocalTime; return false; } } calLocalTime->set(UCAL_HOUR_OF_DAY, hour); // Retrieve the converted date and time gmtDate = calLocalDate->getTime(status); gmtTime = calLocalTime->getTime(status); delete calLocalDate; delete calLocalTime; if( U_FAILURE(status) ) return false; return true; } bool ICU::_ruleBasedNumberFormat(const double rawValue, URBNFRuleSetTag tag, CEGUI::String& formattedValue) { UErrorCode status = U_ZERO_ERROR; formattedValue.clear(); // Create a rule based number formatter RuleBasedNumberFormat* fmt = new RuleBasedNumberFormat(tag, m_locale, status); if( U_FAILURE(status) ) return false; UnicodeString uValue; fmt->format(rawValue, uValue); delete fmt; formattedValue.clear(); UnicodeToCeguiString(uValue, formattedValue); return true; } bool ICU::_ruleBasedNumberFormat(const int32_t rawValue, URBNFRuleSetTag tag, CEGUI::String& formattedValue) { UErrorCode status = U_ZERO_ERROR; formattedValue.clear(); // Create a rule based number formatter RuleBasedNumberFormat* fmt = new RuleBasedNumberFormat(tag, m_locale, status); if( U_FAILURE(status) ) return false; UnicodeString uValue; Formattable fValue(rawValue); fmt->format(fValue, uValue, status); delete fmt; if( U_FAILURE(status) ) return false; formattedValue.clear(); UnicodeToCeguiString(uValue, formattedValue); return true; }
FormattedData.h
#ifndef _FormattedData_h_ #define _FormattedData_h_ #include "CEGuiSample.h" #include "CEGUI.h" #include "ICU.h" class DemoSample : public CEGuiSample { public: bool initialiseSample() { using namespace CEGUI; try { // Retrieve the window manager WindowManager& winMgr = WindowManager::getSingleton(); // Load the TaharezLook scheme and set up the default mouse cursor and font SchemeManager::getSingleton().loadScheme("TaharezLook.scheme"); System::getSingleton().setDefaultMouseCursor("TaharezLook", "MouseArrow"); if(!FontManager::getSingleton().isFontPresent("Commonwealth-10")) FontManager::getSingleton().createFont("Commonwealth-10.font"); // Set the GUI Sheet Window* sheet = winMgr.createWindow("DefaultWindow", "root_wnd"); System::getSingleton().setGUISheet(sheet); // Load a layout Window* guiLayout = winMgr.loadWindowLayout("FormattedData.layout"); sheet->addChildWindow(guiLayout); /******** ICU Stuff ********/ // Display one ISO country in a combo box Combobox* countries = static_cast<Combobox*>(winMgr.getWindow("Countries")); countries->setReadOnly(true); ListboxTextItem* listboxTextItem; listboxTextItem = new ListboxTextItem( Locale::getDefault().getCountry() ); listboxTextItem->setSelectionBrushImage("TaharezLook", "MultiListSelectionBrush"); countries->addItem(listboxTextItem); countries->setText( Locale::getDefault().getCountry() ); countries->subscribeEvent(Combobox::EventListSelectionAccepted, Event::Subscriber(&DemoSample::onLocaleChanged, this)); // Display two ISO languages in a combo box Combobox* languages = static_cast<Combobox*>(winMgr.getWindow("Languages")); languages->subscribeEvent(Combobox::EventListSelectionAccepted, Event::Subscriber(&DemoSample::onLocaleChanged, this)); languages->setReadOnly(true); listboxTextItem = new ListboxTextItem("en"); listboxTextItem->setSelectionBrushImage("TaharezLook", "MultiListSelectionBrush"); languages->addItem(listboxTextItem); listboxTextItem = new ListboxTextItem("fr"); listboxTextItem->setSelectionBrushImage("TaharezLook", "MultiListSelectionBrush"); languages->addItem(listboxTextItem); languages->setText("en"); languages->subscribeEvent(Combobox::EventListSelectionAccepted, Event::Subscriber(&DemoSample::onLocaleChanged, this)); PushButton* everyISO = static_cast<PushButton*>(winMgr.getWindow("EveryISO")); everyISO->subscribeEvent(PushButton::EventClicked, Event::Subscriber(&DemoSample::onLoadEveryISO, this)); // Configure the currency widgets Editbox* currencyValue = static_cast<Editbox*>(winMgr.getWindow("CurrencyValue")); currencyValue->subscribeEvent(Editbox::EventTextChanged, Event::Subscriber(&DemoSample::onCurrencyChanged, this)); RadioButton* radio; radio = static_cast<RadioButton*>(winMgr.getWindow("RadioCAD")); radio->subscribeEvent(RadioButton::EventSelectStateChanged, Event::Subscriber(&DemoSample::onCurrencySelected, this)); radio->setID(1); radio->setSelected(true); radio = static_cast<RadioButton*>(winMgr.getWindow("RadioUSD")); radio->subscribeEvent(RadioButton::EventSelectStateChanged, Event::Subscriber(&DemoSample::onCurrencySelected, this)); radio->setID(2); radio = static_cast<RadioButton*>(winMgr.getWindow("RadioEUR")); radio->subscribeEvent(RadioButton::EventSelectStateChanged, Event::Subscriber(&DemoSample::onCurrencySelected, this)); radio->setID(3); radio = static_cast<RadioButton*>(winMgr.getWindow("RadioMRO")); radio->subscribeEvent(RadioButton::EventSelectStateChanged, Event::Subscriber(&DemoSample::onCurrencySelected, this)); radio->setID(4); // Configure the numeric widgets Editbox* numericValue = static_cast<Editbox*>(winMgr.getWindow("NumericValue")); numericValue->subscribeEvent(Editbox::EventTextChanged, Event::Subscriber(&DemoSample::onNumericChanged, this)); Editbox* numericFormat = static_cast<Editbox*>(winMgr.getWindow("NumericFormat")); numericFormat->subscribeEvent(Editbox::EventTextChanged, Event::Subscriber(&DemoSample::onNumericChanged, this)); PushButton* numericFormatButton = static_cast<PushButton*>(winMgr.getWindow("NumericFormatButton")); numericFormatButton->subscribeEvent(PushButton::EventClicked, Event::Subscriber(&DemoSample::onNumericFormatClicked, this)); // Configure the date/time widgets Editbox* dateValue = static_cast<Editbox*>(winMgr.getWindow("DateValue")); dateValue->subscribeEvent(Editbox::EventTextChanged, Event::Subscriber(&DemoSample::onDateTimeChanged, this)); Editbox* timeValue = static_cast<Editbox*>(winMgr.getWindow("TimeValue")); timeValue->subscribeEvent(Editbox::EventTextChanged, Event::Subscriber(&DemoSample::onDateTimeChanged, this)); Editbox* dateFormat = static_cast<Editbox*>(winMgr.getWindow("DateFormat")); dateFormat->subscribeEvent(Editbox::EventTextChanged, Event::Subscriber(&DemoSample::onDateTimeChanged, this)); Editbox* timeFormat = static_cast<Editbox*>(winMgr.getWindow("TimeFormat")); timeFormat->subscribeEvent(Editbox::EventTextChanged, Event::Subscriber(&DemoSample::onDateTimeChanged, this)); PushButton* dateTimeFormatButton = static_cast<PushButton*>(winMgr.getWindow("DateTimeFormatButton")); dateTimeFormatButton->subscribeEvent(PushButton::EventClicked, Event::Subscriber(&DemoSample::onDateTimeFormatClicked, this)); // Configure the spinner Spinner* spinner = static_cast<Spinner*>(winMgr.getWindow("Spinner")); spinner->subscribeEvent(Spinner::EventValueChanged, Event::Subscriber(&DemoSample::onSpinnerValueChanged, this)); static_cast<Editbox*>(winMgr.getWindow(spinner->getName() + "__auto_editbox__"))->setReadOnly(true); // We cannot handle manually specified values yet spinner->setTextInputMode(Spinner::FloatingPoint); // FloatingPoint, Integer, Hexadecimal, Octal spinner->setMinimumValue(-10.0f); spinner->setMaximumValue(10.0f); spinner->setStepSize(0.02f); spinner->setCurrentValue(5.2f); // Configure the character widgets Editbox* characterValue = static_cast<Editbox*>(winMgr.getWindow("CharacterValue")); characterValue->subscribeEvent(Editbox::EventTextChanged, Event::Subscriber(&DemoSample::onCharacterChanged, this)); Editbox* characterFormat = static_cast<Editbox*>(winMgr.getWindow("CharacterFormat")); characterFormat->subscribeEvent(Editbox::EventTextChanged, Event::Subscriber(&DemoSample::onCharacterChanged, this)); PushButton* characterFormatButton = static_cast<PushButton*>(winMgr.getWindow("CharacterFormatButton")); characterFormatButton->subscribeEvent(PushButton::EventClicked, Event::Subscriber(&DemoSample::onCharacterFormatClicked, this)); EventArgs e; onCharacterFormatClicked(e); // Initialize the localise values RefreshLocalisedValues(); } catch(Exception &e) { #if defined( __WIN32__ ) || defined( _WIN32 ) MessageBox(NULL, e.getMessage().c_str(), "Error initializing the demo", MB_OK | MB_ICONERROR | MB_TASKMODAL); #else std::cerr << "Error initializing the demo:" << e.getMessage().c_str() << "\n"; #endif } return true; } void cleanupSample(void) { CEGUI::FontManager::getSingleton().destroyAllFonts(); } private: ICU icu; // International Components for Unicode void RefreshLocalisedValues() { // Trigger changes in localised widgets to refresh their values accordingly using namespace CEGUI; WindowManager& winMgr = WindowManager::getSingleton(); EventArgs eventArgs; static_cast<RadioButton*>(winMgr.getWindow("RadioCAD"))->fireEvent(RadioButton::EventSelectStateChanged, eventArgs); static_cast<PushButton*>(winMgr.getWindow("NumericFormatButton"))->fireEvent(PushButton::EventClicked, eventArgs); static_cast<PushButton*>(winMgr.getWindow("DateTimeFormatButton"))->fireEvent(PushButton::EventClicked, eventArgs); static_cast<Spinner*>(winMgr.getWindow("Spinner"))->fireEvent(Spinner::EventValueChanged, eventArgs); } bool onLocaleChanged(const CEGUI::EventArgs& e) { using namespace CEGUI; WindowManager& winMgr = WindowManager::getSingleton(); String country = static_cast<Combobox*>(winMgr.getWindow("Countries"))->getText(); String language = static_cast<Combobox*>(winMgr.getWindow("Languages"))->getText(); if(icu.setLocale(language.c_str(), country.c_str())) RefreshLocalisedValues(); else MessageBox(NULL, ("Error with setLocale(" + language + ", " + country + ")").c_str(), "Error", MB_OK | MB_ICONERROR | MB_TASKMODAL); return true; } bool onLoadEveryISO(const CEGUI::EventArgs& e) { using namespace CEGUI; WindowManager& winMgr = WindowManager::getSingleton(); ListboxTextItem* listboxTextItem; int32_t count; // Change the label of the button PushButton* everyISO = static_cast<PushButton*>(winMgr.getWindow("EveryISO")); everyISO->setText("This will take a few seconds..."); // Display every ISO countries in a combobox Combobox* countries = static_cast<Combobox*>(winMgr.getWindow("Countries")); const char * const * listCountries = Locale::getISOCountries(); for(count = 0; listCountries[count]; count++) { listboxTextItem = new ListboxTextItem(listCountries[count]); listboxTextItem->setSelectionBrushImage("TaharezLook", "MultiListSelectionBrush"); countries->addItem(listboxTextItem); } countries->setText( Locale::getDefault().getCountry() ); // Display every ISO languages in a combobox Combobox* languages = static_cast<Combobox*>(winMgr.getWindow("Languages")); const char * const * listLanguages = Locale::getISOLanguages(); for(count = 0; listLanguages[count]; count++) { listboxTextItem = new ListboxTextItem(listLanguages[count]); listboxTextItem->setSelectionBrushImage("TaharezLook", "MultiListSelectionBrush"); languages->addItem(listboxTextItem); } languages->setText( Locale::getDefault().getLanguage() ); // Remove this button since it is no longer useful everyISO->setEnabled(false); everyISO->setVisible(false); return true; } bool onCurrencyChanged(const CEGUI::EventArgs& e) { using namespace CEGUI; WindowManager& winMgr = WindowManager::getSingleton(); EventArgs eventArgs; static_cast<RadioButton*>(winMgr.getWindow("RadioCAD"))->fireEvent(RadioButton::EventSelectStateChanged, eventArgs); return true; } bool onCurrencySelected(const CEGUI::EventArgs& e) { // Reformat the numeric value into a properly formatted currency using namespace CEGUI; WindowManager& winMgr = WindowManager::getSingleton(); // Set the currency CEGUI::uint id = static_cast<RadioButton*>(winMgr.getWindow("RadioCAD"))->getSelectedButtonInGroup()->getID(); switch(id) { case 1: icu.setCurrency("CAD"); break; case 2: icu.setCurrency("USD"); break; case 3: icu.setCurrency("EUR"); break; case 4: // Mauritania does not use a decimal division of units // and yet ICU still displays decimal units?? icu.setCurrency("MRO"); break; } CEGUI::String rawValue = static_cast<Editbox*>(winMgr.getWindow("CurrencyValue"))->getText(); double currency = atof(rawValue.c_str()); CEGUI::String formattedValue; if( icu.formatCurrency(currency, formattedValue) ) static_cast<Editbox*>(winMgr.getWindow("CurrencyFormattedValue"))->setText(formattedValue); return true; } bool onNumericChanged(const CEGUI::EventArgs& e) { using namespace CEGUI; WindowManager& winMgr = WindowManager::getSingleton(); EventArgs eventArgs; static_cast<PushButton*>(winMgr.getWindow("NumericFormatButton"))->fireEvent(PushButton::EventClicked, eventArgs); return true; } bool onNumericFormatClicked(const CEGUI::EventArgs& e) { using namespace CEGUI; WindowManager& winMgr = WindowManager::getSingleton(); String formattedText; if( icu.formatNumber(static_cast<Editbox*>(winMgr.getWindow("NumericValue"))->getText(), static_cast<Editbox*>(winMgr.getWindow("NumericFormat"))->getText(), formattedText) ) static_cast<Editbox*>(winMgr.getWindow("NumericFormattedValue"))->setText(formattedText); // Ordinal representation of an integer value double doubleValue = atof(static_cast<Editbox*>(winMgr.getWindow("NumericValue"))->getText().c_str()); if( icu.numberToOrdinal((int) doubleValue, formattedText) ) static_cast<Editbox*>(winMgr.getWindow("NumericFormattedOrdinal"))->setText(formattedText); // Textual representation of the numeric value // Note that this value must be raw, containing only digits and a decimal point // Since atof() is used to convert from a string to a double this numeric value is not localised if( icu.numberToText(doubleValue, formattedText) ) static_cast<Editbox*>(winMgr.getWindow("NumericFormattedText"))->setText(formattedText); return true; } bool onDateTimeChanged(const CEGUI::EventArgs& e) { using namespace CEGUI; WindowManager& winMgr = WindowManager::getSingleton(); EventArgs eventArgs; static_cast<PushButton*>(winMgr.getWindow("DateTimeFormatButton"))->fireEvent(PushButton::EventClicked, eventArgs); return true; } bool onDateTimeFormatClicked(const CEGUI::EventArgs& e) { // Format the date and time according to their specified values and formats // In theory a format can include both the date and the time: yyyy/MM/dd HH:mm:ss // However in practice the resulting time is not accurate (within 1 minute 47 seconds) using namespace CEGUI; WindowManager& winMgr = WindowManager::getSingleton(); UDate localDate, localTime, gmtDate, gmtTime, gmtDateTime; if(icu.CeguiStringToDateTime( static_cast<Editbox*>(winMgr.getWindow("DateValue"))->getText(), "yyyy/MM/dd", // Internal format localDate) && icu.CeguiStringToDateTime( static_cast<Editbox*>(winMgr.getWindow("TimeValue"))->getText(), "HH:mm:ss", // Internal format localTime) ) { String formattedDate, formattedTime; if(icu.formatDateTime( localDate, static_cast<Editbox*>(winMgr.getWindow("DateFormat"))->getText(), formattedDate) && icu.formatDateTime( localTime, static_cast<Editbox*>(winMgr.getWindow("TimeFormat"))->getText(), formattedTime) ) static_cast<Editbox*>(winMgr.getWindow("LocalDateTimeFormattedValue"))->setText(formattedDate + " " + formattedTime); // GMT time if( icu.CeguiStringToDateTime(static_cast<Editbox*>(winMgr.getWindow("LocalDateTimeFormattedValue"))->getText(), "yyyy/MM/dd HH:mm:ss", gmtDateTime) && icu.localToGmt(localDate, localTime, gmtDate, gmtTime) && icu.formatDateTime(gmtDate, "yyyy/MM/dd", formattedDate) && icu.formatDateTime(gmtTime, "HH:mm:ss", formattedTime) ) static_cast<Editbox*>(winMgr.getWindow("GmtDateTimeFormattedValue"))->setText(formattedDate + " " + formattedTime); } return true; } bool onSpinnerValueChanged(const CEGUI::EventArgs& e) { // Reformat the displayed value into a locale appropriate format using namespace CEGUI; WindowManager& winMgr = WindowManager::getSingleton(); Spinner* spinner = static_cast<Spinner*>(winMgr.getWindow("Spinner")); String formattedValue; if( icu.formatNumber(spinner->getCurrentValue(), "#0.00", formattedValue) ) { // Disable the Editbox events, especially the EventTextChanged that // triggers Spinner::handleEditTextChange, which attempts to convert // the textual value into a non-localised numeric value Editbox* editbox = static_cast<Editbox*>(winMgr.getWindow(spinner->getName() + "__auto_editbox__")); bool muted = editbox->isMuted(); editbox->setMutedState(true); spinner->setText(formattedValue); editbox->setMutedState(muted); } return true; } bool onCharacterChanged(const CEGUI::EventArgs& e) { using namespace CEGUI; WindowManager& winMgr = WindowManager::getSingleton(); EventArgs eventArgs; static_cast<PushButton*>(winMgr.getWindow("CharacterFormatButton"))->fireEvent(PushButton::EventClicked, eventArgs); return true; } bool onCharacterFormatClicked(const CEGUI::EventArgs& e) { using namespace CEGUI; WindowManager& winMgr = WindowManager::getSingleton(); String formattedText; if( icu.formatText(static_cast<Editbox*>(winMgr.getWindow("CharacterValue"))->getText(), static_cast<Editbox*>(winMgr.getWindow("CharacterFormat"))->getText(), "*", formattedText) ) static_cast<Editbox*>(winMgr.getWindow("CharacterFormattedValue"))->setText(formattedText); return true; } }; #endif // _FormattedData_h_
main.cpp
#if defined( __WIN32__ ) || defined( _WIN32 ) #define WIN32_LEAN_AND_MEAN #define NOMINMAX #include "windows.h" #endif #include "FormattedNumericData.h" #if defined( __WIN32__ ) || defined( _WIN32 ) int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,int nCmdShow) #else int main(int argc, char *argv[]) #endif { DemoSample app; return app.run(); }
FormattedData.layout
<?xml version="1.0" encoding="UTF-8"?> <GUILayout > <Window Type="DefaultWindow" Name="Root" > <Property Name="InheritsAlpha" Value="False" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0,0},{0,0},{1,0},{1,0}}" /> <Window Type="TaharezLook/FrameWindow" Name="FrameWindow" > <Property Name="TitlebarFont" Value="Commonwealth-10" /> <Property Name="CaptionColour" Value="00FFFFFF" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="TitlebarEnabled" Value="True" /> <Property Name="UnifiedAreaRect" Value="{{0.07125,0},{0.013335,0},{0.910001,0},{0.873733,0}}" /> <Property Name="MouseCursorImage" Value="set:TaharezLook image:MouseTarget" /> <Window Type="TaharezLook/Spinner" Name="Spinner" > <Property Name="Text" Value="10.00" /> <Property Name="StepSize" Value="1" /> <Property Name="CurrentValue" Value="10" /> <Property Name="MaximumValue" Value="32767" /> <Property Name="MinimumValue" Value="-32768" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.8473,0},{0.731682,0},{0.951964,0},{0.790123,0}}" /> </Window> <Window Type="TaharezLook/StaticText" Name="SpinnerLabel" > <Property Name="Text" Value="Localised Spinner widget with 2 decimals:" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.395457,0},{0.731682,0},{0.836346,0},{0.790123,0}}" /> </Window> <Window Type="TaharezLook/Editbox" Name="CurrencyFormattedValue" > <Property Name="ReadOnly" Value="True" /> <Property Name="MaxTextLength" Value="1073741823" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.616765,0},{0.203821,0},{0.954642,0},{0.262262,0}}" /> </Window> <Window Type="TaharezLook/RadioButton" Name="RadioCAD" > <Property Name="Text" Value="Canadian (CAD)" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.430655,0},{0.158378,0},{0.614153,0},{0.187144,0}}" /> </Window> <Window Type="TaharezLook/RadioButton" Name="RadioMRO" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="Text" Value="Mauritania (MRO)" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.430655,0},{0.26902,0},{0.614153,0},{0.297787,0}}" /> </Window> <Window Type="TaharezLook/RadioButton" Name="RadioUSD" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="Text" Value="US (USD)" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.430655,0},{0.195183,0},{0.5605,0},{0.22395,0}}" /> </Window> <Window Type="TaharezLook/RadioButton" Name="RadioEUR" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="Text" Value="Euro (EUR)" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.430655,0},{0.232215,0},{0.5605,0},{0.260983,0}}" /> </Window> <Window Type="TaharezLook/StaticText" Name="CountriesLabel" > <Property Name="Text" Value="Countries:" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.022504,0},{0.069049,0},{0.132414,0},{0.117804,0}}" /> </Window> <Window Type="TaharezLook/StaticText" Name="LanguagesLabel" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="Text" Value="Languages:" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.268405,0},{0.069049,0},{0.385766,0},{0.117804,0}}" /> </Window> <Window Type="TaharezLook/Combobox" Name="Countries" > <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.142027,0},{0.069049,0},{0.245976,0},{0.902039,0}}" /> <Property Name="MaxEditTextLength" Value="1073741823" /> </Window> <Window Type="TaharezLook/Combobox" Name="Languages" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.395379,0},{0.069049,0},{0.499329,0},{0.90204,0}}" /> <Property Name="MaxEditTextLength" Value="1073741823" /> </Window> <Window Type="TaharezLook/StaticText" Name="Separator1" > <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.013562,0},{0.141452,0},{0.995305,0},{0.150048,0}}" /> </Window> <Window Type="TaharezLook/StaticText" Name="Separator2" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.013562,0},{0.309408,0},{0.995305,0},{0.318004,0}}" /> </Window> <Window Type="TaharezLook/StaticText" Name="Separator3" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.013562,0},{0.553045,0},{0.995305,0},{0.561642,0}}" /> </Window> <Window Type="TaharezLook/StaticText" Name="Separator5" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.007601,0},{0.814139,0},{0.989344,0},{0.822736,0}}" /> </Window> <Window Type="TaharezLook/StaticText" Name="NumericFormatLabel" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="Text" Value="Format:" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.036292,0},{0.403136,0},{0.141946,0},{0.461576,0}}" /> </Window> <Window Type="TaharezLook/Editbox" Name="NumericFormat" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="Text" Value="#,##0.03" /> <Property Name="MaxTextLength" Value="1073741823" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.150298,0},{0.403136,0},{0.421111,0},{0.461576,0}}" /> </Window> <Window Type="TaharezLook/Button" Name="NumericFormatButton" > <Property Name="Text" Value="Apply" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.473919,0},{0.370638,0},{0.603204,0},{0.429079,0}}" /> <Property Name="MouseCursorImage" Value="set:TaharezLook image:MouseArrow" /> </Window> <Window Type="TaharezLook/Editbox" Name="NumericFormattedValue" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="ReadOnly" Value="True" /> <Property Name="MaxTextLength" Value="1073741823" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.616765,0},{0.339418,0},{0.954642,0},{0.397859,0}}" /> </Window> <Window Type="TaharezLook/StaticText" Name="DateFormatLabel" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="Text" Value="Format:" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.036292,0},{0.63711,0},{0.141946,0},{0.695551,0}}" /> </Window> <Window Type="TaharezLook/Editbox" Name="DateFormat" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="Text" Value="yyyy/MM/dd" /> <Property Name="MaxTextLength" Value="1073741823" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.150298,0},{0.63711,0},{0.269099,0},{0.695551,0}}" /> </Window> <Window Type="TaharezLook/StaticText" Name="DateValueLabel" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="Text" Value="Date:" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.036292,0},{0.574987,0},{0.141946,0},{0.633428,0}}" /> </Window> <Window Type="TaharezLook/Editbox" Name="DateValue" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="Text" Value="2006/05/14" /> <Property Name="MaxTextLength" Value="1073741823" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.150298,0},{0.574987,0},{0.267608,0},{0.633428,0}}" /> </Window> <Window Type="TaharezLook/Button" Name="DateTimeFormatButton" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="Text" Value="Apply" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.473919,0},{0.610743,0},{0.603205,0},{0.669184,0}}" /> <Property Name="MouseCursorImage" Value="set:TaharezLook image:MouseArrow" /> </Window> <Window Type="TaharezLook/Editbox" Name="LocalDateTimeFormattedValue" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="ReadOnly" Value="True" /> <Property Name="MaxTextLength" Value="1073741823" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.724067,0},{0.578862,0},{0.954642,0},{0.637303,0}}" /> </Window> <Window Type="TaharezLook/Editbox" Name="TimeValue" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="Text" Value="12:00:01" /> <Property Name="MaxTextLength" Value="1073741823" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.351492,0},{0.574987,0},{0.441976,0},{0.633428,0}}" /> </Window> <Window Type="TaharezLook/StaticText" Name="TimeValueLabel" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="Text" Value="Time:" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.280703,0},{0.574987,0},{0.347609,0},{0.633428,0}}" /> </Window> <Window Type="TaharezLook/Editbox" Name="TimeFormat" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="Text" Value="HH:mm:ss" /> <Property Name="MaxTextLength" Value="1073741823" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.281446,0},{0.63711,0},{0.441976,0},{0.695551,0}}" /> </Window> <Window Type="TaharezLook/StaticText" Name="NumericValueLabel" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="Text" Value="Numeric:" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.036292,0},{0.339418,0},{0.141946,0},{0.397857,0}}" /> </Window> <Window Type="TaharezLook/Editbox" Name="NumericValue" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="Text" Value="123456.78" /> <Property Name="MaxTextLength" Value="1073741823" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.150298,0},{0.339418,0},{0.421111,0},{0.397858,0}}" /> </Window> <Window Type="TaharezLook/StaticText" Name="CurrencyValueLabel" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="Text" Value="Currency:" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.036292,0},{0.203821,0},{0.141946,0},{0.26226,0}}" /> </Window> <Window Type="TaharezLook/Editbox" Name="CurrencyValue" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="Text" Value="123456.78" /> <Property Name="MaxTextLength" Value="1073741823" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.150298,0},{0.203821,0},{0.421111,0},{0.262262,0}}" /> </Window> <Window Type="TaharezLook/StaticText" Name="Separator4" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.013562,0},{0.702202,0},{0.995305,0},{0.710798,0}}" /> </Window> <Window Type="TaharezLook/Button" Name="EveryISO" > <Property Name="Text" Value="Load every country and languages" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.559611,0},{0.069049,0},{0.94523,0},{0.12749,0}}" /> <Property Name="MouseCursorImage" Value="set:TaharezLook image:MouseArrow" /> </Window> <Window Type="TaharezLook/Editbox" Name="NumericFormattedText" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="ReadOnly" Value="True" /> <Property Name="MaxTextLength" Value="1073741823" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.153278,0},{0.482989,0},{0.954642,0},{0.54143,0}}" /> </Window> <Window Type="TaharezLook/Editbox" Name="CharacterFormattedValue" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="ReadOnly" Value="True" /> <Property Name="MaxTextLength" Value="1073741823" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.616765,0},{0.883872,0},{0.954642,0},{0.942313,0}}" /> </Window> <Window Type="TaharezLook/Editbox" Name="CharacterFormat" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="Text" Value="000 000 000" /> <Property Name="MaxTextLength" Value="1073741823" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.150298,0},{0.908716,0},{0.421111,0},{0.967156,0}}" /> </Window> <Window Type="TaharezLook/Button" Name="CharacterFormatButton" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="Text" Value="Apply" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.473919,0},{0.883872,0},{0.603205,0},{0.942313,0}}" /> <Property Name="MouseCursorImage" Value="set:TaharezLook image:MouseArrow" /> </Window> <Window Type="TaharezLook/Editbox" Name="CharacterValue" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="Text" Value="123456" /> <Property Name="MaxTextLength" Value="1073741823" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.150298,0},{0.844998,0},{0.421111,0},{0.903438,0}}" /> </Window> <Window Type="TaharezLook/StaticText" Name="LocalDateTimeFormattedLabel" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="Text" Value="Local:" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.641358,0},{0.578862,0},{0.718697,0},{0.637302,0}}" /> </Window> <Window Type="TaharezLook/StaticText" Name="GmtDateTimeFormattedLabel" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="Text" Value="GMT:" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.641358,0},{0.63711,0},{0.718697,0},{0.69555,0}}" /> </Window> <Window Type="TaharezLook/Editbox" Name="GmtDateTimeFormattedValue" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="ReadOnly" Value="True" /> <Property Name="MaxTextLength" Value="1073741823" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.725558,0},{0.63711,0},{0.954642,0},{0.695551,0}}" /> </Window> <Window Type="TaharezLook/StaticText" Name="NumericValueLabel1" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="Text" Value="Numeric:" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.036292,0},{0.844998,0},{0.141946,0},{0.903437,0}}" /> </Window> <Window Type="TaharezLook/StaticText" Name="NumericFormatLabel1" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="Text" Value="Format:" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.036292,0},{0.908716,0},{0.141946,0},{0.967156,0}}" /> </Window> <Window Type="TaharezLook/Editbox" Name="NumericFormattedOrdinal" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="ReadOnly" Value="True" /> <Property Name="MaxTextLength" Value="1073741823" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.616765,0},{0.403136,0},{0.954642,0},{0.461577,0}}" /> </Window> </Window> </Window> </GUILayout>