TextBoxBase.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
  1. // Permission is hereby granted, free of charge, to any person obtaining
  2. // a copy of this software and associated documentation files (the
  3. // "Software"), to deal in the Software without restriction, including
  4. // without limitation the rights to use, copy, modify, merge, publish,
  5. // distribute, sublicense, and/or sell copies of the Software, and to
  6. // permit persons to whom the Software is furnished to do so, subject to
  7. // the following conditions:
  8. //
  9. // The above copyright notice and this permission notice shall be
  10. // included in all copies or substantial portions of the Software.
  11. //
  12. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  13. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  14. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  15. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  16. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  17. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  18. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  19. //
  20. // Copyright (c) 2004 Novell, Inc. (http://www.novell.com)
  21. //
  22. // Authors:
  23. // Peter Bartok [email protected]
  24. //
  25. //
  26. // NOT COMPLETE
  27. #define Debug
  28. using System.Drawing;
  29. using System.Drawing.Text;
  30. namespace System.Windows.Forms {
  31. public abstract class TextBoxBase : Control {
  32. #region Local Variables
  33. internal bool accepts_tab;
  34. internal bool auto_size;
  35. internal BorderStyle border_style;
  36. internal bool undo;
  37. internal bool hide_selection;
  38. internal int max_length;
  39. internal bool modified;
  40. internal bool multiline;
  41. internal int preferred_height;
  42. internal bool read_only;
  43. internal bool word_wrap;
  44. internal Document document;
  45. internal LineTag caret_tag; // tag our cursor is in
  46. internal int caret_pos; // position on the line our cursor is in (can be 0 = beginning of line)
  47. internal int viewport_x; // left visible pixel
  48. internal int viewport_y; // top visible pixel
  49. #if Debug
  50. internal static bool draw_lines = true;
  51. #endif
  52. #endregion // Local Variables
  53. #region Private Constructor
  54. // Constructor will go when complete, only for testing - pdb
  55. public TextBoxBase() {
  56. accepts_tab = false;
  57. auto_size = true;
  58. border_style = BorderStyle.Fixed3D;
  59. undo = false;
  60. hide_selection = true;
  61. max_length = 32767;
  62. modified = false;
  63. multiline = false;
  64. preferred_height = 10;
  65. read_only = false;
  66. word_wrap = true;
  67. document = new Document(this);
  68. this.MouseDown += new MouseEventHandler(TextBoxBase_MouseDown);
  69. this.MouseUp += new MouseEventHandler(TextBoxBase_MouseUp);
  70. //SetStyle(ControlStyles.ResizeRedraw, true);
  71. SetStyle(ControlStyles.AllPaintingInWmPaint, true);
  72. SetStyle(ControlStyles.UserPaint, true);
  73. }
  74. #endregion // Private Constructor
  75. #region Public Instance Properties
  76. public bool AcceptsTab {
  77. get {
  78. return accepts_tab;
  79. }
  80. set {
  81. if (value != accepts_tab) {
  82. accepts_tab = value;
  83. OnAcceptsTabChanged(EventArgs.Empty);
  84. }
  85. }
  86. }
  87. public virtual bool AutoSize {
  88. get {
  89. return auto_size;
  90. }
  91. set {
  92. if (value != auto_size) {
  93. auto_size = value;
  94. OnAutoSizeChanged(EventArgs.Empty);
  95. }
  96. }
  97. }
  98. public override System.Drawing.Color BackColor {
  99. get {
  100. return base.BackColor;
  101. }
  102. set {
  103. base.BackColor = value;
  104. }
  105. }
  106. public override System.Drawing.Image BackgroundImage {
  107. get {
  108. return base.BackgroundImage;
  109. }
  110. set {
  111. base.BackgroundImage = value;
  112. }
  113. }
  114. public BorderStyle BorderStyle {
  115. get {
  116. return border_style;
  117. }
  118. set {
  119. if (value != border_style) {
  120. border_style = value;
  121. OnBorderStyleChanged(EventArgs.Empty);
  122. }
  123. }
  124. }
  125. public bool CanUndo {
  126. get {
  127. return undo;
  128. }
  129. }
  130. public override System.Drawing.Color ForeColor {
  131. get {
  132. return base.ForeColor;
  133. }
  134. set {
  135. base.ForeColor = value;
  136. }
  137. }
  138. public bool HideSelection {
  139. get {
  140. return hide_selection;
  141. }
  142. set {
  143. if (value != hide_selection) {
  144. hide_selection = value;
  145. OnHideSelectionChanged(EventArgs.Empty);
  146. }
  147. }
  148. }
  149. public string[] Lines {
  150. get {
  151. // FIXME
  152. return null;
  153. }
  154. set {
  155. // FIXME
  156. }
  157. }
  158. public virtual int MaxLength {
  159. get {
  160. return max_length;
  161. }
  162. set {
  163. if (value != max_length) {
  164. max_length = value;
  165. }
  166. }
  167. }
  168. public bool Modified {
  169. get {
  170. return modified;
  171. }
  172. set {
  173. if (value != modified) {
  174. modified = value;
  175. OnModifiedChanged(EventArgs.Empty);
  176. }
  177. }
  178. }
  179. public virtual bool Multiline {
  180. get {
  181. return multiline;
  182. }
  183. set {
  184. if (value != multiline) {
  185. multiline = value;
  186. OnMultilineChanged(EventArgs.Empty);
  187. }
  188. }
  189. }
  190. public int PreferredHeight {
  191. get {
  192. return preferred_height;
  193. }
  194. }
  195. public bool ReadOnly {
  196. get {
  197. return read_only;
  198. }
  199. set {
  200. if (value != read_only) {
  201. read_only = value;
  202. OnReadOnlyChanged(EventArgs.Empty);
  203. }
  204. }
  205. }
  206. public virtual string SelectedText {
  207. get {
  208. // FIXME
  209. return string.Empty;
  210. }
  211. set {
  212. // FIXME
  213. }
  214. }
  215. public virtual int SelectionLength {
  216. get {
  217. // FIXME
  218. return 0;
  219. }
  220. set {
  221. // FIXME
  222. }
  223. }
  224. public bool WordWrap {
  225. get {
  226. return word_wrap;
  227. }
  228. set {
  229. if (value != word_wrap) {
  230. word_wrap = value;
  231. }
  232. }
  233. }
  234. #endregion // Public Instance Properties
  235. #region Protected Instance Properties
  236. protected override CreateParams CreateParams {
  237. get {
  238. return base.CreateParams;
  239. }
  240. }
  241. protected override System.Drawing.Size DefaultSize {
  242. get {
  243. return base.DefaultSize;
  244. }
  245. }
  246. #endregion // Protected Instance Properties
  247. #region Public Instance Methods
  248. public void AppendText(string text) {
  249. // FIXME
  250. throw new NotImplementedException();
  251. }
  252. public void Clear() {
  253. // FIXME
  254. throw new NotImplementedException();
  255. }
  256. public void ClearUndo() {
  257. // FIXME
  258. throw new NotImplementedException();
  259. }
  260. public void Copy() {
  261. // FIXME
  262. throw new NotImplementedException();
  263. }
  264. public void Cut() {
  265. // FIXME
  266. throw new NotImplementedException();
  267. }
  268. public void Paste() {
  269. // FIXME
  270. throw new NotImplementedException();
  271. }
  272. public void ScrollToCaret() {
  273. // FIXME
  274. throw new NotImplementedException();
  275. }
  276. public void Select(int start, int length) {
  277. // FIXME
  278. throw new NotImplementedException();
  279. }
  280. public void SelectAll() {
  281. }
  282. public override string ToString() {
  283. // FIXME
  284. return base.ToString ();
  285. }
  286. public void Undo() {
  287. }
  288. #endregion // Public Instance Methods
  289. #region Protected Instance Methods
  290. protected override void CreateHandle() {
  291. base.CreateHandle ();
  292. }
  293. protected virtual void OnAcceptsTabChanged(EventArgs e) {
  294. if (AcceptsTabChanged != null) {
  295. AcceptsTabChanged(this, e);
  296. }
  297. }
  298. protected virtual void OnAutoSizeChanged(EventArgs e) {
  299. if (AutoSizeChanged != null) {
  300. AutoSizeChanged(this, e);
  301. }
  302. }
  303. protected virtual void OnBorderStyleChanged(EventArgs e) {
  304. if (BorderStyleChanged != null) {
  305. BorderStyleChanged(this, e);
  306. }
  307. }
  308. protected override void OnFontChanged(EventArgs e) {
  309. base.OnFontChanged (e);
  310. }
  311. protected override void OnHandleCreated(EventArgs e) {
  312. base.OnHandleCreated (e);
  313. }
  314. protected override void OnHandleDestroyed(EventArgs e) {
  315. base.OnHandleDestroyed (e);
  316. }
  317. protected virtual void OnHideSelectionChanged(EventArgs e) {
  318. if (HideSelectionChanged != null) {
  319. HideSelectionChanged(this, e);
  320. }
  321. }
  322. protected virtual void OnModifiedChanged(EventArgs e) {
  323. if (ModifiedChanged != null) {
  324. ModifiedChanged(this, e);
  325. }
  326. }
  327. protected virtual void OnMultilineChanged(EventArgs e) {
  328. if (MultilineChanged != null) {
  329. MultilineChanged(this, e);
  330. }
  331. }
  332. protected virtual void OnReadOnlyChanged(EventArgs e) {
  333. if (ReadOnlyChanged != null) {
  334. ReadOnlyChanged(this, e);
  335. }
  336. }
  337. protected override bool ProcessDialogKey(Keys keyData) {
  338. return base.ProcessDialogKey (keyData);
  339. }
  340. protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified) {
  341. base.SetBoundsCore (x, y, width, height, specified);
  342. }
  343. protected override void WndProc(ref Message m) {
  344. switch ((Msg)m.Msg) {
  345. case Msg.WM_PAINT: {
  346. PaintEventArgs paint_event;
  347. #if !__MonoCS__
  348. XplatUIWin32.Win32SetFocus(Handle);
  349. #endif
  350. paint_event = XplatUI.PaintEventStart(Handle);
  351. PaintControl(paint_event);
  352. XplatUI.PaintEventEnd(Handle);
  353. DefWndProc(ref m);
  354. return;
  355. }
  356. case Msg.WM_SETFOCUS: {
  357. // Set caret
  358. document.CaretHasFocus();
  359. Console.WriteLine("Creating caret");
  360. base.WndProc(ref m);
  361. return;
  362. }
  363. case Msg.WM_KILLFOCUS: {
  364. // Kill caret
  365. document.CaretLostFocus();
  366. Console.WriteLine("Destroying caret");
  367. base.WndProc(ref m);
  368. return;
  369. }
  370. case Msg.WM_KEYDOWN: {
  371. switch ((Keys)(m.WParam.ToInt32())) {
  372. case Keys.Left: {
  373. if ((Control.ModifierKeys & Keys.Control) != 0) {
  374. document.MoveCaret(CaretDirection.WordBack);
  375. } else {
  376. document.MoveCaret(CaretDirection.CharBack);
  377. }
  378. return;
  379. }
  380. case Keys.Right: {
  381. if ((Control.ModifierKeys & Keys.Control) != 0) {
  382. document.MoveCaret(CaretDirection.WordForward);
  383. } else {
  384. document.MoveCaret(CaretDirection.CharForward);
  385. }
  386. return;
  387. }
  388. case Keys.Up: {
  389. document.MoveCaret(CaretDirection.LineUp);
  390. return;
  391. }
  392. case Keys.Down: {
  393. document.DumpTree(document.Root, true);
  394. document.MoveCaret(CaretDirection.LineDown);
  395. return;
  396. }
  397. case Keys.Home: {
  398. if ((Control.ModifierKeys & Keys.Control) != 0) {
  399. document.MoveCaret(CaretDirection.CtrlHome);
  400. } else {
  401. document.MoveCaret(CaretDirection.Home);
  402. }
  403. return;
  404. }
  405. case Keys.End: {
  406. if ((Control.ModifierKeys & Keys.Control) != 0) {
  407. document.MoveCaret(CaretDirection.CtrlEnd);
  408. } else {
  409. document.MoveCaret(CaretDirection.End);
  410. }
  411. return;
  412. }
  413. case Keys.Enter: {
  414. document.Split(document.CaretLine, document.CaretTag, document.CaretPosition);
  415. document.UpdateView(document.CaretLine, 2, 0);
  416. document.MoveCaret(CaretDirection.CharForward);
  417. return;
  418. }
  419. case Keys.Back: {
  420. // delete only deletes on the line, doesn't do the combine
  421. if (document.CaretPosition == 0) {
  422. if (document.CaretLine.LineNo > 1) {
  423. Line line;
  424. int new_caret_pos;
  425. line = document.GetLine(document.CaretLine.LineNo - 1);
  426. new_caret_pos = line.text.Length;
  427. document.Combine(line, document.CaretLine);
  428. document.UpdateView(line, 1, 0);
  429. document.PositionCaret(line, new_caret_pos);
  430. document.UpdateCaret();
  431. }
  432. } else {
  433. document.DeleteChar(document.CaretTag, document.CaretPosition, false);
  434. document.MoveCaret(CaretDirection.CharBack);
  435. }
  436. return;
  437. }
  438. case Keys.Delete: {
  439. // delete only deletes on the line, doesn't do the combine
  440. if (document.CaretPosition == document.CaretLine.text.Length) {
  441. if (document.CaretLine.LineNo < document.Lines) {
  442. Line line;
  443. line = document.GetLine(document.CaretLine.LineNo + 1);
  444. document.Combine(document.CaretLine, line);
  445. document.UpdateView(document.CaretLine, 2, 0);
  446. #if Debug
  447. Line check_first;
  448. Line check_second;
  449. check_first = document.GetLine(document.CaretLine.LineNo);
  450. check_second = document.GetLine(check_first.line_no + 1);
  451. Console.WriteLine("Post-UpdateView: Y of first line: {0}, second line: {1}", check_first.Y, check_second.Y);
  452. #endif
  453. // Caret doesn't move
  454. }
  455. } else {
  456. document.DeleteChar(document.CaretTag, document.CaretPosition, true);
  457. }
  458. return;
  459. }
  460. }
  461. return;
  462. }
  463. case Msg.WM_CHAR: {
  464. Console.WriteLine("Got char, inserting at cursor");
  465. if (m.WParam.ToInt32() >= 32) { // FIXME, tabs should probably go through
  466. document.InsertCharAtCaret((char)m.WParam, true);
  467. }
  468. return;
  469. }
  470. default: {
  471. base.WndProc(ref m);
  472. return;
  473. }
  474. }
  475. }
  476. #endregion // Protected Instance Methods
  477. #region Events
  478. public event EventHandler AcceptsTabChanged;
  479. public event EventHandler AutoSizeChanged;
  480. public event EventHandler BorderStyleChanged;
  481. public event EventHandler Click;
  482. public event EventHandler HideSelectionChanged;
  483. public event EventHandler ModifiedChanged;
  484. public event EventHandler MultilineChanged;
  485. public event PaintEventHandler Paint;
  486. public event EventHandler ReadOnlyChanged;
  487. #endregion // Events
  488. #region Private Methods
  489. public Document Document {
  490. get {
  491. return document;
  492. }
  493. set {
  494. document = value;
  495. }
  496. }
  497. static int current;
  498. private void PaintControl(PaintEventArgs pevent) {
  499. Console.WriteLine("Received expose: {0}", pevent.ClipRectangle);
  500. // Fill background
  501. pevent.Graphics.FillRectangle(ThemeEngine.Current.ResPool.GetSolidBrush(BackColor), pevent.ClipRectangle);
  502. pevent.Graphics.TextRenderingHint=TextRenderingHint.AntiAlias;
  503. // Draw the viewable document
  504. document.Draw(pevent.Graphics, pevent.ClipRectangle);
  505. #if Debug
  506. int start;
  507. int end;
  508. Line line;
  509. int line_no;
  510. LineTag tag;
  511. Pen p;
  512. p = new Pen(Color.Red, 1);
  513. // First, figure out from what line to what line we need to draw
  514. start = document.GetLineByPixel(pevent.ClipRectangle.Top - viewport_y, false).line_no;
  515. end = document.GetLineByPixel(pevent.ClipRectangle.Bottom - viewport_y, false).line_no;
  516. Console.WriteLine("Starting drawing on line '{0}'", document.GetLine(start));
  517. Console.WriteLine("Ending drawing on line '{0}'", document.GetLine(end));
  518. line_no = start;
  519. while (line_no <= end) {
  520. line = document.GetLine(line_no);
  521. if (draw_lines) {
  522. for (int i = 0; i < line.text.Length; i++) {
  523. pevent.Graphics.DrawLine(p, (int)line.widths[i] - viewport_x, line.Y - viewport_y, (int)line.widths[i] - viewport_x, line.Y + line.height - viewport_y);
  524. }
  525. }
  526. line_no++;
  527. }
  528. #endif
  529. }
  530. private void TextBoxBase_MouseDown(object sender, MouseEventArgs e) {
  531. LineTag tag;
  532. Line line;
  533. int pos;
  534. if (e.Button == MouseButtons.Left) {
  535. document.PositionCaret(e.X, e.Y);
  536. return;
  537. }
  538. if (e.Button == MouseButtons.Right) {
  539. #if Debug
  540. draw_lines = !draw_lines;
  541. #endif
  542. ((Control)sender).Invalidate();
  543. return;
  544. }
  545. tag = document.FindTag(e.X, e.Y, out pos, false);
  546. bool recalc_line = false;
  547. Console.WriteLine("Click found tag {0}, character {1}", tag, pos);
  548. line = tag.line;
  549. switch(current) {
  550. case 4: recalc_line = LineTag.FormatText(tag.line, pos, (pos+10)<line.Text.Length ? 10 : line.Text.Length - pos+1, new Font("impact", 20, FontStyle.Bold, GraphicsUnit.Pixel), ThemeEngine.Current.ResPool.GetSolidBrush(Color.Red)); break;
  551. case 1: recalc_line = LineTag.FormatText(tag.line, pos, (pos+10)<line.Text.Length ? 10 : line.Text.Length - pos+1, new Font("arial unicode ms", 24, FontStyle.Italic, GraphicsUnit.Pixel), ThemeEngine.Current.ResPool.GetSolidBrush(Color.DarkGoldenrod)); break;
  552. case 2: recalc_line = LineTag.FormatText(tag.line, pos, (pos+10)<line.Text.Length ? 10 : line.Text.Length - pos+1, new Font("arial", 10, FontStyle.Regular, GraphicsUnit.Pixel), ThemeEngine.Current.ResPool.GetSolidBrush(Color.Aquamarine)); break;
  553. case 3: recalc_line = LineTag.FormatText(tag.line, pos, (pos+10)<line.Text.Length ? 10 : line.Text.Length - pos+1, new Font("times roman", 16, FontStyle.Underline, GraphicsUnit.Pixel), ThemeEngine.Current.ResPool.GetSolidBrush(Color.Turquoise)); break;
  554. case 0: recalc_line = LineTag.FormatText(tag.line, pos, (pos+10)<line.Text.Length ? 10 : line.Text.Length - pos+1, new Font("times roman", 64, FontStyle.Italic | FontStyle.Bold, GraphicsUnit.Pixel), ThemeEngine.Current.ResPool.GetSolidBrush(Color.LightSeaGreen)); break;
  555. case 5: recalc_line = LineTag.FormatText(tag.line, pos, (pos+10)<line.Text.Length ? 10 : line.Text.Length - pos+1, ((TextBoxBase)sender).Font, ThemeEngine.Current.ResPool.GetSolidBrush(ForeColor)); break;
  556. }
  557. current++;
  558. if (current==6) {
  559. current=0;
  560. }
  561. // Update/Recalculate what we see
  562. document.UpdateView(line, 0);
  563. // Make sure our caret is properly positioned and sized
  564. document.AlignCaret();
  565. }
  566. private void TextBoxBase_MouseUp(object sender, MouseEventArgs e) {
  567. if (e.Button == MouseButtons.Left) {
  568. document.PositionCaret(e.X, e.Y);
  569. document.DisplayCaret();
  570. return;
  571. }
  572. }
  573. #endregion // Private Methods
  574. }
  575. }