PageRenderTime 73ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/src/core/utils/win32/TLogViewer.cpp

http://tvpcn.codeplex.com
C++ | 843 lines | 682 code | 94 blank | 67 comment | 135 complexity | 2f89fe14b50059a1b82240c80d00afc2 MD5 | raw file
Possible License(s): LGPL-3.0, MIT, LGPL-2.0
  1. //---------------------------------------------------------------------------
  2. /*
  3. TVP2 ( T Visual Presenter 2 ) A script authoring tool
  4. Copyright (C) 2000 W.Dee <dee@kikyou.info> and contributors
  5. See details of license at "license.txt"
  6. */
  7. //---------------------------------------------------------------------------
  8. // Log Viewer Control
  9. //---------------------------------------------------------------------------
  10. #include "tjsCommHead.h"
  11. #include <Clipbrd.hpp>
  12. #include <stdlib.h>
  13. #include "WideNativeFuncs.h"
  14. #include "MsgIntf.h"
  15. #include "TLogViewer.h"
  16. //---------------------------------------------------------------------------
  17. void TVPCopyToClipboard(const ttstr & unicode)
  18. {
  19. TClipboard *cb = Clipboard();
  20. cb->Open();
  21. HGLOBAL ansihandle = NULL;
  22. HGLOBAL unicodehandle = NULL;
  23. try
  24. {
  25. // store ANSI string
  26. AnsiString ansistr = unicode.AsAnsiString();
  27. ansihandle = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE,
  28. ansistr.Length() + 1);
  29. if(!ansihandle) throw Exception("copying to clipboard failed.");
  30. char *mem = (char*)GlobalLock(ansihandle);
  31. if(mem) strcpy(mem, ansistr.c_str());
  32. GlobalUnlock(ansihandle);
  33. cb->SetAsHandle(CF_TEXT, (int)ansihandle);
  34. ansihandle = NULL;
  35. // store UNICODE string
  36. unicodehandle = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE,
  37. (unicode.GetLen() + 1) * sizeof(tjs_char));
  38. if(!unicodehandle) throw Exception("copying to clipboard failed.");
  39. tjs_char *unimem = (tjs_char*)GlobalLock(unicodehandle);
  40. if(unimem) TJS_strcpy(unimem, unicode.c_str());
  41. GlobalUnlock(unicodehandle);
  42. cb->SetAsHandle(CF_UNICODETEXT, (int)unicodehandle);
  43. unicodehandle = NULL;
  44. }
  45. catch(...)
  46. {
  47. if(ansihandle) GlobalFree(ansihandle);
  48. if(unicodehandle) GlobalFree(unicodehandle);
  49. cb->Close();
  50. throw;
  51. }
  52. cb->Close();
  53. }
  54. //---------------------------------------------------------------------------
  55. //---------------------------------------------------------------------------
  56. __fastcall TLogViewer::TLogViewer(TWinControl *owner) : TCustomControl(Owner)
  57. {
  58. Brush->Style = bsClear;
  59. Color = clBlack;
  60. Cursor = crIBeam;
  61. FDataLength = 0;
  62. FFirstLine = 0;
  63. FMargin = 3;
  64. FLastClickedDataPos = 0;
  65. FSelStart = 0;
  66. FSelLength = 0;
  67. ScrollTimer = NULL;
  68. CharWidthMap = NULL;
  69. FMouseSelecting = false;
  70. FDoubleClickSelecting = false;
  71. }
  72. //---------------------------------------------------------------------------
  73. __fastcall TLogViewer::~TLogViewer()
  74. {
  75. if(CharWidthMap) delete [] CharWidthMap;
  76. if(ScrollTimer) delete ScrollTimer;
  77. }
  78. //---------------------------------------------------------------------------
  79. void __fastcall TLogViewer::CreateParams(TCreateParams &params)
  80. {
  81. // create window parameters
  82. inherited::CreateParams(params);
  83. params.Style |= WS_VSCROLL;
  84. }
  85. //---------------------------------------------------------------------------
  86. void __fastcall TLogViewer::Paint()
  87. {
  88. int start = Canvas->ClipRect.top / FLineHeight;
  89. int end = Canvas->ClipRect.bottom / FLineHeight;
  90. Brush->Style = bsSolid;
  91. Canvas->Brush->Color = clBlack;
  92. int sellim = FSelStart + FSelLength;
  93. for(int y = start; y <= end; y++)
  94. {
  95. int ys = y * FLineHeight;
  96. Canvas->Brush->Color = clBlack;
  97. Canvas->FillRect(TRect(0, ys, ClientWidth, ys + FLineHeight) );
  98. if((unsigned int)(FFirstLine + y) < FDisplayLineData.size())
  99. {
  100. const TDisplayLineData &data = FDisplayLineData[FFirstLine + y];
  101. Canvas->Brush->Color = clBlack;
  102. Canvas->Font->Color = clWhite;
  103. const tjs_char *data_start = FData.c_str() + data.Start;
  104. tjs_int data_len = data.Length;
  105. bool allocated = false;
  106. for(tjs_int i = 0; i < data_len; i++)
  107. {
  108. if(data_start[i] == TJS_W('\t'))
  109. {
  110. // includes tab
  111. const tjs_char *data_start_org = data_start;
  112. data_start = new tjs_char[data_len];
  113. allocated = true;
  114. memcpy(const_cast<tjs_char*>(data_start),
  115. data_start_org, sizeof(tjs_char)*data_len);
  116. for(; i < data_len; i++)
  117. {
  118. if(data_start[i] == TJS_W('\t'))
  119. const_cast<tjs_char*>(data_start)[i] = TJS_W(' ');
  120. }
  121. break;
  122. }
  123. }
  124. if(procTextOutW)
  125. {
  126. procTextOutW(Canvas->Handle, FMargin, ys + 1,
  127. data_start, data_len);
  128. }
  129. else
  130. {
  131. char *buf2 = new char[data_len * 3 + 1];
  132. const tjs_char *p = data_start;
  133. char *pp = buf2;
  134. for(int i = 0; i < data_len; i++)
  135. {
  136. TJS_wctomb(pp, 0);
  137. int narrowlen = TJS_wctomb(pp, p[i]);
  138. if(narrowlen != -1) pp += narrowlen;
  139. }
  140. *pp = 0;
  141. TextOut(Canvas->Handle, FMargin, ys + 1,
  142. buf2, pp - buf2);
  143. delete [] buf2;
  144. }
  145. if(allocated) delete [] data_start;
  146. if(FSelLength > 0)
  147. {
  148. int ss = data.Start < FSelStart ? FSelStart : data.Start;
  149. int dl = data.Start + data.Length;
  150. int se = dl < sellim ? dl : sellim;
  151. if(ss < se)
  152. {
  153. // invert selection
  154. RECT r;
  155. r.left = GetTextWidth(FData.c_str() + data.Start,
  156. ss - data.Start) + FMargin;
  157. r.right = GetTextWidth(FData.c_str() + data.Start,
  158. se - data.Start) + FMargin;
  159. r.top = ys;
  160. r.bottom = ys + FLineHeight;
  161. InvertRect(Canvas->Handle, &r);
  162. }
  163. }
  164. }
  165. }
  166. Brush->Style = bsClear;
  167. }
  168. //---------------------------------------------------------------------------
  169. void __fastcall TLogViewer::InvalidateRange(int start, int len)
  170. {
  171. if(len <= 0) return;
  172. int st = DataPosToLine(start) - FFirstLine;
  173. int ed = DataPosToLine(start + len) - FFirstLine;
  174. if(st < 0) st = 0;
  175. if(ed >= FViewLines) ed = FViewLines;
  176. if(ed >= st)
  177. {
  178. RECT r;
  179. r.left = 0;
  180. r.top = st * FLineHeight;
  181. r.right = ClientWidth;
  182. r.bottom = (ed+1) * FLineHeight;
  183. ::InvalidateRect(Handle, &r, FALSE);
  184. }
  185. }
  186. //---------------------------------------------------------------------------
  187. void __fastcall TLogViewer::CreateCharWidthMap()
  188. {
  189. // create table for character size
  190. if(CharWidthMap) return;
  191. CharWidthMap = new tjs_uint16[65536];
  192. CharWidthMap[0] = 0;
  193. for(tjs_int i = 1; i < 65536; i++) CharWidthMap[i] = 0xffff;
  194. }
  195. //---------------------------------------------------------------------------
  196. int __fastcall TLogViewer::GetTextWidth(const tjs_char *txt, int len)
  197. {
  198. CreateCharWidthMap();
  199. int w = 0;
  200. while(len--)
  201. {
  202. if(CharWidthMap[*txt] == 0xffff)
  203. {
  204. if(!procGetTextExtentPoint32W)
  205. {
  206. char narrow[10 + 1];
  207. TJS_wctomb(narrow, 0);
  208. tjs_char wc = *txt;
  209. if(wc == TJS_W('\t')) wc = TJS_W(' ');
  210. int narrowlen = TJS_wctomb(narrow, wc);
  211. if(narrowlen == -1)
  212. {
  213. CharWidthMap[*txt] = 0;
  214. }
  215. else
  216. {
  217. SIZE s;
  218. GetTextExtentPoint32A(Canvas->Handle, narrow, narrowlen, &s);
  219. CharWidthMap[*txt] = s.cx;
  220. }
  221. }
  222. else
  223. {
  224. tjs_char wc = *txt;
  225. if(wc == TJS_W('\t')) wc = TJS_W(' ');
  226. SIZE s;
  227. procGetTextExtentPoint32W(Canvas->Handle, &wc, 1, &s);
  228. CharWidthMap[*txt] = s.cx;
  229. }
  230. }
  231. w += CharWidthMap[*txt];
  232. txt++;
  233. }
  234. return w;
  235. }
  236. //---------------------------------------------------------------------------
  237. void __fastcall TLogViewer::InternalLayout(int start)
  238. {
  239. int line = start ? DataPosToLine(start) : 0;
  240. int clientsize = ClientWidth - FMargin * 2;
  241. const tjs_char *p = FData.c_str();
  242. if(!p) return;
  243. const tjs_char *org_p = p;
  244. if(line > 0) p += FDisplayLineData[line].Start;
  245. FDisplayLineData.resize(line);
  246. const tjs_char *p_start = p;
  247. while(*p)
  248. {
  249. int w = 0;
  250. while(*p)
  251. {
  252. if(*p == '\n' || *p == '\r')
  253. {
  254. FDisplayLineData.push_back(
  255. TDisplayLineData(p_start - org_p, p - p_start));
  256. if(*p == '\r')
  257. {
  258. p++;
  259. if(*p == '\n') p++;
  260. }
  261. else
  262. {
  263. p++;
  264. }
  265. p_start = p;
  266. break;
  267. }
  268. w += GetTextWidth(p, 1);
  269. if(w >= clientsize)
  270. {
  271. if(p == p_start) p++;
  272. FDisplayLineData.push_back(
  273. TDisplayLineData(p_start - org_p, p - p_start));
  274. p_start = p;
  275. break;
  276. }
  277. p++;
  278. }
  279. }
  280. if(p - p_start)
  281. {
  282. FDisplayLineData.push_back(
  283. TDisplayLineData(p_start - org_p, p - p_start));
  284. }
  285. }
  286. //---------------------------------------------------------------------------
  287. void __fastcall TLogViewer::RedoLayout()
  288. {
  289. // layout all lines
  290. InternalLayout(0);
  291. }
  292. //---------------------------------------------------------------------------
  293. void __fastcall TLogViewer::SetFont(TFont * font)
  294. {
  295. Canvas->Font->Assign(font);
  296. delete [] CharWidthMap;
  297. CharWidthMap = NULL;
  298. Resize();
  299. }
  300. //---------------------------------------------------------------------------
  301. void __fastcall TLogViewer::SetText(const ttstr & str)
  302. {
  303. // set text
  304. bool showinglast = IsShowingLast();
  305. FData = str;
  306. FDataLength = str.GetLen();
  307. RedoLayout();
  308. SetScrollRange();
  309. if(showinglast) ShowLast();
  310. Invalidate();
  311. }
  312. //---------------------------------------------------------------------------
  313. void __fastcall TLogViewer::Append(const ttstr & str, bool appendcr)
  314. {
  315. // append to log
  316. bool showinglast = IsShowingLast();
  317. int last = FDataLength;
  318. int strlen = str.GetLen();
  319. if(appendcr) strlen++;
  320. FData += str;
  321. if(appendcr) FData += TJS_W('\n');
  322. FDataLength += strlen;
  323. InternalLayout(last);
  324. SetScrollRange();
  325. if(showinglast) ShowLast();
  326. InvalidateRange(last, strlen);
  327. }
  328. //---------------------------------------------------------------------------
  329. void __fastcall TLogViewer::Trim(int maxlen, int trimlen)
  330. {
  331. if(FDataLength < maxlen) return;
  332. if(FDataLength < trimlen) return;
  333. int surplus = FDataLength - trimlen;
  334. int tofirstline = DataPosToLine(surplus);
  335. if(tofirstline == 0) return;
  336. int ofs = FDisplayLineData[tofirstline].Start;
  337. int lim = FDisplayLineData.size() - tofirstline;
  338. for(int i = 0; i < lim; i++)
  339. {
  340. FDisplayLineData[i] = FDisplayLineData[i + tofirstline];
  341. FDisplayLineData[i].Start -= ofs;
  342. }
  343. FDisplayLineData.resize(lim);
  344. FData = ttstr(FData.c_str() + ofs);
  345. FDataLength -= ofs;
  346. FSelStart -= ofs;
  347. if(FSelStart < 0)
  348. {
  349. FSelLength += FSelStart;
  350. FSelStart = 0;
  351. if(FSelLength < 0) FSelLength = 0;
  352. }
  353. FLastClickedDataPos -= ofs;
  354. if(FLastClickedDataPos < 0) FLastClickedDataPos = 0;
  355. FLastDblClickedLineStart -= ofs;
  356. if(FLastDblClickedLineStart < 0)
  357. {
  358. FLastDblClickedLineLength += FLastDblClickedLineStart;
  359. FLastDblClickedLineStart = 0;
  360. if(FLastDblClickedLineLength < 0) FLastDblClickedLineLength = 0;
  361. }
  362. ScrollBy(-tofirstline);
  363. SetScrollRange();
  364. Invalidate();
  365. }
  366. //---------------------------------------------------------------------------
  367. int __fastcall TLogViewer::ClickPosToDataPos(int x, int y)
  368. {
  369. // compute data pos from clicked client position
  370. y /= FLineHeight;
  371. y += FFirstLine;
  372. x -= FMargin;
  373. if(y < 0) return 0;
  374. if((unsigned int)y >= FDisplayLineData.size()) return FDataLength;
  375. const TDisplayLineData &data = FDisplayLineData[y];
  376. const tjs_char * str = FData.c_str() + data.Start;
  377. int w = 0;
  378. int i;
  379. for(i = 0; i < data.Length; i++)
  380. {
  381. int cw = GetTextWidth(str + i, 1);
  382. w += cw;
  383. if(w > x)
  384. {
  385. w -= cw;
  386. if(x - w > (cw>>1)) i++;
  387. break;
  388. }
  389. }
  390. int result = i + data.Start;
  391. if(result < 0) result = 0;
  392. if(result > FDataLength) result = FDataLength;
  393. return result;
  394. }
  395. //---------------------------------------------------------------------------
  396. int __fastcall TLogViewer::DataPosToLine(int pos)
  397. {
  398. // convert data position to display line number
  399. int linecount = FDisplayLineData.size();
  400. if(!linecount) return 0;
  401. if(pos < 0) pos = 0;
  402. if(pos >= FDataLength) return linecount - 1;
  403. // do binary search
  404. int s = 0, e = linecount;
  405. while(true)
  406. {
  407. if(s == e) return s;
  408. int m = (s + e) /2;
  409. const TDisplayLineData &mdata = FDisplayLineData[m];
  410. int lim;
  411. if(m == linecount - 1)
  412. lim = FDataLength;
  413. else
  414. lim = FDisplayLineData[m+1].Start;
  415. if(pos >= mdata.Start && pos < lim) return m;
  416. if(mdata.Start < pos)
  417. s = m;
  418. else
  419. e = m;
  420. }
  421. }
  422. //---------------------------------------------------------------------------
  423. void __fastcall TLogViewer::DataPosToLogicalLine(int pos, int &start, int &len)
  424. {
  425. // convert data position to logical line
  426. // search backward
  427. const tjs_char * data = FData.c_str();
  428. int p = pos;
  429. p--;
  430. while(p >= 0)
  431. {
  432. if(data[p] == '\n') break;
  433. p--;
  434. }
  435. p++;
  436. start = p;
  437. // search forward
  438. p = pos;
  439. while(p < FDataLength)
  440. {
  441. if(data[p] == '\n') break;
  442. p++;
  443. }
  444. if(p < FDataLength && data[p] == '\n') p++;
  445. len = p - start;
  446. }
  447. //---------------------------------------------------------------------------
  448. void __fastcall TLogViewer::SetSelection(int start, int len)
  449. {
  450. if(FSelLength > 0)
  451. {
  452. if(len > 0)
  453. {
  454. int s, e;
  455. if(FSelStart > start)
  456. s = start, e = FSelStart;
  457. else
  458. s = FSelStart, e = start;
  459. InvalidateRange(s, e - s);
  460. if(FSelStart + FSelLength > start + len)
  461. s = start + len, e = FSelStart + FSelLength;
  462. else
  463. s = FSelStart + FSelLength, e = start + len;
  464. InvalidateRange(s, e - s);
  465. }
  466. else
  467. {
  468. InvalidateRange(FSelStart, FSelLength);
  469. }
  470. }
  471. else
  472. {
  473. if(len > 0)
  474. {
  475. InvalidateRange(start, len);
  476. }
  477. }
  478. FSelStart = start;
  479. FSelLength = len;
  480. }
  481. //---------------------------------------------------------------------------
  482. void __fastcall TLogViewer::StartSelect()
  483. {
  484. TPoint pt = GetMousePos();
  485. FLastClickedDataPos = ClickPosToDataPos(pt.x, pt.y);
  486. }
  487. //---------------------------------------------------------------------------
  488. void __fastcall TLogViewer::UpdateMouseSelect()
  489. {
  490. TPoint pt = GetMousePos();
  491. int s, e;
  492. int pos = ClickPosToDataPos(pt.x, pt.y);
  493. if(FDoubleClickSelecting)
  494. {
  495. int st, len;
  496. DataPosToLogicalLine(pos, st, len);
  497. if(st < FLastDblClickedLineStart)
  498. s = st, e = FLastDblClickedLineStart + FLastDblClickedLineLength;
  499. else
  500. s = FLastDblClickedLineStart, e = st + len;
  501. }
  502. else
  503. {
  504. if(pos < FLastClickedDataPos)
  505. s = pos, e = FLastClickedDataPos;
  506. else
  507. s = FLastClickedDataPos, e = pos;
  508. }
  509. SetSelection(s, e - s);
  510. }
  511. //---------------------------------------------------------------------------
  512. void __fastcall TLogViewer::SelectAll()
  513. {
  514. SetSelection(0, FDataLength);
  515. }
  516. //---------------------------------------------------------------------------
  517. void __fastcall TLogViewer::CopyToClipboard()
  518. {
  519. TVPCopyToClipboard(ttstr(FData.c_str() + FSelStart, FSelLength));
  520. }
  521. //---------------------------------------------------------------------------
  522. void __fastcall TLogViewer::DblClick()
  523. {
  524. TPoint pt = GetMousePos();
  525. int pos = ClickPosToDataPos(pt.x, pt.y);
  526. int start, len;
  527. DataPosToLogicalLine(pos, start, len);
  528. SetSelection(start, len);
  529. FLastDblClickedLineStart = start;
  530. FLastDblClickedLineLength = len;
  531. FDoubleClickSelecting = true;
  532. inherited::DblClick();
  533. }
  534. //---------------------------------------------------------------------------
  535. void __fastcall TLogViewer::MouseDown(TMouseButton button, TShiftState shift,
  536. int x, int y)
  537. {
  538. if(button == mbLeft)
  539. {
  540. if(shift.Contains(ssShift))
  541. {
  542. UpdateMouseSelect();
  543. }
  544. else
  545. {
  546. StartScrollTimer();
  547. StartSelect();
  548. FMouseSelecting = true;
  549. }
  550. }
  551. inherited::MouseDown(button, shift, x, y);
  552. }
  553. //---------------------------------------------------------------------------
  554. void __fastcall TLogViewer::MouseUp(TMouseButton button, TShiftState shift,
  555. int x, int y)
  556. {
  557. if(button == mbLeft)
  558. {
  559. if(FMouseSelecting && !FDoubleClickSelecting) UpdateMouseSelect();
  560. FMouseSelecting = false;
  561. FDoubleClickSelecting = false;
  562. EndScrollTimer();
  563. }
  564. inherited::MouseUp(button, shift, x, y);
  565. }
  566. //---------------------------------------------------------------------------
  567. void __fastcall TLogViewer::MouseMove(TShiftState shift, int x, int y)
  568. {
  569. if(FMouseSelecting)
  570. {
  571. UpdateMouseSelect();
  572. ScrollTimerHandler(this);
  573. }
  574. inherited::MouseMove(shift, x, y);
  575. }
  576. //---------------------------------------------------------------------------
  577. TPoint __fastcall TLogViewer::GetMousePos()
  578. {
  579. POINT p;
  580. ::GetCursorPos(&p);
  581. return ScreenToClient(TPoint(p));
  582. }
  583. //---------------------------------------------------------------------------
  584. void __fastcall TLogViewer::Resize(void)
  585. {
  586. bool showinglast = IsShowingLast();
  587. RecalcMetrics();
  588. RedoLayout();
  589. SetScrollRange();
  590. if(showinglast) ShowLast();
  591. inherited::Resize();
  592. }
  593. //---------------------------------------------------------------------------
  594. void __fastcall TLogViewer::RecalcMetrics()
  595. {
  596. FLineHeight = Canvas->TextHeight("|") + 2;
  597. FViewLines = Height / FLineHeight;
  598. if(FViewLines * FLineHeight < Height) FViewLines ++;
  599. }
  600. //---------------------------------------------------------------------------
  601. void __fastcall TLogViewer::WMVScroll(TWMVScroll &msg)
  602. {
  603. SCROLLINFO si;
  604. ZeroMemory(&si, sizeof(si));
  605. si.cbSize = sizeof(si);
  606. si.fMask = SIF_ALL;
  607. GetScrollInfo(Handle, SB_VERT, &si);
  608. if(msg.ScrollCode == SB_THUMBTRACK)
  609. {
  610. si.nPos = si.nTrackPos;
  611. }
  612. else if(msg.ScrollCode == SB_LINELEFT)
  613. {
  614. si.nPos --;
  615. if(si.nPos<0) si.nPos=0;
  616. }
  617. else if(msg.ScrollCode == SB_LINERIGHT)
  618. {
  619. si.nPos ++;
  620. if(si.nPos >= si.nMax) si.nPos = si.nMax - 1;
  621. }
  622. else if(msg.ScrollCode == SB_PAGELEFT)
  623. {
  624. si.nPos = si.nPos - si.nPage;
  625. if(si.nPos<0) si.nPos=0;
  626. }
  627. else if(msg.ScrollCode == SB_PAGERIGHT)
  628. {
  629. si.nPos = si.nPos + si.nPage;
  630. if(si.nPos >=si.nMax) si.nPos = si.nMax - 1;
  631. }
  632. ScrollTo(si.nPos);
  633. }
  634. //---------------------------------------------------------------------------
  635. void __fastcall TLogViewer::ScrollTo(int pos)
  636. {
  637. int org = FFirstLine;
  638. SCROLLINFO si;
  639. ZeroMemory(&si, sizeof(si));
  640. si.cbSize = sizeof(si);
  641. si.nPos = pos;
  642. si.fMask = SIF_POS;
  643. SetScrollInfo(Handle, SB_VERT, &si, true);
  644. ZeroMemory(&si, sizeof(si));
  645. si.cbSize = sizeof(si);
  646. si.fMask = SIF_POS;
  647. GetScrollInfo(Handle, SB_VERT, &si);
  648. FFirstLine = si.nPos;
  649. RECT r;
  650. r.left = 0;
  651. r.top = 0;
  652. r.right = ClientWidth;
  653. r.bottom = ClientHeight;
  654. ScrollWindowEx(Handle, 0, (org -si.nPos) * FLineHeight,
  655. &r, NULL, NULL, NULL, SW_INVALIDATE);
  656. }
  657. //---------------------------------------------------------------------------
  658. void __fastcall TLogViewer::ScrollBy(int lines)
  659. {
  660. ScrollTo(FFirstLine + lines);
  661. }
  662. //---------------------------------------------------------------------------
  663. void __fastcall TLogViewer::SetScrollRange()
  664. {
  665. // set scroll range
  666. // enable scroll bar and set scroll range
  667. SCROLLINFO si;
  668. si.cbSize = sizeof(si);
  669. si.fMask = SIF_PAGE | SIF_RANGE | SIF_DISABLENOSCROLL;
  670. si.nMin = 0;
  671. si.nMax = FDisplayLineData.size() + 1;
  672. si.nPage = FViewLines;
  673. si.nPos = 0;
  674. SetScrollInfo(Handle, SB_VERT, &si, TRUE);
  675. ZeroMemory(&si, sizeof(si));
  676. si.cbSize = sizeof(si);
  677. si.fMask = SIF_POS;
  678. GetScrollInfo(Handle, SB_VERT, &si);
  679. FFirstLine = si.nPos;
  680. }
  681. //---------------------------------------------------------------------------
  682. bool __fastcall TLogViewer::IsShowingLast()
  683. {
  684. if(FDisplayLineData.size() <= (unsigned int)FViewLines) return true;
  685. SCROLLINFO si;
  686. ZeroMemory(&si, sizeof(si));
  687. si.cbSize = sizeof(si);
  688. si.fMask = SIF_ALL;
  689. GetScrollInfo(Handle, SB_VERT, &si);
  690. return (unsigned int)si.nPos >= (si.nMax - si.nPage - 1);
  691. }
  692. //---------------------------------------------------------------------------
  693. void __fastcall TLogViewer::ShowLast()
  694. {
  695. SCROLLINFO si;
  696. ZeroMemory(&si, sizeof(si));
  697. si.cbSize = sizeof(si);
  698. si.fMask = SIF_ALL;
  699. GetScrollInfo(Handle, SB_VERT, &si);
  700. ScrollTo(si.nMax - 1);
  701. }
  702. //---------------------------------------------------------------------------
  703. void __fastcall TLogViewer::StartScrollTimer()
  704. {
  705. if(!ScrollTimer)
  706. {
  707. ScrollTimer = new TTimer(this);
  708. ScrollTimer->OnTimer = ScrollTimerHandler;
  709. ScrollTimer->Interval = 100;
  710. ScrollTimer->Enabled = true;
  711. }
  712. }
  713. //---------------------------------------------------------------------------
  714. void __fastcall TLogViewer::EndScrollTimer()
  715. {
  716. if(ScrollTimer) delete ScrollTimer, ScrollTimer = NULL;
  717. }
  718. //---------------------------------------------------------------------------
  719. void __fastcall TLogViewer::ScrollTimerHandler(TObject *Sender)
  720. {
  721. POINT p;
  722. ::GetCursorPos(&p);
  723. TPoint pt;
  724. pt.x = 0;
  725. pt.y = 0;
  726. pt = ClientToScreen(pt);
  727. int m = 0;
  728. if(p.y < pt.y)
  729. {
  730. m = (pt.y - p.y) / FLineHeight;
  731. m++;
  732. if(m > 10) m = 10;
  733. m = -m;
  734. }
  735. else if(p.y > pt.y + ClientHeight)
  736. {
  737. m = (p.y - (pt.y + ClientHeight)) / FLineHeight;
  738. m++;
  739. if(m > 10) m = 10;
  740. }
  741. if(m)
  742. {
  743. ScrollBy(m);
  744. UpdateMouseSelect();
  745. }
  746. }
  747. //---------------------------------------------------------------------------
  748. #pragma package(smart_init)