GLine.cs
上传用户:szltgg
上传日期:2019-05-16
资源大小:604k
文件大小:28k
源码类别:

Telnet服务器

开发平台:

C#

  1. /*
  2. * Copyright (c) 2005 Poderosa Project, All Rights Reserved.
  3. * $Id: GLine.cs,v 1.3 2005/04/27 08:48:50 okajima Exp $
  4. */
  5. using System;
  6. using System.Collections;
  7. using System.Drawing;
  8. using System.Diagnostics;
  9. using System.Text;
  10. using Poderosa.Forms;
  11. using Poderosa.Terminal;
  12. using Poderosa.UI;
  13. namespace Poderosa.Text
  14. {
  15. internal class RenderParameter {
  16. private int _linefrom;
  17. private int _linecount;
  18. private Rectangle _targetRect;
  19. public int LineFrom { 
  20. get {
  21. return _linefrom;
  22. }
  23. set {
  24. _linefrom=value;
  25. }
  26. }
  27. public int LineCount { 
  28. get {
  29. return _linecount;
  30. }
  31. set {
  32. _linecount=value;
  33. }
  34. }
  35. public Rectangle TargetRect { 
  36. get {
  37. return _targetRect;
  38. }
  39. set {
  40. _targetRect=value;
  41. }
  42. }
  43. }
  44. /// <summary>
  45. /// 峴枛偺庬椶
  46. /// </summary>
  47. public enum EOLType {
  48. Continue,
  49. CRLF,
  50. CR,
  51. LF
  52. }
  53. public enum CharGroup {
  54. SingleByte, //unicode偱0x100枹枮偺暥帤
  55. TwoBytes    //0x100埲忋偺暥帤
  56. }
  57. /// <summary>
  58. /// GLine偺峔惉梫慺丅GWord偼TextDecoration側偳傪嫟桳偡傞丅
  59. /// </summary>
  60. public class GWord
  61. {
  62. private TextDecoration _decoration;
  63. private int _offset;
  64. private CharGroup _charGroup;
  65. private GWord _next;
  66. //偟偽偟偽嶲徠偡傞偺偱僉儍僢僔儏偡傞抣
  67. internal int nextOffsetCache;
  68. internal int displayLengthCache;
  69. /// <summary>
  70. /// 昞帵梡偺憰忺
  71. /// </summary>
  72. internal TextDecoration Decoration {
  73. get {
  74. return _decoration;
  75. }
  76. }
  77. /// <summary>
  78. /// 強懏偡傞GLine偺拞偱壗暥帤栚偐傜巒傑偭偰偄傞偐
  79. /// </summary>
  80. public int Offset {
  81. get {
  82. return _offset;
  83. }
  84. }
  85. ///師偺Word
  86. public GWord Next {
  87. get {
  88. return _next;
  89. }
  90. set {
  91. _next = value;
  92. }
  93. }
  94. public CharGroup CharGroup {
  95. get {
  96. return _charGroup;
  97. }
  98. set {
  99. _charGroup = value;
  100. }
  101. }
  102. /// <summary>
  103. /// 暥帤楍丄僨僐儗乕僔儑儞丄僆僼僙僢僩傪巜掕偡傞僐儞僗僩儔僋僞丅Type偼Normal偵側傞丅
  104. /// </summary>
  105. internal GWord(TextDecoration d, int o, CharGroup chargroup) {
  106. Debug.Assert(d!=null);
  107. _offset = o;
  108. _decoration = d;
  109. _next = null;
  110. _charGroup = chargroup;
  111. nextOffsetCache = -1;
  112. displayLengthCache = -1;
  113. }
  114. //Next偺抣埲奜傪僐僺乕偡傞
  115. public GWord StandAloneClone() {
  116. return new GWord(_decoration, _offset, _charGroup);
  117. }
  118. public GWord DeepClone() {
  119. GWord w = new GWord(_decoration, _offset, _charGroup);
  120. if(_next!=null)
  121. w._next = _next.DeepClone();
  122. return w;
  123. }
  124. }
  125. /// <summary>
  126. /// 侾峴偺僨乕僞
  127. /// GWord傊偺暘夝偼抶墑昡壙偝傟傞丅
  128. /// </summary>
  129. public class GLine {
  130. static GLine() {
  131. InitLengthMap();
  132. }
  133. public const char WIDECHAR_PAD = 'uFFFF';
  134. private char[] _text;
  135. private EOLType _eolType;
  136. private int _id;
  137. private GWord _firstWord;
  138. private GLine _nextLine;
  139. private GLine _prevLine;
  140. public GLine(int length) {
  141. Debug.Assert(length>0);
  142. _text = new char[length];
  143. _firstWord = new GWord(TextDecoration.ClonedDefault(), 0, CharGroup.SingleByte);
  144. _id = -1;
  145. }
  146. public GLine(char[] data, GWord firstWord) {
  147. _text = (char[])data.Clone();
  148. _firstWord = firstWord;
  149. _id = -1;
  150. }
  151. public GLine Clone() {
  152. GLine nl = new GLine(_text, _firstWord.DeepClone());
  153. nl._eolType = _eolType;
  154. nl._id = _id;
  155. return nl;
  156. }
  157. public void Clear() {
  158. for(int i=0; i<_text.Length; i++)
  159. _text[i] = '';
  160. _firstWord = new GWord(TextDecoration.ClonedDefault(), 0, CharGroup.SingleByte);
  161. }
  162. internal void Clear(TextDecoration dec) {
  163. for(int i=0; i<_text.Length; i++)
  164. _text[i] = ' ';
  165. _firstWord = new GWord(dec, 0, CharGroup.SingleByte);
  166. }
  167. public int Length {
  168. get {
  169. return _text.Length;
  170. }
  171. }
  172. /// <summary>
  173. /// 僀儞僨僋僗傪巜掕偟偰GWord傪曉偡丅儗儞僟儕儞僌嵪傒偐偳偆偐偼峫椂偟偰偄側偄丅
  174. /// </summary>
  175. public GWord FirstWord { 
  176. get {
  177. return _firstWord;
  178. }
  179. }
  180. public char[] Text {
  181. get {
  182. return _text;
  183. }
  184. }
  185. public int DisplayLength {
  186. get {
  187. int i = 0;
  188. int m = _text.Length;
  189. for(i=0; i<m; i++) {
  190. if(_text[i]=='') break;
  191. }
  192. return i;
  193. }
  194. }
  195. public int CharLength {
  196. get {
  197. int n = _text.Length-1;
  198. while(n>=0 && _text[n]=='') n--;
  199. return n+1;
  200. }
  201. }
  202. //慜屻偺扨岅嬫愗傝傪尒偮偗傞丅曉偡埵抲偼丄pos偲GetWordBreakGroup偺抣偑堦抳偡傞拞偱墦偄抧揰
  203. public int FindPrevWordBreak(int pos) {
  204. int v = ToCharGroupForWordBreak(_text[pos]);
  205. while(pos>=0) {
  206. if(v!=ToCharGroupForWordBreak(_text[pos])) return pos;
  207. pos--;
  208. }
  209. return -1;
  210. }
  211. public int FindNextWordBreak(int pos) {
  212. int v = ToCharGroupForWordBreak(_text[pos]);
  213. while(pos<_text.Length) {
  214. if(v!=ToCharGroupForWordBreak(_text[pos])) return pos;
  215. pos++;
  216. }
  217. return _text.Length;
  218. }
  219. private static int ToCharGroupForWordBreak(char ch) {
  220. if(('0'<=ch && ch<='9') || ('a'<=ch && ch<='z') || ('A'<=ch && ch<='Z') || ch=='_' || GEnv.Options.AdditionalWordElement.IndexOf(ch)!=-1)
  221. return 1;
  222. else if(ch<=0x20 || ch==0x40)
  223. return 2;
  224. else if(ch<=0x100)
  225. return 3;
  226. else //偝傜偵偙偙傪UnicodeCategory摍傪傒偰揔摉偵偙偟傜偊傞偙偲傕偱偒傞偑
  227. return 4;
  228. }
  229. public int ID {
  230. get {
  231. return _id;
  232. }
  233. set {
  234. _id = value;
  235. }
  236. }
  237. //椬愙峴偺愝掕丂偙偺曄峏偼TerminalDocument偐傜偺傒峴偆偙偲両
  238. public GLine NextLine {
  239. get {
  240. return _nextLine;
  241. }
  242. set {
  243. _nextLine = value;
  244. }
  245. }
  246. public GLine PrevLine {
  247. get {
  248. return _prevLine;
  249. }
  250. set {
  251. _prevLine = value;
  252. }
  253. }
  254. public EOLType EOLType {
  255. get {
  256. return _eolType;
  257. }
  258. set {
  259. _eolType = value;
  260. }
  261. }
  262. internal void ExpandBuffer(int length) {
  263. if(length<=_text.Length) return;
  264. char[] current = _text;
  265. _text = new char[length];
  266. Array.Copy(current, 0, _text, 0, current.Length);
  267. }
  268. internal void Render(IntPtr hdc, RenderParameter param, RenderProfile prof, int y) {
  269. if(_text[0]=='') return; //壗傕昤偐側偔偰傛偄
  270. float fx = (float)param.TargetRect.Left;
  271. RectangleF rect = new RectangleF();
  272. rect.Y = param.TargetRect.Top+y;
  273. rect.Height = prof.Pitch.Height;
  274. GWord word = _firstWord;
  275. while(word != null) {
  276. rect.X = fx /*- prof.CharGap*/; //Native側昤夋偱偼晄梫丠
  277. rect.Width = param.TargetRect.Right - rect.X;
  278. int ix = (int)rect.X;
  279. int iy = (int)rect.Y;
  280. TextDecoration dec = word.Decoration;
  281. //Brush brush = prof.CalcTextBrush(dec);
  282. uint forecolorref = DrawUtil.ToCOLORREF(prof.CalcTextColor(dec));
  283. Color bkcolor = prof.CalcBackColor(dec);
  284. uint bkcolorref   = DrawUtil.ToCOLORREF(bkcolor);
  285. IntPtr hfont = prof.CalcHFONT_NoUnderline(dec, word.CharGroup);
  286. Win32.SelectObject(hdc, hfont);
  287. Win32.SetTextColor(hdc, forecolorref);
  288. Win32.SetBkColor(hdc, bkcolorref);
  289. Win32.SetBkMode(hdc, bkcolor==prof.BackColor? 1 : 2); //婎杮攚宨怓偲堦弿側傜TRANSPARENT, 堎側傟偽OPAQUE
  290. IntPtr bkbrush = bkcolor==prof.BackColor? IntPtr.Zero : Win32.CreateSolidBrush(bkcolorref);
  291. int display_length = WordDisplayLength(word);
  292. if(word.Decoration==null) { //憰忺側偟
  293. //g.DrawString(WordText(word), font, brush, rect);
  294. DrawWord(hdc, ix, iy, word);
  295. }
  296. else {
  297. //if(dec.Bold || (!prof.UsingIdenticalFont && word.CharGroup==CharGroup.TwoBytes))
  298. if(dec.Bold || word.CharGroup==CharGroup.TwoBytes) //摨偠僼僅儞僩巜掕偱傕擔杮岅偑敿妏偺俀攞偱側偄応崌偁傝丅僷僼僅乕儅儞僗栤戣偼僋儕傾偝傟偮偮偁傞偺偱妋幚偵侾暥帤偢偮昤夋
  299. DrawStringByOneChar2(hdc, word, display_length, bkbrush, rect.X, iy, prof);
  300. else
  301. DrawWord(hdc, ix, iy, word); //偄傑傗傾儂側昤夋僄儞僕儞偺栤戣偐傜偼夝曻偝傟偨両
  302. }
  303. //Debug.WriteLine("PW="+p.Pitch.Width+",TL="+(pb.Text.Length*p.Pitch.Width)+", real="+g.MeasureString(pb.Text, p.Font).Width);
  304. if(dec.Underline)
  305. DrawUnderline(hdc, forecolorref, ix, iy+(int)prof.Pitch.Height-1, (int)(prof.Pitch.Width * display_length));
  306. fx += prof.Pitch.Width * display_length;
  307. word = word.Next;
  308. if(bkbrush!=IntPtr.Zero) Win32.DeleteObject(bkbrush);
  309. }
  310. }
  311. private void DrawUnderline(IntPtr hdc, uint col, int x, int y, int length) {
  312. //Underline偑偮偔偙偲偼偁傑傝側偄偩傠偆偐傜枅夞Pen傪嶌傞丅栤戣偵側傝偦偆偩偭偨傜偦偺偲偒偵峫偊傛偆
  313. IntPtr pen = Win32.CreatePen(0, 1, col);
  314. IntPtr prev = Win32.SelectObject(hdc, pen);
  315. Win32.POINT pt = new Win32.POINT();
  316. Win32.MoveToEx(hdc, x, y, out pt);
  317. Win32.LineTo(hdc, x+length, y);
  318. Win32.SelectObject(hdc, prev);
  319. Win32.DeleteObject(pen);
  320. }
  321. private void DrawWord(IntPtr hdc, int x, int y, GWord word) {
  322. unsafe {
  323. int len;
  324. if(word.CharGroup==CharGroup.SingleByte) {
  325. fixed(char* p = &_text[0]) {
  326. len = WordNextOffset(word) - word.Offset;
  327. Win32.TextOut(hdc, x, y, p+word.Offset, len);
  328. //Win32.ExtTextOut(hdc, x, y, 4, null, p+word.Offset, len, null);
  329. }
  330. }
  331. else {
  332. string t = WordText(word);
  333. fixed(char* p = t) {
  334. len = t.Length;
  335. Win32.TextOut(hdc, x, y, p, len);
  336. //Win32.ExtTextOut(hdc, x, y, 4, null, p, len, null);
  337. }
  338. }
  339. }
  340. }
  341. private void DrawStringByOneChar2(IntPtr hdc, GWord word, int display_length, IntPtr bkbrush, float fx, int y, RenderProfile prof) {
  342. float pitch = prof.Pitch.Width;
  343. int nextoffset = WordNextOffset(word);
  344. if(bkbrush!=IntPtr.Zero) { //偙傟偑側偄偲擔杮岅暥帤僺僢僠偑彫偝偄偲偒慖戰帪偺偡偒傑偑偱偒傞応崌偑偁傞
  345. Win32.RECT rect = new Win32.RECT();
  346. rect.left = (int)fx;
  347. rect.top  = y;
  348. rect.right = (int)(fx + pitch*display_length);
  349. rect.bottom = y + (int)prof.Pitch.Height;
  350. Win32.FillRect(hdc, ref rect, bkbrush);
  351. }
  352. for(int i=word.Offset; i<nextoffset; i++) {
  353. char ch = _text[i];
  354. if(ch=='') break;
  355. if(ch==GLine.WIDECHAR_PAD) continue;
  356. unsafe {
  357. Win32.TextOut(hdc, (int)fx, y, &ch, 1);
  358. }
  359. fx += pitch * CalcDisplayLength(ch);
  360. }
  361. }
  362. /*
  363.  * //!!.NET偺昤夋僶僌
  364.  * Graphics#DrawString偵搉偡暥帤楍偼丄僗儁乕僗偺傒偱峔惉偝傟偰偄傞偲柍帇偝傟偰偟傑偆傛偆偩丅
  365.  * 偙傟偩偲傾儞僟乕儔僀儞偩偗傪堷偒偨偄偲偒側偳偵崲傞丅挷傋偨偲偙傠丄枛旜偵僞僽傪偮偗傞偲偙偺巇慻傒傪偩傑偡偙偲偑偱偒傞偙偲偑敾柧
  366.  * .NET偺師偺僶乕僕儑儞偱偼捈偭偰偄傞偙偲傪婜懸
  367.  */
  368. private string WordTextForFuckingDotNet(GWord word) {
  369. int nextoffset = WordNextOffset(word);
  370. if(nextoffset==0)
  371. return "";
  372. else {
  373. bool last_is_space = false;
  374. Debug.Assert(nextoffset-word.Offset >= 0);
  375. if(word.CharGroup==CharGroup.SingleByte) {
  376. last_is_space = _text[nextoffset-1]==' ';
  377. if(last_is_space)
  378. return new string(_text, word.Offset, nextoffset-word.Offset)+'t';
  379. else
  380. return new string(_text, word.Offset, nextoffset-word.Offset);
  381. }
  382. else {
  383. char[] buf = new char[256];
  384. int o = word.Offset, i=0;
  385. while(o < nextoffset) {
  386. char ch = _text[o];
  387. if(ch!=GLine.WIDECHAR_PAD) {
  388. last_is_space = ch==' ';
  389. buf[i++] = ch;
  390. }
  391. o++;
  392. }
  393. if(last_is_space)
  394. buf[i++] = (char)'t';
  395. return new string(buf, 0, i);
  396. }
  397. }
  398. }
  399. private string WordText(GWord word) {
  400. int nextoffset = WordNextOffset(word);
  401. if(nextoffset==0)
  402. return "";
  403. else {
  404. Debug.Assert(nextoffset-word.Offset >= 0);
  405. if(word.CharGroup==CharGroup.SingleByte)
  406. return new string(_text, word.Offset, nextoffset-word.Offset);
  407. else {
  408. char[] buf = new char[256];
  409. int o = word.Offset, i=0;
  410. while(o < nextoffset) {
  411. char ch = _text[o];
  412. if(ch!=GLine.WIDECHAR_PAD)
  413. buf[i++] = ch;
  414. o++;
  415. }
  416. return new string(buf, 0, i);
  417. }
  418. }
  419. }
  420. private int WordDisplayLength(GWord word) {
  421. //偙偙偼屇偽傟傞偙偲偑偲偰傕懡偄偺偱僉儍僢僔儏傪愝偗傞
  422. int cache = word.displayLengthCache;
  423. if(cache < 0) {
  424. int nextoffset = WordNextOffset(word);
  425. int l = nextoffset - word.Offset;
  426. word.displayLengthCache = l;
  427. return l;
  428. }
  429. else
  430. return cache;
  431. }
  432. internal int WordNextOffset(GWord word) {
  433. //偙偙偼屇偽傟傞偙偲偑偲偰傕懡偄偺偱僉儍僢僔儏傪愝偗傞
  434. int cache = word.nextOffsetCache;
  435. if(cache < 0) {
  436. if(word.Next==null) {
  437. int i = _text.Length-1;
  438. while(i>=0 && _text[i]=='')
  439. i--;
  440. word.nextOffsetCache = i+1;
  441. return i+1;
  442. }
  443. else {
  444. word.nextOffsetCache = word.Next.Offset;
  445. return word.Next.Offset;
  446. }
  447. }
  448. else
  449. return cache;
  450. }
  451. internal void Append(GWord w) {
  452. if(_firstWord==null)
  453. _firstWord = w;
  454. else
  455. this.LastWord.Next = w;
  456. }
  457. public GWord LastWord {
  458. get {
  459. GWord w = _firstWord;
  460. while(w.Next!=null)
  461. w = w.Next;
  462. return w;
  463. }
  464. }
  465. //index偺埵抲偺昞帵傪斀揮偟偨怴偟偄GLine傪曉偡
  466. //inverse偑false偩偲丄GWord偺暘妱偼偡傞偑Decoration偺斀揮偼偟側偄丅僸僋僸僋栤戣偺懳張偲偟偰幚憰丅
  467. internal GLine InverseCaret(int index, bool inverse, bool underline) {
  468. ExpandBuffer(index+1);
  469. if(_text[index]==WIDECHAR_PAD) index--;
  470. GLine ret = new GLine(_text, null);
  471. ret.ID = _id;
  472. ret.EOLType = _eolType;
  473. GWord w = _firstWord;
  474. int nextoffset = 0;
  475. while(w!=null) {
  476. nextoffset = WordNextOffset(w);
  477. if(w.Offset<=index && index<nextoffset) {
  478. //!!tail偐傜弴偵楢寢偟偨曽偑岠棪偼傛偄
  479. if(w.Offset<index) {
  480. GWord head = new GWord(w.Decoration, w.Offset, w.CharGroup);
  481. ret.Append(head);
  482. }
  483. TextDecoration dec = (TextDecoration)w.Decoration.Clone();
  484. if(inverse) {
  485. //怓偮偒僉儍儗僢僩偺僒億乕僩
  486. dec.ToCaretStyle();
  487. }
  488. if(underline) dec.Underline = true;
  489. GWord mid = new GWord(dec, index, w.CharGroup);
  490. ret.Append(mid);
  491. if(index+CalcDisplayLength(_text[index]) < nextoffset) {
  492. GWord tail = new GWord(w.Decoration, index+CalcDisplayLength(_text[index]), w.CharGroup);
  493. ret.Append(tail);
  494. }
  495. }
  496. else
  497. ret.Append(w.StandAloneClone());
  498. w = w.Next;
  499. }
  500. //!!偙偺丄僉儍儗僢僩埵抲偵僗儁乕僗傪擖傟傞偺偼Inverse偲偼堘偆張棟偱偁傞偐傜暘棧偡傞偙偲
  501. if(nextoffset<=index) {
  502. while(nextoffset<=index) {
  503. Debug.Assert(nextoffset < ret.Text.Length);
  504. ret.Text[nextoffset++] = ' ';
  505. }
  506. TextDecoration dec = TextDecoration.ClonedDefault();
  507. if(inverse) {
  508. dec.ToCaretStyle();
  509. }
  510. if(underline) dec.Underline = true;
  511. ret.Append(new GWord(dec, index, CharGroup.SingleByte));
  512. }
  513. return ret;
  514. }
  515. internal GLine InverseRange(int from, int to) {
  516. ExpandBuffer(Math.Max(from+1,to)); //寖偟偔儕僒僀僘偟偨偲偒側偳偵偙偺忦審偑枮偨偣側偄偙偲偑偁傞
  517. Debug.Assert(from>=0 && from<_text.Length);
  518. if(from<_text.Length && _text[from]==WIDECHAR_PAD) from--;
  519. if(to>0 && to-1<_text.Length && _text[to-1]==WIDECHAR_PAD) to--;
  520. GLine ret = new GLine(_text, null);
  521. ret.ID = _id;
  522. ret.EOLType = _eolType;
  523. //憰忺偺攝楍傪僙僢僩
  524. TextDecoration[] dec = new TextDecoration[_text.Length];
  525. GWord w = _firstWord;
  526. while(w!=null) {
  527. Debug.Assert(w.Decoration!=null);
  528. dec[w.Offset] = w.Decoration;
  529. w = w.Next;
  530. }
  531. //斀揮奐巒揰
  532. TextDecoration original = null;
  533. TextDecoration inverse = null;
  534. for(int i=from; i>=0; i--) {
  535. if(dec[i]!=null) {
  536. original = dec[i];
  537. break;
  538. }
  539. }
  540. Debug.Assert(original!=null);
  541. inverse = (TextDecoration)original.Clone();
  542. inverse.Inverse();
  543. dec[from] = inverse;
  544. //斖埻偵搉偭偰斀揮嶌嬈
  545. for(int i=from+1; i<to; i++) {
  546. if(i<dec.Length && dec[i]!=null) {
  547. original = dec[i];
  548. inverse = (TextDecoration)original.Clone();
  549. inverse.Inverse();
  550. dec[i] = inverse;
  551. }
  552. }
  553. if(to<dec.Length && dec[to]==null) dec[to] = original;
  554. //偙傟偵廬偭偰GWord傪嶌傞
  555. w = null;
  556. for(int i=dec.Length-1; i>=0; i--) {
  557. char ch = _text[i];
  558. if(dec[i]!=null && ch!='') {
  559. int j = i;
  560. if(ch==WIDECHAR_PAD) j++;
  561. GWord ww = new GWord(dec[i], j, CalcCharGroup(ch));
  562. ww.Next = w;
  563. w = ww;
  564. }
  565. }
  566. ret.Append(w);
  567. return ret;
  568. }
  569. //偙偺椞堟偺暥帤偺暆偼杮摉偼僼僅儞僩埶懚偩偑丄懡偔偺擔杮岅娐嫬偱偼慡妏偲偟偰埖傢傟傞柾條丅BS偱徚偡偲俀屄棃偨傝偡傞
  570. private static byte[] _length_map_0x80_0xFF;
  571. private static byte[] _length_map_0x2500_0x25FF;
  572. private static void InitLengthMap() {
  573. _length_map_0x80_0xFF = new byte[0x80];
  574. for(int i=0; i<_length_map_0x80_0xFF.Length; i++) {
  575. int t = i+0x80;
  576. //    仒         丯         亱         亇         丩         侘          亊         亐
  577. if(t==0xA7 || t==0xA8 || t==0xB0 || t==0xB1 || t==0xB4 || t==0xB6 || t==0xD7 || t==0xF7)
  578. _length_map_0x80_0xFF[i] = 2;
  579. else
  580. _length_map_0x80_0xFF[i] = 1;
  581. }
  582.             //慡妏敿妏崿嵼僝乕儞
  583. _length_map_0x2500_0x25FF = new byte[] {
  584.               //劅 劒 劆 劔                        劇       劕
  585.                 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, //2500-0F
  586.               //劉       劖 劋       劘 劊       劗 劌 労
  587.                 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 2, 1, 1, //2510-1F
  588.               //劦       劙 劎 劶       劮       劜 劍       劧
  589.                 2, 1, 1, 2, 2, 2, 1, 1, 2, 1, 1, 2, 2, 1, 1, 2, //2520-2F
  590.               //劵       劚 劏       劯 劷       劤 劑       劰
  591.                 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, //2530-3F
  592.               //      劸                         劥
  593.                 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, //2540-4F
  594.               //
  595.                 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //2550-5F
  596.               //
  597.                 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //2560-6F
  598.               //
  599.                 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //2570-7F
  600.               //
  601.                 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //2580-8F
  602.               //
  603.                 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //2590-9F
  604.               //仭 仩
  605.                 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //25A0-AF
  606.               //      仯 仮                         仴 仱
  607.                 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, //25B0-BF
  608.               //                  仧 仦          仜       仢 仠
  609.                 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 2, 1, 1, 2, 2, //25C0-CF
  610.               //
  611.                 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //25D0-DF
  612.               //                                             侟
  613.                 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, //25E0-EF
  614.               //
  615.                 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1  //25F0-FF
  616. };
  617. Debug.Assert(_length_map_0x2500_0x25FF.Length==256);
  618. }
  619. //暥帤偵傛偭偰昤夋暆傪寛傔傞
  620. internal static int CalcDisplayLength(char ch) {
  621. if(ch >= 0x100) {
  622. if(0xFF61<=ch && ch<=0xFF9F) //敿妏僇僫
  623. return 1;
  624. else if(0x2500<=ch && ch<=0x25FF) //宺慄摍摿庩婰崋
  625. return _length_map_0x2500_0x25FF[ch-0x2500];
  626. else
  627. return 2;
  628. }
  629. else if(ch >= 0x80) {
  630. return _length_map_0x80_0xFF[ch-0x80];
  631. }
  632. else
  633. return 1; //杮摉偼tab側偳偁傞偐傕偟傟側偄偺偱傕偆彮偟恀柺栚偵寁嶼偡傋偒
  634. }
  635. //ASCII偐擔杮岅暥帤偐 僼僅儞僩偺慖戰偵巊偆
  636. internal static CharGroup CalcCharGroup(char ch) {
  637. if(ch < 0x80)
  638. return CharGroup.SingleByte; 
  639. else if(ch < 0x100)
  640. return _length_map_0x80_0xFF[ch-0x80]==1? CharGroup.SingleByte : CharGroup.TwoBytes;
  641. else {
  642. if(0x2500 <= ch && ch <= 0x25FF) //宺慄偼擔杮岅僼僅儞僩偼巊傢側偄
  643. return _length_map_0x2500_0x25FF[ch-0x2500]==1? CharGroup.SingleByte : CharGroup.TwoBytes; 
  644. else
  645. return CharGroup.TwoBytes;
  646. }
  647. }
  648. }
  649. /// <summary>
  650. /// 暥帤偺捛壛嶍彍側偳傪偟偰GLine傪憖嶌偡傞丅椺偊偽僞乕儈僫儖偑偙偺僋儔僗傪宱桼偟偰僪僉儏儊儞僩偺摿掕偺GLine傪彂偒姺偊傞偺偵巊偆丅
  651. /// </summary>
  652. internal class GLineManipulator {
  653. private char[] _text;
  654. private TextDecoration[] _decorations;
  655. private int _caretColumn;
  656. private TextDecoration _defaultDecoration;
  657. private EOLType _eolType;
  658. /// <summary>
  659. /// 嬻偱峔抸
  660. /// </summary>
  661. public GLineManipulator(int length) {
  662. _decorations = new TextDecoration[length];
  663. _text = new char[length];
  664. Clear(length);
  665. }
  666. /// <summary>
  667. /// 慡撪梕傪攋婞偡傞
  668. /// </summary>
  669. public void Clear(int length) {
  670. if(length!=_text.Length) {
  671. _decorations = new TextDecoration[length];
  672. _text = new char[length];
  673. }
  674. else {
  675. for(int i=0; i<_decorations.Length; i++) _decorations[i] = null;
  676. for(int i=0; i<_text.Length;        i++) _text[i] = '';
  677. }
  678. _caretColumn = 0;
  679. _eolType = EOLType.Continue;
  680. }
  681. public int CaretColumn {
  682. get {
  683. return _caretColumn;
  684. }
  685. set {
  686. Debug.Assert(value>=0 && value<=_text.Length);
  687. _caretColumn = value;
  688. value--;
  689. while(value>=0 && _text[value]=='')
  690. _text[value--] = ' ';
  691. }
  692. }
  693. public void CarriageReturn() {
  694. _caretColumn = 0;
  695. _eolType = EOLType.CR;
  696. }
  697. public bool IsEmpty {
  698. get {
  699. //_text傪慡晹尒傞昁梫偼側偄偩傠偆
  700. return _caretColumn==0 && _text[0]=='';
  701. }
  702. }
  703. public TextDecoration DefaultDecoration {
  704. get {
  705. return _defaultDecoration;
  706. }
  707. set {
  708. _defaultDecoration = value;
  709. }
  710. }
  711. /// <summary>
  712. /// 堷悢偲摨偠撪梕偱弶婜壔偡傞丅line偺撪梕偼攋夡偝傟側偄丅
  713. /// 堷悢偑null偺偲偒偼堷悢側偟偺僐儞僗僩儔僋僞偲摨偠寢壥偵側傞丅
  714. /// </summary>
  715. public void Load(GLine line, int cc) {
  716. if(line==null) { //偙傟偑null偵側偭偰偄傞偲偟偐巚偊側偄僋儔僢僔儏儗億乕僩偑偁偭偨丅杮棃偼側偄偼偢側傫偩偑...
  717. Clear(80);
  718. return;
  719. }
  720. Clear(line.Length);
  721. GWord w = line.FirstWord;
  722. Debug.Assert(line.Text.Length==_text.Length);
  723. Array.Copy(line.Text, 0, _text, 0, _text.Length);
  724. int n = 0;
  725. while(w != null) {
  726. int nextoffset = line.WordNextOffset(w);
  727. while(n < nextoffset)
  728. _decorations[n++] = w.Decoration;
  729. w = w.Next;
  730. }
  731. _eolType = line.EOLType;
  732. ExpandBuffer(cc+1);
  733. this.CaretColumn = cc; //' '偱杽傔傞偙偲傕偁傞偺偱僾儘僷僥傿僙僢僩傪巊偆
  734. }
  735. public int BufferSize {
  736. get {
  737. return _text.Length;
  738. }
  739. }
  740. public void ExpandBuffer(int length) {
  741. if(length<=_text.Length) return;
  742. char[] current = _text;
  743. _text = new char[length];
  744. Array.Copy(current, 0, _text, 0, current.Length);
  745. TextDecoration[] current2 = _decorations;
  746. _decorations = new TextDecoration[length];
  747. Array.Copy(current2, 0, _decorations, 0, current2.Length);
  748. }
  749. public void PutChar(char ch, TextDecoration dec) {
  750. Debug.Assert(dec!=null);
  751. Debug.Assert(_caretColumn>=0);
  752. Debug.Assert(_caretColumn<_text.Length);
  753. //埲壓傢偐傝偵偔偄偑丄梫偼応崌暘偗丅偙傟偺巇條傪彂偄偨帒椏偁傝
  754. bool onZenkakuRight = (_text[_caretColumn] == GLine.WIDECHAR_PAD);
  755. bool onZenkaku = onZenkakuRight || (_text.Length>_caretColumn+1 && _text[_caretColumn+1] == GLine.WIDECHAR_PAD);
  756. if(onZenkaku) {
  757. //慡妏偺忋偵彂偔
  758. if(!onZenkakuRight) {
  759. _text[_caretColumn] = ch;
  760. _decorations[_caretColumn] = dec;
  761. if(GLine.CalcDisplayLength(ch)==1) {
  762. //慡妏偺忋偵敿妏傪彂偄偨応崌丄椬偵僗儁乕僗傪擖傟側偄偲昞帵偑棎傟傞
  763. if(_caretColumn+1<_text.Length) _text[_caretColumn+1] = ' ';
  764. _caretColumn++;
  765. }
  766. else {
  767. _decorations[_caretColumn+1] = dec;
  768. _caretColumn+=2;
  769. }
  770. }
  771. else {
  772. _text[_caretColumn-1] = ' ';
  773. _text[_caretColumn]   = ch;
  774. _decorations[_caretColumn] = dec;
  775. if(GLine.CalcDisplayLength(ch)==2) {
  776. if(GLine.CalcDisplayLength(_text[_caretColumn+1])==2)
  777. if(_caretColumn+2<_text.Length) _text[_caretColumn+2] = ' ';
  778. _text[_caretColumn+1] = GLine.WIDECHAR_PAD;
  779. _decorations[_caretColumn+1] = _decorations[_caretColumn];
  780. _caretColumn += 2;
  781. }
  782. else
  783. _caretColumn++;
  784. }
  785. }
  786. else { //敿妏偺忋偵彂偔
  787. _text[_caretColumn] = ch;
  788. _decorations[_caretColumn] = dec;
  789. if(GLine.CalcDisplayLength(ch)==2) {
  790. if(GLine.CalcDisplayLength(_text[_caretColumn+1])==2) //敿妏丄慡妏偲側偭偰偄傞偲偙傠偵慡妏傪彂偄偨傜
  791. if(_caretColumn+2<_text.Length) _text[_caretColumn+2] = ' ';
  792. _text[_caretColumn+1] = GLine.WIDECHAR_PAD;
  793. _decorations[_caretColumn+1] = _decorations[_caretColumn];
  794. _caretColumn += 2;
  795. }
  796. else
  797. _caretColumn++; //偙傟偑嵟傕common側働乕僗偩偑
  798. }
  799. }
  800. public void SetDecoration(TextDecoration dec) {
  801. if(_caretColumn<_decorations.Length)
  802. _decorations[_caretColumn] = dec;
  803. }
  804. public char CharAt(int index) {
  805. return _text[index];
  806. }
  807. public void BackCaret() {
  808. if(_caretColumn>0) { //嵟嵍抂偵偁傞偲偒偼壗傕偟側偄
  809. _caretColumn--;
  810. }
  811. }
  812. public void RemoveAfterCaret() {
  813. for(int i=_caretColumn; i<_text.Length; i++) {
  814. _text[i] = '';
  815. _decorations[i] = null;
  816. }
  817. }
  818. public void FillSpace(int from, int to) {
  819. if(to>_text.Length) to = _text.Length;
  820. for(int i=from; i<to; i++) {
  821. _text[i] = ' ';
  822. _decorations[i] = null;
  823. }
  824. }
  825. public void FillSpace(int from, int to, TextDecoration dec) {
  826. if(to>_text.Length) to = _text.Length;
  827. for(int i=from; i<to; i++) {
  828. _text[i] = ' ';
  829. _decorations[i] = dec;
  830. }
  831. }
  832. //start偐傜count暥帤傪徚嫀偟偰媗傔傞丅塃抂偵偼null傪擖傟傞
  833. public void DeleteChars(int start, int count) {
  834. for(int i = start; i<_text.Length; i++) {
  835. int j = i + count;
  836. if(j < _text.Length) {
  837. _text[i] = _text[j];
  838. _decorations[i] = _decorations[j];
  839. }
  840. else {
  841. _text[i] = '';
  842. _decorations[i] = null;
  843. }
  844. }
  845. }
  846. public void InsertBlanks(int start, int count) {
  847. for(int i=_text.Length-1; i>=_caretColumn; i--) {
  848. int j = i - count;
  849. if(j >= _caretColumn) {
  850. _text[i] = _text[j];
  851. _decorations[i] = _decorations[j];
  852. }
  853. else {
  854. _text[i] = ' ';
  855. _decorations[i] = null;
  856. }
  857. }
  858. }
  859. public GLine Export() {
  860. GWord w = new GWord(_decorations[0]==null? TextDecoration.ClonedDefault() : _decorations[0], 0, GLine.CalcCharGroup(_text[0]));
  861. GLine line = new GLine(_text, w);
  862. line.EOLType = _eolType;
  863. int m = _text.Length;
  864. for(int offset=1; offset<m; offset++) {
  865. char ch = _text[offset];
  866. if(ch=='') break;
  867. else if(ch==GLine.WIDECHAR_PAD) continue;
  868. TextDecoration dec = _decorations[offset];
  869. if(_decorations[offset-1]!=dec || w.CharGroup!=GLine.CalcCharGroup(ch)) {
  870. if(dec==null) dec = TextDecoration.ClonedDefault(); //!!杮摉偼偙偙偑null偵側偭偰偄傞偺偼偁傝偊側偄偼偢丅屻偱挷嵏偡傞偙偲
  871. GWord ww = new GWord(dec, offset, GLine.CalcCharGroup(ch));
  872. w.Next = ww;
  873. w = ww;
  874. }
  875. }
  876. return line;
  877. }
  878. public override string ToString() {
  879. StringBuilder b = new StringBuilder();
  880. b.Append(_text);
  881. //傾僩儕價儏乕僩傑傢傝偺昞帵偼傑偩偟偰偄側偄
  882. return b.ToString();
  883. }
  884.         /*
  885. public static void TestPutChar() {
  886. TestPutChar(1, "aaaaz ", 0, '偄');
  887. TestPutChar(2, "a偁uFFFFaz ", 0, '偄');
  888. TestPutChar(3, "偁uFFFF偁uFFFFz ", 0, 'b');
  889. TestPutChar(4, "偁uFFFF偁uFFFFz ", 0, '偄');
  890. TestPutChar(5, "偁uFFFF偁uFFFFz ", 1, 'b');
  891. TestPutChar(6, "偁uFFFFaaz ", 1, '偄');
  892. TestPutChar(7, "偁uFFFF偁uFFFFz ", 1, '偄');
  893. }*/
  894. private static void TestPutChar(int num, string initial, int col, char ch) {
  895. GLineManipulator m = new GLineManipulator(10);
  896. m._text = initial.ToCharArray();
  897. m.CaretColumn = col;
  898. Debug.WriteLine(String.Format("Test{0}  [{1}] col={2} char={3}", num, SafeString(m._text), m.CaretColumn, ch));
  899. m.PutChar(ch, TextDecoration.Default);
  900. Debug.WriteLine(String.Format("Result [{0}] col={1}", SafeString(m._text), m.CaretColumn));
  901. }
  902. public static string SafeString(char[] d) {
  903. StringBuilder bld = new StringBuilder();
  904. for(int i=0; i<d.Length; i++) {
  905. char ch = d[i];
  906. if(ch=='') break;
  907. if(ch!=GLine.WIDECHAR_PAD) bld.Append(ch);
  908. }
  909. return bld.ToString();
  910. }
  911. }
  912. }