Gwen::Point DirectX9::MeasureText( Gwen::Font* pFont, const Gwen::UnicodeString & text ) { // If the font doesn't exist, or the font size should be changed if ( !pFont->data || fabs( pFont->realsize - pFont->size * Scale() ) > 2 ) { FreeFont( pFont ); LoadFont( pFont ); } FontData* pFontData = ( FontData* ) pFont->data; Gwen::Point size; if ( text.empty() ) { RECT rct = {0, 0, 0, 0}; pFontData->pFont->DrawTextW( NULL, L"W", -1, &rct, DT_CALCRECT, 0 ); return Gwen::Point( 0, rct.bottom ); } RECT rct = {0, 0, 0, 0}; pFontData->pFont->DrawTextW( NULL, text.c_str(), -1, &rct, DT_CALCRECT | DT_LEFT | DT_TOP | DT_SINGLELINE, 0 ); for ( int i = text.length() - 1; i >= 0 && text[i] == L' '; i-- ) { rct.right += pFontData->iSpaceWidth; } return Gwen::Point( rct.right / Scale(), rct.bottom / Scale() ); }
bool TextBoxNumeric::IsTextAllowed( const Gwen::UnicodeString & str, int iPos ) { const UnicodeString & strString = GetText().GetUnicode(); if ( str.length() == 0 ) { return true; } for ( size_t i = 0; i < str.length(); i++ ) { if ( str[i] == L'-' ) { // Has to be at the start if ( i != 0 || iPos != 0 ) { return false; } // Can only be one if ( std::count( strString.begin(), strString.end(), L'-' ) > 0 ) { return false; } continue; } if ( str[i] == L'0' ) { continue; } if ( str[i] == L'1' ) { continue; } if ( str[i] == L'2' ) { continue; } if ( str[i] == L'3' ) { continue; } if ( str[i] == L'4' ) { continue; } if ( str[i] == L'5' ) { continue; } if ( str[i] == L'6' ) { continue; } if ( str[i] == L'7' ) { continue; } if ( str[i] == L'8' ) { continue; } if ( str[i] == L'9' ) { continue; } if ( str[i] == L'.' ) { // Already a fullstop if ( std::count( strString.begin(), strString.end(), L'.' ) > 0 ) { return false; } continue; } return false; } return true; }
float dumpRecursive(CProfileIterator* profileIterator, Gwen::Controls::TreeNode* parentNode) { profileIterator->First(); if (profileIterator->Is_Done()) return 0.f; float accumulated_time=0,parent_time = profileIterator->Is_Root() ? CProfileManager::Get_Time_Since_Reset() : profileIterator->Get_Current_Parent_Total_Time(); int i; int frames_since_reset = CProfileManager::Get_Frame_Count_Since_Reset(); //printf("Profiling: %s (total running time: %.3f ms) ---\n", profileIterator->Get_Current_Parent_Name(), parent_time ); float totalTime = 0.f; int numChildren = 0; Gwen::UnicodeString txt; std::vector<Gwen::Controls::TreeNode*> nodes; for (i = 0; !profileIterator->Is_Done(); i++,profileIterator->Next()) { numChildren++; float current_total_time = profileIterator->Get_Current_Total_Time(); accumulated_time += current_total_time; double fraction = parent_time > SIMD_EPSILON ? (current_total_time / parent_time) * 100 : 0.f; Gwen::String name(profileIterator->Get_Current_Name()); Gwen::UnicodeString uname = Gwen::Utility::StringToUnicode(name); txt = Gwen::Utility::Format(L"%s (%.2f %%) :: %.3f ms / frame (%d calls)",uname.c_str(), fraction,(current_total_time / (double)frames_since_reset),profileIterator->Get_Current_Total_Calls()); Gwen::Controls::TreeNode* childNode = (Gwen::Controls::TreeNode*)profileIterator->Get_Current_UserPointer(); if (!childNode) { childNode = parentNode->AddNode(L""); profileIterator->Set_Current_UserPointer(childNode); } childNode->SetText(txt); nodes.push_back(childNode); totalTime += current_total_time; //recurse into children } for (i=0;i<numChildren;i++) { profileIterator->Enter_Child(i); Gwen::Controls::TreeNode* curNode = nodes[i]; dumpRecursive(profileIterator, curNode); profileIterator->Enter_Parent(); } return accumulated_time; }
void Gwen::Utility::Strings::Strip( Gwen::UnicodeString& str, const Gwen::UnicodeString& chars ) { Gwen::UnicodeString Source = str; str = L""; for ( int i =0; i<Source.length(); i++ ) { if ( chars.find( Source[i] ) != Gwen::UnicodeString::npos ) continue; str += Source[i]; } }
Gwen::Point Base::MeasureText( Gwen::Font* pFont, const Gwen::UnicodeString & text ) { Gwen::Point p; p.x = pFont->size * Scale() * ( float ) text.length() * 0.4; p.y = pFont->size * Scale(); return p; }
void GDIPlus::RenderText( gwen::Font* pFont, gwen::Point pos, const gwen::UnicodeString & text ) { Translate( pos.x, pos.y ); // If the font doesn't exist, or the font size should be changed if ( !pFont->data || fabs( pFont->realsize - pFont->size * Scale() ) > 2 ) { FreeFont( pFont ); LoadFont( pFont ); } Gdiplus::StringFormat strFormat( Gdiplus::StringFormat::GenericDefault() ); Gdiplus::SolidBrush solidBrush( m_Colour ); Gdiplus::RectF r( pos.x, pos.y, 1000, 1000 ); Gdiplus::Font* pGDIFont = ( Gdiplus::Font* ) pFont->data; graphics->DrawString( text.c_str(), text.length() + 1, pGDIFont, r, &strFormat, &solidBrush ); }
void OpenGL_DebugFont::RenderText( Gwen::Font* pFont, Gwen::Point pos, const Gwen::UnicodeString& text ) { float fSize = pFont->size * Scale(); if ( !text.length() ) return; Gwen::String converted_string = Gwen::Utility::UnicodeToString( text ); float yOffset=0.0f; for ( int i=0; i<text.length(); i++ ) { wchar_t chr = text[i]; char ch = converted_string[i]; float curSpacing = sGwenDebugFontSpacing[ch] * m_fLetterSpacing * fSize * m_fFontScale[0]; Gwen::Rect r( pos.x + yOffset, pos.y-fSize*0.2f, (fSize * m_fFontScale[0]), fSize * m_fFontScale[1] ); if ( m_pFontTexture ) { float uv_texcoords[8]={0.,0.,1.,1.}; if ( ch >= 0 ) { float cx= (ch%16)/16.0; float cy= (ch/16)/16.0; uv_texcoords[0] = cx; uv_texcoords[1] = cy; uv_texcoords[4] = float(cx+1.0f/16.0f); uv_texcoords[5] = float(cy+1.0f/16.0f); } DrawTexturedRect( m_pFontTexture, r, uv_texcoords[0], uv_texcoords[5], uv_texcoords[4], uv_texcoords[1] ); yOffset+=curSpacing; } else { DrawFilledRect( r ); yOffset+=curSpacing; } } }
Gwen::Point Chowdren::MeasureText( Gwen::Font* pFont, const Gwen::UnicodeString & text ) { FTSimpleLayout layout; layout.SetLineLength(10000); layout.SetFont(get_font(pFont->size)); FTBBox bbox = layout.BBox(text.c_str()); FTPoint size = bbox.Upper() - bbox.Lower(); return Gwen::Point((int)ceil(size.X()), (int)ceil(size.Y())); }
bool Gwen::Platform::SetClipboardText( const Gwen::UnicodeString& str ) { if ( !OpenClipboard( NULL ) ) return false; EmptyClipboard(); // Create a buffer to hold the string size_t iDataSize = (str.length()+1) * sizeof(wchar_t); HGLOBAL clipbuffer = GlobalAlloc( GMEM_DDESHARE, iDataSize ); // Copy the string into the buffer wchar_t* buffer = (wchar_t*) GlobalLock( clipbuffer ); wcscpy( buffer, str.c_str() ); GlobalUnlock(clipbuffer); // Place it on the clipboard SetClipboardData( CF_UNICODETEXT, clipbuffer ); CloseClipboard(); return true; }
void SplitWords(const Gwen::UnicodeString &s, wchar_t delim, std::vector<Gwen::UnicodeString> &elems) { Gwen::UnicodeString str; for ( int i=0; i<s.length(); i++ ) { if ( s[i] == L'\n' ) { if ( !str.empty() ) elems.push_back( str ); elems.push_back( L"\n" ); str.clear(); continue; } if ( s[i] == L' ' ) { str += s[i]; elems.push_back( str ); str.clear(); continue; } str += s[i]; } if ( !str.empty() ) elems.push_back( str ); }
void Base::RenderText( Gwen::Font* pFont, Gwen::Point pos, const Gwen::UnicodeString & text ) { // std::cout << "tryinta render sum txt '" << Gwen::Utility::UnicodeToString(text) <<"'\n"; float fSize = pFont->size * Scale(); SetDrawColor(Gwen::Color(0,0,0,255)); for ( float i = 0; i < text.length(); i++ ) { wchar_t chr = text[i]; if ( chr == ' ' ) { continue; } Gwen::Rect r( pos.x + i * fSize * 0.4, pos.y, fSize * 0.4 - 1, fSize ); /* This isn't important, it's just me messing around changing the shape of the rect based on the letter.. just for fun. */ if ( chr == 'l' || chr == 'i' || chr == '!' || chr == 't' ) { r.w = 1; } else if ( chr >= 'a' && chr <= 'z' ) { r.y += fSize * 0.5f; r.h -= fSize * 0.4f; } else if ( chr == '.' || chr == ',' ) { r.x += 2; r.y += r.h - 2; r.w = 2; r.h = 2; } else if ( chr == '\'' || chr == '`' || chr == '"' ) { r.x += 3; r.w = 2; r.h = 2; } if ( chr == 'o' || chr == 'O' || chr == '0' ) { DrawLinedRect( r ); } else { // std::cout << "drawing ur flld rct: " <<r.x<<','<<r.y<<','<<r.w<<','<<r.h<<"\n"; DrawFilledRect( r ); } } }
void RichLabel::SplitLabel( const Gwen::UnicodeString & text, Gwen::Font* pFont, const DividedText & txt, int & x, int & y, int & lineheight ) { Gwen::Utility::Strings::UnicodeList lst; Gwen::Utility::Strings::Split( text, U" ", lst, true ); if ( lst.size() == 0 ) { return; } int iSpaceLeft = Width() - x; // Does the whole word fit in? { Gwen::Point StringSize = GetSkin()->GetRender()->MeasureText( pFont, text ); if ( iSpaceLeft > StringSize.x ) { return CreateLabel( text, txt, x, y, lineheight, true ); } } // If the first word is bigger than the line, just give up. { Gwen::Point WordSize = GetSkin()->GetRender()->MeasureText( pFont, lst[0] ); if ( WordSize.x >= iSpaceLeft ) { CreateLabel( lst[0], txt, x, y, lineheight, true ); if ( lst[0].size() >= text.size() ) { return; } Gwen::UnicodeString LeftOver = text.substr( lst[0].size() + 1 ); return SplitLabel( LeftOver, pFont, txt, x, y, lineheight ); } } Gwen::UnicodeString strNewString = U""; for ( size_t i = 0; i < lst.size(); i++ ) { Gwen::Point WordSize = GetSkin()->GetRender()->MeasureText( pFont, strNewString + lst[i] ); if ( WordSize.x > iSpaceLeft ) { CreateLabel( strNewString, txt, x, y, lineheight, true ); x = 0; y += lineheight; break;; } strNewString += lst[i]; } if ( strNewString.size() >= text.size() ) return; Gwen::UnicodeString LeftOver = text.substr( strNewString.size() + 1 ); return SplitLabel( LeftOver, pFont, txt, x, y, lineheight ); }
void DirectX9::RenderText( Gwen::Font* pFont, Gwen::Point pos, const Gwen::UnicodeString & text ) { Flush(); // If the font doesn't exist, or the font size should be changed if ( !pFont->data || fabs( pFont->realsize - pFont->size * Scale() ) > 2 ) { FreeFont( pFont ); LoadFont( pFont ); } FontData* pFontData = ( FontData* ) pFont->data; Translate( pos.x, pos.y ); RECT ClipRect = { pos.x, pos.y, 0, 0 }; pFontData->pFont->DrawTextW( NULL, text.c_str(), -1, &ClipRect, DT_LEFT | DT_TOP | DT_NOCLIP | DT_SINGLELINE, m_Color ); }
void Chowdren::RenderText( Gwen::Font* pFont, Gwen::Point pos, const Gwen::UnicodeString & text ) { if (!init_font()) return; FTTextureFont* font = get_font(pFont->size); if (font) { Translate(pos.x, pos.y); FTTextureFont::color = m_Color; FTSimpleLayout layout; layout.SetLineLength(10000); layout.SetFont(font); layout.Render(text.c_str(), -1, FTPoint(pos.x, pos.y + font->Ascender())); } }
void Base::RenderText( Gwen::Font* pFont, Gwen::Point pos, const Gwen::UnicodeString& text ) { float fSize = pFont->size * Scale(); for ( float i=0; i<text.length(); i++ ) { wchar_t chr = text[i]; if ( chr == ' ' ) continue; Gwen::Rect r( pos.x + i * fSize * 0.4, pos.y, fSize * 0.4 -1, fSize ); /* This isn't important, it's just me messing around changing the shape of the rect based on the letter.. just for fun. */ if ( chr == 'l' || chr == 'i' || chr == '!' || chr == 't' ) { r.w = 1; } else if ( chr >= 'a' && chr <= 'z' ) { r.y += fSize * 0.5f; r.h -= fSize * 0.4f; } else if ( chr == '.' || chr == ',' ) { r.x += 2; r.y += r.h - 2; r.w = 2; r.h = 2; } else if ( chr == '\'' || chr == '`' || chr == '"' ) { r.x += 3; r.w = 2; r.h = 2; } if ( chr == 'o' || chr == 'O' || chr == '0' ) DrawLinedRect( r ); else DrawFilledRect( r ); } }
gwen::Point GDIPlus::MeasureText( gwen::Font* pFont, const gwen::UnicodeString & text ) { gwen::Point p( 1, 1 ); if ( !pFont->data || fabs( pFont->realsize - pFont->size * Scale() ) > 2 ) { FreeFont( pFont ); LoadFont( pFont ); } Gdiplus::StringFormat strFormat( Gdiplus::StringFormat::GenericDefault() ); strFormat.SetFormatFlags( Gdiplus::StringFormatFlagsMeasureTrailingSpaces | strFormat.GetFormatFlags() ); Gdiplus::SizeF size; Gdiplus::Graphics g( m_HWND ); Gdiplus::Font* pGDIFont = ( Gdiplus::Font* ) pFont->data; g.MeasureString( text.c_str(), -1, pGDIFont, Gdiplus::SizeF( 10000, 10000 ), &strFormat, &size ); return gwen::Point( size.Width + 1, size.Height + 1 ); }
Gwen::Point OpenGL_DebugFont::MeasureText( Gwen::Font* pFont, const Gwen::UnicodeString& text ) { Gwen::Point p; float fSize = pFont->size * Scale(); Gwen::String converted_string = Gwen::Utility::UnicodeToString( text ); float spacing = 0.0f; for ( int i=0; i<text.length(); i++ ) { char ch = converted_string[i]; spacing += sGwenDebugFontSpacing[ch]; } p.x = spacing*m_fLetterSpacing*fSize * m_fFontScale[0]; p.y = pFont->size * Scale() * m_fFontScale[1]; return p; }
void Text::SplitWords(const Gwen::UnicodeString &s, std::vector<Gwen::UnicodeString> & elems ) { Gwen::UnicodeString str; int w = GetParent()->Width() - GetParent()->GetPadding().left-GetParent()->GetPadding().right; for ( int i=0; i<(int)s.length(); i++ ) { if ( s[i] == L'\n' ) { if ( !str.empty() ) { elems.push_back( str ); } elems.push_back( L"\n" ); str.clear(); continue; } if ( s[i] == L' ' ) { str += s[i]; elems.push_back( str ); str.clear(); continue; } str += s[i]; //if adding character makes the word bigger than the textbox size Gwen::Point p = GetSkin()->GetRender()->MeasureText( GetFont(), str ); if ( p.x > w ) { int addSum = GetPadding().left+GetPadding().right; //split words str.pop_back(); elems.push_back( str ); str.clear(); --i; continue; } } if ( !str.empty() ) { elems.push_back( str ); } }
void TextBox::InsertText( const Gwen::UnicodeString& strInsert ) { // TODO: Make sure fits (implement maxlength) if ( HasSelection() ) { EraseSelection(); } if ( m_iCursorPos > TextLength() ) m_iCursorPos = TextLength(); if ( !IsTextAllowed( strInsert, m_iCursorPos ) ) return; UnicodeString str = GetText(); str.insert( m_iCursorPos, strInsert ); SetText( str ); m_iCursorPos += (int) strInsert.size(); m_iCursorEnd = m_iCursorPos; RefreshCursorBounds(); }
void Gwen::Utility::Strings::Split( const Gwen::UnicodeString& str, const Gwen::UnicodeString& seperator, Strings::UnicodeList& outbits, bool bLeave ) { int iOffset = 0; int iLength = str.length(); int iSepLen = seperator.length(); size_t i = str.find( seperator, 0 ); while ( i != std::wstring::npos ) { outbits.push_back( str.substr( iOffset, i-iOffset ) ); iOffset = i + iSepLen; i = str.find( seperator, iOffset ); if ( bLeave ) iOffset -= iSepLen; } outbits.push_back( str.substr( iOffset, iLength-iOffset ) ); }
void Text::RefreshSizeWrap() { RemoveAllChildren(); for ( TextLines::iterator it = m_Lines.begin(); it != m_Lines.end(); ++it ) { delete *it; } m_Lines.clear(); std::vector<Gwen::UnicodeString> words; SplitWords( GetText().GetUnicode(), words ); // Adding a bullshit word to the end simplifies the code below // which is anything but simple. words.push_back( L"" ); if ( !GetFont() ) { Debug::AssertCheck( 0, "Text::RefreshSize() - No Font!!\n" ); return; } Point pFontSize = GetSkin()->GetRender()->MeasureText( GetFont(), L" " ); int w = GetParent()->Width() - GetParent()->GetPadding().left-GetParent()->GetPadding().right; int x = 0, y = 0; Gwen::UnicodeString strLine; for ( std::vector<Gwen::UnicodeString>::iterator it = words.begin(); it != words.end(); ++it ) { bool bFinishLine = false; bool bWrapped = false; // If this word is a newline - make a newline (we still add it to the text) if ( ( *it ).c_str() [0] == L'\n' ) { bFinishLine = true; } // Does adding this word drive us over the width? { strLine += ( *it ); Gwen::Point p = GetSkin()->GetRender()->MeasureText( GetFont(), strLine ); if ( p.x > w ) { bFinishLine = true; bWrapped = true; } } // If this is the last word then finish the line if ( --words.end() == it ) { bFinishLine = true; } if ( bFinishLine ) { Text* t = new Text( this ); t->SetFont( GetFont() ); t->SetTextColor( m_Color ); if(bWrapped) { t->SetString( strLine.substr( 0, strLine.length() - (*it).length() ) ); // newline should start with the word that was too big strLine = *it; } else { t->SetString( strLine.substr( 0, strLine.length()) ); //new line is empty strLine.clear(); } t->RefreshSize(); t->SetPos( x, y ); m_Lines.push_back( t ); // newline should start with the word that was too big // strLine = *it; // Position the newline y += pFontSize.y; x = 0; //if ( strLine[0] == L' ' ) x -= pFontSize.x; } } // Size to children height and parent width Point childsize = ChildrenSize(); { SetSize( w, childsize.y ); } // Align the text within the parent int y_offset = 0; for ( TextLines::iterator it = m_Lines.begin(); it != m_Lines.end(); ++it ) { Text* text = *it; const Rect & bounds = GetInnerBounds(); int x = 0; int y = 0; if ( m_iAlign & Pos::Left ) { x = bounds.x; } if ( m_iAlign & Pos::Right ) { x = bounds.x + ( bounds.w - text->Width() ); } if ( m_iAlign & Pos::CenterH ) { x = bounds.x + ( bounds.w - text->Width() ) * 0.5; } if ( m_iAlign & Pos::Top ) { y = bounds.y; } if ( m_iAlign & Pos::Bottom ) { y = bounds.y + ( bounds.h - childsize.y ); } if ( m_iAlign & Pos::CenterV ) { y = bounds.y + ( bounds.h - childsize.y ) * 0.5; } text->SetPos( x, y + y_offset ); y_offset += text->Height(); } InvalidateParent(); Invalidate(); }
void Text::RefreshSizeWrap() { RemoveAllChildren(); for( TextLines::const_iterator it = m_Lines.begin(), end = m_Lines.end(); it != end; ++it ) { Text *t = *it; delete t, t = 0; } m_Lines.clear(); std::vector<Gwen::UnicodeString> words; SplitWords( GetText().GetUnicode(), L' ', words ); // Adding a bullshit word to the end simplifies the code below // which is anything but simple. words.push_back( L"" ); if ( !GetFont() ) { Debug::AssertCheck( 0, "Text::RefreshSize() - No Font!!\n" ); return; } Point pFontSize = GetSkin()->GetRender()->MeasureText( GetFont(), L" " ); int w = GetParent()->Width(); int x = 0, y = 0; Gwen::UnicodeString strLine; std::vector<Gwen::UnicodeString>::iterator it = words.begin(); for ( it; it != words.end(); ++it ) { bool bFinishLine = false; bool bWrapped = false; // If this word is a newline - make a newline (we still add it to the text) if ( (*it).c_str()[0] == L'\n' ) bFinishLine = true; // Does adding this word drive us over the width? { strLine += (*it); Gwen::Point p = GetSkin()->GetRender()->MeasureText( GetFont(), strLine ); if ( p.x > Width() ) { bFinishLine = true; bWrapped = true; } } // If this is the last word then finish the line if ( --words.end() == it ) { bFinishLine = true; } if ( bFinishLine ) { Text* t = new Text( this ); t->SetFont( GetFont() ); t->SetString( strLine.substr( 0, strLine.length() - (*it).length() ) ); t->RefreshSize(); t->SetPos( x, y ); m_Lines.push_back( t ); // newline should start with the word that was too big strLine = *it; // Position the newline y += pFontSize.y; x = 0; //if ( strLine[0] == L' ' ) x -= pFontSize.x; } } // Size to children height and parent width { Point childsize = ChildrenSize(); SetSize( w, childsize.y ); } InvalidateParent(); Invalidate(); }
void UpdateText(CProfileIterator* profileIterator, bool idle) { static bool update=true; m_ctrl->SetBounds(0,0,this->GetInnerBounds().w,this->GetInnerBounds().h); // if (!update) // return; update=false; static int test = 1; test++; static double time_since_reset = 0.f; if (!idle) { time_since_reset = CProfileManager::Get_Time_Since_Reset(); } //Gwen::UnicodeString txt = Gwen::Utility::Format( L"FEM Settings %i fps", test ); { //recompute profiling data, and store profile strings char blockTime[128]; double totalTime = 0; int frames_since_reset = CProfileManager::Get_Frame_Count_Since_Reset(); profileIterator->First(); double parent_time = profileIterator->Is_Root() ? time_since_reset : profileIterator->Get_Current_Parent_Total_Time(); Gwen::Controls::TreeNode* curParent = m_node; double accumulated_time = dumpRecursive(profileIterator,m_node); const char* name = profileIterator->Get_Current_Parent_Name(); #ifdef _WIN32 Gwen::UnicodeString uname = Gwen::Utility::StringToUnicode(name); Gwen::UnicodeString txt = Gwen::Utility::Format( L"Profiling: %s total time: %.3f ms, unaccounted %.3f %% :: %.3f ms", uname.c_str(), parent_time , parent_time > SIMD_EPSILON ? ((parent_time - accumulated_time) / parent_time) * 100 : 0.f, parent_time - accumulated_time); #else Gwen::UnicodeString txt = Gwen::Utility::Format( L"Profiling: %s total time: %.3f ms, unaccounted %.3f %% :: %.3f ms", name, parent_time , parent_time > SIMD_EPSILON ? ((parent_time - accumulated_time) / parent_time) * 100 : 0.f, parent_time - accumulated_time); #endif //sprintf(blockTime,"--- Profiling: %s (total running time: %.3f ms) ---", profileIterator->Get_Current_Parent_Name(), parent_time ); //displayProfileString(xOffset,yStart,blockTime); m_node->SetText(txt); //printf("%s (%.3f %%) :: %.3f ms\n", "Unaccounted:",); } static int counter=10; if (counter) { counter--; m_ctrl->ExpandAll(); } }
void Gwen::Utility::Strings::ToUpper( Gwen::UnicodeString& str ) { transform( str.begin(), str.end(), str.begin(), towupper ); }