QListCtrl.cpp 61 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334
  1. // QListCtrl.cpp : implementation file
  2. //
  3. #include "stdafx.h"
  4. #include "CP_Main.h"
  5. #include "QListCtrl.h"
  6. #include "ProcessPaste.h"
  7. #include "BitmapHelper.h"
  8. #include "MainTableFunctions.h"
  9. #include "DittoCopyBuffer.h"
  10. #include <atlbase.h>
  11. #include "DrawHTML.h"
  12. #include "..\Shared\TextConvert.h"
  13. #include <cmath>
  14. #include <vector>
  15. #include <string>
  16. #include <cwchar> // For swscanf
  17. #include <algorithm> // For std::round
  18. #include <gdiplus.h>
  19. #ifdef _DEBUG
  20. #define new DEBUG_NEW
  21. #undef THIS_FILE
  22. static char THIS_FILE[] = __FILE__;
  23. #endif
  24. #define ROW_BOTTOM_BORDER 4
  25. #define ROW_LEFT_BORDER 3
  26. #define COLOR_SHADOW RGB(245, 245, 245)
  27. #define DUMMY_COL_WIDTH 2
  28. #define TIMER_SHOW_PROPERTIES 1
  29. #define TIMER_HIDE_SCROL 2
  30. #define TIMER_SHOW_SCROLL 3
  31. #define VALID_TOOLTIP (m_pToolTip && ::IsWindow(m_pToolTip->m_hWnd))
  32. #ifndef M_PI
  33. #define M_PI 3.14159265358979323846
  34. #endif
  35. // Static map to hold W3C color names and their RGB values
  36. static std::map<CString, COLORREF> g_colorNameMap;
  37. static CMutex g_colorNameMapMutex;
  38. // Initializes the color map on first use
  39. void InitializeColorNameMap()
  40. {
  41. CSingleLock lock(&g_colorNameMapMutex, TRUE);
  42. if (g_colorNameMap.empty())
  43. {
  44. // Populate the map with W3C named colors
  45. // A comprehensive list of 148 colors
  46. g_colorNameMap[_T("black")] = RGB(0, 0, 0);
  47. g_colorNameMap[_T("silver")] = RGB(192, 192, 192);
  48. g_colorNameMap[_T("gray")] = RGB(128, 128, 128);
  49. g_colorNameMap[_T("white")] = RGB(255, 255, 255);
  50. g_colorNameMap[_T("maroon")] = RGB(128, 0, 0);
  51. g_colorNameMap[_T("red")] = RGB(255, 0, 0);
  52. g_colorNameMap[_T("purple")] = RGB(128, 0, 128);
  53. g_colorNameMap[_T("fuchsia")] = RGB(255, 0, 255);
  54. g_colorNameMap[_T("green")] = RGB(0, 128, 0);
  55. g_colorNameMap[_T("lime")] = RGB(0, 255, 0);
  56. g_colorNameMap[_T("olive")] = RGB(128, 128, 0);
  57. g_colorNameMap[_T("yellow")] = RGB(255, 255, 0);
  58. g_colorNameMap[_T("navy")] = RGB(0, 0, 128);
  59. g_colorNameMap[_T("blue")] = RGB(0, 0, 255);
  60. g_colorNameMap[_T("teal")] = RGB(0, 128, 128);
  61. g_colorNameMap[_T("aqua")] = RGB(0, 255, 255);
  62. g_colorNameMap[_T("aliceblue")] = RGB(240, 248, 255);
  63. g_colorNameMap[_T("antiquewhite")] = RGB(250, 235, 215);
  64. g_colorNameMap[_T("aquamarine")] = RGB(127, 255, 212);
  65. g_colorNameMap[_T("azure")] = RGB(240, 255, 255);
  66. g_colorNameMap[_T("beige")] = RGB(245, 245, 220);
  67. g_colorNameMap[_T("bisque")] = RGB(255, 228, 196);
  68. g_colorNameMap[_T("blanchedalmond")] = RGB(255, 235, 205);
  69. g_colorNameMap[_T("blueviolet")] = RGB(138, 43, 226);
  70. g_colorNameMap[_T("brown")] = RGB(165, 42, 42);
  71. g_colorNameMap[_T("burlywood")] = RGB(222, 184, 135);
  72. g_colorNameMap[_T("cadetblue")] = RGB(95, 158, 160);
  73. g_colorNameMap[_T("chartreuse")] = RGB(127, 255, 0);
  74. g_colorNameMap[_T("chocolate")] = RGB(210, 105, 30);
  75. g_colorNameMap[_T("coral")] = RGB(255, 127, 80);
  76. g_colorNameMap[_T("cornflowerblue")] = RGB(100, 149, 237);
  77. g_colorNameMap[_T("cornsilk")] = RGB(255, 248, 220);
  78. g_colorNameMap[_T("crimson")] = RGB(220, 20, 60);
  79. g_colorNameMap[_T("cyan")] = RGB(0, 255, 255);
  80. g_colorNameMap[_T("darkblue")] = RGB(0, 0, 139);
  81. g_colorNameMap[_T("darkcyan")] = RGB(0, 139, 139);
  82. g_colorNameMap[_T("darkgoldenrod")] = RGB(184, 134, 11);
  83. g_colorNameMap[_T("darkgray")] = RGB(169, 169, 169);
  84. g_colorNameMap[_T("darkgreen")] = RGB(0, 100, 0);
  85. g_colorNameMap[_T("darkkhaki")] = RGB(189, 183, 107);
  86. g_colorNameMap[_T("darkmagenta")] = RGB(139, 0, 139);
  87. g_colorNameMap[_T("darkolivegreen")] = RGB(85, 107, 47);
  88. g_colorNameMap[_T("darkorange")] = RGB(255, 140, 0);
  89. g_colorNameMap[_T("darkorchid")] = RGB(153, 50, 204);
  90. g_colorNameMap[_T("darkred")] = RGB(139, 0, 0);
  91. g_colorNameMap[_T("darksalmon")] = RGB(233, 150, 122);
  92. g_colorNameMap[_T("darkseagreen")] = RGB(143, 188, 143);
  93. g_colorNameMap[_T("darkslateblue")] = RGB(72, 61, 139);
  94. g_colorNameMap[_T("darkslategray")] = RGB(47, 79, 79);
  95. g_colorNameMap[_T("darkturquoise")] = RGB(0, 206, 209);
  96. g_colorNameMap[_T("darkviolet")] = RGB(148, 0, 211);
  97. g_colorNameMap[_T("deeppink")] = RGB(255, 20, 147);
  98. g_colorNameMap[_T("deepskyblue")] = RGB(0, 191, 255);
  99. g_colorNameMap[_T("dimgray")] = RGB(105, 105, 105);
  100. g_colorNameMap[_T("dodgerblue")] = RGB(30, 144, 255);
  101. g_colorNameMap[_T("firebrick")] = RGB(178, 34, 34);
  102. g_colorNameMap[_T("floralwhite")] = RGB(255, 250, 240);
  103. g_colorNameMap[_T("forestgreen")] = RGB(34, 139, 34);
  104. g_colorNameMap[_T("gainsboro")] = RGB(220, 220, 220);
  105. g_colorNameMap[_T("ghostwhite")] = RGB(248, 248, 255);
  106. g_colorNameMap[_T("gold")] = RGB(255, 215, 0);
  107. g_colorNameMap[_T("goldenrod")] = RGB(218, 165, 32);
  108. g_colorNameMap[_T("greenyellow")] = RGB(173, 255, 47);
  109. g_colorNameMap[_T("honeydew")] = RGB(240, 255, 240);
  110. g_colorNameMap[_T("hotpink")] = RGB(255, 105, 180);
  111. g_colorNameMap[_T("indianred")] = RGB(205, 92, 92);
  112. g_colorNameMap[_T("indigo")] = RGB(75, 0, 130);
  113. g_colorNameMap[_T("ivory")] = RGB(255, 255, 240);
  114. g_colorNameMap[_T("khaki")] = RGB(240, 230, 140);
  115. g_colorNameMap[_T("lavender")] = RGB(230, 230, 250);
  116. g_colorNameMap[_T("lavenderblush")] = RGB(255, 240, 245);
  117. g_colorNameMap[_T("lawngreen")] = RGB(124, 252, 0);
  118. g_colorNameMap[_T("lemonchiffon")] = RGB(255, 250, 205);
  119. g_colorNameMap[_T("lightblue")] = RGB(173, 216, 230);
  120. g_colorNameMap[_T("lightcoral")] = RGB(240, 128, 128);
  121. g_colorNameMap[_T("lightcyan")] = RGB(224, 255, 255);
  122. g_colorNameMap[_T("lightgoldenrodyellow")] = RGB(250, 250, 210);
  123. g_colorNameMap[_T("lightgray")] = RGB(211, 211, 211);
  124. g_colorNameMap[_T("lightgreen")] = RGB(144, 238, 144);
  125. g_colorNameMap[_T("lightpink")] = RGB(255, 182, 193);
  126. g_colorNameMap[_T("lightsalmon")] = RGB(255, 160, 122);
  127. g_colorNameMap[_T("lightseagreen")] = RGB(32, 178, 170);
  128. g_colorNameMap[_T("lightskyblue")] = RGB(135, 206, 250);
  129. g_colorNameMap[_T("lightslategray")] = RGB(119, 136, 153);
  130. g_colorNameMap[_T("lightsteelblue")] = RGB(176, 196, 222);
  131. g_colorNameMap[_T("lightyellow")] = RGB(255, 255, 224);
  132. g_colorNameMap[_T("limegreen")] = RGB(50, 205, 50);
  133. g_colorNameMap[_T("linen")] = RGB(250, 240, 230);
  134. g_colorNameMap[_T("magenta")] = RGB(255, 0, 255);
  135. g_colorNameMap[_T("mediumaquamarine")] = RGB(102, 205, 170);
  136. g_colorNameMap[_T("mediumblue")] = RGB(0, 0, 205);
  137. g_colorNameMap[_T("mediumorchid")] = RGB(186, 85, 211);
  138. g_colorNameMap[_T("mediumpurple")] = RGB(147, 112, 219);
  139. g_colorNameMap[_T("mediumseagreen")] = RGB(60, 179, 113);
  140. g_colorNameMap[_T("mediumslateblue")] = RGB(123, 104, 238);
  141. g_colorNameMap[_T("mediumspringgreen")] = RGB(0, 250, 154);
  142. g_colorNameMap[_T("mediumturquoise")] = RGB(72, 209, 204);
  143. g_colorNameMap[_T("mediumvioletred")] = RGB(199, 21, 133);
  144. g_colorNameMap[_T("midnightblue")] = RGB(25, 25, 112);
  145. g_colorNameMap[_T("mintcream")] = RGB(245, 255, 250);
  146. g_colorNameMap[_T("mistyrose")] = RGB(255, 228, 225);
  147. g_colorNameMap[_T("moccasin")] = RGB(255, 228, 181);
  148. g_colorNameMap[_T("navajowhite")] = RGB(255, 222, 173);
  149. g_colorNameMap[_T("oldlace")] = RGB(253, 245, 230);
  150. g_colorNameMap[_T("olivedrab")] = RGB(107, 142, 35);
  151. g_colorNameMap[_T("orange")] = RGB(255, 165, 0);
  152. g_colorNameMap[_T("orangered")] = RGB(255, 69, 0);
  153. g_colorNameMap[_T("orchid")] = RGB(218, 112, 214);
  154. g_colorNameMap[_T("palegoldenrod")] = RGB(238, 232, 170);
  155. g_colorNameMap[_T("palegreen")] = RGB(152, 251, 152);
  156. g_colorNameMap[_T("paleturquoise")] = RGB(175, 238, 238);
  157. g_colorNameMap[_T("palevioletred")] = RGB(219, 112, 147);
  158. g_colorNameMap[_T("papayawhip")] = RGB(255, 239, 213);
  159. g_colorNameMap[_T("peachpuff")] = RGB(255, 218, 185);
  160. g_colorNameMap[_T("peru")] = RGB(205, 133, 63);
  161. g_colorNameMap[_T("pink")] = RGB(255, 192, 203);
  162. g_colorNameMap[_T("plum")] = RGB(221, 160, 221);
  163. g_colorNameMap[_T("powderblue")] = RGB(176, 224, 230);
  164. g_colorNameMap[_T("rebeccapurple")] = RGB(102, 51, 153);
  165. g_colorNameMap[_T("rosybrown")] = RGB(188, 143, 143);
  166. g_colorNameMap[_T("royalblue")] = RGB(65, 105, 225);
  167. g_colorNameMap[_T("saddlebrown")] = RGB(139, 69, 19);
  168. g_colorNameMap[_T("salmon")] = RGB(250, 128, 114);
  169. g_colorNameMap[_T("sandybrown")] = RGB(244, 164, 96);
  170. g_colorNameMap[_T("seagreen")] = RGB(46, 139, 87);
  171. g_colorNameMap[_T("seashell")] = RGB(255, 245, 238);
  172. g_colorNameMap[_T("sienna")] = RGB(160, 82, 45);
  173. g_colorNameMap[_T("skyblue")] = RGB(135, 206, 235);
  174. g_colorNameMap[_T("slateblue")] = RGB(106, 90, 205);
  175. g_colorNameMap[_T("slategray")] = RGB(112, 128, 144);
  176. g_colorNameMap[_T("snow")] = RGB(255, 250, 250);
  177. g_colorNameMap[_T("springgreen")] = RGB(0, 255, 127);
  178. g_colorNameMap[_T("steelblue")] = RGB(70, 130, 180);
  179. g_colorNameMap[_T("tan")] = RGB(210, 180, 140);
  180. g_colorNameMap[_T("thistle")] = RGB(216, 191, 216);
  181. g_colorNameMap[_T("tomato")] = RGB(255, 99, 71);
  182. g_colorNameMap[_T("turquoise")] = RGB(64, 224, 208);
  183. g_colorNameMap[_T("violet")] = RGB(238, 130, 238);
  184. g_colorNameMap[_T("wheat")] = RGB(245, 222, 179);
  185. g_colorNameMap[_T("whitesmoke")] = RGB(245, 245, 245);
  186. g_colorNameMap[_T("yellowgreen")] = RGB(154, 205, 50);
  187. }
  188. }
  189. /////////////////////////////////////////////////////////////////////////////
  190. // CQListCtrl
  191. CQListCtrl::CQListCtrl()
  192. {
  193. m_pchTip = NULL;
  194. m_pwchTip = NULL;
  195. m_linesPerRow = 1;
  196. m_windowDpi = NULL;
  197. m_SmallFont = NULL;
  198. m_pToolTip = NULL;
  199. m_pFormatter = NULL;
  200. m_allSelected = false;
  201. m_rowHeight = 50;
  202. m_mouseOverScrollAreaStart = 0;
  203. m_showIfClipWasPasted = TRUE;
  204. m_bShowTextForFirstTenHotKeys = true;
  205. m_pToolTipActions = NULL;
  206. }
  207. CQListCtrl::~CQListCtrl()
  208. {
  209. if (m_pchTip != NULL)
  210. delete m_pchTip;
  211. if (m_pwchTip != NULL)
  212. delete m_pwchTip;
  213. if (m_SmallFont)
  214. ::DeleteObject(m_SmallFont);
  215. m_Font.DeleteObject();
  216. m_boldFont.DeleteObject();
  217. if (m_pFormatter)
  218. {
  219. delete m_pFormatter;
  220. m_pFormatter = NULL;
  221. }
  222. }
  223. // returns the position 1-10 if the index is in the FirstTen block else -1
  224. int CQListCtrl::GetFirstTenNum(int index)
  225. {
  226. // set firstTenNum to the first ten number (1-10) corresponding to the given index
  227. int firstTenNum = -1; // -1 means that nItem is not in the FirstTen block.
  228. int count = GetItemCount();
  229. if (0 <= index && index <= 9)
  230. {
  231. firstTenNum = index + CGetSetOptions::m_firstTenHotKeysStart;
  232. firstTenNum = firstTenNum % 10;
  233. }
  234. return firstTenNum;
  235. }
  236. BEGIN_MESSAGE_MAP(CQListCtrl, CListCtrl)
  237. //{{AFX_MSG_MAP(CQListCtrl)
  238. ON_NOTIFY_REFLECT(LVN_KEYDOWN, OnKeydown)
  239. ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomdrawList)
  240. ON_WM_MOUSEMOVE()
  241. ON_WM_SYSKEYDOWN()
  242. ON_WM_ERASEBKGND()
  243. ON_WM_CREATE()
  244. ON_WM_HSCROLL()
  245. ON_WM_TIMER()
  246. ON_NOTIFY_REFLECT(LVN_ITEMCHANGED, OnSelectionChange)
  247. ON_WM_VSCROLL()
  248. ON_WM_WINDOWPOSCHANGED()
  249. //}}AFX_MSG_MAP
  250. ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText)
  251. ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipText)
  252. ON_WM_KILLFOCUS()
  253. ON_WM_MEASUREITEM_REFLECT()
  254. ON_WM_MOUSEHWHEEL()
  255. END_MESSAGE_MAP()
  256. /////////////////////////////////////////////////////////////////////////////
  257. // CQListCtrl message handlers
  258. void CQListCtrl::OnKeydown(NMHDR* pNMHDR, LRESULT* pResult)
  259. {
  260. LV_KEYDOWN* pLVKeyDown = (LV_KEYDOWN*)pNMHDR;
  261. *pResult = 0;
  262. }
  263. DROPEFFECT CQListCtrl::OnDragOver(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point)
  264. {
  265. return DROPEFFECT_COPY;
  266. }
  267. void CQListCtrl::GetSelectionIndexes(ARRAY& arr)
  268. {
  269. arr.RemoveAll();
  270. POSITION pos = GetFirstSelectedItemPosition();
  271. while (pos)
  272. {
  273. arr.Add(GetNextSelectedItem(pos));
  274. }
  275. }
  276. bool CQListCtrl::PutSelectedItemOnDittoCopyBuffer(long lBuffer)
  277. {
  278. bool bRet = false;
  279. ARRAY arr;
  280. GetSelectionItemData(arr);
  281. INT_PTR nCount = arr.GetSize();
  282. if (nCount > 0 && arr[0])
  283. {
  284. CDittoCopyBuffer::PutClipOnDittoCopyBuffer(arr[0], lBuffer);
  285. bRet = true;
  286. }
  287. return bRet;
  288. }
  289. void CQListCtrl::GetSelectionItemData(ARRAY& arr)
  290. {
  291. DWORD dwData;
  292. int i;
  293. arr.RemoveAll();
  294. POSITION pos = GetFirstSelectedItemPosition();
  295. while (pos)
  296. {
  297. i = GetNextSelectedItem(pos);
  298. dwData = GetItemData(i);
  299. arr.Add(dwData);
  300. }
  301. }
  302. void CQListCtrl::RemoveAllSelection()
  303. {
  304. POSITION pos = GetFirstSelectedItemPosition();
  305. while (pos)
  306. {
  307. SetSelection(GetNextSelectedItem(pos), FALSE);
  308. }
  309. }
  310. BOOL CQListCtrl::SetSelection(int nRow, BOOL bSelect)
  311. {
  312. if (bSelect)
  313. return SetItemState(nRow, LVIS_SELECTED, LVIS_SELECTED);
  314. else
  315. return SetItemState(nRow, ~LVIS_SELECTED, LVIS_SELECTED);
  316. }
  317. BOOL CQListCtrl::SetText(int nRow, int nCol, CString cs)
  318. {
  319. return SetItemText(nRow, nCol, cs);
  320. }
  321. BOOL CQListCtrl::SetCaret(int nRow, BOOL bFocus)
  322. {
  323. if (bFocus)
  324. return SetItemState(nRow, LVIS_FOCUSED, LVIS_FOCUSED);
  325. else
  326. return SetItemState(nRow, ~LVIS_FOCUSED, LVIS_FOCUSED);
  327. }
  328. long CQListCtrl::GetCaret()
  329. {
  330. return GetNextItem(-1, LVNI_FOCUSED);
  331. }
  332. // moves the caret to the given index, selects it, and ensures it is visible.
  333. BOOL CQListCtrl::SetListPos(int index)
  334. {
  335. if (index < 0 || index >= GetItemCount())
  336. return FALSE;
  337. RemoveAllSelection();
  338. SetCaret(index);
  339. SetSelection(index);
  340. ListView_SetSelectionMark(m_hWnd, index);
  341. EnsureVisible(index, FALSE);
  342. return TRUE;
  343. }
  344. BOOL CQListCtrl::SetFormattedText(int nRow, int nCol, LPCTSTR lpszFormat, ...)
  345. {
  346. CString csText;
  347. va_list vlist;
  348. ASSERT(AfxIsValidString(lpszFormat));
  349. va_start(vlist, lpszFormat);
  350. csText.FormatV(lpszFormat, vlist);
  351. va_end(vlist);
  352. return SetText(nRow, nCol, csText);
  353. }
  354. void CQListCtrl::SetNumberOfLinesPerRow(int nLines, bool force)
  355. {
  356. if (m_linesPerRow != nLines ||
  357. force)
  358. {
  359. m_linesPerRow = nLines;
  360. CRect rc;
  361. GetWindowRect(&rc);
  362. WINDOWPOS wp;
  363. wp.hwnd = m_hWnd;
  364. wp.cx = rc.Width();
  365. wp.cy = rc.Height();
  366. wp.flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER;
  367. SendMessage(WM_WINDOWPOSCHANGED, 0, (LPARAM)&wp);
  368. }
  369. }
  370. void CQListCtrl::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
  371. {
  372. TEXTMETRIC tm;
  373. HDC hDC = ::GetDC(NULL);
  374. CFont* pFont = GetFont();
  375. HFONT hFontOld = (HFONT)SelectObject(hDC, pFont->GetSafeHandle());
  376. GetTextMetrics(hDC, &tm);
  377. if (m_windowDpi != NULL)
  378. {
  379. lpMeasureItemStruct->itemHeight = ((tm.tmHeight + tm.tmExternalLeading) * m_linesPerRow) + m_windowDpi->Scale(ROW_BOTTOM_BORDER);
  380. m_rowHeight = lpMeasureItemStruct->itemHeight;
  381. }
  382. SelectObject(hDC, hFontOld);
  383. ::ReleaseDC(NULL, hDC);
  384. }
  385. void CQListCtrl::OnCustomdrawList(NMHDR* pNMHDR, LRESULT* pResult)
  386. {
  387. NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>(pNMHDR);
  388. *pResult = 0;
  389. // Request item-specific notifications if this is the
  390. // beginning of the paint cycle.
  391. if (CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage)
  392. {
  393. *pResult = CDRF_NOTIFYITEMDRAW;
  394. }
  395. else if (CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage)
  396. {
  397. LVITEM rItem;
  398. int nItem = static_cast<int>(pLVCD->nmcd.dwItemSpec);
  399. CDC* pDC = CDC::FromHandle(pLVCD->nmcd.hdc);
  400. COLORREF crBkgnd;
  401. BOOL bListHasFocus;
  402. CRect rcItem;
  403. bListHasFocus = (GetSafeHwnd() == ::GetFocus());
  404. // Get the image index and selected/focused state of the
  405. // item being drawn.
  406. ZeroMemory(&rItem, sizeof(LVITEM));
  407. rItem.mask = LVIF_STATE;
  408. rItem.iItem = nItem;
  409. rItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
  410. GetItem(&rItem);
  411. // Get the rect that bounds the text label.
  412. GetItemRect(nItem, rcItem, LVIR_SELECTBOUNDS);
  413. COLORREF OldColor = -1;
  414. int nOldBKMode = -1;
  415. CString csText;
  416. LPTSTR lpszText = csText.GetBufferSetLength(CGetSetOptions::m_bDescTextSize);
  417. GetItemText(nItem, 0, lpszText, CGetSetOptions::m_bDescTextSize);
  418. csText.ReleaseBuffer();
  419. // extract symbols
  420. CString strSymbols;
  421. int nSymEnd = csText.Find('|');
  422. if (nSymEnd >= 0)
  423. {
  424. strSymbols = csText.Left(nSymEnd);
  425. csText = csText.Mid(nSymEnd + 1);
  426. }
  427. // Draw the background of the list item. Colors are selected
  428. // according to the item's state.
  429. if (rItem.state & LVIS_SELECTED)
  430. {
  431. if (bListHasFocus)
  432. {
  433. crBkgnd = CGetSetOptions::m_Theme.ListBoxSelectedBG();
  434. OldColor = pDC->SetTextColor(CGetSetOptions::m_Theme.ListBoxSelectedText());
  435. }
  436. else
  437. {
  438. crBkgnd = CGetSetOptions::m_Theme.ListBoxSelectedNoFocusBG();
  439. OldColor = pDC->SetTextColor(CGetSetOptions::m_Theme.ListBoxSelectedNoFocusText());
  440. }
  441. }
  442. else
  443. {
  444. //Shade alternating Rows
  445. if ((nItem % 2) == 0)
  446. {
  447. crBkgnd = CGetSetOptions::m_Theme.ListBoxOddRowsBG();
  448. OldColor = pDC->SetTextColor(CGetSetOptions::m_Theme.ListBoxOddRowsText());
  449. }
  450. else
  451. {
  452. crBkgnd = CGetSetOptions::m_Theme.ListBoxEvenRowsBG();
  453. OldColor = pDC->SetTextColor(CGetSetOptions::m_Theme.ListBoxEvenRowsText());
  454. }
  455. }
  456. pDC->FillSolidRect(rcItem, crBkgnd);
  457. nOldBKMode = pDC->SetBkMode(TRANSPARENT);
  458. CRect rcText = rcItem;
  459. rcText.left += m_windowDpi->Scale(ROW_LEFT_BORDER);
  460. rcText.top += m_windowDpi->Scale(1);
  461. rcText.bottom -= m_windowDpi->Scale(1);
  462. if (m_showIfClipWasPasted &&
  463. strSymbols.GetLength() > 0 &&
  464. strSymbols.Find(_T("<pasted>")) >= 0) //clip was pasted from ditto
  465. {
  466. CRect pastedRect(rcItem);
  467. pastedRect.left++;
  468. pastedRect.right = pastedRect.left + m_windowDpi->Scale(2);
  469. pDC->FillSolidRect(pastedRect, CGetSetOptions::m_Theme.ClipPastedColor());
  470. }
  471. // set firstTenNum to the first ten number (1-10) corresponding to
  472. // the current nItem.
  473. // -1 means that nItem is not in the FirstTen block.
  474. int firstTenNum = GetFirstTenNum(nItem);
  475. if (m_bShowTextForFirstTenHotKeys && firstTenNum >= 0)
  476. {
  477. rcText.left += m_windowDpi->Scale(12);
  478. }
  479. else
  480. {
  481. rcText.left += m_windowDpi->Scale(3);
  482. }
  483. bool drawInGroupIcon = true;
  484. // if we are inside a group, don't display the "in group" flag
  485. if (theApp.m_GroupID > 0)
  486. {
  487. int nFlag = strSymbols.Find(_T("<ingroup>"));
  488. if (nFlag >= 0)
  489. drawInGroupIcon = false;
  490. }
  491. DrawCopiedColorCode(csText, rcText, pDC);
  492. DrawBitMap(nItem, rcText, pDC, csText);
  493. // draw the symbol box
  494. if (strSymbols.GetLength() > 0)
  495. {
  496. if (strSymbols.Find(_T("<group>")) >= 0) //group
  497. {
  498. m_groupFolder.Draw(pDC, *m_windowDpi, this, rcText.left, rcText.top, false, false);
  499. rcText.left += m_groupFolder.ImageWidth() + m_windowDpi->Scale(2);
  500. }
  501. if (strSymbols.Find(_T("<noautodelete>")) >= 0) //don't auto delete
  502. {
  503. m_dontDeleteImage.Draw(pDC, *m_windowDpi, this, rcText.left, rcText.top, false, false);
  504. rcText.left += m_dontDeleteImage.ImageWidth() + m_windowDpi->Scale(2);
  505. }
  506. if (strSymbols.Find(_T("<shortcut>")) >= 0) // has shortcut
  507. {
  508. m_shortCutImage.Draw(pDC, *m_windowDpi, this, rcText.left, rcText.top, false, false);
  509. rcText.left += m_shortCutImage.ImageWidth() + m_windowDpi->Scale(2);
  510. }
  511. if (drawInGroupIcon &&
  512. strSymbols.Find(_T("<ingroup>")) >= 0) // in group
  513. {
  514. m_inFolderImage.Draw(pDC, *m_windowDpi, this, rcText.left, rcText.top, false, false);
  515. rcText.left += m_inFolderImage.ImageWidth() + m_windowDpi->Scale(2);
  516. }
  517. if (strSymbols.Find(_T("<qpastetext>")) >= 0) // has quick paste text
  518. {
  519. }
  520. if (strSymbols.Find(_T("<sticky>")) >= 0) //sticky clip
  521. {
  522. m_stickyImage.Draw(pDC, *m_windowDpi, this, rcText.left, rcText.top, false, false);
  523. rcText.left += m_stickyImage.ImageWidth() + m_windowDpi->Scale(2);
  524. }
  525. }
  526. if (DrawRtfText(nItem, rcText, pDC) == FALSE)
  527. {
  528. auto highlightColor = CGetSetOptions::m_Theme.SearchTextHighlight();
  529. //use unprintable characters so it doesn't find copied html to convert
  530. if (m_searchText.GetLength() > 0 &&
  531. FindNoCaseAndInsert(csText, m_searchText, StrF(_T("\x01\x04 color='#%02x%02x%02x'\x02"), GetRValue(highlightColor), GetGValue(highlightColor), GetBValue(highlightColor)), _T("\x01\x03\x04\x02"), m_linesPerRow) > 0)
  532. {
  533. DrawHTML(pDC->m_hDC, csText, csText.GetLength(), rcText, DT_VCENTER | DT_EXPANDTABS | DT_NOPREFIX);
  534. }
  535. else
  536. {
  537. pDC->DrawText(csText, rcText, DT_VCENTER | DT_EXPANDTABS | DT_NOPREFIX);
  538. }
  539. }
  540. // Draw a focus rect around the item if necessary.
  541. //if(bListHasFocus && (rItem.state & LVIS_FOCUSED))
  542. // pDC->DrawFocusRect(rcItem);
  543. if (m_bShowTextForFirstTenHotKeys && firstTenNum >= 0)
  544. {
  545. CString cs;
  546. if (firstTenNum == 10)
  547. cs = "0";
  548. else
  549. cs.Format(_T("%d"), firstTenNum);
  550. CRect crClient;
  551. GetWindowRect(crClient);
  552. ScreenToClient(crClient);
  553. CRect crHotKey = rcItem;
  554. int extraFromClipWasPaste = 0;
  555. if (m_showIfClipWasPasted)
  556. extraFromClipWasPaste = 3;
  557. crHotKey.right = crHotKey.left + m_windowDpi->Scale(11);
  558. crHotKey.left += m_windowDpi->Scale(1 + extraFromClipWasPaste);
  559. crHotKey.top += m_windowDpi->Scale(1 + extraFromClipWasPaste);
  560. HFONT hOldFont = (HFONT)pDC->SelectObject(m_SmallFont);
  561. COLORREF localOldTextColor = pDC->SetTextColor(CGetSetOptions::m_Theme.ListSmallQuickPasteIndexColor());
  562. CPen pen(PS_SOLID, 0, CGetSetOptions::m_Theme.ListSmallQuickPasteIndexColor());
  563. CPen* pOldPen = pDC->SelectObject(&pen);
  564. pDC->DrawText(cs, crHotKey, DT_BOTTOM);
  565. pDC->MoveTo(CPoint(rcItem.left + m_windowDpi->Scale(8 + extraFromClipWasPaste), rcItem.top));
  566. pDC->LineTo(CPoint(rcItem.left + m_windowDpi->Scale(8 + extraFromClipWasPaste), rcItem.bottom));
  567. pDC->SelectObject(hOldFont);
  568. pDC->SetTextColor(localOldTextColor);
  569. pDC->SelectObject(pOldPen);
  570. }
  571. // restore the previous values
  572. if (OldColor > -1)
  573. pDC->SetTextColor(OldColor);
  574. if (nOldBKMode > -1)
  575. pDC->SetBkMode(nOldBKMode);
  576. *pResult = CDRF_SKIPDEFAULT; // We've painted everything.
  577. }
  578. }
  579. // Helper function implementation to check for valid hex characters
  580. bool CQListCtrl::IsHexString(const CString& str)
  581. {
  582. if (str.IsEmpty()) {
  583. return false;
  584. }
  585. for (int i = 0; i < str.GetLength(); ++i) {
  586. if (!iswxdigit(str[i])) {
  587. return false;
  588. }
  589. }
  590. return true;
  591. }
  592. // Helper function implementation for HSL to RGB conversion
  593. COLORREF CQListCtrl::HslToRgb(double h, double s, double l)
  594. {
  595. // Input h(0-360), s(0-1), l(0-1)
  596. // Output COLORREF (RGB)
  597. double r, g, b;
  598. if (s == 0)
  599. {
  600. r = g = b = l; // Achromatic (gray)
  601. }
  602. else
  603. {
  604. auto hue2rgb = [&](double p, double q, double t)
  605. {
  606. if (t < 0) t += 1;
  607. if (t > 1) t -= 1;
  608. if (t < 1.0 / 6.0) return p + (q - p) * 6 * t;
  609. if (t < 1.0 / 2.0) return q;
  610. if (t < 2.0 / 3.0) return p + (q - p) * (2.0 / 3.0 - t) * 6;
  611. return p;
  612. };
  613. // Normalize h to 0-1 range
  614. double h_norm = h / 360.0;
  615. double q = l < 0.5 ? l * (1 + s) : l + s - l * s;
  616. double p = 2 * l - q;
  617. r = hue2rgb(p, q, h_norm + 1.0 / 3.0);
  618. g = hue2rgb(p, q, h_norm);
  619. b = hue2rgb(p, q, h_norm - 1.0 / 3.0);
  620. }
  621. // Scale RGB values to 0-255 and round
  622. int R = static_cast<int>(std::round(r * 255));
  623. int G = static_cast<int>(std::round(g * 255));
  624. int B = static_cast<int>(std::round(b * 255));
  625. // Clamp values to 0-255 just in case of floating point inaccuracies
  626. R = max(0, min(255, R));
  627. G = max(0, min(255, G));
  628. B = max(0, min(255, B));
  629. return RGB(R, G, B);
  630. }
  631. // Helper function to parse a CSS numeric value which can be a percentage or a number
  632. static bool ParseCssValue(const CString& token, double& value)
  633. {
  634. CString localToken = token;
  635. localToken.Trim();
  636. if (localToken.IsEmpty()) return false;
  637. bool isPercent = (localToken.Right(1) == _T('%'));
  638. if (isPercent)
  639. {
  640. localToken.TrimRight(_T('%'));
  641. }
  642. if (_stscanf(localToken, _T("%lf"), &value) == 1)
  643. {
  644. return true;
  645. }
  646. return false;
  647. }
  648. // Converts a color from OKLCH color space to sRGB.
  649. // l: 0-1, c: 0-0.4 (theoretically unbounded, but practically small), h: 0-360
  650. static COLORREF OklchToRgb(double l, double c, double h)
  651. {
  652. // 1. Convert OKLCH to OKLAB
  653. double h_rad = h * M_PI / 180.0;
  654. double a = c * cos(h_rad);
  655. double b = c * sin(h_rad);
  656. // 2. Convert OKLAB to XYZ
  657. // First, convert to an intermediate non-linear LMS-like space
  658. double l_ = l + 0.3963377774 * a + 0.2158037573 * b;
  659. double m_ = l - 0.1055613458 * a - 0.0638541728 * b;
  660. double s_ = l - 0.0894841775 * a - 1.2914855480 * b;
  661. // Then, convert to linear LMS by undoing the cube-root non-linearity
  662. double l_linear = l_ * l_ * l_;
  663. double m_linear = m_ * m_ * m_;
  664. double s_linear = s_ * s_ * s_;
  665. // Finally, convert linear LMS to XYZ color space
  666. double x = +1.2270138511 * l_linear - 0.5577999807 * m_linear + 0.2812561490 * s_linear;
  667. double y = -0.0405801784 * l_linear + 1.1122568696 * m_linear - 0.0716766787 * s_linear;
  668. double z = -0.0763812845 * l_linear - 0.4214819784 * m_linear + 1.5861632204 * s_linear;
  669. // 3. Convert XYZ to linear sRGB
  670. double r_linear = +3.2404542 * x - 1.5371385 * y - 0.4985314 * z;
  671. double g_linear = -0.9692660 * x + 1.8760108 * y + 0.0415560 * z;
  672. double b_linear = +0.0556434 * x - 0.2040259 * y + 1.0572252 * z;
  673. // 4. Convert linear sRGB to gamma-corrected sRGB
  674. auto ToSrgb = [](double val) {
  675. if (val <= 0.0031308) {
  676. return 12.92 * val;
  677. }
  678. return 1.055 * pow(val, 1.0 / 2.4) - 0.055;
  679. };
  680. double r_srgb = ToSrgb(r_linear);
  681. double g_srgb = ToSrgb(g_linear);
  682. double b_srgb = ToSrgb(b_linear);
  683. // 5. Scale to 0-255 and clamp (for out-of-gamut colors)
  684. int R = static_cast<int>(std::round(r_srgb * 255.0));
  685. int G = static_cast<int>(std::round(g_srgb * 255.0));
  686. int B = static_cast<int>(std::round(b_srgb * 255.0));
  687. R = max(0, min(255, R));
  688. G = max(0, min(255, G));
  689. B = max(0, min(255, B));
  690. return RGB(R, G, B);
  691. }
  692. void CQListCtrl::DrawCheckerboard(CDC* pDC, CRect rect)
  693. {
  694. COLORREF color1 = RGB(255, 255, 255); // White
  695. COLORREF color2 = RGB(204, 204, 204); // Light grey
  696. int squareSize = m_windowDpi->Scale(4);
  697. if (squareSize <= 0)
  698. {
  699. squareSize = 4;
  700. }
  701. for (int y = rect.top; y < rect.bottom; y += squareSize)
  702. {
  703. for (int x = rect.left; x < rect.right; x += squareSize)
  704. {
  705. COLORREF color = ((( (x - rect.left) / squareSize) + ((y - rect.top) / squareSize)) % 2 == 0) ? color1 : color2;
  706. CRect square(x, y, min(x + squareSize, rect.right), min(y + squareSize, rect.bottom));
  707. pDC->FillSolidRect(square, color);
  708. }
  709. }
  710. }
  711. void CQListCtrl::DrawCopiedColorCode(CString& csText, CRect& rcText, CDC* pDC)
  712. {
  713. if (CGetSetOptions::m_bDrawCopiedColorCode == FALSE || csText.IsEmpty())
  714. return;
  715. // 1. Initial Cleaning and Prep
  716. CString cleanedText = csText;
  717. cleanedText.Trim(_T("»"));
  718. cleanedText.Trim();
  719. cleanedText.TrimRight(_T(";"));
  720. cleanedText.Trim();
  721. if (cleanedText.IsEmpty())
  722. return;
  723. CString originalCleanedText = cleanedText;
  724. CString parseText = cleanedText;
  725. parseText.MakeLower();
  726. // 2. Helper lambda to draw the color box
  727. auto DrawColorBox = [&](COLORREF color, int alpha = 255)
  728. {
  729. CRect pastedRect(rcText);
  730. int boxSize = rcText.Height();
  731. pastedRect.right = pastedRect.left + boxSize;
  732. pastedRect.bottom = pastedRect.top + boxSize;
  733. if (alpha < 255)
  734. {
  735. DrawCheckerboard(pDC, pastedRect);
  736. // Use GDI+ for alpha blending
  737. Gdiplus::Graphics graphics(pDC->GetSafeHdc());
  738. Gdiplus::Color gdiplusColor(alpha, GetRValue(color), GetGValue(color), GetBValue(color));
  739. Gdiplus::SolidBrush brush(gdiplusColor);
  740. graphics.FillRectangle(&brush, Gdiplus::Rect(pastedRect.left, pastedRect.top, pastedRect.Width(), pastedRect.Height()));
  741. }
  742. else
  743. {
  744. // Opaque color is faster with FillSolidRect and doesn't need a checkerboard.
  745. pDC->FillSolidRect(pastedRect, color);
  746. }
  747. rcText.left += boxSize + m_windowDpi->Scale(ROW_LEFT_BORDER);
  748. csText = originalCleanedText;
  749. };
  750. // 3. Check for formats with unique signatures first
  751. // Check for W3C Named Colors
  752. InitializeColorNameMap();
  753. auto it = g_colorNameMap.find(parseText);
  754. if (it != g_colorNameMap.end())
  755. {
  756. DrawColorBox(it->second);
  757. return;
  758. }
  759. // Check for Hex Colors with # or 0x prefix
  760. if (parseText.Left(1) == _T('#') || parseText.Left(2) == _T("0x"))
  761. {
  762. CString hexString = parseText;
  763. if (hexString.Left(1) == _T('#')) hexString.Delete(0, 1);
  764. else if (hexString.Left(2) == _T("0x")) hexString.Delete(0, 2);
  765. int len = hexString.GetLength();
  766. if (len == 3 || len == 4) // Expand shorthand
  767. {
  768. CString expanded;
  769. for (int i = 0; i < len; ++i) { expanded += hexString[i]; expanded += hexString[i]; }
  770. hexString = expanded;
  771. }
  772. if (IsHexString(hexString) && (hexString.GetLength() == 6 || hexString.GetLength() == 8))
  773. {
  774. unsigned int r = 0, g = 0, b = 0, a = 255;
  775. if (hexString.GetLength() == 8)
  776. {
  777. if (swscanf(hexString, _T("%2x%2x%2x%2x"), &r, &g, &b, &a) == 4)
  778. {
  779. DrawColorBox(RGB(r, g, b), a);
  780. return;
  781. }
  782. }
  783. else // length is 6
  784. {
  785. if (swscanf(hexString, _T("%2x%2x%2x"), &r, &g, &b) == 3)
  786. {
  787. DrawColorBox(RGB(r, g, b)); // default alpha
  788. return;
  789. }
  790. }
  791. }
  792. }
  793. // Check for W3C notations: rgb(...), hsl(...), and oklch(...)
  794. if (parseText.Right(1) == _T(")"))
  795. {
  796. if (parseText.Left(3) == _T("rgb"))
  797. {
  798. CString content;
  799. int prefixLen = (parseText.Left(4) == _T("rgba")) ? 5 : 4;
  800. content = parseText.Mid(prefixLen, parseText.GetLength() - prefixLen - 1);
  801. content.Replace(_T(','), _T(' '));
  802. content.Replace(_T('/'), _T(' '));
  803. std::vector<CString> tokens;
  804. int curPos = 0;
  805. CString token;
  806. while (!(token = content.Tokenize(_T(" "), curPos)).IsEmpty())
  807. {
  808. tokens.push_back(token);
  809. }
  810. if (tokens.size() >= 3)
  811. {
  812. double r_val, g_val, b_val;
  813. if (ParseCssValue(tokens[0], r_val) && ParseCssValue(tokens[1], g_val) && ParseCssValue(tokens[2], b_val))
  814. {
  815. if (tokens[0].Find('%') != -1)
  816. {
  817. r_val = std::round(r_val * 2.55);
  818. g_val = std::round(g_val * 2.55);
  819. b_val = std::round(b_val * 2.55);
  820. }
  821. int alpha = 255;
  822. double a_val = 1.0;
  823. if (tokens.size() >= 4 && ParseCssValue(tokens[3], a_val))
  824. {
  825. if (tokens[3].Find('%') != -1)
  826. {
  827. a_val /= 100.0;
  828. }
  829. a_val = max(0.0, min(1.0, a_val));
  830. alpha = static_cast<int>(std::round(a_val * 255.0));
  831. }
  832. if (r_val >= 0 && r_val <= 255 && g_val >= 0 && g_val <= 255 && b_val >= 0 && b_val <= 255)
  833. {
  834. DrawColorBox(RGB((int)r_val, (int)g_val, (int)b_val), alpha);
  835. return;
  836. }
  837. }
  838. }
  839. }
  840. else if (parseText.Left(3) == _T("hsl"))
  841. {
  842. CString content;
  843. int prefixLen = (parseText.Left(4) == _T("hsla")) ? 5 : 4;
  844. content = parseText.Mid(prefixLen, parseText.GetLength() - prefixLen - 1);
  845. content.Replace(_T(','), _T(' '));
  846. content.Replace(_T('/'), _T(' '));
  847. content.Replace(_T("deg"), _T(""));
  848. std::vector<CString> tokens;
  849. int curPos = 0;
  850. CString token;
  851. while (!(token = content.Tokenize(_T(" "), curPos)).IsEmpty())
  852. {
  853. tokens.push_back(token);
  854. }
  855. if (tokens.size() >= 3)
  856. {
  857. double h_val, s_val, l_val;
  858. if (ParseCssValue(tokens[0], h_val) && ParseCssValue(tokens[1], s_val) && ParseCssValue(tokens[2], l_val))
  859. {
  860. int alpha = 255;
  861. double a_val = 1.0;
  862. if (tokens.size() >= 4 && ParseCssValue(tokens[3], a_val))
  863. {
  864. if (tokens[3].Find('%') != -1)
  865. {
  866. a_val /= 100.0;
  867. }
  868. a_val = max(0.0, min(1.0, a_val));
  869. alpha = static_cast<int>(std::round(a_val * 255.0));
  870. }
  871. if (s_val >= 0 && s_val <= 100 && l_val >= 0 && l_val <= 100)
  872. {
  873. h_val = fmod(h_val, 360.0);
  874. if (h_val < 0) h_val += 360.0;
  875. DrawColorBox(HslToRgb(h_val, s_val / 100.0, l_val / 100.0), alpha);
  876. return;
  877. }
  878. }
  879. }
  880. }
  881. else if (parseText.Left(5) == _T("oklch"))
  882. {
  883. CString content;
  884. content = parseText.Mid(6, parseText.GetLength() - 7);
  885. content.Replace(_T(','), _T(' '));
  886. content.Replace(_T('/'), _T(' '));
  887. std::vector<CString> tokens;
  888. int curPos = 0;
  889. CString token;
  890. while (!(token = content.Tokenize(_T(" "), curPos)).IsEmpty())
  891. {
  892. tokens.push_back(token);
  893. }
  894. if (tokens.size() >= 3)
  895. {
  896. double l_val, c_val, h_val;
  897. if (ParseCssValue(tokens[0], l_val) && ParseCssValue(tokens[1], c_val) && ParseCssValue(tokens[2], h_val))
  898. {
  899. bool l_is_percent = tokens[0].Find('%') != -1;
  900. double l_normalized = l_val;
  901. if (l_is_percent)
  902. {
  903. l_normalized = l_val / 100.0;
  904. }
  905. int alpha = 255;
  906. double a_val = 1.0;
  907. if (tokens.size() >= 4 && ParseCssValue(tokens[3], a_val))
  908. {
  909. if (tokens[3].Find('%') != -1)
  910. {
  911. a_val /= 100.0;
  912. }
  913. a_val = max(0.0, min(1.0, a_val));
  914. alpha = static_cast<int>(std::round(a_val * 255.0));
  915. }
  916. if (l_normalized >= 0 && l_normalized <= 1.0 && c_val >= 0)
  917. {
  918. DrawColorBox(OklchToRgb(l_normalized, c_val, h_val), alpha);
  919. return;
  920. }
  921. }
  922. }
  923. }
  924. }
  925. // 4. --- Non-W3C Format Parsing ---
  926. int r, g, b, chars_consumed = 0;
  927. // Check for parenthesized RGB: "(255, 128, 0)" or "(255 128 0)"
  928. if (parseText.Left(1) == _T("(") && parseText.Right(1) == _T(")"))
  929. {
  930. CString content = parseText.Mid(1, parseText.GetLength() - 2);
  931. content.Trim();
  932. content.Replace(_T(','), _T(' '));
  933. if (swscanf(content, _T("%d %d %d %n"), &r, &g, &b, &chars_consumed) == 3)
  934. {
  935. CString remainingText = content.Mid(chars_consumed);
  936. remainingText.Trim();
  937. if (remainingText.IsEmpty())
  938. {
  939. if (r >= 0 && r <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255)
  940. {
  941. DrawColorBox(RGB(r, g, b));
  942. return;
  943. }
  944. }
  945. }
  946. }
  947. // Check for comma-separated RGB: "255, 0, 0"
  948. if (swscanf(parseText, _T("%d , %d , %d %n"), &r, &g, &b, &chars_consumed) == 3 && chars_consumed == parseText.GetLength())
  949. {
  950. if (r >= 0 && r <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255)
  951. {
  952. DrawColorBox(RGB(r, g, b));
  953. return;
  954. }
  955. }
  956. // Check for space-separated RGB: "255 128 0"
  957. if (swscanf(parseText, _T("%d %d %d %n"), &r, &g, &b, &chars_consumed) == 3 && chars_consumed == parseText.GetLength())
  958. {
  959. if (r >= 0 && r <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255)
  960. {
  961. DrawColorBox(RGB(r, g, b));
  962. return;
  963. }
  964. }
  965. // Check for 6-digit hex: "FF00CC"
  966. if (parseText.GetLength() == 6 && IsHexString(parseText))
  967. {
  968. // Use %n here as well for consistency, though length check is sufficient.
  969. if (swscanf(parseText, _T("%2x%2x%2x%n"), &r, &g, &b, &chars_consumed) == 3 && chars_consumed == 6)
  970. {
  971. DrawColorBox(RGB(r, g, b));
  972. return;
  973. }
  974. }
  975. }
  976. BOOL CQListCtrl::DrawRtfText(int nItem, CRect& crRect, CDC* pDC)
  977. {
  978. if (CGetSetOptions::m_bDrawRTF == FALSE)
  979. return FALSE;
  980. BOOL bRet = FALSE;
  981. CClipFormat* pThumbnail = GetItem_CF_RTF_ClipFormat(nItem);
  982. if (pThumbnail == NULL)
  983. return FALSE;
  984. // if there's no data, then we're done.
  985. if (pThumbnail->m_hgData == NULL)
  986. return FALSE;
  987. if (m_pFormatter == NULL)
  988. {
  989. m_pFormatter = new CFormattedTextDraw;
  990. m_pFormatter->Create();
  991. }
  992. if (m_rtfFormater.m_hWnd == NULL)
  993. {
  994. m_rtfFormater.Create(_T(""), _T(""), WS_CHILD | WS_VSCROLL |
  995. WS_HSCROLL | ES_MULTILINE | ES_AUTOVSCROLL | ES_NOHIDESEL |
  996. ES_AUTOHSCROLL, CRect(0, 0, 0, 0), this, -1);
  997. }
  998. if (m_pFormatter)
  999. {
  1000. //somehow ms word places crazy rtf text onto the clipboard and our draw routine doesn't handle that
  1001. //pass the rtf text into a richtext control and get it out and the contorl will clean the rtf so our routine can draw it
  1002. m_rtfFormater.SetRTF(pThumbnail->GetAsCStringA());
  1003. CString betterRTF = m_rtfFormater.GetRTF();
  1004. CComBSTR bStr(betterRTF);
  1005. m_pFormatter->put_RTFText(bStr);
  1006. m_pFormatter->Draw(pDC->m_hDC, crRect);
  1007. bRet = TRUE;
  1008. }
  1009. return bRet;
  1010. }
  1011. // DrawBitMap loads a DIB from the DB, draws a crRect thumbnail of the image
  1012. // to pDC and caches that thumbnail as a DIB in m_ThumbNails[ ItemID ].
  1013. // ALL items are cached in m_ThumbNails (those without images are cached with NULL m_hgData)
  1014. BOOL CQListCtrl::DrawBitMap(int nItem, CRect& crRect, CDC* pDC, const CString& csDescription)
  1015. {
  1016. if (CGetSetOptions::m_bDrawThumbnail == FALSE)
  1017. return FALSE;
  1018. CClipFormatQListCtrl* format = GetItem_CF_DIB_ClipFormat(nItem);
  1019. if (format != NULL)
  1020. {
  1021. HGLOBAL smallImage = format->GetDibFittingToHeight(pDC, crRect.Height());
  1022. if (smallImage != NULL)
  1023. {
  1024. //Will return the width of the bitmap in nWidth
  1025. int nWidth = 0;
  1026. if (CBitmapHelper::DrawDIB(pDC, smallImage, crRect.left, crRect.top, nWidth))
  1027. {
  1028. // adjust the rect so other information can be drawn next to the thumbnail
  1029. crRect.left += nWidth + 3;
  1030. }
  1031. }
  1032. }
  1033. else if (csDescription.Find(_T("CF_DIB")) == 0)
  1034. {
  1035. crRect.left += crRect.Height();
  1036. }
  1037. return TRUE;
  1038. }
  1039. void CQListCtrl::RefreshVisibleRows()
  1040. {
  1041. int nTopIndex = GetTopIndex();
  1042. int nLastIndex = nTopIndex + GetCountPerPage();
  1043. RedrawItems(nTopIndex, nLastIndex);
  1044. }
  1045. void CQListCtrl::RefreshRow(int row)
  1046. {
  1047. RedrawItems(row, row);
  1048. }
  1049. void CQListCtrl::OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
  1050. {
  1051. CListCtrl::OnSysKeyDown(nChar, nRepCnt, nFlags);
  1052. }
  1053. BOOL CQListCtrl::OnEraseBkgnd(CDC* pDC)
  1054. {
  1055. CRect rect;
  1056. GetClientRect(&rect);
  1057. CBrush myBrush(CGetSetOptions::m_Theme.MainWindowBG()); // dialog background color
  1058. CBrush* pOld = pDC->SelectObject(&myBrush);
  1059. BOOL bRes = pDC->PatBlt(0, 0, rect.Width(), rect.Height(), PATCOPY);
  1060. pDC->SelectObject(pOld); // restore old brush
  1061. return bRes; // CDialog::OnEraseBkgnd(pDC);
  1062. // Simply returning TRUE seems OK since we do custom item
  1063. // painting. However, there is a pixel buffer around the
  1064. // border of this control (not within the item rects)
  1065. // which becomes visually corrupt if it is not erased.
  1066. // In most cases, I do not notice the erasure, so I have kept
  1067. // the call to CListCtrl::OnEraseBkgnd(pDC);
  1068. // However, for some reason, bulk erasure is very noticeable when
  1069. // shift-scrolling the page to select a block of items, so
  1070. // I made a special case for that:
  1071. //if(GetSelectedCount() >= 2)
  1072. // return TRUE;
  1073. //return CListCtrl::OnEraseBkgnd(pDC);
  1074. }
  1075. BOOL CQListCtrl::OnToolTipText(UINT id, NMHDR* pNMHDR, LRESULT* pResult)
  1076. {
  1077. // need to handle both ANSI and UNICODE versions of the message
  1078. TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR;
  1079. TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR;
  1080. CString strTipText;
  1081. UINT_PTR nID = pNMHDR->idFrom;
  1082. if (nID == 0) // Notification in NT from automatically
  1083. return FALSE; // created tooltip
  1084. ::SendMessage(pNMHDR->hwndFrom, TTM_SETMAXTIPWIDTH, 0, 500);
  1085. if (CGetSetOptions::m_tooltipTimeout > 0)
  1086. {
  1087. ::SendMessage(pNMHDR->hwndFrom, TTM_SETDELAYTIME, TTDT_AUTOPOP, MAKELPARAM(CGetSetOptions::m_tooltipTimeout, 0));
  1088. }
  1089. // Use Item's name as the tool tip. Change this for something different.
  1090. // Like use its file size, etc.
  1091. GetToolTipText((int)nID - 1, strTipText);
  1092. //Replace the tabs with spaces, the tooltip didn't like the \t s
  1093. strTipText.Replace(_T("\t"), _T(" "));
  1094. int nLength = strTipText.GetLength() + 2;
  1095. #ifndef _UNICODE
  1096. if (pNMHDR->code == TTN_NEEDTEXTA)
  1097. {
  1098. if (m_pchTip != NULL)
  1099. delete m_pchTip;
  1100. m_pchTip = new TCHAR[nLength];
  1101. lstrcpyn(m_pchTip, strTipText, nLength - 1);
  1102. m_pchTip[nLength - 1] = 0;
  1103. pTTTW->lpszText = (WCHAR*)m_pchTip;
  1104. }
  1105. else
  1106. {
  1107. if (m_pwchTip != NULL)
  1108. delete m_pwchTip;
  1109. m_pwchTip = new WCHAR[nLength];
  1110. _mbstowcsz(m_pwchTip, strTipText, nLength - 1);
  1111. m_pwchTip[nLength - 1] = 0; // end of text
  1112. pTTTW->lpszText = (WCHAR*)m_pwchTip;
  1113. }
  1114. #else
  1115. if (pNMHDR->code == TTN_NEEDTEXTA)
  1116. {
  1117. if (m_pchTip != NULL)
  1118. delete m_pchTip;
  1119. m_pchTip = new TCHAR[nLength];
  1120. STRNCPY(m_pchTip, strTipText, nLength - 1);
  1121. m_pchTip[nLength - 1] = 0; // end of text
  1122. pTTTW->lpszText = (LPTSTR)m_pchTip;
  1123. }
  1124. else
  1125. {
  1126. if (m_pwchTip != NULL)
  1127. delete m_pwchTip;
  1128. m_pwchTip = new WCHAR[nLength];
  1129. lstrcpyn(m_pwchTip, strTipText, nLength - 1);
  1130. m_pwchTip[nLength - 1] = 0;
  1131. pTTTW->lpszText = (LPTSTR)m_pwchTip;
  1132. }
  1133. #endif
  1134. * pResult = 0;
  1135. return TRUE; // message was handled
  1136. }
  1137. INT_PTR CQListCtrl::OnToolHitTest(CPoint point, TOOLINFO* pTI) const
  1138. {
  1139. CRect rect;
  1140. GetClientRect(&rect);
  1141. if (rect.PtInRect(point))
  1142. {
  1143. if (GetItemCount())
  1144. {
  1145. int nTopIndex = GetTopIndex();
  1146. int nBottomIndex = nTopIndex + GetCountPerPage();
  1147. if (nBottomIndex > GetItemCount()) nBottomIndex = GetItemCount();
  1148. for (int nIndex = nTopIndex; nIndex <= nBottomIndex; nIndex++)
  1149. {
  1150. GetItemRect(nIndex, rect, LVIR_BOUNDS);
  1151. if (rect.PtInRect(point))
  1152. {
  1153. pTI->hwnd = m_hWnd;
  1154. pTI->uId = (UINT)(nIndex + 1);
  1155. pTI->lpszText = LPSTR_TEXTCALLBACK;
  1156. pTI->rect = rect;
  1157. pTI->uFlags = TTF_TRANSPARENT;
  1158. return pTI->uId;
  1159. }
  1160. }
  1161. }
  1162. }
  1163. return -1;
  1164. }
  1165. int CQListCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
  1166. {
  1167. if (CListCtrl::OnCreate(lpCreateStruct) == -1)
  1168. return -1;
  1169. if (CGetSetOptions::m_tooltipTimeout > 0 ||
  1170. CGetSetOptions::m_tooltipTimeout == -1)
  1171. {
  1172. EnableToolTips();
  1173. }
  1174. else
  1175. {
  1176. EnableToolTips(FALSE);
  1177. }
  1178. //m_pToolTip = new CToolTipEx;
  1179. //m_pToolTip->Create(this);
  1180. //m_pToolTip->SetNotifyWnd(GetParent());
  1181. return 0;
  1182. }
  1183. BOOL CQListCtrl::PreTranslateMessage(MSG* pMsg)
  1184. {
  1185. CAccel a;
  1186. if (m_Accels.OnMsg(pMsg, a))
  1187. {
  1188. switch (a.Cmd)
  1189. {
  1190. case COPY_BUFFER_HOT_KEY_1_ID:
  1191. PutSelectedItemOnDittoCopyBuffer(0);
  1192. break;
  1193. case COPY_BUFFER_HOT_KEY_2_ID:
  1194. PutSelectedItemOnDittoCopyBuffer(1);
  1195. break;
  1196. case COPY_BUFFER_HOT_KEY_3_ID:
  1197. PutSelectedItemOnDittoCopyBuffer(2);
  1198. break;
  1199. default:
  1200. if (a.RefId == CHotKey::PASTE_OPEN_CLIP)
  1201. {
  1202. GetParent()->SendMessage(NM_SELECT_DB_ID, a.Cmd, 0);
  1203. }
  1204. else if (a.RefId == CHotKey::MOVE_TO_GROUP)
  1205. {
  1206. GetParent()->SendMessage(NM_MOVE_TO_GROUP, a.Cmd, 0);
  1207. }
  1208. }
  1209. return TRUE;
  1210. }
  1211. if (VALID_TOOLTIP)
  1212. {
  1213. if (m_pToolTip->OnMsg(pMsg))
  1214. return TRUE;
  1215. }
  1216. switch (pMsg->message)
  1217. {
  1218. case WM_KEYDOWN:
  1219. if (HandleKeyDown(pMsg->wParam, pMsg->lParam))
  1220. return TRUE;
  1221. break; // end case WM_KEYDOWN
  1222. case WM_MOUSEWHEEL:
  1223. // Will be handled by default, but ensure scrollbar updates after
  1224. {
  1225. BOOL result = CListCtrl::PreTranslateMessage(pMsg);
  1226. CWnd* pParent = GetParent();
  1227. if (pParent && pParent->GetSafeHwnd())
  1228. {
  1229. pParent->PostMessage(NM_UPDATE_SCROLLBAR, TRUE, 0);
  1230. }
  1231. return result;
  1232. }
  1233. case WM_VSCROLL:
  1234. ASSERT(FALSE);
  1235. break;
  1236. } // end switch(pMsg->message)
  1237. return CListCtrl::PreTranslateMessage(pMsg);
  1238. }
  1239. BOOL CQListCtrl::HandleKeyDown(WPARAM wParam, LPARAM lParam)
  1240. {
  1241. if (VALID_TOOLTIP)
  1242. {
  1243. MSG Msg;
  1244. Msg.lParam = lParam;
  1245. Msg.wParam = wParam;
  1246. Msg.message = WM_KEYDOWN;
  1247. if (m_pToolTip->OnMsg(&Msg))
  1248. return TRUE;
  1249. }
  1250. WPARAM vk = wParam;
  1251. switch (vk)
  1252. {
  1253. case 'A': // Ctrl-A = Select All
  1254. if (CONTROL_PRESSED)
  1255. {
  1256. int nCount = GetItemCount();
  1257. for (int i = 0; i < nCount; i++)
  1258. {
  1259. SetSelection(i);
  1260. }
  1261. return TRUE;
  1262. }
  1263. break;
  1264. case VK_HOME:
  1265. if (GetKeyState(VK_SHIFT) & 0x8000)
  1266. {
  1267. int nAnchor = GetSelectionMark();
  1268. if (nAnchor < 0)
  1269. {
  1270. nAnchor = GetCaret();
  1271. }
  1272. if (nAnchor >= 0)
  1273. {
  1274. RemoveAllSelection();
  1275. for (int i = 0; i <= nAnchor; i++)
  1276. {
  1277. SetSelection(i, TRUE);
  1278. }
  1279. ListView_SetSelectionMark(m_hWnd, nAnchor);
  1280. SetCaret(0);
  1281. EnsureVisible(0, FALSE);
  1282. }
  1283. }
  1284. else
  1285. {
  1286. SetListPos(0);
  1287. }
  1288. return TRUE;
  1289. } // end switch(vk)
  1290. return FALSE;
  1291. }
  1292. bool CQListCtrl::PostEventLoadedCheckDescription(int updatedRow)
  1293. {
  1294. bool loadedClip = false;
  1295. if (VALID_TOOLTIP)
  1296. {
  1297. int toolTipClipId = m_pToolTip->GetClipId();
  1298. int toolTipClipRow = m_pToolTip->GetClipRow();
  1299. if (toolTipClipRow >= 0)
  1300. {
  1301. log(StrF(_T("PostEventLoadedCheckDescription refreshRow: %d tt_row: %d tt_id: %d"), updatedRow, toolTipClipRow, toolTipClipId));
  1302. }
  1303. //We tried to show the clip but we didn't have the id yet, it was loaded in a thread, now it's being updated
  1304. //see if we need to show this rows description
  1305. if (toolTipClipId <= 0 &&
  1306. toolTipClipRow == updatedRow &&
  1307. ::IsWindow(m_toolTipHwnd))
  1308. {
  1309. ShowFullDescription(false, true);
  1310. loadedClip = true;
  1311. }
  1312. }
  1313. return loadedClip;
  1314. }
  1315. bool CQListCtrl::ShowFullDescription(bool bFromAuto, bool fromNextPrev)
  1316. {
  1317. if (this->GetSelectedCount() == 0)
  1318. {
  1319. return false;
  1320. }
  1321. int clipRow = this->GetCaret();
  1322. int clipId = this->GetItemData(clipRow);
  1323. log(StrF(_T("Show full description row: %d id: %d"), clipRow, clipId));
  1324. if (VALID_TOOLTIP &&
  1325. clipId > 0 &&
  1326. m_pToolTip->GetClipId() == clipId &&
  1327. ::IsWindow(m_toolTipHwnd))
  1328. {
  1329. return false;
  1330. }
  1331. int nItem = GetCaret();
  1332. CRect rc, crWindow;
  1333. GetWindowRect(&crWindow);
  1334. GetItemRect(nItem, rc, LVIR_BOUNDS);
  1335. ClientToScreen(rc);
  1336. CPoint pt;
  1337. if (CGetSetOptions::GetRememberDescPos())
  1338. {
  1339. CGetSetOptions::GetDescWndPoint(pt);
  1340. }
  1341. else if (bFromAuto == false)
  1342. {
  1343. pt = CPoint(rc.left, rc.bottom);
  1344. }
  1345. else
  1346. {
  1347. pt = CPoint((crWindow.left + (crWindow.right - crWindow.left) / 2), rc.bottom);
  1348. }
  1349. CString csDescription;
  1350. GetToolTipText(nItem, csDescription);
  1351. if (m_pToolTip == NULL ||
  1352. //fromNextPrev == false ||
  1353. ::IsWindow(m_toolTipHwnd) == FALSE)
  1354. {
  1355. if (m_pToolTip != NULL)
  1356. {
  1357. m_pToolTip->DestroyWindow();
  1358. }
  1359. m_pToolTip = new CToolTipEx;
  1360. m_pToolTip->Create(this);
  1361. m_toolTipHwnd = m_pToolTip->GetSafeHwnd();
  1362. m_pToolTip->SetNotifyWnd(GetParent());
  1363. }
  1364. else if (VALID_TOOLTIP)
  1365. {
  1366. if (fromNextPrev)
  1367. {
  1368. CRect r;
  1369. m_pToolTip->GetWindowRectEx(r);
  1370. pt = r.TopLeft();
  1371. }
  1372. m_pToolTip->SetGdiplusBitmap(NULL);
  1373. m_pToolTip->SetRTFText("");
  1374. m_pToolTip->SetToolTipText(_T(""));
  1375. m_pToolTip->SetFolderPath(_T(""));
  1376. }
  1377. if (VALID_TOOLTIP)
  1378. {
  1379. m_pToolTip->SetTooltipActions(m_pToolTipActions);
  1380. m_pToolTip->SetClipId(clipId);
  1381. m_pToolTip->SetClipRow(clipRow);
  1382. m_pToolTip->SetSearchText(m_searchText);
  1383. LOGFONT lf;
  1384. m_Font.GetLogFont(&lf);
  1385. lf.lfHeight = m_windowDpi->UnScale(lf.lfHeight);
  1386. m_pToolTip->SetLogFont(&lf, FALSE);
  1387. m_pToolTip->SetClipData(_T(""));
  1388. m_pToolTip->SetToolTipText(_T(""));
  1389. m_pToolTip->SetRTFText("");
  1390. bool bSetPlainText = false;
  1391. CClipFormat Clip;
  1392. try
  1393. {
  1394. CppSQLite3Query q = theApp.m_db.execQueryEx(_T("SELECT lID, lDate, lastPasteDate, lDontAutoDelete, QuickPasteText, lShortCut, globalShortCut, stickyClipOrder, stickyClipGroupOrder, lParentID FROM Main WHERE lID = %d"), clipId);
  1395. if (q.eof() == false)
  1396. {
  1397. CString clipData;
  1398. COleDateTime time((time_t)q.getInt64Field(_T("lDate")));
  1399. clipData += "Added: " + time.Format();
  1400. COleDateTime modified((time_t)q.getInt64Field(_T("lastPasteDate")));
  1401. clipData += _T(" | Last Used: ") + modified.Format();
  1402. if (q.getIntField(_T("lDontAutoDelete")) > 0)
  1403. {
  1404. clipData += _T(" | Never Auto Delete");
  1405. }
  1406. CString csQuickPaste = q.getStringField(_T("QuickPasteText"));
  1407. if (csQuickPaste.IsEmpty() == FALSE)
  1408. {
  1409. clipData += _T(" | Quick Paste = ");
  1410. clipData += csQuickPaste;
  1411. }
  1412. int shortCut = q.getIntField(_T("lShortCut"));
  1413. if (shortCut > 0)
  1414. {
  1415. clipData += _T(" | ");
  1416. clipData += CHotKey::GetHotKeyDisplayStatic(shortCut);
  1417. BOOL globalShortCut = q.getIntField(_T("globalShortCut"));
  1418. if (globalShortCut)
  1419. {
  1420. clipData += _T(" - Global Shortcut Key");
  1421. }
  1422. }
  1423. if (theApp.m_GroupID > 0)
  1424. {
  1425. int sticky = q.getIntField(_T("stickyClipGroupOrder"));
  1426. if (sticky != INVALID_STICKY)
  1427. {
  1428. clipData += _T(" | ");
  1429. clipData += _T(" - Sticky In Group");
  1430. }
  1431. }
  1432. else
  1433. {
  1434. int sticky = q.getIntField(_T("stickyClipOrder"));
  1435. if (sticky != INVALID_STICKY)
  1436. {
  1437. clipData += _T(" | ");
  1438. clipData += _T(" - Sticky");
  1439. }
  1440. }
  1441. int parentId = q.getIntField(_T("lParentID"));
  1442. if (parentId > 0)
  1443. {
  1444. CString folder = FolderPath(parentId);
  1445. m_pToolTip->SetFolderPath(folder);
  1446. }
  1447. m_pToolTip->SetClipData(clipData);
  1448. }
  1449. }
  1450. CATCH_SQLITE_EXCEPTION
  1451. Clip.m_cfType = CF_UNICODETEXT;
  1452. if (GetClipData(nItem, Clip) && Clip.m_hgData)
  1453. {
  1454. m_pToolTip->SetToolTipText(Clip.GetAsCString());
  1455. bSetPlainText = true;
  1456. Clip.Free();
  1457. Clip.Clear();
  1458. }
  1459. if (bSetPlainText == false)
  1460. {
  1461. Clip.m_cfType = CF_TEXT;
  1462. if (GetClipData(nItem, Clip) && Clip.m_hgData)
  1463. {
  1464. CString cs(Clip.GetAsCStringA());
  1465. m_pToolTip->SetToolTipText(cs);
  1466. bSetPlainText = true;
  1467. Clip.Free();
  1468. Clip.Clear();
  1469. }
  1470. }
  1471. if (bSetPlainText == false)
  1472. {
  1473. m_pToolTip->SetToolTipText(csDescription);
  1474. }
  1475. Clip.m_cfType = RegisterClipboardFormat(CF_RTF);
  1476. if (GetClipData(nItem, Clip) && Clip.m_hgData)
  1477. {
  1478. m_pToolTip->SetRTFText(Clip.GetAsCStringA());
  1479. Clip.Free();
  1480. Clip.Clear();
  1481. }
  1482. m_pToolTip->SetHtmlText(_T(""));
  1483. Clip.m_cfType = GetFormatID(_T("HTML Format"));
  1484. if (GetClipData(nItem, Clip) && Clip.m_hgData)
  1485. {
  1486. CString html = CTextConvert::Utf8ToUnicode(Clip.GetAsCStringA());
  1487. m_pToolTip->SetHtmlText(html);
  1488. Clip.Free();
  1489. Clip.Clear();
  1490. }
  1491. Clip.m_cfType = CF_DIB;
  1492. if (GetClipData(nItem, Clip) && Clip.m_hgData)
  1493. {
  1494. m_pToolTip->SetGdiplusBitmap(Clip.CreateGdiplusBitmap());
  1495. }
  1496. else
  1497. {
  1498. Clip.m_cfType = theApp.m_PNG_Format;
  1499. if (GetClipData(nItem, Clip) && Clip.m_hgData)
  1500. {
  1501. m_pToolTip->SetGdiplusBitmap(Clip.CreateGdiplusBitmap());
  1502. }
  1503. }
  1504. m_pToolTip->Show(pt);
  1505. }
  1506. return true;
  1507. }
  1508. void CQListCtrl::GetToolTipText(int nItem, CString& csText)
  1509. {
  1510. CWnd* pParent = GetParent();
  1511. if (pParent && (pParent->GetSafeHwnd() != NULL))
  1512. {
  1513. CQListToolTipText info;
  1514. memset(&info, 0, sizeof(info));
  1515. info.hdr.code = NM_GETTOOLTIPTEXT;
  1516. info.hdr.hwndFrom = GetSafeHwnd();
  1517. info.hdr.idFrom = GetDlgCtrlID();
  1518. info.lItem = nItem;
  1519. //plus 100 for extra info - shortcut and such
  1520. int maxCharacters = CGetSetOptions::GetMaxToolTipCharacters();
  1521. info.cchTextMax = min(maxCharacters, CGetSetOptions::m_bDescTextSize) + 200;
  1522. info.pszText = csText.GetBufferSetLength(info.cchTextMax);
  1523. pParent->SendMessage(WM_NOTIFY, (WPARAM)info.hdr.idFrom, (LPARAM)&info);
  1524. csText.ReleaseBuffer();
  1525. }
  1526. }
  1527. BOOL CQListCtrl::GetClipData(int nItem, CClipFormat& Clip)
  1528. {
  1529. return theApp.GetClipData(GetItemData(nItem), Clip);
  1530. }
  1531. DWORD CQListCtrl::GetItemData(int nItem)
  1532. {
  1533. if ((GetStyle() & LVS_OWNERDATA))
  1534. {
  1535. CWnd* pParent = GetParent();
  1536. if (pParent && (pParent->GetSafeHwnd() != NULL))
  1537. {
  1538. LV_DISPINFO info;
  1539. memset(&info, 0, sizeof(info));
  1540. info.hdr.code = LVN_GETDISPINFO;
  1541. info.hdr.hwndFrom = GetSafeHwnd();
  1542. info.hdr.idFrom = GetDlgCtrlID();
  1543. info.item.iItem = nItem;
  1544. info.item.lParam = -1;
  1545. info.item.mask = LVIF_PARAM;
  1546. pParent->SendMessage(WM_NOTIFY, (WPARAM)info.hdr.idFrom, (LPARAM)&info);
  1547. return (DWORD)info.item.lParam;
  1548. }
  1549. }
  1550. return (DWORD)CListCtrl::GetItemData(nItem);
  1551. }
  1552. CClipFormatQListCtrl* CQListCtrl::GetItem_CF_DIB_ClipFormat(int nItem)
  1553. {
  1554. CClipFormatQListCtrl* format = NULL;
  1555. CWnd* pParent = GetParent();
  1556. if (pParent && (pParent->GetSafeHwnd() != NULL))
  1557. {
  1558. LV_DISPINFO info;
  1559. memset(&info, 0, sizeof(info));
  1560. info.hdr.code = LVN_GETDISPINFO;
  1561. info.hdr.hwndFrom = GetSafeHwnd();
  1562. info.hdr.idFrom = GetDlgCtrlID();
  1563. info.item.iItem = nItem;
  1564. info.item.lParam = NULL;
  1565. info.item.mask = LVIF_CF_DIB;
  1566. pParent->SendMessage(WM_NOTIFY, (WPARAM)info.hdr.idFrom, (LPARAM)&info);
  1567. if (info.item.lParam != NULL)
  1568. {
  1569. format = (CClipFormatQListCtrl*)info.item.lParam;
  1570. }
  1571. }
  1572. return format;
  1573. }
  1574. CClipFormatQListCtrl* CQListCtrl::GetItem_CF_RTF_ClipFormat(int nItem)
  1575. {
  1576. CClipFormatQListCtrl* format = NULL;
  1577. CWnd* pParent = GetParent();
  1578. if (pParent && (pParent->GetSafeHwnd() != NULL))
  1579. {
  1580. LV_DISPINFO info;
  1581. memset(&info, 0, sizeof(info));
  1582. info.hdr.code = LVN_GETDISPINFO;
  1583. info.hdr.hwndFrom = GetSafeHwnd();
  1584. info.hdr.idFrom = GetDlgCtrlID();
  1585. info.item.iItem = nItem;
  1586. info.item.lParam = NULL;
  1587. info.item.mask = LVIF_CF_RICHTEXT;
  1588. pParent->SendMessage(WM_NOTIFY, (WPARAM)info.hdr.idFrom, (LPARAM)&info);
  1589. if (info.item.lParam != NULL)
  1590. {
  1591. format = (CClipFormatQListCtrl*)info.item.lParam;
  1592. }
  1593. }
  1594. return format;
  1595. }
  1596. void CQListCtrl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
  1597. {
  1598. CListCtrl::OnHScroll(nSBCode, nPos, pScrollBar);
  1599. }
  1600. void CQListCtrl::DestroyAndCreateAccelerator(BOOL bCreate, CppSQLite3DB& db)
  1601. {
  1602. m_Accels.RemoveAll();
  1603. if (bCreate)
  1604. {
  1605. CMainTableFunctions::LoadAcceleratorKeys(m_Accels, db);
  1606. LoadDittoCopyBufferHotkeys();
  1607. }
  1608. }
  1609. void CQListCtrl::LoadDittoCopyBufferHotkeys()
  1610. {
  1611. CCopyBufferItem Item;
  1612. CAccel a;
  1613. CGetSetOptions::GetCopyBufferItem(0, Item);
  1614. if (Item.m_lCopyHotKey > 0)
  1615. {
  1616. a.Cmd = COPY_BUFFER_HOT_KEY_1_ID;
  1617. a.Key = Item.m_lCopyHotKey;
  1618. m_Accels.AddAccel(a);
  1619. }
  1620. CGetSetOptions::GetCopyBufferItem(1, Item);
  1621. if (Item.m_lCopyHotKey > 0)
  1622. {
  1623. a.Cmd = COPY_BUFFER_HOT_KEY_2_ID;
  1624. a.Key = Item.m_lCopyHotKey;
  1625. m_Accels.AddAccel(a);
  1626. }
  1627. CGetSetOptions::GetCopyBufferItem(2, Item);
  1628. if (Item.m_lCopyHotKey > 0)
  1629. {
  1630. a.Cmd = COPY_BUFFER_HOT_KEY_3_ID;
  1631. a.Key = Item.m_lCopyHotKey;
  1632. m_Accels.AddAccel(a);
  1633. }
  1634. }
  1635. void CQListCtrl::OnKillFocus(CWnd* pNewWnd)
  1636. {
  1637. CListCtrl::OnKillFocus(pNewWnd);
  1638. //if(FocusOnToolTip() == FALSE)
  1639. //m_pToolTip->Hide();
  1640. }
  1641. HWND CQListCtrl::GetToolTipHWnd()
  1642. {
  1643. if (VALID_TOOLTIP)
  1644. return m_pToolTip->GetSafeHwnd();
  1645. return NULL;
  1646. }
  1647. BOOL CQListCtrl::SetItemCountEx(int iCount, DWORD dwFlags /* = 0 */)
  1648. {
  1649. return CListCtrl::SetItemCountEx(iCount, dwFlags);
  1650. }
  1651. void CQListCtrl::OnSelectionChange(NMHDR* pNMHDR, LRESULT* pResult)
  1652. {
  1653. NMLISTVIEW* pnmv = (NMLISTVIEW*)pNMHDR;
  1654. if ((pnmv->uNewState == 3) ||
  1655. (pnmv->uNewState == 1))
  1656. {
  1657. // Notify parent to update modern scrollbar when selection changes (keyboard navigation)
  1658. CWnd* pParent = GetParent();
  1659. if (pParent && pParent->GetSafeHwnd())
  1660. {
  1661. pParent->PostMessage(NM_UPDATE_SCROLLBAR, FALSE, 0);
  1662. }
  1663. if (VALID_TOOLTIP &&
  1664. ::IsWindowVisible(m_pToolTip->m_hWnd))
  1665. {
  1666. this->ShowFullDescription(false, true);
  1667. }
  1668. if (CGetSetOptions::m_bAllwaysShowDescription)
  1669. {
  1670. KillTimer(TIMER_SHOW_PROPERTIES);
  1671. SetTimer(TIMER_SHOW_PROPERTIES, 300, NULL);
  1672. }
  1673. if (GetSelectedCount() > 0)
  1674. theApp.SetStatus(NULL, FALSE);
  1675. }
  1676. if (GetSelectedCount() == this->GetItemCount())
  1677. {
  1678. if (m_allSelected == false)
  1679. {
  1680. Log(StrF(_T("List box Select All")));
  1681. GetParent()->SendMessage(NM_ALL_SELECTED, 0, 0);
  1682. m_allSelected = true;
  1683. }
  1684. }
  1685. else if (m_allSelected == true)
  1686. {
  1687. Log(StrF(_T("List box REMOVED Select All")));
  1688. m_allSelected = false;
  1689. }
  1690. }
  1691. void CQListCtrl::OnTimer(UINT_PTR nIDEvent)
  1692. {
  1693. //http://support.microsoft.com/kb/200054
  1694. //OnTimer() Is Not Called Repeatedly for a List Control
  1695. bool callBase = true;
  1696. switch (nIDEvent)
  1697. {
  1698. case TIMER_SHOW_PROPERTIES:
  1699. {
  1700. if (theApp.m_bShowingQuickPaste)
  1701. ShowFullDescription(true);
  1702. KillTimer(TIMER_SHOW_PROPERTIES);
  1703. callBase = false;
  1704. }
  1705. break;
  1706. case TIMER_HIDE_SCROL:
  1707. {
  1708. CPoint cursorPos;
  1709. GetCursorPos(&cursorPos);
  1710. CRect crWindow;
  1711. this->GetWindowRect(&crWindow);
  1712. //check and see if they moved out of the scroll area
  1713. //If they did tell our parent so
  1714. if (MouseInScrollBarArea(crWindow, cursorPos) == false)
  1715. {
  1716. StopHideScrollBarTimer();
  1717. }
  1718. callBase = false;
  1719. }
  1720. break;
  1721. case TIMER_SHOW_SCROLL:
  1722. {
  1723. CPoint cursorPos;
  1724. GetCursorPos(&cursorPos);
  1725. CRect crWindow;
  1726. this->GetWindowRect(&crWindow);
  1727. //Adjust for the v-scroll bar being off of the screen
  1728. crWindow.right -= m_windowDpi->Scale(GetSystemMetrics(SM_CXVSCROLL));
  1729. crWindow.bottom -= m_windowDpi->Scale(::GetSystemMetrics(SM_CXHSCROLL));
  1730. //Check and see if we are still in the cursor area
  1731. if (MouseInScrollBarArea(crWindow, cursorPos))
  1732. {
  1733. m_timerToHideScrollAreaSet = true;
  1734. GetParent()->SendMessage(NM_SHOW_HIDE_SCROLLBARS, 1, 0);
  1735. //Start looking to hide the scroll bars
  1736. SetTimer(TIMER_HIDE_SCROL, 1000, NULL);
  1737. }
  1738. KillTimer(TIMER_SHOW_SCROLL);
  1739. callBase = false;
  1740. }
  1741. break;
  1742. }
  1743. if (callBase)
  1744. {
  1745. CListCtrl::OnTimer(nIDEvent);
  1746. }
  1747. }
  1748. void CQListCtrl::SetLogFont(LOGFONT& font)
  1749. {
  1750. m_Font.DeleteObject();
  1751. m_boldFont.DeleteObject();
  1752. m_Font.CreateFontIndirect(&font);
  1753. font.lfWeight = 600;
  1754. m_boldFont.CreateFontIndirect(&font);
  1755. SetFont(&m_Font);
  1756. }
  1757. void CQListCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
  1758. {
  1759. CListCtrl::OnVScroll(nSBCode, nPos, pScrollBar);
  1760. // Notify parent to update modern scrollbar
  1761. CWnd* pParent = GetParent();
  1762. if (pParent && pParent->GetSafeHwnd())
  1763. {
  1764. pParent->PostMessage(NM_UPDATE_SCROLLBAR, TRUE, 0);
  1765. }
  1766. }
  1767. BOOL CQListCtrl::OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pLResult)
  1768. {
  1769. NMLVCACHEHINT* pcachehint = NULL;
  1770. if (message == WM_NOTIFY)
  1771. {
  1772. NMHDR* phdr = (NMHDR*)lParam;
  1773. switch (phdr->code)
  1774. {
  1775. case LVN_ODCACHEHINT:
  1776. pcachehint = (NMLVCACHEHINT*)phdr;
  1777. GetParent()->SendMessage(NM_FILL_REST_OF_LIST, pcachehint->iFrom, pcachehint->iTo);
  1778. return FALSE;
  1779. }
  1780. }
  1781. return CListCtrl::OnChildNotify(message, wParam, lParam, pLResult);
  1782. }
  1783. BOOL CQListCtrl::OnItemDeleted(long lID)
  1784. {
  1785. BOOL bRet2 = m_RTFData.RemoveKey(lID);
  1786. return (bRet2);
  1787. }
  1788. void CQListCtrl::OnMouseMove(UINT nFlags, CPoint point)
  1789. {
  1790. if (CGetSetOptions::m_showScrollBar == FALSE)
  1791. {
  1792. CRect crWindow;
  1793. this->GetWindowRect(&crWindow);
  1794. ScreenToClient(&crWindow);
  1795. // Don't subtract scrollbar size - detect in the full window area
  1796. // This prevents flickering when scrollbar appears/disappears
  1797. if (MouseInScrollBarArea(crWindow, point))
  1798. {
  1799. // Show scrollbar immediately when mouse enters scrollbar area
  1800. if (m_mouseOverScrollAreaStart == 0)
  1801. {
  1802. m_mouseOverScrollAreaStart = GetTickCount();
  1803. // For modern scrollbar, notify parent
  1804. if (CGetSetOptions::m_useModernScrollBar)
  1805. {
  1806. GetParent()->PostMessage(NM_UPDATE_SCROLLBAR, TRUE, 0);
  1807. }
  1808. else
  1809. {
  1810. // For native scrollbar, show immediately and start hide timer
  1811. m_timerToHideScrollAreaSet = true;
  1812. GetParent()->SendMessage(NM_SHOW_HIDE_SCROLLBARS, 1, 0);
  1813. SetTimer(TIMER_HIDE_SCROL, 1000, NULL);
  1814. }
  1815. }
  1816. }
  1817. else
  1818. {
  1819. m_mouseOverScrollAreaStart = 0;
  1820. if (m_timerToHideScrollAreaSet)
  1821. {
  1822. StopHideScrollBarTimer();
  1823. }
  1824. KillTimer(TIMER_SHOW_SCROLL);
  1825. }
  1826. }
  1827. CListCtrl::OnMouseMove(nFlags, point);
  1828. }
  1829. bool CQListCtrl::MouseInScrollBarArea(CRect crWindow, CPoint point)
  1830. {
  1831. int scrollBarWidth = m_windowDpi->Scale(::GetSystemMetrics(SM_CXVSCROLL));
  1832. int scrollBarHeight = m_windowDpi->Scale(::GetSystemMetrics(SM_CYHSCROLL));
  1833. int extraMargin = m_windowDpi->Scale(6); // Small extra margin for easier detection
  1834. CRect crRight(crWindow);
  1835. CRect crBottom(crWindow);
  1836. // Detect from the right edge of the window (includes scrollbar area when visible)
  1837. crRight.left = crRight.right - scrollBarWidth - extraMargin;
  1838. crBottom.top = crBottom.bottom - scrollBarHeight - extraMargin;
  1839. /*CString cs;
  1840. cs.Format(_T("point.x: %d, Width: %d, Height: %d\n"), point.x, crWindow.Width(), crWindow.Height());
  1841. OutputDebugString(cs);*/
  1842. if (crRight.PtInRect(point) || crBottom.PtInRect(point))
  1843. {
  1844. return true;
  1845. }
  1846. return false;
  1847. }
  1848. void CQListCtrl::StopHideScrollBarTimer()
  1849. {
  1850. GetParent()->SendMessage(NM_SHOW_HIDE_SCROLLBARS, 0, 0);
  1851. m_timerToHideScrollAreaSet = false;
  1852. KillTimer(TIMER_HIDE_SCROL);
  1853. }
  1854. void CQListCtrl::SetSearchText(CString text)
  1855. {
  1856. m_searchText = text;
  1857. }
  1858. void CQListCtrl::HidePopup(bool checkShowPersistant)
  1859. {
  1860. if (VALID_TOOLTIP)
  1861. {
  1862. if (checkShowPersistant == false ||
  1863. m_pToolTip->GetShowPersistant() == false)
  1864. {
  1865. m_pToolTip->Hide();
  1866. }
  1867. }
  1868. }
  1869. BOOL CQListCtrl::IsToolTipWindowVisible()
  1870. {
  1871. if (VALID_TOOLTIP)
  1872. {
  1873. return ::IsWindowVisible(m_toolTipHwnd);
  1874. }
  1875. return FALSE;
  1876. }
  1877. void CQListCtrl::ToggleToolTipShowPersistant()
  1878. {
  1879. if (VALID_TOOLTIP)
  1880. {
  1881. m_pToolTip->ToggleShowPersistant();
  1882. }
  1883. }
  1884. bool CQListCtrl::ToggleToolTipWordWrap()
  1885. {
  1886. bool didWordWrap = false;
  1887. if (VALID_TOOLTIP)
  1888. {
  1889. didWordWrap = m_pToolTip->ToggleWordWrap();
  1890. }
  1891. return didWordWrap;
  1892. }
  1893. BOOL CQListCtrl::IsToolTipWindowFocus()
  1894. {
  1895. if (VALID_TOOLTIP)
  1896. {
  1897. return ::GetFocus() == m_toolTipHwnd ||
  1898. ::GetParent(::GetFocus()) == m_toolTipHwnd;
  1899. }
  1900. return FALSE;
  1901. }
  1902. bool CQListCtrl::IsToolTipShowPersistant()
  1903. {
  1904. if (VALID_TOOLTIP)
  1905. {
  1906. return m_pToolTip->GetShowPersistant();
  1907. }
  1908. return false;
  1909. }
  1910. void CQListCtrl::DoToolTipSearch()
  1911. {
  1912. if (VALID_TOOLTIP)
  1913. {
  1914. return m_pToolTip->DoSearch();
  1915. }
  1916. }
  1917. void CQListCtrl::HideToolTip()
  1918. {
  1919. if (VALID_TOOLTIP)
  1920. {
  1921. m_pToolTip->Hide();
  1922. }
  1923. }
  1924. void CQListCtrl::OnDpiChanged()
  1925. {
  1926. SetDpiInfo(m_windowDpi);
  1927. }
  1928. void CQListCtrl::SetDpiInfo(CDPI* dpi)
  1929. {
  1930. m_windowDpi = dpi;
  1931. m_groupFolder.Reset();
  1932. m_groupFolder.LoadStdImageDPI(m_windowDpi->GetDPI(), IDB_OPEN_FOLDER_16_16, IDB_OPEN_FOLDER_20_20, IDB_OPEN_FOLDER_24_24, IDB_OPEN_FOLDER_24_24, IDB_OPEN_FOLDER_32_32, _T("PNG"));
  1933. m_dontDeleteImage.Reset();
  1934. m_dontDeleteImage.LoadStdImageDPI(m_windowDpi->GetDPI(), IDB_YELLOW_STAR_16_16, IDB_YELLOW_STAR_20_20, IDB_YELLOW_STAR_24_24, IDB_YELLOW_STAR_24_24, IDB_YELLOW_STAR_32_32, _T("PNG"));
  1935. m_inFolderImage.Reset();
  1936. m_inFolderImage.LoadStdImageDPI(m_windowDpi->GetDPI(), IDB_IN_FOLDER_16_16, IDB_IN_FOLDER_20_20, IDB_IN_FOLDER_24_24, IDB_IN_FOLDER_24_24, IDB_IN_FOLDER_32_32, _T("PNG"));
  1937. m_shortCutImage.Reset();
  1938. m_shortCutImage.LoadStdImageDPI(m_windowDpi->GetDPI(), IDB_KEY_16_16, IDB_KEY_20_20, IDB_KEY_24_24, IDB_KEY_24_24, IDB_KEY_32_32, _T("PNG"));
  1939. m_stickyImage.Reset();
  1940. m_stickyImage.LoadStdImageDPI(m_windowDpi->GetDPI(), IDB_STICKY_16_16, IDB_STICKY_20_20, IDB_STICKY_24_24, IDB_STICKY_24_24, IDB_STICKY_32_32, _T("PNG"));
  1941. DeleteObject(m_SmallFont);
  1942. CreateSmallFont();
  1943. }
  1944. void CQListCtrl::CreateSmallFont()
  1945. {
  1946. LOGFONT lf;
  1947. lf.lfHeight = -MulDiv(CGetSetOptions::GetFirstTenHotKeysFontSize(), m_windowDpi->GetDPI(), 72);
  1948. lf.lfWidth = 0;
  1949. lf.lfEscapement = 0;
  1950. lf.lfOrientation = 0;
  1951. lf.lfWeight = FW_LIGHT;
  1952. lf.lfItalic = FALSE;
  1953. lf.lfUnderline = FALSE;
  1954. lf.lfStrikeOut = FALSE;
  1955. lf.lfCharSet = ANSI_CHARSET;
  1956. lf.lfOutPrecision = OUT_STRING_PRECIS;
  1957. lf.lfClipPrecision = CLIP_STROKE_PRECIS;
  1958. lf.lfQuality = DEFAULT_QUALITY;
  1959. lf.lfPitchAndFamily = VARIABLE_PITCH | FF_DONTCARE;
  1960. lstrcpy(lf.lfFaceName, _T("Small Font"));
  1961. m_SmallFont = ::CreateFontIndirect(&lf);
  1962. }
  1963. void CQListCtrl::OnMouseHWheel(UINT nFlags, short zDelta, CPoint pt)
  1964. {
  1965. if (zDelta < 0)
  1966. {
  1967. this->SendMessage(WM_HSCROLL, SB_LINERIGHT, NULL);
  1968. }
  1969. else
  1970. {
  1971. this->SendMessage(WM_HSCROLL, SB_LINELEFT, NULL);
  1972. }
  1973. // Notify parent to update modern scrollbar
  1974. CWnd* pParent = GetParent();
  1975. if (pParent && pParent->GetSafeHwnd())
  1976. {
  1977. pParent->PostMessage(NM_UPDATE_SCROLLBAR, TRUE, 0);
  1978. }
  1979. //CListCtrl::OnMouseHWheel(nFlags, zDelta, pt);
  1980. }