TextBoxBase.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095
  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. using System.Text;
  31. namespace System.Windows.Forms {
  32. public abstract class TextBoxBase : Control {
  33. #region Local Variables
  34. internal HorizontalAlignment alignment;
  35. internal bool accepts_tab;
  36. internal bool accepts_return;
  37. internal bool auto_size;
  38. internal CharacterCasing character_casing;
  39. internal bool undo;
  40. internal bool hide_selection;
  41. internal int max_length;
  42. internal bool modified;
  43. internal bool multiline;
  44. internal bool read_only;
  45. internal bool word_wrap;
  46. internal Document document;
  47. internal LineTag caret_tag; // tag our cursor is in
  48. internal int caret_pos; // position on the line our cursor is in (can be 0 = beginning of line)
  49. internal int viewport_x; // left visible pixel
  50. internal int viewport_y; // top visible pixel
  51. internal HScrollBar hscroll;
  52. internal VScrollBar vscroll;
  53. internal ScrollBars scrollbars;
  54. internal bool grabbed;
  55. internal bool richtext;
  56. internal Rectangle text_bounds;
  57. #if Debug
  58. internal static bool draw_lines = false;
  59. #endif
  60. #endregion // Local Variables
  61. #region Private Constructor
  62. // Constructor will go when complete, only for testing - pdb
  63. public TextBoxBase() {
  64. alignment = HorizontalAlignment.Left;
  65. accepts_return = false;
  66. accepts_tab = false;
  67. auto_size = true;
  68. border_style = BorderStyle.Fixed3D;
  69. character_casing = CharacterCasing.Normal;
  70. undo = false;
  71. hide_selection = true;
  72. max_length = 32767;
  73. modified = false;
  74. multiline = false;
  75. read_only = false;
  76. word_wrap = true;
  77. richtext = false;
  78. document = new Document(this);
  79. text_bounds = Rectangle.Empty;
  80. MouseDown += new MouseEventHandler(TextBoxBase_MouseDown);
  81. MouseUp += new MouseEventHandler(TextBoxBase_MouseUp);
  82. MouseMove += new MouseEventHandler(TextBoxBase_MouseMove);
  83. SizeChanged += new EventHandler(TextBoxBase_SizeChanged);
  84. FontChanged += new EventHandler(TextBoxBase_FontOrColorChanged);
  85. ForeColorChanged += new EventHandler(TextBoxBase_FontOrColorChanged);
  86. scrollbars = ScrollBars.None;
  87. hscroll = new HScrollBar();
  88. hscroll.ValueChanged +=new EventHandler(hscroll_ValueChanged);
  89. hscroll.Enabled = true;
  90. hscroll.Visible = false;
  91. vscroll = new VScrollBar();
  92. vscroll.Visible = false;
  93. this.Controls.Add(hscroll);
  94. this.Controls.Add(vscroll);
  95. //SetStyle(ControlStyles.ResizeRedraw, true);
  96. SetStyle(ControlStyles.AllPaintingInWmPaint, true);
  97. SetStyle(ControlStyles.UserPaint, true);
  98. }
  99. #endregion // Private Constructor
  100. #region Private and Internal Methods
  101. internal string CaseAdjust(string s) {
  102. if (character_casing == CharacterCasing.Normal) {
  103. return s;
  104. }
  105. if (character_casing == CharacterCasing.Lower) {
  106. return s.ToLower();
  107. } else {
  108. return s.ToUpper();
  109. }
  110. }
  111. #endregion // Private and Internal Methods
  112. #region Public Instance Properties
  113. public bool AcceptsTab {
  114. get {
  115. return accepts_tab;
  116. }
  117. set {
  118. if (value != accepts_tab) {
  119. accepts_tab = value;
  120. OnAcceptsTabChanged(EventArgs.Empty);
  121. }
  122. }
  123. }
  124. public virtual bool AutoSize {
  125. get {
  126. return auto_size;
  127. }
  128. set {
  129. if (value != auto_size) {
  130. auto_size = value;
  131. if (auto_size) {
  132. if (PreferredHeight != Height) {
  133. Height = PreferredHeight;
  134. }
  135. }
  136. OnAutoSizeChanged(EventArgs.Empty);
  137. }
  138. }
  139. }
  140. public override System.Drawing.Color BackColor {
  141. get {
  142. return base.BackColor;
  143. }
  144. set {
  145. base.BackColor = value;
  146. }
  147. }
  148. public override System.Drawing.Image BackgroundImage {
  149. get {
  150. return base.BackgroundImage;
  151. }
  152. set {
  153. base.BackgroundImage = value;
  154. }
  155. }
  156. public BorderStyle BorderStyle {
  157. get {
  158. return border_style;
  159. }
  160. set {
  161. if (value != border_style) {
  162. border_style = value;
  163. OnBorderStyleChanged(EventArgs.Empty);
  164. }
  165. }
  166. }
  167. public bool CanUndo {
  168. get {
  169. return undo;
  170. }
  171. }
  172. public override System.Drawing.Color ForeColor {
  173. get {
  174. return base.ForeColor;
  175. }
  176. set {
  177. base.ForeColor = value;
  178. }
  179. }
  180. public bool HideSelection {
  181. get {
  182. return hide_selection;
  183. }
  184. set {
  185. if (value != hide_selection) {
  186. hide_selection = value;
  187. OnHideSelectionChanged(EventArgs.Empty);
  188. }
  189. if (hide_selection) {
  190. document.selection_visible = false;
  191. } else {
  192. document.selection_visible = true;
  193. }
  194. document.InvalidateSelectionArea();
  195. }
  196. }
  197. public string[] Lines {
  198. get {
  199. string[] lines;
  200. int i;
  201. int l;
  202. l = document.Lines;
  203. lines = new string[l];
  204. for (i = 1; i <= l; i++) {
  205. lines[i - 1] = document.GetLine(i).text.ToString();
  206. }
  207. return lines;
  208. }
  209. set {
  210. int i;
  211. int l;
  212. Brush brush;
  213. document.Empty();
  214. l = value.Length;
  215. brush = ThemeEngine.Current.ResPool.GetSolidBrush(this.ForeColor);
  216. for (i = 0; i < l; i++) {
  217. document.Add(i+1, CaseAdjust(value[i]), alignment, Font, brush);
  218. }
  219. document.RecalculateDocument(CreateGraphics());
  220. OnTextChanged(EventArgs.Empty);
  221. }
  222. }
  223. public virtual int MaxLength {
  224. get {
  225. return max_length;
  226. }
  227. set {
  228. if (value != max_length) {
  229. max_length = value;
  230. }
  231. }
  232. }
  233. public bool Modified {
  234. get {
  235. return modified;
  236. }
  237. set {
  238. if (value != modified) {
  239. modified = value;
  240. OnModifiedChanged(EventArgs.Empty);
  241. }
  242. }
  243. }
  244. public virtual bool Multiline {
  245. get {
  246. return multiline;
  247. }
  248. set {
  249. if (value != multiline) {
  250. multiline = value;
  251. // Make sure we update our size; the user may have already set the size before going to multiline
  252. if (text_bounds != Rectangle.Empty) {
  253. SetBoundsCore(text_bounds.X, text_bounds.Y, text_bounds.Width, text_bounds.Height, BoundsSpecified.All);
  254. }
  255. OnMultilineChanged(EventArgs.Empty);
  256. }
  257. document.multiline = multiline;
  258. }
  259. }
  260. public int PreferredHeight {
  261. get {
  262. return this.Font.Height + 7; // FIXME - consider border style as well
  263. }
  264. }
  265. public bool ReadOnly {
  266. get {
  267. return read_only;
  268. }
  269. set {
  270. if (value != read_only) {
  271. read_only = value;
  272. OnReadOnlyChanged(EventArgs.Empty);
  273. }
  274. }
  275. }
  276. public virtual string SelectedText {
  277. get {
  278. return document.GetSelection();
  279. }
  280. set {
  281. document.ReplaceSelection(CaseAdjust(value));
  282. OnTextChanged(EventArgs.Empty);
  283. }
  284. }
  285. public virtual int SelectionLength {
  286. get {
  287. return document.SelectionLength();
  288. }
  289. set {
  290. if (value != 0) {
  291. int start;
  292. Line line;
  293. LineTag tag;
  294. int pos;
  295. start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
  296. document.CharIndexToLineTag(start + value, out line, out tag, out pos);
  297. document.SetSelectionEnd(line, pos);
  298. document.PositionCaret(line, pos);
  299. } else {
  300. document.SetSelectionEnd(document.selection_start.line, document.selection_start.pos);
  301. document.PositionCaret(document.selection_start.line, document.selection_start.pos);
  302. }
  303. }
  304. }
  305. public int SelectionStart {
  306. get {
  307. int index;
  308. index = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
  309. return index;
  310. }
  311. set {
  312. Line line;
  313. LineTag tag;
  314. int pos;
  315. document.CharIndexToLineTag(value, out line, out tag, out pos);
  316. document.SetSelectionStart(line, pos);
  317. }
  318. }
  319. public override string Text {
  320. get {
  321. if (document == null || document.Root == null || document.Root.text == null) {
  322. return string.Empty;
  323. }
  324. if (!multiline) {
  325. return document.Root.text.ToString();
  326. } else {
  327. StringBuilder sb;
  328. int i;
  329. sb = new StringBuilder();
  330. for (i = 1; i < document.Lines; i++) {
  331. sb.Append(document.GetLine(i).text.ToString() + Environment.NewLine);
  332. }
  333. return sb.ToString();
  334. }
  335. }
  336. set {
  337. Line line;
  338. if (multiline) {
  339. string[] lines;
  340. lines = value.Split(new char[] {'\n'});
  341. for (int i = 0; i < lines.Length; i++) {
  342. if (lines[i].EndsWith("\r")) {
  343. lines[i] = lines[i].Substring(0, lines[i].Length - 1);
  344. }
  345. }
  346. this.Lines = lines;
  347. line = document.GetLine(1);
  348. document.SetSelectionStart(line, 0);
  349. line = document.GetLine(document.Lines);
  350. document.SetSelectionEnd(line, line.text.Length);
  351. document.PositionCaret(line, line.text.Length);
  352. } else {
  353. document.Clear();
  354. document.Add(1, CaseAdjust(value), alignment, Font, ThemeEngine.Current.ResPool.GetSolidBrush(ForeColor));
  355. document.RecalculateDocument(CreateGraphics());
  356. line = document.GetLine(1);
  357. document.SetSelectionStart(line, 0);
  358. document.SetSelectionEnd(line, value.Length);
  359. document.PositionCaret(line, value.Length);
  360. }
  361. base.Text = value;
  362. OnTextChanged(EventArgs.Empty);
  363. }
  364. }
  365. public virtual int TextLength {
  366. get {
  367. if (document == null || document.Root == null || document.Root.text == null) {
  368. return 0;
  369. }
  370. if (!multiline) {
  371. return document.Root.text.Length;
  372. } else {
  373. int total;
  374. int i;
  375. total = 0;
  376. for (i = 1; i < document.Lines; i++) {
  377. total += document.GetLine(i).text.Length + Environment.NewLine.Length;
  378. }
  379. return total;
  380. }
  381. }
  382. }
  383. public bool WordWrap {
  384. get {
  385. return word_wrap;
  386. }
  387. set {
  388. if (value != word_wrap) {
  389. word_wrap = value;
  390. }
  391. }
  392. }
  393. #endregion // Public Instance Properties
  394. #region Protected Instance Properties
  395. protected override CreateParams CreateParams {
  396. get {
  397. return base.CreateParams;
  398. }
  399. }
  400. protected override System.Drawing.Size DefaultSize {
  401. get {
  402. return base.DefaultSize;
  403. }
  404. }
  405. #endregion // Protected Instance Properties
  406. #region Public Instance Methods
  407. public void AppendText(string text) {
  408. if (multiline) {
  409. string[] lines;
  410. int linecount;
  411. // Break the string into separate lines
  412. lines = text.Split(new char[] {'\n'});
  413. linecount = lines.Length;
  414. for (int i = 0; i < linecount; i++) {
  415. if (lines[i].EndsWith("\r")) {
  416. lines[i] = lines[i].Substring(0, lines[i].Length - 1);
  417. }
  418. }
  419. // Grab the formatting for the last element
  420. document.MoveCaret(CaretDirection.CtrlEnd);
  421. // Insert the first line
  422. document.InsertString(document.CaretLine, document.CaretPosition, lines[0]);
  423. for (int i = 1; i < linecount; i++) {
  424. document.Add(document.CaretLine.LineNo+i, CaseAdjust(lines[i]), alignment, document.CaretTag.font, document.CaretTag.color);
  425. }
  426. document.RecalculateDocument(CreateGraphics());
  427. document.MoveCaret(CaretDirection.CtrlEnd);
  428. Invalidate();
  429. } else {
  430. document.MoveCaret(CaretDirection.CtrlEnd);
  431. document.InsertStringAtCaret(text, true);
  432. Invalidate();
  433. }
  434. OnTextChanged(EventArgs.Empty);
  435. }
  436. public void Clear() {
  437. // FIXME
  438. throw new NotImplementedException();
  439. }
  440. public void ClearUndo() {
  441. // FIXME
  442. throw new NotImplementedException();
  443. }
  444. public void Copy() {
  445. // FIXME
  446. throw new NotImplementedException();
  447. }
  448. public void Cut() {
  449. // FIXME
  450. throw new NotImplementedException();
  451. }
  452. public void Paste() {
  453. // FIXME
  454. throw new NotImplementedException();
  455. }
  456. public void ScrollToCaret() {
  457. // FIXME
  458. throw new NotImplementedException();
  459. }
  460. public void Select(int start, int length) {
  461. SelectionStart = start;
  462. SelectionLength = length;
  463. }
  464. public void SelectAll() {
  465. Line last;
  466. last = document.GetLine(document.Lines);
  467. document.SetSelectionStart(document.GetLine(1), 0);
  468. document.SetSelectionEnd(last, last.text.Length);
  469. }
  470. public override string ToString() {
  471. StringBuilder sb;
  472. int i;
  473. int end;
  474. sb = new StringBuilder();
  475. end = document.Lines;
  476. for (i = 1; i < end; i++) {
  477. sb.Append(document.GetLine(i).text.ToString() + "\n");
  478. }
  479. return sb.ToString();
  480. }
  481. public void Undo() {
  482. return;
  483. }
  484. #endregion // Public Instance Methods
  485. #region Protected Instance Methods
  486. protected override void CreateHandle() {
  487. base.CreateHandle ();
  488. }
  489. protected override bool IsInputKey(Keys keyData) {
  490. switch (keyData) {
  491. case Keys.Enter: {
  492. if (multiline && (accepts_return || ((keyData & Keys.Control) != 0))) {
  493. return true;
  494. }
  495. return false;
  496. }
  497. case Keys.Tab: {
  498. if (accepts_tab) {
  499. return true;
  500. }
  501. return false;
  502. }
  503. }
  504. return false;
  505. }
  506. protected virtual void OnAcceptsTabChanged(EventArgs e) {
  507. if (AcceptsTabChanged != null) {
  508. AcceptsTabChanged(this, e);
  509. }
  510. }
  511. protected virtual void OnAutoSizeChanged(EventArgs e) {
  512. if (AutoSizeChanged != null) {
  513. AutoSizeChanged(this, e);
  514. }
  515. }
  516. protected virtual void OnBorderStyleChanged(EventArgs e) {
  517. if (BorderStyleChanged != null) {
  518. BorderStyleChanged(this, e);
  519. }
  520. }
  521. protected override void OnFontChanged(EventArgs e) {
  522. base.OnFontChanged (e);
  523. if (auto_size) {
  524. if (PreferredHeight != Height) {
  525. Height = PreferredHeight;
  526. }
  527. }
  528. }
  529. protected override void OnHandleCreated(EventArgs e) {
  530. base.OnHandleCreated (e);
  531. }
  532. protected override void OnHandleDestroyed(EventArgs e) {
  533. base.OnHandleDestroyed (e);
  534. }
  535. protected virtual void OnHideSelectionChanged(EventArgs e) {
  536. if (HideSelectionChanged != null) {
  537. HideSelectionChanged(this, e);
  538. }
  539. }
  540. protected virtual void OnModifiedChanged(EventArgs e) {
  541. if (ModifiedChanged != null) {
  542. ModifiedChanged(this, e);
  543. }
  544. }
  545. protected virtual void OnMultilineChanged(EventArgs e) {
  546. if (MultilineChanged != null) {
  547. MultilineChanged(this, e);
  548. }
  549. }
  550. protected virtual void OnReadOnlyChanged(EventArgs e) {
  551. if (ReadOnlyChanged != null) {
  552. ReadOnlyChanged(this, e);
  553. }
  554. }
  555. protected override bool ProcessDialogKey(Keys keyData) {
  556. return base.ProcessDialogKey (keyData);
  557. }
  558. protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified) {
  559. // Make sure we don't get sized bigger than we want to be
  560. if (!richtext) {
  561. if (!multiline) {
  562. if (height > PreferredHeight) {
  563. text_bounds = new Rectangle(x, y, width, height);
  564. text_bounds.Height = PreferredHeight;
  565. }
  566. }
  567. }
  568. base.SetBoundsCore (x, y, width, height, specified);
  569. }
  570. protected override void WndProc(ref Message m) {
  571. switch ((Msg)m.Msg) {
  572. case Msg.WM_PAINT: {
  573. PaintEventArgs paint_event;
  574. paint_event = XplatUI.PaintEventStart(Handle);
  575. PaintControl(paint_event);
  576. XplatUI.PaintEventEnd(Handle);
  577. DefWndProc(ref m);
  578. return;
  579. }
  580. case Msg.WM_SETFOCUS: {
  581. // Set caret
  582. document.CaretHasFocus();
  583. Console.WriteLine("Creating caret");
  584. base.WndProc(ref m);
  585. return;
  586. }
  587. case Msg.WM_KILLFOCUS: {
  588. // Kill caret
  589. document.CaretLostFocus();
  590. Console.WriteLine("Destroying caret");
  591. base.WndProc(ref m);
  592. return;
  593. }
  594. case Msg.WM_KEYDOWN: {
  595. switch ((Keys)(m.WParam.ToInt32())) {
  596. case Keys.Left: {
  597. document.SetSelectionToCaret(true);
  598. if ((Control.ModifierKeys & Keys.Control) != 0) {
  599. document.MoveCaret(CaretDirection.WordBack);
  600. } else {
  601. document.MoveCaret(CaretDirection.CharBack);
  602. }
  603. return;
  604. }
  605. case Keys.Right: {
  606. document.SetSelectionToCaret(true);
  607. if ((Control.ModifierKeys & Keys.Control) != 0) {
  608. document.MoveCaret(CaretDirection.WordForward);
  609. } else {
  610. document.MoveCaret(CaretDirection.CharForward);
  611. }
  612. return;
  613. }
  614. case Keys.Up: {
  615. document.SetSelectionToCaret(true);
  616. document.MoveCaret(CaretDirection.LineUp);
  617. return;
  618. }
  619. case Keys.Down: {
  620. document.SetSelectionToCaret(true);
  621. document.MoveCaret(CaretDirection.LineDown);
  622. return;
  623. }
  624. case Keys.Home: {
  625. document.SetSelectionToCaret(true);
  626. if ((Control.ModifierKeys & Keys.Control) != 0) {
  627. document.MoveCaret(CaretDirection.CtrlHome);
  628. } else {
  629. document.MoveCaret(CaretDirection.Home);
  630. }
  631. return;
  632. }
  633. case Keys.End: {
  634. document.SetSelectionToCaret(true);
  635. if ((Control.ModifierKeys & Keys.Control) != 0) {
  636. document.MoveCaret(CaretDirection.CtrlEnd);
  637. } else {
  638. document.MoveCaret(CaretDirection.End);
  639. }
  640. return;
  641. }
  642. case Keys.Enter: {
  643. if (multiline && (accepts_return || ((Control.ModifierKeys & Keys.Control) != 0))) {
  644. if (document.selection_visible) {
  645. document.ReplaceSelection("");
  646. }
  647. document.SetSelectionToCaret(true);
  648. document.Split(document.CaretLine, document.CaretTag, document.CaretPosition);
  649. OnTextChanged(EventArgs.Empty);
  650. document.UpdateView(document.CaretLine, 2, 0);
  651. document.MoveCaret(CaretDirection.CharForward);
  652. return;
  653. }
  654. break;
  655. }
  656. case Keys.Tab: {
  657. if (accepts_tab) {
  658. document.InsertChar(document.CaretLine, document.CaretPosition, '\t');
  659. if (document.selection_visible) {
  660. document.ReplaceSelection("");
  661. }
  662. document.SetSelectionToCaret(true);
  663. OnTextChanged(EventArgs.Empty);
  664. } else {
  665. base.WndProc(ref m);
  666. }
  667. return;
  668. }
  669. case Keys.Back: {
  670. // delete only deletes on the line, doesn't do the combine
  671. if (document.selection_visible) {
  672. document.ReplaceSelection("");
  673. }
  674. document.SetSelectionToCaret(true);
  675. if (document.CaretPosition == 0) {
  676. if (document.CaretLine.LineNo > 1) {
  677. Line line;
  678. int new_caret_pos;
  679. line = document.GetLine(document.CaretLine.LineNo - 1);
  680. new_caret_pos = line.text.Length;
  681. document.Combine(line, document.CaretLine);
  682. document.UpdateView(line, 1, 0);
  683. document.PositionCaret(line, new_caret_pos);
  684. document.UpdateCaret();
  685. OnTextChanged(EventArgs.Empty);
  686. }
  687. } else {
  688. document.DeleteChar(document.CaretTag, document.CaretPosition, false);
  689. document.MoveCaret(CaretDirection.CharBack);
  690. OnTextChanged(EventArgs.Empty);
  691. }
  692. return;
  693. }
  694. case Keys.Delete: {
  695. // delete only deletes on the line, doesn't do the combine
  696. if (document.CaretPosition == document.CaretLine.text.Length) {
  697. if (document.CaretLine.LineNo < document.Lines) {
  698. Line line;
  699. line = document.GetLine(document.CaretLine.LineNo + 1);
  700. document.Combine(document.CaretLine, line);
  701. document.UpdateView(document.CaretLine, 2, 0);
  702. OnTextChanged(EventArgs.Empty);
  703. #if Debug
  704. Line check_first;
  705. Line check_second;
  706. check_first = document.GetLine(document.CaretLine.LineNo);
  707. check_second = document.GetLine(check_first.line_no + 1);
  708. Console.WriteLine("Post-UpdateView: Y of first line: {0}, second line: {1}", check_first.Y, check_second.Y);
  709. #endif
  710. // Caret doesn't move
  711. }
  712. } else {
  713. document.DeleteChar(document.CaretTag, document.CaretPosition, true);
  714. OnTextChanged(EventArgs.Empty);
  715. }
  716. return;
  717. }
  718. }
  719. base.WndProc(ref m);
  720. return;
  721. }
  722. case Msg.WM_CHAR: {
  723. if (m.WParam.ToInt32() >= 32) { // FIXME, tabs should probably go through
  724. if (document.selection_visible) {
  725. document.ReplaceSelection("");
  726. }
  727. switch (character_casing) {
  728. case CharacterCasing.Normal: {
  729. document.InsertCharAtCaret((char)m.WParam, true);
  730. OnTextChanged(EventArgs.Empty);
  731. return;
  732. }
  733. case CharacterCasing.Lower: {
  734. document.InsertCharAtCaret(Char.ToLower((char)m.WParam), true);
  735. OnTextChanged(EventArgs.Empty);
  736. return;
  737. }
  738. case CharacterCasing.Upper: {
  739. document.InsertCharAtCaret(Char.ToUpper((char)m.WParam), true);
  740. OnTextChanged(EventArgs.Empty);
  741. return;
  742. }
  743. }
  744. }
  745. base.WndProc(ref m);
  746. return;
  747. }
  748. default: {
  749. base.WndProc(ref m);
  750. return;
  751. }
  752. }
  753. }
  754. #endregion // Protected Instance Methods
  755. #region Events
  756. public event EventHandler AcceptsTabChanged;
  757. public event EventHandler AutoSizeChanged;
  758. public event EventHandler BorderStyleChanged;
  759. public event EventHandler Click;
  760. public event EventHandler HideSelectionChanged;
  761. public event EventHandler ModifiedChanged;
  762. public event EventHandler MultilineChanged;
  763. public event PaintEventHandler Paint;
  764. public event EventHandler ReadOnlyChanged;
  765. #endregion // Events
  766. #region Private Methods
  767. internal Document Document {
  768. get {
  769. return document;
  770. }
  771. set {
  772. document = value;
  773. }
  774. }
  775. static int current;
  776. private void PaintControl(PaintEventArgs pevent) {
  777. // Fill background
  778. pevent.Graphics.FillRectangle(ThemeEngine.Current.ResPool.GetSolidBrush(BackColor), pevent.ClipRectangle);
  779. //pevent.Graphics.TextRenderingHint=TextRenderingHint.AntiAlias;
  780. // Draw the viewable document
  781. document.Draw(pevent.Graphics, pevent.ClipRectangle);
  782. Rectangle rect = ClientRectangle;
  783. rect.Width--;
  784. rect.Height--;
  785. pevent.Graphics.DrawRectangle(ThemeEngine.Current.ResPool.GetPen(ThemeEngine.Current.ColorButtonShadow), rect);
  786. // Set the scrollbar
  787. switch (scrollbars) {
  788. case ScrollBars.Both: {
  789. break;
  790. }
  791. case ScrollBars.Vertical: {
  792. break;
  793. }
  794. case ScrollBars.Horizontal: {
  795. hscroll.Minimum = 0;
  796. hscroll.Maximum = document.Width - this.Width;
  797. break;
  798. }
  799. }
  800. #if Debug
  801. int start;
  802. int end;
  803. Line line;
  804. int line_no;
  805. Pen p;
  806. p = new Pen(Color.Red, 1);
  807. // First, figure out from what line to what line we need to draw
  808. start = document.GetLineByPixel(pevent.ClipRectangle.Top - viewport_y, false).line_no;
  809. end = document.GetLineByPixel(pevent.ClipRectangle.Bottom - viewport_y, false).line_no;
  810. //Console.WriteLine("Starting drawing on line '{0}'", document.GetLine(start));
  811. //Console.WriteLine("Ending drawing on line '{0}'", document.GetLine(end));
  812. line_no = start;
  813. while (line_no <= end) {
  814. line = document.GetLine(line_no);
  815. if (draw_lines) {
  816. for (int i = 0; i < line.text.Length; i++) {
  817. pevent.Graphics.DrawLine(p, (int)line.widths[i] - document.ViewPortX, line.Y - document.ViewPortY, (int)line.widths[i] - document.ViewPortX, line.Y + line.height - document.ViewPortY);
  818. }
  819. }
  820. line_no++;
  821. }
  822. #endif
  823. }
  824. private void TextBoxBase_MouseDown(object sender, MouseEventArgs e) {
  825. LineTag tag;
  826. Line line;
  827. int pos;
  828. if (e.Button == MouseButtons.Left) {
  829. document.PositionCaret(e.X, e.Y);
  830. document.SetSelectionToCaret(true);
  831. this.grabbed = true;
  832. this.Capture = true;
  833. return;
  834. }
  835. #if Debug
  836. if (e.Button == MouseButtons.Right) {
  837. draw_lines = !draw_lines;
  838. this.Invalidate();
  839. Console.WriteLine("SelectedText: {0}, length {1}", this.SelectedText, this.SelectionLength);
  840. Console.WriteLine("Selection start: {0}", this.SelectionStart);
  841. this.SelectionStart = 10;
  842. this.SelectionLength = 5;
  843. return;
  844. }
  845. tag = document.FindTag(e.X, e.Y, out pos, false);
  846. Console.WriteLine("Click found tag {0}, character {1}", tag, pos);
  847. line = tag.line;
  848. switch(current) {
  849. case 4: 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;
  850. case 1: 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;
  851. case 2: 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;
  852. case 3: 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;
  853. case 0: 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;
  854. case 5: 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;
  855. }
  856. current++;
  857. if (current==6) {
  858. current=0;
  859. }
  860. // Update/Recalculate what we see
  861. document.UpdateView(line, 0);
  862. // Make sure our caret is properly positioned and sized
  863. document.AlignCaret();
  864. #endif
  865. }
  866. private void TextBoxBase_MouseUp(object sender, MouseEventArgs e) {
  867. this.Capture = false;
  868. this.grabbed = false;
  869. if (e.Button == MouseButtons.Left) {
  870. document.PositionCaret(e.X + viewport_x, e.Y + viewport_y);
  871. document.SetSelectionToCaret(false);
  872. document.DisplayCaret();
  873. return;
  874. }
  875. }
  876. #endregion // Private Methods
  877. private void TextBoxBase_SizeChanged(object sender, EventArgs e) {
  878. // First, check which scrollbars we need
  879. hscroll.Bounds = new Rectangle (ClientRectangle.Left, ClientRectangle.Bottom - hscroll.Height, Width, hscroll.Height);
  880. }
  881. private void hscroll_ValueChanged(object sender, EventArgs e) {
  882. XplatUI.ScrollWindow(this.Handle, document.ViewPortX-this.hscroll.Value, 0, true);
  883. document.ViewPortX = this.hscroll.Value;
  884. document.UpdateCaret();
  885. Console.WriteLine("Dude scrolled");
  886. }
  887. private void TextBoxBase_MouseMove(object sender, MouseEventArgs e) {
  888. // FIXME - handle auto-scrolling if mouse is to the right/left of the window
  889. if (grabbed) {
  890. document.PositionCaret(e.X + viewport_x, e.Y + viewport_y);
  891. document.SetSelectionToCaret(false);
  892. document.DisplayCaret();
  893. }
  894. }
  895. private void TextBoxBase_FontOrColorChanged(object sender, EventArgs e) {
  896. if (!richtext) {
  897. Line line;
  898. // Font changes apply to the whole document
  899. for (int i = 1; i <= document.Lines; i++) {
  900. line = document.GetLine(i);
  901. LineTag.FormatText(line, 1, line.text.Length, Font, ThemeEngine.Current.ResPool.GetSolidBrush(ForeColor));
  902. document.UpdateView(line, 0);
  903. }
  904. // Make sure the caret height is matching the new font height
  905. document.AlignCaret();
  906. }
  907. }
  908. }
  909. }