aboutsummaryrefslogtreecommitdiff
path: root/Src/Wasabi/api/skin/widgets/text.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Wasabi/api/skin/widgets/text.cpp')
-rw-r--r--Src/Wasabi/api/skin/widgets/text.cpp1767
1 files changed, 1767 insertions, 0 deletions
diff --git a/Src/Wasabi/api/skin/widgets/text.cpp b/Src/Wasabi/api/skin/widgets/text.cpp
new file mode 100644
index 00000000..fd7a16f4
--- /dev/null
+++ b/Src/Wasabi/api/skin/widgets/text.cpp
@@ -0,0 +1,1767 @@
+#include <precomp.h>
+#include "text.h"
+#include <api.h>
+#include <api/wndmgr/layout.h>
+#ifdef WASABI_WIDGETS_COMPBUCK
+#include <api/skin/widgets/compbuck2.h>
+#endif
+#include <api/skin/skinparse.h>
+#if defined(WA3COMPATIBILITY) || defined(WASABI_STATICVARMGR)
+#include <api/util/varmgr.h>
+#endif
+#include <api/core/sequence.h>
+#include <api/script/vcpu.h>
+#ifdef WA3COMPATIBILITY
+#include <core/corehandle.h>
+#endif
+#include <api/wnd/notifmsg.h>
+#include <api/locales/xlatstr.h>
+#include <api/skin/feeds/TextFeedEnum.h>
+#include <bfc/parse/pathparse.h>
+#include <bfc/util/timefmt.h>
+#ifdef WASABI_COMPILE_MEDIACORE
+#include <api/core/api_core.h>
+#endif
+#include <api/service/svcs/svc_font.h>
+#include <api/config/items/attribs.h>
+#include <api/skin/skinelem.h>
+#include <api/service/svcs/svc_action.h>
+#include <tataki/blending/blending.h>
+#include <tataki/canvas/bltcanvas.h>
+
+
+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<Text *>(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<SvcCallbackI*>(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 <bfc/util/profiler.h>
+
+// 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<SvcCallbackI*>(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<Text *>(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<Text *>(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<Text *>(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<Text *>(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<Text *>(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}; \ No newline at end of file