winamp/Src/Wasabi/api/skin/widgets/text.cpp
2024-09-24 14:54:57 +02:00

1767 lines
42 KiB
C++

#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};