listwnd.cpp 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151
  1. #pragma warning(disable:4355)
  2. #include <precomp.h>
  3. #include "listwnd.h"
  4. #include <bfc/wasabi_std.h>
  5. #include <api/wnd/usermsg.h>
  6. #include <bfc/ptrlist.h>
  7. #include <tataki/color/skinclr.h>
  8. #include <api/wnd/notifmsg.h>
  9. #include <bfc/assert.h>
  10. #include <api/locales/xlatstr.h>
  11. #include <api/wnd/accessible.h>
  12. #include <bfc/string/StringW.h>
  13. #include <new>
  14. #define DEF_TEXT_SIZE 14 // Default text size
  15. #define ITEMLIST_INC 4092
  16. #define LISTWND_DRAG_TIMERID 0x8972
  17. #define LISTWND_DRAG_MARGIN 12
  18. #define LISTWND_DRAG_TIMERDELAY 100
  19. #define DRAGSKIP_START 5
  20. #define X_SHIFT 2
  21. #define Y_SHIFT 2
  22. #define DRAG_THRESHOLD 4
  23. #define COLUMNS_DEFAULT_HEIGHT 12
  24. #define COLUMNS_DEFAULT_WIDTH 96
  25. #define COLUMNS_MARGIN 2
  26. #define COLUMNS_RESIZE_THRESHOLD 4
  27. #define COLUMNS_MIN_WIDTH 1
  28. #define COLSEPHEIGHT 1
  29. static SkinColor textColor(L"studio.list.text");// todo: have own color in skin.cpp
  30. static SkinColor bgcolor(L"studio.list.background");// todo: have own color in skin.cpp
  31. static SkinColor color_item_selected_fg(L"studio.list.item.selected.fg"); // RGB(0, 0, 128)
  32. static SkinColor color_item_selected(L"studio.list.item.selected"); // RGB(0, 0, 128)
  33. static SkinColor color_item_focused(L"studio.list.item.focused");// RGB(0, 128, 128)
  34. static SkinColor color_item_focusrect(L"studio.list.item.focused");// RGB(0, 128, 128)
  35. static SkinColor color_headers(L"studio.list.column.background");//RGB(0, 152, 208)
  36. static SkinColor columnTextColor(L"studio.list.column.text");
  37. static SkinColor columnSepColor(L"studio.list.column.separator");
  38. typedef struct
  39. {
  40. wchar_t *label;
  41. int column;
  42. } listSubitemStruct;
  43. class listItem
  44. {
  45. friend ListWnd;
  46. public:
  47. ListWnd *getList() const { return listwnd; }
  48. protected:
  49. listItem()
  50. {
  51. data = 0;
  52. subitems = NULL;
  53. listwnd = NULL;
  54. }
  55. ~listItem()
  56. {
  57. if (subitems != NULL)
  58. {
  59. for (int i=0;i<subitems->getNumItems();i++)
  60. {
  61. listSubitemStruct *subitem = subitems->enumItem(i);
  62. if (subitem->label)
  63. FREE(subitem->label);
  64. }
  65. subitems->freeAll();
  66. delete subitems;
  67. }
  68. }
  69. void setList(ListWnd *newlist) { listwnd=newlist; }
  70. StringW label;
  71. LPARAM data;
  72. PtrList<listSubitemStruct> *subitems;
  73. ListWnd *listwnd;
  74. AutoSkinBitmap icon;
  75. };
  76. class CompareListItem {
  77. public:
  78. static int compareItem(listItem *p1, listItem *p2);
  79. };
  80. int CompareListItem::compareItem(listItem *p1, listItem *p2) {
  81. return p1->getList()->sortCompareItem(p1, p2);
  82. }
  83. XMLParamPair ListWnd::params[] = {
  84. {LIST_ANTIALIAS, L"ANTIALIAS"},
  85. {LIST_BACKGROUND, L"BACKGROUND"},
  86. {LIST_TILE, L"TILE"},
  87. {LIST_NOCOLHEADER, L"NOCOLHEADER"},
  88. };
  89. ListWnd::ListWnd()
  90. : selItemList(this)
  91. {
  92. xuihandle = newXuiHandle();
  93. CreateXMLParameters(xuihandle);
  94. if (WASABI_API_SKIN->skin_getVersion() >= 1) {
  95. textColor.setElementName(L"wasabi.list.text");
  96. textColor.setColorGroup(L"");
  97. bgcolor.setElementName(L"wasabi.list.background");
  98. bgcolor.setColorGroup(L"");
  99. color_item_selected_fg.setElementName(L"wasabi.list.text.selected");
  100. color_item_selected_fg.setColorGroup(L"");
  101. color_item_selected.setElementName(L"wasabi.list.text.selected.background");
  102. color_item_selected.setColorGroup(L"");
  103. color_headers.setElementName(L"wasabi.list.column.background");
  104. color_headers.setColorGroup(L"");
  105. columnTextColor.setElementName(L"wasabi.list.column.text");
  106. columnTextColor.setColorGroup(L"");
  107. columnSepColor.setElementName(L"wasabi.list.column.frame.bottom");
  108. columnSepColor.setColorGroup(L"");
  109. color_item_focused.setColorGroup(L"");
  110. color_item_focusrect.setColorGroup(L"");
  111. }
  112. selectonupdown = 1;
  113. setAutoSort(FALSE);
  114. setOwnerDraw(FALSE);
  115. setSortDirection(0);
  116. setSortColumn(0);
  117. lastcolsort=-1;
  118. dragtimeron = 0;
  119. dragskip = DRAGSKIP_START;
  120. dragskipcount = 0;
  121. item_invalidate_border = 0;
  122. metrics_ok = FALSE;
  123. setFontSize(DEF_TEXT_SIZE);
  124. redraw = TRUE;
  125. columnsHeight = COLUMNS_DEFAULT_HEIGHT;
  126. lastItemFocused = NULL;
  127. lastItemFocusedPos = -1;
  128. lastAddedItem = NULL;
  129. selectionStart = -1;
  130. colresize = -1;
  131. resizing_col = FALSE;
  132. processbup = FALSE;
  133. bdown = FALSE;
  134. nodrag = FALSE;
  135. showColumnsHeaders = TRUE;
  136. rectselecting=0;
  137. preventMultipleSelection = 0;
  138. //CUT autoresizecol0 = 0;
  139. wantautodeselect = 1;
  140. registerAcceleratorSection(L"listwnd");
  141. hoverselect = 0;
  142. firstItemVisible = -1;
  143. lastItemVisible = -1;
  144. showicons = 0;
  145. iconWidth = -1; // If it's still negative use itemHeight instead -- better user getIconWidth()
  146. iconHeight = -1;
  147. antialias=1;
  148. hasUserBg = false;
  149. }
  150. void ListWnd::CreateXMLParameters(int master_handle)
  151. {
  152. //LISTWND_PARENT::CreateXMLParameters(master_handle);
  153. int numParams = sizeof(params) / sizeof(params[0]);
  154. hintNumberOfParams(xuihandle, numParams);
  155. for (int i = 0;i < numParams;i++)
  156. addParam(xuihandle, params[i], XUI_ATTRIBUTE_IMPLIED);
  157. }
  158. ListWnd::~ListWnd() {
  159. deleteAllItems();
  160. columnsList.deleteAll();
  161. nodrag=FALSE;
  162. }
  163. int ListWnd::setXuiParam(int _xuihandle, int xmlattributeid, const wchar_t *xmlattributename, const wchar_t *value)
  164. {
  165. if (_xuihandle != xuihandle)
  166. return ScrlBkgWnd::setXuiParam(_xuihandle, xmlattributeid, xmlattributename, value);
  167. switch (xmlattributeid)
  168. {
  169. case LIST_ANTIALIAS:
  170. antialias = WTOI(value);
  171. break;
  172. case LIST_BACKGROUND:
  173. {
  174. SkinBitmap __bmp(value);
  175. if (!__bmp.isInvalid())
  176. {
  177. this->setBgBitmap(value);
  178. hasUserBg = true;
  179. }
  180. else
  181. {
  182. this->setBgBitmap(L"wasabi.list.background");
  183. hasUserBg = false;
  184. }
  185. }
  186. this->invalidate();
  187. break;
  188. case LIST_TILE:
  189. this->wantTileBg = WTOI(value)?1:0;
  190. this->invalidate();
  191. break;
  192. case LIST_NOCOLHEADER:
  193. setShowColumnsHeaders(!WTOI(value));
  194. break;
  195. default:
  196. return 0;
  197. }
  198. return 1;
  199. }
  200. int ListWnd::onInit() {
  201. LISTWND_PARENT::onInit();
  202. if (!hasUserBg) setBgBitmap(L"wasabi.list.background");
  203. setLineHeight(getItemHeight());
  204. return 1;
  205. }
  206. int ListWnd::onPostOnInit() {
  207. LISTWND_PARENT::onPostOnInit();
  208. recalcHeaders();
  209. return 1;
  210. }
  211. int ListWnd::onPaint(Canvas *canvas)
  212. {
  213. PaintCanvas paintcanvas;
  214. PaintBltCanvas paintbcanvas;
  215. if (canvas == NULL) {
  216. if (needDoubleBuffer()) {
  217. if (!paintbcanvas.beginPaintNC(this)) return 0;
  218. canvas = &paintbcanvas;
  219. } else {
  220. if (!paintcanvas.beginPaint(this)) return 0;
  221. canvas = &paintcanvas;
  222. }
  223. }
  224. LISTWND_PARENT::onPaint(canvas);
  225. RegionI clip;
  226. canvas->getClipRgn(&clip);
  227. api_region *orig;
  228. orig = clip.clone();
  229. drawColumnHeaders(canvas);
  230. if (getColumnsHeight() > 0) {
  231. RECT cr;
  232. getClientRect(&cr);
  233. cr.bottom = cr.top;
  234. cr.top -= getColumnsHeight();
  235. clip.subtractRect(&cr);
  236. canvas->selectClipRgn(&clip);
  237. }
  238. firstItemVisible = -1;
  239. lastItemVisible = -1;
  240. //drawSubItems(canvas, x, &y, items, r.top, r.bottom, 0);
  241. drawItems(canvas);
  242. canvas->selectClipRgn(orig); // reset cliping region;
  243. clip.disposeClone(orig);
  244. return 1;
  245. }
  246. int ListWnd::onResize() {
  247. LISTWND_PARENT::onResize();
  248. recalcHeaders();
  249. return 1;
  250. }
  251. int ListWnd::getNumItems(void) {
  252. return itemList.getNumItems();
  253. }
  254. void ListWnd::drawItems(Canvas *canvas) {
  255. RECT r, c;
  256. getClientRect(&r);
  257. RegionI clip;
  258. if (!canvas->getClipRgn(&clip))
  259. {
  260. clip.setRect(&r);
  261. }
  262. if (GetClipBox(canvas->getHDC(), &c) == NULLREGION) {
  263. getClientRect(&c);
  264. }
  265. // DebugString("%d %d %d %d\n", c.left, c.top, c.right, c.bottom);
  266. // float f,l;
  267. calcBounds();
  268. //int first, last;
  269. /* RECT s=c;
  270. s.bottom = min(s.bottom, r.bottom);
  271. s.top = max(s.top, getLabelHeight()+(showColumnsHeaders ? getColumnsHeight() : 0));
  272. f = ((float)(s.top - getLabelHeight() - (showColumnsHeaders ? getColumnsHeight() : 0) - getYShift() + getScrollY())) / (float)itemHeight;
  273. l = ((float)(s.bottom - getLabelHeight() - (showColumnsHeaders ? getColumnsHeight() : 0) - getYShift() + getScrollY())) / (float)itemHeight;
  274. first = (int)f;
  275. first = max(0,first);
  276. last = (int)l;
  277. if ((float)((int)l) != l) {
  278. last++;
  279. }*/
  280. int g=0;
  281. for (int i=firstItemVisible;i<=lastItemVisible && i<itemList.getNumItems();i++) {
  282. RECT ir={0,0,0,0};
  283. getItemRect(i, &ir);
  284. int a=ir.right;
  285. ir.right = r.right;
  286. if (!clip.doesIntersectRect(&ir))
  287. continue;
  288. ir.right=a;
  289. g++;
  290. LPARAM itemdata = getItemData(i);
  291. int itemselected = getItemSelected(i);
  292. int itemfocused = getItemFocused(i);
  293. onPreItemDraw(canvas, i, &ir, itemdata, itemselected, itemfocused);
  294. int sel = getItemSelected(i);
  295. canvas->pushPen(PS_SOLID, 1, getColumnSepColor());
  296. if (!ownerDraw(canvas, i, &ir, itemdata, itemselected, itemfocused))
  297. {
  298. Wasabi::FontInfo fontInfo;
  299. fontInfo.antialias = getTextAntialias(itemdata);
  300. fontInfo.bold = getTextBold(itemdata);
  301. fontInfo.italic = !!getTextItalic(itemdata);
  302. fontInfo.opaque = false;
  303. fontInfo.color = sel ? getSelFgColor(itemdata) : getTextColor(itemdata);
  304. fontInfo.pointSize = getFontSize();
  305. int x = -getScrollX();
  306. if (sel)
  307. canvas->fillRect(&ir, getSelBgColor(itemdata));
  308. if (getItemFocused(i))
  309. canvas->fillRect(&ir, getFocusColor(itemdata));
  310. if (needFocusRect(itemdata))
  311. canvas->drawRect(&ir, 1, getFocusRectColor(itemdata));
  312. if (showicons)
  313. {
  314. SkinBitmap *icon = getItemIcon(i);
  315. if (icon)
  316. {
  317. RECT dst={x+X_SHIFT+r.left+1, ir.top+1, x+X_SHIFT+r.left+getIconWidth()+1, ir.top+getIconHeight()+1};
  318. icon->stretchToRect(canvas, &dst);
  319. }
  320. x += getIconWidth()+1;
  321. }
  322. int xsep = wantColSepOnItems()?COLSEPHEIGHT:0;
  323. for (int j=0;j<columnsList.getNumItems();j++) {
  324. ListColumn *col = columnsList[j];
  325. RECT cr=ir;
  326. cr.left = x+X_SHIFT+r.left;
  327. cr.right = cr.left + col->getWidth()-X_SHIFT*2+xsep;
  328. if (j > 0 && wantColSepOnItems()) {
  329. canvas->moveTo(x, ir.top);
  330. canvas->lineTo(x, ir.top+getItemHeight());
  331. }
  332. switch (col->getAlignment()) {
  333. case COL_LEFTALIGN:
  334. canvas->textOutEllipsed(cr.left+2, cr.top, cr.right-cr.left-4, cr.bottom-cr.top, getSubitemText(i, j), &fontInfo);
  335. break;
  336. case COL_CENTERALIGN: {
  337. RECT _cr = {cr.left+2, cr.top, cr.right-4, cr.bottom};
  338. canvas->textOutCentered(&_cr, getSubitemText(i, j), &fontInfo);
  339. break;
  340. }
  341. case COL_RIGHTALIGN: {
  342. const wchar_t *txt = getSubitemText(i, j);
  343. int __x = cr.left;
  344. int __y = cr.top;
  345. int fw = canvas->getTextWidth(txt, &fontInfo);
  346. int aw = cr.right-cr.left-4;
  347. __x -= fw-aw;
  348. canvas->textOut(__x, __y, txt, &fontInfo);
  349. break;
  350. }
  351. }
  352. x += col->getWidth()+xsep;
  353. }
  354. if (wantColSepOnItems()) {
  355. canvas->moveTo(x, ir.top);
  356. canvas->lineTo(x, ir.top+getItemHeight());
  357. }
  358. }
  359. canvas->popPen();
  360. onPostItemDraw(canvas, i, &ir, itemdata, itemselected, itemfocused);
  361. }
  362. /*
  363. OutputDebugString("%d items draw\n", g);
  364. */
  365. }
  366. int ListWnd::wantColSepOnItems() {
  367. return 0;
  368. }
  369. int ListWnd::getXShift() {
  370. if (wantColSepOnItems()) return X_SHIFT; else return 0;
  371. }
  372. int ListWnd::getFirstItemSelected() {
  373. return getNextItemSelected(-1);
  374. }
  375. int ListWnd::getNextItemSelected(int lastpos) {
  376. if (lastpos < -1) lastpos = -1;
  377. for (int i=lastpos+1;i<itemList.getNumItems();i++)
  378. if (getItemSelected(i))
  379. return i;
  380. return -1;
  381. }
  382. void ListWnd::calcBounds() {
  383. lastComplete = TRUE;
  384. firstComplete = TRUE;
  385. float f,l;
  386. RECT r;
  387. getClientRect(&r);
  388. f = ((float)(getScrollY()-Y_SHIFT) / getItemHeight());
  389. l = ((float)(getScrollY()-Y_SHIFT+(r.bottom-r.top)) / getItemHeight()) - 1.0f;
  390. firstItemVisible = (int)f;
  391. lastItemVisible = (int)l;
  392. if ((float)((int)l) != l) {
  393. lastItemVisible++;
  394. lastComplete = FALSE;
  395. }
  396. if ((float)((int)f) != f && f >= 0) {
  397. firstComplete = FALSE;
  398. }
  399. }
  400. // Draws tiled background
  401. void ListWnd::drawBackground(Canvas *canvas)
  402. {
  403. LISTWND_PARENT::drawBackground(canvas);
  404. drawColumnHeaders(canvas);
  405. }
  406. void ListWnd::drawColumnHeaders(Canvas *c)
  407. {
  408. if (columnsList.getNumItems() == 0 || !showColumnsHeaders) return;
  409. RECT r;
  410. getClientRect(&r);
  411. r.top -= getColumnsHeight();
  412. r.bottom = r.top + getColumnsHeight();
  413. if (renderRatioActive())
  414. r.left -= (int)((double)getScrollX()*getRenderRatio());
  415. else
  416. r.left-=getScrollX();
  417. c->fillRect(&r, color_headers);
  418. int x = r.left + X_SHIFT/*+ 1*/;
  419. if (showicons)
  420. x += getIconWidth()+1 + 2;
  421. Wasabi::FontInfo fontInfo;
  422. fontInfo.color = columnTextColor;
  423. fontInfo.opaque = false;
  424. fontInfo.pointSize = getColumnsHeight();
  425. c->pushPen(PS_SOLID, 1, getColumnSepColor());
  426. for (int i=0;i<columnsList.getNumItems();i++)
  427. {
  428. ListColumn *col = columnsList[i];
  429. int width = col->getWidth();
  430. if (i > 0) {
  431. c->moveTo(x, r.top);
  432. c->lineTo(x, r.top+getColumnsHeight());
  433. }
  434. RECT ch;
  435. ch.left = x+COLUMNS_MARGIN-((i==0)?X_SHIFT:0);
  436. ch.top = r.top;
  437. ch.right = ch.left + col->getWidth()-1-COLUMNS_MARGIN*2+((i==0)?X_SHIFT:0);
  438. ch.bottom = ch.top + getColumnsHeight()-1;
  439. col->customDrawHeader(c, &ch, &fontInfo);
  440. x+=width/*+1*/;
  441. }
  442. c->moveTo(x, r.top);
  443. c->lineTo(x, r.top+getColumnsHeight());
  444. c->popPen();
  445. }
  446. ARGB32 ListWnd::getColumnSepColor() {
  447. return columnSepColor;
  448. }
  449. int ListWnd::getHeaderHeight() {
  450. return (showColumnsHeaders && columnsList.getNumItems() > 0) ? getColumnsHeight() : 0;
  451. }
  452. // Returns the current tree width in pixels
  453. int ListWnd::getContentsWidth() {
  454. return getColumnsWidth()+X_SHIFT;
  455. }
  456. // Returns the current tree height in pixels
  457. int ListWnd::getContentsHeight() {
  458. return itemList.getNumItems()*(getItemHeight()+(wantColSepOnItems()?COLSEPHEIGHT:0))+Y_SHIFT*2;
  459. }
  460. void ListWnd::setAutoSort(bool dosort) {
  461. autosort = dosort;
  462. itemList.setAutoSort(dosort);
  463. }
  464. void ListWnd::setOwnerDraw(bool doownerdraw) {
  465. ownerdraw = doownerdraw;
  466. }
  467. int ListWnd::setFontSize(int size)
  468. {
  469. LISTWND_PARENT::setFontSize(size);
  470. if (size >= 0) textsize = size;
  471. TextInfoCanvas c(this);
  472. Wasabi::FontInfo fontInfo;
  473. fontInfo.pointSize = getFontSize();
  474. setItemHeight(c.getTextHeight(&fontInfo)+2, false);
  475. redraw = TRUE;
  476. metrics_ok = FALSE;
  477. invalidate();
  478. return 1;
  479. }
  480. int ListWnd::getFontSize() {
  481. #ifndef WASABINOMAINAPI
  482. return textsize+api->metrics_getDelta();
  483. #else
  484. //MULTIAPI-FIXME: not handling delta
  485. return textsize;
  486. #endif
  487. }
  488. void ListWnd::onSetVisible(int show) {
  489. LISTWND_PARENT::onSetVisible(show);
  490. if (show) invalidate();
  491. }
  492. int ListWnd::fullyVisible(int pos) {
  493. return (((lastComplete && pos <= lastItemVisible) || (!lastComplete && pos < lastItemVisible)) && ((firstComplete && pos >= firstItemVisible) || (!firstComplete && pos > firstItemVisible)));
  494. }
  495. void ListWnd::ensureItemVisible(int pos) {
  496. if (pos >= itemList.getNumItems()) pos = itemList.getNumItems()-1;
  497. if (pos < 0) pos = 0;
  498. if (fullyVisible(pos)) return;
  499. RECT c;
  500. int y=pos*getItemHeight();
  501. getClientRect(&c);
  502. int showing_height = c.bottom - c.top;
  503. if (getScrollY() < y) // scrolling up
  504. y = (y - showing_height) + getItemHeight()*3;
  505. else
  506. y -= getItemHeight()*2;
  507. if (y < 0) y = 0;
  508. else if (y + showing_height > getContentsHeight()) {
  509. // just show bottom pane
  510. y = getContentsHeight()-showing_height;
  511. }
  512. scrollToY(y);
  513. }
  514. void ListWnd::scrollToItem(int pos) {
  515. if (!isInited()) return;
  516. scrollToY(Y_SHIFT+pos*(getItemHeight()+(wantColSepOnItems()?COLSEPHEIGHT:0)));
  517. }
  518. int ListWnd::getNumColumns() {
  519. return columnsList.getNumItems();
  520. }
  521. ListColumn *ListWnd::getColumn(int n) {
  522. return columnsList.enumItem(n);
  523. }
  524. int ListWnd::getColumnWidth(int c) {
  525. ListColumn *col = columnsList[c];
  526. ASSERT(col != NULL);
  527. return col->getWidth();
  528. }
  529. int ListWnd::selectAll(int cb) {
  530. int i;
  531. if (preventMultipleSelection) return 1;
  532. for (i=0;i<itemList.getNumItems();i++) {
  533. selItemList.setSelected(i, TRUE, cb);
  534. }
  535. if (cb)
  536. notifySelChanged();
  537. return 1;
  538. }
  539. int ListWnd::deselectAll(int cb) {
  540. int lif = getItemFocused();
  541. if (lif != -1)
  542. invalidateItem(lif);
  543. lastItemFocused = NULL;
  544. for (int i = 0; i < itemList.getNumItems(); i++) {
  545. selItemList.setSelected(i, FALSE, cb);
  546. }
  547. if (cb)
  548. notifySelChanged();
  549. return 1;
  550. }
  551. void ListWnd::notifySelChanged(int item, int sel) {
  552. if (!getRedraw()) return;
  553. if (item == -1)
  554. notifyParent(ChildNotify::LISTWND_SELCHANGED);
  555. else
  556. notifyParent(ChildNotify::LISTWND_ITEMSELCHANGED, item, sel);
  557. }
  558. int ListWnd::invertSelection(int cb) {
  559. if (preventMultipleSelection) return 1;
  560. for (int i = 0; i < itemList.getNumItems(); i++) {
  561. toggleSelection(i, FALSE, cb);
  562. }
  563. return 1;
  564. }
  565. int ListWnd::invalidateItem(int pos) {
  566. RECT r;
  567. if (!isInited()) return 0;
  568. int rv = getItemRect(pos, &r);
  569. r.top -= item_invalidate_border;
  570. r.bottom += item_invalidate_border;
  571. if (rv)
  572. invalidateRect(&r);
  573. return rv;
  574. }
  575. int ListWnd::onLeftButtonDblClk(int x, int y) {
  576. // check for column dblclick
  577. int colhit;
  578. if ((colhit = hitTestColumns(Wasabi::Std::makePoint(x, y))) >= 0) {
  579. return onColumnDblClick(colhit, x, y);
  580. }
  581. if (itemList.getNumItems() == 0) return 0;
  582. POINT p={x,y};
  583. int i = hitTest(p);
  584. if (i > -1) {
  585. notifyParent(ChildNotify::LISTWND_DBLCLK, i, 0);
  586. onDoubleClick(i);
  587. return 1;
  588. }
  589. return 0;
  590. }
  591. int ListWnd::onRightButtonDown(int x, int y) {
  592. nodrag=TRUE;
  593. return 1;
  594. }
  595. int ListWnd::onRightButtonUp(int x, int y) {
  596. nodrag=FALSE;
  597. int i = hitTest(x,y);
  598. if (i >= 0) { // did hit something
  599. setItemFocused(i); // it always gets the focus
  600. if (!getItemSelected(i)) { // reselect the item out of the cur selection
  601. ListWnd::onLeftButtonDown(x,y); // don't call inherited!
  602. ListWnd::onLeftButtonUp(x,y); // don't call inherited!
  603. }
  604. onRightClick(i);
  605. } else {
  606. if (wantAutoDeselect())
  607. deselectAll();
  608. }
  609. onContextMenu(x,y);
  610. return 1;
  611. }
  612. int ListWnd::onRightClick(int itemnum) {
  613. return 0;
  614. }
  615. int ListWnd::onLeftButtonDown(int x, int y) {
  616. if (colresize != -1) {
  617. resizing_col = TRUE;
  618. drawXorLine(colresizept.x);
  619. }
  620. processbup = FALSE;
  621. bdown = TRUE;
  622. bdownx = x;
  623. bdowny = y;
  624. if (!resizing_col) {
  625. POINT p={x,y};
  626. int i = hitTest(p);
  627. if (i >= 0) {
  628. if (Std::keyDown(VK_SHIFT)) {
  629. if (getItemSelected(i))
  630. processbup=TRUE;
  631. else
  632. setSelectionEnd(i);
  633. } else
  634. if (Std::keyDown(VK_CONTROL)) {
  635. if (getItemSelected(i))
  636. processbup=TRUE;
  637. else
  638. toggleSelection(i);
  639. } else {
  640. if (getItemSelected(i))
  641. processbup = TRUE;
  642. else
  643. setSelectionStart(i);
  644. }
  645. } else {
  646. if (wantAutoDeselect())
  647. deselectAll();
  648. /*rectselecting=1;
  649. selectStart.x = x;
  650. selectStart.y = y;
  651. selectLast.x = x;
  652. selectLast.y = y;
  653. drawRect(selectStart.x, selectStart.y, x, y);
  654. beginCapture();*/
  655. }
  656. }
  657. return 1;
  658. }
  659. int ListWnd::onLeftButtonUp(int x, int y) {
  660. bdown = FALSE;
  661. if (resizing_col) {
  662. resizing_col = FALSE;
  663. drawXorLine(colresizept.x);
  664. calcNewColWidth(colresize, colresizept.x);
  665. recalcHeaders();
  666. return 1;
  667. }
  668. // check for column label click
  669. int colhit;
  670. if ((colhit = hitTestColumnsLabel(Wasabi::Std::makePoint(x, y))) >= 0) {
  671. ListColumn *lc = getColumn(colhit);
  672. int ret = lc->onHeaderClick();
  673. if (!ret) ret = onColumnLabelClick(colhit, x, y);
  674. return ret;
  675. }
  676. POINT p={x,y};
  677. int i = hitTest(p);
  678. if (rectselecting || (processbup && !resizing_col) || hoverselect) {
  679. if (i >= 0) {
  680. if (Std::keyDown(VK_SHIFT)) {
  681. if (getItemSelected(i))
  682. setSelectionStart(i);
  683. else
  684. setSelectionEnd(i);
  685. } else {
  686. if (Std::keyDown(VK_CONTROL) || !wantAutoDeselect()) {
  687. toggleSelection(i);
  688. selectionStart = i;
  689. } else {
  690. setSelectionStart(i);
  691. }
  692. }
  693. } else {
  694. /* if (rectselecting) {
  695. drawRect(selectStart.x, selectStart.y, selectLast.x, selectLast.y);
  696. endCapture();
  697. rectselecting=0;
  698. selectRect(selectStart.x, selectStart.y, x, y);
  699. } else*/
  700. if (wantAutoDeselect())
  701. deselectAll();
  702. }
  703. }
  704. if (i >= 0) {
  705. int cn = hitTestColumnClient(x);
  706. int r = 0;
  707. if (cn >= 0) {
  708. ListColumn *lc = getColumn(cn);
  709. ASSERT(lc != NULL);
  710. r = lc->onColumnLeftClick(i);
  711. }
  712. if (!r)
  713. {
  714. // Add 1px clickable border to our icon
  715. if (x < getIconWidth()+2) r = onIconLeftClick(i,x,y-(i*getItemHeight()) - getHeaderHeight());
  716. if (!r) onLeftClick(i);
  717. }
  718. }
  719. return 1;
  720. }
  721. int ListWnd::onMouseMove(int x, int y) {
  722. LISTWND_PARENT::onMouseMove(x,y);
  723. if (!bdown && (Std::keyDown(MK_RBUTTON) || Std::keyDown(MK_RBUTTON))) {
  724. bdown = TRUE;
  725. processbup = TRUE;
  726. _enterCapture();
  727. }
  728. if (!rectselecting && bdown && !resizing_col && !nodrag && (ABS(x-bdownx) >= 4 || ABS(y-bdowny) >= 4)) {
  729. processbup = FALSE;
  730. bdown = FALSE;
  731. int i = hitTest(x, y);
  732. if (i != -1) {
  733. onBeginDrag(i);
  734. return 1;
  735. }
  736. }
  737. /* if (rectselecting) {
  738. drawRect(selectStart.x, selectStart.y, selectLast.x, selectLast.y);
  739. selectLast.x = x;
  740. selectLast.y = y;
  741. drawRect(selectStart.x, selectStart.y, selectLast.x, selectLast.y);
  742. return 1;
  743. }*/
  744. POINT p={x,y};
  745. if (wantResizeCols()) {
  746. if (!resizing_col) {
  747. int c = hitTestColumns(p, &colresizeo);
  748. if (c != -1) {
  749. if (colresize != c) {
  750. SetCursor(LoadCursor(NULL, IDC_SIZEWE)); // NONPORTABLE
  751. if (!getCapture())
  752. beginCapture();
  753. colresize = c;
  754. colresizept = p;
  755. }
  756. } else {
  757. if (colresize != -1) {
  758. SetCursor(LoadCursor(NULL, IDC_ARROW)); // NONPORTABLE
  759. endCapture();
  760. colresize = -1;
  761. }
  762. }
  763. } else {
  764. if (p.x + getScrollX() < colresizeo + COLUMNS_MIN_WIDTH) {
  765. p.x = colresizeo + COLUMNS_MIN_WIDTH - getScrollX();
  766. }
  767. drawXorLine(colresizept.x);
  768. colresizept = p;
  769. drawXorLine(colresizept.x);
  770. }
  771. }
  772. if (hoverselect) {
  773. int i = hitTest(x, y);
  774. if (i >= 0 && !getItemSelected(i)) {
  775. deselectAll(0);
  776. setSelected(i, 1, 0);
  777. wchar_t t[256]=L"";
  778. getItemLabel(i, 0, t, 255);
  779. foreach(tempselectnotifies)
  780. sendAction(tempselectnotifies.getfor(), L"tempselectnotify", t);
  781. endfor;
  782. }
  783. }
  784. return 1;
  785. }
  786. // NONPORTABLE / Todo: implement necessary stuff in canvas
  787. void ListWnd::drawXorLine(int x) {
  788. HDC dc = GetDC(gethWnd());
  789. HBRUSH brush = CreateSolidBrush(0xFFFFFF);
  790. HPEN pen = CreatePen(PS_SOLID,0,0xFFFFFF);
  791. HBRUSH oldB = (HBRUSH)SelectObject(dc, brush);
  792. HPEN oldP = (HPEN)SelectObject(dc, pen);
  793. int mix = SetROP2(dc,R2_XORPEN);
  794. RECT r;
  795. getClientRect(&r);
  796. r.top -= getColumnsHeight();
  797. r.bottom = r.top + getColumnsHeight();
  798. if (renderRatioActive()) {
  799. multRatio(&x);
  800. multRatio(&r);
  801. }
  802. MoveToEx(dc, x, r.top, NULL);
  803. LineTo(dc, x, r.bottom);
  804. SelectObject(dc, oldB);
  805. SelectObject(dc, oldP);
  806. SetROP2(dc, mix);
  807. DeleteObject(pen);
  808. DeleteObject(brush);
  809. ReleaseDC(gethWnd(), dc);
  810. }
  811. void ListWnd::calcNewColWidth(int c, int px) {
  812. RECT r;
  813. getClientRect(&r);
  814. r.top -= getColumnsHeight();
  815. r.bottom = r.top + getColumnsHeight();
  816. px += getScrollX();
  817. int x = r.left+X_SHIFT;
  818. for (int i=0;i<columnsList.getNumItems();i++) {
  819. ListColumn *col = columnsList[i];
  820. if (col->getIndex() == c) {
  821. int w = px - x;
  822. col->setWidth(w);
  823. setSlidersPosition();
  824. return;
  825. }
  826. x += col->getWidth();
  827. }
  828. return;
  829. }
  830. int ListWnd::hitTestColumns(POINT p, int *origin) {
  831. RECT r;
  832. if (!showColumnsHeaders) return -1;
  833. int best=-1, besto = 0, bestd=9999;
  834. getClientRect(&r);
  835. r.top -= getColumnsHeight();
  836. r.bottom = r.top + getColumnsHeight();
  837. p.x += getScrollX();
  838. if (p.y > r.top && p.y < r.top + getColumnsHeight()) {
  839. int x = r.left+X_SHIFT;
  840. for (int i=0;i<columnsList.getNumItems();i++) {
  841. ListColumn *col = columnsList[i];
  842. x += col->getWidth();
  843. if (p.x > x-COLUMNS_RESIZE_THRESHOLD && p.x < x+COLUMNS_RESIZE_THRESHOLD) {
  844. int d = ABS(p.x-x);
  845. if (d < bestd) {
  846. bestd = d;
  847. besto = x - col->getWidth();
  848. best = col->getIndex();
  849. }
  850. }
  851. }
  852. }
  853. if (best != -1)
  854. if (origin != NULL) *origin = besto;
  855. return best;
  856. }
  857. int ListWnd::hitTestColumnClient(int x) {
  858. RECT cr = clientRect();
  859. int x1 = cr.left+X_SHIFT;
  860. foreach(columnsList)
  861. int x2 = x1 + columnsList.getfor()->getWidth();
  862. if (x >= x1 && x <= x2) return foreach_index;
  863. x1 = x2;
  864. endfor
  865. return -1;
  866. }
  867. void ListWnd::invalidateColumns() {
  868. RECT r;
  869. getClientRect(&r);
  870. r.top -= getColumnsHeight();
  871. r.bottom = r.top + getColumnsHeight();
  872. invalidateRect(&r);
  873. }
  874. int ListWnd::hitTestColumnsLabel(POINT p) {
  875. RECT r;
  876. if (!showColumnsHeaders) return -1;
  877. getClientRect(&r);
  878. r.top -= getColumnsHeight();
  879. r.bottom = r.top + getColumnsHeight();
  880. p.x += getScrollX();
  881. if (p.y > r.top && p.y < r.top + getColumnsHeight()) {
  882. int x = X_SHIFT;
  883. for (int i=0;i<columnsList.getNumItems();i++) {
  884. ListColumn *col = columnsList[i];
  885. if (p.x >= x && p.x <= x+col->getWidth())
  886. return i;
  887. x += col->getWidth();
  888. }
  889. }
  890. return -1;
  891. }
  892. void ListWnd::setSelectionStart(int pos, int wantcb) {
  893. if (wantAutoDeselect())
  894. deselectAll(wantcb);
  895. if (!selItemList.isSelected(pos)) {
  896. selItemList.setSelected(pos, TRUE, wantcb);
  897. lastItemFocused = itemList[pos];
  898. lastItemFocusedPos = pos;
  899. invalidateItem(pos);
  900. repaint();
  901. }
  902. selectionStart = pos;
  903. notifySelChanged();
  904. }
  905. void ListWnd::setSelectionEnd(int pos) {
  906. if (itemList.getNumItems() == 0) return;
  907. if (selectionStart == -1) selectionStart = 0;
  908. if (wantAutoDeselect())
  909. deselectAll();
  910. int inc = (selectionStart > pos) ? -1 : 1;
  911. int i = selectionStart;
  912. while (1) {
  913. if (!selItemList.isSelected(i)) {
  914. selItemList.setSelected(i, TRUE);
  915. lastItemFocused = itemList[i];
  916. lastItemFocusedPos = i;
  917. invalidateItem(i);
  918. }
  919. if (i == pos) break;
  920. i += inc;
  921. }
  922. notifySelChanged();
  923. }
  924. void ListWnd::setSelected(int pos, int selected, int cb) {
  925. selItemList.setSelected(pos, selected, cb);
  926. }
  927. void ListWnd::toggleSelection(int pos, int setfocus, int cb) {
  928. if (!selItemList.isSelected(pos)) {
  929. selItemList.setSelected(pos, TRUE, cb);
  930. if (setfocus) {
  931. if (selItemList.getNumSelected() > 1) {
  932. for (int i=0;i<itemList.getNumItems();i++)
  933. if (selItemList.isSelected(i))
  934. invalidateItem(i);
  935. }
  936. lastItemFocused = itemList[pos];
  937. lastItemFocusedPos = pos;
  938. }
  939. } else {
  940. selItemList.setSelected(pos, FALSE, cb);
  941. if (setfocus) {
  942. lastItemFocused = NULL;
  943. lastItemFocusedPos = -1;
  944. }
  945. }
  946. invalidateItem(pos);
  947. if (cb)
  948. notifySelChanged();
  949. }
  950. int ListWnd::onBeginDrag(int iItem) {
  951. // nothing by default
  952. lastItemFocused = NULL;
  953. lastItemFocusedPos = -1;
  954. invalidateItem(iItem);
  955. return 0;
  956. }
  957. int ListWnd::dragOver(int x, int y, ifc_window *sourceWnd) {
  958. int rt = LISTWND_PARENT::dragOver(x, y, sourceWnd);
  959. if (dragtimeron) return rt;
  960. POINT pos={x,y};
  961. screenToClient(&pos);
  962. int item = hitTest(pos);
  963. if (item == LW_HT_BELOW || item == LW_HT_ABOVE) {
  964. dragtimeron = 1;
  965. dragskip = DRAGSKIP_START;
  966. dragskipcount = DRAGSKIP_START-1; // start right away
  967. setTimer(LISTWND_DRAG_TIMERID, LISTWND_DRAG_TIMERDELAY);
  968. }
  969. return rt;
  970. }
  971. void ListWnd::onDragTimer() {
  972. POINT pos;
  973. Wasabi::Std::getMousePos(&pos);
  974. screenToClient(&pos);
  975. int item = hitTest(pos);
  976. if (item == LW_HT_BELOW || item == LW_HT_ABOVE) {
  977. dragskipcount++;
  978. if (dragskipcount >= dragskip) {
  979. switch (item) {
  980. case LW_HT_BELOW:
  981. scrollDown();
  982. break;
  983. case LW_HT_ABOVE:
  984. scrollUp();
  985. break;
  986. }
  987. dragskipcount = 0;
  988. if (dragskip > 0) dragskip--;
  989. }
  990. } else {
  991. killTimer(LISTWND_DRAG_TIMERID);
  992. dragtimeron = 0;
  993. }
  994. }
  995. void ListWnd::timerCallback(int id) {
  996. switch (id) {
  997. case LISTWND_DRAG_TIMERID:
  998. onDragTimer();
  999. return;
  1000. }
  1001. LISTWND_PARENT::timerCallback(id);
  1002. }
  1003. void ListWnd::onSelectAll() {
  1004. }
  1005. void ListWnd::onDelete() {
  1006. // do nothing by default
  1007. }
  1008. void ListWnd::onDoubleClick(int itemnum) {
  1009. // do nothing by default
  1010. }
  1011. void ListWnd::onLeftClick(int itemnum) {
  1012. // do nothing by default
  1013. }
  1014. int ListWnd::onIconLeftClick (int itemnum, int x, int y)
  1015. {
  1016. return 0;
  1017. }
  1018. void ListWnd::onSecondLeftClick(int itemnum) {
  1019. // do nothing by default
  1020. }
  1021. int ListWnd::scrollAbsolute(int x) {
  1022. scrollToX(x);
  1023. return getScrollX();
  1024. }
  1025. int ListWnd::scrollRelative(int x) {
  1026. scrollToX(getScrollX() + x);
  1027. return getScrollX();
  1028. }
  1029. int ListWnd::getItemFocused() {
  1030. if (lastItemFocused == NULL) return -1;
  1031. if (itemList[lastItemFocusedPos] == lastItemFocused)
  1032. return lastItemFocusedPos;
  1033. else {
  1034. lastItemFocusedPos = itemList.searchItem(lastItemFocused);
  1035. return lastItemFocusedPos;
  1036. }
  1037. }
  1038. void ListWnd::setItemFocused(int pos, int ensure_visible) {
  1039. invalidateItem(lastItemFocusedPos);
  1040. lastItemFocused = itemList[pos];
  1041. lastItemFocusedPos = -1;
  1042. if (lastItemFocused != NULL) lastItemFocusedPos = pos;
  1043. invalidateItem(lastItemFocusedPos);
  1044. if (ensure_visible) ensureItemVisible(pos);
  1045. }
  1046. int ListWnd::getItemRect(int pos, RECT *r) {
  1047. MEMSET(r, 0, sizeof(RECT));
  1048. if (pos < 0 || pos >= itemList.getNumItems()) return 0;
  1049. RECT cr={0,0,0,0};
  1050. getClientRect(&cr);
  1051. r->left = -getScrollX() + X_SHIFT + cr.left;
  1052. r->right = cr.left + getColumnsWidth();
  1053. if (showicons) r->right += getItemHeight();
  1054. r->top = -getScrollY() + pos * (getItemHeight() + (wantColSepOnItems() ? COLSEPHEIGHT : 0)) + Y_SHIFT + cr.top;
  1055. r->bottom = r->top + getItemHeight();
  1056. // clip!
  1057. if (r->top > cr.bottom || r->bottom < cr.top) return 0;
  1058. return 1;
  1059. }
  1060. int ListWnd::locateData(LPARAM data) { // linear search
  1061. for (int i=0;i<itemList.getNumItems();i++) {
  1062. if (itemList[i]->data == data)
  1063. return i;
  1064. }
  1065. return -1;
  1066. }
  1067. int ListWnd::getItemFocused(int pos) {
  1068. if (pos >= itemList.getNumItems()) return 0;
  1069. return getItemFocused() == pos;
  1070. }
  1071. int ListWnd::getItemSelected(int pos) {
  1072. listItem *item = itemList[pos];
  1073. return (item && selItemList.isSelected(pos));
  1074. }
  1075. int ListWnd::hitTest(POINT pos, int drag) {
  1076. RECT r;
  1077. getClientRect(&r);
  1078. if (pos.y < r.top) return LW_HT_ABOVE;
  1079. if (getScrollY() > 0 && drag && pos.y < r.top + LISTWND_DRAG_MARGIN) return LW_HT_ABOVE;
  1080. if (pos.y > r.bottom) return LW_HT_BELOW;
  1081. if (getContentsHeight() > (getScrollY() + r.bottom-r.top) && drag && pos.y > r.bottom - LISTWND_DRAG_MARGIN) return LW_HT_BELOW;
  1082. if (pos.x > r.left + getColumnsWidth() - getScrollX()) return LW_HT_DONTKNOW;
  1083. if (pos.x < r.left + getScrollX()) return LW_HT_DONTKNOW;
  1084. int i = (pos.y - r.top + getScrollY() - Y_SHIFT) / (getItemHeight() + (wantColSepOnItems() ? COLSEPHEIGHT : 0));
  1085. if (i >= itemList.getNumItems()) return LW_HT_DONTKNOW;
  1086. return i;
  1087. }
  1088. int ListWnd::hitTest(int x, int y, int drag) {
  1089. POINT pt={x, y};
  1090. return hitTest(pt, drag);
  1091. }
  1092. void ListWnd::selectRect(int x1, int y1, int x2, int y2) {
  1093. }
  1094. void ListWnd::drawRect(int x1, int y1, int x2, int y2) {
  1095. HDC dc = GetDC(gethWnd());
  1096. RECT r={x1,y1,x2,y2};
  1097. DrawFocusRect(dc, &r);
  1098. ReleaseDC(gethWnd(), dc);
  1099. }
  1100. LPARAM ListWnd::getItemData(int pos) {
  1101. if (pos >= itemList.getNumItems()) return 0;
  1102. listItem *item = itemList[pos];
  1103. if (item) return item->data;
  1104. return NULL;
  1105. }
  1106. int ListWnd::getItemLabel(int pos, int subpos, wchar_t *txt, int textmax)
  1107. {
  1108. const wchar_t *t = getSubitemText(pos, subpos);
  1109. if (t)
  1110. {
  1111. WCSCPYN(txt, t, textmax);
  1112. return 1;
  1113. }
  1114. return 0;
  1115. }
  1116. void ListWnd::setItemLabel(int pos, const wchar_t *text)
  1117. {
  1118. if (pos >= itemList.getNumItems()) return;
  1119. listItem *item = itemList[pos];
  1120. if (!item) return;
  1121. item->label = text;
  1122. invalidateItem(pos);
  1123. }
  1124. void ListWnd::resort() {
  1125. itemList.sort(TRUE);
  1126. invalidate();
  1127. }
  1128. int ListWnd::getSortDirection() {
  1129. return sortdir;
  1130. }
  1131. int ListWnd::getSortColumn() {
  1132. return sortcol;
  1133. }
  1134. void ListWnd::setSortDirection(int dir) {
  1135. sortdir=dir;
  1136. }
  1137. void ListWnd::setSortColumn(int col) {
  1138. sortcol=col;
  1139. }
  1140. int ListWnd::sortCompareItem(listItem *p1, listItem *p2)
  1141. {
  1142. const wchar_t *l1=p1->label;
  1143. const wchar_t *l2=p2->label;
  1144. int i;
  1145. if(sortcol!=0)
  1146. {
  1147. if (p1->subitems != NULL)
  1148. {
  1149. for (i=0;i<p1->subitems->getNumItems();i++)
  1150. {
  1151. listSubitemStruct *subitem = p1->subitems->enumItem(i);
  1152. if (subitem->column == sortcol)
  1153. {
  1154. l1=subitem->label;
  1155. break;
  1156. }
  1157. }
  1158. } else {
  1159. l1 = L"";
  1160. }
  1161. if (p2->subitems != NULL) {
  1162. for (i=0;i<p2->subitems->getNumItems();i++) {
  1163. listSubitemStruct *subitem = p2->subitems->enumItem(i);
  1164. if (subitem->column == sortcol) {
  1165. l2=subitem->label;
  1166. break;
  1167. }
  1168. }
  1169. } else {
  1170. l2 = L"";
  1171. }
  1172. }
  1173. if(!columnsList.enumItem(sortcol)->getNumeric()) {
  1174. if(!sortdir) return(WCSICMP(l1, l2));
  1175. else return(WCSICMP(l2, l1));
  1176. } else {
  1177. int a=WTOI(l1),b=WTOI(l2);
  1178. if(!sortdir) return a-b;
  1179. else return b-a;
  1180. }
  1181. }
  1182. int ListWnd::findItemByParam(LPARAM param) {
  1183. for (int i=0;i<itemList.getNumItems();i++) {
  1184. if (itemList[i]->data == param)
  1185. return i;
  1186. }
  1187. return -1;
  1188. }
  1189. void ListWnd::setItemParam(int pos, LPARAM param) {
  1190. if (pos >= itemList.getNumItems()) return;
  1191. itemList[pos]->data = param;
  1192. invalidateItem(pos);
  1193. }
  1194. int ListWnd::deleteByPos(int pos) {
  1195. listItem *item = itemList[pos];
  1196. if (item == NULL) return 0;
  1197. // selItemList.setSelected(pos, FALSE); // If you do not delete the item from the selItemList, you corrupt it for all item positions downstream of this one.
  1198. selItemList.deleteByPos(pos);
  1199. itemList.removeByPos(pos);
  1200. onItemDelete(item->data);
  1201. deleteListItem(item); item=NULL;
  1202. if (redraw) {
  1203. invalidate();
  1204. setSlidersPosition();
  1205. }
  1206. return 1;
  1207. }
  1208. void ListWnd::deleteAllItems() {
  1209. bool sav = getRedraw();
  1210. deselectAll();
  1211. setRedraw(FALSE);
  1212. selItemList.deselectAll(); //force desel so as to avoid the MEMCPY
  1213. while (itemList.getNumItems()) {
  1214. deleteByPos(0);
  1215. }
  1216. setRedraw(sav);
  1217. // setSlidersPosition();
  1218. }
  1219. void ListWnd::setSubItem(int pos, int subpos, const wchar_t *txt)
  1220. {
  1221. if (pos >= itemList.getNumItems()) return;
  1222. listItem *item = itemList[pos];
  1223. if (!item) return;
  1224. if (!item->subitems)
  1225. item->subitems = new PtrList<listSubitemStruct>;
  1226. for (int i=0;i<item->subitems->getNumItems();i++) {
  1227. listSubitemStruct *subitem = item->subitems->enumItem(i);
  1228. if (subitem->column == subpos) {
  1229. if (subitem->label) {
  1230. FREE(subitem->label);
  1231. subitem->label = NULL;
  1232. }
  1233. if (txt)
  1234. subitem->label = WCSDUP(txt);
  1235. invalidateItem(pos);
  1236. return;
  1237. }
  1238. }
  1239. listSubitemStruct *subitem = (listSubitemStruct *) MALLOC(sizeof(listSubitemStruct));
  1240. item->subitems->addItem(subitem);
  1241. subitem->label = WCSDUP(txt);
  1242. subitem->column = subpos;
  1243. invalidateItem(pos);
  1244. }
  1245. SkinBitmap *ListWnd::getItemIcon(int pos)
  1246. {
  1247. if (pos >= itemList.getNumItems()) return NULL;
  1248. listItem *item = itemList[pos];
  1249. return item->icon;
  1250. }
  1251. void ListWnd::setItemIcon(int pos, const wchar_t *bitmapid) {
  1252. if (pos >= itemList.getNumItems()) return;
  1253. listItem *item = itemList[pos];
  1254. item->icon = bitmapid;
  1255. invalidateItem(pos);
  1256. }
  1257. const wchar_t *ListWnd::getSubitemText(int pos, int subpos) {
  1258. if (pos >= itemList.getNumItems()) return NULL;
  1259. listItem *item = itemList[pos];
  1260. if (!item) return NULL;
  1261. if (subpos == 0) {
  1262. return item->label;
  1263. }
  1264. if (!item->subitems) return NULL;
  1265. for (int i=0;i<item->subitems->getNumItems();i++) {
  1266. listSubitemStruct *subitem = item->subitems->enumItem(i);
  1267. if (subitem->column == subpos) {
  1268. return subitem->label;
  1269. }
  1270. }
  1271. return NULL;
  1272. }
  1273. listItem *ListWnd::createListItem() {
  1274. listItem *item = listItem_freelist.getRecord();
  1275. new(item) listItem();
  1276. item->setList(this);
  1277. return item;
  1278. }
  1279. void ListWnd::deleteListItem(listItem *item) {
  1280. if (item == NULL) return;
  1281. item->~listItem();
  1282. listItem_freelist.freeRecord(item);
  1283. }
  1284. ListColumn *ListWnd::enumListColumn(int pos) {
  1285. return columnsList[pos];
  1286. }
  1287. int ListWnd::getColumnPosByName(const wchar_t *name)
  1288. {
  1289. for (int i = 0; i < columnsList.getNumItems(); i++)
  1290. {
  1291. const wchar_t *name2 = columnsList[i]->getName();
  1292. if (name2 == NULL) continue;
  1293. if (!wcscmp(name, name2)) return i;
  1294. }
  1295. return -1;
  1296. }
  1297. int ListWnd::delColumnByPos(int pos) {
  1298. if (pos < 0 || pos >= columnsList.getNumItems()) return 0;
  1299. delete columnsList[pos];
  1300. columnsList.removeByPos(pos);
  1301. recalcHeaders();
  1302. return 1;
  1303. }
  1304. void ListWnd::recalcHeaders() {
  1305. if (getNumColumns() <= 0) return;
  1306. int wid = 0, ndynamic = 0;
  1307. for (int i = 0; i < getNumColumns(); i++) {
  1308. ListColumn *col = enumListColumn(i);
  1309. if (!col->isDynamic()) wid += col->getWidth()+COLUMNS_MARGIN-1;
  1310. else ndynamic++;
  1311. }
  1312. if (ndynamic == 0) return;
  1313. RECT r = clientRect();
  1314. int wwidth = (r.right - r.left) - 2;
  1315. int leftover = wwidth - wid;
  1316. if (leftover <= 1) return;
  1317. leftover--;
  1318. leftover /= ndynamic;
  1319. for (int i = 0; i < getNumColumns(); i++) {
  1320. ListColumn *col = enumListColumn(i);
  1321. if (col->isDynamic()) col->setWidth(leftover);
  1322. }
  1323. //BU note: we could probably find a way to not invalidate everything
  1324. invalidate();
  1325. }
  1326. void ListWnd::itemSelection(int itemnum, int selected) {
  1327. notifySelChanged(itemnum, selected);
  1328. onItemSelection(itemnum, selected);
  1329. }
  1330. void ListWnd::onItemSelection(int itemnum, int selected) {
  1331. if (selected) {
  1332. Accessible *a = getAccessibleObject();
  1333. if (a != NULL)
  1334. a->onGetFocus(itemnum);
  1335. }
  1336. }
  1337. int ListWnd::doAddItem(const wchar_t *label, LPARAM lParam, int pos)
  1338. {
  1339. listItem *item = createListItem();
  1340. item->label = label;
  1341. item->data = lParam;
  1342. itemList.addItem(item, pos, ITEMLIST_INC);
  1343. lastAddedItem = item;
  1344. if (redraw)
  1345. {
  1346. invalidate(); // todo: optimize to invalidate only if necessary
  1347. setSlidersPosition();
  1348. }
  1349. if (isInited()) calcBounds();
  1350. int p = (pos == POS_LAST) ? itemList.getNumItems()-1 : pos;
  1351. if (p <= selectionStart) selectionStart++;
  1352. if (autosort) {
  1353. itemList.sort();
  1354. p = itemList.searchItem(item);
  1355. }
  1356. return p;
  1357. }
  1358. void ListWnd::setMinimumSize(int size) {
  1359. if (size > 0) itemList.setMinimumSize(size);
  1360. }
  1361. int ListWnd::addItem(const wchar_t *label, LPARAM lParam)
  1362. {
  1363. return doAddItem(label, lParam, POS_LAST);
  1364. }
  1365. int ListWnd::insertItem(int pos, const wchar_t *label, LPARAM lParam)
  1366. {
  1367. return doAddItem(label, lParam, pos);
  1368. }
  1369. int ListWnd::getLastAddedItemPos() {
  1370. if (lastAddedItem == NULL) return -1;
  1371. return itemList.searchItem(lastAddedItem);
  1372. }
  1373. int ListWnd::getColumnsHeight() {
  1374. return columnsHeight;
  1375. }
  1376. int ListWnd::getColumnsWidth() {
  1377. int i, x=0;
  1378. for (i=0;i<columnsList.getNumItems();i++) x+= columnsList[i]->getWidth();
  1379. return x+1;
  1380. }
  1381. int ListWnd::insertColumn(ListColumn *col, int pos, int alignment)
  1382. {
  1383. ASSERT(col != NULL);
  1384. ASSERT(pos >= -1);
  1385. if (pos < 0) col->setIndex(columnsList.getNumItems());
  1386. else col->setIndex(pos);
  1387. col->setList(this);
  1388. col->setAlignment(alignment);
  1389. columnsList.addItem(col);
  1390. if (pos >= 0) {
  1391. columnsList.moveItem(columnsList.getNumItems()-1, pos);
  1392. }
  1393. if (redraw && isInited()) {
  1394. invalidate();
  1395. setSlidersPosition();
  1396. }
  1397. recalcHeaders();
  1398. return columnsList.getNumItems();
  1399. }
  1400. void ListWnd::deleteAllColumns() {
  1401. columnsList.deleteAll();
  1402. if (redraw && isInited()) {
  1403. invalidate();
  1404. setSlidersPosition();
  1405. }
  1406. recalcHeaders();
  1407. }
  1408. int ListWnd::addColumn(const wchar_t *name, int width, int numeric, int align)
  1409. {
  1410. ListColumn *col = new ListColumn();
  1411. col->setWidth(width);
  1412. col->setLabel(name);
  1413. col->setNumeric(numeric);
  1414. col->setAlignment(align);
  1415. return insertColumn(col, -1, align);
  1416. }
  1417. bool ListWnd::setRedraw(bool _redraw) {
  1418. bool prev = redraw;
  1419. if (!redraw && _redraw) {
  1420. invalidate();
  1421. setSlidersPosition();
  1422. notifySelChanged();
  1423. }
  1424. redraw = _redraw;
  1425. return prev;
  1426. }
  1427. bool ListWnd::getRedraw() {
  1428. return redraw;
  1429. }
  1430. int ListWnd::onChar(unsigned int c) {
  1431. //CT> Commented this out so shortcuts work in playlist editor
  1432. /*char b = TOUPPER(c);
  1433. if (b >= 'A' && b <= 'Z') {
  1434. jumpToNext(b);
  1435. return 1;
  1436. }*/
  1437. return LISTWND_PARENT::onChar(c);
  1438. }
  1439. int ListWnd::onKeyDown(int keyCode) {
  1440. switch (keyCode) {
  1441. case VK_DOWN:
  1442. next(selectonupdown);
  1443. return 1;
  1444. case VK_UP:
  1445. previous(selectonupdown);
  1446. return 1;
  1447. case VK_PRIOR:
  1448. pageup(selectonupdown);
  1449. return 1;
  1450. case VK_NEXT:
  1451. pagedown(selectonupdown);
  1452. return 1;
  1453. case VK_HOME:
  1454. home(selectonupdown);
  1455. return 1;
  1456. case VK_END:
  1457. end(selectonupdown);
  1458. return 1;
  1459. case VK_DELETE:
  1460. onDelete();
  1461. return 1;
  1462. case VK_RETURN: {
  1463. int i=getItemFocused();
  1464. //setSelected(i, 0, 0);
  1465. //setSelected(i, 1, 1);
  1466. if(i!=-1)
  1467. onDoubleClick(i);
  1468. return 1;
  1469. }
  1470. }
  1471. return LISTWND_PARENT::onKeyDown(keyCode);
  1472. }
  1473. void ListWnd::next(int wantcb) {
  1474. int from=getItemFocused();
  1475. /* if (selItemList.getNumItems() > 0)
  1476. for (int i=0;i<itemList.getNumItems();i++)
  1477. if (getItemSelected(i)) {
  1478. from = i;
  1479. break;
  1480. }*/
  1481. int to = from + 1;
  1482. if (to < itemList.getNumItems() && to >= 0) {
  1483. setSelectionStart(to, wantcb);
  1484. if (!fullyVisible(to)) {
  1485. RECT c;
  1486. getClientRect(&c);
  1487. scrollToY((Y_SHIFT*2+(to+1)*(getItemHeight()+(wantColSepOnItems()?COLSEPHEIGHT:0)))-(c.bottom-c.top));
  1488. }
  1489. if (!wantcb)
  1490. {
  1491. wchar_t t[256]=L"";
  1492. getItemLabel(to, 0, t, 255);
  1493. foreach(tempselectnotifies)
  1494. sendAction(tempselectnotifies.getfor(), L"tempselectnotify", t);
  1495. endfor;
  1496. }
  1497. }
  1498. }
  1499. void ListWnd::selectCurrent() {
  1500. int from=getItemFocused();
  1501. int to = from;
  1502. if (to < itemList.getNumItems() && to >= 0) {
  1503. setSelectionStart(to);
  1504. if (!fullyVisible(to)) {
  1505. RECT c;
  1506. getClientRect(&c);
  1507. scrollToY((Y_SHIFT*2+(to+1)*(getItemHeight()+(wantColSepOnItems()?COLSEPHEIGHT:0)))-(c.bottom-c.top));
  1508. }
  1509. }
  1510. }
  1511. void ListWnd::selectFirstEntry(int wantcb) {
  1512. setSelectionStart(0, wantcb);
  1513. ensureItemVisible(0);
  1514. }
  1515. void ListWnd::previous(int wantcb) {
  1516. int from=0;
  1517. /* if (selItemList.getNumItems() > 0)
  1518. for (int i=0;i<itemList.getNumItems();i++)
  1519. if (getItemSelected(i)) {
  1520. from = i;
  1521. break;
  1522. }*/
  1523. from = getItemFocused();
  1524. int to = from - 1;
  1525. if (to < itemList.getNumItems() && to >= 0) {
  1526. setSelectionStart(to, wantcb);
  1527. ensureItemVisible(to);
  1528. if (!wantcb) {
  1529. wchar_t t[256]=L"";
  1530. getItemLabel(to, 0, t, 255);
  1531. foreach(tempselectnotifies)
  1532. sendAction(tempselectnotifies.getfor(), L"tempselectnotify", t);
  1533. endfor;
  1534. }
  1535. }
  1536. }
  1537. void ListWnd::pagedown(int wantcb) {
  1538. int from=-1,to;
  1539. if (selItemList.getNumSelected())
  1540. for (int i=0;i<itemList.getNumItems();i++)
  1541. if (getItemSelected(i)) {
  1542. from = i;
  1543. break;
  1544. }
  1545. if(from==-1) to = 0;
  1546. else to = from + getLinesPerPage();
  1547. to=MIN(to,itemList.getNumItems()-1);
  1548. if(to>=0) {
  1549. setSelectionStart(to, wantcb);
  1550. if (!fullyVisible(to)) {
  1551. RECT c;
  1552. getClientRect(&c);
  1553. scrollToY((Y_SHIFT*2+(to+1)*(getItemHeight()+(wantColSepOnItems()?COLSEPHEIGHT:0)))-(c.bottom-c.top));
  1554. }
  1555. if (!wantcb) {
  1556. wchar_t t[256]=L"";
  1557. getItemLabel(to, 0, t, 255);
  1558. foreach(tempselectnotifies)
  1559. sendAction(tempselectnotifies.getfor(), L"tempselectnotify", t);
  1560. endfor;
  1561. }
  1562. }
  1563. }
  1564. void ListWnd::pageup(int wantcb) {
  1565. int from=-1,to;
  1566. if (selItemList.getNumSelected())
  1567. for (int i=0;i<itemList.getNumItems();i++)
  1568. if (getItemSelected(i)) {
  1569. from = i;
  1570. break;
  1571. }
  1572. if(from==-1) to = 0;
  1573. else to = from - getLinesPerPage();
  1574. to=MAX(to,0);
  1575. to=MIN(to,itemList.getNumItems()-1);
  1576. if(to>=0) {
  1577. setSelectionStart(to, wantcb);
  1578. ensureItemVisible(to);
  1579. if (!wantcb) {
  1580. wchar_t t[256]=L"";
  1581. getItemLabel(to, 0, t, 255);
  1582. foreach(tempselectnotifies)
  1583. sendAction(tempselectnotifies.getfor(), L"tempselectnotify", t);
  1584. endfor;
  1585. }
  1586. }
  1587. }
  1588. void ListWnd::home(int wantcb) {
  1589. if(!itemList.getNumItems()) return;
  1590. setSelectionStart(0, wantcb);
  1591. ensureItemVisible(0);
  1592. if (!wantcb) {
  1593. wchar_t t[256]=L"";
  1594. getItemLabel(0, 0, t, 255);
  1595. foreach(tempselectnotifies)
  1596. sendAction(tempselectnotifies.getfor(), L"tempselectnotify", t);
  1597. endfor;
  1598. }
  1599. }
  1600. void ListWnd::end(int wantcb) {
  1601. if(!itemList.getNumItems()) return;
  1602. int i=itemList.getNumItems()-1;
  1603. setSelectionStart(i, wantcb);
  1604. if (!fullyVisible(i)) {
  1605. RECT c;
  1606. getClientRect(&c);
  1607. scrollToY((Y_SHIFT*2+(i+1)*(getItemHeight()+(wantColSepOnItems()?COLSEPHEIGHT:0)))-(c.bottom-c.top));
  1608. }
  1609. if (!wantcb) {
  1610. wchar_t t[256]=L"";
  1611. getItemLabel(i, 0, t, 255);
  1612. foreach(tempselectnotifies)
  1613. sendAction(tempselectnotifies.getfor(), L"tempselectnotify", t);
  1614. endfor;
  1615. }
  1616. }
  1617. void ListWnd::jumpToNext(wchar_t c)
  1618. {
  1619. if (doJumpToNext(c, FALSE)) return;
  1620. doJumpToNext(c, TRUE);
  1621. }
  1622. int ListWnd::doJumpToNext(wchar_t c, bool fromtop)
  1623. {
  1624. int from = 0;
  1625. if (!fromtop && selItemList.getNumSelected())
  1626. {
  1627. for (int i=0;i<itemList.getNumItems();i++)
  1628. if (getItemSelected(i))
  1629. {
  1630. from = i+1;
  1631. break;
  1632. }
  1633. }
  1634. for (int j=from;j<itemList.getNumItems();j++)
  1635. {
  1636. listItem *item = itemList[j];
  1637. if (item->label != NULL) {
  1638. wchar_t z = TOUPPERW(*(item->label));
  1639. if (z == c)
  1640. {
  1641. setSelectionStart(j);
  1642. ensureItemVisible(j);
  1643. return 1;
  1644. }
  1645. }
  1646. }
  1647. return 0;
  1648. }
  1649. void ListWnd::reset() {
  1650. columnsList.deleteAll();
  1651. deleteAllItems();
  1652. }
  1653. void ListWnd::setShowColumnsHeaders(int show) {
  1654. int prev = showColumnsHeaders;
  1655. showColumnsHeaders = !!show;
  1656. if (prev != show) {
  1657. invalidate();
  1658. }
  1659. }
  1660. int ListWnd::onContextMenu (int x, int y) {
  1661. return notifyParent(ChildNotify::LISTWND_POPUPMENU, x, y);
  1662. }
  1663. void ListWnd::scrollUp(int lines) {
  1664. scrollToY(MAX(0, getScrollY()-getItemHeight()*lines));
  1665. }
  1666. void ListWnd::scrollLeft(int lines) {
  1667. scrollToX(MAX(0, getScrollX()-getItemHeight()*lines));
  1668. }
  1669. void ListWnd::scrollDown(int lines) {
  1670. scrollToY(MIN(getMaxScrollY(), getScrollY()+getItemHeight()*lines));
  1671. }
  1672. void ListWnd::scrollRight(int lines) {
  1673. scrollToX(MIN(getMaxScrollX(), getScrollX()+getItemHeight()*lines));
  1674. }
  1675. int ListWnd::onMouseWheelUp(int clicked, int lines) {
  1676. lines *= Wasabi::Std::osparam_getScrollLines();
  1677. if (!clicked)
  1678. scrollUp(lines);
  1679. else
  1680. scrollLeft(lines);
  1681. return 1;
  1682. }
  1683. int ListWnd::onMouseWheelDown(int clicked, int lines) {
  1684. lines *= Wasabi::Std::osparam_getScrollLines();
  1685. if (!clicked)
  1686. scrollDown(lines);
  1687. else
  1688. scrollRight(lines);
  1689. return 1;
  1690. }
  1691. int ListWnd::onColumnLabelClick(int col, int x, int y)
  1692. {
  1693. if(lastcolsort==col) {
  1694. setSortDirection(1);
  1695. lastcolsort=-1;
  1696. } else {
  1697. setSortDirection(0);
  1698. lastcolsort=col;
  1699. }
  1700. setSortColumn(col);
  1701. resort();
  1702. return 1;
  1703. }
  1704. ARGB32 ListWnd::getTextColor(LPARAM lParam) {
  1705. return textColor;
  1706. }
  1707. ARGB32 ListWnd::getSelBgColor(LPARAM LParam) {
  1708. return color_item_selected;
  1709. }
  1710. ARGB32 ListWnd::getSelFgColor(LPARAM LParam) {
  1711. ARGB32 r = color_item_selected_fg;
  1712. if (r == 0xFFFFFFFF)
  1713. return color_item_selected_fg;
  1714. return r;
  1715. }
  1716. ARGB32 ListWnd::getBgColor() {
  1717. return bgcolor;
  1718. }
  1719. ARGB32 ListWnd::getFocusColor(LPARAM LParam) {
  1720. return color_item_focused;
  1721. }
  1722. ARGB32 ListWnd::getFocusRectColor(LPARAM lParam) {
  1723. return color_item_focusrect;
  1724. }
  1725. void ListWnd::moveItem(int from, int to) {
  1726. itemList.moveItem(from,to);
  1727. invalidate();
  1728. }
  1729. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1730. // ListColumn
  1731. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1732. ListColumn::ListColumn(const wchar_t *name, int isdynamic)
  1733. : NamedW(name), dynamic(isdynamic)
  1734. {
  1735. align=COL_LEFTALIGN;
  1736. index = -1;
  1737. width = COLUMNS_DEFAULT_WIDTH;
  1738. list = NULL;
  1739. numeric = 0;
  1740. }
  1741. void ListColumn::setLabel(const wchar_t *newlabel) {
  1742. setName(newlabel);
  1743. }
  1744. const wchar_t *ListColumn::getLabel() {
  1745. return getName();
  1746. }
  1747. void ListColumn::setIndex(int newindex) {
  1748. index = newindex;
  1749. }
  1750. int ListColumn::getIndex() {
  1751. return index;
  1752. }
  1753. void ListColumn::setWidth(int _width) {
  1754. width = _width;
  1755. if (list && list->getRedraw()) {
  1756. list->invalidate();
  1757. }
  1758. }
  1759. int ListColumn::getWidth() {
  1760. return width;
  1761. }
  1762. int ListColumn::customDrawHeader(Canvas *c, RECT *r, const Wasabi::FontInfo *fontInfo)
  1763. {
  1764. int y = (r->bottom-r->top-c->getTextHeight(fontInfo)) / 2;
  1765. c->textOutEllipsed(r->left, y, r->right-r->left, c->getTextHeight(fontInfo), _(getName()), fontInfo);
  1766. return 1;
  1767. }
  1768. void ListColumn::setDynamic(int isdynamic)
  1769. {
  1770. int prev = dynamic;
  1771. dynamic = !!isdynamic;
  1772. if (prev != dynamic && dynamic && list != NULL)
  1773. list->recalcHeaders();
  1774. }
  1775. void ListColumn::setList(ListWnd *_list) {
  1776. list = _list;
  1777. }
  1778. ListWnd *ListColumn::getList() {
  1779. return list;
  1780. }
  1781. int ListWnd::wantAutoContextMenu() {
  1782. return 0;
  1783. }
  1784. int ListWnd::onAcceleratorEvent(const wchar_t *name) {
  1785. if(!_wcsicmp(name, L"selectall")) {
  1786. selectAll();
  1787. return 1;
  1788. }
  1789. return 0;
  1790. }
  1791. int ListWnd::onAction(const wchar_t *action, const wchar_t *param, int x, int y, intptr_t p1, intptr_t p2, void *data, size_t datalen, ifc_window *source) {
  1792. int r = LISTWND_PARENT::onAction(action, param, x, y, p1, p2, data, datalen, source);
  1793. if (WCSCASEEQLSAFE(action, L"register_tempselectnotify")) {
  1794. tempselectnotifies.addItem(source);
  1795. }
  1796. else if (WCSCASEEQLSAFE(action, L"up")) {
  1797. previous((int)p1);
  1798. }
  1799. else if (WCSCASEEQLSAFE(action, L"down")) {
  1800. next((int)p1);
  1801. }
  1802. else if (WCSCASEEQLSAFE(action, L"home")) {
  1803. home((int)p1);
  1804. }
  1805. else if (WCSCASEEQLSAFE(action, L"end")) {
  1806. end((int)p1);
  1807. }
  1808. else if (WCSCASEEQLSAFE(action, L"pageup")) {
  1809. pageup((int)p1);
  1810. }
  1811. else if (WCSCASEEQLSAFE(action, L"pagedown")) {
  1812. pagedown((int)p1);
  1813. }
  1814. else if (WCSCASEEQLSAFE(action, L"select_current")) {
  1815. selectCurrent();
  1816. }
  1817. else if (WCSCASEEQLSAFE(action, L"doubleclick")) {
  1818. int pos = getItemFocused();
  1819. if (pos >= 0) onDoubleClick(pos);
  1820. return 1;
  1821. }
  1822. return r;
  1823. }
  1824. void ListWnd::setShowIcons(int icons)
  1825. {
  1826. showicons = icons;
  1827. invalidate();
  1828. }
  1829. int ListWnd::getShowIcons ()
  1830. {
  1831. return showicons;
  1832. }
  1833. int ListWnd::getIconWidth ()
  1834. {
  1835. // The old behaviour used the itemheight as value, so we return this for backwards compatibility if iconWidth is negative
  1836. return (iconWidth < 0 ? itemHeight-2 : iconWidth);
  1837. }
  1838. void ListWnd::setIconWidth (int width)
  1839. {
  1840. iconWidth = width;
  1841. invalidate();
  1842. }
  1843. int ListWnd::getIconHeight ()
  1844. {
  1845. // The old behaviour used the itemheight as value, so we return this for backwards compatibility if iconWidth is negative
  1846. return (iconHeight < 0 ? itemHeight-2 : iconHeight);
  1847. }
  1848. void ListWnd::setIconHeight (int height)
  1849. {
  1850. iconHeight = height;
  1851. invalidate();
  1852. }
  1853. int ListWnd::getItemHeight ()
  1854. {
  1855. return (itemHeight < getIconHeight()+2) ? getIconHeight()+2 : itemHeight;
  1856. }
  1857. void ListWnd::setItemHeight (int height, bool forceInvalidate /*true*/)
  1858. {
  1859. itemHeight = height;
  1860. if (forceInvalidate) invalidate();
  1861. }