X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/92b0a2a13ccaaa23a97964ff35cdaf39dd44a104..bc6ca1a9e68a84817092856059d8ee9f5d109d1d:/src/common/ctrlcmn.cpp diff --git a/src/common/ctrlcmn.cpp b/src/common/ctrlcmn.cpp index 2ebabc1f0d..f7145a78a5 100644 --- a/src/common/ctrlcmn.cpp +++ b/src/common/ctrlcmn.cpp @@ -1,12 +1,12 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: ctrlcmn.cpp +// Name: src/common/ctrlcmn.cpp // Purpose: wxControl common interface // Author: Vadim Zeitlin // Modified by: // Created: 26.07.99 // RCS-ID: $Id$ -// Copyright: (c) wxWindows team -// Licence: wxWindows license +// Copyright: (c) wxWidgets team +// Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// // ============================================================================ @@ -17,11 +17,6 @@ // headers // ---------------------------------------------------------------------------- -#ifdef __GNUG__ - #pragma implementation "controlbase.h" - #pragma implementation "statbmpbase.h" -#endif - // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" @@ -31,15 +26,19 @@ #if wxUSE_CONTROLS +#include "wx/control.h" + #ifndef WX_PRECOMP - #include "wx/control.h" + #include "wx/dc.h" #include "wx/log.h" + #include "wx/radiobut.h" + #include "wx/statbmp.h" + #include "wx/bitmap.h" + #include "wx/utils.h" // for wxStripMenuCodes() + #include "wx/settings.h" #endif -#if wxUSE_STATBMP - #include "wx/bitmap.h" - #include "wx/statbmp.h" -#endif // wxUSE_STATBMP +const char wxControlNameStr[] = "control"; // ============================================================================ // implementation @@ -55,7 +54,7 @@ bool wxControlBase::Create(wxWindow *parent, const wxPoint &pos, const wxSize &size, long style, - const wxValidator& validator, + const wxValidator& wxVALIDATOR_PARAM(validator), const wxString &name) { bool ret = wxWindow::Create(parent, id, pos, size, style, name); @@ -79,28 +78,21 @@ bool wxControlBase::CreateControl(wxWindowBase *parent, // even if it's possible to create controls without parents in some port, // it should surely be discouraged because it doesn't work at all under // Windows - wxCHECK_MSG( parent, FALSE, wxT("all controls must have parents") ); + wxCHECK_MSG( parent, false, wxT("all controls must have parents") ); if ( !CreateBase(parent, id, pos, size, style, validator, name) ) - return FALSE; + return false; parent->AddChild(this); - return TRUE; + return true; } -// inherit colour and font settings from the parent window -void wxControlBase::InheritAttributes() +/* static */ +wxString wxControlBase::GetLabelText(const wxString& label) { - // it definitely doesn't make sense to inherit the background colour as the - // controls typically have their own standard one and probably not the - // foreground neither? -#if 0 - SetBackgroundColour(GetParent()->GetBackgroundColour()); - SetForegroundColour(GetParent()->GetForegroundColour()); -#endif // 0 - - SetFont(GetParent()->GetFont()); + // we don't want strip the TABs here, just the mnemonics + return wxStripMenuCodes(label, wxStrip_Mnemonics); } void wxControlBase::Command(wxCommandEvent& event) @@ -130,6 +122,327 @@ void wxControlBase::InitCommandEvent(wxCommandEvent& event) const } } +bool wxControlBase::SetFont(const wxFont& font) +{ + InvalidateBestSize(); + return wxWindow::SetFont(font); +} + +// wxControl-specific processing after processing the update event +void wxControlBase::DoUpdateWindowUI(wxUpdateUIEvent& event) +{ + // call inherited + wxWindowBase::DoUpdateWindowUI(event); + + // update label + if ( event.GetSetText() ) + { + if ( event.GetText() != GetLabel() ) + SetLabel(event.GetText()); + } + + // Unfortunately we don't yet have common base class for + // wxRadioButton, so we handle updates of radiobuttons here. + // TODO: If once wxRadioButtonBase will exist, move this code there. +#if wxUSE_RADIOBTN + if ( event.GetSetChecked() ) + { + wxRadioButton *radiobtn = wxDynamicCastThis(wxRadioButton); + if ( radiobtn ) + radiobtn->SetValue(event.GetChecked()); + } +#endif // wxUSE_RADIOBTN +} + +/* static */ +wxString wxControlBase::RemoveMnemonics(const wxString& str) +{ + return wxStripMenuCodes(str, wxStrip_Mnemonics); +} + +/* static */ +wxString wxControlBase::EscapeMnemonics(const wxString& text) +{ + wxString label(text); + label.Replace("&", "&&"); + return label; +} + +/* static */ +int wxControlBase::FindAccelIndex(const wxString& label, wxString *labelOnly) +{ + // the character following MNEMONIC_PREFIX is the accelerator for this + // control unless it is MNEMONIC_PREFIX too - this allows to insert + // literal MNEMONIC_PREFIX chars into the label + static const wxChar MNEMONIC_PREFIX = wxT('&'); + + if ( labelOnly ) + { + labelOnly->Empty(); + labelOnly->Alloc(label.length()); + } + + int indexAccel = -1; + for ( wxString::const_iterator pc = label.begin(); pc != label.end(); ++pc ) + { + if ( *pc == MNEMONIC_PREFIX ) + { + ++pc; // skip it + if ( pc == label.end() ) + break; + else if ( *pc != MNEMONIC_PREFIX ) + { + if ( indexAccel == -1 ) + { + // remember it (-1 is for MNEMONIC_PREFIX itself + indexAccel = pc - label.begin() - 1; + } + else + { + wxFAIL_MSG(wxT("duplicate accel char in control label")); + } + } + } + + if ( labelOnly ) + { + *labelOnly += *pc; + } + } + + return indexAccel; +} + +wxBorder wxControlBase::GetDefaultBorder() const +{ + return wxBORDER_THEME; +} + +/* static */ wxVisualAttributes +wxControlBase::GetCompositeControlsDefaultAttributes(wxWindowVariant WXUNUSED(variant)) +{ + wxVisualAttributes attrs; + attrs.font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); + attrs.colFg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT); + attrs.colBg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); + + return attrs; +} + +// ---------------------------------------------------------------------------- +// wxControlBase - ellipsization code +// ---------------------------------------------------------------------------- + +#define wxELLIPSE_REPLACEMENT wxT("...") + +/* static and protected */ +wxString wxControlBase::DoEllipsizeSingleLine(const wxString& curLine, const wxDC& dc, + wxEllipsizeMode mode, int maxFinalWidth, + int replacementWidth, int marginWidth) +{ + wxASSERT_MSG(replacementWidth > 0 && marginWidth > 0, + "Invalid parameters"); + wxASSERT_MSG(!curLine.Contains('\n'), + "Use Ellipsize() instead!"); + + wxASSERT_MSG( mode != wxELLIPSIZE_NONE, "shouldn't be called at all then" ); + + // NOTE: this function assumes that any mnemonic/tab character has already + // been handled if it was necessary to handle them (see Ellipsize()) + + if (maxFinalWidth <= 0) + return wxEmptyString; + + wxArrayInt charOffsets; + size_t len = curLine.length(); + if (len == 0 || + !dc.GetPartialTextExtents(curLine, charOffsets)) + return curLine; + + wxASSERT(charOffsets.GetCount() == len); + + size_t totalWidth = charOffsets.Last(); + if ( totalWidth <= (size_t)maxFinalWidth ) + return curLine; // we don't need to do any ellipsization! + + int excessPixels = totalWidth - maxFinalWidth + + replacementWidth + + marginWidth; // security margin (NEEDED!) + wxASSERT(excessPixels>0); + + // remove characters in excess + size_t initialChar, // index of first char to erase + nChars; // how many chars do we need to erase? + + switch (mode) + { + case wxELLIPSIZE_START: + initialChar = 0; + for ( nChars=0; + nChars < len && charOffsets[nChars] < excessPixels; + nChars++ ) + ; + break; + + case wxELLIPSIZE_MIDDLE: + { + // the start & end of the removed span of chars + initialChar = len/2; + size_t endChar = len/2; + + int removed = 0; + for ( ; removed < excessPixels; ) + { + if (initialChar > 0) + { + // width of the initialChar-th character + int width = charOffsets[initialChar] - + charOffsets[initialChar-1]; + + // remove the initialChar-th character + removed += width; + initialChar--; + } + + if (endChar < len - 1 && + removed < excessPixels) + { + // width of the (endChar+1)-th character + int width = charOffsets[endChar+1] - + charOffsets[endChar]; + + // remove the endChar-th character + removed += width; + endChar++; + } + + if (initialChar == 0 && endChar == len-1) + { + nChars = len+1; + break; + } + } + + initialChar++; + nChars = endChar - initialChar + 1; + } + break; + + case wxELLIPSIZE_END: + { + wxASSERT(len > 0); + + int maxWidth = totalWidth - excessPixels; + for ( initialChar = 0; + initialChar < len && charOffsets[initialChar] < maxWidth; + initialChar++ ) + ; + + if (initialChar == 0) + { + nChars = len; + } + else + { + //initialChar--; // go back one character + nChars = len - initialChar; + } + } + break; + + case wxELLIPSIZE_NONE: + default: + wxFAIL_MSG("invalid ellipsize mode"); + return curLine; + } + + wxString ret(curLine); + if (nChars >= len) + { + // need to remove the entire row! + ret.clear(); + } + else + { + // erase nChars characters after initialChar (included): + ret.erase(initialChar, nChars+1); + + // if there is space for the replacement dots, add them + if (maxFinalWidth > replacementWidth) + ret.insert(initialChar, wxELLIPSE_REPLACEMENT); + } + + // if everything was ok, we should have shortened this line + // enough to make it fit in maxFinalWidth: + wxASSERT(dc.GetTextExtent(ret).GetWidth() < maxFinalWidth); + + return ret; +} + +/* static */ +wxString wxControlBase::Ellipsize(const wxString& label, const wxDC& dc, + wxEllipsizeMode mode, int maxFinalWidth, + int flags) +{ + wxString ret; + + // these cannot be cached between different Ellipsize() calls as they can + // change because of e.g. a font change; however we calculate them only once + // when ellipsizing multiline labels: + int replacementWidth = dc.GetTextExtent(wxELLIPSE_REPLACEMENT).GetWidth(); + int marginWidth = dc.GetCharWidth(); + + // NB: we must handle correctly labels with newlines: + wxString curLine; + for ( wxString::const_iterator pc = label.begin(); ; ++pc ) + { + if ( pc == label.end() || *pc == wxS('\n') ) + { + curLine = DoEllipsizeSingleLine(curLine, dc, mode, maxFinalWidth, + replacementWidth, marginWidth); + + // add this (ellipsized) row to the rest of the label + ret << curLine; + if ( pc == label.end() ) + { + // NOTE: this is the return which always exits the function + return ret; + } + else + { + ret << *pc; + curLine.clear(); + } + } + // we need to remove mnemonics from the label for correct calculations + else if ( *pc == wxS('&') && (flags & wxELLIPSIZE_FLAGS_PROCESS_MNEMONICS) ) + { + // pc+1 is safe: at worst we'll be at end() + wxString::const_iterator next = pc + 1; + if ( next != label.end() && *next == wxS('&') ) + curLine += wxS('&'); // && becomes & + //else: remove this ampersand + } + // we need also to expand tabs to properly calc their size + else if ( *pc == wxS('\t') && (flags & wxELLIPSIZE_FLAGS_EXPAND_TABS) ) + { + // Windows natively expands the TABs to 6 spaces. Do the same: + curLine += wxS(" "); + } + else + { + curLine += *pc; + } + } + + // this return would generate a + // warning C4702: unreachable code + // with MSVC since the function always exits from inside the loop + //return ret; +} + + + // ---------------------------------------------------------------------------- // wxStaticBitmap // ---------------------------------------------------------------------------- @@ -141,17 +454,19 @@ wxStaticBitmapBase::~wxStaticBitmapBase() // this destructor is required for Darwin } -wxSize wxStaticBitmapBase::DoGetBestClientSize() const +wxSize wxStaticBitmapBase::DoGetBestSize() const { + wxSize best; wxBitmap bmp = GetBitmap(); if ( bmp.Ok() ) - return wxSize(bmp.GetWidth(), bmp.GetHeight()); - - // this is completely arbitrary - return wxSize(16, 16); + best = wxSize(bmp.GetWidth(), bmp.GetHeight()); + else + // this is completely arbitrary + best = wxSize(16, 16); + CacheBestSize(best); + return best; } #endif // wxUSE_STATBMP #endif // wxUSE_CONTROLS -