1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        caret.cpp
3 // Purpose:     wxCaret sample
4 // Author:      Robert Roebling
5 // Modified by:
6 // Created:     04/01/98
7 // Copyright:   (c) wxWindows team
8 // Licence:     wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10 
11 // For compilers that support precompilation, includes "wx/wx.h".
12 #include "wx/wxprec.h"
13 
14 #ifdef __BORLANDC__
15     #pragma hdrstop
16 #endif
17 
18 // for all others, include the necessary headers (this file is usually all you
19 // need because it includes almost all <standard< wxWidgets headers
20 #ifndef WX_PRECOMP
21     #include "wx/wx.h"
22     #include "wx/log.h"
23 #endif
24 
25 #include "wx/caret.h"
26 #include "wx/numdlg.h"
27 
28 // ----------------------------------------------------------------------------
29 // resources
30 // ----------------------------------------------------------------------------
31 
32 // the application icon
33 #ifndef wxHAS_IMAGES_IN_RESOURCES
34     #include "../sample.xpm"
35 #endif
36 
37 // ----------------------------------------------------------------------------
38 // private classes
39 // ----------------------------------------------------------------------------
40 
41 // Define a new application type, each program should derive a class from wxApp
42 class MyApp : public wxApp
43 {
44 public:
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
55 class MyCanvas: public wxScrolledWindow
56 {
57 public:
MyCanvas()58     MyCanvas() { }
59     MyCanvas( wxWindow *parent );
60     ~MyCanvas();
61 
CharAt(int x,int y)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
Home()70     void Home() { m_xCaret = 0; }
End()71     void End() { m_xCaret = m_xChars - 1; }
FirstLine()72     void FirstLine() { m_yCaret = 0; }
LastLine()73     void LastLine() { m_yCaret = m_yChars - 1; }
PrevChar()74     void PrevChar() { if ( !m_xCaret-- ) { End(); PrevLine(); } }
NextChar()75     void NextChar() { if ( ++m_xCaret == m_xChars ) { Home(); NextLine(); } }
PrevLine()76     void PrevLine() { if ( !m_yCaret-- ) LastLine(); }
NextLine()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 
84 private:
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     wxDECLARE_DYNAMIC_CLASS(MyCanvas);
109     wxDECLARE_EVENT_TABLE();
110 };
111 
112 
113 // Define a new frame type: this is going to be our main frame
114 class MyFrame : public wxFrame
115 {
116 public:
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 
127 private:
128     MyCanvas *m_canvas;
129 
130     // any class wishing to process wxWidgets events must use this macro
131     wxDECLARE_EVENT_TABLE();
132 };
133 
134 // ----------------------------------------------------------------------------
135 // constants
136 // ----------------------------------------------------------------------------
137 
138 // IDs for the controls and the menu commands
139 enum
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.
wxBEGIN_EVENT_TABLE(MyFrame,wxFrame)159 wxBEGIN_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)
165 wxEND_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)
172 IMPLEMENT_APP(MyApp)
173 
174 // ============================================================================
175 // implementation
176 // ============================================================================
177 
178 // ----------------------------------------------------------------------------
179 // the application class
180 // ----------------------------------------------------------------------------
181 
182 // `Main program' equivalent: the program execution "starts" here
183 bool MyApp::OnInit()
184 {
185     if ( !wxApp::OnInit() )
186         return false;
187 
188     // create and show the main application window
189     MyFrame *frame = new MyFrame(wxT("Caret wxWidgets sample"),
190                                  wxPoint(50, 50), wxSize(450, 340));
191 
192     frame->Show(true);
193 
194     // success: wxApp::OnRun() will be called which will enter the main message
195     // loop and the application will run. If we returned false here, the
196     // application would exit immediately.
197     return true;
198 }
199 
200 // ----------------------------------------------------------------------------
201 // main frame
202 // ----------------------------------------------------------------------------
203 
204 // frame constructor
MyFrame(const wxString & title,const wxPoint & pos,const wxSize & size)205 MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
206        : wxFrame((wxFrame *)NULL, wxID_ANY, title, pos, size)
207 {
208     // set the frame icon
209     SetIcon(wxICON(sample));
210 
211     // create a menu bar
212     wxMenu *menuFile = new wxMenu;
213 
214     menuFile->Append(Caret_SetBlinkTime, wxT("&Blink time...\tCtrl-B"));
215     menuFile->Append(Caret_SetFontSize, wxT("&Font size...\tCtrl-S"));
216     menuFile->Append(Caret_Move, wxT("&Move caret\tCtrl-C"));
217     menuFile->AppendSeparator();
218     menuFile->Append(Caret_About, wxT("&About\tCtrl-A"), wxT("Show about dialog"));
219     menuFile->AppendSeparator();
220     menuFile->Append(Caret_Quit, wxT("E&xit\tAlt-X"), wxT("Quit this program"));
221 
222     // now append the freshly created menu to the menu bar...
223     wxMenuBar *menuBar = new wxMenuBar;
224     menuBar->Append(menuFile, wxT("&File"));
225 
226     // ... and attach this menu bar to the frame
227     SetMenuBar(menuBar);
228 
229     m_canvas = new MyCanvas(this);
230 
231 #if wxUSE_STATUSBAR
232     // create a status bar just for fun (by default with 1 pane only)
233     CreateStatusBar(2);
234     SetStatusText(wxT("Welcome to wxWidgets!"));
235 #endif // wxUSE_STATUSBAR
236 }
237 
238 
239 // event handlers
240 
OnQuit(wxCommandEvent & WXUNUSED (event))241 void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
242 {
243     // true is to force the frame to close
244     Close(true);
245 }
246 
OnAbout(wxCommandEvent & WXUNUSED (event))247 void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
248 {
249     wxMessageBox(wxT("The caret wxWidgets sample.\n(c) 1999 Vadim Zeitlin"),
250                  wxT("About Caret"), wxOK | wxICON_INFORMATION, this);
251 }
252 
OnCaretMove(wxCommandEvent & WXUNUSED (event))253 void MyFrame::OnCaretMove(wxCommandEvent& WXUNUSED(event))
254 {
255     m_canvas->MoveCaret(10, 10);
256 }
257 
OnSetBlinkTime(wxCommandEvent & WXUNUSED (event))258 void MyFrame::OnSetBlinkTime(wxCommandEvent& WXUNUSED(event))
259 {
260     long blinkTime = wxGetNumberFromUser
261                      (
262                       wxT("The caret blink time is the time between two blinks"),
263                       wxT("Time in milliseconds:"),
264                       wxT("wxCaret sample"),
265                       wxCaret::GetBlinkTime(), 0, 10000,
266                       this
267                      );
268     if ( blinkTime != -1 )
269     {
270         wxCaret::SetBlinkTime((int)blinkTime);
271         m_canvas->CreateCaret();
272         wxLogStatus(this, wxT("Blink time set to %ld milliseconds."), blinkTime);
273     }
274 }
275 
OnSetFontSize(wxCommandEvent & WXUNUSED (event))276 void MyFrame::OnSetFontSize(wxCommandEvent& WXUNUSED(event))
277 {
278     long fontSize = wxGetNumberFromUser
279                     (
280                         wxT("The font size also determines the caret size so\nthis demonstrates resizing the caret."),
281                         wxT("Font size (in points):"),
282                         wxT("wxCaret sample"),
283                         12, 1, 100,
284                         this
285                     );
286 
287     if ( fontSize != -1 )
288     {
289         m_canvas->SetFontSize((int)fontSize);
290     }
291 }
292 
293 // ----------------------------------------------------------------------------
294 // MyCanvas
295 // ----------------------------------------------------------------------------
296 
IMPLEMENT_DYNAMIC_CLASS(MyCanvas,wxScrolledWindow)297 IMPLEMENT_DYNAMIC_CLASS(MyCanvas, wxScrolledWindow)
298 
299 wxBEGIN_EVENT_TABLE(MyCanvas, wxScrolledWindow)
300     EVT_PAINT(MyCanvas::OnPaint)
301     EVT_SIZE(MyCanvas::OnSize)
302     EVT_CHAR(MyCanvas::OnChar)
303 wxEND_EVENT_TABLE()
304 
305 MyCanvas::MyCanvas( wxWindow *parent )
306         : wxScrolledWindow( parent, wxID_ANY,
307                             wxDefaultPosition, wxDefaultSize,
308                             wxSUNKEN_BORDER )
309 {
310     m_text = (wxChar *)NULL;
311 
312     SetBackgroundColour(*wxWHITE);
313 
314     SetFontSize(12);
315 
316     m_xCaret = m_yCaret =
317     m_xChars = m_yChars = 0;
318 
319     m_xMargin = m_yMargin = 5;
320 
321     CreateCaret();
322 }
323 
~MyCanvas()324 MyCanvas::~MyCanvas()
325 {
326     free(m_text);
327 }
328 
CreateCaret()329 void MyCanvas::CreateCaret()
330 {
331     wxCaret *caret = new wxCaret(this, m_widthChar, m_heightChar);
332     SetCaret(caret);
333 
334     caret->Move(m_xMargin, m_yMargin);
335     caret->Show();
336 }
337 
SetFontSize(int fontSize)338 void MyCanvas::SetFontSize(int fontSize)
339 {
340     m_font = wxFont(fontSize, wxFONTFAMILY_TELETYPE,
341                     wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
342 
343     wxClientDC dc(this);
344     dc.SetFont(m_font);
345     m_heightChar = dc.GetCharHeight();
346     m_widthChar = dc.GetCharWidth();
347 
348     wxCaret *caret = GetCaret();
349     if ( caret )
350     {
351         caret->SetSize(m_widthChar, m_heightChar);
352 
353         ChangeSize();
354     }
355 }
356 
MoveCaret(int x,int y)357 void MyCanvas::MoveCaret(int x, int y)
358 {
359     m_xCaret = x;
360     m_yCaret = y;
361 
362     DoMoveCaret();
363 }
364 
DoMoveCaret()365 void MyCanvas::DoMoveCaret()
366 {
367     wxLogStatus(wxT("Caret is at (%d, %d)"), m_xCaret, m_yCaret);
368 
369     GetCaret()->Move(m_xMargin + m_xCaret * m_widthChar,
370                      m_yMargin + m_yCaret * m_heightChar);
371 }
372 
OnSize(wxSizeEvent & event)373 void MyCanvas::OnSize(wxSizeEvent& event)
374 {
375     ChangeSize();
376 
377     event.Skip();
378 }
379 
ChangeSize()380 void MyCanvas::ChangeSize()
381 {
382     wxSize size = GetClientSize();
383     m_xChars = (size.x - 2*m_xMargin) / m_widthChar;
384     m_yChars = (size.y - 2*m_yMargin) / m_heightChar;
385     if ( !m_xChars )
386         m_xChars = 1;
387     if ( !m_yChars )
388         m_yChars = 1;
389 
390     free(m_text);
391     m_text = (wxChar *)calloc(m_xChars * m_yChars, sizeof(wxChar));
392 
393 #if wxUSE_STATUSBAR
394     wxFrame *frame = wxDynamicCast(GetParent(), wxFrame);
395 
396     if ( frame && frame->GetStatusBar() )
397     {
398         wxString msg;
399         msg.Printf(wxT("Panel size is (%d, %d)"), m_xChars, m_yChars);
400         frame->SetStatusText(msg, 1);
401     }
402 #endif // wxUSE_STATUSBAR
403 }
404 
405 // NB: this method is horrible inefficient especially because the caret
406 //     needs to be redrawn often and in this case we only have to redraw
407 //     the caret location and not the entire window - in a real program we
408 //     would use GetUpdateRegion() and iterate over rectangles it contains
OnPaint(wxPaintEvent & WXUNUSED (event))409 void MyCanvas::OnPaint( wxPaintEvent &WXUNUSED(event) )
410 {
411     wxCaretSuspend cs(this);
412     wxPaintDC dc( this );
413     PrepareDC( dc );
414     dc.Clear();
415 
416     dc.SetFont( m_font );
417 
418     for ( int y = 0; y < m_yChars; y++ )
419     {
420         wxString line;
421 
422         for ( int x = 0; x < m_xChars; x++ )
423         {
424             wxChar ch = CharAt(x, y);
425             if ( !ch )
426                 ch = wxT(' ');
427 #ifdef __WXOSX__
428             dc.DrawText(ch, m_xMargin + x * m_widthChar,
429                         m_yMargin + y * m_heightChar );
430 #else
431             line += ch;
432 #endif
433         }
434 
435 #ifndef __WXOSX__
436         dc.DrawText( line, m_xMargin, m_yMargin + y * m_heightChar );
437 #endif
438     }
439 }
440 
OnChar(wxKeyEvent & event)441 void MyCanvas::OnChar( wxKeyEvent &event )
442 {
443     switch ( event.GetKeyCode() )
444     {
445         case WXK_LEFT:
446             PrevChar();
447             break;
448 
449         case WXK_RIGHT:
450             NextChar();
451             break;
452 
453         case WXK_UP:
454             PrevLine();
455             break;
456 
457         case WXK_DOWN:
458             NextLine();
459             break;
460 
461         case WXK_HOME:
462             Home();
463             break;
464 
465         case WXK_END:
466             End();
467             break;
468 
469         case WXK_RETURN:
470             Home();
471             NextLine();
472             break;
473 
474         default:
475             if ( !event.AltDown() && wxIsprint(event.GetKeyCode()) )
476             {
477                 wxChar ch = (wxChar)event.GetKeyCode();
478                 CharAt(m_xCaret, m_yCaret) = ch;
479 
480                 wxCaretSuspend cs(this);
481                 wxClientDC dc(this);
482                 dc.SetFont(m_font);
483                 dc.SetBackgroundMode(wxSOLID); // overwrite old value
484                 dc.DrawText(ch, m_xMargin + m_xCaret * m_widthChar,
485                                 m_yMargin + m_yCaret * m_heightChar );
486 
487                 NextChar();
488             }
489             else
490             {
491                 event.Skip();
492             }
493     }
494 
495     DoMoveCaret();
496 }
497 
498