#include #include "text.h" #include #include #ifdef WASABI_WIDGETS_COMPBUCK #include #endif #include #if defined(WA3COMPATIBILITY) || defined(WASABI_STATICVARMGR) #include #endif #include #include #ifdef WA3COMPATIBILITY #include #endif #include #include #include #include #include #ifdef WASABI_COMPILE_MEDIACORE #include #endif #include #include #include #include #include #include const wchar_t textXuiObjectStr[] = L"Text"; // This is the xml tag char textXuiSvcName[] = "Text xui object"; // this is the name of the xuiservice #define TTS_DELAY 4000 #define TICKER_TIMER_POS 1 #define TICKER_RESET_ALTNAME 2 #define TIMER_SKIPCFG 0x987 #define COLORMODE_RGB 0 #define COLORMODE_SKINCOLOR 1 XMLParamPair Text::params[] = { {TEXT_SETALTSHADOWCOLOR, L"ALTSHADOWCOLOR"}, {TEXT_SETALTSHADOWX, L"ALTSHADOWX"}, {TEXT_SETALTSHADOWY, L"ALTSHADOWY"}, {TEXT_SETALTVALIGN, L"ALTVALIGN"}, {TEXT_SETCBSOURCE, L"CBSOURCE"}, {TEXT_SETTEXT, L"DEFAULT"}, {TEXT_SETDISPLAY, L"DISPLAY"}, {TEXT_SETFORCEFIXED, L"FORCEFIXED"}, {TEXT_SETFORCELOCASE, L"FORCELOWERCASE"}, {TEXT_SETFORCELOCASE, L"FORCELOCASE"}, {TEXT_SETFORCEUPCASE, L"FORCEUPCASE"}, {TEXT_SETFORCEUPCASE, L"FORCEUPPERCASE"}, {TEXT_SETNOGRAB, L"NOGRAB"}, {TEXT_SETOFFSETX, L"OFFSETX"}, {TEXT_SETOFFSETY, L"OFFSETY"}, {TEXT_SETSHADOWCOLOR, L"SHADOWCOLOR"}, {TEXT_SETSHADOWX, L"SHADOWX"}, {TEXT_SETSHADOWY, L"SHADOWY"}, {TEXT_SETSHOWLEN, L"SHOWLEN"}, {TEXT_SETTEXT, L"TEXT"}, {TEXT_SETTICKER, L"TICKER"}, {TEXT_SETTICKERSTEP, L"TICKERSTEP"}, {TEXT_SETTIMECOLONWIDTH, L"TIMECOLONWIDTH"}, {TEXT_SETTIMERHOURS, L"TIMERHOURS"}, {TEXT_SETTIMEROFFSTYLE, L"TIMEROFFSTYLE"}, {TEXT_SETVALIGN, L"VALIGN"}, {TEXT_SETWRAPPED, L"WRAP"}, {TEXT_SETTIMERHOURSROLLOVER, L"TIMERHOURSROLLOVER"}, }; Text::Text() { getScriptObject()->vcpu_setInterface(textGuid, (void *)static_cast(this)); getScriptObject()->vcpu_setClassName(L"Text"); getScriptObject()->vcpu_setController(textController); //isbitmapfont = iswinfontrender = 0; bufferinvalid = 1; cachedsizew = 0; size[0] = size[1] = 0; textpos = 0; time_tts = 20; tts = time_tts; sens = 0; grab_x = 0; cur_len = 0; ticker = 0; timerhours = 0; timerhoursRollover = 0; display = DISPLAY_NONE; elapsed = 1; fixedTimerStyle = 0; shadowcolor[0].setColorGroup(L"Text backgrounds"); shadowcolor[0].setColor(RGB(0, 0, 0)); shadowcolor[1].setColorGroup(L"Text backgrounds"); shadowcolor[1].setColor(RGB(0, 0, 0)); shadowcolor_mode[0] = COLORMODE_RGB; shadowcolor_mode[1] = COLORMODE_RGB; shadowx[0] = shadowx[1] = shadowy[0] = shadowy[1] = 0; timecolonw = -1; timeroffstyle = 0; nograb = 0; showlen = 0; forcefixed = 0; forceupcase = 0; forcelocase = 0; lastautowidth = 32; textfeed = NULL; wrapped = 0; valign[0] = ALIGN_CENTER; valign[1] = ALIGN_CENTER; offsetx = 0; offsety = 0; tickerstep = 1; const GUID uioptions_guid = { 0x9149c445, 0x3c30, 0x4e04, { 0x84, 0x33, 0x5a, 0x51, 0x8e, 0xd0, 0xfd, 0xde } }; CfgItem *item = WASABI_API_CONFIG->config_getCfgItemByGuid(uioptions_guid); if (item != NULL) { float f = (float)item->getDataAsFloat(L"Text Ticker Speed", 1.0f / 2.0f); skipn = (int)((1.0f / f) - 1 + 0.5f); } skip = 0; xuihandle = newXuiHandle(); CreateXMLParameters(xuihandle); registered_syscb = 0; } void Text::CreateXMLParameters(int master_handle) { //TEXT_PARENT::CreateXMLParameters(master_handle); int numParams = sizeof(params) / sizeof(params[0]); hintNumberOfParams(xuihandle, numParams); for (int i = 0;i < numParams;i++) addParam(xuihandle, params[i], XUI_ATTRIBUTE_IMPLIED); } Text::~Text() { killTimer(TICKER_TIMER_POS); killTimer(TICKER_RESET_ALTNAME); killTimer(TIMER_SKIPCFG); if (registered_syscb) WASABI_API_SYSCB->syscb_deregisterCallback(static_cast(this)); #ifdef WASABI_WIDGETS_COMPBUCK if (display == DISPLAY_CB) if (mycbid.getNumItems() == 0) ComponentBucket2::unRegisterText(this); else for (int i = 0;i < mycbid.getNumItems();i++) ComponentBucket2::unRegisterText(this, mycbid.enumItem(i)->getValue()); #endif #ifdef WASABI_COMPILE_MEDIACORE WASABI_API_MEDIACORE->core_delCallback(0, this); #endif if (textfeed) { viewer_delViewItem(textfeed->getDependencyPtr()); SvcEnum::release(textfeed); textfeed = NULL; } mycbid.deleteAll(); } int Text::setXuiParam(int _xuihandle, int attrid, const wchar_t *name, const wchar_t *strval) { if (xuihandle != _xuihandle) return TEXT_PARENT::setXuiParam(_xuihandle, attrid, name, strval); switch (attrid) { #ifdef WASABI_COMPILE_MEDIACORE case TEXT_SETDISPLAY: displaystr = strval; setDisplay(SkinParser::getDisplay(strval)); if (!_wcsicmp(strval, L"TIMEREMAINING")) { fixedTimerStyle = 1; elapsed = 0; } else if (!_wcsicmp(strval, L"TIMEELAPSED")) { fixedTimerStyle = 1; elapsed = 1; } break; #endif case TEXT_SETTICKER: setTickering(WTOI(strval)); break; case TEXT_SETTEXT: { StringW old = getPrintedText(); deftext = parseText(strval); if (!WCSCASEEQLSAFE(old, getPrintedText())) { if (WCSCASEEQLSAFE(L":componentname", deftext) || WCSCASEEQLSAFE(L"@COMPONENTNAME@", deftext)) { Container *container = getGuiObject()->guiobject_getParentGroup()->getParentContainer(); viewer_addViewItem(container); } StringW str = getPrintedText(); onTextChanged(str); } break; } case TEXT_SETSHADOWCOLOR: if (WASABI_API_PALETTE->getColorElementRef(strval)) { shadowcolor_mode[0] = COLORMODE_SKINCOLOR; sshadowcolor[0] = strval; shadowcolor_mode[1] = COLORMODE_SKINCOLOR; sshadowcolor[1] = strval; } else setShadowColor(SkinParser::parseColor(strval), 0); break; case TEXT_SETALTSHADOWCOLOR: if (WASABI_API_PALETTE->getColorElementRef(strval)) { shadowcolor_mode[1] = COLORMODE_SKINCOLOR; sshadowcolor[1] = strval; } else setShadowColor(SkinParser::parseColor(strval), 1); break; case TEXT_SETSHADOWX: setShadowX(WTOI(strval)); break; case TEXT_SETALTSHADOWX: setShadowX(WTOI(strval), 1); break; case TEXT_SETSHADOWY: setShadowY(WTOI(strval)); break; case TEXT_SETALTSHADOWY: setShadowY(WTOI(strval), 0); break; case TEXT_SETTIMEROFFSTYLE: setTimerOffStyle(WTOI(strval)); break; case TEXT_SETTIMERHOURS: setTimerHours(WTOI(strval)); break; case TEXT_SETTIMERHOURSROLLOVER: setTimerHoursRollover(WTOI(strval)); break; case TEXT_SETTIMECOLONWIDTH: setTimeColonWidth(WTOI(strval)); break; case TEXT_SETNOGRAB: nograb = WTOI(strval); break; case TEXT_SETSHOWLEN: showlen = WTOI(strval); break; case TEXT_SETFORCEFIXED: forcefixed = WTOI(strval); break; case TEXT_SETFORCEUPCASE: forceupcase = WTOI(strval); break; case TEXT_SETFORCELOCASE: forcelocase = WTOI(strval); break; case TEXT_SETCBSOURCE: addCBSource(strval); break; case TEXT_SETWRAPPED: wrapped = WTOI(strval); if (isPostOnInit()) invalidateTextBuffer(); break; case TEXT_SETVALIGN: valign[0] = SkinParser::getAlign(strval); valign[1] = valign[0]; if (isPostOnInit()) invalidateTextBuffer(); break; case TEXT_SETALTVALIGN: valign[1] = SkinParser::getAlign(strval); if (isPostOnInit()) invalidateTextBuffer(); break; case TEXT_SETOFFSETX: offsetx = WTOI(strval); if (isPostOnInit()) invalidateTextBuffer(); break; case TEXT_SETTICKERSTEP: tickerstep = WTOI(strval); break; case TEXT_SETOFFSETY: offsety = WTOI(strval); if (isPostOnInit()) invalidateTextBuffer(); break; default: return 0; } return 1; } int Text::getPreferences(int what) { StringW thaname = getPrintedText(); if (thaname.isempty()) { return 32; } switch(wantTranslation()) { case 1: thaname = _(thaname); break; case 2: thaname = __(thaname); break; } int alt = 0; #ifdef WASABI_COMPILE_CONFIG // {280876CF-48C0-40bc-8E86-73CE6BB462E5} const GUID options_guid = { 0x280876cf, 0x48c0, 0x40bc, { 0x8e, 0x86, 0x73, 0xce, 0x6b, 0xb4, 0x62, 0xe5 } }; CfgItem *item = WASABI_API_CONFIG->config_getCfgItemByGuid(options_guid); if (item != NULL) { alt = item->getDataAsInt(L"Alternate Fonts", 0); if (alt < 0 || alt > 1) alt = 0; } if (alt) { if (item && item->getDataAsInt(L"No 7-bit TTF AltFonts", 1)) { const wchar_t *p = (const wchar_t *)thaname.getValue(); while (p && *p) { if (*p > 127) break; p++; } if (p && !*p) alt = 0; } } #endif switch (what) { case SUGGESTED_W: { int min_w = 0; if (forceupcase) thaname.toupper(); if (forcelocase) thaname.tolower(); TextInfoCanvas canvas(this); Wasabi::FontInfo fontInfo; GetFontInfo(&fontInfo, alt); const wchar_t *p = wcschr(thaname, ':'); if (display == DISPLAY_TIME && p) { wchar_t secs[256] = {0}; wchar_t mins[256] = {0}; WCSCPYN(mins, thaname, p - thaname); wcsncpy(secs, p + 1, 256); int fixw = canvas.getTextWidth(L"0", &fontInfo); int _ws = forcefixed ? fixw * wcslen(secs) : canvas.getTextWidth(secs, &fontInfo); int _wm = forcefixed ? fixw * wcslen(mins) : canvas.getTextWidth(mins, &fontInfo); int _wc = forcefixed ? fixw * wcslen(L":") : canvas.getTextWidth(L":", &fontInfo); min_w = _ws + _wm + getTimeColonWidth(_wc); } else { PathParserW ppg(thaname, L"\n"); for (int i = 0;i < ppg.getNumStrings();i++) { PathParserW pp(ppg.enumString(i), L"\t"); int w = 0; for (int j = 0; j < pp.getNumStrings(); j++) { w += canvas.getTextWidth(pp.enumString(j), &fontInfo) + 4; } min_w = MAX(min_w, w); } } return min_w + lpadding + rpadding; } case SUGGESTED_H: PathParserW pp(thaname, L"\n"); return fontsize[alt] * pp.getNumStrings(); } return TEXT_PARENT::getPreferences(what); } // supermegafucko! corehandle should mirror bitrate/samplerate/channels functions instead of text having to know about gen_ff ! -- will do that real soon #if defined(GEN_FF) & defined(WA5) #include "../../../../Plugins/General/gen_ff/wa2frontend.h" #endif int Text::onInit() { TEXT_PARENT::onInit(); registered_syscb++; initDisplay(); return 1; } void Text::initDisplay() { #ifdef WASABI_COMPILE_CONFIG setTimer(TIMER_SKIPCFG, 1000); #endif switch (display) { #ifdef WASABI_COMPILE_MEDIACORE case DISPLAY_SONGNAME: setName(WASABI_API_APP->main_getVersionString()); case DISPLAY_SONGARTIST: case DISPLAY_SONGALBUM: case DISPLAY_SONGLENGTH: case DISPLAY_SONGTITLE: #ifndef WASABI_COMPILE_METADB case DISPLAY_SONGINFO: case DISPLAY_SONGINFO_TRANSLATED: #endif setTimer(TICKER_TIMER_POS, 25); setTimeTTS(TTS_DELAY / 25); WASABI_API_MEDIACORE->core_addCallback(0, this); timerCallback(TICKER_TIMER_POS); #ifdef GEN_FF // supermegafucko! if(WASABI_API_MEDIACORE->core_getStatus(0) != 0){ if (display == DISPLAY_SONGINFO) { StringW txt; GET_SONG_INFO_TEXT(txt); corecb_onInfoChange(txt); } else if (display == DISPLAY_SONGINFO_TRANSLATED) { StringW txt; GET_SONG_INFO_TEXT_TRANSLATED(txt); corecb_onInfoChange(txt); } } #endif break; case DISPLAY_SONGBITRATE: WASABI_API_MEDIACORE->core_addCallback(0, this); corecb_onBitrateChange(wa2.getBitrate()); break; case DISPLAY_SONGSAMPLERATE: WASABI_API_MEDIACORE->core_addCallback(0, this); corecb_onSampleRateChange(wa2.getSamplerate()); break; case DISPLAY_TIME: #ifdef WASABI_COMPILE_CONFIG if (getGuiObject()) { Layout *l = getGuiObject()->guiobject_getParentLayout(); 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); else elapsed = WASABI_API_CONFIG->getIntPrivate(L"timer_elapsed", elapsed); } else elapsed = WASABI_API_CONFIG->getIntPrivate(L"timer_elapsed", elapsed); #endif setTimer(TICKER_TIMER_POS, 250); setTimeTTS(TTS_DELAY / 250); WASABI_API_MEDIACORE->core_addCallback(0, this); timerCallback(TICKER_TIMER_POS); break; #endif #ifdef WASABI_WIDGETS_COMPBUCK case DISPLAY_CB: setTimer(TICKER_TIMER_POS, 50); setTimeTTS(TTS_DELAY / 50); postDeferredCallback(DISPLAY_CB, 0); break; #endif case DISPLAY_SERVICE: registerToTextFeedService(); break; break; } } int Text::onDeferredCallback(intptr_t p1, intptr_t p2) { #ifdef WASABI_WIDGETS_COMPBUCK switch (p1) { case DISPLAY_CB: if (mycbid.getNumItems() == 0) ComponentBucket2::registerText(this); else for (int i = 0;i < mycbid.getNumItems();i++) ComponentBucket2::registerText(this, mycbid.enumItem(i)->getValue()); return 0; } #endif return TEXT_PARENT::onDeferredCallback(p1, p2); } void Text::setShadowColor(COLORREF c, int alt) { if (alt < 0 || alt > 1) alt = 0; shadowcolor_mode[alt] = COLORMODE_RGB; shadowcolor[alt].setColor(c); invalidateTextBuffer(); if (alt == 0) setShadowColor(c, 1); } void Text::setShadowX(int x, int alt) { if (alt < 0 || alt > 1) alt = 0; shadowx[alt] = x; invalidateTextBuffer(); if (alt == 0) setShadowX(x, 1); } void Text::setShadowY(int y, int alt) { if (alt < 0 || alt > 1) alt = 0; shadowy[alt] = y; invalidateTextBuffer(); if (alt == 0) setShadowY(y, 1); } void Text::getBufferPaintSize(int *w, int *h) { RECT r; getClientRect(&r); int _w = r.right - r.left; int _h = r.bottom - r.top; if (bufferinvalid) { cachedsizew = getPreferences(SUGGESTED_W); } if (w) *w = MAX(_w, cachedsizew); if (h) *h = _h; } void Text::getBufferPaintSource(RECT *r) { if (r) { RECT cr; getClientRect(&cr); r->left = textpos; r->right = cr.right - cr.left + textpos; r->top = 0; r->bottom = cr.bottom - cr.top; } } #include // this is a temporary buffer, it should not be painted over with the painting alpha value, since it is going // to be hanled in the actual blit by our ancestor int Text::onBufferPaint(BltCanvas *canvas, int _w, int _h) { int h, x, y=0; TEXT_PARENT::onBufferPaint(canvas, _w, _h); if (bufferinvalid) { cachedsizew = getPreferences(SUGGESTED_W); StringW thaname = getPrintedText(); if (thaname.isempty()) { RECT r = {0, 0, _w, _h}; canvas->fillRect(&r, RGB(0, 0, 0)); } onTextChanged(thaname); // don't remove, skipped if unnecessary switch(wantTranslation()) { case 1: thaname = _(thaname); break; case 2: thaname = __(thaname); break; } int alt = 0; #ifdef WASABI_COMPILE_CONFIG // {280876CF-48C0-40bc-8E86-73CE6BB462E5} const GUID options_guid = { 0x280876cf, 0x48c0, 0x40bc, { 0x8e, 0x86, 0x73, 0xce, 0x6b, 0xb4, 0x62, 0xe5 } }; CfgItem *item = WASABI_API_CONFIG->config_getCfgItemByGuid(options_guid); if (item != NULL) { alt = item->getDataAsInt(L"Alternate Fonts", 0); if (alt < 0 || alt > 1) alt = 0; } if (alt) { if (item && item->getDataAsInt(L"No 7-bit TTF AltFonts", 1)) { const wchar_t *p = (const wchar_t *)thaname.getValue(); while (p && *p) { if (*p > 127) break; p++; } if (p && !*p) alt = 0; } } #endif // canvas may have changed because of onTextChanged ! canvas = render_canvas; canvas->getDim(&_w, &_h, NULL); RECT r = {0, 0, _w, _h}; canvas->fillRect(&r, RGB(0, 0, 0)); if (forceupcase) CharUpperW(thaname.getNonConstVal()); if (forcelocase) CharLowerW(thaname.getNonConstVal()); wchar_t secs[256] = {0}; wchar_t mins[256] = {0}; wchar_t hours[256] = {0}; Wasabi::FontInfo fontInfo; GetFontInfo(&fontInfo, alt); const wchar_t *p = wcschr(thaname, L':'); if (display != DISPLAY_TIME || !p) { int wantpadding = 0; int w = canvas->getTextWidth(thaname, &fontInfo); if (w <= r.right - r.left - 2 - lpadding - rpadding) { // if text is wider than area, don't try to align it or it'll screw up the scroll if (fontInfo.alignFlags != DT_CENTER) wantpadding = 1; } else { fontInfo.alignFlags = STDFONT_LEFT; wantpadding = 1; } h = canvas->getTextHeight(thaname, &fontInfo); x = r.left + 2 /*-textpos*/; if (wantpadding) x += lpadding; switch (valign[alt]) { case ALIGN_CENTER: y = r.top + ((r.bottom - r.top - h) / 2); break; case ALIGN_TOP: y = r.top; break; } x += offsetx; y += offsety; cur_len = 0; PathParserW pp(thaname, L"\t"); for (int i = 0; i < pp.getNumStrings(); i++) { if (i > 0) fontInfo.alignFlags = ALIGN_RIGHT; if (shadowx[alt] != 0 || shadowy[alt] != 0) { fontInfo.color = getShadowColor(alt); if (wrapped) canvas->textOutWrapped(x + shadowx[alt], y + shadowy[alt], r.right - r.left - 2 /*+textpos*/, r.bottom - r.top, pp.enumString(i), &fontInfo); else canvas->textOut(x + shadowx[alt], y + shadowy[alt], r.right - r.left - 2 /*+textpos*/, r.bottom - r.top, pp.enumString(i), &fontInfo); fontInfo.color = GetColor(alt); } if (wrapped) canvas->textOutWrapped(x, y, r.right - r.left - 2 /*+textpos*/, r.bottom - r.top, pp.enumString(i), &fontInfo); else canvas->textOut(x, y, r.right - r.left - 2 /*+textpos*/, r.bottom - r.top, pp.enumString(i), &fontInfo); cur_len = canvas->getTextWidth(pp.enumString(i), &fontInfo) + (wantpadding ? (lpadding + rpadding) : 0); } } else { if(timerhours) { WCSCPYN(hours, thaname, (p - thaname)+1); const wchar_t* p2 = wcschr(p + 1, L':'); WCSCPYN(mins, p + 1, (p2 - p)); if(p2 && *(p2 + 1)) wcsncpy(secs, p2 + 1, 256); else { wcsncpy(secs, mins, 256); wcsncpy(mins, hours, 256); hours[0] = 0; } } else { WCSCPYN(mins, thaname, (p - thaname)+1); wcsncpy(secs, p + 1, 256); } h = canvas->getTextHeight(thaname, &fontInfo); int fixw = canvas->getTextWidth(L"0", &fontInfo); int _ws = forcefixed ? fixw * wcslen(secs) : canvas->getTextWidth(secs, &fontInfo); int _wm = forcefixed ? fixw * wcslen(mins) : canvas->getTextWidth(mins, &fontInfo); int _wh = forcefixed ? fixw * wcslen(hours) : canvas->getTextWidth(hours, &fontInfo); int _wc = forcefixed ? fixw * wcslen(L":") : canvas->getTextWidth(L":", &fontInfo); wchar_t widthchar = forcefixed ? '0' : 0; if (fontInfo.alignFlags == ALIGN_RIGHT) { x = (r.right - 2) - shadowx[alt] - rpadding; switch (valign[alt]) { case ALIGN_CENTER: y = r.top + ((r.bottom - r.top - h) / 2); break; case ALIGN_TOP: y = r.top; break; } x += offsetx; y += offsety; if (shadowx[alt] != 0 || shadowy[alt] != 0) { fontInfo.color = getShadowColor(alt); textOut(canvas, x - _ws, y, secs, widthchar, &fontInfo); textOut(canvas, x - _ws - getTimeColonWidth(_wc), y, L":", widthchar, &fontInfo); textOut(canvas, x - _ws - getTimeColonWidth(_wc) - _wm, y, mins, widthchar, &fontInfo); if(timerhours && hours[0]) { textOut(canvas, x - _ws - getTimeColonWidth(_wc) - _wm - getTimeColonWidth(_wc), y, L":", widthchar, &fontInfo); textOut(canvas, x - _ws - getTimeColonWidth(_wc) - _wm - getTimeColonWidth(_wc) - _wh, y, hours, widthchar, &fontInfo); } fontInfo.color = GetColor(alt); } x += shadowx[alt]; y += shadowy[alt]; textOut(canvas, x - _ws, y, secs, widthchar, &fontInfo); textOut(canvas, x - _ws - getTimeColonWidth(_wc), y, L":", widthchar, &fontInfo); textOut(canvas, x - _ws - getTimeColonWidth(_wc) - _wm, y, mins, widthchar, &fontInfo); if(timerhours && hours[0]) { textOut(canvas, x - _ws - getTimeColonWidth(_wc) - _wm - getTimeColonWidth(_wc), y, L":", widthchar, &fontInfo); textOut(canvas, x - _ws - getTimeColonWidth(_wc) - _wm - getTimeColonWidth(_wc) - _wh, y, hours, widthchar, &fontInfo); } } else if (fontInfo.alignFlags == ALIGN_LEFT) { x = (r.left + 2) - shadowx[alt] + lpadding; switch (valign[alt]) { case ALIGN_CENTER: y = r.top + ((r.bottom - r.top - h) / 2); break; case ALIGN_TOP: y = r.top; break; } x += offsetx; y += offsety; if (shadowx != 0 || shadowy != 0) { fontInfo.color = getShadowColor(alt); if(timerhours && hours[0]) { textOut(canvas, x, y, hours, widthchar, &fontInfo); textOut(canvas, x + _wh, y, L":", widthchar, &fontInfo); textOut(canvas, x + _wh + getTimeColonWidth(_wc), y, mins, widthchar, &fontInfo); textOut(canvas, x + _wh + getTimeColonWidth(_wc) + _wm, y, L":", widthchar, &fontInfo); textOut(canvas, x + _wh + getTimeColonWidth(_wc) + _wm + getTimeColonWidth(_wc), y, secs, widthchar, &fontInfo); } else { textOut(canvas, x, y, mins, widthchar, &fontInfo); textOut(canvas, x + _wm, y, L":", widthchar, &fontInfo); textOut(canvas, x + _wm + getTimeColonWidth(_wc), y, secs, widthchar, &fontInfo); } fontInfo.color = GetColor(alt); } x += shadowx[alt]; y += shadowy[alt]; if(timerhours && hours[0]) { textOut(canvas, x, y, hours, widthchar, &fontInfo); textOut(canvas, x + _wh, y, L":", widthchar, &fontInfo); textOut(canvas, x + _wh + getTimeColonWidth(_wc), y, mins, widthchar, &fontInfo); textOut(canvas, x + _wh + getTimeColonWidth(_wc) + _wm, y, L":", widthchar, &fontInfo); textOut(canvas, x + _wh + getTimeColonWidth(_wc) + _wm + getTimeColonWidth(_wc), y, secs, widthchar, &fontInfo); } else{ textOut(canvas, x, y, mins, widthchar, &fontInfo); textOut(canvas, x + _wm, y, L":", widthchar, &fontInfo); textOut(canvas, x + _wm + getTimeColonWidth(_wc), y, secs, widthchar, &fontInfo); } } else if (fontInfo.alignFlags == ALIGN_CENTER) { if(timerhours && hours[0]) x = (r.left + ((r.right - r.left - _ws - _wm - _wh - getTimeColonWidth(_wc)) / 3)) - shadowx[alt]; else x = (r.left + ((r.right - r.left - _ws - _wm - getTimeColonWidth(_wc)) / 2)) - shadowx[alt]; switch (valign[alt]) { case ALIGN_CENTER: y = r.top + ((r.bottom - r.top - h) / 2); break; case ALIGN_TOP: y = r.top; break; } x += offsetx; y += offsety; if (shadowx[alt] != 0 || shadowy[alt] != 0) { fontInfo.color = getShadowColor(alt); if(timerhours && hours[0]) { textOut(canvas, x, y, hours, widthchar, &fontInfo); textOut(canvas, x + _wh, y, L":", widthchar, &fontInfo); textOut(canvas, x + _wh + getTimeColonWidth(_wc), y, mins, widthchar, &fontInfo); textOut(canvas, x + _wh + getTimeColonWidth(_wc) + _wm, y, L":", widthchar, &fontInfo); textOut(canvas, x + _wh + getTimeColonWidth(_wc) + _wm + getTimeColonWidth(_wc), y, secs, widthchar, &fontInfo); } else{ textOut(canvas, x, y, mins, widthchar, &fontInfo); textOut(canvas, x + _wm, y, L":", widthchar, &fontInfo); textOut(canvas, x + _wm + getTimeColonWidth(_wc), y, secs, widthchar, &fontInfo); } fontInfo.color = GetColor(alt); } x += shadowx[alt]; y += shadowy[alt]; if(timerhours && hours[0]) { textOut(canvas, x, y, hours, widthchar, &fontInfo); textOut(canvas, x + _wh, y, L":", widthchar, &fontInfo); textOut(canvas, x + _wh + getTimeColonWidth(_wc), y, mins, widthchar, &fontInfo); textOut(canvas, x + _wh + getTimeColonWidth(_wc) + _wm, y, L":", widthchar, &fontInfo); textOut(canvas, x + _wh + getTimeColonWidth(_wc) + _wm + getTimeColonWidth(_wc), y, secs, widthchar, &fontInfo); } else{ textOut(canvas, x, y, mins, widthchar, &fontInfo); textOut(canvas, x + _wm, y, L":", widthchar, &fontInfo); textOut(canvas, x + _wm + getTimeColonWidth(_wc), y, secs, widthchar, &fontInfo); } } cur_len = _ws + _wm + getTimeColonWidth(_wc); } bufferinvalid = 0; } // alpha is taken care of in our bufferpaintwnd return 1; } void Text::timerCallback(int id) { int upd = 0; if (id == TIMER_SKIPCFG) { #ifdef WASABI_COMPILE_CONFIG const GUID uioptions_guid = { 0x9149c445, 0x3c30, 0x4e04, { 0x84, 0x33, 0x5a, 0x51, 0x8e, 0xd0, 0xfd, 0xde } }; CfgItem *item = WASABI_API_CONFIG->config_getCfgItemByGuid(uioptions_guid); if (item != NULL) { float f = (float)item->getDataAsFloat(L"Text Ticker Speed", 1.0f / 2.0f); skipn = (int)((1.0f / f) - 1 + 0.5f); } #endif } if (id == TICKER_RESET_ALTNAME) { killTimer(id); setAlternateName(NULL); } if (getAlternateName() == NULL || !*getAlternateName()) { if (id == TICKER_TIMER_POS) { #ifdef WASABI_COMPILE_MEDIACORE wchar_t txt[4096] = {0}; // TODO: Change the way to get the current status text switch (display) { #ifdef WASABI_COMPILE_METADB case DISPLAY_SONGALBUM: { const char *cur = WASABI_API_CORE->core_getCurrent(0); if (cur && (WASABI_API_METADB->metadb_getMetaData(cur, MT_ALBUM, txt, 4095, MDT_STRINGZ))) { if (!lastText.getValue() || STRCMP(txt, lastText.getValue())) { upd = 1; setName(txt); } } if (upd) { lastText = txt; resetTicker(); } } break; #endif case DISPLAY_SONGLENGTH: { int len = -1; #ifdef WASABI_COMPILE_METADB const char *cur = WASABI_API_CORE->core_getCurrent(0); if (cur && (WASABI_API_METADB->metadb_getMetaData(cur, MT_LENGTH, (char *)&len, 4, MDT_TIME)) && len != -1) { #else len = WASABI_API_MEDIACORE->core_getLength(0); if (len != -1) { #endif if (timerhours) TimeFmt::printHourMinSec(len / 1000, txt, 4096, timerhoursRollover); else TimeFmt::printMinSec(len / 1000, txt, 4096); if (!lastText.getValue() || wcscmp(txt, lastText.getValue())) { upd = 1; setName(txt); } } if (upd) { lastText = txt; resetTicker(); } } break; #ifdef WASABI_COMPILE_METADB case DISPLAY_SONGARTIST: { const char *cur = WASABI_API_CORE->core_getCurrent(0); if (cur && (WASABI_API_METADB->metadb_getMetaData(cur, MT_ARTIST, txt, 4095, MDT_STRINGZ))) { if (!lastText.getValue() || STRCMP(txt, lastText.getValue())) { upd = 1; setName(txt); } } if (upd) { lastText = txt; resetTicker(); } } break; #endif case DISPLAY_SONGNAME: case DISPLAY_SONGTITLE: { WCSCPYN(txt, WASABI_API_MEDIACORE->core_getTitle(0), 4096); { if (showlen) { int length = wa2.getLength(); if (length != 0 && length != -1) { length /= 1000; if (wcslen(txt) < 4095 - 25) wcscat(txt, StringPrintfW(L" (%d:%02d)", length / 60, length % 60)); } } if (!lastText.getValue() || wcscmp(txt, lastText.getValue())) { upd = 1; setName(txt); } } if (upd) { lastText = txt; resetTicker(); } } break; case DISPLAY_TIME: { int cp = WASABI_API_MEDIACORE->core_getPosition(0); if (cp < 0) { switch (timeroffstyle) { case 0: wcsncpy(txt, L" : ", 4096); break; case 1: StringCbPrintfW(txt, sizeof(txt), L"%s00:00", elapsed ? L"" : L"-"); break; case 2: *txt = 0; break; case 3: StringCbPrintfW(txt, sizeof(txt), L"%s0:00:00", elapsed ? L"" : L"-"); break; case 4: wcsncpy(txt, L" : : ", 4096); break; } } else { int p; int len = WASABI_API_MEDIACORE->core_getLength(0); int el = elapsed; if (len == -1000 || el == -1) el = 1; // no remaining time on http streams, etc... if (el) p = cp / 1000; else p = (len - cp) / 1000; if (!el) p = -p; if (timerhours) TimeFmt::printHourMinSec(p, txt, 4096, timerhoursRollover); else TimeFmt::printMinSec(p, txt, 4096); } if (!lastText.getValue() || wcscmp(txt, lastText.getValue())) { setName(txt); upd = 1; lastText = txt; } } break; } int u = 0; advanceTicker(&u); if (u) invalidateBuffer(); #endif } else { TEXT_PARENT::timerCallback(id); } } if (upd) { invalidateTextBuffer(); } } void Text::advanceTicker(int *upd) { // update tts stuff if (ticker && !grab && isVisible()) { int oldpos = textpos; RECT re = clientRect(); if (cur_len < (re.right - re.left - 2)) textpos = 0; else if (tts > 0) tts -= (timerclient_getSkipped() + 1); else { if (skip < skipn) skip++; else { skip = 0; if (!sens) textpos += tickerstep * (timerclient_getSkipped() + 1); else textpos -= tickerstep * (timerclient_getSkipped() + 1); if (textpos < 0) textpos = 0; if (textpos > cur_len - (re.right - re.left - 2)) textpos = cur_len - (re.right - re.left - 2); if (cur_len <= (textpos + re.right - re.left - 2)) { sens = 1; tts = time_tts; } if (textpos <= 0) { sens = 0; textpos = 0; tts = time_tts; } } } if (textpos != oldpos && upd != NULL) *upd = 1; } } void Text::setTimeDisplayMode(int remaining) { if (fixedTimerStyle) return; elapsed = !remaining; Layout *l = getGuiObject()->guiobject_getParentLayout(); if (l && l->getId()) WASABI_API_CONFIG->setIntPrivate(StringPrintfW(L"%s/timer_elapsed", l->getId()), elapsed); else WASABI_API_CONFIG->setIntPrivate(L"timer_elapsed", elapsed); invalidateTextBuffer(); } int Text::onLeftButtonDown(int x, int y) { if (!TEXT_PARENT::onLeftButtonDown(x, y)) { grab = 0; return 0; } if (nograb || wrapped) return 0; if (display == DISPLAY_TIME) { elapsed = !elapsed; #ifdef WIN32 // HACK! lone needs to make that a cfg attrib, but no time, a build needs to go out :D #define WINAMP_OPTIONS_ELAPSED 40037 #define WINAMP_OPTIONS_REMAINING 40038 if (!fixedTimerStyle) SendMessageW(WASABI_API_WND->main_getRootWnd()->gethWnd(), WM_COMMAND, elapsed ? WINAMP_OPTIONS_ELAPSED : WINAMP_OPTIONS_REMAINING, 0); #endif #ifdef WASABI_COMPILE_WNDMGR #ifdef WASABI_COMPILE_CONFIG if (getGuiObject()) { Layout *l = getGuiObject()->guiobject_getParentLayout(); if (l && l->getId()) WASABI_API_CONFIG->setIntPrivate(StringPrintfW(L"%s/timer_elapsed%s", l->getId(), (fixedTimerStyle ? StringPrintfW(L".%s", this->getId()) : L"")), elapsed); else WASABI_API_CONFIG->setIntPrivate(L"timer_elapsed", elapsed); } else WASABI_API_CONFIG->setIntPrivate(L"timer_elapsed", elapsed); #endif #endif timerCallback(TICKER_TIMER_POS); return 1; } grab = 1; grab_x = x + textpos; // onMouseMove(x,y); return 1; } int Text::onMouseMove(int x, int y) { if (!TEXT_PARENT::onMouseMove(x, y)) { grab = 0; } //POINT pos = {x, y}; //clientToScreen(&pos); if (!grab) return 1; textpos = grab_x - x; RECT re; getClientRect(&re); textpos = min(textpos, cur_len - ((re.right - re.left) - 2) - 1); if (textpos < 0) textpos = 0; invalidateBuffer(); return 1; } int Text::onLeftButtonUp(int x, int y) { if (!TEXT_PARENT::onLeftButtonUp(x, y)) { grab = 0; return 0; } if (nograb) return 0; grab = 0; tts = time_tts; return 1; } #ifdef WASABI_COMPILE_MEDIACORE int Text::corecb_onStatusMsg(const wchar_t *text) { if (display == DISPLAY_SONGNAME) setAlternateName(text); return 0; } int Text::corecb_onBitrateChange(int kbps) { if (display == DISPLAY_SONGBITRATE) { if (kbps) { wchar_t bitrate[64] = {0}; WCSNPRINTF(bitrate, 64, L"%d", kbps); setName(bitrate); } else setName(L""); } return 0; } int Text::corecb_onSampleRateChange(int hz) { if (display == DISPLAY_SONGSAMPLERATE) { if (hz) { wchar_t sampleRate[64] = {0}; WCSNPRINTF(sampleRate, 64, L"%d", hz); setName(sampleRate); } else setName(L""); } return 0; } int Text::corecb_onInfoChange(const wchar_t *text) { switch (display) { case DISPLAY_SONGINFO: case DISPLAY_SONGINFO_TRANSLATED: setName(text); break; case DISPLAY_TIME: timerCallback(TICKER_TIMER_POS); break; } return 0; } int Text::corecb_onStopped() { switch (display) { case DISPLAY_SONGINFO: case DISPLAY_SONGINFO_TRANSLATED: case DISPLAY_SONGBITRATE: case DISPLAY_SONGSAMPLERATE: setName(L""); break; case DISPLAY_TIME: timerCallback(TICKER_TIMER_POS); break; } return 0; } int Text::corecb_onStarted() { /* if (display == DISPLAY_TIME) { timerCallback(TICKER_TIMER_POS); }*/ return 0; } int Text::corecb_onSeeked(int newpos) { if (display == DISPLAY_TIME) timerCallback(TICKER_TIMER_POS); return 0; } #endif //mediacore void Text::invalidateTextBuffer() { bufferinvalid = 1; invalidateBuffer(); } int Text::setTextSize(int newsize, int alt) { if (alt < 0 || alt > 1) alt = 0; if (newsize < 1 || newsize > 72) return 0; size[alt] = newsize; invalidateTextBuffer(); return 1; } void Text::setTickering(int enable) { ticker = enable; if (!enable) textpos = 0; invalidateTextBuffer(); } void Text::setDisplay(int disp) { if (disp == display) return ; if (textfeed) { viewer_delViewItem(textfeed->getDependencyPtr()); feed_id = L""; SvcEnum::release(textfeed); textfeed = NULL; } display = disp; if (isPostOnInit()) initDisplay(); if (disp == DISPLAY_SERVICE && isPostOnInit()) registerToTextFeedService(); invalidateTextBuffer(); } void Text::setAlternateName(const wchar_t *s) { if (((!s || !*s) && alternatename.isempty()) || WCSCASEEQLSAFE(alternatename, s)) return ; killTimer(TICKER_RESET_ALTNAME); alternatename = parseText(s); onTextChanged(getPrintedText()); resetTicker(); invalidate(); setTimer(TICKER_RESET_ALTNAME, 1000); } void Text::setText(const wchar_t *t) { deftext = parseText(t); invalidate(); onTextChanged(getPrintedText()); } const wchar_t *Text::parseText(const wchar_t *s) { static wchar_t t[4096]; if (!s) return NULL; WCSCPYN(t, s, 4096); wchar_t *p = t; while (p && *p && *(p + 1)) { if (*p == '\\' && *(p + 1) == 'n') { // TODO check wcscpy(p, p + 1); t[wcslen(t)] = 0; *p = '\n'; } p++; } return t; } void Text::onTextChanged(const wchar_t *txt) { if (WCSCASEEQLSAFE(lasttxt, txt)) return ; lasttxt = txt; invalidate(); int w = getTextWidth(); if (w != lastautowidth) notifyParent(ChildNotify::AUTOWHCHANGED); lastautowidth = w; script_vcpu_onTextChanged(SCRIPT_CALL, getScriptObject(), MAKE_SCRIPT_STRING(lasttxt)); invalidateTextBuffer(); } const wchar_t *Text::getPrintedText() { const wchar_t *name = getAlternateName(); if (!name || !*name) name = deftext.getValue(); if (!name || !*name) name = getName(); if (name == NULL) return L""; #if defined(WASABI_STATICVARMGR) || !defined(WASABINOMAINAPI) if (wantTranslation()) { StringW *s = PublicVarManager::translate(name, getGuiObject()); if (s != NULL) { printedtxt.swap(s); delete s; return printedtxt.getValueSafe(); } } return name; #else return name; #endif } void Text::onSetName() { invalidateTextBuffer(); onTextChanged(getPrintedText()); } const wchar_t *Text::getAlternateName(void) { if (alternatename.isempty()) return NULL; return alternatename; } void Text::setTimerOffStyle(int o) { if (timeroffstyle == o) return ; timeroffstyle = o; invalidateTextBuffer(); } void Text::setTimerHours(int o) { if (timerhours == o) return ; timerhours = o; invalidateTextBuffer(); } void Text::setTimerHoursRollover(int o) { if (timerhoursRollover == o) return ; timerhoursRollover = o; invalidateTextBuffer(); } void Text::setTimeTTS(int tts) { time_tts = tts; invalidateTextBuffer(); } void Text::resetTicker() { sens = 0; textpos = 0; tts = time_tts; invalidateBuffer(); } void Text::setTimeColonWidth(int w) { timecolonw = w; invalidateTextBuffer(); } int Text::getTimeColonWidth(int def) { return timecolonw == -1 ? def : timecolonw; } void Text::textOut(Canvas *canvas, int x, int y, const wchar_t *txt, wchar_t widthchar, const Wasabi::FontInfo *fontInfo) { if (widthchar == 0) { canvas->textOut(x, y, txt, fontInfo); return ; } wchar_t wc[2] = { widthchar, 0 }; int cwidth = canvas->getTextWidth(wc, fontInfo); int slen = wcslen(txt); for (int i = 0; i < slen; i++) { wc[0] = txt[i]; int dw = cwidth - canvas->getTextWidth(wc, fontInfo); // get difference canvas->textOut(x + dw / 2, y, wc, fontInfo); x += cwidth; } } void Text::addCBSource(const wchar_t *cbsource) { StringW *s = new StringW(cbsource); mycbid.addItem(s); } int Text::getTextWidth() { const wchar_t *txt = getAlternateName() ? getAlternateName() : isInited() ? getName() : NULL; if (!txt) txt = deftext.getValue(); if (!txt) return 0; #ifdef WA3COMPATIBILITY /* String *translate = PublicVarManager::translate(thaname, getGuiObject()); if (translate) thanme = translate->getValueSafe(); */ #endif //txt = _(txt); int alt = 0; #ifdef WASABI_COMPILE_CONFIG // {280876CF-48C0-40bc-8E86-73CE6BB462E5} const GUID options_guid = { 0x280876cf, 0x48c0, 0x40bc, { 0x8e, 0x86, 0x73, 0xce, 0x6b, 0xb4, 0x62, 0xe5 } }; CfgItem *item = WASABI_API_CONFIG->config_getCfgItemByGuid(options_guid); if (item != NULL) { alt = item->getDataAsInt(L"Alternate Fonts", 0); if (alt < 0 || alt > 1) alt = 0; } if (alt) { if (item && item->getDataAsInt(L"No 7-bit TTF AltFonts", 1)) { const wchar_t *p = (const wchar_t *)txt; while (p && *p) { if (*p > 127) break; p++; } if (p && !*p) alt = 0; } } #endif TextInfoCanvas canvas(this); Wasabi::FontInfo fontInfo; GetFontInfo(&fontInfo, alt); int w = canvas.getTextWidth(txt, &fontInfo) + 4; // delete txt; return w; } void Text::registerToTextFeedService() { if (!registered_syscb++) WASABI_API_SYSCB->syscb_registerCallback(static_cast(this)); if (textfeed) { viewer_delViewItem(textfeed->getDependencyPtr()); feed_id = L""; SvcEnum::release(textfeed); textfeed = NULL; } if (!displaystr.isempty()) textfeed = TextFeedEnum(displaystr).getFirst(); if (textfeed != NULL) { feed_id = displaystr; viewer_addViewItem(textfeed->getDependencyPtr()); } } void Text::svccb_onSvcRegister(FOURCC type, waServiceFactory *svc) { if (type == WaSvc::TEXTFEED) { //CUTif (!displaystr.isempty()) { //CUTDebugString("RERERERER %s", displaystr.v()); //CUT} registerToTextFeedService(); } } int Text::viewer_onEvent(api_dependent *item, const GUID *classguid, int event, intptr_t param, void *ptr, size_t ptrlen) { if (textfeed && item == textfeed->getDependencyPtr()) { if (event == svc_textFeed::Event_TEXTCHANGE && WCSCASEEQLSAFE((const wchar_t *)param, feed_id)) { //CUTDebugString("got feed '%s'", (const char *)ptr); setName((const wchar_t *)ptr); return 1; } } else if (classguid && *classguid == *Container::depend_getClassGuid()) { onSetName(); return 1; } return 0; } int Text::triggerEvent(int event, intptr_t p1, intptr_t p2) { int r = TEXT_PARENT::triggerEvent(event, p1, p2); if (event == TRIGGER_ONRESIZE) notifyParent(ChildNotify::AUTOWHCHANGED); if (event == TRIGGER_INVALIDATE) invalidateTextBuffer(); return r; } COLORREF Text::getShadowColor(int alt) { if (alt < 0 || alt > 1) alt = 0; if (shadowcolor_mode[alt] == COLORMODE_SKINCOLOR) return sshadowcolor[alt]; return shadowcolor[alt].getColor(); } TextScriptController _textController; TextScriptController *textController = &_textController; // -- Functions table ------------------------------------- function_descriptor_struct TextScriptController::exportedFunction[] = { {L"setText", 1, (void*)Text::script_vcpu_setText }, {L"setAlternateText", 1, (void*)Text::script_vcpu_setAlternateText }, {L"getText", 0, (void*)Text::script_vcpu_getText }, {L"getTextWidth", 0, (void*)Text::script_vcpu_getTextWidth }, {L"onTextChanged", 1, (void*)Text::script_vcpu_onTextChanged }, }; // -------------------------------------------------------- const wchar_t *TextScriptController::getClassName() { return L"Text"; } const wchar_t *TextScriptController::getAncestorClassName() { return L"GuiObject"; } ScriptObject *TextScriptController::instantiate() { Text *t = new Text; ASSERT(t != NULL); return t->getScriptObject(); } void TextScriptController::destroy(ScriptObject *o) { Text *t = static_cast(o->vcpu_getInterface(textGuid)); ASSERT(t != NULL); delete t; } void *TextScriptController::encapsulate(ScriptObject *o) { return NULL; // no encapsulation for text yet } void TextScriptController::deencapsulate(void *o) {} int TextScriptController::getNumFunctions() { return sizeof(exportedFunction) / sizeof(function_descriptor_struct); } const function_descriptor_struct *TextScriptController::getExportedFunctions() { return exportedFunction; } GUID TextScriptController::getClassGuid() { return textGuid; } const wchar_t *Text::vcpu_getClassName() { return L"Text"; } scriptVar Text::script_vcpu_setText(SCRIPT_FUNCTION_PARAMS, ScriptObject *o, scriptVar t) { SCRIPT_FUNCTION_INIT ASSERT(t.type == SCRIPT_STRING); Text *tx = static_cast(o->vcpu_getInterface(textGuid)); if (tx) tx->setText(GET_SCRIPT_STRING(t)); RETURN_SCRIPT_VOID; } scriptVar Text::script_vcpu_setAlternateText(SCRIPT_FUNCTION_PARAMS, ScriptObject *o, scriptVar t) { SCRIPT_FUNCTION_INIT ASSERT(t.type == SCRIPT_STRING); Text *tx = static_cast(o->vcpu_getInterface(textGuid)); if (tx) tx->setAlternateName(GET_SCRIPT_STRING(t)); RETURN_SCRIPT_VOID; } scriptVar Text::script_vcpu_getText(SCRIPT_FUNCTION_PARAMS, ScriptObject *o) { SCRIPT_FUNCTION_INIT Text *t = static_cast(o->vcpu_getInterface(textGuid)); if (t) { const wchar_t *from = t->getPrintedText(); // BU rewrote in response to talkback for 489 if (from == NULL || *from == '\0') from = t->getLastText(); if (from == NULL || *from == '\0') from = L""; WCSCPYN(s_txt, from, 4096); return MAKE_SCRIPT_STRING(s_txt); } return MAKE_SCRIPT_STRING(L""); } scriptVar Text::script_vcpu_getTextWidth(SCRIPT_FUNCTION_PARAMS, ScriptObject *o) { SCRIPT_FUNCTION_INIT Text *t = static_cast(o->vcpu_getInterface(textGuid)); if (t) return MAKE_SCRIPT_INT(t->getTextWidth()); return MAKE_SCRIPT_INT(0); } scriptVar Text::script_vcpu_onTextChanged(SCRIPT_FUNCTION_PARAMS, ScriptObject *o, scriptVar newtxt) { SCRIPT_FUNCTION_INIT; PROCESS_HOOKS1(o, textController, newtxt); SCRIPT_FUNCTION_CHECKABORTEVENT; SCRIPT_EXEC_EVENT1(o, newtxt); } wchar_t Text::s_txt[WA_MAX_PATH] = {0};