RichTextLayer.cs 49 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using CommonLang;
  5. using CommonUI.Gemo;
  6. using CommonUI.Cell.Game;
  7. namespace CommonUI.Display.Text
  8. {
  9. public abstract class BaseRichTextLayer : IDisposable
  10. {
  11. private List<Region> mBlocks = new List<Region>();
  12. private List<Region> mOldBlocks = new List<Region>();
  13. private List<Line> mLines = new List<Line>();
  14. private AttributedString mText = new AttributedString();
  15. private float mWidth;
  16. private int mBorderCount;
  17. private uint mBorderColor;
  18. private RichTextAlignment mAlignment = RichTextAlignment.taLEFT;
  19. private float mLineSpace;
  20. private float mFixedLineSpace;
  21. private bool mEnableLineBreak;
  22. private float mContentWidth;
  23. private float mContentHeigh;
  24. private bool mIsEnable = true;
  25. private bool mIsColorDirty = true;
  26. private HashMap<string, TImageRegion> mImageCache = new HashMap<string, TImageRegion>();
  27. private HashMap<string, TSpriteMetaAnimateFrame> mSpriteCache = new HashMap<string, TSpriteMetaAnimateFrame>();
  28. public RichTextAlignment Alignment { get { return mAlignment; } }
  29. public bool IsMultiline { get { return mEnableLineBreak; } }
  30. public int LineCount { get { return mLines.Count; } }
  31. public float LineSpace { get { return mLineSpace; } }
  32. public float FixedLineSpace { get { return mFixedLineSpace; } }
  33. public int TextLength { get { return mText.Length; } }
  34. public float Width { get { return mWidth; } }
  35. /// <summary>
  36. /// 获取全部宽
  37. /// </summary>
  38. public float ContentWidth { get { return mContentWidth; } }
  39. /// <summary>
  40. /// 获取全部高
  41. /// </summary>
  42. public float ContentHeight { get { return mContentHeigh; } }
  43. public int BorderCount { get { return mBorderCount; } }
  44. public uint BorderColor { get { return mBorderColor; } }
  45. public bool IsEnable
  46. {
  47. get { return mIsEnable; }
  48. set
  49. {
  50. if (mIsEnable != value)
  51. {
  52. mIsEnable = value;
  53. mIsColorDirty = true;
  54. }
  55. }
  56. }
  57. protected List<Region> AllRegions
  58. {
  59. get { return mBlocks; }
  60. }
  61. protected List<Line> AllLines
  62. {
  63. get { return mLines; }
  64. }
  65. protected BaseRichTextLayer(float width = 100, RichTextAlignment anchor = RichTextAlignment.taLEFT)
  66. {
  67. mWidth = width;
  68. mAlignment = anchor;
  69. mEnableLineBreak = true;
  70. mLineSpace = 0;
  71. mFixedLineSpace = 0;
  72. mContentHeigh = 0;
  73. mContentWidth = 0;
  74. mBorderCount = 0;
  75. }
  76. /// <summary>
  77. /// 设置锚点
  78. /// </summary>
  79. /// <param name="anchor"></param>
  80. /// <returns></returns>
  81. public BaseRichTextLayer SetAnchor(RichTextAlignment anchor)
  82. {
  83. if (mAlignment != anchor)
  84. {
  85. mAlignment = anchor;
  86. ResetLines();
  87. }
  88. return this;
  89. }
  90. /// <summary>
  91. /// 设置行距
  92. /// </summary>
  93. /// <param name="space"></param>
  94. /// <returns></returns>
  95. public BaseRichTextLayer SetLineSpace(float space)
  96. {
  97. if (mLineSpace != space)
  98. {
  99. mLineSpace = space;
  100. ResetLines();
  101. }
  102. return this;
  103. }
  104. /// <summary>
  105. /// 设置固定行间距,忽略文字大小
  106. /// </summary>
  107. /// <param name="space"></param>
  108. /// <returns></returns>
  109. public BaseRichTextLayer SetFixedLineSpace(float space)
  110. {
  111. if (mFixedLineSpace != space)
  112. {
  113. mFixedLineSpace = space;
  114. ResetLines();
  115. }
  116. return this;
  117. }
  118. public BaseRichTextLayer SetEnableMultiline(bool multiline)
  119. {
  120. if (mEnableLineBreak != multiline)
  121. {
  122. mEnableLineBreak = multiline;
  123. ResetChars();
  124. }
  125. return this;
  126. }
  127. public BaseRichTextLayer SetWidth(float width)
  128. {
  129. if (mWidth != width)
  130. {
  131. mWidth = width;
  132. ResetChars();
  133. }
  134. return this;
  135. }
  136. public BaseRichTextLayer SetBorder(int count, uint color)
  137. {
  138. if (mBorderCount != count || mBorderColor != color)
  139. {
  140. mBorderCount = count;
  141. mBorderColor = color;
  142. ResetChars();
  143. }
  144. return this;
  145. }
  146. public BaseRichTextLayer SetString(AttributedString text)
  147. {
  148. if (!mText.Equals(text))
  149. {
  150. this.mText = text;
  151. ResetChars();
  152. }
  153. return this;
  154. }
  155. public BaseRichTextLayer.Line GetLine(int index)
  156. {
  157. if (index < mLines.Count)
  158. {
  159. return mLines[index];
  160. }
  161. return null;
  162. }
  163. public AttributedString GetText()
  164. {
  165. return mText;
  166. }
  167. /// <summary>
  168. /// 获取文本在文本区域的位置
  169. /// </summary>
  170. /// <param name="charIndex">文本位置</param>
  171. /// <returns></returns>
  172. public BaseRichTextLayer.Region GetRegion(int charIndex)
  173. {
  174. if (mLines.Count == 0)
  175. {
  176. return null;
  177. }
  178. for (int i = 0; i < mBlocks.Count; i++)
  179. {
  180. BaseRichTextLayer.Region rg = mBlocks[i];
  181. if (charIndex <= rg.mStartIndex)
  182. {
  183. return rg;
  184. }
  185. }
  186. return null;
  187. }
  188. protected void BeginRender(Graphics g)
  189. {
  190. if (mOldBlocks.Count > 0)
  191. {
  192. foreach (BaseRichTextLayer.Region it in mOldBlocks)
  193. {
  194. it.Dispose();
  195. }
  196. mOldBlocks.Clear();
  197. }
  198. if (mIsColorDirty)
  199. {
  200. mIsColorDirty = false;
  201. this.CreateRegionBuffs();
  202. }
  203. }
  204. protected void InternalRender(Graphics g, float px, float py, float pw, float ph, float cx, float cy)
  205. {
  206. Line tempL = null;
  207. for (int i = 0; i < mLines.Count; i++)
  208. {
  209. tempL = mLines[i];
  210. if (tempL.mBlocks.Count > 0)
  211. {
  212. if (Rectangle2D.IntersectRectWH(cx, cy, pw, ph,
  213. tempL.mBounds.x,
  214. tempL.mBounds.y,
  215. tempL.mBounds.width,
  216. tempL.mBounds.height))
  217. {
  218. tempL.RenderLine(g, px, py);
  219. }
  220. else
  221. {
  222. tempL.HideLine(px, py);
  223. }
  224. }
  225. }
  226. }
  227. protected void AfterRender(Graphics g) { }
  228. protected virtual void OnDrawRegion(Graphics g, Region rg, float px, float py) { }
  229. protected virtual void OnDrawLine(Graphics g, Line rg, float px, float py) { }
  230. /// <summary>
  231. /// 渲染文本
  232. /// </summary>
  233. /// <param name="g">绘图指针</param>
  234. /// <param name="dx">绘制到目标x</param>
  235. /// <param name="dy">绘制到目标y</param>
  236. /// <param name="dw">绘制范围宽</param>
  237. /// <param name="dh">绘制范围高</param>
  238. /// <param name="sx">自身坐标X</param>
  239. /// <param name="sy">自身坐标Y</param>
  240. public virtual void Render(Graphics g, float dx, float dy, float dw, float dh, float sx, float sy)
  241. {
  242. this.BeginRender(g);
  243. this.InternalRender(g, dx, dy, dw, dh, sx, sy);
  244. this.AfterRender(g);
  245. }
  246. /// <summary>
  247. /// 绘制全部富文本
  248. /// </summary>
  249. /// <param name="g"></param>
  250. /// <param name="dx"></param>
  251. /// <param name="dy"></param>
  252. public virtual void Render(Graphics g, float dx, float dy)
  253. {
  254. Render(g, dx, dy, Width, mContentHeigh, 0, 0);
  255. }
  256. /// <summary>
  257. /// 点选文本
  258. /// </summary>
  259. /// <param name="cx">自身坐标X</param>
  260. /// <param name="cy">自身坐标Y</param>
  261. /// <param name="info">输出点选信息</param>
  262. /// <returns></returns>
  263. public virtual bool Click(float cx, float cy, out RichTextClickInfo info)
  264. {
  265. info = new RichTextClickInfo();
  266. for (int i = 0; i < mLines.Count; i++)
  267. {
  268. Line line = mLines[i];
  269. for (int c = 0; c < line.mBlocks.Count; c++)
  270. {
  271. Region rg = line.mBlocks[c];
  272. if (rg.mBounds.contains(cx, cy))
  273. {
  274. info.mRegion = rg;
  275. return true;
  276. }
  277. }
  278. }
  279. return false;
  280. }
  281. public virtual RichTextClickInfo Click(float cx, float cy)
  282. {
  283. RichTextClickInfo info = new RichTextClickInfo();
  284. for (int i = 0; i < mLines.Count; i++)
  285. {
  286. Line line = mLines[i];
  287. for (int c = 0; c < line.mBlocks.Count; c++)
  288. {
  289. Region rg = line.mBlocks[c];
  290. if (rg.mBounds.contains(cx, cy))
  291. {
  292. info.mRegion = rg;
  293. return info;
  294. }
  295. }
  296. }
  297. return info;
  298. }
  299. public virtual void Dispose()
  300. {
  301. foreach (BaseRichTextLayer.Region it in mBlocks)
  302. {
  303. it.Dispose();
  304. }
  305. foreach (BaseRichTextLayer.Region it in mOldBlocks)
  306. {
  307. it.Dispose();
  308. }
  309. mBlocks.Clear();
  310. mOldBlocks.Clear();
  311. mLines.Clear();
  312. }
  313. //----------------------------------------------------------------------------------------
  314. protected virtual void OnBeginResetChars() { }
  315. protected virtual void OnEndResetLines() { }
  316. private Action<BaseRichTextLayer> event_EndResetLines;
  317. public event Action<BaseRichTextLayer> EndResetLines
  318. {
  319. add { event_EndResetLines += value; }
  320. remove { event_EndResetLines -= value; }
  321. }
  322. private void ResetChars()
  323. {
  324. OnBeginResetChars();
  325. if (mOldBlocks.Count > 0)
  326. {
  327. // 不要删除已经在显示的内容,防止显示空白,BeginRender时会更新到最新
  328. foreach (BaseRichTextLayer.Region it in mBlocks)
  329. {
  330. it.Dispose();
  331. }
  332. mBlocks.Clear();
  333. }
  334. else
  335. {
  336. // 临时缓存正在显示的内容,防止显示空白, BeginRender时删除
  337. var tmp = mOldBlocks;
  338. mOldBlocks = mBlocks;
  339. mBlocks = tmp;
  340. }
  341. this.mBlocks.Capacity = (mText.Length);
  342. // 按照属性划分区段
  343. if (mText.Length > 0)
  344. {
  345. Region buildRG = null;
  346. for (int i = 0; i < mText.Length; i++)
  347. {
  348. TextAttribute curTA = mText.GetAttribute(i);
  349. if (!string.IsNullOrEmpty(curTA.resImage))
  350. {
  351. AddImage(curTA);
  352. }
  353. else if (!string.IsNullOrEmpty(curTA.resSprite))
  354. {
  355. AddSprite(curTA);
  356. }
  357. char mCH = mText.GetChar(i);
  358. //出现换行,立即分段,保持每个换行符占一个Region//
  359. if (mEnableLineBreak && (mCH == '\n'))
  360. {
  361. if (buildRG != null)
  362. {
  363. buildRG.mEndIndex = i;
  364. buildRG.mText = mText.ToString().Substring(buildRG.mStartIndex, buildRG.CharCount);
  365. mBlocks.Add(buildRG);
  366. }
  367. Region br = new Region(this, curTA);
  368. br.mText = "\n";
  369. br.mStartIndex = i;
  370. br.mEndIndex = i + 1;
  371. mBlocks.Add(br);
  372. buildRG = null;
  373. }
  374. else
  375. {
  376. if (buildRG != null)
  377. {
  378. //属性不同,则截断//
  379. if (!TestSplitByAttribute(buildRG.mAttribute, curTA))
  380. {
  381. buildRG.mEndIndex = i;
  382. buildRG.mText = mText.ToString().Substring(buildRG.mStartIndex, buildRG.CharCount);
  383. mBlocks.Add(buildRG);
  384. buildRG = new Region(this, curTA);
  385. buildRG.mStartIndex = i;
  386. }
  387. }
  388. else
  389. {
  390. //首次解析//
  391. buildRG = new Region(this, curTA);
  392. buildRG.mStartIndex = i;
  393. }
  394. }
  395. }
  396. //防止最后一段漏掉//
  397. if (buildRG != null)
  398. {
  399. buildRG.mEndIndex = mText.Length;
  400. buildRG.mText = mText.ToString().Substring(buildRG.mStartIndex, buildRG.CharCount);
  401. mBlocks.Add(buildRG);
  402. buildRG = null;
  403. }
  404. }
  405. // 计算换行
  406. this.mLines.Clear();
  407. if (mBlocks.Count > 0)
  408. {
  409. if (mEnableLineBreak)
  410. {
  411. float curX = 0;
  412. Line curLine = new Line(this);
  413. for (int i = 0; i < mBlocks.Count; i++)
  414. {
  415. Region rg = mBlocks[i];
  416. Region split_cur;
  417. Region split_next;
  418. int testW = (int)(mWidth - curX);
  419. //测试边界已经到达//
  420. if (testW <= 0)
  421. {
  422. //当前行入栈//
  423. mLines.Add(curLine);
  424. curLine = new Line(this);
  425. curX = 0;
  426. testW = (int)mWidth;
  427. }
  428. if (rg.mText.EndsWith("\n"))
  429. {
  430. //直接换行////当前行入栈//
  431. this.TestLineBreak2(rg.mText.Substring(0, rg.mText.Length - 1), rg.mAttribute, float.MaxValue, out rg.mBounds.width, out rg.mBounds.height);
  432. curLine.AddRegion(rg);
  433. mLines.Add(curLine);
  434. curLine = new Line(this);
  435. curX = 0;
  436. }
  437. else if (TestLineBreak(rg, testW, out split_cur, out split_next))
  438. {
  439. //测试截断成功//
  440. if (split_next == rg)
  441. {
  442. //当前段直接到下一行//
  443. if (curLine.RegionCount == 0)
  444. {
  445. //当前行为空,表示最小尺寸已经大于宽//添加到当前行//
  446. curLine.AddRegion(rg);
  447. mLines.Add(curLine);
  448. curLine = new Line(this);
  449. curX = 0;
  450. }
  451. else
  452. {
  453. //添加到下一行//
  454. mLines.Add(curLine);
  455. curLine = new Line(this);
  456. curX = 0;
  457. //重新从下一行开始检索//
  458. --i;
  459. }
  460. }
  461. else
  462. {
  463. // 换行并且被切成2断
  464. mBlocks.RemoveAt(i);
  465. mBlocks.Insert(i, split_cur);
  466. mBlocks.Insert(i + 1, split_next);
  467. rg.Dispose();
  468. // next line
  469. curLine.AddRegion(split_cur);
  470. mLines.Add(curLine);
  471. curLine = new Line(this);
  472. curX = 0;
  473. }
  474. }
  475. else
  476. {
  477. //本行增加段//
  478. curLine.AddRegion(rg);
  479. curX += rg.mBounds.width;
  480. //最后一行//
  481. if (i == (mBlocks.Count - 1))
  482. {
  483. mLines.Add(curLine);
  484. }
  485. }
  486. }
  487. }
  488. else
  489. {
  490. Line curLine = new Line(this);
  491. for (int i = 0; i < mBlocks.Count; i++)
  492. {
  493. Region rg = mBlocks[i];
  494. Region split_cur;
  495. Region split_next;
  496. TestLineBreak(rg, int.MaxValue, out split_cur, out split_next);
  497. curLine.AddRegion(rg);
  498. }
  499. mLines.Add(curLine);
  500. }
  501. }
  502. ResetLines();
  503. mIsColorDirty = true;
  504. }
  505. private void ResetLines()
  506. {
  507. mContentWidth = 1;
  508. mContentHeigh = 0;
  509. float c_left = float.MaxValue;
  510. float c_right = 0;
  511. for (int i = 0; i < mLines.Count; i++)
  512. {
  513. Line line = mLines[i];
  514. line.mIndex = i;
  515. float dw = 0;
  516. float dh = 0;
  517. //计算宽高//
  518. {
  519. line.mAnchor = RichTextAlignment.taNA;
  520. for (int c = 0; c < line.mBlocks.Count; c++)
  521. {
  522. Region rg = line.mBlocks[c];
  523. rg.mBounds.x = dw;
  524. rg.mBounds.y = mContentHeigh;
  525. dw += rg.mBounds.width;
  526. dh = Math.Max(dh, rg.mBounds.height);
  527. if (rg.Attribute.anchor != RichTextAlignment.taNA)
  528. {
  529. line.mAnchor = rg.Attribute.anchor;
  530. }
  531. }
  532. line.mBounds.width = dw;
  533. line.mBounds.height = dh;
  534. line.mBounds.x = 0;
  535. line.mBounds.y = mContentHeigh;
  536. if (line.mAnchor == RichTextAlignment.taNA)
  537. {
  538. line.mAnchor = mAlignment;
  539. }
  540. }
  541. //计算位置//
  542. {
  543. float dx = 0;
  544. switch (line.mAnchor)
  545. {
  546. case RichTextAlignment.taLEFT:
  547. break;
  548. case RichTextAlignment.taCENTER:
  549. dx += (mWidth - dw) / 2;
  550. break;
  551. case RichTextAlignment.taRIGHT:
  552. dx += (mWidth - dw);
  553. break;
  554. }
  555. for (int c = 0; c < line.mBlocks.Count; c++)
  556. {
  557. Region rg = line.mBlocks[c];
  558. rg.mBounds.x += dx;
  559. rg.mBounds.y = rg.mBounds.y + dh - rg.mBounds.height;
  560. }
  561. line.mBounds.x += dx;
  562. }
  563. c_left = Math.Min(line.mBounds.x, c_left);
  564. c_right = Math.Max(line.mBounds.x + line.mBounds.width, c_right);
  565. if (mFixedLineSpace > 0)
  566. {
  567. mContentHeigh += mFixedLineSpace;
  568. }
  569. else
  570. {
  571. mContentHeigh += dh + mLineSpace;
  572. }
  573. }
  574. if (c_left < c_right)
  575. {
  576. mContentWidth = c_right - c_left;
  577. }
  578. else
  579. {
  580. mContentWidth = 1;
  581. }
  582. OnEndResetLines();
  583. if (event_EndResetLines != null) event_EndResetLines.Invoke(this);
  584. }
  585. /// <summary>
  586. /// 测试截断
  587. /// </summary>
  588. /// <param name="rg"></param>
  589. /// <param name="testW"></param>
  590. /// <param name="split_cur"></param>
  591. /// <param name="split_next"></param>
  592. /// <returns></returns>
  593. private bool TestLineBreak(Region rg, float testW, out Region split_cur, out Region split_next)
  594. {
  595. rg.mBounds.width = 0;
  596. rg.mBounds.height = 0;
  597. split_cur = null;
  598. split_next = null;
  599. TextAttribute ta = rg.mAttribute;
  600. float last_tw = 0;
  601. float last_th = 0;
  602. float tw = 0;
  603. float th = 0;
  604. int textLength = rg.mText.Length;
  605. for (int ci = 0; ci < textLength; ++ci)
  606. {
  607. int cci = ci;
  608. int emoji_extra_len = 0; // emoji 额外长度 //
  609. bool isemoji = Driver.Instance.IsEmoji(rg.mText, ci, out emoji_extra_len);
  610. if (isemoji)
  611. {
  612. //keep self index//
  613. emoji_extra_len -= 1;
  614. ci += emoji_extra_len;
  615. }
  616. string text = rg.mText.Substring(0, ci + 1);
  617. if (TestLineBreak2(text, ta, testW, out tw, out th))
  618. {
  619. if (cci == 0)
  620. {
  621. // 直接需要换行 //
  622. split_next = rg;
  623. split_cur = rg;
  624. rg.mBounds.width = tw;
  625. rg.mBounds.height = th;
  626. }
  627. else
  628. {
  629. //需要切2段//
  630. Region[] splits = rg.Split(isemoji ? ci - emoji_extra_len : ci);
  631. rg.Dispose();
  632. split_cur = splits[0];
  633. //切开后,第一段宽高保持上一次检测值//
  634. split_cur.mBounds.width = last_tw;
  635. split_cur.mBounds.height = last_th;
  636. split_next = splits[1];
  637. }
  638. return true;
  639. }
  640. else
  641. {
  642. rg.mBounds.width = tw;
  643. rg.mBounds.height = th;
  644. }
  645. last_tw = tw;
  646. last_th = th;
  647. }
  648. return false;
  649. }
  650. /// <summary>
  651. /// 检测文本范围,构造Region尺寸。
  652. /// </summary>
  653. /// <param name="text"></param>
  654. /// <param name="ta"></param>
  655. /// <param name="testW"></param>
  656. /// <param name="tw"></param>
  657. /// <param name="th"></param>
  658. /// <returns></returns>
  659. private bool TestLineBreak2(String text, TextAttribute ta, float testW, out float tw, out float th)
  660. {
  661. tw = 0;
  662. th = 0;
  663. if (text.Equals("\n"))
  664. {
  665. TestTextLineBreak(text, ta, testW, out tw, out th);
  666. tw = 0;
  667. return true;
  668. }
  669. else if (ta.drawable != null)
  670. {
  671. tw = ta.drawable.CharWidth * text.Length;
  672. th = ta.drawable.CharHeight;
  673. if (tw > testW)
  674. {
  675. tw = (float)Math.Ceiling(testW - ta.drawable.CharWidth);
  676. return true;
  677. }
  678. }
  679. else if (!string.IsNullOrEmpty(ta.resImage))
  680. {
  681. if (ta.resImageZoom != null)
  682. {
  683. tw = ta.resImageZoom.Width * text.Length;
  684. th = ta.resImageZoom.Height;
  685. if (tw > testW)
  686. {
  687. tw = (float)Math.Ceiling(testW - ta.resImageZoom.Width);
  688. return true;
  689. }
  690. }
  691. else
  692. {
  693. TImageRegion img = AddImage(ta);
  694. if (img.image != null)
  695. {
  696. tw = img.sw * text.Length;
  697. th = img.sh;
  698. if (tw > testW)
  699. {
  700. tw = (float)Math.Ceiling(testW - img.sw);
  701. return true;
  702. }
  703. }
  704. }
  705. }
  706. else if (!string.IsNullOrEmpty(ta.resSprite))
  707. {
  708. TSpriteMetaAnimateFrame spr = AddSprite(ta);
  709. if (spr.sprite != null)
  710. {
  711. CCD bounds = spr.sprite.getVisibleBounds(spr.anim);
  712. tw = bounds.Width * text.Length;
  713. th = bounds.Height;
  714. if (tw > testW)
  715. {
  716. tw = (float)Math.Ceiling(testW - bounds.Width);
  717. return true;
  718. }
  719. }
  720. }
  721. else if (this.TestTextLineBreak(text, ta, testW, out tw, out th))
  722. {
  723. return true;
  724. }
  725. return false;
  726. }
  727. /// <summary>
  728. /// 检测属性上是否要分段
  729. /// </summary>
  730. /// <param name="rg"></param>
  731. /// <param name="ta"></param>
  732. /// <returns></returns>
  733. protected virtual bool TestSplitByAttribute(TextAttribute rg, TextAttribute ta)
  734. {
  735. return rg.Equals(ta);
  736. }
  737. /// <summary>
  738. /// 检测文本是否超过指定范围,并返回文本实际尺寸。
  739. /// </summary>
  740. /// <param name="text"></param>
  741. /// <param name="ta"></param>
  742. /// <param name="testW"></param>
  743. /// <param name="tw"></param>
  744. /// <param name="th"></param>
  745. /// <returns></returns>
  746. protected virtual bool TestTextLineBreak(string text, TextAttribute ta, float testW, out float tw, out float th)
  747. {
  748. return Driver.Instance.testTextLineBreak(text, ta.fontSize, ta.fontStyle, mBorderCount, testW, out tw, out th);
  749. }
  750. //------------------------------------------------------------------------------------
  751. private void CreateRegionBuffs()
  752. {
  753. mIsColorDirty = false;
  754. // 生成缓冲区
  755. for (int i = 0; i < mBlocks.Count; i++)
  756. {
  757. Region rg = mBlocks[i];
  758. rg.mIndex = i;
  759. CreateRegionBuffer(rg);
  760. }
  761. }
  762. private Drawable CreateRegionBuffer(Region rg)
  763. {
  764. if (rg.IsBreak)
  765. {
  766. rg.Buffer = null;
  767. }
  768. else if (rg.mAttribute.drawable != null)
  769. {
  770. rg.Buffer = this.CreateDrawable(rg, rg.mAttribute.drawable);
  771. }
  772. else if (!string.IsNullOrEmpty(rg.mAttribute.resImage))
  773. {
  774. TImageRegion img = AddImage(rg.mAttribute);
  775. if (img.image != null)
  776. {
  777. rg.Buffer = this.CreateDrawable(rg, img);
  778. }
  779. }
  780. else if (!string.IsNullOrEmpty(rg.mAttribute.resSprite))
  781. {
  782. TSpriteMetaAnimateFrame spr = AddSprite(rg.mAttribute);
  783. if (spr.sprite != null)
  784. {
  785. rg.Buffer = this.CreateDrawable(rg, spr);
  786. }
  787. }
  788. else
  789. {
  790. rg.Buffer = this.CreateDrawable(rg, rg.Text);
  791. }
  792. return rg.Buffer;
  793. }
  794. private TImageRegion AddImage(TextAttribute ta)
  795. {
  796. TImageRegion ret = new TImageRegion();
  797. if (mImageCache.TryGetValue(ta.resImage, out ret))
  798. {
  799. return ret;
  800. }
  801. if (ta.resImage.StartsWith("#"))
  802. {
  803. string[] kvs = ta.resImage.Split(',');
  804. if (kvs.Length >= 3)
  805. {
  806. string file = kvs[0].Substring(1);
  807. Cell.CPJResource res = this.AddCPJResource(file);
  808. if (res != null)
  809. {
  810. Cell.CPJAtlas atlas = res.GetAtlas(kvs[1]);
  811. int tid;
  812. if (atlas != null && int.TryParse(kvs[2], out tid))
  813. {
  814. Image image = atlas.GetTile(tid);
  815. if (image != null)
  816. {
  817. Rectangle2D rect = atlas.GetAtlasRegion(tid);
  818. ret.sx = rect.x;
  819. ret.sy = rect.y;
  820. ret.sw = rect.width;
  821. ret.sh = rect.height;
  822. ret.image = image;
  823. mImageCache.Add(ta.resImage, ret);
  824. return ret;
  825. }
  826. }
  827. }
  828. }
  829. }
  830. else
  831. {
  832. string file = ta.resImage;
  833. Image image = AddImage(file);
  834. if (image != null)
  835. {
  836. ret.sw = image.Width;
  837. ret.sh = image.Height;
  838. ret.image = image;
  839. mImageCache.Add(ta.resImage, ret);
  840. return ret;
  841. }
  842. }
  843. return ret;
  844. }
  845. private TSpriteMetaAnimateFrame AddSprite(TextAttribute ta)
  846. {
  847. TSpriteMetaAnimateFrame ret;
  848. if (mSpriteCache.TryGetValue(ta.resSprite, out ret))
  849. {
  850. return ret;
  851. }
  852. string[] resSpr = ta.resSprite.Split(',');
  853. string file = resSpr[0];
  854. Cell.CPJResource res = this.AddCPJResource(file);
  855. if (res != null)
  856. {
  857. int anim;
  858. string spr_name = null;
  859. if (resSpr.Length >= 2)
  860. {
  861. spr_name = resSpr[1];
  862. }
  863. else
  864. {
  865. spr_name = res.Loader.DefaultSpriteName;
  866. }
  867. if (resSpr.Length >= 3)
  868. {
  869. int.TryParse(resSpr[2], out anim);
  870. }
  871. else
  872. {
  873. anim = 0;
  874. }
  875. if (spr_name != null)
  876. {
  877. CSpriteMeta spr = res.GetSpriteMeta(spr_name);
  878. if (spr != null)
  879. {
  880. ret.sprite = spr;
  881. ret.anim = anim;
  882. mSpriteCache.Add(ta.resSprite, ret);
  883. return ret;
  884. }
  885. }
  886. }
  887. return ret;
  888. }
  889. //----------------------------------------------------------------------------------------
  890. protected abstract Image AddImage(string path);
  891. protected abstract Cell.CPJResource AddCPJResource(string path);
  892. public abstract Drawable CreateDrawable(Region rg, object content);
  893. public interface Drawable : IDisposable
  894. {
  895. float CharWidth { get; }
  896. float CharHeight { get; }
  897. void Render(Graphics g, Region self, float x, float y);
  898. void Hide(Region self, float x, float y);
  899. }
  900. //----------------------------------------------------------------------------------------
  901. #region _LineAndRegion_
  902. /// <summary>
  903. /// 一块渲染区域
  904. /// </summary>
  905. public class Region
  906. {
  907. private readonly BaseRichTextLayer mLayer;
  908. public bool IsBreak { get { return mText.EndsWith("\n"); } }
  909. public int CharStartIndex { get { return mStartIndex; } }
  910. public int CharEndIndex { get { return mEndIndex; } }
  911. public int CharCount { get { return mEndIndex - mStartIndex; } }
  912. public Rectangle2D Bounds { get { return mBounds; } }
  913. public TextAttribute Attribute { get { return mAttribute; } }
  914. public string Text { get { return mText; } }
  915. public int Index { get { return mIndex; } }
  916. internal Drawable Buffer
  917. {
  918. get { return m_buffer; }
  919. set
  920. {
  921. if (m_buffer != null) m_buffer.Dispose();
  922. m_buffer = value;
  923. }
  924. }
  925. private Drawable m_buffer;
  926. internal readonly TextAttribute mAttribute;
  927. internal int mStartIndex;
  928. internal int mEndIndex;
  929. internal string mText;
  930. internal Rectangle2D mBounds = new Rectangle2D();
  931. /// <summary>
  932. /// 位于mBlocks的位置
  933. /// </summary>
  934. internal int mIndex;
  935. internal Region(BaseRichTextLayer layer, TextAttribute ta)
  936. {
  937. this.mLayer = layer;
  938. this.mAttribute = ta;
  939. }
  940. internal Region[] Split(int charIndex)
  941. {
  942. if (charIndex >= 0 && charIndex < mText.Length)
  943. {
  944. Region a = new Region(mLayer, mAttribute);
  945. {
  946. a.mStartIndex = this.mStartIndex;
  947. a.mEndIndex = this.mStartIndex + charIndex;
  948. a.mText = this.mText.Substring(0, charIndex);
  949. }
  950. Region b = new Region(mLayer, mAttribute);
  951. {
  952. b.mStartIndex = this.mStartIndex + charIndex;
  953. b.mEndIndex = this.mEndIndex;
  954. b.mText = this.mText.Substring(charIndex);
  955. }
  956. return new Region[] { a, b };
  957. }
  958. return null;
  959. }
  960. public void Render(Graphics g, float px, float py)
  961. {
  962. if (m_buffer != null)
  963. {
  964. m_buffer.Render(g, this, mBounds.x + px, mBounds.y + py);
  965. }
  966. this.mLayer.OnDrawRegion(g, this, px, py);
  967. }
  968. public void Hide(float px, float py)
  969. {
  970. if (m_buffer != null)
  971. {
  972. m_buffer.Hide(this, mBounds.x + px, mBounds.y + py);
  973. }
  974. }
  975. internal void Dispose()
  976. {
  977. if (m_buffer != null)
  978. {
  979. m_buffer.Dispose();
  980. m_buffer = null;
  981. }
  982. }
  983. public override string ToString()
  984. {
  985. return string.Format("Region({0})", mText);
  986. }
  987. }
  988. public class Line
  989. {
  990. private readonly BaseRichTextLayer mLayer;
  991. internal int mIndex = 0;
  992. internal readonly Rectangle2D mBounds = new Rectangle2D();
  993. internal readonly List<Region> mBlocks = new List<Region>();
  994. internal RichTextAlignment mAnchor = RichTextAlignment.taNA;
  995. public int Index
  996. {
  997. get
  998. {
  999. return mIndex;
  1000. }
  1001. }
  1002. public Rectangle2D Bounds
  1003. {
  1004. get
  1005. {
  1006. return mBounds;
  1007. }
  1008. }
  1009. public int CharStartIndex
  1010. {
  1011. get
  1012. {
  1013. if (mBlocks.Count > 0)
  1014. {
  1015. return mBlocks[0].mStartIndex;
  1016. }
  1017. return -1;
  1018. }
  1019. }
  1020. public int RegionCount
  1021. {
  1022. get
  1023. {
  1024. return mBlocks.Count;
  1025. }
  1026. }
  1027. public int CharEndIndex
  1028. {
  1029. get
  1030. {
  1031. if (mBlocks.Count > 0)
  1032. {
  1033. return mBlocks[mBlocks.Count - 1].mEndIndex;
  1034. }
  1035. return -1;
  1036. }
  1037. }
  1038. public RichTextAlignment Anchor
  1039. {
  1040. get { return mAnchor; }
  1041. }
  1042. internal Line(BaseRichTextLayer layer)
  1043. {
  1044. this.mLayer = layer;
  1045. }
  1046. internal void AddRegion(Region rg)
  1047. {
  1048. mBlocks.Add(rg);
  1049. if (rg.Attribute.anchor != RichTextAlignment.taNA)
  1050. {
  1051. this.mAnchor = rg.Attribute.anchor;
  1052. }
  1053. }
  1054. public void RenderLine(Graphics g, float px, float py)
  1055. {
  1056. for (int i = 0; i < mBlocks.Count; i++)
  1057. {
  1058. mBlocks[i].Render(g, px, py);
  1059. }
  1060. mLayer.OnDrawLine(g, this, px, py);
  1061. }
  1062. public void HideLine(float px, float py)
  1063. {
  1064. for (int i = 0; i < mBlocks.Count; i++)
  1065. {
  1066. mBlocks[i].Hide(px, py);
  1067. }
  1068. }
  1069. }
  1070. #endregion
  1071. //----------------------------------------------------------------------------------------
  1072. }
  1073. //----------------------------------------------------------------------------------------
  1074. public struct RichTextClickInfo
  1075. {
  1076. public BaseRichTextLayer.Region mRegion;
  1077. public BaseRichTextLayer.Line mLine;
  1078. }
  1079. public enum RichTextAlignment
  1080. {
  1081. taNA = 0,
  1082. taLEFT = 1,
  1083. taCENTER = 2,
  1084. taRIGHT = 3,
  1085. }
  1086. //----------------------------------------------------------------------------------------
  1087. public class RichTextLayer : BaseRichTextLayer
  1088. {
  1089. public static bool TestDraw = false;
  1090. public static uint TestFillContentSize = 0x80808080;
  1091. public static uint TestDrawRegionSize = 0x000000ff;
  1092. public static string DefaultImageRoot = "";
  1093. public string ImageRoot = DefaultImageRoot;
  1094. protected HashMap<string, Image> mImageMap = new HashMap<string, Image>();
  1095. protected HashMap<string, Cell.CPJResource> mResMap = new HashMap<string, Cell.CPJResource>();
  1096. /// <summary>
  1097. /// 自己加载的图片
  1098. /// </summary>
  1099. protected HashMap<string, Image> mSelfImageMap = new HashMap<string, Image>();
  1100. /// <summary>
  1101. /// 自己加载的精灵
  1102. /// </summary>
  1103. protected HashMap<string, Cell.CPJResource> mSelfResMap = new HashMap<string, Cell.CPJResource>();
  1104. public RichTextLayer(float width = 100, RichTextAlignment anchor = RichTextAlignment.taLEFT)
  1105. : base(width, anchor)
  1106. {
  1107. }
  1108. protected override Image AddImage(string file)
  1109. {
  1110. Image img = mImageMap.Get(file);
  1111. if (img == null)
  1112. {
  1113. img = Driver.Instance.createImage(ImageRoot + file);
  1114. if (img != null)
  1115. {
  1116. mSelfImageMap.Put(file, img);
  1117. mImageMap.Put(file, img);
  1118. }
  1119. }
  1120. return img;
  1121. }
  1122. protected override Cell.CPJResource AddCPJResource(string file)
  1123. {
  1124. Cell.CPJResource res = mResMap.Get(file);
  1125. if (res == null)
  1126. {
  1127. res = Cell.CPJResource.CreateResource(ImageRoot + file);
  1128. if (res != null)
  1129. {
  1130. mSelfResMap.Put(file, res);
  1131. mResMap.Put(file, res);
  1132. }
  1133. }
  1134. return res;
  1135. }
  1136. /// <summary>
  1137. /// 添加图片映射表
  1138. /// </summary>
  1139. /// <param name="file"></param>
  1140. /// <param name="img"></param>
  1141. /// <returns></returns>
  1142. public virtual void AddImage(string file, Image img)
  1143. {
  1144. if (img != null)
  1145. {
  1146. mImageMap.Put(file, img);
  1147. }
  1148. }
  1149. /// <summary>
  1150. /// 添加精灵映射表
  1151. /// </summary>
  1152. /// <param name="file"></param>
  1153. /// <param name="res"></param>
  1154. /// <returns></returns>
  1155. public virtual void AddResource(string file, Cell.CPJResource res)
  1156. {
  1157. if (res != null)
  1158. {
  1159. mResMap.Put(file, res);
  1160. }
  1161. }
  1162. public override void Render(Graphics g, float px, float py, float pw, float ph, float cx, float cy)
  1163. {
  1164. base.BeginRender(g);
  1165. Blend cur_blend = g.getBlend();
  1166. try
  1167. {
  1168. if (!IsEnable)
  1169. {
  1170. g.setBlend(Blend.BLEND_MODE_GRAY);
  1171. }
  1172. //测试绘制区域.//
  1173. if (TestDraw && ContentWidth > 0 && ContentHeight > 0)
  1174. {
  1175. g.setColor(TestFillContentSize);
  1176. switch (Alignment)
  1177. {
  1178. case RichTextAlignment.taLEFT:
  1179. g.fillRect(0, 0, ContentWidth, ContentHeight);
  1180. break;
  1181. case RichTextAlignment.taRIGHT:
  1182. g.fillRect(Width - ContentWidth, 0, ContentWidth, ContentHeight);
  1183. break;
  1184. case RichTextAlignment.taCENTER:
  1185. g.fillRect((Width - ContentWidth) / 2, 0, ContentWidth, ContentHeight);
  1186. break;
  1187. }
  1188. }
  1189. base.InternalRender(g, px, py, pw, ph, cx, cy);
  1190. }
  1191. finally
  1192. {
  1193. g.setBlend(cur_blend);
  1194. }
  1195. base.AfterRender(g);
  1196. }
  1197. protected override void OnDrawRegion(Graphics g, Region rg, float px, float py)
  1198. {
  1199. if (TestDraw)
  1200. {
  1201. g.setColor(TestDrawRegionSize);
  1202. g.drawRect(rg.Bounds.x + px, rg.Bounds.y + py, rg.Bounds.width, rg.Bounds.height);
  1203. }
  1204. }
  1205. public override void Dispose()
  1206. {
  1207. base.Dispose();
  1208. if (mSelfImageMap != null)
  1209. {
  1210. foreach (KeyValuePair<string, Image> kvp in mSelfImageMap)
  1211. {
  1212. kvp.Value.Dispose();
  1213. }
  1214. mSelfImageMap.Clear();
  1215. }
  1216. if (mSelfResMap != null)
  1217. {
  1218. foreach (KeyValuePair<string, Cell.CPJResource> kvp in mSelfResMap)
  1219. {
  1220. kvp.Value.Dispose();
  1221. }
  1222. mSelfResMap.Clear();
  1223. }
  1224. }
  1225. public override Drawable CreateDrawable(Region rg, object content)
  1226. {
  1227. if (content is TextDrawable)
  1228. {
  1229. return content as TextDrawable;
  1230. }
  1231. if (content is TImageRegion)
  1232. {
  1233. return new DrawImage(this, rg, (TImageRegion)content);
  1234. }
  1235. if (content is TSpriteMetaAnimateFrame)
  1236. {
  1237. return new DrawSprite(this, rg, (TSpriteMetaAnimateFrame)content);
  1238. }
  1239. return new DrawText(this, rg, content.ToString());
  1240. }
  1241. public class DrawText : Drawable
  1242. {
  1243. private TextLayer text;
  1244. public DrawText(RichTextLayer layer, Region rg, string content)
  1245. {
  1246. TextAttribute ta = rg.Attribute;
  1247. this.text = Driver.Instance.createTextLayer(content, ta.fontSize, ta.fontStyle);
  1248. text.IsEnable = layer.IsEnable;
  1249. text.FontColor = ta.fontColor;
  1250. if (ta.borderCount > 0)
  1251. {
  1252. text.BorderColor = ta.borderColor;
  1253. text.BorderTime = (int)ta.borderCount;
  1254. }
  1255. else
  1256. {
  1257. text.BorderColor = layer.BorderColor;
  1258. text.BorderTime = layer.BorderCount;
  1259. }
  1260. }
  1261. public float CharWidth { get { return text.Width; } }
  1262. public float CharHeight { get { return text.Height; } }
  1263. public void Render(Graphics g, Region rg, float x, float y)
  1264. {
  1265. g.drawTextLayer(text, x, y, CommonUI.Display.Anchor.NONE);
  1266. }
  1267. public void Hide(Region self, float x, float y) { }
  1268. public void Dispose()
  1269. {
  1270. text.Dispose();
  1271. }
  1272. }
  1273. public class DrawImage : Drawable
  1274. {
  1275. private TImageRegion image;
  1276. private TextAttribute ta;
  1277. public DrawImage(RichTextLayer layer, Region rg, TImageRegion img)
  1278. {
  1279. this.image = img;
  1280. this.ta = rg.Attribute;
  1281. }
  1282. public float CharWidth
  1283. {
  1284. get
  1285. {
  1286. if (ta.resImageZoom != null) { return ta.resImageZoom.Width; }
  1287. return image.sw;
  1288. }
  1289. }
  1290. public float CharHeight
  1291. {
  1292. get
  1293. {
  1294. if (ta.resImageZoom != null) { return ta.resImageZoom.Height; }
  1295. return image.sh;
  1296. }
  1297. }
  1298. public void Render(Graphics g, Region rg, float x, float y)
  1299. {
  1300. string text = rg.mText;
  1301. int len = text.Length;
  1302. if (ta.resImageZoom != null)
  1303. {
  1304. float tw = ta.resImageZoom.Width;
  1305. float th = ta.resImageZoom.Height;
  1306. for (int i = 0; i < len; i++)
  1307. {
  1308. g.drawImageZoom(image.image, x + i * tw, y, tw, th);
  1309. }
  1310. }
  1311. else
  1312. {
  1313. for (int i = 0; i < len; i++)
  1314. {
  1315. g.drawImage(image.image, x + i * image.sw, y);
  1316. }
  1317. }
  1318. }
  1319. public void Hide(Region self, float x, float y) { }
  1320. public void Dispose() { }
  1321. }
  1322. public class DrawSprite : Drawable
  1323. {
  1324. private CSpriteMeta spr;
  1325. private int frame_count;
  1326. private int curframe;
  1327. private int curanim;
  1328. private CCD bounds;
  1329. public DrawSprite(RichTextLayer layer, Region rg, TSpriteMetaAnimateFrame spr)
  1330. {
  1331. this.spr = spr.sprite;
  1332. this.curanim = spr.anim;
  1333. this.frame_count = spr.sprite.getFrameCount(spr.anim);
  1334. this.bounds = spr.sprite.getVisibleBounds(spr.anim);
  1335. }
  1336. public float CharWidth { get { return bounds.Width; } }
  1337. public float CharHeight { get { return bounds.Height; } }
  1338. public void Render(Graphics g, Region rg, float x, float y)
  1339. {
  1340. if (frame_count > 0)
  1341. {
  1342. string text = rg.mText;
  1343. int len = text.Length;
  1344. float px;
  1345. for (int i = 0; i < len; i++)
  1346. {
  1347. px = x + i * bounds.Width;
  1348. spr.render(g, curanim, curframe, px - bounds.X1, y - bounds.Y1);
  1349. }
  1350. curframe++;
  1351. curframe = curframe % frame_count;
  1352. }
  1353. }
  1354. public void Hide(Region self, float x, float y) { }
  1355. public void Dispose() { }
  1356. }
  1357. }
  1358. //----------------------------------------------------------------------------------------
  1359. }