X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/14f355c2b5c71fc7c3d680aea366582d2ac60f7b..ef25e5a4c8102c9d981e3f720c27462c72102b54:/src/common/dlgcmn.cpp diff --git a/src/common/dlgcmn.cpp b/src/common/dlgcmn.cpp index 82501e06d9..64011f46c7 100644 --- a/src/common/dlgcmn.cpp +++ b/src/common/dlgcmn.cpp @@ -17,10 +17,6 @@ // headers // ---------------------------------------------------------------------------- -#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) - #pragma implementation "dialogbase.h" -#endif - // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" @@ -40,11 +36,69 @@ #include "wx/containr.h" #endif -//-------------------------------------------------------------------------- +#include "wx/statline.h" +#include "wx/sysopt.h" + +#if wxUSE_STATTEXT + +// ---------------------------------------------------------------------------- +// wxTextWrapper +// ---------------------------------------------------------------------------- + +// this class is used to wrap the text on word boundary: wrapping is done by +// calling OnStartLine() and OnOutputLine() functions +class wxTextWrapper +{ +public: + wxTextWrapper() { m_eol = false; } + + // win is used for getting the font, text is the text to wrap, width is the + // max line width or -1 to disable wrapping + void Wrap(wxWindow *win, const wxString& text, int widthMax); + + // we don't need it, but just to avoid compiler warnings + virtual ~wxTextWrapper() { } + +protected: + // line may be empty + virtual void OnOutputLine(const wxString& line) = 0; + + // called at the start of every new line (except the very first one) + virtual void OnNewLine() { } + +private: + // call OnOutputLine() and set m_eol to true + void DoOutputLine(const wxString& line) + { + OnOutputLine(line); + + m_eol = true; + } + + // this function is a destructive inspector: when it returns true it also + // resets the flag to false so calling it again woulnd't return true any + // more + bool IsStartOfNewLine() + { + if ( !m_eol ) + return false; + + m_eol = false; + + return true; + } + + + bool m_eol; +}; + +#endif // wxUSE_STATTEXT + +// ---------------------------------------------------------------------------- // wxDialogBase -//-------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- -// FIXME - temporary hack in absence of wxtopLevelWindow, should be always used +// FIXME - temporary hack in absence of wxTopLevelWindow, should be always used #ifdef wxTopLevelWindowNative BEGIN_EVENT_TABLE(wxDialogBase, wxTopLevelWindow) WX_EVENT_TABLE_CONTROL_CONTAINER(wxDialogBase) @@ -56,6 +110,8 @@ WX_DELEGATE_TO_CONTROL_CONTAINER(wxDialogBase) void wxDialogBase::Init() { m_returnCode = 0; + m_affirmativeId = wxID_OK; + m_escapeId = wxID_ANY; // the dialogs have this flag on by default to prevent the events from the // dialog controls from reaching the parent frame which is usually @@ -67,187 +123,272 @@ void wxDialogBase::Init() #endif } -#if wxUSE_STATTEXT // && wxUSE_TEXTCTRL +#if wxUSE_STATTEXT -wxSizer *wxDialogBase::CreateTextSizer( const wxString& message ) +void wxTextWrapper::Wrap(wxWindow *win, const wxString& text, int widthMax) { - bool is_pda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA); - - wxString text = message; - - // I admit that this is complete bogus, but it makes - // message boxes work for pda screens temporarily.. - int max_width = -1; - if (is_pda) - { - max_width = wxSystemSettings::GetMetric( wxSYS_SCREEN_X ) - 25; - text += wxT('\n'); - } - - - wxBoxSizer *box = new wxBoxSizer( wxVERTICAL ); - - // get line height for empty lines - int y = 0; - wxFont font( GetFont() ); - if (!font.Ok()) - font = *wxSWISS_FONT; - GetTextExtent( wxT("H"), (int*)NULL, &y, (int*)NULL, (int*)NULL, &font); - - size_t last_space = 0; + const wxChar *lastSpace = NULL; wxString line; - for ( size_t pos = 0; pos < text.length(); pos++ ) + + const wxChar *lineStart = text.c_str(); + for ( const wxChar *p = lineStart; ; p++ ) { - switch ( text[pos] ) + if ( IsStartOfNewLine() ) { - case wxT('\n'): - if (!line.IsEmpty()) - { - wxStaticText *s = new wxStaticText( this, -1, line ); - box->Add( s ); - line = wxT(""); - } - else - { - box->Add( 5, y ); - } + OnNewLine(); + + lastSpace = NULL; + line.clear(); + lineStart = p; + } + + if ( *p == _T('\n') || *p == _T('\0') ) + { + DoOutputLine(line); + + if ( *p == _T('\0') ) break; + } + else // not EOL + { + if ( *p == _T(' ') ) + lastSpace = p; + + line += *p; + + if ( widthMax >= 0 && lastSpace ) + { + int width; + win->GetTextExtent(line, &width, NULL); - case wxT('&'): - // this is used as accel mnemonic prefix in the wxWindows - // controls but in the static messages created by - // CreateTextSizer() (used by wxMessageBox, for example), we - // don't want this special meaning, so we need to quote it - line += wxT('&'); - - // fall through to add it normally too - - default: - if (text[pos] == wxT(' ')) - last_space = pos; - - line += message[pos]; - - if (is_pda) + if ( width > widthMax ) { - int width = 0; - GetTextExtent( line, &width, (int*)NULL, (int*)NULL, (int*)NULL, &font ); - - if (width > max_width) - { - // exception if there was no previous space - if (last_space == 0) - last_space = pos; - - int diff = pos-last_space; - int len = line.Len(); - line.Remove( len-diff, diff ); - - wxStaticText *s = new wxStaticText( this, -1, line ); - box->Add( s ); - - pos = last_space; - last_space = 0; - line = wxT(""); - } + // remove the last word from this line + line.erase(lastSpace - lineStart, p + 1 - lineStart); + DoOutputLine(line); + + // go back to the last word of this line which we didn't + // output yet + p = lastSpace; } + } + //else: no wrapping at all or impossible to wrap } } +} - // remaining text behind last '\n' - if (!line.IsEmpty()) +class wxTextSizerWrapper : public wxTextWrapper +{ +public: + wxTextSizerWrapper(wxWindow *win) { - wxStaticText *s2 = new wxStaticText( this, -1, line ); - box->Add( s2 ); + m_win = win; + m_hLine = 0; } - return box; -} + wxSizer *CreateSizer(const wxString& text, int widthMax) + { + m_sizer = new wxBoxSizer(wxVERTICAL); + Wrap(m_win, text, widthMax); + return m_sizer; + } -#endif // wxUSE_STATTEXT // && wxUSE_TEXTCTRL +protected: + virtual void OnOutputLine(const wxString& line) + { + if ( !line.empty() ) + { + m_sizer->Add(new wxStaticText(m_win, wxID_ANY, line)); + } + else // empty line, no need to create a control for it + { + if ( !m_hLine ) + m_hLine = m_win->GetCharHeight(); -#if wxUSE_BUTTON + m_sizer->Add(5, m_hLine); + } + } + +private: + wxWindow *m_win; + wxSizer *m_sizer; + int m_hLine; +}; -wxSizer *wxDialogBase::CreateButtonSizer( long flags ) +wxSizer *wxDialogBase::CreateTextSizer(const wxString& message) { - bool is_pda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA); - - wxBoxSizer *box = NULL; - - // If we have a PDA screen, put yes/no button over - // all other buttons, otherwise on the left side. + // I admit that this is complete bogus, but it makes + // message boxes work for pda screens temporarily.. + int widthMax = -1; + const bool is_pda = wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA; if (is_pda) - box = new wxBoxSizer( wxVERTICAL ); - else - box = new wxBoxSizer( wxHORIZONTAL ); - - wxBoxSizer *inner_yes_no = NULL; - - // Only create sizer containing yes/no - // if it is actually required - if ( (flags & wxYES_NO) != 0 ) { - inner_yes_no = new wxBoxSizer( wxHORIZONTAL ); - box->Add( inner_yes_no, 0, wxBOTTOM, 10 ); + widthMax = wxSystemSettings::GetMetric( wxSYS_SCREEN_X ) - 25; } - - wxBoxSizer *inner_rest = new wxBoxSizer( wxHORIZONTAL ); - box->Add( inner_rest, 0, 0, 0 ); -#if defined(__WXMSW__) || defined(__WXMAC__) - static const int margin = 6; -#else - static const int margin = 10; -#endif + // '&' is used as accel mnemonic prefix in the wxWidgets controls but in + // the static messages created by CreateTextSizer() (used by wxMessageBox, + // for example), we don't want this special meaning, so we need to quote it + wxString text(message); + text.Replace(_T("&"), _T("&&")); - wxButton *ok = (wxButton *) NULL; - wxButton *cancel = (wxButton *) NULL; - wxButton *yes = (wxButton *) NULL; - wxButton *no = (wxButton *) NULL; + wxTextSizerWrapper wrapper(this); - // always show an OK button, unless we have both YES and NO - if ( (flags & wxYES_NO) != wxYES_NO ) - flags |= wxOK; + return wrapper.CreateSizer(text, widthMax); +} - if (flags & wxYES) +class wxLabelWrapper : public wxTextWrapper +{ +public: + void WrapLabel(wxWindow *text, int widthMax) { - yes = new wxButton( this, wxID_YES, _("Yes"),wxDefaultPosition,wxDefaultSize,wxCLIP_SIBLINGS ); - inner_yes_no->Add( yes, 0, wxLEFT|wxRIGHT, margin ); + m_text.clear(); + Wrap(text, text->GetLabel(), widthMax); + text->SetLabel(m_text); } - if (flags & wxNO) + +protected: + virtual void OnOutputLine(const wxString& line) { - no = new wxButton( this, wxID_NO, _("No"),wxDefaultPosition,wxDefaultSize,wxCLIP_SIBLINGS ); - inner_yes_no->Add( no, 0, wxLEFT|wxRIGHT, margin ); + m_text += line; } - if (flags & wxOK) + virtual void OnNewLine() { - ok = new wxButton( this, wxID_OK, _("OK"),wxDefaultPosition,wxDefaultSize,wxCLIP_SIBLINGS ); - inner_rest->Add( ok, 0, wxLEFT|wxRIGHT, margin ); + m_text += _T('\n'); } - if (flags & wxFORWARD) - inner_rest->Add( new wxButton( this, wxID_FORWARD, _("Forward"),wxDefaultPosition,wxDefaultSize,wxCLIP_SIBLINGS ), 0, wxLEFT|wxRIGHT, margin ); +private: + wxString m_text; +}; + +// NB: don't "factor out" the scope operator, SGI MIPSpro 7.3 (but not 7.4) +// gets confused if it doesn't immediately follow the class name +void +#if defined(__WXGTK__) && !defined(__WXUNIVERSAL__) +wxStaticText:: +#else +wxStaticTextBase:: +#endif +Wrap(int width) +{ + wxLabelWrapper wrapper; + wrapper.WrapLabel(this, width); +} - if (flags & wxBACKWARD) - inner_rest->Add( new wxButton( this, wxID_BACKWARD, _("Backward"),wxDefaultPosition,wxDefaultSize,wxCLIP_SIBLINGS ), 0, wxLEFT|wxRIGHT, margin ); +#endif // wxUSE_STATTEXT - if (flags & wxSETUP) - inner_rest->Add( new wxButton( this, wxID_SETUP, _("Setup"),wxDefaultPosition,wxDefaultSize,wxCLIP_SIBLINGS ), 0, wxLEFT|wxRIGHT, margin ); +wxSizer *wxDialogBase::CreateButtonSizer( long flags, bool separated, wxCoord distance ) +{ +#ifdef __SMARTPHONE__ + wxUnusedVar(separated); + wxUnusedVar(distance); + + wxDialog* dialog = (wxDialog*) this; + if (flags & wxOK){ + dialog->SetLeftMenu(wxID_OK); + } - if (flags & wxMORE) - inner_rest->Add( new wxButton( this, wxID_MORE, _("More..."),wxDefaultPosition,wxDefaultSize,wxCLIP_SIBLINGS ), 0, wxLEFT|wxRIGHT, margin ); + if (flags & wxCANCEL){ + dialog->SetRightMenu(wxID_CANCEL); + } - if (flags & wxHELP) - inner_rest->Add( new wxButton( this, wxID_HELP, _("Help"),wxDefaultPosition,wxDefaultSize,wxCLIP_SIBLINGS ), 0, wxLEFT|wxRIGHT, margin ); + if (flags & wxYES){ + dialog->SetLeftMenu(wxID_YES); + } - if (flags & wxCANCEL) + if (flags & wxNO){ + dialog->SetLeftMenu(wxID_NO); + } + wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL); + return sizer; + +#else // !__SMARTPHONE__ + +#ifdef __POCKETPC__ + // PocketPC guidelines recommend for Ok/Cancel dialogs to use + // OK button located inside caption bar and implement Cancel functionality + // through Undo outside dialog. As native behaviour this will be default + // here but can be easily replaced with real wxButtons + // with "wince.dialog.real-ok-cancel" option set to 1 + if ( ((flags & ~(wxCANCEL|wxNO_DEFAULT))== wxOK) && + (wxSystemOptions::GetOptionInt(wxT("wince.dialog.real-ok-cancel"))==0) + ) { - cancel = new wxButton( this, wxID_CANCEL, _("Cancel"),wxDefaultPosition,wxDefaultSize,wxCLIP_SIBLINGS ); - inner_rest->Add( cancel, 0, wxLEFT|wxRIGHT, margin ); + wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL); + return sizer; + } +#endif // __POCKETPC__ + +#if wxUSE_BUTTON + + wxSizer* buttonSizer = CreateStdDialogButtonSizer( flags ); + + // Mac Human Interface Guidelines recommend not to use static lines as grouping elements +#if wxUSE_STATLINE && !defined(__WXMAC__) + if(!separated) + return buttonSizer; + + wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL ); + topsizer->Add( new wxStaticLine( this, wxID_ANY ), 0, wxEXPAND | wxBOTTOM, distance ); + topsizer->Add( buttonSizer, 0, wxEXPAND ); + return topsizer; + +#else // !wxUSE_STATLINE + + wxUnusedVar(separated); + wxUnusedVar(distance); + return buttonSizer; + +#endif // wxUSE_STATLINE/!wxUSE_STATLINE + +#else // !wxUSE_BUTTON + + wxUnusedVar(separated); + wxUnusedVar(distance); + wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL); + return sizer; + +#endif // wxUSE_BUTTON/!wxUSE_BUTTON + +#endif // __SMARTPHONE__/!__SMARTPHONE__ +} + +#if wxUSE_BUTTON + +wxStdDialogButtonSizer *wxDialogBase::CreateStdDialogButtonSizer( long flags ) +{ + wxStdDialogButtonSizer *sizer = new wxStdDialogButtonSizer(); + + wxButton *ok = NULL; + wxButton *yes = NULL; + wxButton *no = NULL; + + if (flags & wxOK){ + ok = new wxButton(this, wxID_OK); + sizer->AddButton(ok); + } + + if (flags & wxCANCEL){ + wxButton *cancel = new wxButton(this, wxID_CANCEL); + sizer->AddButton(cancel); + } + + if (flags & wxYES){ + yes = new wxButton(this, wxID_YES); + sizer->AddButton(yes); + } + + if (flags & wxNO){ + no = new wxButton(this, wxID_NO); + sizer->AddButton(no); + } + + if (flags & wxHELP){ + wxButton *help = new wxButton(this, wxID_HELP); + sizer->AddButton(help); } - // choose the default button if (flags & wxNO_DEFAULT) { if (no) @@ -270,7 +411,14 @@ wxSizer *wxDialogBase::CreateButtonSizer( long flags ) } } - return box; + if (flags & wxOK) + SetAffirmativeId(wxID_OK); + else if (flags & wxYES) + SetAffirmativeId(wxID_YES); + + sizer->Realize(); + + return sizer; } #endif // wxUSE_BUTTON