caret.cpp 14 KB

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