treewnd.cpp 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645
  1. #include "precomp.h"
  2. #include "treewnd.h"
  3. #include <tataki/canvas/ifc_canvas.h>
  4. #include <bfc/stack.h>
  5. #include <api/wnd/wndclass/scrollbar.h>
  6. #include <tataki/color/skinclr.h>
  7. #include <api/wnd/notifmsg.h>
  8. #include <api/wnd/accessible.h>
  9. #include <api/wnd/PaintCanvas.h>
  10. #define DEF_TEXT_SIZE 14
  11. #define CHILD_INDENT itemHeight
  12. #define X_SHIFT 2
  13. #define Y_SHIFT 2
  14. #define DRAG_THRESHOLD 4
  15. #define TIMER_EDIT_DELAY 1000
  16. #define TIMER_EDIT_ID 1249
  17. ///////////////////////////////////////////////////////////////////////////////
  18. // TreeWnd
  19. ///////////////////////////////////////////////////////////////////////////////
  20. static SkinColor textcolor(L"wasabi.tree.text");
  21. static SkinColor drophilitecolor(L"wasabi.tree.hiliteddrop");
  22. static SkinColor selectedcolor(L"wasabi.tree.selected");
  23. int CompareTreeItem::compareItem(TreeItem *p1, TreeItem *p2) {
  24. return p1->getTree()->compareItem(p1, p2);
  25. }
  26. TreeWnd::TreeWnd() {
  27. tabClosed = NULL;
  28. tabOpen = NULL;
  29. linkTopBottom = NULL;
  30. linkTopRight = NULL;
  31. linkTopRightBottom = NULL;
  32. linkTabTopBottom = NULL;
  33. linkTabTopRight = NULL;
  34. linkTabTopRightBottom = NULL;
  35. curSelected = NULL;
  36. mousedown_item = NULL;
  37. hitItem = NULL;
  38. draggedItem = NULL;
  39. tipitem = NULL;
  40. edited = NULL;
  41. editwnd = NULL;
  42. metrics_ok = FALSE;
  43. setSorted(TRUE);
  44. setFontSize(DEF_TEXT_SIZE);
  45. redraw = TRUE;
  46. prevbdownitem = NULL;
  47. autoedit=0;
  48. autocollapse=1;
  49. tabClosed = L"wasabi.tree.tab.closed";
  50. tabOpen = L"wasabi.tree.tab.open";
  51. linkTopBottom = L"wasabi.tree.link.top.bottom";
  52. linkTopRight = L"wasabi.tree.link.top.right";
  53. linkTopRightBottom = L"wasabi.tree.link.top.rightBottom";
  54. linkTabTopBottom = L"wasabi.tree.link.tab.top.bottom";
  55. linkTabTopRight = L"wasabi.tree.link.tab.top.right";
  56. linkTabTopRightBottom = L"wasabi.tree.link.tab.top.rightBottom";
  57. }
  58. TreeWnd::~TreeWnd() {
  59. // delete all root items
  60. deleteAllItems();
  61. drawList.removeAll();
  62. }
  63. int TreeWnd::onInit() {
  64. TREEWND_PARENT::onInit();
  65. setBgBitmap(L"wasabi.tree.background");
  66. setLineHeight(itemHeight);
  67. return 1;
  68. }
  69. void TreeWnd::setRedraw(bool r) {
  70. int old = redraw;
  71. redraw = r;
  72. if (!old && redraw)
  73. invalidate();
  74. }
  75. int TreeWnd::onPaint(Canvas *canvas) {
  76. PaintCanvas paintcanvas;
  77. PaintBltCanvas paintbcanvas;
  78. if (canvas == NULL) {
  79. if (needDoubleBuffer()) {
  80. if (!paintbcanvas.beginPaintNC(this)) return 0;
  81. canvas = &paintbcanvas;
  82. } else {
  83. if (!paintcanvas.beginPaint(this)) return 0;
  84. canvas = &paintcanvas;
  85. }
  86. }
  87. TREEWND_PARENT::onPaint(canvas);
  88. /* uncomment if you add columns or anything that should be not be drawn over by onPaint in which case you'll have to clip->subtract(your_region)
  89. api_region *clip = new RegionI();
  90. canvas->getClipRgn(clip); */
  91. /*RECT r;
  92. getNonClientRect(&r);
  93. int y = -getScrollY()+Y_SHIFT+r.top;
  94. int x = -getScrollX()+X_SHIFT;*/
  95. Wasabi::FontInfo fontInfo;
  96. fontInfo.color = textcolor;
  97. fontInfo.opaque=false;
  98. fontInfo.pointSize = getFontSize();
  99. firstItemVisible = NULL;
  100. lastItemVisible = NULL;
  101. ensureMetricsValid();
  102. //drawSubItems(canvas, x, &y, items, r.top, r.bottom, 0);
  103. drawItems(canvas, &fontInfo);
  104. canvas->selectClipRgn(NULL); // reset cliping region - NEEDED;
  105. // delete clip; uncomment if necessary
  106. return 1;
  107. }
  108. void TreeWnd::drawItems(Canvas *canvas, const Wasabi::FontInfo *fontInfo)
  109. {
  110. RECT r, c, ir;
  111. RegionI *orig=NULL;
  112. getClientRect(&r);
  113. if (!canvas->getClipBox(&c)) {
  114. getClientRect(&c);
  115. orig = new RegionI(&c);
  116. } else
  117. orig = new RegionI(canvas);
  118. int first = ((c.top-r.top) + getScrollY() - Y_SHIFT) / itemHeight;
  119. int last = ((c.bottom-r.top) + getScrollY() - Y_SHIFT) / itemHeight + 1;
  120. POINT pt;
  121. TreeItem *item;
  122. bool hastab;
  123. for (int i=first;i<=last;i++)
  124. {
  125. if (i >= drawList.getNumItems()) break;
  126. item = drawList[i];
  127. if (!item) continue;
  128. item->getCurRect(&ir);
  129. pt.x = r.left + X_SHIFT+item->getIndent()*itemHeight - getScrollX();//ir.left;
  130. pt.y = ir.top;
  131. // if we need the +/- icon and any of the link lines, draw them
  132. if (item->needTab()) {
  133. // pt.x += itemHeight;
  134. RECT _r={pt.x-itemHeight, pt.y, pt.x, pt.y+itemHeight};
  135. (item->isCollapsed() ? tabClosed : tabOpen).stretchToRectAlpha(canvas, &_r);
  136. hastab=TRUE;
  137. } else hastab = FALSE;
  138. int indent = item->getIndent();
  139. for (int j=0;j<indent;j++)
  140. {
  141. RECT _r={pt.x-itemHeight*(j+1), pt.y, pt.x-itemHeight*j, pt.y+itemHeight};
  142. int l = getLinkLine(item, j);
  143. if (l == (LINK_RIGHT | LINK_TOP)) {
  144. ((hastab && j == 0) ? linkTabTopRight : linkTopRight).stretchToRectAlpha(canvas, &_r);
  145. }
  146. if (l == (LINK_RIGHT | LINK_TOP | LINK_BOTTOM)) {
  147. ((hastab && j == 0) ? linkTabTopRightBottom : linkTopRightBottom).stretchToRectAlpha(canvas, &_r);
  148. }
  149. if (l == (LINK_BOTTOM | LINK_TOP)) {
  150. ((hastab && j == 0) ? linkTabTopBottom : linkTopBottom).stretchToRectAlpha(canvas, &_r);
  151. }
  152. }
  153. item->customDraw(canvas, pt, itemHeight, (pt.x+getScrollX())-r.left-X_SHIFT, r, fontInfo);
  154. }
  155. delete orig;
  156. }
  157. TreeItem *TreeWnd::hitTest(int x, int y) {
  158. POINT pt={x,y};
  159. return hitTest(pt);
  160. }
  161. TreeItem *TreeWnd::hitTest(POINT pt) {
  162. RECT r, ir;
  163. getClientRect(&r);
  164. int first = (getScrollY() - Y_SHIFT) / itemHeight;
  165. int last = ((r.bottom-r.top) + getScrollY() - Y_SHIFT) / itemHeight + 1;
  166. for (int i=first;i<=last;i++) {
  167. if (i >= drawList.getNumItems()) break;
  168. TreeItem *item = drawList.enumItem(i);
  169. if (item) {
  170. item->getCurRect(&ir);
  171. if (Wasabi::Std::pointInRect(ir, pt) && item->isHitTestable())
  172. return item;
  173. }
  174. }
  175. return NULL;
  176. }
  177. void TreeWnd::getMetrics(int *numItemsShown, int *mWidth) {
  178. *mWidth=0;
  179. *numItemsShown=0;
  180. drawList.removeAll();
  181. countSubItems(drawList, &items, X_SHIFT, numItemsShown, mWidth, 0);
  182. }
  183. void TreeWnd::countSubItems(PtrList<TreeItem> &drawlist, TreeItemList *_list, int indent, int *count, int *maxwidth, int z) {
  184. TreeItemList &list = *_list;
  185. for (int i=0;i<list.getNumItems();i++) {
  186. TreeItem *nextitem = list[i];
  187. int w = nextitem->getItemWidth(itemHeight, indent-X_SHIFT);
  188. if (indent+w > *maxwidth) *maxwidth = w+indent;
  189. int j = indent-(nextitem->needTab() ? itemHeight : 0);
  190. int k;
  191. k = indent + w;
  192. nextitem->setCurRect(j, Y_SHIFT+(*count * itemHeight), k, Y_SHIFT+((*count+1) * itemHeight), z);
  193. (*count)++;
  194. drawlist.addItem(nextitem);
  195. if (nextitem->isExpanded())
  196. countSubItems(drawlist, &nextitem->subitems, indent+CHILD_INDENT, count, maxwidth, z+1);
  197. }
  198. }
  199. void TreeWnd::timerCallback(int c) {
  200. switch (c) {
  201. case TIMER_EDIT_ID:
  202. prevbdownitem = NULL;
  203. killTimer(TIMER_EDIT_ID);
  204. break;
  205. default:
  206. TREEWND_PARENT::timerCallback(c);
  207. }
  208. }
  209. int TreeWnd::onLeftButtonDown(int x, int y) {
  210. if (edited)
  211. {
  212. delete editwnd; editwnd = NULL;
  213. endEditLabel(editbuffer);
  214. }
  215. POINT pt={x,y};
  216. TreeItem *item = hitTest(pt);
  217. if (item) {
  218. mousedown_item = item;
  219. mousedown_anchor.x = pt.x;
  220. mousedown_anchor.y = pt.y;
  221. mousedown_dragdone = FALSE;
  222. // only do expand/collapse if was already selected
  223. setCurItem(item, autocollapse?(curSelected == item):0, FALSE);
  224. beginCapture();
  225. }
  226. return 1;
  227. }
  228. int TreeWnd::onLeftButtonUp(int x, int y) {
  229. if (getCapture())
  230. endCapture();
  231. TREEWND_PARENT::onLeftButtonUp(x, y);
  232. POINT pt={x,y};
  233. TreeItem *item = hitTest(pt);
  234. if (autoedit && item == mousedown_item && item == prevbdownitem)
  235. setCurItem(item, FALSE, TRUE);
  236. else
  237. if (autoedit) {
  238. prevbdownitem = getCurItem();
  239. setTimer(TIMER_EDIT_ID, TIMER_EDIT_DELAY);
  240. }
  241. mousedown_item = NULL;
  242. return 1;
  243. }
  244. int TreeWnd::onRightButtonUp(int x, int y){
  245. TREEWND_PARENT::onRightButtonUp(x, y);
  246. POINT pos={x,y};
  247. TreeItem *ti = hitTest(pos);
  248. if (ti != NULL) {
  249. selectItem(ti);
  250. if (onPreItemContextMenu(ti, x, y) == 0) {
  251. int ret = ti->onContextMenu(x, y);
  252. onPostItemContextMenu(ti, x, y, ret);
  253. return ret;
  254. }
  255. return 1;
  256. } else {
  257. return onContextMenu(x, y);
  258. }
  259. }
  260. int TreeWnd::onMouseMove(int x, int y) {
  261. TREEWND_PARENT::onMouseMove(x, y);
  262. POINT pt={x,y};
  263. if (mousedown_item) {
  264. if (!mousedown_dragdone && (ABS(pt.x - mousedown_anchor.x) > DRAG_THRESHOLD || ABS(pt.y - mousedown_anchor.y) > DRAG_THRESHOLD)) {
  265. mousedown_dragdone = TRUE;
  266. if (getCapture())
  267. endCapture();
  268. onBeginDrag(mousedown_item);
  269. }
  270. }
  271. else
  272. {
  273. TreeItem *item = hitTest(pt);
  274. if (item) {
  275. if (tipitem != item) {
  276. tipitem = item;
  277. RECT r;
  278. RECT c;
  279. getClientRect(&c);
  280. item->getCurRect(&r);
  281. const wchar_t *tt = item->getTip();
  282. if (tt != NULL && *tt != '\0')
  283. setLiveTip(tt);
  284. else if (r.right > c.right || r.bottom > c.bottom || r.top < c.top || r.left < c.left)
  285. setLiveTip(item->getLabel());
  286. else
  287. setLiveTip(NULL);
  288. }
  289. } else {
  290. setLiveTip(NULL);
  291. }
  292. }
  293. return 1;
  294. }
  295. int TreeWnd::onLeftButtonDblClk(int x, int y) {
  296. TreeItem *item = hitTest(x, y);
  297. if (item == NULL) return 0;
  298. return item->onLeftDoubleClick();
  299. }
  300. int TreeWnd::onRightButtonDblClk(int x, int y) {
  301. TreeItem *item = hitTest(x, y);
  302. if (item == NULL) return 0;
  303. return item->onRightDoubleClick();
  304. }
  305. void TreeWnd::setLiveTip(const wchar_t *tip)
  306. {
  307. if (!tip)
  308. {
  309. setTip(oldtip);
  310. oldtip = L"";
  311. return;
  312. }
  313. oldtip = TREEWND_PARENT::getTip();
  314. setTip(tip);
  315. }
  316. int TreeWnd::onBeginDrag(TreeItem *treeitem)
  317. {
  318. wchar_t title[WA_MAX_PATH]=L"";
  319. // item calls addDragItem()
  320. if (!treeitem->onBeginDrag(title)) return 0;
  321. ASSERT(draggedItem == NULL);
  322. draggedItem = treeitem;
  323. if (*title != 0) setSuggestedDropTitle(title);
  324. handleDrag();
  325. return 1;
  326. }
  327. int TreeWnd::dragEnter(ifc_window *sourceWnd) {
  328. // uh... we don't know yet, but we can accept drops in general
  329. hitItem = NULL;
  330. return 1;
  331. }
  332. int TreeWnd::dragOver(int x, int y, ifc_window *sourceWnd) {
  333. POINT pos={x,y};
  334. screenToClient(&pos);
  335. TreeItem *prevItem;
  336. prevItem = hitItem;
  337. hitItem = hitTest(pos);
  338. // no dropping on yourself! :)
  339. if (hitItem == draggedItem) hitItem = NULL;
  340. // unselect previous item
  341. if (prevItem != hitItem && prevItem != NULL) {
  342. unhiliteDropItem(prevItem);
  343. repaint(); // commit invalidation of unhilited item so no trouble with scrolling
  344. prevItem->dragLeave(sourceWnd);
  345. }
  346. RECT r;
  347. getClientRect(&r);
  348. if (pos.y < r.top + 16) {
  349. if (getScrollY() >= 0) {
  350. scrollToY(MAX(0, getScrollY()-itemHeight));
  351. }
  352. } else if (pos.y > r.bottom - 16) {
  353. if (getScrollY() < getMaxScrollY()) {
  354. scrollToY(MIN(getMaxScrollY(), getScrollY()+itemHeight));
  355. }
  356. }
  357. if (hitItem != NULL) {
  358. // hilight it
  359. if (prevItem != hitItem) {
  360. hiliteDropItem(hitItem);
  361. repaint(); // commit invalidation of hilited so no trouble with scrolling
  362. }
  363. }
  364. if (hitItem == NULL) return defaultDragOver(x, y, sourceWnd);
  365. // ask the item if it can really accept such a drop
  366. return hitItem->dragOver(sourceWnd);
  367. }
  368. int TreeWnd::dragLeave(ifc_window *sourceWnd) {
  369. if (hitItem != NULL) {
  370. unhiliteDropItem(hitItem);
  371. hitItem->dragLeave(sourceWnd);
  372. }
  373. hitItem = NULL;
  374. return 1;
  375. }
  376. int TreeWnd::dragDrop(ifc_window *sourceWnd, int x, int y) {
  377. int res;
  378. if (hitItem == NULL) return defaultDragDrop(sourceWnd, x, y);
  379. // unhilite the dest
  380. unhiliteDropItem(hitItem);
  381. // the actual drop
  382. res = hitItem->dragDrop(sourceWnd);
  383. if (res) {
  384. onItemRecvDrop(hitItem);
  385. }
  386. hitItem = NULL;
  387. return res;
  388. }
  389. int TreeWnd::dragComplete(int success) {
  390. int ret;
  391. ASSERT(draggedItem != NULL);
  392. ret = draggedItem->dragComplete(success);
  393. draggedItem = NULL;
  394. return ret;
  395. }
  396. void TreeItem::setTip(const wchar_t *tip)
  397. {
  398. tooltip = tip;
  399. }
  400. const wchar_t *TreeItem::getTip()
  401. {
  402. return tooltip;
  403. }
  404. void TreeWnd::hiliteDropItem(TreeItem *item) {
  405. if (item)
  406. item->setHilitedDrop(TRUE);
  407. }
  408. void TreeWnd::hiliteItem(TreeItem *item) {
  409. if (item)
  410. item->setHilited(TRUE);
  411. }
  412. void TreeWnd::selectItem(TreeItem *item) {
  413. setCurItem(item, FALSE);
  414. }
  415. void TreeWnd::selectItemDeferred(TreeItem *item) {
  416. postDeferredCallback(DC_SETITEM, (intptr_t)item);
  417. }
  418. void TreeWnd::delItemDeferred(TreeItem *item) {
  419. postDeferredCallback(DC_DELITEM, (intptr_t)item);
  420. }
  421. void TreeWnd::unhiliteItem(TreeItem *item) {
  422. if (item)
  423. item->setHilited(FALSE);
  424. }
  425. void TreeWnd::unhiliteDropItem(TreeItem *item) {
  426. if (item)
  427. item->setHilitedDrop(FALSE);
  428. }
  429. void TreeWnd::setCurItem(TreeItem *item, bool expandCollapse, bool editifselected) {
  430. if (curSelected && curSelected != item) {
  431. onDeselectItem(curSelected);
  432. curSelected->setSelected(FALSE);
  433. }
  434. if (item) {
  435. curSelected = item;
  436. onSelectItem(curSelected);
  437. item->setSelected(TRUE, expandCollapse, editifselected);
  438. setSlidersPosition();
  439. }
  440. }
  441. // Returns the current tree width in pixels
  442. int TreeWnd::getContentsWidth() {
  443. ensureMetricsValid();
  444. return maxWidth;
  445. }
  446. // Returns the current tree height in pixels
  447. int TreeWnd::getContentsHeight() {
  448. ensureMetricsValid();
  449. return maxHeight;
  450. }
  451. void TreeWnd::ensureMetricsValid() {
  452. if (metrics_ok) return;
  453. int n;
  454. getMetrics(&n, &maxWidth);
  455. maxWidth += X_SHIFT*2;
  456. maxHeight = n*itemHeight+Y_SHIFT*2;
  457. metrics_ok = TRUE;
  458. setSlidersPosition();
  459. }
  460. // Gets notification from sliders
  461. int TreeWnd::childNotify(ifc_window *child, int msg, intptr_t param1, intptr_t param2) {
  462. switch (msg) {
  463. case ChildNotify::EDITWND_ENTER_PRESSED:
  464. if (child == editwnd && editwnd != NULL) {
  465. endEditLabel(editbuffer);
  466. return 1;
  467. }
  468. break;
  469. case ChildNotify::EDITWND_CANCEL_PRESSED:
  470. if (child == editwnd && editwnd != NULL) {
  471. cancelEditLabel();
  472. return 1;
  473. }
  474. break;
  475. case ChildNotify::EDITWND_DATA_MODIFIED:
  476. if (child == editwnd && editwnd != NULL) {
  477. editUpdate();
  478. return 1;
  479. }
  480. break;
  481. }
  482. return TREEWND_PARENT::childNotify(child, msg, param1, param2);
  483. }
  484. void TreeWnd::editUpdate() {
  485. ASSERT(edited != NULL && editwnd != NULL);
  486. if (!edited || !editwnd) return;
  487. int w = editwnd->getTextLength()+16;
  488. RECT i, r, e;
  489. edited->getCurRect(&i);
  490. getClientRect(&r);
  491. editwnd->getClientRect(&e);
  492. e.left += i.left;
  493. e.right += i.left;
  494. e.top += i.top;
  495. e.bottom += i.top;
  496. e.right = i.left+w;
  497. e.right = MIN<int>(r.right - X_SHIFT, e.right);
  498. editwnd->resize(&e);
  499. editwnd->invalidate();
  500. }
  501. TreeItem *TreeWnd::addTreeItem(TreeItem *item, TreeItem *par, int _sorted, int haschildtab) {
  502. ASSERT(item != NULL);
  503. ASSERTPR(item->getTree() == NULL, "can't transplant TreeItems");
  504. ASSERTPR(item->getLabel() != NULL, "tree items must have a label to be inserted");
  505. item->setSorted(_sorted);
  506. item->setChildTab(haschildtab ? TAB_AUTO : TAB_NO/*&& par != NULL*/);
  507. item->setTree(this);
  508. item->linkTo(par);
  509. if (par == NULL)
  510. items.addItem(item);
  511. all_items.addItem(item);
  512. metrics_ok = FALSE;
  513. if (redraw)
  514. invalidate();
  515. item->onTreeAdd();
  516. return item;
  517. }
  518. int TreeWnd::removeTreeItem(TreeItem *item) {
  519. ASSERT(item != NULL);
  520. ASSERT(item->getTree() == this);
  521. if (item->isSelected()) item->setSelected(FALSE);
  522. if (curSelected == item) curSelected = NULL;
  523. //CUT item->deleteSubitems();
  524. TreeItem *par = item->getParent();
  525. if (!par) { // is root item ?
  526. ASSERT(items.haveItem(item));
  527. items.removeItem(item);
  528. } else {
  529. if (!par->removeSubitem(item))
  530. return 0;
  531. }
  532. all_items.removeItem(item);
  533. metrics_ok = FALSE;
  534. drawList.removeItem(item);
  535. if (redraw)
  536. invalidate();
  537. item->setTree(NULL);
  538. item->onTreeRemove();
  539. if (par != NULL) par->onChildItemRemove(item);
  540. return 1;
  541. }
  542. void TreeWnd::moveTreeItem(TreeItem *item, TreeItem *newparent) {
  543. ASSERT(item != NULL);
  544. ASSERTPR(item->getTree() == this, "can't move between trees (fucks up Freelist)");
  545. removeTreeItem(item);
  546. addTreeItem(item, newparent, item->subitems.getAutoSort(), item->childTab);
  547. }
  548. void TreeWnd::deleteAllItems() {
  549. bool save_redraw = redraw;
  550. setRedraw(FALSE);
  551. TreeItem *item;
  552. while ((item = enumRootItem(0)) != NULL)
  553. delete item;
  554. setRedraw(save_redraw);
  555. }
  556. void TreeWnd::setSorted(bool dosort) {
  557. items.setAutoSort(dosort);
  558. }
  559. bool TreeWnd::getSorted() {
  560. return items.getAutoSort();
  561. }
  562. void TreeWnd::sortTreeItems() {
  563. items.sort(TRUE);
  564. metrics_ok = FALSE;
  565. if (redraw)
  566. invalidate();
  567. }
  568. TreeItem *TreeWnd::getSibling(TreeItem *item) {
  569. for (int i=0;i<items.getNumItems();i++) {
  570. if (items[i] == item) {
  571. if (i == items.getNumItems()-1) return NULL;
  572. return items[i+1];
  573. }
  574. }
  575. return NULL;
  576. }
  577. void TreeWnd::setAutoCollapse(bool doautocollase) {
  578. autocollapse=doautocollase;
  579. }
  580. int TreeWnd::onContextMenu(int x, int y) {
  581. POINT pos={x,y};
  582. screenToClient(&pos);
  583. TreeItem *ti = hitTest(pos);
  584. if (ti != NULL) {
  585. selectItem(ti);
  586. return ti->onContextMenu(x, y);
  587. }
  588. return 0;
  589. }
  590. int TreeWnd::onDeferredCallback(intptr_t param1, intptr_t param2) {
  591. switch (param1) {
  592. case DC_SETITEM:
  593. setCurItem((TreeItem *)param2, FALSE);
  594. return 1;
  595. case DC_DELITEM:
  596. delete (TreeItem *)param2;
  597. return 1;
  598. case DC_EXPAND:
  599. expandItem((TreeItem *)param2);
  600. return 1;
  601. case DC_COLLAPSE:
  602. collapseItem((TreeItem *)param2);
  603. return 1;
  604. }
  605. return 0;
  606. }
  607. int TreeWnd::getNumRootItems() {
  608. return items.getNumItems();
  609. }
  610. TreeItem *TreeWnd::enumRootItem(int which) {
  611. return items[which];
  612. }
  613. void TreeWnd::invalidateMetrics() {
  614. metrics_ok = FALSE;
  615. }
  616. int TreeWnd::getLinkLine(TreeItem *item, int level) {
  617. ASSERT(item != NULL);
  618. int l = 0;
  619. int r = 0;
  620. if (item->parent == NULL)
  621. return 0;
  622. TreeItem *cur=item;
  623. while (cur->getParent() && l < level) {
  624. cur = cur->getParent();
  625. l++;
  626. }
  627. if (cur->getSibling()) r |= LINK_BOTTOM | LINK_TOP;
  628. if (level == 0) r |= LINK_RIGHT;
  629. if (level == 0 && cur->getParent()) r |= LINK_TOP;
  630. return r;
  631. }
  632. int TreeWnd::onMouseWheelDown(int clicked, int lines) {
  633. if (!clicked)
  634. scrollToY(MIN(getMaxScrollY(), getScrollY()+itemHeight));
  635. else
  636. scrollToX(MIN(getMaxScrollX(), getScrollX()+itemHeight));
  637. return 1;
  638. }
  639. int TreeWnd::onMouseWheelUp(int clicked, int lines) {
  640. if (!clicked)
  641. scrollToY(MAX(0, getScrollY()-itemHeight));
  642. else
  643. scrollToX(MAX(0, getScrollX()-itemHeight));
  644. return 1;
  645. }
  646. int TreeWnd::expandItem(TreeItem *item) {
  647. ASSERT(item != NULL);
  648. return item->expand();
  649. }
  650. void TreeWnd::expandItemDeferred(TreeItem *item) {
  651. postDeferredCallback(DC_EXPAND, (intptr_t)item);
  652. }
  653. int TreeWnd::collapseItem(TreeItem *item) {
  654. ASSERT(item != NULL);
  655. return item->collapse();
  656. }
  657. void TreeWnd::collapseItemDeferred(TreeItem *item) {
  658. postDeferredCallback(DC_COLLAPSE, (intptr_t)item);
  659. }
  660. TreeItem *TreeWnd::getCurItem() {
  661. return curSelected;
  662. }
  663. int TreeWnd::getItemRect(TreeItem *item, RECT *r) {
  664. ASSERT(item != NULL);
  665. return item->getCurRect(r);
  666. }
  667. void TreeWnd::editItemLabel(TreeItem *item) {
  668. if (edited) {
  669. edited->setEdition(FALSE);
  670. edited->invalidate();
  671. }
  672. ASSERT(item != NULL);
  673. if (item == NULL) return;
  674. if (item->onBeginLabelEdit()) return;
  675. item->setEdition(TRUE);
  676. edited = item;
  677. editwnd = new EditWnd();
  678. editwnd->setModal(TRUE);
  679. editwnd->setAutoSelect(TRUE);
  680. editwnd->setStartHidden(TRUE);
  681. editwnd->init(getOsModuleHandle(), getOsWindowHandle());
  682. editwnd->setParent(this);
  683. RECT r;
  684. edited->getCurRect(&r);
  685. RECT cr;
  686. getClientRect(&cr);
  687. r.right = cr.right;
  688. if (r.bottom - r.top < 24) r.bottom = r.top + 24;
  689. editwnd->resize(&r);
  690. wcsncpy(editbuffer, edited->getLabel(), 256);
  691. editwnd->setBuffer(editbuffer, 255);
  692. editUpdate();
  693. editwnd->setVisible(TRUE);
  694. }
  695. void TreeWnd::endEditLabel(const wchar_t *newlabel)
  696. {
  697. editwnd = NULL; // editwnd self destructs
  698. if (edited->onEndLabelEdit(newlabel))
  699. edited->setLabel(newlabel);
  700. edited->setEdition(FALSE);
  701. edited->invalidate();
  702. onLabelChange(edited);
  703. edited = NULL;
  704. invalidateMetrics();
  705. setSlidersPosition();
  706. }
  707. void TreeWnd::cancelEditLabel(int destroyit) {
  708. ASSERT(edited != NULL);
  709. if (!edited) return;
  710. if (destroyit)
  711. delete editwnd;
  712. editwnd = NULL; // editwnd self destructs (update> except if destroyit for cancelling from treewnd)
  713. edited->setEdition(FALSE);
  714. edited->invalidate();
  715. edited = NULL;
  716. }
  717. void TreeWnd::setAutoEdit(int ae) {
  718. autoedit = ae;
  719. }
  720. int TreeWnd::getAutoEdit() {
  721. return autoedit;
  722. }
  723. TreeItem *TreeWnd::getByLabel(TreeItem *item, const wchar_t *name)
  724. {
  725. TreeItem *ti;
  726. // handle root-level searching
  727. if (item == NULL) {
  728. int n = getNumRootItems();
  729. for (int i = 0; i < n; i++) {
  730. ti = enumRootItem(i);
  731. if (!wcscmp(name, ti->getLabel())) return ti;
  732. ti = getByLabel(ti, name);
  733. if (ti) return ti;
  734. }
  735. return NULL;
  736. }
  737. // check the given item
  738. if (!wcscmp(name, item->getLabel())) return item;
  739. // depth first search
  740. ti = item->getChild();
  741. if (ti != NULL) {
  742. ti = getByLabel(ti, name);
  743. if (ti != NULL) return ti;
  744. }
  745. // recursively check siblings
  746. ti = item->getSibling();
  747. if (ti != NULL) ti = getByLabel(ti, name);
  748. return ti;
  749. }
  750. int TreeWnd::onGetFocus() {
  751. int r = TREEWND_PARENT::onGetFocus();
  752. #if 0
  753. DebugString("yay got focus");
  754. TreeItem *ti = getCurItem();
  755. if (ti != NULL) {
  756. ti->setSelected(FALSE);
  757. selectItemDeferred(ti);
  758. }
  759. #endif
  760. return r;
  761. }
  762. int TreeWnd::onKillFocus() {
  763. TREEWND_PARENT::onKillFocus();
  764. mousedown_item=NULL;
  765. /* if (edited)
  766. cancelEditLabel();*/
  767. #if 0
  768. DebugString("no mo focus");
  769. #endif
  770. return 1;
  771. }
  772. int TreeWnd::onChar(unsigned int c)
  773. {
  774. int r = 0;
  775. if (c == 27) {
  776. if (edited)
  777. cancelEditLabel(1);
  778. }
  779. if (curSelected != NULL && (r = curSelected->onChar(c)) != 0) return r;
  780. wchar_t b = TOUPPERW(c);
  781. if (b >= 'A' && b <= 'Z')
  782. {
  783. jumpToNext(b);
  784. r = 1;
  785. }
  786. return r ? r : TREEWND_PARENT::onChar(c);
  787. }
  788. int TreeWnd::getNumVisibleChildItems(TreeItem *c) {
  789. int nb=0;
  790. for(int i=0;i<c->getNumChildren();i++) {
  791. TreeItem *t=c->getNthChild(i);
  792. if(t->hasSubItems() && t->isExpanded())
  793. nb+=getNumVisibleChildItems(t);
  794. nb++;
  795. }
  796. return nb;
  797. }
  798. int TreeWnd::getNumVisibleItems() {
  799. int nb=0;
  800. for(int i=0;i<items.getNumItems();i++) {
  801. TreeItem *t=items.enumItem(i);
  802. if(t->hasSubItems() && t->isExpanded())
  803. nb+=getNumVisibleChildItems(t);
  804. nb++;
  805. }
  806. return nb;
  807. }
  808. TreeItem *TreeWnd::enumVisibleChildItems(TreeItem *c, int n) {
  809. int nb=0;
  810. for(int i=0;i<c->getNumChildren();i++) {
  811. TreeItem *t=c->getNthChild(i);
  812. if(nb==n) return t;
  813. if(t->hasSubItems() && t->isExpanded()) {
  814. TreeItem *t2=enumVisibleChildItems(t, n-nb-1);
  815. if(t2) return t2;
  816. nb+=getNumVisibleChildItems(t);
  817. }
  818. nb++;
  819. }
  820. return NULL;
  821. }
  822. TreeItem *TreeWnd::enumVisibleItems(int n) {
  823. int nb=0;
  824. for(int i=0;i<items.getNumItems();i++) {
  825. TreeItem *t=items.enumItem(i);
  826. if(nb==n) return t;
  827. if(t->hasSubItems() && t->isExpanded()) {
  828. TreeItem *t2=enumVisibleChildItems(t, n-nb-1);
  829. if(t2) return t2;
  830. nb+=getNumVisibleChildItems(t);
  831. }
  832. nb++;
  833. }
  834. return NULL;
  835. }
  836. int TreeWnd::findChildItem(TreeItem *c, TreeItem *i, int *nb) {
  837. for(int j=0;j<c->getNumChildren();j++) {
  838. TreeItem *t=c->getNthChild(j); (*nb)++;
  839. if (t == i) return *nb;
  840. if(t->hasSubItems() && t->isExpanded()) {
  841. int n = findChildItem(t, i, nb);
  842. if (n != -1) return *nb;
  843. }
  844. }
  845. return -1;
  846. }
  847. int TreeWnd::findItem(TreeItem *i) {
  848. int nb=-1;
  849. for(int j=0;j<items.getNumItems();j++) {
  850. TreeItem *t=items.enumItem(j); nb++;
  851. if (t == i) return nb;
  852. if(t->hasSubItems() && t->isExpanded()) {
  853. int n = findChildItem(t, i, &nb);
  854. if (n != -1) return nb;
  855. }
  856. }
  857. return -1;
  858. }
  859. TreeItem *TreeWnd::enumAllItems(int n) {
  860. return all_items[n];
  861. }
  862. int TreeWnd::onKeyDown(int keycode)
  863. {
  864. switch(keycode)
  865. {
  866. case 113: {
  867. TreeItem *item = getCurItem();
  868. if (item)
  869. item->editLabel();
  870. return 1;
  871. }
  872. case STDKEY_UP: {
  873. TreeItem *t=getCurItem();
  874. int l=getNumVisibleItems();
  875. if (t == NULL) {
  876. if (l > 0) setCurItem(enumVisibleItems(getNumVisibleItems()-1), FALSE, FALSE);
  877. } else {
  878. for(int i=0;i<l;i++)
  879. if(enumVisibleItems(i)==t) {
  880. if(i-1>=0) {
  881. TreeItem *t2=enumVisibleItems(i-1);
  882. if(t2) setCurItem(t2,FALSE,FALSE);
  883. }
  884. }
  885. }
  886. return 1;
  887. }
  888. case STDKEY_DOWN: {
  889. TreeItem *t=getCurItem();
  890. int l=getNumVisibleItems();
  891. if (t == NULL) {
  892. if (l > 0) setCurItem(enumVisibleItems(0), FALSE, FALSE);
  893. } else {
  894. for(int i=0;i<l;i++)
  895. if(enumVisibleItems(i)==t) {
  896. TreeItem *t2=enumVisibleItems(i+1);
  897. if(t2) setCurItem(t2,FALSE,FALSE);
  898. }
  899. }
  900. return 1;
  901. }
  902. case VK_PRIOR: {
  903. TreeItem *t=getCurItem();
  904. int l=getNumVisibleItems();
  905. for(int i=0;i<l;i++)
  906. if(enumVisibleItems(i)==t) {
  907. int a=MAX(i-5,0);
  908. TreeItem *t2=enumVisibleItems(a);
  909. if(t2) setCurItem(t2,FALSE,FALSE);
  910. }
  911. return 1;
  912. }
  913. case VK_NEXT: {
  914. TreeItem *t=getCurItem();
  915. int l=getNumVisibleItems();
  916. for(int i=0;i<l;i++)
  917. if(enumVisibleItems(i)==t) {
  918. int a=MIN(i+5,l-1);
  919. TreeItem *t2=enumVisibleItems(a);
  920. if(t2) setCurItem(t2,FALSE,FALSE);
  921. }
  922. return 1;
  923. }
  924. case STDKEY_HOME: {
  925. TreeItem *t=enumVisibleItems(0);
  926. if(t) setCurItem(t,FALSE,FALSE);
  927. return 1;
  928. }
  929. case STDKEY_END: {
  930. TreeItem *t=enumVisibleItems(getNumVisibleItems()-1);
  931. if(t) setCurItem(t,FALSE,FALSE);
  932. return 1;
  933. }
  934. case STDKEY_LEFT: {
  935. TreeItem *t=getCurItem();
  936. if(t) t->collapse();
  937. return 1;
  938. }
  939. case STDKEY_RIGHT: {
  940. TreeItem *t=getCurItem();
  941. if(t) t->expand();
  942. return 1;
  943. }
  944. }
  945. return TREEWND_PARENT::onKeyDown(keycode);
  946. }
  947. void TreeWnd::jumpToNext(wchar_t c) {
  948. firstFound=FALSE;
  949. if (jumpToNextSubItems(&items, c)) return;
  950. firstFound=TRUE;
  951. jumpToNextSubItems(&items, c);
  952. }
  953. int TreeWnd::jumpToNextSubItems(TreeItemList *list, wchar_t c) {
  954. for (int i=0;i<list->getNumItems();i++) {
  955. TreeItem *nextitem = list->enumItem(i);
  956. const wchar_t *l = nextitem->getLabel();
  957. wchar_t b = l ? TOUPPERW(*l) : 0;
  958. if (b == c && firstFound)
  959. {
  960. selectItem(nextitem);
  961. nextitem->ensureVisible();
  962. return 1;
  963. }
  964. if (nextitem->isSelected()) firstFound = TRUE;
  965. if (nextitem->isExpanded())
  966. if (jumpToNextSubItems(&nextitem->subitems, c)) return 1;
  967. }
  968. return 0;
  969. }
  970. void TreeWnd::ensureItemVisible(TreeItem *item) {
  971. ASSERT(item != NULL);
  972. // walk the parent tree to make sure item is visible
  973. for (TreeItem *cur = item->getParent(); cur; cur = cur->getParent()) {
  974. if (cur->isCollapsed()) cur->expand();
  975. }
  976. RECT r;
  977. RECT c;
  978. item->getCurRect(&r);
  979. getClientRect(&c);
  980. if (r.top < c.top || r.bottom > c.bottom) {
  981. if (r.top + (c.bottom - c.top) <= getContentsHeight())
  982. scrollToY(r.top);
  983. else {
  984. scrollToY(getContentsHeight()-(c.bottom-c.top));
  985. }
  986. }
  987. }
  988. void TreeWnd::setHilitedColor(const wchar_t *colorname) {
  989. // we have to store it in a String because SkinColor does not make a copy
  990. hilitedColorName = colorname;
  991. hilitedColor = hilitedColorName;
  992. }
  993. ARGB32 TreeWnd::getHilitedColor() {
  994. return hilitedColor;
  995. }
  996. int TreeWnd::compareItem(TreeItem *p1, TreeItem *p2)
  997. {
  998. int r = wcscmp(p1->getLabel(), p2->getLabel());
  999. if (r == 0) return CMP3(p1, p2);
  1000. return r;
  1001. }
  1002. int TreeWnd::setFontSize(int newsize)
  1003. {
  1004. TREEWND_PARENT::setFontSize(newsize);
  1005. if (newsize >= 0) textsize = newsize;
  1006. TextInfoCanvas c(this);
  1007. Wasabi::FontInfo fontInfo;
  1008. fontInfo.pointSize = getFontSize();
  1009. itemHeight = c.getTextHeight(&fontInfo);
  1010. redraw = 1;
  1011. metrics_ok = 0;
  1012. invalidate();
  1013. return 1;
  1014. }
  1015. int TreeWnd::getFontSize() {
  1016. #ifndef WASABINOMAINAPI
  1017. return textsize + api->metrics_getDelta();
  1018. #else
  1019. //MULTIAPI-FIXME: not handling delta
  1020. return textsize;
  1021. #endif
  1022. }
  1023. void TreeWnd::onSelectItem(TreeItem *i) {
  1024. Accessible *a = getAccessibleObject();
  1025. if (a != NULL)
  1026. a->onGetFocus(findItem(i));
  1027. }
  1028. void TreeWnd::onDeselectItem(TreeItem *i) {
  1029. }
  1030. ////////////////////////////////////////////////////////////////////////////////////
  1031. // TreeItem
  1032. ////////////////////////////////////////////////////////////////////////////////////
  1033. TreeItem::TreeItem(const wchar_t *label) {
  1034. parent=NULL;
  1035. MEMZERO(&curRect, sizeof(RECT));
  1036. childTab = TAB_AUTO;
  1037. tree = NULL;
  1038. expandStatus = STATUS_COLLAPSED;
  1039. icon = NULL;
  1040. _z = 0;
  1041. if (label != NULL)
  1042. setLabel(label);
  1043. selected = FALSE;
  1044. hilitedDrop = FALSE;
  1045. hilited = FALSE;
  1046. being_edited = FALSE;
  1047. setSorted(TRUE);
  1048. }
  1049. TreeItem::~TreeItem() {
  1050. // the subitem will call parent tree which will remove item from our list
  1051. deleteSubitems();
  1052. // remove from parent tree
  1053. if (tree) tree->removeTreeItem(this);
  1054. delete icon;
  1055. }
  1056. void TreeItem::deleteSubitems() {
  1057. while (subitems.getNumItems() > 0) {
  1058. delete subitems.enumItem(0);
  1059. }
  1060. }
  1061. void TreeItem::setSorted(int issorted) {
  1062. subitems.setAutoSort(!!issorted);
  1063. }
  1064. void TreeItem::setChildTab(int haschildtab) {
  1065. childTab = haschildtab;
  1066. }
  1067. void TreeItem::linkTo(TreeItem *par) {
  1068. parent = par;
  1069. if (par == NULL) return;
  1070. par->addSubItem(this);
  1071. }
  1072. void TreeItem::addSubItem(TreeItem *item) {
  1073. subitems.addItem(item);
  1074. }
  1075. int TreeItem::removeSubitem(TreeItem *item) {
  1076. if (subitems.searchItem(item) == -1) return 0;
  1077. subitems.removeItem(item);
  1078. if (tree->redraw)
  1079. tree->invalidate();
  1080. return 1;
  1081. }
  1082. TreeItem *TreeItem::getChild() {
  1083. return subitems.getFirst();
  1084. }
  1085. TreeItem *TreeItem::getChildSibling(TreeItem *item) { // locate item in children and return its sibling
  1086. for (int i=0;i<subitems.getNumItems();i++) {
  1087. if (subitems.enumItem(i) == item) {
  1088. if (i == subitems.getNumItems()-1) return NULL;
  1089. return subitems.enumItem(i+1);
  1090. }
  1091. }
  1092. return NULL;
  1093. }
  1094. TreeItem *TreeItem::getSibling() { // returns next item
  1095. if (!parent)
  1096. return tree->getSibling(this);
  1097. else
  1098. return parent->getChildSibling(this);
  1099. }
  1100. void TreeItem::setTree(TreeWnd *newtree) {
  1101. tree = newtree;
  1102. // recursively reset tree for children, if any
  1103. for (int i = 0; ; i++) {
  1104. TreeItem *item = getNthChild(i);
  1105. if (item == NULL) break;
  1106. item->setTree(tree);
  1107. }
  1108. }
  1109. void TreeItem::ensureVisible()
  1110. {
  1111. if (tree) tree->ensureItemVisible(this);
  1112. }
  1113. const wchar_t *TreeItem::getLabel()
  1114. {
  1115. return label;
  1116. }
  1117. void TreeItem::setLabel(const wchar_t *newlabel)
  1118. {
  1119. label = newlabel;
  1120. if (newlabel) {
  1121. if (tree)
  1122. tree->invalidateMetrics();
  1123. invalidate();
  1124. }
  1125. }
  1126. int TreeItem::customDraw(Canvas *canvas, const POINT &pt, int txtHeight, int indentation, const RECT &clientRect, const Wasabi::FontInfo *fontInfo)
  1127. {
  1128. if (being_edited) return 0;
  1129. SkinBitmap *icon = getIcon();
  1130. int cw = clientRect.right - clientRect.left;
  1131. int iconw = MIN(icon ? icon->getWidth() : 0, cw);
  1132. if (isSelected() || isHilitedDrop())
  1133. {
  1134. RECT r;
  1135. r.left = pt.x;
  1136. r.top = pt.y;
  1137. //r.right = r.left + canvas->getTextWidth(label)+2+(icon ? txtHeight : 0);
  1138. r.right = r.left + canvas->getTextWidth(label, fontInfo)+2+iconw;
  1139. r.bottom = r.top + txtHeight;
  1140. canvas->fillRect(&r, isHilitedDrop() ? drophilitecolor : selectedcolor);
  1141. }
  1142. if (isHilited())
  1143. {
  1144. RECT r;
  1145. r.left = pt.x;
  1146. r.top = pt.y;
  1147. //r.right = r.left + canvas->getTextWidth(label)+2+(icon ? txtHeight : 0);
  1148. r.right = r.left + canvas->getTextWidth(label, fontInfo)+2+iconw;
  1149. r.bottom = r.top + txtHeight;
  1150. canvas->drawRect(&r, 1, tree->getHilitedColor());
  1151. }
  1152. POINT d=pt;
  1153. if (icon) {
  1154. RECT i;
  1155. i.left = pt.x+1;
  1156. i.right = i.left + iconw;
  1157. // i.top = pt.y+1;
  1158. int lh = MIN(icon->getHeight(), txtHeight);
  1159. i.top = pt.y + (txtHeight - lh) / 2;
  1160. // i.bottom = i.top + txtHeight-2;
  1161. i.bottom = i.top + lh;
  1162. icon->stretchToRectAlpha(canvas, &i);
  1163. //d.x += txtHeight;
  1164. d.x += icon->getWidth();
  1165. }
  1166. canvas->textOut(d.x+1, d.y, label, fontInfo);
  1167. return canvas->getTextWidth(label, fontInfo)+2+iconw;
  1168. }
  1169. int TreeItem::getItemWidth(int txtHeight, int indentation) {
  1170. SkinBitmap *icon = getIcon();
  1171. if (!label) return (icon ? txtHeight : 0);
  1172. TextInfoCanvas c(tree);
  1173. Wasabi::FontInfo fontInfo;
  1174. fontInfo.pointSize = getTree()->getFontSize();
  1175. int width = c.getTextWidth(label, &fontInfo)+2;
  1176. width += (icon ? txtHeight : 0);
  1177. return width;
  1178. }
  1179. int TreeItem::getNumChildren() {
  1180. return subitems.getNumItems();
  1181. }
  1182. TreeItem *TreeItem::getNthChild(int nth) {
  1183. if (nth >= subitems.getNumItems()) return NULL;
  1184. return subitems.enumItem(nth);
  1185. }
  1186. void TreeItem::setCurRect(int x1, int y1, int x2, int y2, int z) {
  1187. curRect.left = x1;
  1188. curRect.right = x2;
  1189. curRect.top = y1;
  1190. curRect.bottom = y2;
  1191. _z = z;
  1192. }
  1193. int TreeItem::getIndent() {
  1194. return _z;
  1195. }
  1196. bool TreeItem::hasSubItems() {
  1197. return subitems.getNumItems()>0;
  1198. }
  1199. bool TreeItem::needTab() {
  1200. return (childTab == TAB_YES || (childTab == TAB_AUTO && hasSubItems()));
  1201. }
  1202. bool TreeItem::isExpanded() {
  1203. if (!hasSubItems()) return FALSE;
  1204. return expandStatus == STATUS_EXPANDED;
  1205. }
  1206. bool TreeItem::isCollapsed() {
  1207. if (!hasSubItems()) return TRUE;
  1208. return expandStatus == STATUS_COLLAPSED;
  1209. }
  1210. int TreeItem::getCurRect(RECT *r) {
  1211. r->left = curRect.left-tree->getScrollX();
  1212. r->top = curRect.top-tree->getScrollY();
  1213. r->right = curRect.right-tree->getScrollX();
  1214. r->bottom = curRect.bottom-tree->getScrollY();
  1215. RECT c;
  1216. tree->getClientRect(&c);
  1217. r->top += c.top;
  1218. r->bottom += c.top;
  1219. r->left += c.left;
  1220. r->right += c.left;
  1221. return 1;
  1222. }
  1223. TreeWnd *TreeItem::getTree() const {
  1224. return tree;
  1225. }
  1226. void TreeItem::setSelected(bool isSelected, bool expandCollapse, bool editifselected) {
  1227. bool wasselected = selected;
  1228. selected = !!isSelected;
  1229. if (selected != wasselected) {
  1230. invalidate();
  1231. tree->repaint();
  1232. if (selected) {
  1233. onSelect();
  1234. ASSERT(tree != NULL);
  1235. tree->onItemSelected(this);
  1236. } else {
  1237. onDeselect();
  1238. ASSERT(tree != NULL);
  1239. tree->onItemDeselected(this);
  1240. }
  1241. } else {
  1242. if (selected && editifselected) {
  1243. editLabel();
  1244. }
  1245. }
  1246. if (expandCollapse) {
  1247. if (isCollapsed())
  1248. expand();
  1249. else
  1250. collapse();
  1251. }
  1252. }
  1253. void TreeItem::invalidate() {
  1254. if (tree) {
  1255. RECT r;
  1256. getCurRect(&r);
  1257. tree->invalidateRect(&r);
  1258. }
  1259. }
  1260. bool TreeItem::isSelected() {
  1261. return selected;
  1262. }
  1263. int TreeItem::collapse() {
  1264. int old = expandStatus;
  1265. if (hasSubItems()) {
  1266. if (expandStatus == STATUS_COLLAPSED)
  1267. return 0;
  1268. expandStatus = STATUS_COLLAPSED;
  1269. RECT c;
  1270. tree->getClientRect(&c);
  1271. RECT r;
  1272. getCurRect(&r);
  1273. r.bottom = c.bottom;
  1274. r.left = c.left;
  1275. r.right = c.right;
  1276. if (tree) {
  1277. tree->invalidateRect(&r);
  1278. tree->invalidateMetrics();
  1279. }
  1280. }
  1281. onCollapse();
  1282. return old != expandStatus;
  1283. }
  1284. int TreeItem::expand() {
  1285. int old = expandStatus;
  1286. if (hasSubItems()) {
  1287. if (expandStatus == STATUS_EXPANDED)
  1288. return 0;
  1289. expandStatus = STATUS_EXPANDED;
  1290. RECT c;
  1291. tree->getClientRect(&c);
  1292. RECT r;
  1293. getCurRect(&r);
  1294. r.bottom = c.bottom;
  1295. r.left = c.left;
  1296. r.right = c.right;
  1297. if (tree) {
  1298. tree->invalidateRect(&r);
  1299. tree->invalidateMetrics();
  1300. }
  1301. }
  1302. onExpand();
  1303. return old != expandStatus;
  1304. }
  1305. int TreeItem::onContextMenu(int x, int y) {
  1306. return 0;
  1307. }
  1308. void TreeItem::setHilitedDrop(bool ishilitedDrop) {
  1309. bool washilighted = hilitedDrop;
  1310. hilitedDrop = !!ishilitedDrop;
  1311. if (washilighted != hilitedDrop)
  1312. invalidate();
  1313. }
  1314. void TreeItem::setHilited(bool ishilited) {
  1315. bool washilighted = hilited;
  1316. hilited = !!ishilited;
  1317. if (washilighted != hilited)
  1318. invalidate();
  1319. }
  1320. TreeItem *TreeItem::getParent() {
  1321. return parent;
  1322. }
  1323. bool TreeItem::isHilitedDrop() {
  1324. return hilitedDrop;
  1325. }
  1326. bool TreeItem::isHilited() {
  1327. return hilited;
  1328. }
  1329. void TreeItem::setIcon(SkinBitmap *newicon) {
  1330. if (icon) {
  1331. delete icon;
  1332. icon = NULL;
  1333. }
  1334. icon = newicon;
  1335. invalidate();
  1336. }
  1337. SkinBitmap *TreeItem::getIcon() {
  1338. return icon;
  1339. }
  1340. void TreeItem::sortItems() {
  1341. subitems.sort();
  1342. }
  1343. void TreeItem::editLabel() {
  1344. if (!tree) return;
  1345. tree->editItemLabel(this);
  1346. }
  1347. int TreeItem::onBeginLabelEdit() {
  1348. return 1; // disable editing by default
  1349. }
  1350. int TreeItem::onEndLabelEdit(const wchar_t *newlabel)
  1351. {
  1352. return 1; // accept new label by default
  1353. }
  1354. void TreeItem::setEdition(bool isedited) {
  1355. being_edited = !!isedited;
  1356. invalidate();
  1357. }
  1358. bool TreeItem::getEdition() {
  1359. return being_edited;
  1360. }
  1361. bool TreeItem::isSorted()
  1362. {
  1363. return subitems.getAutoSort();
  1364. }