1///////////////////////////////////////////////////////////////////////////// 2// Name: caret.cpp 3// Purpose: wxCaret sample 4// Author: Robert Roebling 5// Modified by: 6// Created: 04/01/98 7// RCS-ID: $Id: caret.cpp 29599 2004-10-02 12:36:02Z VS $ 8// Copyright: (c) wxWindows team 9// Licence: wxWindows licence 10///////////////////////////////////////////////////////////////////////////// 11 12// For compilers that support precompilation, includes "wx/wx.h". 13#include "wx/wxprec.h" 14 15#ifdef __BORLANDC__ 16 #pragma hdrstop 17#endif 18 19// for all others, include the necessary headers (this file is usually all you 20// need because it includes almost all <standard< wxWidgets headers 21#ifndef WX_PRECOMP 22 #include "wx/wx.h" 23 #include "wx/log.h" 24#endif 25 26#include "wx/caret.h" 27#include "wx/numdlg.h" 28 29// ---------------------------------------------------------------------------- 30// ressources 31// ---------------------------------------------------------------------------- 32// the application icon 33#if defined(__WXGTK__) || defined(__WXX11__) || defined(__WXMOTIF__) || defined(__WXMAC__) || defined(__WXMGL__) 34 #include "mondrian.xpm" 35#endif 36 37// ---------------------------------------------------------------------------- 38// private classes 39// ---------------------------------------------------------------------------- 40 41// Define a new application type, each program should derive a class from wxApp 42class MyApp : public wxApp 43{ 44public: 45 // override base class virtuals 46 // ---------------------------- 47 48 // this one is called on application startup and is a good place for the app 49 // initialization (doing it here and not in the ctor allows to have an error 50 // return: if OnInit() returns false, the application terminates) 51 virtual bool OnInit(); 52}; 53 54// MyCanvas is a canvas on which you can type 55class MyCanvas: public wxScrolledWindow 56{ 57public: 58 MyCanvas() { } 59 MyCanvas( wxWindow *parent ); 60 ~MyCanvas(); 61 62 wxChar& CharAt(int x, int y) { return *(m_text + x + m_xChars * y); } 63 64 // operations 65 void SetFontSize(int fontSize); 66 void CreateCaret(); 67 void MoveCaret(int x, int y); 68 69 // caret movement 70 void Home() { m_xCaret = 0; } 71 void End() { m_xCaret = m_xChars - 1; } 72 void FirstLine() { m_yCaret = 0; } 73 void LastLine() { m_yCaret = m_yChars - 1; } 74 void PrevChar() { if ( !m_xCaret-- ) { End(); PrevLine(); } } 75 void NextChar() { if ( ++m_xCaret == m_xChars ) { Home(); NextLine(); } } 76 void PrevLine() { if ( !m_yCaret-- ) LastLine(); } 77 void NextLine() { if ( ++m_yCaret == m_yChars ) FirstLine(); } 78 79 // event handlers 80 void OnPaint( wxPaintEvent &event ); 81 void OnSize( wxSizeEvent &event ); 82 void OnChar( wxKeyEvent &event ); 83 84private: 85 // move the caret to m_xCaret, m_yCaret 86 void DoMoveCaret(); 87 88 // update the geometry 89 void ChangeSize(); 90 91 wxFont m_font; 92 93 // the margin around the text (looks nicer) 94 int m_xMargin, m_yMargin; 95 96 // size (in pixels) of one character 97 long m_widthChar, m_heightChar; 98 99 // position (in text coords) of the caret 100 int m_xCaret, m_yCaret; 101 102 // the size (in text coords) of the window 103 int m_xChars, m_yChars; 104 105 // the text 106 wxChar *m_text; 107 108 DECLARE_DYNAMIC_CLASS(MyCanvas) 109 DECLARE_EVENT_TABLE() 110}; 111 112 113// Define a new frame type: this is going to be our main frame 114class MyFrame : public wxFrame 115{ 116public: 117 // ctor(s) 118 MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size); 119 120 // event handlers (these functions should _not_ be virtual) 121 void OnQuit(wxCommandEvent& event); 122 void OnAbout(wxCommandEvent& event); 123 void OnSetBlinkTime(wxCommandEvent& event); 124 void OnSetFontSize(wxCommandEvent& event); 125 void OnCaretMove(wxCommandEvent& event); 126 127private: 128 MyCanvas *m_canvas; 129 130 // any class wishing to process wxWidgets events must use this macro 131 DECLARE_EVENT_TABLE() 132}; 133 134// ---------------------------------------------------------------------------- 135// constants 136// ---------------------------------------------------------------------------- 137 138// IDs for the controls and the menu commands 139enum 140{ 141 // menu items 142 Caret_Quit = 1, 143 Caret_About, 144 Caret_SetBlinkTime, 145 Caret_SetFontSize, 146 Caret_Move, 147 148 // controls start here (the numbers are, of course, arbitrary) 149 Caret_Text = 1000 150}; 151 152// ---------------------------------------------------------------------------- 153// event tables and other macros for wxWidgets 154// ---------------------------------------------------------------------------- 155 156// the event tables connect the wxWidgets events with the functions (event 157// handlers) which process them. It can be also done at run-time, but for the 158// simple menu events like this the static method is much simpler. 159BEGIN_EVENT_TABLE(MyFrame, wxFrame) 160 EVT_MENU(Caret_Quit, MyFrame::OnQuit) 161 EVT_MENU(Caret_About, MyFrame::OnAbout) 162 EVT_MENU(Caret_SetBlinkTime, MyFrame::OnSetBlinkTime) 163 EVT_MENU(Caret_SetFontSize, MyFrame::OnSetFontSize) 164 EVT_MENU(Caret_Move, MyFrame::OnCaretMove) 165END_EVENT_TABLE() 166 167// Create a new application object: this macro will allow wxWidgets to create 168// the application object during program execution (it's better than using a 169// static object for many reasons) and also declares the accessor function 170// wxGetApp() which will return the reference of the right type (i.e. MyApp and 171// not wxApp) 172IMPLEMENT_APP(MyApp) 173 174// ============================================================================ 175// implementation 176// ============================================================================ 177 178// ---------------------------------------------------------------------------- 179// the application class 180// ---------------------------------------------------------------------------- 181 182// `Main program' equivalent: the program execution "starts" here 183bool MyApp::OnInit() 184{ 185 // create and show the main application window 186 MyFrame *frame = new MyFrame(_T("Caret wxWidgets sample"), 187 wxPoint(50, 50), wxSize(450, 340)); 188 189 frame->Show(true); 190 191 // success: wxApp::OnRun() will be called which will enter the main message 192 // loop and the application will run. If we returned false here, the 193 // application would exit immediately. 194 return true; 195} 196 197// ---------------------------------------------------------------------------- 198// main frame 199// ---------------------------------------------------------------------------- 200 201// frame constructor 202MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) 203 : wxFrame((wxFrame *)NULL, wxID_ANY, title, pos, size) 204{ 205 // set the frame icon 206 SetIcon(wxICON(mondrian)); 207 208 // create a menu bar 209 wxMenu *menuFile = new wxMenu; 210 211 menuFile->Append(Caret_SetBlinkTime, _T("&Blink time...\tCtrl-B")); 212 menuFile->Append(Caret_SetFontSize, _T("&Font size...\tCtrl-S")); 213 menuFile->Append(Caret_Move, _T("&Move caret\tCtrl-C")); 214 menuFile->AppendSeparator(); 215 menuFile->Append(Caret_About, _T("&About...\tCtrl-A"), _T("Show about dialog")); 216 menuFile->AppendSeparator(); 217 menuFile->Append(Caret_Quit, _T("E&xit\tAlt-X"), _T("Quit this program")); 218 219 // now append the freshly created menu to the menu bar... 220 wxMenuBar *menuBar = new wxMenuBar; 221 menuBar->Append(menuFile, _T("&File")); 222 223 // ... and attach this menu bar to the frame 224 SetMenuBar(menuBar); 225 226 m_canvas = new MyCanvas(this); 227 228#if wxUSE_STATUSBAR 229 // create a status bar just for fun (by default with 1 pane only) 230 CreateStatusBar(2); 231 SetStatusText(_T("Welcome to wxWidgets!")); 232#endif // wxUSE_STATUSBAR 233} 234 235 236// event handlers 237 238void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) 239{ 240 // true is to force the frame to close 241 Close(true); 242} 243 244void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) 245{ 246 wxMessageBox(_T("The caret wxWidgets sample.\n(c) 1999 Vadim Zeitlin"), 247 _T("About Caret"), wxOK | wxICON_INFORMATION, this); 248} 249 250void MyFrame::OnCaretMove(wxCommandEvent& WXUNUSED(event)) 251{ 252 m_canvas->MoveCaret(10, 10); 253} 254 255void MyFrame::OnSetBlinkTime(wxCommandEvent& WXUNUSED(event)) 256{ 257 long blinkTime = wxGetNumberFromUser 258 ( 259 _T("The caret blink time is the time between two blinks"), 260 _T("Time in milliseconds:"), 261 _T("wxCaret sample"), 262 wxCaret::GetBlinkTime(), 0, 10000, 263 this 264 ); 265 if ( blinkTime != -1 ) 266 { 267 wxCaret::SetBlinkTime((int)blinkTime); 268 m_canvas->CreateCaret(); 269 wxLogStatus(this, _T("Blink time set to %ld milliseconds."), blinkTime); 270 } 271} 272 273void MyFrame::OnSetFontSize(wxCommandEvent& WXUNUSED(event)) 274{ 275 long fontSize = wxGetNumberFromUser 276 ( 277 _T("The font size also determines the caret size so\nthis demonstrates resizing the caret."), 278 _T("Font size (in points):"), 279 _T("wxCaret sample"), 280 12, 1, 100, 281 this 282 ); 283 284 if ( fontSize != -1 ) 285 { 286 m_canvas->SetFontSize((int)fontSize); 287 } 288} 289 290// ---------------------------------------------------------------------------- 291// MyCanvas 292// ---------------------------------------------------------------------------- 293 294IMPLEMENT_DYNAMIC_CLASS(MyCanvas, wxScrolledWindow) 295 296BEGIN_EVENT_TABLE(MyCanvas, wxScrolledWindow) 297 EVT_PAINT(MyCanvas::OnPaint) 298 EVT_SIZE(MyCanvas::OnSize) 299 EVT_CHAR(MyCanvas::OnChar) 300END_EVENT_TABLE() 301 302MyCanvas::MyCanvas( wxWindow *parent ) 303 : wxScrolledWindow( parent, wxID_ANY, 304 wxDefaultPosition, wxDefaultSize, 305 wxSUNKEN_BORDER ) 306{ 307 m_text = (wxChar *)NULL; 308 309 SetBackgroundColour(*wxWHITE); 310 311 SetFontSize(12); 312 313 m_xCaret = m_yCaret = 314 m_xChars = m_yChars = 0; 315 316 m_xMargin = m_yMargin = 5; 317 318 CreateCaret(); 319} 320 321MyCanvas::~MyCanvas() 322{ 323 free(m_text); 324} 325 326void MyCanvas::CreateCaret() 327{ 328 wxCaret *caret = new wxCaret(this, m_widthChar, m_heightChar); 329 SetCaret(caret); 330 331 caret->Move(m_xMargin, m_yMargin); 332 caret->Show(); 333} 334 335void MyCanvas::SetFontSize(int fontSize) 336{ 337 m_font = wxFont(fontSize, wxFONTFAMILY_TELETYPE, 338 wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL); 339 340 wxClientDC dc(this); 341 dc.SetFont(m_font); 342 m_heightChar = dc.GetCharHeight(); 343 m_widthChar = dc.GetCharWidth(); 344 345 wxCaret *caret = GetCaret(); 346 if ( caret ) 347 { 348 caret->SetSize(m_widthChar, m_heightChar); 349 350 ChangeSize(); 351 } 352} 353 354void MyCanvas::MoveCaret(int x, int y) 355{ 356 m_xCaret = x; 357 m_yCaret = y; 358 359 DoMoveCaret(); 360} 361 362void MyCanvas::DoMoveCaret() 363{ 364 wxLogStatus(_T("Caret is at (%d, %d)"), m_xCaret, m_yCaret); 365 366 GetCaret()->Move(m_xMargin + m_xCaret * m_widthChar, 367 m_yMargin + m_yCaret * m_heightChar); 368} 369 370void MyCanvas::OnSize(wxSizeEvent& event) 371{ 372 ChangeSize(); 373 374 event.Skip(); 375} 376 377void MyCanvas::ChangeSize() 378{ 379 wxSize size = GetClientSize(); 380 m_xChars = (size.x - 2*m_xMargin) / m_widthChar; 381 m_yChars = (size.y - 2*m_yMargin) / m_heightChar; 382 if ( !m_xChars ) 383 m_xChars = 1; 384 if ( !m_yChars ) 385 m_yChars = 1; 386 387 free(m_text); 388 m_text = (wxChar *)calloc(m_xChars * m_yChars, sizeof(wxChar)); 389 390#if wxUSE_STATUSBAR 391 wxFrame *frame = wxDynamicCast(GetParent(), wxFrame); 392 393 if ( frame && frame->GetStatusBar() ) 394 { 395 wxString msg; 396 msg.Printf(_T("Panel size is (%d, %d)"), m_xChars, m_yChars); 397 frame->SetStatusText(msg, 1); 398 } 399#endif // wxUSE_STATUSBAR 400} 401 402// NB: this method is horrible inefficient especially because the caret 403// needs to be redrawn often and in this case we only have to redraw 404// the caret location and not the entire window - in a real program we 405// would use GetUpdateRegion() and iterate over rectangles it contains 406void MyCanvas::OnPaint( wxPaintEvent &WXUNUSED(event) ) 407{ 408 wxCaretSuspend cs(this); 409 wxPaintDC dc( this ); 410 PrepareDC( dc ); 411 dc.Clear(); 412 413 dc.SetFont( m_font ); 414 415 for ( int y = 0; y < m_yChars; y++ ) 416 { 417 wxString line; 418 419 for ( int x = 0; x < m_xChars; x++ ) 420 { 421 wxChar ch = CharAt(x, y); 422 if ( !ch ) 423 ch = _T(' '); 424 line += ch; 425 } 426 427 dc.DrawText( line, m_xMargin, m_yMargin + y * m_heightChar ); 428 } 429} 430 431void MyCanvas::OnChar( wxKeyEvent &event ) 432{ 433 switch ( event.GetKeyCode() ) 434 { 435 case WXK_LEFT: 436 PrevChar(); 437 break; 438 439 case WXK_RIGHT: 440 NextChar(); 441 break; 442 443 case WXK_UP: 444 PrevLine(); 445 break; 446 447 case WXK_DOWN: 448 NextLine(); 449 break; 450 451 case WXK_HOME: 452 Home(); 453 break; 454 455 case WXK_END: 456 End(); 457 break; 458 459 case WXK_RETURN: 460 Home(); 461 NextLine(); 462 break; 463 464 default: 465 if ( !event.AltDown() && wxIsprint(event.GetKeyCode()) ) 466 { 467 wxChar ch = (wxChar)event.GetKeyCode(); 468 CharAt(m_xCaret, m_yCaret) = ch; 469 470 wxCaretSuspend cs(this); 471 wxClientDC dc(this); 472 dc.SetFont(m_font); 473 dc.SetBackgroundMode(wxSOLID); // overwrite old value 474 dc.DrawText(ch, m_xMargin + m_xCaret * m_widthChar, 475 m_yMargin + m_yCaret * m_heightChar ); 476 477 NextChar(); 478 } 479 else 480 { 481 event.Skip(); 482 } 483 } 484 485 DoMoveCaret(); 486} 487 488