1. fix for generation of mouse enter/leave events in wxMSW

2. render disabled check/radio box [more] correctly
3. several bug fixes with m_posLast caching
4. implemented wxTextCtrl word (as opposed to line) wrap
5. problem with selection refresh in line wrap style fixed


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/wxUNIVERSAL@8827 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2000-11-26 04:36:33 +00:00
parent 20b45caa12
commit 528a112b2c
5 changed files with 244 additions and 97 deletions

View File

@@ -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

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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,