From 32023f884cda24077d136389bed86ba184b7f0ff Mon Sep 17 00:00:00 2001 From: Chris Frey Date: Thu, 19 Jul 2012 23:55:32 -0400 Subject: [PATCH] desktop: added basic support for i18n text drawing on buttons --- desktop/src/PNGButton.cc | 9 +++ desktop/src/util.cc | 165 +++++++++++++++++++++++++++++++++++++++++++++++ desktop/src/util.h | 16 +++++ 3 files changed, 190 insertions(+) diff --git a/desktop/src/PNGButton.cc b/desktop/src/PNGButton.cc index 09e95c4a..ed3df13a 100644 --- a/desktop/src/PNGButton.cc +++ b/desktop/src/PNGButton.cc @@ -53,6 +53,15 @@ wxBitmap PNGButton::LoadButtonBitmap(int state) wxGetApp().Yield(); throw std::runtime_error(_C("Cannot load button bitmap.")); } + + int pointsize = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT) + .GetPointSize(); + wxFont font(pointsize + 2, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, + wxFONTWEIGHT_BOLD); + + wxString label = GetButtonLabel(m_id); + DrawButtonLabel(bmp, label, font, *wxBLACK, 75, -1, -1, -1); + return bmp; } diff --git a/desktop/src/util.cc b/desktop/src/util.cc index 729f0b00..feed9c89 100644 --- a/desktop/src/util.cc +++ b/desktop/src/util.cc @@ -23,6 +23,11 @@ #include "barrydesktop.h" #include "windowids.h" #include +#include +#include +#include "wxi18n.h" + +using namespace std; const wxChar *ButtonNames[] = { _T("backuprestore"), @@ -36,6 +41,24 @@ const wxChar *ButtonNames[] = { 0 }; +const wxArrayString& GetButtonLabels() +{ + static wxArrayString m_labels; + + if( m_labels.GetCount() == 0 ) { + m_labels.Add( _W("Backup &\nRestore") ); + m_labels.Add( _W("Sync") ); + m_labels.Add( _W("Modem\nTethering") ); + m_labels.Add( _W("Migrate\nDevice") ); + m_labels.Add( _W("Browse\nDatabases") ); + m_labels.Add( _W("Application\nLoader") ); + m_labels.Add( _W("Media") ); + m_labels.Add( _W("Misc") ); + } + + return m_labels; +} + bool ButtonEnabled[] = { true, // backuprestore true, // sync @@ -104,6 +127,11 @@ wxString GetButtonFilename(int id, int state) ); } +wxString GetButtonLabel(int id) +{ + return GetButtonLabels()[id - MainMenu_FirstButton]; +} + bool IsButtonEnabled(int id) { return ButtonEnabled[id - MainMenu_FirstButton]; @@ -142,3 +170,140 @@ bool IsBuildable(const std::string &dbname) return false; } +namespace { + struct LabelLine + { + wxString m_line; + int m_width; + int m_height; + + LabelLine(const wxString &line, const wxDC &dc) + : m_line(line) + , m_width(0) + , m_height(0) + { + dc.GetTextExtent(line, &m_width, &m_height); + } + }; +} + +// +// DrawButtonLabel +// +/// Draws the given label text in the specified area of the bitmap, +/// modifying the bitmap in the process. This is intended for use in +/// creating the main Desktop buttons, but can be used on any image. +/// +/// The left/top/right/bottom coordinates are relative to the 0,0 of +/// the bitmap itself, and limit the area where the label text will be +/// drawn. If -1 is used for any of the values, the bitmap edge will +/// be used. +/// +/// The label text can contain \n characters to split into multiple +/// lines. Each line will be centered (left/right) in the coordinate +/// area, and all lines will be centered (top/bottom) in the coordinate +/// area. A trailing \n character is not required, and not recommended. +/// +/// If the coordinate area is too small for the given text and font, +/// the font will be reduced by 1 or two points and tried again. If still +/// too big, a DrawButtonLabelError exception will be thrown. +/// +/// If the label contains an empty string, a DrawButtonLabelError exception will +/// be thrown. This is to prevent any unlabeled buttons in the system. +/// +/// If Font is invalid, DrawButtonLabelError will be thrown. +/// +void DrawButtonLabel(wxBitmap &bmp, const wxString &label, + const wxFont &orig_font, const wxColour &textfg, + int left, int top, int right, int bottom) +{ + // calculate the coordinates, and various sanity checks + if( left == -1 ) left = 0; + if( top == -1 ) top = 0; + if( right == -1 ) right = bmp.GetWidth(); + if( bottom == -1 ) bottom = bmp.GetHeight(); + + int width = right - left; + if( width < 0 ) { + swap(left, right); + width = right - left; + } + + int height = bottom - top; + if( height < 0 ) { + swap(top, bottom); + height = bottom - top; + } + + wxFont font = orig_font; + if( !font.IsOk() ) + throw DrawButtonLabelError(_C("Unable to create button: font is invalid")); + + // create DC to work with, writing into the bitmap given to us + wxMemoryDC dc; + dc.SelectObject(bmp); + dc.SetFont(font); + dc.SetTextForeground(textfg); + dc.SetMapMode(wxMM_TEXT); + + // build vector of lines, and calculate totals + int total_text_height = 0; + int widest_line = 0; + std::vector lines; + + // ... and keep trying if too big + for( int tries = 0; ; tries++ ) { + // start fresh + total_text_height = 0; + widest_line = 0; + lines.clear(); + + wxStringTokenizer tokens(label, _T("\n")); + while( tokens.HasMoreTokens() ) { + wxString token = tokens.GetNextToken(); + token.Trim(true); + token.Trim(false); + + if( !tokens.HasMoreTokens() && token.size() == 0 ) { + // we're done here... last line is empty + break; + } + + LabelLine line(token, dc); + lines.push_back( line ); + total_text_height += line.m_height; + widest_line = max(widest_line, line.m_width); + } + + // do we have enough room? + if( total_text_height <= height && widest_line <= width ) { + // good to go! + break; + } + + // only reduce font so much... + if( tries >= 2 ) + throw DrawButtonLabelError(_C("Unable to create button: text is too big to fit")); + + // too big, reduce font and try again + font.SetPointSize( font.GetPointSize() - 1 ); + dc.SetFont(font); + } + + // empty? + if( lines.size() == 0 ) + throw DrawButtonLabelError(_C("Unable to create button: label is empty")); + + // calculate starting height + int y = (height - total_text_height) / 2 + top; + + // draw each line, centering each one horizontally, and + // incrementing y by the line's height on each pass + std::vector::iterator b = lines.begin(), e = lines.end(); + for( ; b != e; ++b ) { + int x = (width - b->m_width) / 2 + left; + dc.DrawText(b->m_line, x, y); + y += b->m_height; + } +} + diff --git a/desktop/src/util.h b/desktop/src/util.h index 6215ea15..03028b9d 100644 --- a/desktop/src/util.h +++ b/desktop/src/util.h @@ -29,6 +29,16 @@ #define BUTTON_STATE_FOCUS 1 #define BUTTON_STATE_PUSHED 2 +// exception class for DrawButtonLabel() function below +class DrawButtonLabelError : public std::runtime_error +{ +public: + DrawButtonLabelError(const std::string &msg) + : std::runtime_error(msg) + { + } +}; + template int GetMaxWidth(wxWindow *win, IteratorT begin, IteratorT end, StrFn sfn) { @@ -45,9 +55,11 @@ int GetMaxWidth(wxWindow *win, IteratorT begin, IteratorT end, StrFn sfn) return max_width; } +const wxArrayString& GetButtonLabels(); std::string GetBaseFilename(const std::string &filename); wxString GetImageFilename(const wxString &filename); wxString GetButtonFilename(int id, int state); +wxString GetButtonLabel(int id); bool IsButtonEnabled(int id); class wxDatePickerCtrl; void MakeDateRecent(bool checked, wxDatePickerCtrl *picker); @@ -55,6 +67,10 @@ void MakeDateRecent(bool checked, wxDatePickerCtrl *picker); bool IsParsable(const std::string &dbname); bool IsBuildable(const std::string &dbname); +void DrawButtonLabel(wxBitmap &bmp, const wxString &label, + const wxFont &font, const wxColour &textfg, + int left, int top, int right, int bottom); + // Determine parsable classes via template specialization template inline bool IsParsable() -- 2.11.4.GIT