PageRenderTime 48ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 1ms

/CS/migrated/branches/R0_94/libs/csws/csgrid.cpp

#
C++ | 1035 lines | 864 code | 87 blank | 84 comment | 182 complexity | fa8afa089962dadb826aed716d056d4b MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, LGPL-2.0
  1. /*
  2. Crystal Space Windowing System : grid class
  3. Copyright (C) 2000 by Norman Kramer <normank@lycosmail.com>
  4. This library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Library General Public
  6. License as published by the Free Software Foundation; either
  7. version 2 of the License, or (at your option) any later version.
  8. This library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Library General Public License for more details.
  12. You should have received a copy of the GNU Library General Public
  13. License along with this library; if not, write to the Free
  14. Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. */
  16. #include "cssysdef.h"
  17. #include "csws/csapp.h"
  18. #include "csws/cswindow.h"
  19. #include "csws/csgrid.h"
  20. #include "csws/cssplit.h"
  21. // The minimal width of the new grid view when we split a view horiz. or vert.
  22. #define MIN_GRIDVIEW_SIZE 8
  23. #define GRIDVIEW_BORDER_SIZE 2
  24. /******************************************************************************
  25. * csRegionTree2D
  26. ******************************************************************************/
  27. csRegionTree2D::csRegionTree2D ()
  28. {
  29. region.MakeEmpty ();
  30. data = NULL;
  31. memset (children, 0, 5 * sizeof (csRegionTree2D *));
  32. }
  33. csRegionTree2D::csRegionTree2D (csRect area, csSome data)
  34. {
  35. region.Set (area);
  36. csRegionTree2D::data = data;
  37. memset (children, 0, 5 * sizeof (csRegionTree2D *));
  38. }
  39. csRegionTree2D::~csRegionTree2D ()
  40. {
  41. int i = 0;
  42. while (i < 5 && children [i])
  43. delete children [i++];
  44. }
  45. /**
  46. * Tiles this rect into the tree and creates new children if needed.
  47. */
  48. void csRegionTree2D::Insert (csRect &area, csSome data)
  49. {
  50. if (children [0])
  51. {
  52. int i = 0;
  53. while (i < 5 && children [i])
  54. {
  55. csRect common (area);
  56. common.Intersect (children [i]->region);
  57. if (!common.IsEmpty ())
  58. children [i]->Insert (common, data);
  59. i++;
  60. }
  61. }
  62. else
  63. {
  64. // leaf
  65. if (region.Intersects (area))
  66. {
  67. // maybe this regions equals the area,
  68. // then we simply replace the data and are done
  69. if (region.Equal (area.xmin, area.ymin, area.xmax, area.ymax))
  70. this->data = data;
  71. else
  72. {
  73. int i = 0;
  74. // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  75. // DO NOT CHANGE THE SEQUENCE OF THE FOLLOWING, IT ENSURES FindRegion RETURNS AREAS ORDERED LEFT TO RIGHT
  76. // FOR SINGLE ROW REGIONS (likewise TOP TO DOWN)
  77. // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  78. // does an upper stripe exist ?
  79. if (region.ymin < area.ymin)
  80. {
  81. csRect rc (region); rc.ymax = area.ymin;
  82. children [i++] = new csRegionTree2D (rc, this->data);
  83. }
  84. // does a left stripe exist ?
  85. if (region.xmin < area.xmin)
  86. {
  87. csRect rc (region.xmin, area.ymin, area.xmin, area.ymax);
  88. children [i++] = new csRegionTree2D (rc, this->data);
  89. }
  90. // the region which fully covers area
  91. children [i++] = new csRegionTree2D (area, data);
  92. // does a right stripe exist ?
  93. if (region.xmax > area.xmax)
  94. {
  95. csRect rc (area.xmax, area.ymin, region.xmax, area.ymax);
  96. children [i++] = new csRegionTree2D (rc, this->data);
  97. }
  98. // does a lower stripe exist ?
  99. if (region.ymax > area.ymax)
  100. {
  101. csRect rc (region); rc.ymin = area.ymax;
  102. children [i++] = new csRegionTree2D (rc, this->data);
  103. }
  104. // now this leaf became a simple node
  105. }
  106. }
  107. }
  108. }
  109. /**
  110. * Returns a list of leaves that do all contain parts of area.
  111. */
  112. void csRegionTree2D::FindRegion (const csRect &area, csVector &vLeafList)
  113. {
  114. if (children [0])
  115. {
  116. int i = 0;
  117. while (i < 5 && children [i])
  118. children [i++]->FindRegion (area, vLeafList);
  119. }
  120. else if (region.Intersects (area))
  121. vLeafList.Push (this);
  122. }
  123. /**
  124. * Traverse the tree and call user supplied function for every node.
  125. */
  126. void csRegionTree2D::Traverse (csRegionTreeFunc userFunc, csSome databag)
  127. {
  128. if (userFunc (this, databag))
  129. {
  130. int i = 0;
  131. while (i < 5 && children [i])
  132. children [i++]->Traverse (userFunc, databag);
  133. }
  134. }
  135. /******************************************************************************
  136. * csSparseGrid::csGridRow
  137. ******************************************************************************/
  138. csSparseGrid::csGridRow::csGridRow (int theCol)
  139. {
  140. col = theCol;
  141. }
  142. csSparseGrid::csGridRow::~csGridRow ()
  143. {
  144. DeleteAll ();
  145. }
  146. void csSparseGrid::csGridRow::SetAt (int col, csSome data)
  147. {
  148. int key = FindSortedKey ((csConstSome)col);
  149. if (key == -1 && data)
  150. key = InsertSorted (new csGridRowEntry (col, data));
  151. else
  152. if (data)
  153. Get (key)->data = data;
  154. else
  155. Delete (key);
  156. }
  157. csSparseGrid::csGridRowEntry* csSparseGrid::csGridRow::Get (int index)
  158. {
  159. return (csSparseGrid::csGridRowEntry*)csVector::Get (index);
  160. }
  161. int csSparseGrid::csGridRow::Compare (csSome Item1, csSome Item2, int Mode) const
  162. {
  163. (void)Mode;
  164. csSparseGrid::csGridRowEntry *e1 = (csSparseGrid::csGridRowEntry*)Item1;
  165. csSparseGrid::csGridRowEntry *e2 = (csSparseGrid::csGridRowEntry*)Item2;
  166. return (e1->col < e2->col ? -1 : e1->col > e2->col ? 1 : 0);
  167. }
  168. int csSparseGrid::csGridRow::CompareKey (csSome Item1, csConstSome Key, int Mode) const
  169. {
  170. (void)Mode;
  171. csSparseGrid::csGridRowEntry *e1 = (csSparseGrid::csGridRowEntry*)Item1;
  172. return (e1->col < (int)Key ? -1 : e1->col > (int)Key ? 1 : 0);
  173. }
  174. bool csSparseGrid::csGridRow::FreeItem (csSome Item)
  175. {
  176. delete (csSparseGrid::csGridRowEntry*)Item;
  177. return true;
  178. }
  179. /******************************************************************************
  180. * csGridCell
  181. ******************************************************************************/
  182. csGridCell::csGridCell () : csComponent (NULL), inUse (false)
  183. {
  184. state |= CSS_SELECTABLE;
  185. valuePattern = "%s";
  186. SetPalette (CSPAL_GRIDCELL);
  187. }
  188. void csGridCell::DrawLine (int x1, int y1, int x2, int y2, csCellBorder& border)
  189. {
  190. bool sel = GetState (CSS_GRIDCELL_SELECTED) ? true : false;
  191. if (border.style == gcbsLine)
  192. Box (MIN (x1, x2), y1, MAX (x1, x2), y2,
  193. sel ? CSPAL_GRIDCELL_SEL_BORDER_FG : CSPAL_GRIDCELL_BORDER_FG);
  194. else if (border.style != gcbsNone)
  195. {
  196. int maxX, maxY, i = 0, nSegs, xcompo, ycompo;
  197. static const int linepattern [][13] =
  198. {
  199. { 2, 4, 0, 2, 0 }, // DASH
  200. { 4, 4, 0, 2, 0, 2, 0, 2, 0 }, // DASHPOINT
  201. { 6, 4, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0 }, // DASHPOINTPOINT
  202. { 6, 4, 0, 2, 0, 4, 0, 2, 0, 2, 0, 2, 0 } // DASHDASHPOINT
  203. };
  204. if (x1 <= x2)
  205. xcompo = 0, ycompo = 1;
  206. else
  207. xcompo = 1, ycompo = 0;
  208. maxX = MAX (x1, x2); maxY = MAX (y1, y2);
  209. x1 = MIN (x1, x2); x2 = MAX (x1, x2);
  210. // linesegments in linepattern
  211. nSegs = linepattern [int (border.style) - 1][0];
  212. int colFG = sel ? CSPAL_GRIDCELL_SEL_BORDER_FG : CSPAL_GRIDCELL_BORDER_FG;
  213. int colBG = sel ? CSPAL_GRIDCELL_SEL_BORDER_BG : CSPAL_GRIDCELL_BORDER_BG;
  214. while (x1 < maxX && y1 < maxY)
  215. {
  216. i = i % nSegs;
  217. x2 = x1 + linepattern [int (border.style) - 1][1 + 2 * i + xcompo];
  218. y2 = y1 + linepattern [int (border.style) - 1][1 + 2 * i + ycompo];
  219. Box (x1, y1, MIN (x2, maxX), MIN (y2, maxY),
  220. (i & 1 ? colBG : colFG));
  221. //printf("%d,%d -> %d,%d = %d\n", x1, y1, x2, y2,(i&1 ? 0 : 1));
  222. x1 = x2; y1 = y2;
  223. i++;
  224. }
  225. }
  226. }
  227. void csGridCell::Draw ()
  228. {
  229. int lx = 0, rx = 0, ty = 0, by = 0; // offsets if borders are drawn;
  230. bool sel = GetState (CSS_GRIDCELL_SELECTED) ? true : false;
  231. if (upper.style != gcbsNone)
  232. {
  233. ty = upper.thick;
  234. DrawLine (0, 0, bound.Width () -
  235. (right.style == gcbsNone ? 0 : right.thick), upper.thick, upper);
  236. }
  237. if (right.style != gcbsNone)
  238. {
  239. rx = right.thick;
  240. DrawLine (bound.Width (), 0, bound.Width () - right.thick,
  241. bound.Height () - (lower.style == gcbsNone ? 0 : lower.thick), right);
  242. }
  243. if (lower.style != gcbsNone)
  244. {
  245. by = lower.thick;
  246. DrawLine (0 + (left.style == gcbsNone ? 0 : left.thick),
  247. bound.Height () - lower.thick, bound.Width (), bound.Height (), lower);
  248. }
  249. if (left.style != gcbsNone)
  250. {
  251. lx = left.thick;
  252. DrawLine (left.thick, upper.style == gcbsNone ? 0 : upper.thick, 0,
  253. bound.Height (), left);
  254. }
  255. // fill the canvas with bgcolor
  256. bound.xmin += lx;
  257. bound.ymin += ty;
  258. bound.xmax -= rx;
  259. bound.ymax -= by;
  260. Box (0, 0, bound.Width (), bound.Height (),
  261. sel ? CSPAL_GRIDCELL_SEL_BACKGROUND: CSPAL_GRIDCELL_BACKGROUND);
  262. if (data)
  263. {
  264. const char *t = ((csString*)data)->GetData ();
  265. if (t)
  266. {
  267. int fh, fw = MIN (bound.Width (), GetTextSize (t, &fh));
  268. fh = MIN (bound.Height (), fh);
  269. int tx = (bound.Width () - fw) / 2;
  270. int ty = (bound.Height () - fh) / 2;
  271. Text (tx, ty, sel ? CSPAL_GRIDCELL_SEL_DATA_FG : CSPAL_GRIDCELL_DATA_FG,
  272. sel ? CSPAL_GRIDCELL_SEL_DATA_BG : CSPAL_GRIDCELL_DATA_BG, t);
  273. }
  274. }
  275. bound.xmin -= lx;
  276. bound.ymin -= ty;
  277. bound.xmax += rx;
  278. bound.ymax += by;
  279. }
  280. /******************************************************************************
  281. * csGridView
  282. ******************************************************************************/
  283. csGridView::csGridView (csGrid *pParent, const csRect& region, int iStyle)
  284. : csComponent (pParent)
  285. {
  286. pGrid = pParent;
  287. area.Set (region);
  288. Style = iStyle;
  289. if (Style & CSGVS_HSCROLL)
  290. hscroll = new csScrollBar (this, cssfsThinRect);
  291. else
  292. hscroll = NULL;
  293. if (Style & CSGVS_VSCROLL)
  294. vscroll = new csScrollBar (this, cssfsThinRect);
  295. else
  296. vscroll = NULL;
  297. SetPalette (CSPAL_GRIDVIEW);
  298. col = area.xmin;
  299. row = area.ymin;
  300. }
  301. csGridView::csGridView (const csGridView& view, int iStyle)
  302. : csComponent (view.pGrid)
  303. {
  304. pGrid = view.pGrid;
  305. area.Set (view.area);
  306. Style = ((iStyle != -1) ? iStyle : view.Style);
  307. if (Style & CSGVS_HSCROLL)
  308. hscroll = new csScrollBar (this, cssfsThinRect);
  309. else
  310. hscroll = NULL;
  311. if (Style & CSGVS_VSCROLL)
  312. vscroll = new csScrollBar (this, cssfsThinRect);
  313. else
  314. vscroll = NULL;
  315. SetPalette (view.palette, view.palettesize);
  316. row = view.row;
  317. col = view.col;
  318. }
  319. bool csGridView::SetRect (int xmin, int ymin, int xmax, int ymax)
  320. {
  321. if (csComponent::SetRect (xmin, ymin, xmax, ymax))
  322. {
  323. if (hscroll)
  324. hscroll->SetRect (0,
  325. bound.Height () - CSSB_DEFAULTSIZE,
  326. bound.Width () - (vscroll ? CSSB_DEFAULTSIZE : 0),
  327. bound.Height ());
  328. if (vscroll)
  329. vscroll->SetRect (bound.Width () - CSSB_DEFAULTSIZE,
  330. 0,
  331. bound.Width (),
  332. bound.Height () - (hscroll ? CSSB_DEFAULTSIZE : 0));
  333. fPlaceItems = true;
  334. return true;
  335. }
  336. return false;
  337. }
  338. void csGridView::PlaceItems ()
  339. {
  340. fPlaceItems = false;
  341. // count the number of cells visible in the first row
  342. // (exact would be the minimum of cells in a row in the visible area)
  343. csVector vRegionList;
  344. csRect rc;
  345. int i = 0, w1 = 0, w2 = 0;
  346. int nRowCells = 0, nColCells = 0;
  347. csRegionTree2D *r;
  348. if (hscroll)
  349. {
  350. rc.Set (col, row, area.xmax, row + 1);
  351. pGrid->regions->FindRegion (rc, vRegionList);
  352. while (i < vRegionList.Length() && w1 < bound.Width ())
  353. {
  354. r = (csRegionTree2D *)vRegionList.Get (i);
  355. w2 = (r->region.Width () - MAX (col - r->region.xmin, 0)) *
  356. ((csGridCell *)r->data)->bound.Width (); // #Cells * CellLength
  357. if (w1 + w2 < bound.Width ())
  358. {
  359. nRowCells += (r->region.Width () - MAX (col - r->region.xmin, 0));
  360. w1 += w2;
  361. }
  362. else
  363. {
  364. nRowCells += (bound.Width () - w1) /
  365. ((csGridCell *)r->data)->bound.Width ();
  366. w1 = bound.Width ();
  367. }
  368. i++;
  369. }
  370. csScrollBarStatus hsbstatus;
  371. hsbstatus.value = col - area.xmin;
  372. hsbstatus.step = 1;
  373. hsbstatus.maxsize = area.Width ();
  374. hsbstatus.maxvalue = hsbstatus.maxsize - nRowCells;
  375. hsbstatus.size =
  376. hsbstatus.pagestep = MAX (nRowCells, 1);
  377. hscroll->SendCommand (cscmdScrollBarSet, &hsbstatus);
  378. vRegionList.SetLength (0);
  379. i = 0; w1 = 0; w2 = 0;
  380. }
  381. if (vscroll)
  382. {
  383. // count numbers of cells in first column
  384. // (exact would be the minimum of cells in a column in the visible area)
  385. rc.Set (col, row, col + 1, area.ymax);
  386. pGrid->regions->FindRegion (rc, vRegionList);
  387. while (i < vRegionList.Length () && w1 < bound.Height ())
  388. {
  389. r = (csRegionTree2D*)vRegionList.Get (i);
  390. // #Cells * CellHeight
  391. w2 = (r->region.Height ()-MAX (row - r->region.ymin, 0)) *
  392. ((csGridCell *)r->data)->bound.Height ();
  393. if (w1 + w2 < bound.Height ())
  394. {
  395. nColCells += (r->region.Height () - MAX (row - r->region.ymin, 0));
  396. w1 += w2;
  397. }
  398. else
  399. {
  400. nColCells += (bound.Height () - w1) /
  401. ((csGridCell *)r->data)->bound.Height ();
  402. w1 = bound.Height ();
  403. }
  404. i++;
  405. }
  406. csScrollBarStatus vsbstatus;
  407. vsbstatus.value = row - area.ymin;
  408. vsbstatus.step = 1;
  409. vsbstatus.maxsize = area.Height ();
  410. vsbstatus.maxvalue = vsbstatus.maxsize - nColCells;
  411. vsbstatus.size =
  412. vsbstatus.pagestep = MAX (nColCells, 1);
  413. vscroll->SendCommand (cscmdScrollBarSet, &vsbstatus);
  414. }
  415. }
  416. static bool DrawCellComponents (csComponent *child, void *param)
  417. {
  418. (void)param;
  419. child->Draw ();
  420. return false;
  421. }
  422. void csGridView::CooAt (int theX, int theY, int &theRow, int &theCol)
  423. {
  424. int y = 0, x, n, c;
  425. int actRow = row;
  426. int actCol = col;
  427. csRect rc;
  428. csRegionTree2D *r;
  429. csVector vRegions;
  430. csGridCell *cell = NULL;
  431. theCol = area.xmin -1;
  432. theRow = area.ymin -1;
  433. rc.Set (actCol, actRow, actCol+1, area.ymax);
  434. vRegions.SetLength (0);
  435. pGrid->regions->FindRegion (rc, vRegions);
  436. n = 0;
  437. c = actRow;
  438. while (y < bound.Height () && y < theY && n < vRegions.Length ())
  439. {
  440. r = (csRegionTree2D*)vRegions.Get (n++);
  441. for (; c < r->region.ymax && c < area.ymax && y < theY; c++)
  442. {
  443. cell = (csGridCell *)r->data;
  444. y += cell->bound.Height ();
  445. actRow++;
  446. }
  447. }
  448. if (y >= theY)
  449. {
  450. actRow--;
  451. rc.Set (actCol, actRow, area.xmax, actRow+1);
  452. vRegions.SetLength (0);
  453. pGrid->regions->FindRegion (rc, vRegions);
  454. x = 0;
  455. n = 0;
  456. c = actCol;
  457. while (x < bound.Width () && x < theX && n < vRegions.Length ())
  458. {
  459. r = (csRegionTree2D*)vRegions.Get (n++);
  460. for (; c < r->region.xmax && x < theX && c < area.xmax; c++)
  461. {
  462. cell = (csGridCell *)r->data;
  463. x += cell->bound.Width ();
  464. actCol++;
  465. }
  466. }
  467. if (x>=theX)
  468. {
  469. actCol--;
  470. theRow = actRow;
  471. theCol = actCol;
  472. }
  473. }
  474. }
  475. void csGridView::Draw ()
  476. {
  477. if (fPlaceItems)
  478. PlaceItems ();
  479. int y = GRIDVIEW_BORDER_SIZE, x, n;
  480. int c, actRow = row;
  481. csRect rc;
  482. csRegionTree2D *r;
  483. csVector vRegions;
  484. csGridCell *cell = NULL;
  485. int cs = pGrid->GetCursorStyle ();
  486. int cr, cc;
  487. bool sel;
  488. pGrid->GetCursorPos (cr, cc);
  489. while (y < bound.Height ()-GRIDVIEW_BORDER_SIZE && actRow < area.ymax)
  490. {
  491. rc.Set (col, actRow, area.xmax, actRow + 1);
  492. vRegions.SetLength (0);
  493. pGrid->regions->FindRegion (rc, vRegions);
  494. if (vRegions.Length () == 0)
  495. break; // no more rows to draw
  496. x = GRIDVIEW_BORDER_SIZE; n = 0; c = col;
  497. while (x < bound.Width ()-GRIDVIEW_BORDER_SIZE && n < vRegions.Length () && c < area.xmax)
  498. {
  499. r = (csRegionTree2D*)vRegions.Get (n++);
  500. cell = (csGridCell *)r->data;
  501. Insert (cell); cell->Show (false); // show but don't focus
  502. for (; c < r->region.xmax && x < bound.Width () && c < area.xmax; c++)
  503. {
  504. cell->SetPos (x, y);
  505. cell->row = actRow;
  506. cell->col = c;
  507. cell->data = pGrid->grid->GetAt (actRow, c);
  508. // if a grid cursor is to be shown, then
  509. // we will toggle the selected state of the component
  510. sel = (cs == CSGCS_CELL && c == cc && actRow == cr) ||
  511. (cs == CSGCS_ROW && actRow == cr) ||
  512. (cs == CSGCS_COLUMN && c == cc);
  513. cell->SetState (CSS_GRIDCELL_SELECTED, sel);
  514. cell->Draw ();
  515. cell->ForEach (DrawCellComponents, NULL, true);
  516. x += cell->bound.Width ();
  517. }
  518. Delete (cell);
  519. }
  520. y += cell->bound.Height ();
  521. actRow++;
  522. }
  523. csComponent::Draw ();
  524. sel = pGrid->GetActiveView () == this;
  525. Box (0, 0, bound.Width (), GRIDVIEW_BORDER_SIZE,
  526. sel ? CSPAL_GRIDVIEW_SEL_DARK3D : CSPAL_GRIDVIEW_DARK3D);
  527. Box (0, bound.Height ()- GRIDVIEW_BORDER_SIZE, bound.Width (), bound.Height (),
  528. sel ? CSPAL_GRIDVIEW_SEL_DARK3D : CSPAL_GRIDVIEW_DARK3D);
  529. Box (0, 0, GRIDVIEW_BORDER_SIZE, bound.Height (),
  530. sel ? CSPAL_GRIDVIEW_SEL_DARK3D : CSPAL_GRIDVIEW_DARK3D);
  531. Box (bound.Width () - GRIDVIEW_BORDER_SIZE, 0, bound.Width (), bound.Height (),
  532. sel ? CSPAL_GRIDVIEW_SEL_DARK3D : CSPAL_GRIDVIEW_DARK3D);
  533. // fill the remainingspace with backcolor
  534. // Box (0, y, bound.Width (), bound.Height (), CSPAL_GRIDVIEW_BACKGROUND);
  535. }
  536. bool csGridView::HandleEvent (iEvent& Event)
  537. {
  538. switch (Event.Type)
  539. {
  540. case csevCommand:
  541. switch (Event.Command.Code)
  542. {
  543. case cscmdReceiveFocus:
  544. case cscmdLoseFocus:
  545. Invalidate (true);
  546. break;
  547. case cscmdScrollBarValueChanged:
  548. {
  549. csScrollBar *bar = (csScrollBar*)Event.Command.Info;
  550. csScrollBarStatus sbs;
  551. if (!bar || bar->SendCommand (cscmdScrollBarGetStatus, &sbs))
  552. return true;
  553. if (sbs.maxvalue <= 0)
  554. return true;
  555. if (bar == hscroll)
  556. {
  557. if (col-area.xmin != sbs.value)
  558. {
  559. col = area.xmin + sbs.value;
  560. PlaceItems ();
  561. Invalidate (true);
  562. }
  563. }
  564. else if (bar == vscroll)
  565. {
  566. if (row-area.ymin != sbs.value)
  567. {
  568. row = area.ymin + sbs.value;
  569. PlaceItems ();
  570. Invalidate (true);
  571. }
  572. }
  573. return true;
  574. }
  575. }
  576. break;
  577. case csevMouseClick:
  578. if (Event.Mouse.Button == 1)
  579. {
  580. bool succ = csComponent::HandleEvent (Event);
  581. if (!succ) // if no scrollbar handle was pressed
  582. {
  583. pGrid->SetActiveView (this);
  584. if (pGrid->GetCursorStyle () != CSGCS_NONE)
  585. {
  586. int atrow, atcol;
  587. CooAt (Event.Mouse.x, Event.Mouse.y, atrow, atcol);
  588. pGrid->SetCursorPos (atrow, atcol);
  589. }
  590. return true;
  591. }
  592. return succ;
  593. }
  594. break;
  595. }
  596. return csComponent::HandleEvent (Event);
  597. }
  598. void csGridView::FixSize (int &newW, int &newH)
  599. {
  600. if (hscroll && newH < hscroll->bound.Height ())
  601. newH = hscroll->bound.Height ();
  602. if (vscroll && newW < vscroll->bound.Width ())
  603. newW = vscroll->bound.Width ();
  604. }
  605. void csGridView::SuggestSize (int &w, int &h)
  606. {
  607. w = h = 0;
  608. if (hscroll) { h += CSSB_DEFAULTSIZE; }
  609. if (vscroll) { w += CSSB_DEFAULTSIZE; }
  610. }
  611. csGridView *csGridView::CreateCopy (int iStyle)
  612. {
  613. return new csGridView (*this, iStyle);
  614. }
  615. csGridView *csGridView::SplitX (int x, int iStyle)
  616. {
  617. csGridView *sp = NULL;
  618. if (x > MIN_GRIDVIEW_SIZE && x < bound.Width () - MIN_GRIDVIEW_SIZE)
  619. {
  620. sp = CreateCopy (iStyle);
  621. if (sp)
  622. {
  623. sp->areafactor = (float)x / (float)bound.Width ();
  624. pGrid->vViews.Push (sp);
  625. sp->SetRect (bound.xmin, bound.ymin, bound.xmin + x, bound.ymax);
  626. SetRect (bound.xmin + x, bound.ymin, bound.xmax, bound.ymax);
  627. pGrid->viewlayout->Insert (sp->bound, sp);
  628. }
  629. }
  630. return sp;
  631. }
  632. csGridView *csGridView::SplitY (int y, int iStyle)
  633. {
  634. csGridView *sp = NULL;
  635. if (y > MIN_GRIDVIEW_SIZE && y < bound.Height () - MIN_GRIDVIEW_SIZE)
  636. {
  637. sp = CreateCopy (iStyle);
  638. if (sp)
  639. {
  640. sp->areafactor = (float)y / (float)bound.Height ();
  641. pGrid->vViews.Push (sp);
  642. sp->SetRect (bound.xmin, bound.ymin, bound.xmax, bound.ymin + y);
  643. SetRect (bound.xmin, bound.ymin+y, bound.xmax, bound.ymax);
  644. pGrid->viewlayout->Insert (sp->bound, sp);
  645. }
  646. }
  647. return sp;
  648. }
  649. /******************************************************************************
  650. * csGrid
  651. ******************************************************************************/
  652. csGrid::csGrid (csComponent *pParent, int nRows, int nCols, int iStyle)
  653. : csComponent (pParent)
  654. {
  655. csRect rc (0, 0, nCols, nRows);
  656. csGridCell *gc = new csGridCell;
  657. gc->SetRect (0, 0, 50, 30);
  658. init (pParent, rc, iStyle, gc);
  659. }
  660. csGrid::csGrid (csComponent *pParent, int nRows, int nCols,
  661. csGridCell *gridpattern, int iStyle) : csComponent (pParent)
  662. {
  663. csRect rc (0, 0, nCols, nRows);
  664. init (pParent, rc, iStyle, gridpattern);
  665. }
  666. void csGrid::init (csComponent *pParent, csRect &rc, int iStyle, csGridCell *gc)
  667. {
  668. grid = new csSparseGrid;
  669. SetCursorStyle (CSGCS_NONE);
  670. SetCursorPos (0, 0);
  671. SetPalette (CSPAL_GRIDVIEW);
  672. SetState (CSS_SELECTABLE, true);
  673. vRegionStyles.Push (gc);
  674. vViews.Push (new csGridView (this, rc, (iStyle & ~(CSGS_HSPLIT|CSGS_VSPLIT))));
  675. regions = new csRegionTree2D (rc, vRegionStyles.Get (0) );
  676. // rc below is a dummy and will be recalculated when SetRect is called
  677. viewlayout = new csRegionTree2D (rc, vViews.Get (0) );
  678. splitterX = splitterY = NULL;
  679. if (iStyle & CSGS_HSPLIT)
  680. splitterX = new csSplitter (this);
  681. if (iStyle & CSGS_VSPLIT)
  682. splitterY = new csSplitter (this);
  683. if (pParent)
  684. pParent->SendCommand (cscmdWindowSetClient, (void *)this);
  685. SetActiveView (GetRootView ());
  686. }
  687. csGrid::~csGrid ()
  688. {
  689. int i, j;
  690. for (i = 0; i < grid->rows.Length (); i++)
  691. {
  692. csSparseGrid::csGridRow *r = (csSparseGrid::csGridRow*)grid->rows.Get(i)->data;
  693. for (j = 0; j < r->Length (); j++)
  694. {
  695. csString *str = (csString*)r->Get (j)->data;
  696. if (str) delete str;
  697. }
  698. delete r;
  699. }
  700. delete grid;
  701. delete regions;
  702. for (i = 0; i < vRegionStyles.Length (); i++)
  703. delete (csGridCell *)vRegionStyles.Get (i);
  704. //for (i=0; i<vViews.Length (); i++) delete (csGridView*)vViews.Get (i);
  705. }
  706. void csGrid::Draw ()
  707. {
  708. Box (0, 0, bound.Width (), bound.Height (), CSPAL_GRIDVIEW_BACKGROUND);
  709. csComponent::Draw ();
  710. // views are children, so they are drawn later
  711. }
  712. bool csGrid::HandleEvent (iEvent &Event)
  713. {
  714. switch (Event.Type)
  715. {
  716. case csevCommand:
  717. switch (Event.Command.Code)
  718. {
  719. case cscmdSplitterPosSet:
  720. {
  721. csSplitter *sl = (csSplitter *)Event.Command.Info;
  722. // find the view containing the mouse pointer
  723. int x, y;
  724. sl->GetPos (x, y);
  725. csRect rc (x, y, x + 1, y + 1);
  726. csVector vSpl;
  727. viewlayout->FindRegion (rc, vSpl);
  728. if (vSpl.Length () == 1)
  729. {
  730. csGridView *spl = (csGridView*)((csRegionTree2D*)vSpl.Get (0))->data;
  731. if (sl == splitterX)
  732. spl->SplitX (x - spl->bound.xmin);
  733. else
  734. spl->SplitY (y - spl->bound.ymin);
  735. }
  736. // Place the splitters back
  737. PlaceGadgets ();
  738. return true;
  739. }
  740. break;
  741. }
  742. break;
  743. case csevKeyDown:
  744. switch (Event.Key.Code)
  745. {
  746. case CSKEY_DOWN:
  747. if (GetCursorStyle () != CSGCS_NONE)
  748. {
  749. const csRect &rc = GetRootView ()->GetArea ();
  750. if (ycur < rc.ymax)
  751. SetCursorPos (ycur+1, xcur);
  752. return true;
  753. }
  754. break;
  755. case CSKEY_UP:
  756. if (GetCursorStyle () != CSGCS_NONE)
  757. {
  758. const csRect &rc = GetRootView ()->GetArea ();
  759. if (ycur > rc.ymin)
  760. SetCursorPos (ycur-1, xcur);
  761. return true;
  762. }
  763. break;
  764. case CSKEY_LEFT:
  765. if (GetCursorStyle () != CSGCS_NONE)
  766. {
  767. const csRect &rc = GetRootView ()->GetArea ();
  768. if (xcur > rc.xmin)
  769. SetCursorPos (ycur, xcur-1);
  770. return true;
  771. }
  772. break;
  773. case CSKEY_RIGHT:
  774. if (GetCursorStyle () != CSGCS_NONE)
  775. {
  776. const csRect &rc = GetRootView ()->GetArea ();
  777. if (xcur < rc.xmax)
  778. SetCursorPos (ycur, xcur+1);
  779. return true;
  780. }
  781. break;
  782. }
  783. }
  784. return csComponent::HandleEvent (Event);
  785. }
  786. /**
  787. * Resize views proportional to the new size of csGrid.
  788. * @@@ TODO: TAKE MINIMUM SIZE INTO ACCOUNT
  789. */
  790. static bool ResizeViews (csSome node, csSome /*databag*/)
  791. {
  792. csRegionTree2D *t = (csRegionTree2D*)node;
  793. if (t->children[0] == NULL)
  794. {
  795. // leaf - we find the new size in the region variable
  796. ((csGridView*)t->data)->SetRect (t->region.xmin, t->region.ymin,
  797. t->region.xmax, t->region.ymax);
  798. return false;
  799. }
  800. else
  801. {
  802. csGridView *sp1 = (csGridView*)t->children [0]->data;
  803. int newWidthSp1 = (int)(t->region.Width () * sp1->areafactor);
  804. int newHeightSp1 = (int)(t->region.Height () * sp1->areafactor);
  805. if (t->children [0]->region.xmin != t->children[1]->region.xmin)
  806. {
  807. // views were divided along the x axis
  808. t->children [0]->region.Set (t->region.xmin, t->region.ymin,
  809. t->region.xmin + newWidthSp1, t->region.ymax);
  810. t->children [1]->region.Set (t->region.xmin + newWidthSp1,
  811. t->region.ymin, t->region.xmax, t->region.ymax);
  812. }
  813. else
  814. {
  815. // views were divided along the y axis
  816. t->children [0]->region.Set (t->region.xmin, t->region.ymin,
  817. t->region.xmax, t->region.ymin + newHeightSp1);
  818. t->children [1]->region.Set (t->region.xmin, t->region.ymin + newHeightSp1,
  819. t->region.xmax, t->region.ymax);
  820. }
  821. }
  822. return true;
  823. }
  824. /**
  825. * Calculate the minimal area neeed to display all views.
  826. */
  827. void csGrid::CalcMinimalSize (csRegionTree2D *node, int &w, int &h)
  828. {
  829. if (node->children [0] == NULL)
  830. {
  831. // leaf
  832. ((csGridView*)node->data)->SuggestSize (w, h);
  833. }
  834. else
  835. {
  836. int w1, w2, h1, h2;
  837. csGridView *sp1 = (csGridView*)(node->children [0]->data);
  838. csGridView *sp2 = (csGridView*)(node->children [1]->data);
  839. CalcMinimalSize (node->children [0], w1, h1);
  840. CalcMinimalSize (node->children [1], w2, h2);
  841. if (sp1->bound.xmin != sp2->bound.xmin)
  842. {
  843. w = w1 + w2;
  844. h = MAX (h1, h2);
  845. }
  846. else
  847. {
  848. w = MAX (w1, w2);
  849. h = h1 + h2;
  850. }
  851. }
  852. }
  853. bool csGrid::SetRect (int xmin, int ymin, int xmax, int ymax)
  854. {
  855. if (csComponent::SetRect (xmin, ymin, xmax, ymax))
  856. {
  857. viewlayout->region.Set (0, 0,
  858. bound.Width () - (splitterX ? 3 : 0),
  859. bound.Height () - (splitterY ? 3 : 0));
  860. viewlayout->Traverse (ResizeViews);
  861. PlaceGadgets ();
  862. return true;
  863. }
  864. return false;
  865. }
  866. void csGrid::FixSize (int &newW, int &newH)
  867. {
  868. int w, h;
  869. SuggestSize (w, h);
  870. if (newW < w) newW = w;
  871. if (newH < h) newH = h;
  872. }
  873. void csGrid::SuggestSize (int &w, int &h)
  874. {
  875. CalcMinimalSize (viewlayout, w, h);
  876. w += (splitterX ? splitterX->bound.Width () : 0);
  877. h += (splitterY ? splitterY->bound.Height () : 0);
  878. }
  879. void csGrid::PlaceGadgets ()
  880. {
  881. if (splitterX)
  882. splitterX->SetRect (bound.Width() - 3, 0, bound.Width (), bound.Height ());
  883. if (splitterY)
  884. splitterY->SetRect (0, bound.Height () - 3, bound.Width (), bound.Height ());
  885. }
  886. void csGrid::SetStringAt (int row, int col, const char *data)
  887. {
  888. csString *str = (csString*)grid->GetAt (row, col);
  889. if (str || data)
  890. {
  891. if (!str)
  892. {
  893. str = new csString (data);
  894. grid->SetAt (row, col, str);
  895. }
  896. else if (!data)
  897. {
  898. delete str;
  899. grid->SetAt (row, col, NULL);
  900. }
  901. else
  902. str->Truncate (0).Append (data);
  903. }
  904. }
  905. csString *csGrid::GetStringAt (int row, int col)
  906. {
  907. return (csString*)grid->GetAt (row, col);
  908. }
  909. void csGrid::CreateRegion (csRect& rc, csGridCell *cell)
  910. {
  911. regions->Insert (rc, cell);
  912. if (!cell->IsUsed ())
  913. {
  914. cell->SetUsed ();
  915. vRegionStyles.Push (cell);
  916. }
  917. Invalidate (true);
  918. }
  919. void csGrid::SetCursorStyle (int iCursorStyle)
  920. {
  921. cursorStyle = iCursorStyle;
  922. }
  923. int csGrid::GetCursorStyle ()
  924. {
  925. return cursorStyle;
  926. }
  927. void csGrid::GetCursorPos (int &row, int &col)
  928. {
  929. row = ycur;
  930. col = xcur;
  931. }
  932. void csGrid::SetCursorPos (int row, int col)
  933. {
  934. if (row != ycur || col != xcur)
  935. {
  936. ycur = row;
  937. xcur = col;
  938. if (parent) parent->SendCommand (cscmdGridCursorChanged, (csSome)this);
  939. }
  940. }
  941. void csGrid::SetActiveView (csGridView *view)
  942. {
  943. if (GetFocused () != view) SetFocused (view);
  944. activeView = view;
  945. }