/////////////////////////////////////////////////////////////////////////////
-// Name: univ/textctrl.cpp
+// Name: src/univ/textctrl.cpp
// Purpose: wxTextCtrl
// Author: Vadim Zeitlin
// Modified by:
// Created: 15.09.00
// RCS-ID: $Id$
-// Copyright: (c) 2000 Vadim Zeitlin
-// Licence: wxWindows license
+// Copyright: (c) 2000 SciTech Software, Inc. (www.scitechsoft.com)
+// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
/*
Everywhere in this file LINE refers to a logical line of text, and ROW to a
physical line of text on the display. They are the same unless WrapLines()
- is TRUE in which case a single LINE may correspond to multiple ROWs.
+ is true in which case a single LINE may correspond to multiple ROWs.
A text position is an unsigned int (which for reasons of compatibility is
- still a long) from 0 to GetLastPosition() inclusive. The positions
+ still a long as wxTextPos) from 0 to GetLastPosition() inclusive. The positions
correspond to the gaps between the letters so the position 0 is just
before the first character and the last position is the one beyond the last
character. For an empty text control GetLastPosition() returns 0.
// headers
// ----------------------------------------------------------------------------
-#ifdef __GNUG__
- #pragma implementation "univtextctrl.h"
-#endif
-
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#if wxUSE_TEXTCTRL
+#include "wx/textctrl.h"
+
#ifndef WX_PRECOMP
#include "wx/log.h"
-
#include "wx/dcclient.h"
#include "wx/validate.h"
- #include "wx/textctrl.h"
+ #include "wx/dataobj.h"
#endif
+#include <ctype.h>
+
#include "wx/clipbrd.h"
#include "wx/textfile.h"
#include "wx/tokenzr.h"
#endif // WXDEBUG_TEXT_REPLACE
+// ----------------------------------------------------------------------------
+// wxStdTextCtrlInputHandler: this control handles only the mouse/kbd actions
+// common to Win32 and GTK, platform-specific things are implemented elsewhere
+// ----------------------------------------------------------------------------
+
+class WXDLLEXPORT wxStdTextCtrlInputHandler : public wxStdInputHandler
+{
+public:
+ wxStdTextCtrlInputHandler(wxInputHandler *inphand);
+
+ virtual bool HandleKey(wxInputConsumer *consumer,
+ const wxKeyEvent& event,
+ bool pressed);
+ virtual bool HandleMouse(wxInputConsumer *consumer,
+ const wxMouseEvent& event);
+ virtual bool HandleMouseMove(wxInputConsumer *consumer,
+ const wxMouseEvent& event);
+ virtual bool HandleFocus(wxInputConsumer *consumer, const wxFocusEvent& event);
+
+protected:
+ // get the position of the mouse click
+ static wxTextPos HitTest(const wxTextCtrl *text, const wxPoint& pos);
+
+ // capture data
+ wxTextCtrl *m_winCapture;
+};
+
// ----------------------------------------------------------------------------
// private functions
// ----------------------------------------------------------------------------
// the value which is never used for text position, even not -1 which is
// sometimes used for some special meaning
-static const wxTextPos INVALID_POS_VALUE = -2;
+static const wxTextPos INVALID_POS_VALUE = wxInvalidTextCoord;
// overlap between pages (when using PageUp/Dn) in lines
static const size_t PAGE_OVERLAP_IN_LINES = 1;
// ----------------------------------------------------------------------------
// the data only used by single line text controls
-struct WXDLLEXPORT wxTextSingleLineData
+struct wxTextSingleLineData
{
// the position of the first visible pixel and the first visible column
wxCoord m_ofsHorz;
};
// the data only used by multi line text controls
-struct WXDLLEXPORT wxTextMultiLineData
+struct wxTextMultiLineData
{
// the lines of text
wxArrayString m_lines;
m_scrollRangeY = 0;
m_updateScrollbarX =
- m_updateScrollbarY = FALSE;
+ m_updateScrollbarY = false;
m_widthMax = -1;
m_lineLongest = 0;
};
// the data only used by multi line text controls in line wrap mode
-class WXDLLEXPORT wxWrappedLineData
+class wxWrappedLineData
{
// these functions set all our values, so give them access to them
friend void wxTextCtrl::LayoutLine(wxTextCoord line,
// this code is unused any longer
#if 0
- // return TRUE if the column is in the start of the last row (hence the row
+ // return true if the column is in the start of the last row (hence the row
// it is in is not wrapped)
bool IsLastRow(wxTextCoord colRowStart) const
{
return colRowStart == GetRowStart(m_rowsStart.GetCount());
}
- // return TRUE if the column is the last column of the row starting in
+ // return true if the column is the last column of the row starting in
// colRowStart
bool IsLastColInRow(wxTextCoord colRowStart,
wxTextCoord colRowEnd,
// caller got it wrong
wxFAIL_MSG( _T("this column is not in the start of the row!") );
- return FALSE;
+ return false;
}
#endif // 0
#include "wx/arrimpl.cpp"
WX_DEFINE_OBJARRAY(wxArrayWrappedLinesData);
-struct WXDLLEXPORT wxTextWrappedData : public wxTextMultiLineData
+struct wxTextWrappedData : public wxTextMultiLineData
{
// the width of the column to the right of the text rect used for the
// indicator mark display for the wrapped lines
// ----------------------------------------------------------------------------
/*
- We use custom versions of wxWindows command processor to implement undo/redo
+ We use custom versions of wxWidgets command processor to implement undo/redo
as we want to avoid storing the backpointer to wxTextCtrl in wxCommand
itself: this is a waste of memory as all commands in the given command
processor always have the same associated wxTextCtrl and so it makes sense
class wxTextCtrlCommand : public wxCommand
{
public:
- wxTextCtrlCommand(const wxString& name) : wxCommand(TRUE, name) { }
+ wxTextCtrlCommand(const wxString& name) : wxCommand(true, name) { }
// we don't use these methods as they don't make sense for us as we need a
// wxTextCtrl to be applied
- virtual bool Do() { wxFAIL_MSG(_T("shouldn't be called")); return FALSE; }
- virtual bool Undo() { wxFAIL_MSG(_T("shouldn't be called")); return FALSE; }
+ virtual bool Do() { wxFAIL_MSG(_T("shouldn't be called")); return false; }
+ virtual bool Undo() { wxFAIL_MSG(_T("shouldn't be called")); return false; }
// instead, our command processor uses these methods
virtual bool Do(wxTextCtrl *text) = 0;
virtual bool CanUndo() const;
virtual bool Do(wxTextCtrl *text);
+ virtual bool Do() { return wxTextCtrlCommand::Do(); }
+ virtual bool Undo() { return wxTextCtrlCommand::Undo(); }
virtual bool Undo(wxTextCtrl *text);
private:
virtual bool CanUndo() const;
virtual bool Do(wxTextCtrl *text);
+ virtual bool Do() { return wxTextCtrlCommand::Do(); }
+ virtual bool Undo() { return wxTextCtrlCommand::Undo(); }
virtual bool Undo(wxTextCtrl *text);
private:
public:
wxTextCtrlCommandProcessor(wxTextCtrl *text)
{
- m_compressInserts = FALSE;
+ m_compressInserts = false;
m_text = text;
}
virtual void Store(wxCommand *command);
// stop compressing insert commands when this is called
- void StopCompressing() { m_compressInserts = FALSE; }
+ void StopCompressing() { m_compressInserts = false; }
// accessors
wxTextCtrl *GetTextCtrl() const { return m_text; }
// the control we're associated with
wxTextCtrl *m_text;
- // if the flag is TRUE we're compressing subsequent insert commands into
+ // if the flag is true we're compressing subsequent insert commands into
// one so that the entire typing could be undone in one call to Undo()
bool m_compressInserts;
};
// implementation
// ============================================================================
-BEGIN_EVENT_TABLE(wxTextCtrl, wxControl)
+BEGIN_EVENT_TABLE(wxTextCtrl, wxTextCtrlBase)
EVT_CHAR(wxTextCtrl::OnChar)
EVT_SIZE(wxTextCtrl::OnSize)
-
- EVT_IDLE(wxTextCtrl::OnIdle)
END_EVENT_TABLE()
-IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl, wxControl)
+IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl, wxTextCtrlBase)
// ----------------------------------------------------------------------------
// creation
m_selStart =
m_selEnd = -1;
- m_isModified = FALSE;
- m_isEditable = TRUE;
+ m_isModified = false;
+ m_isEditable = true;
+ m_wrapLines = false;
m_posLast =
m_curPos =
m_heightLine =
m_widthAvg = -1;
- // init wxScrollHelper
- SetWindow(this);
-
// init the undo manager
m_cmdProcessor = new wxTextCtrlCommandProcessor(this);
style |= wxALWAYS_SHOW_SB;
}
- if ( style & wxTE_WORDWRAP )
- {
- // wrapping words means wrapping, hence no horz scrollbar
- style &= ~wxHSCROLL;
- }
+ // wrapping style: wxTE_DONTWRAP == wxHSCROLL so if it's _not_ given,
+ // we won't have horizontal scrollbar automatically, no need to do
+ // anything
// TODO: support wxTE_NO_VSCROLL (?)
// create data object for normal multiline or for controls with line
// wrap as needed
if ( style & wxHSCROLL )
+ {
m_data.mdata = new wxTextMultiLineData;
- else
+ }
+ else // we must wrap lines if we don't have horizontal scrollbar
+ {
+ // NB: we can't rely on HasFlag(wxHSCROLL) as the flags can change
+ // later and even wxWindow::Create() itself temporarily resets
+ // wxHSCROLL in wxUniv, so remember that we have a wrapped data
+ // and not just a multi line data in a separate variable
+ m_wrapLines = true;
m_data.wdata = new wxTextWrappedData;
+ }
}
else
{
m_data.sdata = new wxTextSingleLineData;
}
+#if wxUSE_TWO_WINDOWS
+ if ((style & wxBORDER_MASK) == 0)
+ style |= wxBORDER_SUNKEN;
+#endif
+
if ( !wxControl::Create(parent, id, pos, size, style,
validator, name) )
{
- return FALSE;
+ return false;
}
SetCursor(wxCURSOR_IBEAM);
RecalcFontMetrics();
SetValue(value);
- SetBestSize(size);
+ SetInitialSize(size);
m_isEditable = !(style & wxTE_READONLY);
// we can't show caret right now as we're not shown yet and so it would
// result in garbage on the screen - we'll do it after first OnPaint()
- m_hasCaret = FALSE;
+ m_hasCaret = false;
CreateInputHandler(wxINP_HANDLER_TEXTCTRL);
- return TRUE;
+ wxSizeEvent sizeEvent(GetSize(), GetId());
+ GetEventHandler()->ProcessEvent(sizeEvent);
+
+ return true;
}
wxTextCtrl::~wxTextCtrl()
// set/get the value
// ----------------------------------------------------------------------------
-void wxTextCtrl::SetValue(const wxString& value)
+void wxTextCtrl::DoSetValue(const wxString& value, int flags)
{
- if ( IsSingleLine() && (value == GetValue()) )
+ if ( value != GetValue() )
{
- // nothing changed
- return;
- }
+ EventsSuppressor noeventsIf(this, !(flags & SetValue_SendEvent));
- Replace(0, GetLastPosition(), value);
+ Replace(0, GetLastPosition(), value);
- if ( IsSingleLine() )
+ if ( IsSingleLine() )
+ {
+ SetInsertionPoint(0);
+ }
+ }
+ else // nothing changed
{
- SetInsertionPoint(0);
+ // still send event for consistency
+ if ( flags & SetValue_SendEvent )
+ SendTextUpdatedEvent();
}
-
- // TODO: should we generate the event or not, finally?
}
const wxArrayString& wxTextCtrl::GetLines() const
void wxTextCtrl::Clear()
{
- SetValue(_T(""));
+ SetValue(wxEmptyString);
}
bool wxTextCtrl::ReplaceLine(wxTextCoord line,
}
// the number of rows changed
- return TRUE;
+ return true;
}
}
else // no line wrap
}
// the number of rows didn't change
- return FALSE;
+ return false;
}
void wxTextCtrl::RemoveLine(wxTextCoord line)
// as if it does we need to refresh everything below the changed
// text (it will be shifted...) and we can avoid it if there is no
// row relayout
- bool rowsNumberChanged = FALSE;
+ bool rowsNumberChanged = false;
// (1) join lines
const wxArrayString& linesOld = GetLines();
// we have the replacement line for this one
if ( ReplaceLine(line, lines[nReplaceLine]) )
{
- rowsNumberChanged = TRUE;
+ rowsNumberChanged = true;
}
UpdateMaxWidth(line);
{
// (4b) delete all extra lines (note that we need to delete
// them backwards because indices shift while we do it)
- bool deletedLongestLine = FALSE;
+ bool deletedLongestLine = false;
for ( wxTextCoord lineDel = lineEnd; lineDel >= line; lineDel-- )
{
if ( lineDel == MData().m_lineLongest )
{
// we will need to recalc the max line width
- deletedLongestLine = TRUE;
+ deletedLongestLine = true;
}
RemoveLine(lineDel);
}
// even the line number changed
- rowsNumberChanged = TRUE;
+ rowsNumberChanged = true;
// update line to exit the loop
line = lineEnd + 1;
if ( nReplaceLine < nReplaceCount )
{
// even the line number changed
- rowsNumberChanged = TRUE;
+ rowsNumberChanged = true;
do
{
RefreshLineRange(lineEnd + 1, 0);
// the vert scrollbar might [dis]appear
- MData().m_updateScrollbarY = TRUE;
+ MData().m_updateScrollbarY = true;
}
// must recalculate it - will do later
// now call it to do the rest (not related to refreshing)
ClearSelection();
+
+ if ( EventsAllowed() )
+ SendTextUpdatedEvent();
}
void wxTextCtrl::Remove(wxTextPos from, wxTextPos to)
// if necessary
OrderPositions(from, to);
- Replace(from, to, _T(""));
+ Replace(from, to, wxEmptyString);
}
void wxTextCtrl::WriteText(const wxString& text)
void wxTextCtrl::SetSelection(wxTextPos from, wxTextPos to)
{
// selecting till -1 is the same as selecting to the end
- if ( to == -1 && from != -1 )
+ if ( to == -1 )
{
+ // and selecting (-1, -1) range is the same as selecting everything, by
+ // convention
+ if ( from == -1 )
+ from = 0;
to = GetLastPosition();
}
}
else // valid sel range
{
+ // remember the 'to' position as the current position, used to move the
+ // caret there later
+ wxTextPos toOrig = to;
+
OrderPositions(from, to);
wxCHECK_RET( to <= GetLastPosition(),
}
//else: nothing to do
- // the insertion point is put at the end of selection
- DoSetInsertionPoint(to);
+ // the insertion point is put at the location where the caret was moved
+ DoSetInsertionPoint(toOrig);
}
}
if ( !HasSelection() )
{
// no selection at all, hence no selection in this line
- return FALSE;
+ return false;
}
wxTextCoord lineStart, colStart;
if ( lineStart > line )
{
// this line is entirely above the selection
- return FALSE;
+ return false;
}
wxTextCoord lineEnd, colEnd;
if ( lineEnd < line )
{
// this line is entirely below the selection
- return FALSE;
+ return false;
}
if ( line == lineStart )
*end = GetLineLength(line);
}
- return TRUE;
+ return true;
}
// ----------------------------------------------------------------------------
return m_isEditable && IsEnabled();
}
+void wxTextCtrl::MarkDirty()
+{
+ m_isModified = true;
+}
+
void wxTextCtrl::DiscardEdits()
{
- m_isModified = FALSE;
+ m_isModified = false;
}
void wxTextCtrl::SetEditable(bool editable)
}
else // multiline
{
- wxCHECK_MSG( (size_t)line < GetLineCount(), _T(""),
+ //this is called during DoGetBestSize
+ if (line == 0 && GetLineCount() == 0) return wxEmptyString ;
+
+ wxCHECK_MSG( (size_t)line < GetLineCount(), wxEmptyString,
_T("line index out of range") );
return GetLines()[line];
// if they are out of range
if ( IsSingleLine() )
{
- return x > GetLastPosition() || y > 0 ? -1 : x;
+ return ( x > GetLastPosition() || y > 0 ) ? wxOutOfRangeTextCoord : x;
}
else // multiline
{
if ( IsSingleLine() )
{
if ( (size_t)pos > m_value.length() )
- return FALSE;
+ return false;
if ( x )
*x = pos;
if ( y )
*y = 0;
- return TRUE;
+ return true;
}
else // multiline
{
_T("XYToPosition() or PositionToXY() broken") );
#endif // WXDEBUG_TEXT
- return TRUE;
+ return true;
}
else // go further down
{
}
// beyond the last line
- return FALSE;
+ return false;
}
}
wxTextCoord wxTextCtrl::GetRowCount() const
{
wxTextCoord count = GetLineCount();
+ if (count == 0)
+ return 0;
if ( WrapLines() )
{
count = GetFirstRowOfLine(count - 1) +
else // must really calculate col/line from pos
{
if ( !PositionToXY(pos, &col, &line) )
- return FALSE;
+ return false;
}
int hLine = GetLineHeight();
if ( yOut )
*yOut = y;
- return TRUE;
+ return true;
}
bool wxTextCtrl::PositionToDeviceXY(wxTextPos pos,
{
wxCoord x, y;
if ( !PositionToLogicalXY(pos, &x, &y) )
- return FALSE;
+ return false;
// finally translate the logical text rect coords into physical client
// coords
CalcScrolledPosition(m_rectText.x + x, m_rectText.y + y, xOut, yOut);
- return TRUE;
+ return true;
}
wxPoint wxTextCtrl::GetCaretPosition() const
// pos may be -1 to show the current position
void wxTextCtrl::ShowPosition(wxTextPos pos)
{
- HideCaret();
+ bool showCaret = GetCaret() && GetCaret()->IsVisible();
+ if (showCaret)
+ HideCaret();
if ( IsSingleLine() )
{
{
// finding the last line is easy if each line has exactly
// one row
- yEnd = yStart + rectText.height / GetLineHeight() - 1;
+ yEnd = yStart + rectText.height / GetLineHeight();
}
if ( yEnd < y )
}
//else: multiline but no scrollbars, hence nothing to do
- ShowCaret();
+ if (showCaret)
+ ShowCaret();
}
// ----------------------------------------------------------------------------
bool wxTextCtrl::DoCut()
{
if ( !HasSelection() )
- return FALSE;
+ return false;
Copy();
RemoveSelection();
- return TRUE;
+ return true;
}
void wxTextCtrl::Paste()
{
WriteText(text);
- return TRUE;
+ return true;
}
}
#endif // wxUSE_CLIPBOARD
- return FALSE;
+ return false;
}
// ----------------------------------------------------------------------------
}
// append the following insert commands to this one
- m_compressInserts = TRUE;
+ m_compressInserts = true;
// let the base class version will do the job normally
}
// and now do insert it
text->WriteText(m_text);
- return TRUE;
+ return true;
}
bool wxTextCtrlInsertCommand::Undo(wxTextCtrl *text)
{
- wxCHECK_MSG( CanUndo(), FALSE, _T("impossible to undo insert cmd") );
+ wxCHECK_MSG( CanUndo(), false, _T("impossible to undo insert cmd") );
// remove the text from where we inserted it
text->Remove(m_from, m_from + m_text.length());
- return TRUE;
+ return true;
}
bool wxTextCtrlRemoveCommand::CanUndo() const
m_textDeleted = text->GetSelectionText();
text->RemoveSelection();
- return TRUE;
+ return true;
}
bool wxTextCtrlRemoveCommand::Undo(wxTextCtrl *text)
text->SetInsertionPoint(m_from > posLast ? posLast : m_from);
text->WriteText(m_textDeleted);
- return TRUE;
+ return true;
}
void wxTextCtrl::Undo()
lines = 5;
else if ( lines > 10 )
lines = 10;
- h *= 10;
+ h *= lines;
}
wxRect rectText;
void wxTextCtrl::UpdateTextRect()
{
- wxRect rectTotal(wxPoint(0, 0), GetClientSize());
+ wxRect rectTotal(GetClientSize());
wxCoord *extraSpace = WrapLines() ? &WData().m_widthMark : NULL;
m_rectText = GetRenderer()->GetTextClientArea(this, rectTotal, extraSpace);
WData().m_rowFirstInvalid = 0;
// increase timestamp: this means that the lines which had been
- // laid out before will be relayd out the next time LayoutLines()
+ // laid out before will be relaid out the next time LayoutLines()
// is called because their timestamp will be smaller than the
// current one
WData().m_timestamp++;
{
case wxTE_HT_BEYOND:
// everything is visible
+ SData().m_ofsHorz = 0;
+
+ SData().m_colStart = 0;
SData().m_colLastVisible = text.length();
- // calc it below
+ // calculate it below
SData().m_posLastVisible = -1;
break;
SData().m_colLastVisible += SData().m_colStart;
wxLogTrace(_T("text"), _T("Last visible column/position is %d/%ld"),
- SData().m_colLastVisible, SData().m_posLastVisible);
+ (int) SData().m_colLastVisible, (long) SData().m_posLastVisible);
}
void wxTextCtrl::OnSize(wxSizeEvent& event)
#endif // 0
MData().m_updateScrollbarX =
- MData().m_updateScrollbarY = TRUE;
+ MData().m_updateScrollbarY = true;
}
event.Skip();
wxString s(text);
wxTextCoord col;
- wxCoord wReal = -1;
+ wxCoord wReal = wxDefaultCoord;
switch ( HitTestLine(s, m_rectText.width, &col) )
{
/*
col--;
// recalc the width
- wReal = -1;
+ wReal = wxDefaultCoord;
}
//else: we can just see it
// wrap at any character or only at words boundaries?
- if ( !(GetWindowStyle() & wxTE_LINEWRAP) )
+ if ( !(GetWindowStyle() & wxTE_CHARWRAP) )
{
// find the (last) not word char before this word
wxTextCoord colWordStart;
if ( colWordStart != col )
{
// will have to recalc the real width
- wReal = -1;
+ wReal = wxDefaultCoord;
col = colWordStart;
}
if ( widthReal )
{
- if ( wReal == -1 )
+ if ( wReal == wxDefaultCoord )
{
// calc it if not done yet
wReal = GetTextWidth(s.Truncate(col));
return res;
}
+wxTextCtrlHitTestResult wxTextCtrl::HitTest(const wxPoint& pt, long *pos) const
+{
+ wxTextCoord x, y;
+ wxTextCtrlHitTestResult rc = HitTest(pt, &x, &y);
+ if ( rc != wxTE_HT_UNKNOWN && pos )
+ {
+ *pos = XYToPosition(x, y);
+ }
+
+ return rc;
+}
+
wxTextCtrlHitTestResult wxTextCtrl::HitTest(const wxPoint& pos,
wxTextCoord *colOut,
wxTextCoord *rowOut) const
wxTextCoord *colOut,
wxTextCoord *rowOut) const
{
- return HitTest2(pos.y, pos.x, 0, rowOut, colOut, NULL, NULL, FALSE);
+ return HitTest2(pos.y, pos.x, 0, rowOut, colOut, NULL, NULL, false);
}
wxTextCtrlHitTestResult wxTextCtrl::HitTest2(wxCoord y0,
rowInLine = 0;
if ( row < 0 )
- return FALSE;
+ return false;
int nLines = GetNumberOfLines();
if ( WrapLines() )
if ( line == nLines )
{
// the row is out of range
- return FALSE;
+ return false;
}
}
else // no line wrapping, everything is easy
{
if ( row >= nLines )
- return FALSE;
+ return false;
line = row;
}
if ( rowInLineOut )
*rowInLineOut = rowInLine;
- return TRUE;
+ return true;
}
// ----------------------------------------------------------------------------
fine for vertical scrolling as all lines have the same height but is rather
ugly for horizontal scrolling if proportional font is used. This is why we
manually update and use SData().m_ofsHorz which contains the length of the string
- which is hidden beyond the left borde. An important property of text
+ which is hidden beyond the left border. An important property of text
controls using this kind of scrolling is that an entire number of characters
is always shown and that parts of characters never appear on display -
neither in the leftmost nor rightmost positions.
// pos is the logical position to show
- // SData().m_ofsHorz is the fisrt logical position shown
+ // SData().m_ofsHorz is the first logical position shown
if ( pos < SData().m_ofsHorz )
{
// scroll backwards
if ( dx > 0 )
{
// refresh the uncovered part on the left
- Refresh(TRUE, &rect);
+ Refresh(true, &rect);
// and now the area on the right
rect.x = m_rectText.x + posLastVisible;
rect.width += m_rectText.width - posLastVisible;
}
- Refresh(TRUE, &rect);
+ Refresh(true, &rect);
// I don't know exactly why is this needed here but without it we may
// scroll the window again (from the same method) before the previously
// just to suppress compiler warnings about using uninit vars below
charWidth = maxWidth = 0;
- showScrollbarX = FALSE;
+ showScrollbarX = false;
}
// calc the scrollbars ranges
SetScrollbars(charWidth, lineHeight,
scrollRangeX, scrollRangeY,
x, y,
- TRUE /* no refresh */);
+ true /* no refresh */);
if ( scrollRangeXOld )
{
- x *= scrollRangeX - m_rectText.width / charWidth;
- x /= scrollRangeXOld - m_rectText.width / charWidth;
+ const int w = m_rectText.width / charWidth;
+ if ( w != scrollRangeXOld )
+ {
+ x *= scrollRangeX - w;
+ x /= scrollRangeXOld - w;
+ }
Scroll(x, y);
}
}
MData().m_updateScrollbarX =
- MData().m_updateScrollbarY = FALSE;
+ MData().m_updateScrollbarY = false;
}
-void wxTextCtrl::OnIdle(wxIdleEvent& event)
+void wxTextCtrl::OnInternalIdle()
{
// notice that single line text control never has scrollbars
if ( !IsSingleLine() &&
{
UpdateScrollbars();
}
-
- event.Skip();
+ wxControl::OnInternalIdle();
}
bool wxTextCtrl::SendAutoScrollEvents(wxScrollWinEvent& event) const
{
// intermediate line or the last one but we need to refresh it
// until the end anyhow - do it
- posCount = wxSTRING_MAXLEN;
+ posCount = wxString::npos;
}
else // last line
{
rect.Offset(m_rectText.GetPosition());
// don't refresh beyond the text area unless we're refreshing the line wrap
- // marks in which case textOnly is FALSE
+ // marks in which case textOnly is false
if ( textOnly )
{
if ( rect.GetRight() > m_rectText.GetRight() )
wxLogTrace(_T("text"), _T("Refreshing (%d, %d)-(%d, %d)"),
rect.x, rect.y, rect.x + rect.width, rect.y + rect.height);
- Refresh(TRUE, &rect);
+ Refresh(true, &rect);
}
void wxTextCtrl::RefreshLineWrapMarks(wxTextCoord rowFirst,
rectMarks.y = rowFirst*GetLineHeight();
rectMarks.height = (rowLast - rowFirst)*GetLineHeight();
- RefreshTextRect(rectMarks, FALSE /* don't limit to text area */);
+ RefreshTextRect(rectMarks, false /* don't limit to text area */);
}
}
// the update region is in window coords and text area is in the client
// ones, so it must be shifted before computing intersection
wxRegion rgnUpdate = GetUpdateRegion();
+
wxRect rectTextArea = GetRealTextArea();
wxPoint pt = GetClientAreaOrigin();
wxRect rectTextAreaAdjusted = rectTextArea;
// FIXME: is this really a bug in wxMSW?
rectTextArea.width--;
#endif // __WXMSW__
+ dc.DestroyClippingRegion();
dc.SetClippingRegion(rectTextArea);
// adjust for scrolling
// show caret first time only: we must show it after drawing the text or
// the display can be corrupted when it's hidden
- if ( !m_hasCaret && GetCaret() )
+ if ( !m_hasCaret && GetCaret() && (FindFocus() == this) )
{
ShowCaret();
- m_hasCaret = TRUE;
+ m_hasCaret = true;
}
}
bool wxTextCtrl::SetFont(const wxFont& font)
{
if ( !wxControl::SetFont(font) )
- return FALSE;
+ return false;
// and refresh everything, of course
InitInsertionPoint();
Refresh();
- return TRUE;
+ return true;
}
bool wxTextCtrl::Enable(bool enable)
{
if ( !wxTextCtrlBase::Enable(enable) )
- return FALSE;
+ return false;
- ShowCaret(enable);
+ if (FindFocus() == this && GetCaret() &&
+ ((enable && !GetCaret()->IsVisible()) ||
+ (!enable && GetCaret()->IsVisible())))
+ ShowCaret(enable);
- return TRUE;
+ return true;
}
void wxTextCtrl::CreateCaret()
{
// FIXME use renderer
caret = new wxCaret(this, 1, GetLineHeight());
-#ifndef __WXMSW__
- caret->SetBlinkTime(0);
-#endif // __WXMSW__
}
else
{
caret->Move(GetCaretPosition());
// and show it there
- caret->Show(show);
+ if ((show && !caret->IsVisible()) ||
+ (!show && caret->IsVisible()))
+ caret->Show(show);
}
}
const wxString& strArg)
{
// has the text changed as result of this action?
- bool textChanged = FALSE;
+ bool textChanged = false;
// the remembered cursor abscissa for multiline text controls is usually
// reset after each user action but for ones which do use it (UP and DOWN
// for example) we shouldn't do it - as indicated by this flag
- bool rememberAbscissa = FALSE;
+ bool rememberAbscissa = false;
// the command this action corresponds to or NULL if this action doesn't
// change text at all or can't be undone
wxTextCtrlCommand *command = (wxTextCtrlCommand *)NULL;
wxString action;
- bool del = FALSE,
- sel = FALSE;
+ bool del = false,
+ sel = false;
if ( actionOrig.StartsWith(wxACTION_TEXT_PREFIX_DEL, &action) )
{
if ( IsEditable() )
- del = TRUE;
+ del = true;
}
else if ( actionOrig.StartsWith(wxACTION_TEXT_PREFIX_SEL, &action) )
{
- sel = TRUE;
+ sel = true;
}
else // not selection nor delete action
{
if ( newPos != INVALID_POS_VALUE )
{
// remember where the cursor original had been
- rememberAbscissa = TRUE;
+ rememberAbscissa = true;
}
}
}
if ( newPos != INVALID_POS_VALUE )
{
// remember where the cursor original had been
- rememberAbscissa = TRUE;
+ rememberAbscissa = true;
}
}
}
// inserting text can be undone
command = new wxTextCtrlInsertCommand(strArg);
- textChanged = TRUE;
+ textChanged = true;
}
}
else if ( (action == wxACTION_TEXT_PAGE_UP) ||
}
// remember where the cursor original had been
- rememberAbscissa = TRUE;
+ rememberAbscissa = true;
bool goUp = action == wxACTION_TEXT_PAGE_UP;
for ( size_t line = 0; line < count; line++ )
}
// scroll vertically only
- Scroll(-1, y);
+ Scroll(wxDefaultCoord, y);
}
}
else if ( action == wxACTION_TEXT_SEL_WORD )
m_cmdProcessor->Submit(command);
// undoable commands always change text
- textChanged = TRUE;
+ textChanged = true;
}
else // no undoable command
{
wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, GetId());
InitCommandEvent(event);
- event.SetString(GetValue());
GetEventHandler()->ProcessEvent(event);
// as the text changed...
- m_isModified = TRUE;
+ m_isModified = true;
}
- return TRUE;
+ return true;
}
void wxTextCtrl::OnChar(wxKeyEvent& event)
if ( !event.HasModifiers() )
{
int keycode = event.GetKeyCode();
+#if wxUSE_UNICODE
+ wxChar unicode = event.GetUnicodeKey();
+#endif
if ( keycode == WXK_RETURN )
{
if ( IsSingleLine() || (GetWindowStyle() & wxTE_PROCESS_ENTER) )
// skip event.Skip() below
return;
}
+#if wxUSE_UNICODE
+ else if (unicode > 0)
+ {
+ PerformAction(wxACTION_TEXT_INSERT, -1, unicode);
+
+ return;
+ }
+#endif
}
#ifdef __WXDEBUG__
// Ctrl-R refreshes the control in debug mode
event.Skip();
}
+/* static */
+wxInputHandler *wxTextCtrl::GetStdInputHandler(wxInputHandler *handlerDef)
+{
+ static wxStdTextCtrlInputHandler s_handler(handlerDef);
+
+ return &s_handler;
+}
+
// ----------------------------------------------------------------------------
// wxStdTextCtrlInputHandler
// ----------------------------------------------------------------------------
return pos;
}
-bool wxStdTextCtrlInputHandler::HandleKey(wxControl *control,
+bool wxStdTextCtrlInputHandler::HandleKey(wxInputConsumer *consumer,
const wxKeyEvent& event,
bool pressed)
{
// we're only interested in key presses
if ( !pressed )
- return FALSE;
+ return false;
int keycode = event.GetKeyCode();
break;
case WXK_PAGEDOWN:
- case WXK_NEXT:
// we don't map Ctrl-PgUp/Dn to anything special - what should it
// to? for now, it's the same as without control
action << wxACTION_TEXT_PAGE_DOWN;
break;
case WXK_PAGEUP:
- case WXK_PRIOR:
action << wxACTION_TEXT_PAGE_UP;
break;
if ( (action != wxACTION_NONE) && (action != wxACTION_TEXT_PREFIX_SEL) )
{
- control->PerformAction(action, -1, str);
+ consumer->PerformAction(action, -1, str);
- return TRUE;
+ return true;
}
- return wxStdInputHandler::HandleKey(control, event, pressed);
+ return wxStdInputHandler::HandleKey(consumer, event, pressed);
}
-bool wxStdTextCtrlInputHandler::HandleMouse(wxControl *control,
+bool wxStdTextCtrlInputHandler::HandleMouse(wxInputConsumer *consumer,
const wxMouseEvent& event)
{
if ( event.LeftDown() )
{
wxASSERT_MSG( !m_winCapture, _T("left button going down twice?") );
- wxTextCtrl *text = wxStaticCast(control, wxTextCtrl);
+ wxTextCtrl *text = wxStaticCast(consumer->GetInputWindow(), wxTextCtrl);
m_winCapture = text;
m_winCapture->CaptureMouse();
else if ( event.LeftDClick() )
{
// select the word the cursor is on
- control->PerformAction(wxACTION_TEXT_SEL_WORD);
+ consumer->PerformAction(wxACTION_TEXT_SEL_WORD);
}
else if ( event.LeftUp() )
{
}
}
- return wxStdInputHandler::HandleMouse(control, event);
+ return wxStdInputHandler::HandleMouse(consumer, event);
}
-bool wxStdTextCtrlInputHandler::HandleMouseMove(wxControl *control,
+bool wxStdTextCtrlInputHandler::HandleMouseMove(wxInputConsumer *consumer,
const wxMouseEvent& event)
{
if ( m_winCapture )
}
}
- return wxStdInputHandler::HandleMouseMove(control, event);
+ return wxStdInputHandler::HandleMouseMove(consumer, event);
}
-bool wxStdTextCtrlInputHandler::HandleFocus(wxControl *control,
- const wxFocusEvent& event)
+bool
+wxStdTextCtrlInputHandler::HandleFocus(wxInputConsumer *consumer,
+ const wxFocusEvent& event)
{
- wxTextCtrl *text = wxStaticCast(control, wxTextCtrl);
+ wxTextCtrl *text = wxStaticCast(consumer->GetInputWindow(), wxTextCtrl);
// the selection appearance changes depending on whether we have the focus
text->RefreshSelection();
+ if (event.GetEventType() == wxEVT_SET_FOCUS)
+ {
+ if (text->GetCaret() && !text->GetCaret()->IsVisible())
+ text->ShowCaret();
+ }
+ else
+ {
+ if (text->GetCaret() && text->GetCaret()->IsVisible())
+ text->HideCaret();
+ }
+
// never refresh entirely
- return FALSE;
+ return false;
}
#endif // wxUSE_TEXTCTRL