This could easily result in infinite recursion, as it is very natural to implement DoGetBestSize() in terms of GetSizeFromTextSize() and, in fact, our own implementation of the generic wxSpinCtrl did exactly this. Avoid such problems by only calling GetSizeFromTextSize() from DoGetBestSize(), but not in the other direction. This shouldn't have any effect on the returned size values.
792 lines
19 KiB
C++
792 lines
19 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: src/osx/textctrl_osx.cpp
|
|
// Purpose: wxTextCtrl
|
|
// Author: Stefan Csomor
|
|
// Modified by: Ryan Norton (MLTE GetLineLength and GetLineText)
|
|
// Created: 1998-01-01
|
|
// Copyright: (c) Stefan Csomor
|
|
// Licence: wxWindows licence
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "wx/wxprec.h"
|
|
|
|
#if wxUSE_TEXTCTRL
|
|
|
|
#include "wx/textctrl.h"
|
|
|
|
#ifndef WX_PRECOMP
|
|
#include "wx/intl.h"
|
|
#include "wx/app.h"
|
|
#include "wx/utils.h"
|
|
#include "wx/dc.h"
|
|
#include "wx/button.h"
|
|
#include "wx/menu.h"
|
|
#include "wx/settings.h"
|
|
#include "wx/msgdlg.h"
|
|
#include "wx/toplevel.h"
|
|
#endif
|
|
|
|
#ifdef __DARWIN__
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#else
|
|
#include <stat.h>
|
|
#endif
|
|
|
|
#if wxUSE_STD_IOSTREAM
|
|
#include <fstream>
|
|
#endif
|
|
|
|
#include "wx/filefn.h"
|
|
#include "wx/sysopt.h"
|
|
#include "wx/thread.h"
|
|
|
|
#include "wx/osx/private.h"
|
|
|
|
wxBEGIN_EVENT_TABLE(wxTextCtrl, wxTextCtrlBase)
|
|
EVT_DROP_FILES(wxTextCtrl::OnDropFiles)
|
|
EVT_CHAR(wxTextCtrl::OnChar)
|
|
EVT_KEY_DOWN(wxTextCtrl::OnKeyDown)
|
|
EVT_MENU(wxID_CUT, wxTextCtrl::OnCut)
|
|
EVT_MENU(wxID_COPY, wxTextCtrl::OnCopy)
|
|
EVT_MENU(wxID_PASTE, wxTextCtrl::OnPaste)
|
|
EVT_MENU(wxID_UNDO, wxTextCtrl::OnUndo)
|
|
EVT_MENU(wxID_REDO, wxTextCtrl::OnRedo)
|
|
EVT_MENU(wxID_CLEAR, wxTextCtrl::OnDelete)
|
|
EVT_MENU(wxID_SELECTALL, wxTextCtrl::OnSelectAll)
|
|
|
|
EVT_CONTEXT_MENU(wxTextCtrl::OnContextMenu)
|
|
|
|
EVT_UPDATE_UI(wxID_CUT, wxTextCtrl::OnUpdateCut)
|
|
EVT_UPDATE_UI(wxID_COPY, wxTextCtrl::OnUpdateCopy)
|
|
EVT_UPDATE_UI(wxID_PASTE, wxTextCtrl::OnUpdatePaste)
|
|
EVT_UPDATE_UI(wxID_UNDO, wxTextCtrl::OnUpdateUndo)
|
|
EVT_UPDATE_UI(wxID_REDO, wxTextCtrl::OnUpdateRedo)
|
|
EVT_UPDATE_UI(wxID_CLEAR, wxTextCtrl::OnUpdateDelete)
|
|
EVT_UPDATE_UI(wxID_SELECTALL, wxTextCtrl::OnUpdateSelectAll)
|
|
wxEND_EVENT_TABLE()
|
|
|
|
|
|
void wxTextCtrl::Init()
|
|
{
|
|
m_dirty = false;
|
|
|
|
m_privateContextMenu = NULL;
|
|
}
|
|
|
|
wxTextCtrl::~wxTextCtrl()
|
|
{
|
|
#if wxUSE_MENUS
|
|
delete m_privateContextMenu;
|
|
#endif
|
|
}
|
|
|
|
bool wxTextCtrl::Create( wxWindow *parent,
|
|
wxWindowID id,
|
|
const wxString& str,
|
|
const wxPoint& pos,
|
|
const wxSize& size,
|
|
long style,
|
|
const wxValidator& validator,
|
|
const wxString& name )
|
|
{
|
|
DontCreatePeer();
|
|
m_editable = true ;
|
|
|
|
if ( ! (style & wxNO_BORDER) )
|
|
style = (style & ~wxBORDER_MASK) | wxSUNKEN_BORDER ;
|
|
|
|
if ( !wxTextCtrlBase::Create( parent, id, pos, size, style & ~(wxHSCROLL | wxVSCROLL), validator, name ) )
|
|
return false;
|
|
|
|
SetPeer(wxWidgetImpl::CreateTextControl( this, GetParent(), GetId(), str, pos, size, style, GetExtraStyle() ));
|
|
|
|
MacPostControlCreate(pos, size) ;
|
|
|
|
// only now the embedding is correct and we can do a positioning update
|
|
|
|
MacSuperChangedPosition() ;
|
|
|
|
if ( m_windowStyle & wxTE_READONLY)
|
|
SetEditable( false ) ;
|
|
|
|
SetCursor( wxCursor( wxCURSOR_IBEAM ) ) ;
|
|
|
|
return true;
|
|
}
|
|
|
|
void wxTextCtrl::MacSuperChangedPosition()
|
|
{
|
|
wxWindow::MacSuperChangedPosition() ;
|
|
}
|
|
|
|
void wxTextCtrl::MacVisibilityChanged()
|
|
{
|
|
}
|
|
|
|
void wxTextCtrl::MacCheckSpelling(bool check)
|
|
{
|
|
GetTextPeer()->CheckSpelling(check);
|
|
}
|
|
|
|
void wxTextCtrl::OSXEnableAutomaticQuoteSubstitution(bool enable)
|
|
{
|
|
GetTextPeer()->EnableAutomaticQuoteSubstitution(enable);
|
|
}
|
|
|
|
void wxTextCtrl::OSXEnableAutomaticDashSubstitution(bool enable)
|
|
{
|
|
GetTextPeer()->EnableAutomaticDashSubstitution(enable);
|
|
}
|
|
|
|
void wxTextCtrl::OSXDisableAllSmartSubstitutions()
|
|
{
|
|
OSXEnableAutomaticDashSubstitution(false);
|
|
OSXEnableAutomaticQuoteSubstitution(false);
|
|
}
|
|
|
|
bool wxTextCtrl::SetFont( const wxFont& font )
|
|
{
|
|
if ( !wxTextCtrlBase::SetFont( font ) )
|
|
return false ;
|
|
|
|
GetPeer()->SetFont( font , GetForegroundColour() , GetWindowStyle(), false /* dont ignore black */ ) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
bool wxTextCtrl::SetStyle(long start, long end, const wxTextAttr& style)
|
|
{
|
|
if (GetTextPeer())
|
|
GetTextPeer()->SetStyle( start , end , style ) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
bool wxTextCtrl::SetDefaultStyle(const wxTextAttr& style)
|
|
{
|
|
wxTextCtrlBase::SetDefaultStyle( style ) ;
|
|
SetStyle( -1 /*current selection*/ , -1 /*current selection*/ , GetDefaultStyle() ) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
bool wxTextCtrl::IsModified() const
|
|
{
|
|
return m_dirty;
|
|
}
|
|
|
|
wxSize wxTextCtrl::DoGetBestSize() const
|
|
{
|
|
wxSize size;
|
|
if (GetTextPeer())
|
|
size = GetTextPeer()->GetBestSize();
|
|
|
|
// Normally the width passed to GetSizeFromTextSize() is supposed to be
|
|
// valid, i.e. positive, but we use our knowledge of its implementation
|
|
// just below to rely on it returning the default size if we don't have
|
|
// any valid best size in the peer and size remained default-initialized.
|
|
return GetSizeFromTextSize(size);
|
|
}
|
|
|
|
wxSize wxTextCtrl::DoGetSizeFromTextSize(int xlen, int ylen) const
|
|
{
|
|
static const int TEXTCTRL_BORDER_SIZE = 5;
|
|
|
|
// Compute the default height if not specified.
|
|
int hText = ylen;
|
|
if ( hText <= 0 )
|
|
{
|
|
// these are the numbers from the HIG:
|
|
switch ( m_windowVariant )
|
|
{
|
|
case wxWINDOW_VARIANT_NORMAL :
|
|
hText = 22;
|
|
break ;
|
|
|
|
case wxWINDOW_VARIANT_SMALL :
|
|
hText = 19;
|
|
break ;
|
|
|
|
case wxWINDOW_VARIANT_MINI :
|
|
hText = 15;
|
|
break ;
|
|
|
|
default :
|
|
hText = 22;
|
|
break ;
|
|
}
|
|
|
|
// the numbers above include the border size, so subtract it before
|
|
// possibly adding it back below
|
|
hText -= TEXTCTRL_BORDER_SIZE;
|
|
|
|
// make the control 5 lines tall by default for consistently with how
|
|
// the old code behaved
|
|
if ( m_windowStyle & wxTE_MULTILINE )
|
|
hText *= 5 ;
|
|
}
|
|
|
|
// Keep using the same default 100px width as was used previously in the
|
|
// special case of having invalid width.
|
|
wxSize size(xlen > 0 ? xlen : 100, hText);
|
|
|
|
// Use extra margin size which works under macOS 10.15: note that we don't
|
|
// need the vertical margin when using the automatically determined hText.
|
|
if ( xlen > 0 )
|
|
size.x += 4;
|
|
if ( ylen > 0 )
|
|
size.y += 2;
|
|
|
|
if ( !HasFlag(wxNO_BORDER) )
|
|
size += wxSize(TEXTCTRL_BORDER_SIZE, TEXTCTRL_BORDER_SIZE) ;
|
|
|
|
return size;
|
|
}
|
|
|
|
bool wxTextCtrl::GetStyle(long position, wxTextAttr& style)
|
|
{
|
|
return GetTextPeer()->GetStyle(position, style);
|
|
}
|
|
|
|
void wxTextCtrl::MarkDirty()
|
|
{
|
|
m_dirty = true;
|
|
}
|
|
|
|
void wxTextCtrl::DiscardEdits()
|
|
{
|
|
m_dirty = false;
|
|
}
|
|
|
|
int wxTextCtrl::GetNumberOfLines() const
|
|
{
|
|
return GetTextPeer()->GetNumberOfLines() ;
|
|
}
|
|
|
|
long wxTextCtrl::XYToPosition(long x, long y) const
|
|
{
|
|
return GetTextPeer()->XYToPosition( x , y ) ;
|
|
}
|
|
|
|
bool wxTextCtrl::PositionToXY(long pos, long *x, long *y) const
|
|
{
|
|
return GetTextPeer()->PositionToXY( pos , x , y ) ;
|
|
}
|
|
|
|
void wxTextCtrl::ShowPosition(long pos)
|
|
{
|
|
return GetTextPeer()->ShowPosition(pos) ;
|
|
}
|
|
|
|
int wxTextCtrl::GetLineLength(long lineNo) const
|
|
{
|
|
return GetTextPeer()->GetLineLength(lineNo) ;
|
|
}
|
|
|
|
wxString wxTextCtrl::GetLineText(long lineNo) const
|
|
{
|
|
return GetTextPeer()->GetLineText(lineNo) ;
|
|
}
|
|
|
|
void wxTextCtrl::Copy()
|
|
{
|
|
if (CanCopy())
|
|
{
|
|
wxClipboardTextEvent evt(wxEVT_TEXT_COPY, GetId());
|
|
evt.SetEventObject(this);
|
|
if (!GetEventHandler()->ProcessEvent(evt))
|
|
{
|
|
wxTextEntry::Copy();
|
|
}
|
|
}
|
|
}
|
|
|
|
void wxTextCtrl::Cut()
|
|
{
|
|
if (CanCut())
|
|
{
|
|
wxClipboardTextEvent evt(wxEVT_TEXT_CUT, GetId());
|
|
evt.SetEventObject(this);
|
|
if (!GetEventHandler()->ProcessEvent(evt))
|
|
{
|
|
wxTextEntry::Cut();
|
|
|
|
SendTextUpdatedEvent();
|
|
}
|
|
}
|
|
}
|
|
|
|
void wxTextCtrl::Paste()
|
|
{
|
|
if (CanPaste())
|
|
{
|
|
wxClipboardTextEvent evt(wxEVT_TEXT_PASTE, GetId());
|
|
evt.SetEventObject(this);
|
|
if (!GetEventHandler()->ProcessEvent(evt))
|
|
{
|
|
wxTextEntry::Paste();
|
|
|
|
// TODO: eventually we should add setting the default style again
|
|
SendTextUpdatedEvent();
|
|
}
|
|
}
|
|
}
|
|
|
|
void wxTextCtrl::OnDropFiles(wxDropFilesEvent& event)
|
|
{
|
|
// By default, load the first file into the text window.
|
|
if (event.GetNumberOfFiles() > 0)
|
|
LoadFile( event.GetFiles()[0] );
|
|
}
|
|
|
|
void wxTextCtrl::OnKeyDown(wxKeyEvent& event)
|
|
{
|
|
if ( event.GetModifiers() == wxMOD_CONTROL )
|
|
{
|
|
switch( event.GetKeyCode() )
|
|
{
|
|
case 'A':
|
|
SelectAll();
|
|
return;
|
|
case 'C':
|
|
if ( CanCopy() )
|
|
Copy() ;
|
|
return;
|
|
case 'V':
|
|
if ( CanPaste() )
|
|
Paste() ;
|
|
return;
|
|
case 'X':
|
|
if ( CanCut() )
|
|
Cut() ;
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
// no, we didn't process it
|
|
event.Skip();
|
|
}
|
|
|
|
void wxTextCtrl::OnChar(wxKeyEvent& event)
|
|
{
|
|
int key = event.GetKeyCode() ;
|
|
bool eat_key = false ;
|
|
long from, to;
|
|
|
|
if ( !IsEditable() &&
|
|
!event.IsKeyInCategory(WXK_CATEGORY_ARROW | WXK_CATEGORY_TAB) &&
|
|
!( (key == WXK_RETURN || key == WXK_NUMPAD_ENTER) &&
|
|
( (m_windowStyle & wxTE_PROCESS_ENTER) || (m_windowStyle & wxTE_MULTILINE) ) )
|
|
// && key != WXK_PAGEUP && key != WXK_PAGEDOWN && key != WXK_HOME && key != WXK_END
|
|
)
|
|
{
|
|
// eat it
|
|
return ;
|
|
}
|
|
|
|
if ( !GetTextPeer()->CanClipMaxLength() )
|
|
{
|
|
// Check if we have reached the max # of chars (if it is set), but still
|
|
// allow navigation and deletion
|
|
GetSelection( &from, &to );
|
|
if ( !IsMultiLine() && m_maxLength && GetValue().length() >= m_maxLength &&
|
|
!event.IsKeyInCategory(WXK_CATEGORY_ARROW | WXK_CATEGORY_TAB | WXK_CATEGORY_CUT) &&
|
|
!( (key == WXK_RETURN || key == WXK_NUMPAD_ENTER) &&
|
|
(m_windowStyle & wxTE_PROCESS_ENTER) ) &&
|
|
from == to )
|
|
{
|
|
// eat it, we don't want to add more than allowed # of characters
|
|
|
|
// TODO: generate EVT_TEXT_MAXLEN()
|
|
return;
|
|
}
|
|
}
|
|
|
|
// assume that any key not processed yet is going to modify the control
|
|
m_dirty = true;
|
|
|
|
switch ( key )
|
|
{
|
|
case WXK_RETURN:
|
|
case WXK_NUMPAD_ENTER:
|
|
if (m_windowStyle & wxTE_PROCESS_ENTER)
|
|
{
|
|
wxCommandEvent event(wxEVT_TEXT_ENTER, m_windowId);
|
|
event.SetEventObject( this );
|
|
event.SetString( GetValue() );
|
|
if ( HandleWindowEvent(event) )
|
|
return;
|
|
}
|
|
|
|
if ( !(m_windowStyle & wxTE_MULTILINE) )
|
|
{
|
|
wxTopLevelWindow *tlw = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow);
|
|
if ( tlw && tlw->GetDefaultItem() )
|
|
{
|
|
wxButton *def = wxDynamicCast(tlw->GetDefaultItem(), wxButton);
|
|
if ( def && def->IsEnabled() )
|
|
{
|
|
wxCommandEvent event(wxEVT_BUTTON, def->GetId() );
|
|
event.SetEventObject(def);
|
|
def->Command(event);
|
|
|
|
return ;
|
|
}
|
|
}
|
|
|
|
// this will make wxWidgets eat the ENTER key so that
|
|
// we actually prevent line wrapping in a single line text control
|
|
eat_key = true;
|
|
}
|
|
break;
|
|
|
|
case WXK_TAB:
|
|
if ( !(m_windowStyle & wxTE_PROCESS_TAB))
|
|
{
|
|
int flags = 0;
|
|
if (!event.ShiftDown())
|
|
flags |= wxNavigationKeyEvent::IsForward ;
|
|
if (event.ControlDown())
|
|
flags |= wxNavigationKeyEvent::WinChange ;
|
|
Navigate(flags);
|
|
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
// This is necessary (don't know why);
|
|
// otherwise the tab will not be inserted.
|
|
WriteText(wxT("\t"));
|
|
eat_key = true;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (!eat_key)
|
|
{
|
|
// perform keystroke handling
|
|
event.Skip(true) ;
|
|
}
|
|
|
|
// osx_cocoa sends its event upon insertText
|
|
}
|
|
|
|
void wxTextCtrl::Command(wxCommandEvent & event)
|
|
{
|
|
SetValue(event.GetString());
|
|
ProcessCommand(event);
|
|
}
|
|
|
|
void wxTextCtrl::SetWindowStyleFlag(long style)
|
|
{
|
|
long styleOld = GetWindowStyleFlag();
|
|
|
|
wxTextCtrlBase::SetWindowStyleFlag(style);
|
|
|
|
static const long flagsAlign = wxTE_LEFT | wxTE_CENTRE | wxTE_RIGHT;
|
|
if ( (style & flagsAlign) != (styleOld & flagsAlign) )
|
|
GetTextPeer()->SetJustification();
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// standard handlers for standard edit menu events
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// CS: Context Menus only work with MLTE implementations or non-multiline HIViews at the moment
|
|
|
|
void wxTextCtrl::OnCut(wxCommandEvent& WXUNUSED(event))
|
|
{
|
|
Cut();
|
|
}
|
|
|
|
void wxTextCtrl::OnCopy(wxCommandEvent& WXUNUSED(event))
|
|
{
|
|
Copy();
|
|
}
|
|
|
|
void wxTextCtrl::OnPaste(wxCommandEvent& WXUNUSED(event))
|
|
{
|
|
Paste();
|
|
}
|
|
|
|
void wxTextCtrl::OnUndo(wxCommandEvent& WXUNUSED(event))
|
|
{
|
|
Undo();
|
|
}
|
|
|
|
void wxTextCtrl::OnRedo(wxCommandEvent& WXUNUSED(event))
|
|
{
|
|
Redo();
|
|
}
|
|
|
|
void wxTextCtrl::OnDelete(wxCommandEvent& WXUNUSED(event))
|
|
{
|
|
long from, to;
|
|
|
|
GetSelection( &from, &to );
|
|
if (from != -1 && to != -1)
|
|
Remove( from, to );
|
|
}
|
|
|
|
void wxTextCtrl::OnSelectAll(wxCommandEvent& WXUNUSED(event))
|
|
{
|
|
SetSelection(-1, -1);
|
|
}
|
|
|
|
void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent& event)
|
|
{
|
|
event.Enable( CanCut() );
|
|
}
|
|
|
|
void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent& event)
|
|
{
|
|
event.Enable( CanCopy() );
|
|
}
|
|
|
|
void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent& event)
|
|
{
|
|
event.Enable( CanPaste() );
|
|
}
|
|
|
|
void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent& event)
|
|
{
|
|
event.Enable( CanUndo() );
|
|
}
|
|
|
|
void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent& event)
|
|
{
|
|
event.Enable( CanRedo() );
|
|
}
|
|
|
|
void wxTextCtrl::OnUpdateDelete(wxUpdateUIEvent& event)
|
|
{
|
|
long from, to;
|
|
|
|
GetSelection( &from, &to );
|
|
event.Enable( from != -1 && to != -1 && from != to && IsEditable() ) ;
|
|
}
|
|
|
|
void wxTextCtrl::OnUpdateSelectAll(wxUpdateUIEvent& event)
|
|
{
|
|
event.Enable(GetLastPosition() > 0);
|
|
}
|
|
|
|
void wxTextCtrl::OnContextMenu(wxContextMenuEvent& event)
|
|
{
|
|
if ( GetTextPeer()->HasOwnContextMenu() )
|
|
{
|
|
event.Skip() ;
|
|
return ;
|
|
}
|
|
|
|
#if wxUSE_MENUS
|
|
if (m_privateContextMenu == NULL)
|
|
{
|
|
m_privateContextMenu = new wxMenu;
|
|
m_privateContextMenu->Append(wxID_UNDO, _("&Undo"));
|
|
m_privateContextMenu->Append(wxID_REDO, _("&Redo"));
|
|
m_privateContextMenu->AppendSeparator();
|
|
m_privateContextMenu->Append(wxID_CUT, _("Cu&t"));
|
|
m_privateContextMenu->Append(wxID_COPY, _("&Copy"));
|
|
m_privateContextMenu->Append(wxID_PASTE, _("&Paste"));
|
|
m_privateContextMenu->Append(wxID_CLEAR, _("&Delete"));
|
|
m_privateContextMenu->AppendSeparator();
|
|
m_privateContextMenu->Append(wxID_SELECTALL, _("Select &All"));
|
|
}
|
|
|
|
PopupMenu(m_privateContextMenu);
|
|
#endif
|
|
}
|
|
|
|
bool wxTextCtrl::MacSetupCursor( const wxPoint& pt )
|
|
{
|
|
if ( !GetTextPeer()->SetupCursor( pt ) )
|
|
return wxWindow::MacSetupCursor( pt ) ;
|
|
else
|
|
return true ;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// implementation base class
|
|
// ----------------------------------------------------------------------------
|
|
|
|
bool wxTextWidgetImpl::GetStyle(long WXUNUSED(position),
|
|
wxTextAttr& WXUNUSED(style))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
void wxTextWidgetImpl::SetStyle(long WXUNUSED(start),
|
|
long WXUNUSED(end),
|
|
const wxTextAttr& WXUNUSED(style))
|
|
{
|
|
}
|
|
|
|
void wxTextWidgetImpl::Copy()
|
|
{
|
|
}
|
|
|
|
void wxTextWidgetImpl::Cut()
|
|
{
|
|
}
|
|
|
|
void wxTextWidgetImpl::Paste()
|
|
{
|
|
}
|
|
|
|
bool wxTextWidgetImpl::CanPaste() const
|
|
{
|
|
return false ;
|
|
}
|
|
|
|
void wxTextWidgetImpl::SetEditable(bool WXUNUSED(editable))
|
|
{
|
|
}
|
|
|
|
long wxTextWidgetImpl::GetLastPosition() const
|
|
{
|
|
return GetStringValue().length() ;
|
|
}
|
|
|
|
void wxTextWidgetImpl::Replace( long from , long to , const wxString &val )
|
|
{
|
|
SetSelection( from , to ) ;
|
|
WriteText( val ) ;
|
|
}
|
|
|
|
void wxTextWidgetImpl::Remove( long from , long to )
|
|
{
|
|
SetSelection( from , to ) ;
|
|
WriteText( wxEmptyString) ;
|
|
}
|
|
|
|
void wxTextWidgetImpl::Clear()
|
|
{
|
|
SetStringValue( wxEmptyString ) ;
|
|
}
|
|
|
|
bool wxTextWidgetImpl::CanUndo() const
|
|
{
|
|
return false ;
|
|
}
|
|
|
|
void wxTextWidgetImpl::Undo()
|
|
{
|
|
}
|
|
|
|
bool wxTextWidgetImpl::CanRedo() const
|
|
{
|
|
return false ;
|
|
}
|
|
|
|
void wxTextWidgetImpl::Redo()
|
|
{
|
|
}
|
|
|
|
long wxTextWidgetImpl::XYToPosition(long WXUNUSED(x), long WXUNUSED(y)) const
|
|
{
|
|
return 0 ;
|
|
}
|
|
|
|
bool wxTextWidgetImpl::PositionToXY(long WXUNUSED(pos),
|
|
long *WXUNUSED(x),
|
|
long *WXUNUSED(y)) const
|
|
{
|
|
return false ;
|
|
}
|
|
|
|
void wxTextWidgetImpl::ShowPosition( long WXUNUSED(pos) )
|
|
{
|
|
}
|
|
|
|
int wxTextWidgetImpl::GetNumberOfLines() const
|
|
{
|
|
wxString content = GetStringValue() ;
|
|
ItemCount lines = 1;
|
|
|
|
for (size_t i = 0; i < content.length() ; i++)
|
|
{
|
|
#if wxOSX_USE_COCOA
|
|
if (content[i] == '\n')
|
|
#else
|
|
if (content[i] == '\r')
|
|
#endif
|
|
lines++;
|
|
}
|
|
|
|
return lines ;
|
|
}
|
|
|
|
wxString wxTextWidgetImpl::GetLineText(long lineNo) const
|
|
{
|
|
// TODO: change this if possible to reflect real lines
|
|
wxString content = GetStringValue() ;
|
|
|
|
// Find line first
|
|
int count = 0;
|
|
for (size_t i = 0; i < content.length() ; i++)
|
|
{
|
|
if (count == lineNo)
|
|
{
|
|
// Add chars in line then
|
|
wxString tmp;
|
|
|
|
for (size_t j = i; j < content.length(); j++)
|
|
{
|
|
if (content[j] == '\n')
|
|
return tmp;
|
|
|
|
tmp += content[j];
|
|
}
|
|
|
|
return tmp;
|
|
}
|
|
|
|
if (content[i] == '\n')
|
|
count++;
|
|
}
|
|
|
|
return wxEmptyString ;
|
|
}
|
|
|
|
int wxTextWidgetImpl::GetLineLength(long lineNo) const
|
|
{
|
|
// TODO: change this if possible to reflect real lines
|
|
wxString content = GetStringValue() ;
|
|
|
|
// Find line first
|
|
int count = 0;
|
|
for (size_t i = 0; i < content.length() ; i++)
|
|
{
|
|
if (count == lineNo)
|
|
{
|
|
// Count chars in line then
|
|
count = 0;
|
|
for (size_t j = i; j < content.length(); j++)
|
|
{
|
|
if (content[j] == '\n')
|
|
return count;
|
|
|
|
count++;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
if (content[i] == '\n')
|
|
count++;
|
|
}
|
|
|
|
return -1 ;
|
|
}
|
|
|
|
void wxTextWidgetImpl::SetJustification()
|
|
{
|
|
}
|
|
#endif // wxUSE_TEXTCTRL
|