text.cpp 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767
  1. #include <precomp.h>
  2. #include "text.h"
  3. #include <api.h>
  4. #include <api/wndmgr/layout.h>
  5. #ifdef WASABI_WIDGETS_COMPBUCK
  6. #include <api/skin/widgets/compbuck2.h>
  7. #endif
  8. #include <api/skin/skinparse.h>
  9. #if defined(WA3COMPATIBILITY) || defined(WASABI_STATICVARMGR)
  10. #include <api/util/varmgr.h>
  11. #endif
  12. #include <api/core/sequence.h>
  13. #include <api/script/vcpu.h>
  14. #ifdef WA3COMPATIBILITY
  15. #include <core/corehandle.h>
  16. #endif
  17. #include <api/wnd/notifmsg.h>
  18. #include <api/locales/xlatstr.h>
  19. #include <api/skin/feeds/TextFeedEnum.h>
  20. #include <bfc/parse/pathparse.h>
  21. #include <bfc/util/timefmt.h>
  22. #ifdef WASABI_COMPILE_MEDIACORE
  23. #include <api/core/api_core.h>
  24. #endif
  25. #include <api/service/svcs/svc_font.h>
  26. #include <api/config/items/attribs.h>
  27. #include <api/skin/skinelem.h>
  28. #include <api/service/svcs/svc_action.h>
  29. #include <tataki/blending/blending.h>
  30. #include <tataki/canvas/bltcanvas.h>
  31. const wchar_t textXuiObjectStr[] = L"Text"; // This is the xml tag
  32. char textXuiSvcName[] = "Text xui object"; // this is the name of the xuiservice
  33. #define TTS_DELAY 4000
  34. #define TICKER_TIMER_POS 1
  35. #define TICKER_RESET_ALTNAME 2
  36. #define TIMER_SKIPCFG 0x987
  37. #define COLORMODE_RGB 0
  38. #define COLORMODE_SKINCOLOR 1
  39. XMLParamPair Text::params[] =
  40. {
  41. {TEXT_SETALTSHADOWCOLOR, L"ALTSHADOWCOLOR"},
  42. {TEXT_SETALTSHADOWX, L"ALTSHADOWX"},
  43. {TEXT_SETALTSHADOWY, L"ALTSHADOWY"},
  44. {TEXT_SETALTVALIGN, L"ALTVALIGN"},
  45. {TEXT_SETCBSOURCE, L"CBSOURCE"},
  46. {TEXT_SETTEXT, L"DEFAULT"},
  47. {TEXT_SETDISPLAY, L"DISPLAY"},
  48. {TEXT_SETFORCEFIXED, L"FORCEFIXED"},
  49. {TEXT_SETFORCELOCASE, L"FORCELOWERCASE"},
  50. {TEXT_SETFORCELOCASE, L"FORCELOCASE"},
  51. {TEXT_SETFORCEUPCASE, L"FORCEUPCASE"},
  52. {TEXT_SETFORCEUPCASE, L"FORCEUPPERCASE"},
  53. {TEXT_SETNOGRAB, L"NOGRAB"},
  54. {TEXT_SETOFFSETX, L"OFFSETX"},
  55. {TEXT_SETOFFSETY, L"OFFSETY"},
  56. {TEXT_SETSHADOWCOLOR, L"SHADOWCOLOR"},
  57. {TEXT_SETSHADOWX, L"SHADOWX"},
  58. {TEXT_SETSHADOWY, L"SHADOWY"},
  59. {TEXT_SETSHOWLEN, L"SHOWLEN"},
  60. {TEXT_SETTEXT, L"TEXT"},
  61. {TEXT_SETTICKER, L"TICKER"},
  62. {TEXT_SETTICKERSTEP, L"TICKERSTEP"},
  63. {TEXT_SETTIMECOLONWIDTH, L"TIMECOLONWIDTH"},
  64. {TEXT_SETTIMERHOURS, L"TIMERHOURS"},
  65. {TEXT_SETTIMEROFFSTYLE, L"TIMEROFFSTYLE"},
  66. {TEXT_SETVALIGN, L"VALIGN"},
  67. {TEXT_SETWRAPPED, L"WRAP"},
  68. {TEXT_SETTIMERHOURSROLLOVER, L"TIMERHOURSROLLOVER"},
  69. };
  70. Text::Text()
  71. {
  72. getScriptObject()->vcpu_setInterface(textGuid, (void *)static_cast<Text *>(this));
  73. getScriptObject()->vcpu_setClassName(L"Text");
  74. getScriptObject()->vcpu_setController(textController);
  75. //isbitmapfont = iswinfontrender = 0;
  76. bufferinvalid = 1;
  77. cachedsizew = 0;
  78. size[0] = size[1] = 0;
  79. textpos = 0;
  80. time_tts = 20;
  81. tts = time_tts;
  82. sens = 0;
  83. grab_x = 0;
  84. cur_len = 0;
  85. ticker = 0;
  86. timerhours = 0;
  87. timerhoursRollover = 0;
  88. display = DISPLAY_NONE;
  89. elapsed = 1;
  90. fixedTimerStyle = 0;
  91. shadowcolor[0].setColorGroup(L"Text backgrounds");
  92. shadowcolor[0].setColor(RGB(0, 0, 0));
  93. shadowcolor[1].setColorGroup(L"Text backgrounds");
  94. shadowcolor[1].setColor(RGB(0, 0, 0));
  95. shadowcolor_mode[0] = COLORMODE_RGB;
  96. shadowcolor_mode[1] = COLORMODE_RGB;
  97. shadowx[0] = shadowx[1] = shadowy[0] = shadowy[1] = 0;
  98. timecolonw = -1;
  99. timeroffstyle = 0;
  100. nograb = 0;
  101. showlen = 0;
  102. forcefixed = 0;
  103. forceupcase = 0;
  104. forcelocase = 0;
  105. lastautowidth = 32;
  106. textfeed = NULL;
  107. wrapped = 0;
  108. valign[0] = ALIGN_CENTER;
  109. valign[1] = ALIGN_CENTER;
  110. offsetx = 0;
  111. offsety = 0;
  112. tickerstep = 1;
  113. const GUID uioptions_guid =
  114. { 0x9149c445, 0x3c30, 0x4e04, { 0x84, 0x33, 0x5a, 0x51, 0x8e, 0xd0, 0xfd, 0xde } };
  115. CfgItem *item = WASABI_API_CONFIG->config_getCfgItemByGuid(uioptions_guid);
  116. if (item != NULL)
  117. {
  118. float f = (float)item->getDataAsFloat(L"Text Ticker Speed", 1.0f / 2.0f);
  119. skipn = (int)((1.0f / f) - 1 + 0.5f);
  120. }
  121. skip = 0;
  122. xuihandle = newXuiHandle();
  123. CreateXMLParameters(xuihandle);
  124. registered_syscb = 0;
  125. }
  126. void Text::CreateXMLParameters(int master_handle)
  127. {
  128. //TEXT_PARENT::CreateXMLParameters(master_handle);
  129. int numParams = sizeof(params) / sizeof(params[0]);
  130. hintNumberOfParams(xuihandle, numParams);
  131. for (int i = 0;i < numParams;i++)
  132. addParam(xuihandle, params[i], XUI_ATTRIBUTE_IMPLIED);
  133. }
  134. Text::~Text()
  135. {
  136. killTimer(TICKER_TIMER_POS);
  137. killTimer(TICKER_RESET_ALTNAME);
  138. killTimer(TIMER_SKIPCFG);
  139. if (registered_syscb) WASABI_API_SYSCB->syscb_deregisterCallback(static_cast<SvcCallbackI*>(this));
  140. #ifdef WASABI_WIDGETS_COMPBUCK
  141. if (display == DISPLAY_CB)
  142. if (mycbid.getNumItems() == 0)
  143. ComponentBucket2::unRegisterText(this);
  144. else
  145. for (int i = 0;i < mycbid.getNumItems();i++)
  146. ComponentBucket2::unRegisterText(this, mycbid.enumItem(i)->getValue());
  147. #endif
  148. #ifdef WASABI_COMPILE_MEDIACORE
  149. WASABI_API_MEDIACORE->core_delCallback(0, this);
  150. #endif
  151. if (textfeed)
  152. {
  153. viewer_delViewItem(textfeed->getDependencyPtr());
  154. SvcEnum::release(textfeed);
  155. textfeed = NULL;
  156. }
  157. mycbid.deleteAll();
  158. }
  159. int Text::setXuiParam(int _xuihandle, int attrid, const wchar_t *name, const wchar_t *strval)
  160. {
  161. if (xuihandle != _xuihandle) return TEXT_PARENT::setXuiParam(_xuihandle, attrid, name, strval);
  162. switch (attrid)
  163. {
  164. #ifdef WASABI_COMPILE_MEDIACORE
  165. case TEXT_SETDISPLAY:
  166. displaystr = strval;
  167. setDisplay(SkinParser::getDisplay(strval));
  168. if (!_wcsicmp(strval, L"TIMEREMAINING"))
  169. {
  170. fixedTimerStyle = 1;
  171. elapsed = 0;
  172. }
  173. else if (!_wcsicmp(strval, L"TIMEELAPSED"))
  174. {
  175. fixedTimerStyle = 1;
  176. elapsed = 1;
  177. }
  178. break;
  179. #endif
  180. case TEXT_SETTICKER:
  181. setTickering(WTOI(strval));
  182. break;
  183. case TEXT_SETTEXT:
  184. {
  185. StringW old = getPrintedText();
  186. deftext = parseText(strval);
  187. if (!WCSCASEEQLSAFE(old, getPrintedText()))
  188. {
  189. if (WCSCASEEQLSAFE(L":componentname", deftext) || WCSCASEEQLSAFE(L"@COMPONENTNAME@", deftext))
  190. {
  191. Container *container = getGuiObject()->guiobject_getParentGroup()->getParentContainer();
  192. viewer_addViewItem(container);
  193. }
  194. StringW str = getPrintedText();
  195. onTextChanged(str);
  196. }
  197. break;
  198. }
  199. case TEXT_SETSHADOWCOLOR:
  200. if (WASABI_API_PALETTE->getColorElementRef(strval))
  201. {
  202. shadowcolor_mode[0] = COLORMODE_SKINCOLOR;
  203. sshadowcolor[0] = strval;
  204. shadowcolor_mode[1] = COLORMODE_SKINCOLOR;
  205. sshadowcolor[1] = strval;
  206. }
  207. else
  208. setShadowColor(SkinParser::parseColor(strval), 0);
  209. break;
  210. case TEXT_SETALTSHADOWCOLOR:
  211. if (WASABI_API_PALETTE->getColorElementRef(strval))
  212. {
  213. shadowcolor_mode[1] = COLORMODE_SKINCOLOR;
  214. sshadowcolor[1] = strval;
  215. }
  216. else
  217. setShadowColor(SkinParser::parseColor(strval), 1);
  218. break;
  219. case TEXT_SETSHADOWX:
  220. setShadowX(WTOI(strval));
  221. break;
  222. case TEXT_SETALTSHADOWX:
  223. setShadowX(WTOI(strval), 1);
  224. break;
  225. case TEXT_SETSHADOWY:
  226. setShadowY(WTOI(strval));
  227. break;
  228. case TEXT_SETALTSHADOWY:
  229. setShadowY(WTOI(strval), 0);
  230. break;
  231. case TEXT_SETTIMEROFFSTYLE:
  232. setTimerOffStyle(WTOI(strval));
  233. break;
  234. case TEXT_SETTIMERHOURS:
  235. setTimerHours(WTOI(strval));
  236. break;
  237. case TEXT_SETTIMERHOURSROLLOVER:
  238. setTimerHoursRollover(WTOI(strval));
  239. break;
  240. case TEXT_SETTIMECOLONWIDTH:
  241. setTimeColonWidth(WTOI(strval));
  242. break;
  243. case TEXT_SETNOGRAB:
  244. nograb = WTOI(strval);
  245. break;
  246. case TEXT_SETSHOWLEN:
  247. showlen = WTOI(strval);
  248. break;
  249. case TEXT_SETFORCEFIXED:
  250. forcefixed = WTOI(strval);
  251. break;
  252. case TEXT_SETFORCEUPCASE:
  253. forceupcase = WTOI(strval);
  254. break;
  255. case TEXT_SETFORCELOCASE:
  256. forcelocase = WTOI(strval);
  257. break;
  258. case TEXT_SETCBSOURCE:
  259. addCBSource(strval);
  260. break;
  261. case TEXT_SETWRAPPED:
  262. wrapped = WTOI(strval);
  263. if (isPostOnInit())
  264. invalidateTextBuffer();
  265. break;
  266. case TEXT_SETVALIGN:
  267. valign[0] = SkinParser::getAlign(strval);
  268. valign[1] = valign[0];
  269. if (isPostOnInit())
  270. invalidateTextBuffer();
  271. break;
  272. case TEXT_SETALTVALIGN:
  273. valign[1] = SkinParser::getAlign(strval);
  274. if (isPostOnInit())
  275. invalidateTextBuffer();
  276. break;
  277. case TEXT_SETOFFSETX:
  278. offsetx = WTOI(strval);
  279. if (isPostOnInit())
  280. invalidateTextBuffer();
  281. break;
  282. case TEXT_SETTICKERSTEP:
  283. tickerstep = WTOI(strval);
  284. break;
  285. case TEXT_SETOFFSETY:
  286. offsety = WTOI(strval);
  287. if (isPostOnInit())
  288. invalidateTextBuffer();
  289. break;
  290. default:
  291. return 0;
  292. }
  293. return 1;
  294. }
  295. int Text::getPreferences(int what)
  296. {
  297. StringW thaname = getPrintedText();
  298. if (thaname.isempty())
  299. {
  300. return 32;
  301. }
  302. switch(wantTranslation())
  303. {
  304. case 1:
  305. thaname = _(thaname);
  306. break;
  307. case 2:
  308. thaname = __(thaname);
  309. break;
  310. }
  311. int alt = 0;
  312. #ifdef WASABI_COMPILE_CONFIG
  313. // {280876CF-48C0-40bc-8E86-73CE6BB462E5}
  314. const GUID options_guid =
  315. { 0x280876cf, 0x48c0, 0x40bc, { 0x8e, 0x86, 0x73, 0xce, 0x6b, 0xb4, 0x62, 0xe5 } };
  316. CfgItem *item = WASABI_API_CONFIG->config_getCfgItemByGuid(options_guid);
  317. if (item != NULL)
  318. {
  319. alt = item->getDataAsInt(L"Alternate Fonts", 0);
  320. if (alt < 0 || alt > 1) alt = 0;
  321. }
  322. if (alt)
  323. {
  324. if (item && item->getDataAsInt(L"No 7-bit TTF AltFonts", 1))
  325. {
  326. const wchar_t *p = (const wchar_t *)thaname.getValue();
  327. while (p && *p)
  328. {
  329. if (*p > 127) break;
  330. p++;
  331. }
  332. if (p && !*p) alt = 0;
  333. }
  334. }
  335. #endif
  336. switch (what)
  337. {
  338. case SUGGESTED_W:
  339. {
  340. int min_w = 0;
  341. if (forceupcase)
  342. thaname.toupper();
  343. if (forcelocase)
  344. thaname.tolower();
  345. TextInfoCanvas canvas(this);
  346. Wasabi::FontInfo fontInfo;
  347. GetFontInfo(&fontInfo, alt);
  348. const wchar_t *p = wcschr(thaname, ':');
  349. if (display == DISPLAY_TIME && p)
  350. {
  351. wchar_t secs[256] = {0};
  352. wchar_t mins[256] = {0};
  353. WCSCPYN(mins, thaname, p - thaname);
  354. wcsncpy(secs, p + 1, 256);
  355. int fixw = canvas.getTextWidth(L"0", &fontInfo);
  356. int _ws = forcefixed ? fixw * wcslen(secs) : canvas.getTextWidth(secs, &fontInfo);
  357. int _wm = forcefixed ? fixw * wcslen(mins) : canvas.getTextWidth(mins, &fontInfo);
  358. int _wc = forcefixed ? fixw * wcslen(L":") : canvas.getTextWidth(L":", &fontInfo);
  359. min_w = _ws + _wm + getTimeColonWidth(_wc);
  360. }
  361. else
  362. {
  363. PathParserW ppg(thaname, L"\n");
  364. for (int i = 0;i < ppg.getNumStrings();i++)
  365. {
  366. PathParserW pp(ppg.enumString(i), L"\t");
  367. int w = 0;
  368. for (int j = 0; j < pp.getNumStrings(); j++)
  369. {
  370. w += canvas.getTextWidth(pp.enumString(j), &fontInfo) + 4;
  371. }
  372. min_w = MAX(min_w, w);
  373. }
  374. }
  375. return min_w + lpadding + rpadding;
  376. }
  377. case SUGGESTED_H:
  378. PathParserW pp(thaname, L"\n");
  379. return fontsize[alt] * pp.getNumStrings();
  380. }
  381. return TEXT_PARENT::getPreferences(what);
  382. }
  383. // supermegafucko! corehandle should mirror bitrate/samplerate/channels functions instead of text having to know about gen_ff ! -- will do that real soon
  384. #if defined(GEN_FF) & defined(WA5)
  385. #include "../../../../Plugins/General/gen_ff/wa2frontend.h"
  386. #endif
  387. int Text::onInit()
  388. {
  389. TEXT_PARENT::onInit();
  390. registered_syscb++;
  391. initDisplay();
  392. return 1;
  393. }
  394. void Text::initDisplay()
  395. {
  396. #ifdef WASABI_COMPILE_CONFIG
  397. setTimer(TIMER_SKIPCFG, 1000);
  398. #endif
  399. switch (display)
  400. {
  401. #ifdef WASABI_COMPILE_MEDIACORE
  402. case DISPLAY_SONGNAME:
  403. setName(WASABI_API_APP->main_getVersionString());
  404. case DISPLAY_SONGARTIST:
  405. case DISPLAY_SONGALBUM:
  406. case DISPLAY_SONGLENGTH:
  407. case DISPLAY_SONGTITLE:
  408. #ifndef WASABI_COMPILE_METADB
  409. case DISPLAY_SONGINFO:
  410. case DISPLAY_SONGINFO_TRANSLATED:
  411. #endif
  412. setTimer(TICKER_TIMER_POS, 25);
  413. setTimeTTS(TTS_DELAY / 25);
  414. WASABI_API_MEDIACORE->core_addCallback(0, this);
  415. timerCallback(TICKER_TIMER_POS);
  416. #ifdef GEN_FF // supermegafucko!
  417. if(WASABI_API_MEDIACORE->core_getStatus(0) != 0){
  418. if (display == DISPLAY_SONGINFO)
  419. {
  420. StringW txt;
  421. GET_SONG_INFO_TEXT(txt);
  422. corecb_onInfoChange(txt);
  423. }
  424. else if (display == DISPLAY_SONGINFO_TRANSLATED)
  425. {
  426. StringW txt;
  427. GET_SONG_INFO_TEXT_TRANSLATED(txt);
  428. corecb_onInfoChange(txt);
  429. }
  430. }
  431. #endif
  432. break;
  433. case DISPLAY_SONGBITRATE:
  434. WASABI_API_MEDIACORE->core_addCallback(0, this);
  435. corecb_onBitrateChange(wa2.getBitrate());
  436. break;
  437. case DISPLAY_SONGSAMPLERATE:
  438. WASABI_API_MEDIACORE->core_addCallback(0, this);
  439. corecb_onSampleRateChange(wa2.getSamplerate());
  440. break;
  441. case DISPLAY_TIME:
  442. #ifdef WASABI_COMPILE_CONFIG
  443. if (getGuiObject())
  444. {
  445. Layout *l = getGuiObject()->guiobject_getParentLayout();
  446. if (l && l->getId()) elapsed = WASABI_API_CONFIG->getIntPrivate(StringPrintfW(L"%s/timer_elapsed%s", l->getId(), (fixedTimerStyle ? StringPrintfW(L".%s", this->getId()) : L"")), elapsed);
  447. else elapsed = WASABI_API_CONFIG->getIntPrivate(L"timer_elapsed", elapsed);
  448. }
  449. else elapsed = WASABI_API_CONFIG->getIntPrivate(L"timer_elapsed", elapsed);
  450. #endif
  451. setTimer(TICKER_TIMER_POS, 250);
  452. setTimeTTS(TTS_DELAY / 250);
  453. WASABI_API_MEDIACORE->core_addCallback(0, this);
  454. timerCallback(TICKER_TIMER_POS);
  455. break;
  456. #endif
  457. #ifdef WASABI_WIDGETS_COMPBUCK
  458. case DISPLAY_CB:
  459. setTimer(TICKER_TIMER_POS, 50);
  460. setTimeTTS(TTS_DELAY / 50);
  461. postDeferredCallback(DISPLAY_CB, 0);
  462. break;
  463. #endif
  464. case DISPLAY_SERVICE:
  465. registerToTextFeedService();
  466. break;
  467. break;
  468. }
  469. }
  470. int Text::onDeferredCallback(intptr_t p1, intptr_t p2)
  471. {
  472. #ifdef WASABI_WIDGETS_COMPBUCK
  473. switch (p1)
  474. {
  475. case DISPLAY_CB:
  476. if (mycbid.getNumItems() == 0)
  477. ComponentBucket2::registerText(this);
  478. else
  479. for (int i = 0;i < mycbid.getNumItems();i++)
  480. ComponentBucket2::registerText(this, mycbid.enumItem(i)->getValue());
  481. return 0;
  482. }
  483. #endif
  484. return TEXT_PARENT::onDeferredCallback(p1, p2);
  485. }
  486. void Text::setShadowColor(COLORREF c, int alt)
  487. {
  488. if (alt < 0 || alt > 1) alt = 0;
  489. shadowcolor_mode[alt] = COLORMODE_RGB;
  490. shadowcolor[alt].setColor(c);
  491. invalidateTextBuffer();
  492. if (alt == 0) setShadowColor(c, 1);
  493. }
  494. void Text::setShadowX(int x, int alt)
  495. {
  496. if (alt < 0 || alt > 1) alt = 0;
  497. shadowx[alt] = x;
  498. invalidateTextBuffer();
  499. if (alt == 0) setShadowX(x, 1);
  500. }
  501. void Text::setShadowY(int y, int alt)
  502. {
  503. if (alt < 0 || alt > 1) alt = 0;
  504. shadowy[alt] = y;
  505. invalidateTextBuffer();
  506. if (alt == 0) setShadowY(y, 1);
  507. }
  508. void Text::getBufferPaintSize(int *w, int *h)
  509. {
  510. RECT r;
  511. getClientRect(&r);
  512. int _w = r.right - r.left;
  513. int _h = r.bottom - r.top;
  514. if (bufferinvalid)
  515. {
  516. cachedsizew = getPreferences(SUGGESTED_W);
  517. }
  518. if (w) *w = MAX(_w, cachedsizew);
  519. if (h) *h = _h;
  520. }
  521. void Text::getBufferPaintSource(RECT *r)
  522. {
  523. if (r)
  524. {
  525. RECT cr;
  526. getClientRect(&cr);
  527. r->left = textpos;
  528. r->right = cr.right - cr.left + textpos;
  529. r->top = 0;
  530. r->bottom = cr.bottom - cr.top;
  531. }
  532. }
  533. #include <bfc/util/profiler.h>
  534. // this is a temporary buffer, it should not be painted over with the painting alpha value, since it is going
  535. // to be hanled in the actual blit by our ancestor
  536. int Text::onBufferPaint(BltCanvas *canvas, int _w, int _h)
  537. {
  538. int h, x, y=0;
  539. TEXT_PARENT::onBufferPaint(canvas, _w, _h);
  540. if (bufferinvalid)
  541. {
  542. cachedsizew = getPreferences(SUGGESTED_W);
  543. StringW thaname = getPrintedText();
  544. if (thaname.isempty())
  545. {
  546. RECT r = {0, 0, _w, _h};
  547. canvas->fillRect(&r, RGB(0, 0, 0));
  548. }
  549. onTextChanged(thaname); // don't remove, skipped if unnecessary
  550. switch(wantTranslation())
  551. {
  552. case 1:
  553. thaname = _(thaname);
  554. break;
  555. case 2:
  556. thaname = __(thaname);
  557. break;
  558. }
  559. int alt = 0;
  560. #ifdef WASABI_COMPILE_CONFIG
  561. // {280876CF-48C0-40bc-8E86-73CE6BB462E5}
  562. const GUID options_guid =
  563. { 0x280876cf, 0x48c0, 0x40bc, { 0x8e, 0x86, 0x73, 0xce, 0x6b, 0xb4, 0x62, 0xe5 } };
  564. CfgItem *item = WASABI_API_CONFIG->config_getCfgItemByGuid(options_guid);
  565. if (item != NULL)
  566. {
  567. alt = item->getDataAsInt(L"Alternate Fonts", 0);
  568. if (alt < 0 || alt > 1) alt = 0;
  569. }
  570. if (alt)
  571. {
  572. if (item && item->getDataAsInt(L"No 7-bit TTF AltFonts", 1))
  573. {
  574. const wchar_t *p = (const wchar_t *)thaname.getValue();
  575. while (p && *p)
  576. {
  577. if (*p > 127) break;
  578. p++;
  579. }
  580. if (p && !*p) alt = 0;
  581. }
  582. }
  583. #endif
  584. // canvas may have changed because of onTextChanged !
  585. canvas = render_canvas;
  586. canvas->getDim(&_w, &_h, NULL);
  587. RECT r = {0, 0, _w, _h};
  588. canvas->fillRect(&r, RGB(0, 0, 0));
  589. if (forceupcase)
  590. CharUpperW(thaname.getNonConstVal());
  591. if (forcelocase)
  592. CharLowerW(thaname.getNonConstVal());
  593. wchar_t secs[256] = {0};
  594. wchar_t mins[256] = {0};
  595. wchar_t hours[256] = {0};
  596. Wasabi::FontInfo fontInfo;
  597. GetFontInfo(&fontInfo, alt);
  598. const wchar_t *p = wcschr(thaname, L':');
  599. if (display != DISPLAY_TIME || !p)
  600. {
  601. int wantpadding = 0;
  602. int w = canvas->getTextWidth(thaname, &fontInfo);
  603. if (w <= r.right - r.left - 2 - lpadding - rpadding)
  604. {
  605. // if text is wider than area, don't try to align it or it'll screw up the scroll
  606. if (fontInfo.alignFlags != DT_CENTER) wantpadding = 1;
  607. }
  608. else
  609. {
  610. fontInfo.alignFlags = STDFONT_LEFT;
  611. wantpadding = 1;
  612. }
  613. h = canvas->getTextHeight(thaname, &fontInfo);
  614. x = r.left + 2 /*-textpos*/;
  615. if (wantpadding)
  616. x += lpadding;
  617. switch (valign[alt])
  618. {
  619. case ALIGN_CENTER:
  620. y = r.top + ((r.bottom - r.top - h) / 2);
  621. break;
  622. case ALIGN_TOP:
  623. y = r.top;
  624. break;
  625. }
  626. x += offsetx;
  627. y += offsety;
  628. cur_len = 0;
  629. PathParserW pp(thaname, L"\t");
  630. for (int i = 0; i < pp.getNumStrings(); i++)
  631. {
  632. if (i > 0)
  633. fontInfo.alignFlags = ALIGN_RIGHT;
  634. if (shadowx[alt] != 0 || shadowy[alt] != 0)
  635. {
  636. fontInfo.color = getShadowColor(alt);
  637. if (wrapped)
  638. canvas->textOutWrapped(x + shadowx[alt], y + shadowy[alt], r.right - r.left - 2 /*+textpos*/, r.bottom - r.top, pp.enumString(i), &fontInfo);
  639. else
  640. canvas->textOut(x + shadowx[alt], y + shadowy[alt], r.right - r.left - 2 /*+textpos*/, r.bottom - r.top, pp.enumString(i), &fontInfo);
  641. fontInfo.color = GetColor(alt);
  642. }
  643. if (wrapped)
  644. canvas->textOutWrapped(x, y, r.right - r.left - 2 /*+textpos*/, r.bottom - r.top, pp.enumString(i), &fontInfo);
  645. else
  646. canvas->textOut(x, y, r.right - r.left - 2 /*+textpos*/, r.bottom - r.top, pp.enumString(i), &fontInfo);
  647. cur_len = canvas->getTextWidth(pp.enumString(i), &fontInfo) + (wantpadding ? (lpadding + rpadding) : 0);
  648. }
  649. }
  650. else
  651. {
  652. if(timerhours)
  653. {
  654. WCSCPYN(hours, thaname, (p - thaname)+1);
  655. const wchar_t* p2 = wcschr(p + 1, L':');
  656. WCSCPYN(mins, p + 1, (p2 - p));
  657. if(p2 && *(p2 + 1))
  658. wcsncpy(secs, p2 + 1, 256);
  659. else
  660. {
  661. wcsncpy(secs, mins, 256);
  662. wcsncpy(mins, hours, 256);
  663. hours[0] = 0;
  664. }
  665. }
  666. else
  667. {
  668. WCSCPYN(mins, thaname, (p - thaname)+1);
  669. wcsncpy(secs, p + 1, 256);
  670. }
  671. h = canvas->getTextHeight(thaname, &fontInfo);
  672. int fixw = canvas->getTextWidth(L"0", &fontInfo);
  673. int _ws = forcefixed ? fixw * wcslen(secs) : canvas->getTextWidth(secs, &fontInfo);
  674. int _wm = forcefixed ? fixw * wcslen(mins) : canvas->getTextWidth(mins, &fontInfo);
  675. int _wh = forcefixed ? fixw * wcslen(hours) : canvas->getTextWidth(hours, &fontInfo);
  676. int _wc = forcefixed ? fixw * wcslen(L":") : canvas->getTextWidth(L":", &fontInfo);
  677. wchar_t widthchar = forcefixed ? '0' : 0;
  678. if (fontInfo.alignFlags == ALIGN_RIGHT)
  679. {
  680. x = (r.right - 2) - shadowx[alt] - rpadding;
  681. switch (valign[alt])
  682. {
  683. case ALIGN_CENTER:
  684. y = r.top + ((r.bottom - r.top - h) / 2);
  685. break;
  686. case ALIGN_TOP:
  687. y = r.top;
  688. break;
  689. }
  690. x += offsetx;
  691. y += offsety;
  692. if (shadowx[alt] != 0 || shadowy[alt] != 0)
  693. {
  694. fontInfo.color = getShadowColor(alt);
  695. textOut(canvas, x - _ws, y, secs, widthchar, &fontInfo);
  696. textOut(canvas, x - _ws - getTimeColonWidth(_wc), y, L":", widthchar, &fontInfo);
  697. textOut(canvas, x - _ws - getTimeColonWidth(_wc) - _wm, y, mins, widthchar, &fontInfo);
  698. if(timerhours && hours[0])
  699. {
  700. textOut(canvas, x - _ws - getTimeColonWidth(_wc) - _wm - getTimeColonWidth(_wc), y, L":", widthchar, &fontInfo);
  701. textOut(canvas, x - _ws - getTimeColonWidth(_wc) - _wm - getTimeColonWidth(_wc) - _wh, y, hours, widthchar, &fontInfo);
  702. }
  703. fontInfo.color = GetColor(alt);
  704. }
  705. x += shadowx[alt]; y += shadowy[alt];
  706. textOut(canvas, x - _ws, y, secs, widthchar, &fontInfo);
  707. textOut(canvas, x - _ws - getTimeColonWidth(_wc), y, L":", widthchar, &fontInfo);
  708. textOut(canvas, x - _ws - getTimeColonWidth(_wc) - _wm, y, mins, widthchar, &fontInfo);
  709. if(timerhours && hours[0])
  710. {
  711. textOut(canvas, x - _ws - getTimeColonWidth(_wc) - _wm - getTimeColonWidth(_wc), y, L":", widthchar, &fontInfo);
  712. textOut(canvas, x - _ws - getTimeColonWidth(_wc) - _wm - getTimeColonWidth(_wc) - _wh, y, hours, widthchar, &fontInfo);
  713. }
  714. }
  715. else if (fontInfo.alignFlags == ALIGN_LEFT)
  716. {
  717. x = (r.left + 2) - shadowx[alt] + lpadding;
  718. switch (valign[alt])
  719. {
  720. case ALIGN_CENTER:
  721. y = r.top + ((r.bottom - r.top - h) / 2);
  722. break;
  723. case ALIGN_TOP:
  724. y = r.top;
  725. break;
  726. }
  727. x += offsetx;
  728. y += offsety;
  729. if (shadowx != 0 || shadowy != 0)
  730. {
  731. fontInfo.color = getShadowColor(alt);
  732. if(timerhours && hours[0])
  733. {
  734. textOut(canvas, x, y, hours, widthchar, &fontInfo);
  735. textOut(canvas, x + _wh, y, L":", widthchar, &fontInfo);
  736. textOut(canvas, x + _wh + getTimeColonWidth(_wc), y, mins, widthchar, &fontInfo);
  737. textOut(canvas, x + _wh + getTimeColonWidth(_wc) + _wm, y, L":", widthchar, &fontInfo);
  738. textOut(canvas, x + _wh + getTimeColonWidth(_wc) + _wm + getTimeColonWidth(_wc), y, secs, widthchar, &fontInfo);
  739. }
  740. else
  741. {
  742. textOut(canvas, x, y, mins, widthchar, &fontInfo);
  743. textOut(canvas, x + _wm, y, L":", widthchar, &fontInfo);
  744. textOut(canvas, x + _wm + getTimeColonWidth(_wc), y, secs, widthchar, &fontInfo);
  745. }
  746. fontInfo.color = GetColor(alt);
  747. }
  748. x += shadowx[alt]; y += shadowy[alt];
  749. if(timerhours && hours[0])
  750. {
  751. textOut(canvas, x, y, hours, widthchar, &fontInfo);
  752. textOut(canvas, x + _wh, y, L":", widthchar, &fontInfo);
  753. textOut(canvas, x + _wh + getTimeColonWidth(_wc), y, mins, widthchar, &fontInfo);
  754. textOut(canvas, x + _wh + getTimeColonWidth(_wc) + _wm, y, L":", widthchar, &fontInfo);
  755. textOut(canvas, x + _wh + getTimeColonWidth(_wc) + _wm + getTimeColonWidth(_wc), y, secs, widthchar, &fontInfo);
  756. }
  757. else{
  758. textOut(canvas, x, y, mins, widthchar, &fontInfo);
  759. textOut(canvas, x + _wm, y, L":", widthchar, &fontInfo);
  760. textOut(canvas, x + _wm + getTimeColonWidth(_wc), y, secs, widthchar, &fontInfo);
  761. }
  762. }
  763. else if (fontInfo.alignFlags == ALIGN_CENTER)
  764. {
  765. if(timerhours && hours[0])
  766. x = (r.left + ((r.right - r.left - _ws - _wm - _wh - getTimeColonWidth(_wc)) / 3)) - shadowx[alt];
  767. else
  768. x = (r.left + ((r.right - r.left - _ws - _wm - getTimeColonWidth(_wc)) / 2)) - shadowx[alt];
  769. switch (valign[alt])
  770. {
  771. case ALIGN_CENTER:
  772. y = r.top + ((r.bottom - r.top - h) / 2);
  773. break;
  774. case ALIGN_TOP:
  775. y = r.top;
  776. break;
  777. }
  778. x += offsetx;
  779. y += offsety;
  780. if (shadowx[alt] != 0 || shadowy[alt] != 0)
  781. {
  782. fontInfo.color = getShadowColor(alt);
  783. if(timerhours && hours[0])
  784. {
  785. textOut(canvas, x, y, hours, widthchar, &fontInfo);
  786. textOut(canvas, x + _wh, y, L":", widthchar, &fontInfo);
  787. textOut(canvas, x + _wh + getTimeColonWidth(_wc), y, mins, widthchar, &fontInfo);
  788. textOut(canvas, x + _wh + getTimeColonWidth(_wc) + _wm, y, L":", widthchar, &fontInfo);
  789. textOut(canvas, x + _wh + getTimeColonWidth(_wc) + _wm + getTimeColonWidth(_wc), y, secs, widthchar, &fontInfo);
  790. }
  791. else{
  792. textOut(canvas, x, y, mins, widthchar, &fontInfo);
  793. textOut(canvas, x + _wm, y, L":", widthchar, &fontInfo);
  794. textOut(canvas, x + _wm + getTimeColonWidth(_wc), y, secs, widthchar, &fontInfo);
  795. }
  796. fontInfo.color = GetColor(alt);
  797. }
  798. x += shadowx[alt]; y += shadowy[alt];
  799. if(timerhours && hours[0])
  800. {
  801. textOut(canvas, x, y, hours, widthchar, &fontInfo);
  802. textOut(canvas, x + _wh, y, L":", widthchar, &fontInfo);
  803. textOut(canvas, x + _wh + getTimeColonWidth(_wc), y, mins, widthchar, &fontInfo);
  804. textOut(canvas, x + _wh + getTimeColonWidth(_wc) + _wm, y, L":", widthchar, &fontInfo);
  805. textOut(canvas, x + _wh + getTimeColonWidth(_wc) + _wm + getTimeColonWidth(_wc), y, secs, widthchar, &fontInfo);
  806. }
  807. else{
  808. textOut(canvas, x, y, mins, widthchar, &fontInfo);
  809. textOut(canvas, x + _wm, y, L":", widthchar, &fontInfo);
  810. textOut(canvas, x + _wm + getTimeColonWidth(_wc), y, secs, widthchar, &fontInfo);
  811. }
  812. }
  813. cur_len = _ws + _wm + getTimeColonWidth(_wc);
  814. }
  815. bufferinvalid = 0;
  816. }
  817. // alpha is taken care of in our bufferpaintwnd
  818. return 1;
  819. }
  820. void Text::timerCallback(int id)
  821. {
  822. int upd = 0;
  823. if (id == TIMER_SKIPCFG)
  824. {
  825. #ifdef WASABI_COMPILE_CONFIG
  826. const GUID uioptions_guid =
  827. { 0x9149c445, 0x3c30, 0x4e04, { 0x84, 0x33, 0x5a, 0x51, 0x8e, 0xd0, 0xfd, 0xde } };
  828. CfgItem *item = WASABI_API_CONFIG->config_getCfgItemByGuid(uioptions_guid);
  829. if (item != NULL)
  830. {
  831. float f = (float)item->getDataAsFloat(L"Text Ticker Speed", 1.0f / 2.0f);
  832. skipn = (int)((1.0f / f) - 1 + 0.5f);
  833. }
  834. #endif
  835. }
  836. if (id == TICKER_RESET_ALTNAME)
  837. {
  838. killTimer(id);
  839. setAlternateName(NULL);
  840. }
  841. if (getAlternateName() == NULL || !*getAlternateName())
  842. {
  843. if (id == TICKER_TIMER_POS)
  844. {
  845. #ifdef WASABI_COMPILE_MEDIACORE
  846. wchar_t txt[4096] = {0};
  847. // TODO: Change the way to get the current status text
  848. switch (display)
  849. {
  850. #ifdef WASABI_COMPILE_METADB
  851. case DISPLAY_SONGALBUM:
  852. {
  853. const char *cur = WASABI_API_CORE->core_getCurrent(0);
  854. if (cur && (WASABI_API_METADB->metadb_getMetaData(cur, MT_ALBUM, txt, 4095, MDT_STRINGZ)))
  855. {
  856. if (!lastText.getValue() || STRCMP(txt, lastText.getValue()))
  857. {
  858. upd = 1;
  859. setName(txt);
  860. }
  861. }
  862. if (upd)
  863. {
  864. lastText = txt;
  865. resetTicker();
  866. }
  867. }
  868. break;
  869. #endif
  870. case DISPLAY_SONGLENGTH:
  871. {
  872. int len = -1;
  873. #ifdef WASABI_COMPILE_METADB
  874. const char *cur = WASABI_API_CORE->core_getCurrent(0);
  875. if (cur && (WASABI_API_METADB->metadb_getMetaData(cur, MT_LENGTH, (char *)&len, 4, MDT_TIME)) && len != -1)
  876. {
  877. #else
  878. len = WASABI_API_MEDIACORE->core_getLength(0);
  879. if (len != -1)
  880. {
  881. #endif
  882. if (timerhours)
  883. TimeFmt::printHourMinSec(len / 1000, txt, 4096, timerhoursRollover);
  884. else
  885. TimeFmt::printMinSec(len / 1000, txt, 4096);
  886. if (!lastText.getValue() || wcscmp(txt, lastText.getValue()))
  887. {
  888. upd = 1;
  889. setName(txt);
  890. }
  891. }
  892. if (upd)
  893. {
  894. lastText = txt;
  895. resetTicker();
  896. }
  897. }
  898. break;
  899. #ifdef WASABI_COMPILE_METADB
  900. case DISPLAY_SONGARTIST:
  901. {
  902. const char *cur = WASABI_API_CORE->core_getCurrent(0);
  903. if (cur && (WASABI_API_METADB->metadb_getMetaData(cur, MT_ARTIST, txt, 4095, MDT_STRINGZ)))
  904. {
  905. if (!lastText.getValue() || STRCMP(txt, lastText.getValue()))
  906. {
  907. upd = 1;
  908. setName(txt);
  909. }
  910. }
  911. if (upd)
  912. {
  913. lastText = txt;
  914. resetTicker();
  915. }
  916. }
  917. break;
  918. #endif
  919. case DISPLAY_SONGNAME:
  920. case DISPLAY_SONGTITLE:
  921. {
  922. WCSCPYN(txt, WASABI_API_MEDIACORE->core_getTitle(0), 4096);
  923. {
  924. if (showlen)
  925. {
  926. int length = wa2.getLength();
  927. if (length != 0 && length != -1)
  928. {
  929. length /= 1000;
  930. if (wcslen(txt) < 4095 - 25)
  931. wcscat(txt, StringPrintfW(L" (%d:%02d)", length / 60, length % 60));
  932. }
  933. }
  934. if (!lastText.getValue() || wcscmp(txt, lastText.getValue()))
  935. {
  936. upd = 1;
  937. setName(txt);
  938. }
  939. }
  940. if (upd)
  941. {
  942. lastText = txt;
  943. resetTicker();
  944. }
  945. }
  946. break;
  947. case DISPLAY_TIME:
  948. {
  949. int cp = WASABI_API_MEDIACORE->core_getPosition(0);
  950. if (cp < 0)
  951. {
  952. switch (timeroffstyle)
  953. {
  954. case 0:
  955. wcsncpy(txt, L" : ", 4096);
  956. break;
  957. case 1:
  958. StringCbPrintfW(txt, sizeof(txt), L"%s00:00", elapsed ? L"" : L"-");
  959. break;
  960. case 2:
  961. *txt = 0;
  962. break;
  963. case 3:
  964. StringCbPrintfW(txt, sizeof(txt), L"%s0:00:00", elapsed ? L"" : L"-");
  965. break;
  966. case 4:
  967. wcsncpy(txt, L" : : ", 4096);
  968. break;
  969. }
  970. }
  971. else
  972. {
  973. int p;
  974. int len = WASABI_API_MEDIACORE->core_getLength(0);
  975. int el = elapsed;
  976. if (len == -1000 || el == -1)
  977. el = 1; // no remaining time on http streams, etc...
  978. if (el)
  979. p = cp / 1000;
  980. else
  981. p = (len - cp) / 1000;
  982. if (!el) p = -p;
  983. if (timerhours)
  984. TimeFmt::printHourMinSec(p, txt, 4096, timerhoursRollover);
  985. else
  986. TimeFmt::printMinSec(p, txt, 4096);
  987. }
  988. if (!lastText.getValue() || wcscmp(txt, lastText.getValue()))
  989. {
  990. setName(txt);
  991. upd = 1;
  992. lastText = txt;
  993. }
  994. }
  995. break;
  996. }
  997. int u = 0;
  998. advanceTicker(&u);
  999. if (u) invalidateBuffer();
  1000. #endif
  1001. }
  1002. else
  1003. {
  1004. TEXT_PARENT::timerCallback(id);
  1005. }
  1006. }
  1007. if (upd)
  1008. {
  1009. invalidateTextBuffer();
  1010. }
  1011. }
  1012. void Text::advanceTicker(int *upd)
  1013. {
  1014. // update tts stuff
  1015. if (ticker && !grab && isVisible())
  1016. {
  1017. int oldpos = textpos;
  1018. RECT re = clientRect();
  1019. if (cur_len < (re.right - re.left - 2)) textpos = 0;
  1020. else if (tts > 0) tts -= (timerclient_getSkipped() + 1);
  1021. else
  1022. {
  1023. if (skip < skipn) skip++;
  1024. else
  1025. {
  1026. skip = 0;
  1027. if (!sens) textpos += tickerstep * (timerclient_getSkipped() + 1); else textpos -= tickerstep * (timerclient_getSkipped() + 1);
  1028. if (textpos < 0) textpos = 0;
  1029. if (textpos > cur_len - (re.right - re.left - 2)) textpos = cur_len - (re.right - re.left - 2);
  1030. if (cur_len <= (textpos + re.right - re.left - 2))
  1031. {
  1032. sens = 1;
  1033. tts = time_tts;
  1034. }
  1035. if (textpos <= 0)
  1036. {
  1037. sens = 0;
  1038. textpos = 0;
  1039. tts = time_tts;
  1040. }
  1041. }
  1042. }
  1043. if (textpos != oldpos && upd != NULL) *upd = 1;
  1044. }
  1045. }
  1046. void Text::setTimeDisplayMode(int remaining)
  1047. {
  1048. if (fixedTimerStyle)
  1049. return;
  1050. elapsed = !remaining;
  1051. Layout *l = getGuiObject()->guiobject_getParentLayout();
  1052. if (l && l->getId())
  1053. WASABI_API_CONFIG->setIntPrivate(StringPrintfW(L"%s/timer_elapsed", l->getId()), elapsed);
  1054. else
  1055. WASABI_API_CONFIG->setIntPrivate(L"timer_elapsed", elapsed);
  1056. invalidateTextBuffer();
  1057. }
  1058. int Text::onLeftButtonDown(int x, int y)
  1059. {
  1060. if (!TEXT_PARENT::onLeftButtonDown(x, y))
  1061. {
  1062. grab = 0;
  1063. return 0;
  1064. }
  1065. if (nograb || wrapped) return 0;
  1066. if (display == DISPLAY_TIME)
  1067. {
  1068. elapsed = !elapsed;
  1069. #ifdef WIN32
  1070. // HACK! lone needs to make that a cfg attrib, but no time, a build needs to go out :D
  1071. #define WINAMP_OPTIONS_ELAPSED 40037
  1072. #define WINAMP_OPTIONS_REMAINING 40038
  1073. if (!fixedTimerStyle) SendMessageW(WASABI_API_WND->main_getRootWnd()->gethWnd(), WM_COMMAND, elapsed ? WINAMP_OPTIONS_ELAPSED : WINAMP_OPTIONS_REMAINING, 0);
  1074. #endif
  1075. #ifdef WASABI_COMPILE_WNDMGR
  1076. #ifdef WASABI_COMPILE_CONFIG
  1077. if (getGuiObject())
  1078. {
  1079. Layout *l = getGuiObject()->guiobject_getParentLayout();
  1080. if (l && l->getId()) WASABI_API_CONFIG->setIntPrivate(StringPrintfW(L"%s/timer_elapsed%s", l->getId(), (fixedTimerStyle ? StringPrintfW(L".%s", this->getId()) : L"")), elapsed);
  1081. else WASABI_API_CONFIG->setIntPrivate(L"timer_elapsed", elapsed);
  1082. }
  1083. else WASABI_API_CONFIG->setIntPrivate(L"timer_elapsed", elapsed);
  1084. #endif
  1085. #endif
  1086. timerCallback(TICKER_TIMER_POS);
  1087. return 1;
  1088. }
  1089. grab = 1;
  1090. grab_x = x + textpos;
  1091. // onMouseMove(x,y);
  1092. return 1;
  1093. }
  1094. int Text::onMouseMove(int x, int y)
  1095. {
  1096. if (!TEXT_PARENT::onMouseMove(x, y))
  1097. {
  1098. grab = 0;
  1099. }
  1100. //POINT pos = {x, y};
  1101. //clientToScreen(&pos);
  1102. if (!grab) return 1;
  1103. textpos = grab_x - x;
  1104. RECT re;
  1105. getClientRect(&re);
  1106. textpos = min(textpos, cur_len - ((re.right - re.left) - 2) - 1);
  1107. if (textpos < 0) textpos = 0;
  1108. invalidateBuffer();
  1109. return 1;
  1110. }
  1111. int Text::onLeftButtonUp(int x, int y)
  1112. {
  1113. if (!TEXT_PARENT::onLeftButtonUp(x, y))
  1114. {
  1115. grab = 0;
  1116. return 0;
  1117. }
  1118. if (nograb) return 0;
  1119. grab = 0;
  1120. tts = time_tts;
  1121. return 1;
  1122. }
  1123. #ifdef WASABI_COMPILE_MEDIACORE
  1124. int Text::corecb_onStatusMsg(const wchar_t *text)
  1125. {
  1126. if (display == DISPLAY_SONGNAME)
  1127. setAlternateName(text);
  1128. return 0;
  1129. }
  1130. int Text::corecb_onBitrateChange(int kbps)
  1131. {
  1132. if (display == DISPLAY_SONGBITRATE)
  1133. {
  1134. if (kbps)
  1135. {
  1136. wchar_t bitrate[64] = {0};
  1137. WCSNPRINTF(bitrate, 64, L"%d", kbps);
  1138. setName(bitrate);
  1139. }
  1140. else
  1141. setName(L"");
  1142. }
  1143. return 0;
  1144. }
  1145. int Text::corecb_onSampleRateChange(int hz)
  1146. {
  1147. if (display == DISPLAY_SONGSAMPLERATE)
  1148. {
  1149. if (hz)
  1150. {
  1151. wchar_t sampleRate[64] = {0};
  1152. WCSNPRINTF(sampleRate, 64, L"%d", hz);
  1153. setName(sampleRate);
  1154. }
  1155. else
  1156. setName(L"");
  1157. }
  1158. return 0;
  1159. }
  1160. int Text::corecb_onInfoChange(const wchar_t *text)
  1161. {
  1162. switch (display)
  1163. {
  1164. case DISPLAY_SONGINFO:
  1165. case DISPLAY_SONGINFO_TRANSLATED:
  1166. setName(text);
  1167. break;
  1168. case DISPLAY_TIME:
  1169. timerCallback(TICKER_TIMER_POS);
  1170. break;
  1171. }
  1172. return 0;
  1173. }
  1174. int Text::corecb_onStopped()
  1175. {
  1176. switch (display)
  1177. {
  1178. case DISPLAY_SONGINFO:
  1179. case DISPLAY_SONGINFO_TRANSLATED:
  1180. case DISPLAY_SONGBITRATE:
  1181. case DISPLAY_SONGSAMPLERATE:
  1182. setName(L"");
  1183. break;
  1184. case DISPLAY_TIME:
  1185. timerCallback(TICKER_TIMER_POS);
  1186. break;
  1187. }
  1188. return 0;
  1189. }
  1190. int Text::corecb_onStarted()
  1191. {
  1192. /* if (display == DISPLAY_TIME) {
  1193. timerCallback(TICKER_TIMER_POS);
  1194. }*/
  1195. return 0;
  1196. }
  1197. int Text::corecb_onSeeked(int newpos)
  1198. {
  1199. if (display == DISPLAY_TIME)
  1200. timerCallback(TICKER_TIMER_POS);
  1201. return 0;
  1202. }
  1203. #endif //mediacore
  1204. void Text::invalidateTextBuffer()
  1205. {
  1206. bufferinvalid = 1;
  1207. invalidateBuffer();
  1208. }
  1209. int Text::setTextSize(int newsize, int alt)
  1210. {
  1211. if (alt < 0 || alt > 1) alt = 0;
  1212. if (newsize < 1 || newsize > 72) return 0;
  1213. size[alt] = newsize;
  1214. invalidateTextBuffer();
  1215. return 1;
  1216. }
  1217. void Text::setTickering(int enable)
  1218. {
  1219. ticker = enable;
  1220. if (!enable) textpos = 0;
  1221. invalidateTextBuffer();
  1222. }
  1223. void Text::setDisplay(int disp)
  1224. {
  1225. if (disp == display) return ;
  1226. if (textfeed)
  1227. {
  1228. viewer_delViewItem(textfeed->getDependencyPtr());
  1229. feed_id = L"";
  1230. SvcEnum::release(textfeed);
  1231. textfeed = NULL;
  1232. }
  1233. display = disp;
  1234. if (isPostOnInit()) initDisplay();
  1235. if (disp == DISPLAY_SERVICE && isPostOnInit())
  1236. registerToTextFeedService();
  1237. invalidateTextBuffer();
  1238. }
  1239. void Text::setAlternateName(const wchar_t *s)
  1240. {
  1241. if (((!s || !*s) && alternatename.isempty()) || WCSCASEEQLSAFE(alternatename, s)) return ;
  1242. killTimer(TICKER_RESET_ALTNAME);
  1243. alternatename = parseText(s);
  1244. onTextChanged(getPrintedText());
  1245. resetTicker();
  1246. invalidate();
  1247. setTimer(TICKER_RESET_ALTNAME, 1000);
  1248. }
  1249. void Text::setText(const wchar_t *t)
  1250. {
  1251. deftext = parseText(t);
  1252. invalidate();
  1253. onTextChanged(getPrintedText());
  1254. }
  1255. const wchar_t *Text::parseText(const wchar_t *s)
  1256. {
  1257. static wchar_t t[4096];
  1258. if (!s) return NULL;
  1259. WCSCPYN(t, s, 4096);
  1260. wchar_t *p = t;
  1261. while (p && *p && *(p + 1))
  1262. {
  1263. if (*p == '\\' && *(p + 1) == 'n')
  1264. {
  1265. // TODO check
  1266. wcscpy(p, p + 1);
  1267. t[wcslen(t)] = 0;
  1268. *p = '\n';
  1269. }
  1270. p++;
  1271. }
  1272. return t;
  1273. }
  1274. void Text::onTextChanged(const wchar_t *txt)
  1275. {
  1276. if (WCSCASEEQLSAFE(lasttxt, txt)) return ;
  1277. lasttxt = txt;
  1278. invalidate();
  1279. int w = getTextWidth();
  1280. if (w != lastautowidth)
  1281. notifyParent(ChildNotify::AUTOWHCHANGED);
  1282. lastautowidth = w;
  1283. script_vcpu_onTextChanged(SCRIPT_CALL, getScriptObject(), MAKE_SCRIPT_STRING(lasttxt));
  1284. invalidateTextBuffer();
  1285. }
  1286. const wchar_t *Text::getPrintedText()
  1287. {
  1288. const wchar_t *name = getAlternateName();
  1289. if (!name || !*name)
  1290. name = deftext.getValue();
  1291. if (!name || !*name)
  1292. name = getName();
  1293. if (name == NULL)
  1294. return L"";
  1295. #if defined(WASABI_STATICVARMGR) || !defined(WASABINOMAINAPI)
  1296. if (wantTranslation())
  1297. {
  1298. StringW *s = PublicVarManager::translate(name, getGuiObject());
  1299. if (s != NULL)
  1300. {
  1301. printedtxt.swap(s);
  1302. delete s;
  1303. return printedtxt.getValueSafe();
  1304. }
  1305. }
  1306. return name;
  1307. #else
  1308. return name;
  1309. #endif
  1310. }
  1311. void Text::onSetName()
  1312. {
  1313. invalidateTextBuffer();
  1314. onTextChanged(getPrintedText());
  1315. }
  1316. const wchar_t *Text::getAlternateName(void)
  1317. {
  1318. if (alternatename.isempty()) return NULL;
  1319. return alternatename;
  1320. }
  1321. void Text::setTimerOffStyle(int o)
  1322. {
  1323. if (timeroffstyle == o) return ;
  1324. timeroffstyle = o;
  1325. invalidateTextBuffer();
  1326. }
  1327. void Text::setTimerHours(int o)
  1328. {
  1329. if (timerhours == o) return ;
  1330. timerhours = o;
  1331. invalidateTextBuffer();
  1332. }
  1333. void Text::setTimerHoursRollover(int o)
  1334. {
  1335. if (timerhoursRollover == o) return ;
  1336. timerhoursRollover = o;
  1337. invalidateTextBuffer();
  1338. }
  1339. void Text::setTimeTTS(int tts)
  1340. {
  1341. time_tts = tts;
  1342. invalidateTextBuffer();
  1343. }
  1344. void Text::resetTicker()
  1345. {
  1346. sens = 0;
  1347. textpos = 0;
  1348. tts = time_tts;
  1349. invalidateBuffer();
  1350. }
  1351. void Text::setTimeColonWidth(int w)
  1352. {
  1353. timecolonw = w;
  1354. invalidateTextBuffer();
  1355. }
  1356. int Text::getTimeColonWidth(int def)
  1357. {
  1358. return timecolonw == -1 ? def : timecolonw;
  1359. }
  1360. void Text::textOut(Canvas *canvas, int x, int y, const wchar_t *txt, wchar_t widthchar, const Wasabi::FontInfo *fontInfo)
  1361. {
  1362. if (widthchar == 0)
  1363. {
  1364. canvas->textOut(x, y, txt, fontInfo);
  1365. return ;
  1366. }
  1367. wchar_t wc[2] = { widthchar, 0 };
  1368. int cwidth = canvas->getTextWidth(wc, fontInfo);
  1369. int slen = wcslen(txt);
  1370. for (int i = 0; i < slen; i++)
  1371. {
  1372. wc[0] = txt[i];
  1373. int dw = cwidth - canvas->getTextWidth(wc, fontInfo); // get difference
  1374. canvas->textOut(x + dw / 2, y, wc, fontInfo);
  1375. x += cwidth;
  1376. }
  1377. }
  1378. void Text::addCBSource(const wchar_t *cbsource)
  1379. {
  1380. StringW *s = new StringW(cbsource);
  1381. mycbid.addItem(s);
  1382. }
  1383. int Text::getTextWidth()
  1384. {
  1385. const wchar_t *txt = getAlternateName() ? getAlternateName() : isInited() ? getName() : NULL;
  1386. if (!txt) txt = deftext.getValue();
  1387. if (!txt) return 0;
  1388. #ifdef WA3COMPATIBILITY
  1389. /*
  1390. String *translate = PublicVarManager::translate(thaname, getGuiObject());
  1391. if (translate)
  1392. thanme = translate->getValueSafe();
  1393. */
  1394. #endif
  1395. //txt = _(txt);
  1396. int alt = 0;
  1397. #ifdef WASABI_COMPILE_CONFIG
  1398. // {280876CF-48C0-40bc-8E86-73CE6BB462E5}
  1399. const GUID options_guid =
  1400. { 0x280876cf, 0x48c0, 0x40bc, { 0x8e, 0x86, 0x73, 0xce, 0x6b, 0xb4, 0x62, 0xe5 } };
  1401. CfgItem *item = WASABI_API_CONFIG->config_getCfgItemByGuid(options_guid);
  1402. if (item != NULL)
  1403. {
  1404. alt = item->getDataAsInt(L"Alternate Fonts", 0);
  1405. if (alt < 0 || alt > 1) alt = 0;
  1406. }
  1407. if (alt)
  1408. {
  1409. if (item && item->getDataAsInt(L"No 7-bit TTF AltFonts", 1))
  1410. {
  1411. const wchar_t *p = (const wchar_t *)txt;
  1412. while (p && *p)
  1413. {
  1414. if (*p > 127) break;
  1415. p++;
  1416. }
  1417. if (p && !*p) alt = 0;
  1418. }
  1419. }
  1420. #endif
  1421. TextInfoCanvas canvas(this);
  1422. Wasabi::FontInfo fontInfo;
  1423. GetFontInfo(&fontInfo, alt);
  1424. int w = canvas.getTextWidth(txt, &fontInfo) + 4;
  1425. // delete txt;
  1426. return w;
  1427. }
  1428. void Text::registerToTextFeedService()
  1429. {
  1430. if (!registered_syscb++) WASABI_API_SYSCB->syscb_registerCallback(static_cast<SvcCallbackI*>(this));
  1431. if (textfeed)
  1432. {
  1433. viewer_delViewItem(textfeed->getDependencyPtr());
  1434. feed_id = L"";
  1435. SvcEnum::release(textfeed);
  1436. textfeed = NULL;
  1437. }
  1438. if (!displaystr.isempty()) textfeed = TextFeedEnum(displaystr).getFirst();
  1439. if (textfeed != NULL)
  1440. {
  1441. feed_id = displaystr;
  1442. viewer_addViewItem(textfeed->getDependencyPtr());
  1443. }
  1444. }
  1445. void Text::svccb_onSvcRegister(FOURCC type, waServiceFactory *svc)
  1446. {
  1447. if (type == WaSvc::TEXTFEED)
  1448. {
  1449. //CUTif (!displaystr.isempty()) {
  1450. //CUTDebugString("RERERERER %s", displaystr.v());
  1451. //CUT}
  1452. registerToTextFeedService();
  1453. }
  1454. }
  1455. int Text::viewer_onEvent(api_dependent *item, const GUID *classguid, int event, intptr_t param, void *ptr, size_t ptrlen)
  1456. {
  1457. if (textfeed && item == textfeed->getDependencyPtr())
  1458. {
  1459. if (event == svc_textFeed::Event_TEXTCHANGE && WCSCASEEQLSAFE((const wchar_t *)param, feed_id))
  1460. {
  1461. //CUTDebugString("got feed '%s'", (const char *)ptr);
  1462. setName((const wchar_t *)ptr);
  1463. return 1;
  1464. }
  1465. }
  1466. else if (classguid && *classguid == *Container::depend_getClassGuid())
  1467. {
  1468. onSetName();
  1469. return 1;
  1470. }
  1471. return 0;
  1472. }
  1473. int Text::triggerEvent(int event, intptr_t p1, intptr_t p2)
  1474. {
  1475. int r = TEXT_PARENT::triggerEvent(event, p1, p2);
  1476. if (event == TRIGGER_ONRESIZE)
  1477. notifyParent(ChildNotify::AUTOWHCHANGED);
  1478. if (event == TRIGGER_INVALIDATE)
  1479. invalidateTextBuffer();
  1480. return r;
  1481. }
  1482. COLORREF Text::getShadowColor(int alt)
  1483. {
  1484. if (alt < 0 || alt > 1) alt = 0;
  1485. if (shadowcolor_mode[alt] == COLORMODE_SKINCOLOR) return sshadowcolor[alt];
  1486. return shadowcolor[alt].getColor();
  1487. }
  1488. TextScriptController _textController;
  1489. TextScriptController *textController = &_textController;
  1490. // -- Functions table -------------------------------------
  1491. function_descriptor_struct TextScriptController::exportedFunction[] =
  1492. {
  1493. {L"setText", 1, (void*)Text::script_vcpu_setText },
  1494. {L"setAlternateText", 1, (void*)Text::script_vcpu_setAlternateText },
  1495. {L"getText", 0, (void*)Text::script_vcpu_getText },
  1496. {L"getTextWidth", 0, (void*)Text::script_vcpu_getTextWidth },
  1497. {L"onTextChanged", 1, (void*)Text::script_vcpu_onTextChanged },
  1498. };
  1499. // --------------------------------------------------------
  1500. const wchar_t *TextScriptController::getClassName()
  1501. {
  1502. return L"Text";
  1503. }
  1504. const wchar_t *TextScriptController::getAncestorClassName()
  1505. {
  1506. return L"GuiObject";
  1507. }
  1508. ScriptObject *TextScriptController::instantiate()
  1509. {
  1510. Text *t = new Text;
  1511. ASSERT(t != NULL);
  1512. return t->getScriptObject();
  1513. }
  1514. void TextScriptController::destroy(ScriptObject *o)
  1515. {
  1516. Text *t = static_cast<Text *>(o->vcpu_getInterface(textGuid));
  1517. ASSERT(t != NULL);
  1518. delete t;
  1519. }
  1520. void *TextScriptController::encapsulate(ScriptObject *o)
  1521. {
  1522. return NULL; // no encapsulation for text yet
  1523. }
  1524. void TextScriptController::deencapsulate(void *o)
  1525. {}
  1526. int TextScriptController::getNumFunctions()
  1527. {
  1528. return sizeof(exportedFunction) / sizeof(function_descriptor_struct);
  1529. }
  1530. const function_descriptor_struct *TextScriptController::getExportedFunctions()
  1531. {
  1532. return exportedFunction;
  1533. }
  1534. GUID TextScriptController::getClassGuid()
  1535. {
  1536. return textGuid;
  1537. }
  1538. const wchar_t *Text::vcpu_getClassName()
  1539. {
  1540. return L"Text";
  1541. }
  1542. scriptVar Text::script_vcpu_setText(SCRIPT_FUNCTION_PARAMS, ScriptObject *o, scriptVar t)
  1543. {
  1544. SCRIPT_FUNCTION_INIT
  1545. ASSERT(t.type == SCRIPT_STRING);
  1546. Text *tx = static_cast<Text *>(o->vcpu_getInterface(textGuid));
  1547. if (tx) tx->setText(GET_SCRIPT_STRING(t));
  1548. RETURN_SCRIPT_VOID;
  1549. }
  1550. scriptVar Text::script_vcpu_setAlternateText(SCRIPT_FUNCTION_PARAMS, ScriptObject *o, scriptVar t)
  1551. {
  1552. SCRIPT_FUNCTION_INIT
  1553. ASSERT(t.type == SCRIPT_STRING);
  1554. Text *tx = static_cast<Text *>(o->vcpu_getInterface(textGuid));
  1555. if (tx) tx->setAlternateName(GET_SCRIPT_STRING(t));
  1556. RETURN_SCRIPT_VOID;
  1557. }
  1558. scriptVar Text::script_vcpu_getText(SCRIPT_FUNCTION_PARAMS, ScriptObject *o)
  1559. {
  1560. SCRIPT_FUNCTION_INIT
  1561. Text *t = static_cast<Text *>(o->vcpu_getInterface(textGuid));
  1562. if (t)
  1563. {
  1564. const wchar_t *from = t->getPrintedText();
  1565. // BU rewrote in response to talkback for 489
  1566. if (from == NULL || *from == '\0') from = t->getLastText();
  1567. if (from == NULL || *from == '\0') from = L"";
  1568. WCSCPYN(s_txt, from, 4096);
  1569. return MAKE_SCRIPT_STRING(s_txt);
  1570. }
  1571. return MAKE_SCRIPT_STRING(L"");
  1572. }
  1573. scriptVar Text::script_vcpu_getTextWidth(SCRIPT_FUNCTION_PARAMS, ScriptObject *o)
  1574. {
  1575. SCRIPT_FUNCTION_INIT
  1576. Text *t = static_cast<Text *>(o->vcpu_getInterface(textGuid));
  1577. if (t) return MAKE_SCRIPT_INT(t->getTextWidth());
  1578. return MAKE_SCRIPT_INT(0);
  1579. }
  1580. scriptVar Text::script_vcpu_onTextChanged(SCRIPT_FUNCTION_PARAMS, ScriptObject *o, scriptVar newtxt)
  1581. {
  1582. SCRIPT_FUNCTION_INIT;
  1583. PROCESS_HOOKS1(o, textController, newtxt);
  1584. SCRIPT_FUNCTION_CHECKABORTEVENT;
  1585. SCRIPT_EXEC_EVENT1(o, newtxt);
  1586. }
  1587. wchar_t Text::s_txt[WA_MAX_PATH] = {0};