diff --git a/include/wx/defs.h b/include/wx/defs.h index 65df678745..c550653365 100644 --- a/include/wx/defs.h +++ b/include/wx/defs.h @@ -1036,10 +1036,18 @@ enum wxBorder #define wxTE_RICH 0x0080 #define wxTE_NO_VSCROLL 0x0100 #define wxTE_AUTO_SCROLL 0x0200 -#define wxPROCESS_ENTER 0x0400 -#define wxPASSWORD 0x0800 -#define wxTE_PROCESS_ENTER wxPROCESS_ENTER -#define wxTE_PASSWORD wxPASSWORD +#define wxTE_PROCESS_ENTER 0x0400 +#define wxTE_PASSWORD 0x0800 + +// use wxHSCROLL to not wrap text at all, wxTE_LINEWRAP to wrap it at any +// position and wxTE_WORDWRAP to wrap at words boundary +#define wxTE_DONTWRAP wxHSCROLL +#define wxTE_LINEWRAP 0x0800 +#define wxTE_WORDWRAP 0x0000 // it's just == !wxHSCROLL + +// deprecated synonyms +#define wxPROCESS_ENTER wxTE_PROCESS_ENTER +#define wxPASSWORD wxTE_PASSWORD /* * wxComboBox style flags diff --git a/include/wx/msw/window.h b/include/wx/msw/window.h index e51bc7dd46..008a0bce9e 100644 --- a/include/wx/msw/window.h +++ b/include/wx/msw/window.h @@ -364,6 +364,9 @@ public: // initialize various fields of wxMouseEvent (common part of MSWOnMouseXXX) void InitMouseEvent(wxMouseEvent& event, int x, int y, WXUINT flags); + // check if mouse is in the window + bool IsMouseInWindow() const; + protected: // the window handle WXHWND m_hWnd; diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 41930ec451..8ab473fd5b 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -141,6 +141,9 @@ static void TranslateKbdEventToMouse(wxWindowMSW *win, // get the text metrics for the current font static TEXTMETRIC wxGetTextMetrics(const wxWindowMSW *win); +// check if the mouse is in the window or its child +static bool IsMouseInWindow(HWND hwnd); + // --------------------------------------------------------------------------- // event tables // --------------------------------------------------------------------------- @@ -991,14 +994,27 @@ void wxWindowMSW::SetupColours() SetBackgroundColour(GetParent()->GetBackgroundColour()); } +bool wxWindowMSW::IsMouseInWindow() const +{ + // get the mouse position + POINT pt; + ::GetCursorPos(&pt); + + // find the window which currently has the cursor and go up the window + // chain until we find this window - or exhaust it + HWND hwnd = ::WindowFromPoint(pt); + while ( hwnd && (hwnd != GetHwnd()) ) + hwnd = ::GetParent(hwnd); + + return hwnd != NULL; +} + void wxWindowMSW::OnIdle(wxIdleEvent& event) { // Check if we need to send a LEAVE event if ( m_mouseInWindow ) { - POINT pt; - ::GetCursorPos(&pt); - if ( ::WindowFromPoint(pt) != GetHwnd() ) + if ( !IsMouseInWindow() ) { // Generate a LEAVE event m_mouseInWindow = FALSE; @@ -1018,6 +1034,8 @@ void wxWindowMSW::OnIdle(wxIdleEvent& event) if ( GetKeyState( VK_RBUTTON ) ) state |= MK_RBUTTON; + POINT pt; + ::GetCursorPos(&pt); wxMouseEvent event(wxEVT_LEAVE_WINDOW); InitMouseEvent(event, pt.x, pt.y, state); @@ -3294,13 +3312,11 @@ bool wxWindowMSW::HandleMouseMove(int x, int y, WXUINT flags) { if ( !m_mouseInWindow ) { - // it would be wrogn to assume that just because we get a mouse move - // event the mouse is inside the window: although this is usually true, - // it is not if we had captured the mouse, so we need to check the - // mouse coordinates here - POINT pt; - ::GetCursorPos(&pt); - if ( ::WindowFromPoint(pt) == GetHwnd() ) + // it would be wrong to assume that just because we get a mouse move + // event that the mouse is inside the window: although this is usually + // true, it is not if we had captured the mouse, so we need to check + // the mouse coordinates here + if ( !m_winCaptured || IsMouseInWindow() ) { // Generate an ENTER event m_mouseInWindow = TRUE; @@ -4420,3 +4436,4 @@ static TEXTMETRIC wxGetTextMetrics(const wxWindowMSW *win) return tm; } + diff --git a/src/univ/textctrl.cpp b/src/univ/textctrl.cpp index 0ac059d374..93dde134d8 100644 --- a/src/univ/textctrl.cpp +++ b/src/univ/textctrl.cpp @@ -19,6 +19,8 @@ the same location)? 3. split file into chunks +? 4. rewrite Replace() refresh logic to deal with wrapping lines + 5. cache info found by GetPartOfWrappedLine() - performance must be horrible + with lots of text */ /* @@ -360,6 +362,12 @@ bool wxTextCtrl::Create(wxWindow *parent, style |= wxALWAYS_SHOW_SB; } + if ( style & wxTE_WORDWRAP ) + { + // wrapping words means wrapping, hence no horz scrollbar + style &= ~wxHSCROLL; + } + // TODO: support wxTE_NO_VSCROLL (?) } else @@ -420,6 +428,8 @@ void wxTextCtrl::SetValue(const wxString& value) } Replace(0, GetLastPosition(), value); + + // TODO: should we generate the event or not, finally? } wxString wxTextCtrl::GetValue() const @@ -643,6 +653,9 @@ void wxTextCtrl::Replace(wxTextPos from, wxTextPos to, const wxString& text) // (5) now refresh the changed area + // update the (cached) last position first as refresh functions use it + m_posLast += text.length() - to + from; + // we may optimize refresh if the number of rows didn't change - but if // it did we have to refresh everything below the part we chanegd as // well as it might have moved @@ -669,7 +682,9 @@ void wxTextCtrl::Replace(wxTextPos from, wxTextPos to, const wxString& text) } //else: refresh all lines we changed (OPT?) - RefreshLineRange(lineStart, m_lines.GetCount() - 1); + wxTextCoord lineEnd = m_lines.GetCount() - 1; + if ( lineStart <= lineEnd ) + RefreshLineRange(lineStart, lineEnd); // refresh text rect left below if ( rowsNew < rowsOld ) @@ -686,9 +701,6 @@ void wxTextCtrl::Replace(wxTextPos from, wxTextPos to, const wxString& text) // the vert scrollbar might [dis]appear m_updateScrollbarY = TRUE; } - - // update the (cached) last position - m_posLast += text.length() - to + from; } #ifdef WXDEBUG_TEXT_REPLACE @@ -1903,8 +1915,9 @@ size_t wxTextCtrl::GetPartOfWrappedLine(const wxChar* text, case wxTE_HT_ON_TEXT: if ( col > 0 ) { - // the last entirely seen character is the last one unless the - // width of the string is exactly the max width + // the last entirely seen character is the previous one because + // this one is only partly visible - unless the width of the + // string is exactly the max width wReal = GetTextWidth(s.Truncate(col)); if ( wReal > m_rectText.width ) { @@ -1913,6 +1926,29 @@ size_t wxTextCtrl::GetPartOfWrappedLine(const wxChar* text, col--; } //else: we can just see it + + // wrap at any character or only at words boundaries? + if ( !(GetWindowStyle() & wxTE_LINEWRAP) ) + { + // find the (last) not word char before this word + wxTextCoord colWordStart; + for ( colWordStart = col; + colWordStart && IsWordChar(s[(size_t)colWordStart]); + colWordStart-- ) + ; + + if ( colWordStart > 0 ) + { + if ( colWordStart != col ) + { + // will have to recalc the real width + wReal = -1; + + col = colWordStart; + } + } + //else: only a single word, have to wrap it here + } } break; @@ -1939,7 +1975,7 @@ size_t wxTextCtrl::GetPartOfWrappedLine(const wxChar* text, } // VZ: old, horribly inefficient code which can still be used for checking - // the result - to be removed later + // the result (in line, not word, wrap mode only) - to be removed later #if 0 wxTextCtrl *self = wxConstCast(this, wxTextCtrl); wxClientDC dc(self); @@ -2761,22 +2797,22 @@ void wxTextCtrl::RefreshPixelRange(wxTextCoord line, // special case: width == 0 means to refresh till the end of line if ( width == 0 ) { - // FIXME we refresh till the end of the current line here, but we can't - // tell if the line didn't have fewer or more rows before - it is - // the callers responsability to not call us in this way if it is - // the case + // refresh till the end of visible line + width = GetTotalWidth(); + if ( WrapLines() ) { - width = wxMax(GetTextWidth(text), GetTotalWidth()); - } - else - { - // refresh till the end of visible line - width = GetTotalWidth(); + // refresh till the end of text + wxCoord widthAll = GetTextWidth(text); + + // extend width to the end of ROW + width = widthAll - widthAll % width + width; } + // no need to refresh beyond the end of line width -= start; } + //else: just refresh the specified part wxCoord h = GetCharHeight(); wxRect rect; @@ -2804,6 +2840,7 @@ void wxTextCtrl::RefreshPixelRange(wxTextCoord line, { rect.width = GetTotalWidth() - rect.x; RefreshTextRect(rect); + width -= wLine - rect.x; rect.x = 0; rect.y += h; @@ -3049,23 +3086,33 @@ void wxTextCtrl::DoDrawTextInRect(wxDC& dc, const wxRect& rectUpdate) wxString text = textLine.Mid(colStart, colEnd - colStart + 1); // now deal with the selection: only do something if at least part of - // the line is selected and if this part is (at least partly) in the - // current row + // the line is selected wxTextPos selStart, selEnd; - if ( GetSelectedPartOfLine(line, &selStart, &selEnd) && - (selStart <= colEnd) && (selEnd >= colRowStart) ) + if ( GetSelectedPartOfLine(line, &selStart, &selEnd) ) { - // these values are relative to the start of the line while the - // string passed to DrawTextLine() is only part of it, so adjust - // the selection range accordingly - selStart -= colStart; - selEnd -= colStart; + // and if this part is (at least partly) in the current row + if ( (selStart <= colEnd) && + (selEnd >= wxMax(colStart, colRowStart)) ) + { + // these values are relative to the start of the line while the + // string passed to DrawTextLine() is only part of it, so + // adjust the selection range accordingly + selStart -= colStart; + selEnd -= colStart; - if ( selStart < 0 ) - selStart = 0; + if ( selStart < 0 ) + selStart = 0; - if ( (size_t)selEnd >= text.length() ) - selEnd = text.length(); + if ( (size_t)selEnd >= text.length() ) + selEnd = text.length(); + } + else + { + // reset selStart and selEnd to avoid passing them to + // DrawTextLine() below + selStart = + selEnd = -1; + } } // calculate the text coords on screen diff --git a/src/univ/themes/win32.cpp b/src/univ/themes/win32.cpp index a09955ed82..0ce93a6d33 100644 --- a/src/univ/themes/win32.cpp +++ b/src/univ/themes/win32.cpp @@ -48,6 +48,28 @@ static const int BORDER_THICKNESS = 2; +enum IndicatorType +{ + IndicatorType_Check, + IndicatorType_Radio, + IndicatorType_Max +}; + +enum IndicatorState +{ + IndicatorState_Normal, + IndicatorState_Pressed, + IndicatorState_Disabled, + IndicatorState_Max +}; + +enum IndicatorStatus +{ + IndicatorStatus_Checked, + IndicatorStatus_Unchecked, + IndicatorStatus_Max +}; + // ---------------------------------------------------------------------------- // wxWin32Renderer: draw the GUI elements in Win32 style // ---------------------------------------------------------------------------- @@ -240,8 +262,11 @@ protected: int indexAccel); // get the standard check/radio button bitmap - wxBitmap GetCheckBitmap(int flags); - wxBitmap GetRadioBitmap(int flags); + wxBitmap GetIndicator(IndicatorType indType, int flags); + wxBitmap GetCheckBitmap(int flags) + { return GetIndicator(IndicatorType_Check, flags); } + wxBitmap GetRadioBitmap(int flags) + { return GetIndicator(IndicatorType_Radio, flags); } private: const wxColourScheme *m_scheme; @@ -373,7 +398,7 @@ private: // standard bitmaps // ---------------------------------------------------------------------------- -static char *checked_xpm[] = { +static const char *checked_xpm[] = { /* columns rows colors chars-per-pixel */ "13 13 5 1", "w c white", @@ -398,7 +423,7 @@ static char *checked_xpm[] = { "hhhhhhhhhhhhh" }; -static char *pressed_checked_xpm[] = { +static const char *pressed_checked_xpm[] = { /* columns rows colors chars-per-pixel */ "13 13 4 1", "b c black", @@ -422,7 +447,31 @@ static char *pressed_checked_xpm[] = { "hhhhhhhhhhhhh" }; -static char *checked_item_xpm[] = { +static const char *pressed_disabled_checked_xpm[] = { +/* columns rows colors chars-per-pixel */ +"13 13 4 1", +"b c black", +"d c #7f7f7f", +"g c #c0c0c0", +"h c #e0e0e0", +/* pixels */ +"ddddddddddddh", +"dbbbbbbbbbbgh", +"dbggggggggggh", +"dbgggggggdggh", +"dbggggggddggh", +"dbgdgggdddggh", +"dbgddgdddgggh", +"dbgdddddggggh", +"dbggdddgggggh", +"dbgggdggggggh", +"dbggggggggggh", +"dbggggggggggh", +"dgggggggggggh", +"hhhhhhhhhhhhh" +}; + +static const char *checked_item_xpm[] = { /* columns rows colors chars-per-pixel */ "13 13 3 1", "w c white", @@ -445,7 +494,7 @@ static char *checked_item_xpm[] = { "wwwwwwwwwwwww" }; -static char *unchecked_xpm[] = { +static const char *unchecked_xpm[] = { /* columns rows colors chars-per-pixel */ "13 13 5 1", "w c white", @@ -469,7 +518,7 @@ static char *unchecked_xpm[] = { "hhhhhhhhhhhhh" }; -static char *pressed_unchecked_xpm[] = { +static const char *pressed_unchecked_xpm[] = { /* columns rows colors chars-per-pixel */ "13 13 4 1", "b c black", @@ -492,7 +541,7 @@ static char *pressed_unchecked_xpm[] = { "hhhhhhhhhhhhh" }; -static char *unchecked_item_xpm[] = { +static const char *unchecked_item_xpm[] = { /* columns rows colors chars-per-pixel */ "13 13 2 1", "w c white", @@ -514,7 +563,7 @@ static char *unchecked_item_xpm[] = { "wwwwwwwwwwwww" }; -static char *checked_radio_xpm[] = { +static const char *checked_radio_xpm[] = { /* columns rows colors chars-per-pixel */ "13 13 6 1", " c None", @@ -539,7 +588,7 @@ static char *checked_radio_xpm[] = { " " }; -static char *pressed_checked_radio_xpm[] = { +static const char *pressed_checked_radio_xpm[] = { /* columns rows colors chars-per-pixel */ "13 13 6 1", " c None", @@ -564,7 +613,32 @@ static char *pressed_checked_radio_xpm[] = { " " }; -static char *unchecked_radio_xpm[] = { +static const char *pressed_disabled_checked_radio_xpm[] = { +/* columns rows colors chars-per-pixel */ +"13 13 6 1", +" c None", +"w c white", +"b c black", +"d c #7f7f7f", +"g c #c0c0c0", +"h c #e0e0e0", +/* pixels */ +" dddd ", +" ddbbbbdd ", +" dbbggggbbh ", +" dbgggggggh ", +" dbgggddggggh", +" dbggddddgggh", +" dbggddddgggh", +" dbgggddggggh", +" dbgggggggh ", +" dggggggggh ", +" hhgggghh ", +" hhhh ", +" " +}; + +static const char *unchecked_radio_xpm[] = { /* columns rows colors chars-per-pixel */ "13 13 6 1", " c None", @@ -589,7 +663,7 @@ static char *unchecked_radio_xpm[] = { " " }; -static char *pressed_unchecked_radio_xpm[] = { +static const char *pressed_unchecked_radio_xpm[] = { /* columns rows colors chars-per-pixel */ "13 13 6 1", " c None", @@ -614,6 +688,34 @@ static char *pressed_unchecked_radio_xpm[] = { " " }; +static const char ** + bmpIndicators[IndicatorType_Max][IndicatorState_Max][IndicatorStatus_Max] = +{ + // checkboxes first + { + // normal state + { checked_xpm, unchecked_xpm }, + + // pressed state + { pressed_checked_xpm, pressed_unchecked_xpm }, + + // disabled state + { pressed_disabled_checked_xpm, pressed_unchecked_xpm }, + }, + + // radio + { + // normal state + { checked_radio_xpm, unchecked_radio_xpm }, + + // pressed state + { pressed_checked_radio_xpm, pressed_unchecked_radio_xpm }, + + // disabled state + { pressed_disabled_checked_radio_xpm, pressed_unchecked_radio_xpm }, + }, +}; + // ============================================================================ // implementation // ============================================================================ @@ -1497,50 +1599,20 @@ void wxWin32Renderer::DrawCheckItem(wxDC& dc, // check/radio buttons // ---------------------------------------------------------------------------- -wxBitmap wxWin32Renderer::GetCheckBitmap(int flags) +wxBitmap wxWin32Renderer::GetIndicator(IndicatorType indType, int flags) { + IndicatorState indState; if ( flags & wxCONTROL_DISABLED ) - { - // the disabled indicators look the same as pressed ones in Windows - flags |= wxCONTROL_PRESSED; - } + indState = IndicatorState_Disabled; + else if ( flags & wxCONTROL_PRESSED ) + indState = IndicatorState_Pressed; + else + indState = IndicatorState_Normal; - char **xpm; - if ( flags & wxCONTROL_CHECKED ) - { - xpm = flags & wxCONTROL_PRESSED ? pressed_checked_xpm - : checked_xpm; - } - else // unchecked - { - xpm = flags & wxCONTROL_PRESSED ? pressed_unchecked_xpm - : unchecked_xpm; - } - - return wxBitmap(xpm); -} - -wxBitmap wxWin32Renderer::GetRadioBitmap(int flags) -{ - if ( flags & wxCONTROL_DISABLED ) - { - // the disabled indicators look the same as pressed ones in Windows - flags |= wxCONTROL_PRESSED; - } - - char **xpm; - if ( flags & wxCONTROL_CHECKED ) - { - xpm = flags & wxCONTROL_PRESSED ? pressed_checked_radio_xpm - : checked_radio_xpm; - } - else // unchecked - { - xpm = flags & wxCONTROL_PRESSED ? pressed_unchecked_radio_xpm - : unchecked_radio_xpm; - } - - return wxBitmap(xpm); + IndicatorStatus indStatus = flags & wxCONTROL_CHECKED + ? IndicatorStatus_Checked + : IndicatorStatus_Unchecked; + return wxBitmap(bmpIndicators[indType][indState][indStatus]); } void wxWin32Renderer::DrawCheckOrRadioButton(wxDC& dc,