PageRenderTime 120ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/boxvivid/uppsrc/RichText/TxtPaint.cpp

http://boxvivid.googlecode.com/
C++ | 389 lines | 366 code | 23 blank | 0 comment | 94 complexity | 34aa37a911368313a64ee3c3c022d45d MD5 | raw file
Possible License(s): LGPL-2.1, BSD-2-Clause, BSD-3-Clause, LGPL-3.0
  1. #include "RichText.h"
  2. NAMESPACE_UPP
  3. int RichTxt::GetWidth(const RichStyles& st) const
  4. {
  5. int cx = 0;
  6. for(int i = 0; i < part.GetCount(); i++) {
  7. if(IsPara(i)) {
  8. RichPara p = Get(i, st, true);
  9. RichPara::Lines pl = p.FormatLines(INT_MAX);
  10. int ccx = 0;
  11. Sum(ccx, ~pl.width, ~pl.width + pl.clen);
  12. cx = max(cx, ccx);
  13. }
  14. else
  15. return 10000;
  16. }
  17. return cx;
  18. }
  19. void RichTxt::Sync0(const Para& pp, int parti, const RichContext& rc) const
  20. {
  21. int cx = rc.page.Width();
  22. pp.ccx = cx;
  23. RichPara p = Get(parti, rc.styles, false);
  24. RichPara::Lines pl = p.FormatLines(cx);
  25. pp.ruler = p.format.ruler;
  26. pp.before = p.format.before;
  27. pp.linecy.Clear();
  28. pp.linecy.SetCount(pl.GetCount());
  29. for(int i = 0; i < pl.GetCount(); i++)
  30. pp.linecy[i] = pl[i].Sum();
  31. pp.cy = Sum0(pp.linecy);
  32. pp.after = p.format.after;
  33. pp.newpage = p.format.newpage;
  34. pp.keep = p.format.keep;
  35. pp.keepnext = p.format.keepnext;
  36. pp.orphan = p.format.orphan;
  37. }
  38. void RichTxt::Sync(int parti, const RichContext& rc) const {
  39. ASSERT(part[parti].Is<Para>());
  40. const Para& pp = part[parti].Get<Para>();
  41. if(rc.page.Width() != pp.ccx)
  42. pp.dirty.Invalidate();
  43. if(pp.dirty.BeginUpdate()) {
  44. Sync0(pp, parti, rc);
  45. pp.dirty.EndUpdate();
  46. }
  47. }
  48. bool RichTxt::BreaksPage(PageY py, const Para& pp, int i, const Rect& page) const
  49. {
  50. int linecy = pp.linecy[i];
  51. if(linecy >= page.Height()) return false;
  52. if(linecy + py.y > page.bottom)
  53. return true;
  54. if(pp.orphan || pp.linecy.GetCount() < 2) return false;
  55. if((i == 0 || i == pp.linecy.GetCount() - 2) &&
  56. py.y + linecy + pp.linecy[i + 1] > page.bottom)
  57. return true;
  58. return false;
  59. }
  60. PageY RichTxt::GetNextPageY(int parti, const RichContext& rc) const
  61. {
  62. if(part[parti].Is<RichTable>())
  63. return GetTable(parti).GetHeight(rc);
  64. else {
  65. Sync(parti, rc);
  66. const Para& pp = part[parti].Get<Para>();
  67. int cy = pp.before + pp.ruler;
  68. if(pp.keep || pp.keepnext)
  69. cy += pp.cy;
  70. else
  71. cy += pp.linecy[0];
  72. PageY py = rc.py;
  73. if(rc.page.Height() < 30000) {
  74. int nbefore = 0;
  75. int nline = 0;
  76. if(pp.keepnext && parti + 1 < part.GetCount() && part[parti + 1].Is<Para>()) {
  77. Sync(parti + 1, rc);
  78. const Para& p = part[parti + 1].Get<Para>();
  79. nbefore = p.before + p.ruler;
  80. nline = p.linecy[0];
  81. }
  82. if(pp.newpage || py.y + cy + nbefore + nline > rc.page.bottom && cy < rc.page.Height()) {
  83. py.page++;
  84. py.y = rc.page.top;
  85. }
  86. py.y += pp.before + pp.ruler;
  87. if(py.y + pp.cy < rc.page.bottom)
  88. py.y += pp.cy;
  89. else
  90. for(int lni = 0; lni < pp.linecy.GetCount(); lni++) {
  91. if(BreaksPage(py, pp, lni, rc.page)) {
  92. py.y = rc.page.top;
  93. py.page++;
  94. }
  95. py.y += pp.linecy[lni];
  96. }
  97. py.y += pp.after;
  98. if(py.y > rc.page.bottom) {
  99. py.y = rc.page.top;
  100. py.page++;
  101. }
  102. }
  103. else
  104. py.y += pp.before + pp.cy + pp.after + pp.ruler;
  105. return py;
  106. }
  107. }
  108. PageY RichTxt::GetPartPageY(int parti, RichContext rc) const
  109. {
  110. for(int i = 0; i < parti; i++)
  111. rc.py = GetNextPageY(i, rc);
  112. return rc.py;
  113. }
  114. bool IsPainting(PageDraw& pw, Zoom z, const Rect& page, PageY top, PageY bottom)
  115. {
  116. int t = top.y;
  117. for(int pi = top.page; pi < bottom.page; pi++) {
  118. if(pw.Page(pi).IsPainting(Rect(z * page.left, z * top.y, z * page.right, z * page.bottom)))
  119. return true;
  120. t = page.top;
  121. }
  122. return pw.Page(bottom.page).IsPainting(Rect(z * page.left, z * t, z * page.right, z * bottom.y));
  123. }
  124. void RichTxt::Paint(PageDraw& pw, RichContext rc, const PaintInfo& _pi) const
  125. {
  126. PaintInfo pi = _pi;
  127. int parti = 0;
  128. int pos = 0;
  129. RichPara::Number n;
  130. while(rc.py < pi.bottom && parti < part.GetCount()) {
  131. if(part[parti].Is<RichTable>()) {
  132. pi.tablesel--;
  133. const RichTable& tab = GetTable(parti);
  134. tab.Paint(pw, rc, pi);
  135. rc.py = tab.GetHeight(rc);
  136. pi.tablesel -= tab.GetTableCount();
  137. }
  138. else {
  139. const Para& pp = part[parti].Get<Para>();
  140. if(pp.number) {
  141. n.TestReset(*pp.number);
  142. n.Next(*pp.number);
  143. }
  144. PageY next = GetNextPageY(parti, rc);
  145. if(next >= pi.top) {
  146. int nbefore = 0;
  147. int nline = 0;
  148. if(pp.keepnext && parti + 1 < part.GetCount() && part[parti + 1].Is<Para>()) {
  149. Sync(parti + 1, rc);
  150. const Para& pp = part[parti + 1].Get<Para>();
  151. nbefore = pp.before;
  152. nline = pp.linecy[0];
  153. }
  154. RichPara p = Get(parti, rc.styles, true);
  155. if(pi.spellingchecker) {
  156. if(!pp.checked) {
  157. pp.spellerrors = (*pi.spellingchecker)(p);
  158. pp.checked = true;
  159. }
  160. }
  161. else {
  162. pp.checked = false;
  163. pp.spellerrors.Clear();
  164. }
  165. if(IsPainting(pw, pi.zoom, rc.page, rc.py, next))
  166. p.Paint(pw, rc.page, rc.py, pi, n, pp.spellerrors, nbefore, nline);
  167. }
  168. rc.py = next;
  169. }
  170. int l = GetPartLength(parti) + 1;
  171. pi.highlightpara -= l;
  172. pi.sell -= l;
  173. pi.selh -= l;
  174. pos += l;
  175. ++parti;
  176. }
  177. }
  178. RichCaret RichTxt::GetCaret(int pos, RichContext rc) const
  179. {
  180. int parti = 0;
  181. if(pos > GetLength())
  182. pos = GetLength();
  183. while(parti < part.GetCount()) {
  184. int l = GetPartLength(parti) + 1;
  185. if(pos < l)
  186. if(IsTable(parti))
  187. return GetTable(parti).GetCaret(pos, rc);
  188. else {
  189. const Para& p = part[parti].Get<Para>();
  190. int nbefore = 0;
  191. int nline = 0;
  192. if(p.keepnext && parti + 1 < part.GetCount() && part[parti + 1].Is<Para>()) {
  193. Sync(parti + 1, rc);
  194. const Para& pp = part[parti + 1].Get<Para>();
  195. nbefore = pp.before + pp.ruler;
  196. nline = pp.linecy[0];
  197. }
  198. RichCaret tp = Get(parti, rc.styles, true)
  199. .GetCaret(pos, rc.page, rc.py, nbefore, nline);
  200. tp.textpage = rc.page;
  201. return tp;
  202. }
  203. pos -= l;
  204. rc.py = GetNextPageY(parti++, rc);
  205. }
  206. return RichCaret();
  207. }
  208. int RichTxt::GetPos(int x, PageY y, RichContext rc) const
  209. {
  210. int parti = 0;
  211. int pos = 0;
  212. if(part.GetCount()) {
  213. PageY nnext = GetNextPageY(parti, rc);
  214. while(parti < part.GetCount()) {
  215. PageY next = nnext;
  216. if(parti + 1 < part.GetCount()) {
  217. RichContext nrc = rc;
  218. nrc.py = next;
  219. nnext = GetNextPageY(parti + 1, nrc);
  220. }
  221. if(y < next || y.page < next.page) {
  222. if(IsTable(parti))
  223. return GetTable(parti).GetPos(x, y, rc) + pos;
  224. else {
  225. int nbefore = 0;
  226. int nline = 0;
  227. if(part[parti].Get<Para>().keepnext && parti + 1 < part.GetCount() && IsPara(parti + 1)) {
  228. Sync(parti + 1, rc);
  229. const Para& pp = part[parti + 1].Get<Para>();
  230. nbefore = pp.before + pp.ruler;
  231. nline = pp.linecy[0];
  232. }
  233. return Get(parti, rc.styles, true)
  234. .GetPos(x, y, rc.page, rc.py, nbefore, nline) + pos;
  235. }
  236. }
  237. pos += GetPartLength(parti) + 1;
  238. parti++;
  239. rc.py = next;
  240. }
  241. }
  242. return pos - 1;
  243. }
  244. RichHotPos RichTxt::GetHotPos(int x, PageY y, int tolerance, RichContext rc) const
  245. {
  246. int parti = 0;
  247. int pos = 0;
  248. int ti = 0;
  249. if(part.GetCount()) {
  250. PageY nnext = GetNextPageY(parti, rc);
  251. while(parti < part.GetCount()) {
  252. PageY next = nnext;
  253. if(parti + 1 < part.GetCount()) {
  254. RichContext nrc = rc;
  255. nrc.py = next;
  256. nnext = GetNextPageY(parti + 1, nrc);
  257. }
  258. if(y < next || y.page < next.page) {
  259. if(IsTable(parti)) {
  260. RichHotPos pos = GetTable(parti).GetHotPos(x, y, tolerance, rc);
  261. pos.table += ti + 1;
  262. return pos;
  263. }
  264. else
  265. break;
  266. }
  267. if(IsTable(parti))
  268. ti += 1 + GetTable(parti).GetTableCount();
  269. pos += GetPartLength(parti) + 1;
  270. parti++;
  271. rc.py = next;
  272. }
  273. }
  274. return RichHotPos();
  275. }
  276. int RichTxt::GetVertMove(int pos, int gx, RichContext rc, int dir) const
  277. {
  278. ASSERT(dir == -1 || dir == 1);
  279. if(GetPartCount() == 0)
  280. return -1;
  281. int pi;
  282. int p = pos;
  283. if(pos >= 0) {
  284. pi = FindPart(p);
  285. pos -= p;
  286. }
  287. else {
  288. pi = dir > 0 ? 0 : GetPartCount() - 1;
  289. p = -1;
  290. pos = 0;
  291. }
  292. while(pi < GetPartCount()) {
  293. int q = IsTable(pi) ? GetTable(pi).GetVertMove(p, gx, rc, dir)
  294. : Get(pi, rc.styles, true).GetVertMove(p, gx, rc.page, dir);
  295. if(q >= 0)
  296. return q + pos;
  297. if(dir > 0)
  298. pos += GetPartLength(pi) + 1;
  299. p = -1;
  300. pi += dir;
  301. if(pi < 0)
  302. break;
  303. if(dir < 0)
  304. pos -= GetPartLength(pi) + 1;
  305. }
  306. return -1;
  307. }
  308. void RichTxt::GatherValPos(Vector<RichValPos>& f, RichContext rc, int pos, int type) const
  309. {
  310. int parti = 0;
  311. while(parti < part.GetCount()) {
  312. if(part[parti].Is<RichTable>())
  313. GetTable(parti).GatherValPos(f, rc, pos, type);
  314. else {
  315. int nbefore = 0;
  316. int nline = 0;
  317. const Para& p = part[parti].Get<Para>();
  318. if(p.keepnext && parti + 1 < part.GetCount() && IsPara(parti + 1)) {
  319. Sync(parti + 1, rc);
  320. const Para& pp = part[parti + 1].Get<Para>();
  321. nbefore = pp.before + pp.ruler;
  322. nline = pp.linecy[0];
  323. }
  324. if(p.haspos)
  325. if(type == LABELS)
  326. Get(parti, rc.styles, true).GatherLabels(f, rc.page, rc.py, pos, nbefore, nline);
  327. else
  328. Get(parti, rc.styles, true).GatherIndexes(f, rc.page, rc.py, pos, nbefore, nline);
  329. }
  330. pos += GetPartLength(parti) + 1;
  331. rc.py = GetNextPageY(parti++, rc);
  332. }
  333. }
  334. PageY RichTxt::GetHeight(RichContext rc) const
  335. {
  336. for(int i = 0; i < GetPartCount(); i++)
  337. rc.py = GetNextPageY(i, rc);
  338. return rc.py;
  339. }
  340. PageY RichTxt::GetTop(RichContext rc) const
  341. {
  342. if(part.GetCount() == 0)
  343. return rc.py;
  344. if(part[0].Is<RichTable>())
  345. return GetTable(0).GetTop(rc);
  346. else {
  347. Sync(0, rc);
  348. const Para& pp = part[0].Get<Para>();
  349. rc.py.y += pp.before + pp.ruler;
  350. if(BreaksPage(rc.py, pp, 0, rc.page))
  351. rc.Page();
  352. return rc.py;
  353. }
  354. }
  355. void RichTxt::ApplyZoom(Zoom z, const RichStyles& ostyle, const RichStyles& zstyle)
  356. {
  357. for(int i = 0; i < GetPartCount(); i++)
  358. if(IsTable(i))
  359. part[i].Get<RichTable>().ApplyZoom(z, ostyle, zstyle);
  360. else {
  361. RichPara p = Get(i, ostyle);
  362. p.ApplyZoom(z);
  363. Set(i, p, zstyle);
  364. }
  365. }
  366. END_UPP_NAMESPACE