obs/Source/TextOutputSource.cpp

1455 lines
58 KiB
C++

/********************************************************************************
Copyright (C) 2012 Hugh Bailey <obs.jim@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
********************************************************************************/
#include "Main.h"
#include <memory>
#include <gdiplus.h>
#define ClampVal(val, minVal, maxVal) \
if(val < minVal) val = minVal; \
else if(val > maxVal) val = maxVal;
#define MAX_TEX_SIZE_W 8192
#define MAX_TEX_SIZE_H 8192
#define MIN_TEX_SIZE_W 32
#define MIN_TEX_SIZE_H 32
inline DWORD GetAlphaVal(UINT opacityLevel)
{
return ((opacityLevel*255/100)&0xFF) << 24;
}
class TextOutputSource : public ImageSource
{
bool bUpdateTexture;
String strCurrentText;
Texture *texture;
float scrollValue;
float showExtentTime;
int mode;
String strText;
String strFile;
String strFont;
int size;
DWORD color;
UINT opacity;
UINT globalOpacity;
int scrollSpeed;
bool bBold, bItalic, bUnderline, bVertical;
UINT backgroundOpacity;
DWORD backgroundColor;
bool bUseOutline;
float outlineSize;
DWORD outlineColor;
UINT outlineOpacity;
bool bUseExtents;
UINT extentWidth, extentHeight;
bool bWrap;
bool bScrollMode;
int align;
Vect2 baseSize;
SIZE textureSize;
bool bUsePointFiltering;
bool bMonitoringFileChanges;
OSFileChangeData *fileChangeMonitor;
std::unique_ptr<SamplerState> sampler;
bool bDoUpdate;
SamplerState *ss;
XElement *data;
void DrawOutlineText(Gdiplus::Graphics *graphics,
Gdiplus::Font &font,
const Gdiplus::GraphicsPath &path,
const Gdiplus::StringFormat &format,
const Gdiplus::Brush *brush)
{
Gdiplus::GraphicsPath *outlinePath;
outlinePath = path.Clone();
// Outline color and size
UINT tmpOpacity = (UINT)((((float)opacity * 0.01f) * ((float)outlineOpacity * 0.01f)) * 100.0f);
Gdiplus::Pen pen(Gdiplus::Color(GetAlphaVal(tmpOpacity) | (outlineColor&0xFFFFFF)), outlineSize);
pen.SetLineJoin(Gdiplus::LineJoinRound);
// Widen the outline
// It seems that Widen has a huge performance impact on DrawPath call, screw it! We're talking about freaking seconds in some extreme cases...
//outlinePath->Widen(&pen);
// Draw the outline
graphics->DrawPath(&pen, outlinePath);
// Draw the text
graphics->FillPath(brush, &path);
delete outlinePath;
}
HFONT GetFont()
{
HFONT hFont = NULL;
LOGFONT lf;
zero(&lf, sizeof(lf));
lf.lfHeight = size;
lf.lfWeight = bBold ? FW_BOLD : FW_DONTCARE;
lf.lfItalic = bItalic;
lf.lfUnderline = bUnderline;
lf.lfQuality = ANTIALIASED_QUALITY;
if(strFont.IsValid())
{
scpy_n(lf.lfFaceName, strFont, 31);
hFont = CreateFontIndirect(&lf);
}
if(!hFont)
{
scpy_n(lf.lfFaceName, TEXT("Arial"), 31);
hFont = CreateFontIndirect(&lf);
}
return hFont;
}
void UpdateCurrentText()
{
if(bMonitoringFileChanges)
{
OSMonitorFileDestroy(fileChangeMonitor);
fileChangeMonitor = NULL;
bMonitoringFileChanges = false;
}
if(mode == 0)
strCurrentText = strText;
else if(mode == 1 && strFile.IsValid())
{
XFile textFile;
if(textFile.Open(strFile, XFILE_READ | XFILE_SHARED, XFILE_OPENEXISTING))
{
textFile.ReadFileToString(strCurrentText);
}
else
{
strCurrentText = TEXT("");
AppWarning(TEXT("TextSource::UpdateTexture: could not open specified file (invalid file name or access violation)"));
}
if (fileChangeMonitor = OSMonitorFileStart (strFile))
bMonitoringFileChanges = true;
}
else
strCurrentText = TEXT("");
}
void SetStringFormat(Gdiplus::StringFormat &format)
{
UINT formatFlags;
formatFlags = Gdiplus::StringFormatFlagsNoFitBlackBox
| Gdiplus::StringFormatFlagsMeasureTrailingSpaces;
if(bVertical)
formatFlags |= Gdiplus::StringFormatFlagsDirectionVertical
| Gdiplus::StringFormatFlagsDirectionRightToLeft;
format.SetFormatFlags(formatFlags);
format.SetTrimming(Gdiplus::StringTrimmingWord);
if(bUseExtents && bWrap)
switch(align)
{
case 0:
if(bVertical)
format.SetLineAlignment(Gdiplus::StringAlignmentFar);
else
format.SetAlignment(Gdiplus::StringAlignmentNear);
break;
case 1:
if(bVertical)
format.SetLineAlignment(Gdiplus::StringAlignmentCenter);
else
format.SetAlignment(Gdiplus::StringAlignmentCenter);
break;
case 2:
if(bVertical)
format.SetLineAlignment(Gdiplus::StringAlignmentNear);
else
format.SetAlignment(Gdiplus::StringAlignmentFar);
break;
}
else if(bUseExtents && bVertical && !bWrap)
format.SetLineAlignment(Gdiplus::StringAlignmentFar);
else if(bVertical)
format.SetLineAlignment(Gdiplus::StringAlignmentFar);
}
float ProcessScrollMode(Gdiplus::Graphics *graphics, Gdiplus::Font *font, Gdiplus::RectF &layoutBox, Gdiplus::StringFormat *format)
{
StringList strList;
Gdiplus::RectF boundingBox;
float offset = layoutBox.Height;
Gdiplus::RectF l2(0.0f ,0.0f , layoutBox.Width, 32000.0f); // Really, it needs to be OVER9000
strCurrentText.FindReplace(L"\n\r", L"\n");
strCurrentText.GetTokenList(strList,'\n');
if(strList.Num() != 0)
strCurrentText.Clear();
else
return 0.0f;
for(int i = strList.Num() - 1; i >= 0; i--)
{
strCurrentText.InsertString(0, TEXT("\n"));
strCurrentText.InsertString(0, strList.GetElement((unsigned int)i).Array());
if(strCurrentText.IsValid())
{
graphics->MeasureString(strCurrentText, -1, font, l2, &boundingBox);
offset = layoutBox.Height - boundingBox.Height;
}
if(offset < 0)
break;
}
return offset;
}
void UpdateTexture()
{
HFONT hFont;
Gdiplus::Status stat;
Gdiplus::RectF layoutBox;
SIZE textSize;
float offset;
Gdiplus::RectF boundingBox(0.0f, 0.0f, 32.0f, 32.0f);
UpdateCurrentText();
hFont = GetFont();
if(!hFont)
return;
Gdiplus::StringFormat format(Gdiplus::StringFormat::GenericTypographic());
SetStringFormat(format);
HDC hdc = CreateCompatibleDC(NULL);
Gdiplus::Font font(hdc, hFont);
Gdiplus::Graphics *graphics = new Gdiplus::Graphics(hdc);
graphics->SetTextRenderingHint(Gdiplus::TextRenderingHintAntiAlias);
if(strCurrentText.IsValid())
{
// Apparently, \0 is not always a zero-width character?
// Not including it as part of the string measurement may cut off the final word
// on the line when using certain fonts together with outlines and wrapping.
INT strLength = strCurrentText.Length() + 1;
if(bUseExtents && bWrap)
{
layoutBox.X = layoutBox.Y = 0;
layoutBox.Width = float(extentWidth);
layoutBox.Height = float(extentHeight);
if(bUseOutline)
{
//Note: since there's no path widening in DrawOutlineText the padding is half than what it was supposed to be.
layoutBox.Width -= outlineSize;
layoutBox.Height -= outlineSize;
}
if(!bVertical && bScrollMode)
{
offset = ProcessScrollMode(graphics, &font, layoutBox, &format);
boundingBox = layoutBox;
boundingBox.Y = offset;
if(offset < 0)
boundingBox.Height -= offset;
}
else
{
stat = graphics->MeasureString(strCurrentText, strLength, &font, layoutBox, &format, &boundingBox);
if(stat != Gdiplus::Ok)
AppWarning(TEXT("TextSource::UpdateTexture: Gdiplus::Graphics::MeasureString failed: %u"), (int)stat);
}
}
else
{
stat = graphics->MeasureString(strCurrentText, strLength, &font, Gdiplus::PointF(0.0f, 0.0f), &format, &boundingBox);
if(stat != Gdiplus::Ok)
AppWarning(TEXT("TextSource::UpdateTexture: Gdiplus::Graphics::MeasureString failed: %u"), (int)stat);
if(bUseOutline)
{
//Note: since there's no path widening in DrawOutlineText the padding is half than what it was supposed to be.
boundingBox.Width += outlineSize;
boundingBox.Height += outlineSize;
}
}
}
delete graphics;
DeleteDC(hdc);
hdc = NULL;
DeleteObject(hFont);
if(bVertical)
{
if(boundingBox.Width<size)
{
textSize.cx = size;
boundingBox.Width = float(size);
}
else
textSize.cx = LONG(boundingBox.Width + EPSILON);
textSize.cy = LONG(boundingBox.Height + EPSILON);
}
else
{
if(boundingBox.Height<size)
{
textSize.cy = size;
boundingBox.Height = float(size);
}
else
textSize.cy = LONG(boundingBox.Height + EPSILON);
textSize.cx = LONG(boundingBox.Width + EPSILON);
}
if(bUseExtents)
{
if(bWrap)
{
textSize.cx = extentWidth;
textSize.cy = extentHeight;
}
else
{
if(LONG(extentWidth) > textSize.cx)
textSize.cx = extentWidth;
if(LONG(extentHeight) > textSize.cy)
textSize.cy = extentHeight;
}
}
//textSize.cx &= 0xFFFFFFFE;
//textSize.cy &= 0xFFFFFFFE;
textSize.cx += textSize.cx%2;
textSize.cy += textSize.cy%2;
ClampVal(textSize.cx, MIN_TEX_SIZE_W, MAX_TEX_SIZE_W);
ClampVal(textSize.cy, MIN_TEX_SIZE_H, MAX_TEX_SIZE_H);
//----------------------------------------------------------------------
// write image
{
HDC hTempDC = CreateCompatibleDC(NULL);
BITMAPINFO bi;
zero(&bi, sizeof(bi));
void* lpBits;
BITMAPINFOHEADER &bih = bi.bmiHeader;
bih.biSize = sizeof(bih);
bih.biBitCount = 32;
bih.biWidth = textSize.cx;
bih.biHeight = textSize.cy;
bih.biPlanes = 1;
HBITMAP hBitmap = CreateDIBSection(hTempDC, &bi, DIB_RGB_COLORS, &lpBits, NULL, 0);
Gdiplus::Bitmap bmp(textSize.cx, textSize.cy, 4*textSize.cx, PixelFormat32bppARGB, (BYTE*)lpBits);
graphics = new Gdiplus::Graphics(&bmp);
Gdiplus::SolidBrush *brush = new Gdiplus::SolidBrush(Gdiplus::Color(GetAlphaVal(opacity)|(color&0x00FFFFFF)));
DWORD bkColor;
if(backgroundOpacity == 0 && scrollSpeed !=0)
bkColor = 1<<24 | (color&0x00FFFFFF);
else
bkColor = ((strCurrentText.IsValid() || bUseExtents) ? GetAlphaVal(backgroundOpacity) : GetAlphaVal(0)) | (backgroundColor&0x00FFFFFF);
if((textSize.cx > boundingBox.Width || textSize.cy > boundingBox.Height) && !bUseExtents)
{
stat = graphics->Clear(Gdiplus::Color( 0x00000000));
if(stat != Gdiplus::Ok)
AppWarning(TEXT("TextSource::UpdateTexture: Graphics::Clear failed: %u"), (int)stat);
Gdiplus::SolidBrush *bkBrush = new Gdiplus::SolidBrush(Gdiplus::Color( bkColor ));
graphics->FillRectangle(bkBrush, boundingBox);
delete bkBrush;
}
else
{
stat = graphics->Clear(Gdiplus::Color( bkColor ));
if(stat != Gdiplus::Ok)
AppWarning(TEXT("TextSource::UpdateTexture: Graphics::Clear failed: %u"), (int)stat);
}
graphics->SetTextRenderingHint(Gdiplus::TextRenderingHintAntiAlias);
graphics->SetCompositingMode(Gdiplus::CompositingModeSourceOver);
graphics->SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
if(strCurrentText.IsValid())
{
if(bUseOutline)
{
boundingBox.Offset(outlineSize/2, outlineSize/2);
Gdiplus::FontFamily fontFamily;
Gdiplus::GraphicsPath path;
font.GetFamily(&fontFamily);
path.AddString(strCurrentText, -1, &fontFamily, font.GetStyle(), font.GetSize(), boundingBox, &format);
DrawOutlineText(graphics, font, path, format, brush);
}
else
{
stat = graphics->DrawString(strCurrentText, -1, &font, boundingBox, &format, brush);
if(stat != Gdiplus::Ok)
AppWarning(TEXT("TextSource::UpdateTexture: Graphics::DrawString failed: %u"), (int)stat);
}
}
delete brush;
delete graphics;
//----------------------------------------------------------------------
// upload texture
if(textureSize.cx != textSize.cx || textureSize.cy != textSize.cy)
{
if(texture)
{
delete texture;
texture = NULL;
}
mcpy(&textureSize, &textSize, sizeof(textureSize));
texture = CreateTexture(textSize.cx, textSize.cy, GS_BGRA, lpBits, FALSE, FALSE);
}
else if(texture)
texture->SetImage(lpBits, GS_IMAGEFORMAT_BGRA, 4*textSize.cx);
if(!texture)
{
AppWarning(TEXT("TextSource::UpdateTexture: could not create texture"));
DeleteObject(hFont);
}
DeleteDC(hTempDC);
DeleteObject(hBitmap);
}
}
public:
inline TextOutputSource(XElement *data)
{
this->data = data;
UpdateSettings();
SamplerInfo si;
zero(&si, sizeof(si));
si.addressU = GS_ADDRESS_REPEAT;
si.addressV = GS_ADDRESS_REPEAT;
si.borderColor = 0;
si.filter = GS_FILTER_LINEAR;
ss = CreateSamplerState(si);
globalOpacity = 100;
Log(TEXT("Using text output"));
}
~TextOutputSource()
{
if(texture)
{
delete texture;
texture = NULL;
}
delete ss;
if(bMonitoringFileChanges)
{
OSMonitorFileDestroy(fileChangeMonitor);
}
}
void Preprocess()
{
if(bMonitoringFileChanges)
{
if (OSFileHasChanged(fileChangeMonitor))
bUpdateTexture = true;
}
if(bUpdateTexture)
{
bUpdateTexture = false;
UpdateTexture();
}
}
void Tick(float fSeconds)
{
if(scrollSpeed != 0 && texture)
{
scrollValue += fSeconds*float(scrollSpeed)/(bVertical?(-1.0f)*float(textureSize.cy):float(textureSize.cx));
while(scrollValue > 1.0f)
scrollValue -= 1.0f;
while(scrollValue < -1.0f)
scrollValue += 1.0f;
}
if(showExtentTime > 0.0f)
showExtentTime -= fSeconds;
if(bDoUpdate)
{
bDoUpdate = false;
bUpdateTexture = true;
}
}
void Render(const Vect2 &pos, const Vect2 &size)
{
if(texture)
{
//EnableBlending(FALSE);
Vect2 sizeMultiplier = size/baseSize;
Vect2 newSize = Vect2(float(textureSize.cx), float(textureSize.cy))*sizeMultiplier;
if(bUseExtents)
{
Vect2 extentVal = Vect2(float(extentWidth), float(extentHeight))*sizeMultiplier;
if(showExtentTime > 0.0f)
{
Shader *pShader = GS->GetCurrentPixelShader();
Shader *vShader = GS->GetCurrentVertexShader();
Color4 rectangleColor = Color4(0.0f, 1.0f, 0.0f, 1.0f);
if(showExtentTime < 1.0f)
rectangleColor.w = showExtentTime;
App->solidPixelShader->SetColor(App->solidPixelShader->GetParameter(0), rectangleColor);
LoadVertexShader(App->solidVertexShader);
LoadPixelShader(App->solidPixelShader);
DrawBox(pos, extentVal);
LoadVertexShader(vShader);
LoadPixelShader(pShader);
}
if(!bWrap)
{
XRect rect = {int(pos.x), int(pos.y), int(extentVal.x), int(extentVal.y)};
SetScissorRect(&rect);
}
}
if(bUsePointFiltering) {
if (!sampler) {
SamplerInfo samplerinfo;
samplerinfo.filter = GS_FILTER_POINT;
std::unique_ptr<SamplerState> new_sampler(CreateSamplerState(samplerinfo));
sampler = std::move(new_sampler);
}
LoadSamplerState(sampler.get(), 0);
}
DWORD alpha = DWORD(double(globalOpacity)*2.55);
DWORD outputColor = (alpha << 24) | 0xFFFFFF;
if(scrollSpeed != 0)
{
UVCoord ul(0.0f, 0.0f);
UVCoord lr(1.0f, 1.0f);
if(bVertical)
{
/*float sizeVal = float(textureSize.cy);
float clampedVal = floorf(scrollValue*sizeVal)/sizeVal;*/
ul.y += scrollValue;
lr.y += scrollValue;
}
else
{
/*float sizeVal = float(textureSize.cx);
float clampedVal = floorf(scrollValue*sizeVal)/sizeVal;*/
ul.x += scrollValue;
lr.x += scrollValue;
}
LoadSamplerState(ss);
DrawSpriteEx(texture, outputColor, pos.x, pos.y, pos.x+newSize.x, pos.y+newSize.y, ul.x, ul.y, lr.x, lr.y);
}
else
DrawSprite(texture, outputColor, pos.x, pos.y, pos.x+newSize.x, pos.y+newSize.y);
if (bUsePointFiltering)
LoadSamplerState(NULL, 0);
if(bUseExtents && !bWrap)
SetScissorRect(NULL);
//EnableBlending(TRUE);
}
}
Vect2 GetSize() const
{
return baseSize;
}
void UpdateSettings()
{
strFont = data->GetString(TEXT("font"), TEXT("Arial"));
color = data->GetInt(TEXT("color"), 0xFFFFFFFF);
size = data->GetInt(TEXT("fontSize"), 48);
opacity = data->GetInt(TEXT("textOpacity"), 100);
scrollSpeed = data->GetInt(TEXT("scrollSpeed"), 0);
bBold = data->GetInt(TEXT("bold"), 0) != 0;
bItalic = data->GetInt(TEXT("italic"), 0) != 0;
bWrap = data->GetInt(TEXT("wrap"), 0) != 0;
bScrollMode = data->GetInt(TEXT("scrollMode"), 0) != 0;
bUnderline = data->GetInt(TEXT("underline"), 0) != 0;
bVertical = data->GetInt(TEXT("vertical"), 0) != 0;
bUseExtents = data->GetInt(TEXT("useTextExtents"), 0) != 0;
extentWidth = data->GetInt(TEXT("extentWidth"), 0);
extentHeight= data->GetInt(TEXT("extentHeight"), 0);
align = data->GetInt(TEXT("align"), 0);
strFile = data->GetString(TEXT("file"));
strText = data->GetString(TEXT("text"));
mode = data->GetInt(TEXT("mode"), 0);
bUsePointFiltering = data->GetInt(TEXT("pointFiltering"), 0) != 0;
baseSize.x = data->GetFloat(TEXT("baseSizeCX"), MIN_TEX_SIZE_W);
baseSize.y = data->GetFloat(TEXT("baseSizeCY"), MIN_TEX_SIZE_H);
bUseOutline = data->GetInt(TEXT("useOutline")) != 0;
outlineColor = data->GetInt(TEXT("outlineColor"), 0xFF000000);
outlineSize = data->GetFloat(TEXT("outlineSize"), 2);
outlineOpacity = data->GetInt(TEXT("outlineOpacity"), 100);
backgroundColor = data->GetInt(TEXT("backgroundColor"), 0xFF000000);
backgroundOpacity = data->GetInt(TEXT("backgroundOpacity"), 0);
bUpdateTexture = true;
}
void SetString(CTSTR lpName, CTSTR lpVal)
{
if(scmpi(lpName, TEXT("font")) == 0)
strFont = lpVal;
else if(scmpi(lpName, TEXT("text")) == 0)
strText = lpVal;
else if(scmpi(lpName, TEXT("file")) == 0)
strFile = lpVal;
bUpdateTexture = true;
}
void SetInt(CTSTR lpName, int iValue)
{
if(scmpi(lpName, TEXT("color")) == 0)
color = iValue;
else if(scmpi(lpName, TEXT("fontSize")) == 0)
size = iValue;
else if(scmpi(lpName, TEXT("textOpacity")) == 0)
opacity = iValue;
else if(scmpi(lpName, TEXT("scrollSpeed")) == 0)
{
if(scrollSpeed == 0)
scrollValue = 0.0f;
scrollSpeed = iValue;
}
else if(scmpi(lpName, TEXT("bold")) == 0)
bBold = iValue != 0;
else if(scmpi(lpName, TEXT("italic")) == 0)
bItalic = iValue != 0;
else if(scmpi(lpName, TEXT("wrap")) == 0)
bWrap = iValue != 0;
else if(scmpi(lpName, TEXT("scrollMode")) == 0)
bScrollMode = iValue != 0;
else if(scmpi(lpName, TEXT("underline")) == 0)
bUnderline = iValue != 0;
else if(scmpi(lpName, TEXT("vertical")) == 0)
bVertical = iValue != 0;
else if(scmpi(lpName, TEXT("useTextExtents")) == 0)
bUseExtents = iValue != 0;
else if(scmpi(lpName, TEXT("extentWidth")) == 0)
{
showExtentTime = 2.0f;
extentWidth = iValue;
}
else if(scmpi(lpName, TEXT("extentHeight")) == 0)
{
showExtentTime = 2.0f;
extentHeight = iValue;
}
else if(scmpi(lpName, TEXT("align")) == 0)
align = iValue;
else if(scmpi(lpName, TEXT("mode")) == 0)
mode = iValue;
else if(scmpi(lpName, TEXT("useOutline")) == 0)
bUseOutline = iValue != 0;
else if(scmpi(lpName, TEXT("outlineColor")) == 0)
outlineColor = iValue;
else if(scmpi(lpName, TEXT("outlineOpacity")) == 0)
outlineOpacity = iValue;
else if(scmpi(lpName, TEXT("backgroundColor")) == 0)
backgroundColor = iValue;
else if(scmpi(lpName, TEXT("backgroundOpacity")) == 0)
backgroundOpacity = iValue;
bUpdateTexture = true;
}
void SetFloat(CTSTR lpName, float fValue)
{
if(scmpi(lpName, TEXT("outlineSize")) == 0)
outlineSize = fValue;
bUpdateTexture = true;
}
inline void ResetExtentRect() {showExtentTime = 0.0f;}
};
struct ConfigTextSourceInfo
{
CTSTR lpName;
XElement *data;
float cx, cy;
StringList fontNames;
StringList fontFaces;
};
ImageSource* STDCALL CreateTextSource(XElement *data)
{
if(!data)
return NULL;
return new TextOutputSource(data);
}
int CALLBACK FontEnumProcThingy(ENUMLOGFONTEX *logicalData, NEWTEXTMETRICEX *physicalData, DWORD fontType, ConfigTextSourceInfo *configInfo)
{
if(fontType == TRUETYPE_FONTTYPE) //HomeWorld - GDI+ doesn't like anything other than truetype
{
configInfo->fontNames << logicalData->elfFullName;
configInfo->fontFaces << logicalData->elfLogFont.lfFaceName;
}
return 1;
}
void DoCancelStuff(HWND hwnd)
{
ConfigTextSourceInfo *configInfo = (ConfigTextSourceInfo*)GetWindowLongPtr(hwnd, DWLP_USER);
ImageSource *source = API->GetSceneImageSource(configInfo->lpName);
//XElement *data = configInfo->data;
if(source)
source->UpdateSettings();
}
UINT FindFontFace(ConfigTextSourceInfo *configInfo, HWND hwndFontList, CTSTR lpFontFace)
{
UINT id = configInfo->fontFaces.FindValueIndexI(lpFontFace);
if(id == INVALID)
return INVALID;
else
{
for(UINT i=0; i<configInfo->fontFaces.Num(); i++)
{
UINT targetID = (UINT)SendMessage(hwndFontList, CB_GETITEMDATA, i, 0);
if(targetID == id)
return i;
}
}
return INVALID;
}
UINT FindFontName(ConfigTextSourceInfo *configInfo, HWND hwndFontList, CTSTR lpFontFace)
{
return configInfo->fontNames.FindValueIndexI(lpFontFace);
}
CTSTR GetFontFace(ConfigTextSourceInfo *configInfo, HWND hwndFontList)
{
UINT id = (UINT)SendMessage(hwndFontList, CB_GETCURSEL, 0, 0);
if(id == CB_ERR)
return NULL;
UINT actualID = (UINT)SendMessage(hwndFontList, CB_GETITEMDATA, id, 0);
return configInfo->fontFaces[actualID];
}
INT_PTR CALLBACK ConfigureTextProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static bool bInitializedDialog = false;
switch(message)
{
case WM_INITDIALOG:
{
ConfigTextSourceInfo *configInfo = (ConfigTextSourceInfo*)lParam;
SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)configInfo);
LocalizeWindow(hwnd);
XElement *data = configInfo->data;
//-----------------------------------------
HDC hDCtest = GetDC(hwnd);
LOGFONT lf;
zero(&lf, sizeof(lf));
EnumFontFamiliesEx(hDCtest, &lf, (FONTENUMPROC)FontEnumProcThingy, (LPARAM)configInfo, 0);
HWND hwndFonts = GetDlgItem(hwnd, IDC_FONT);
for(UINT i=0; i<configInfo->fontNames.Num(); i++)
{
int id = (int)SendMessage(hwndFonts, CB_ADDSTRING, 0, (LPARAM)configInfo->fontNames[i].Array());
SendMessage(hwndFonts, CB_SETITEMDATA, id, (LPARAM)i);
}
CTSTR lpFont = data->GetString(TEXT("font"));
UINT id = FindFontFace(configInfo, hwndFonts, lpFont);
if(id == INVALID)
id = (UINT)SendMessage(hwndFonts, CB_FINDSTRINGEXACT, -1, (LPARAM)TEXT("Arial"));
SendMessage(hwndFonts, CB_SETCURSEL, id, 0);
//-----------------------------------------
SendMessage(GetDlgItem(hwnd, IDC_TEXTSIZE), UDM_SETRANGE32, 5, MAX_TEX_SIZE_H);
SendMessage(GetDlgItem(hwnd, IDC_TEXTSIZE), UDM_SETPOS32, 0, data->GetInt(TEXT("fontSize"), 48));
//-----------------------------------------
CCSetColor(GetDlgItem(hwnd, IDC_COLOR), data->GetInt(TEXT("color"), 0xFFFFFFFF));
SendMessage(GetDlgItem(hwnd, IDC_TEXTOPACITY), UDM_SETRANGE32, 0, 100);
SendMessage(GetDlgItem(hwnd, IDC_TEXTOPACITY), UDM_SETPOS32, 0, data->GetInt(TEXT("textOpacity"), 100));
SendMessage(GetDlgItem(hwnd, IDC_SCROLLSPEED), UDM_SETRANGE32, -4095, 4095);
SendMessage(GetDlgItem(hwnd, IDC_SCROLLSPEED), UDM_SETPOS32, 0, data->GetInt(TEXT("scrollSpeed"), 0));
SendMessage(GetDlgItem(hwnd, IDC_BOLD), BM_SETCHECK, data->GetInt(TEXT("bold"), 0) ? BST_CHECKED : BST_UNCHECKED, 0);
SendMessage(GetDlgItem(hwnd, IDC_ITALIC), BM_SETCHECK, data->GetInt(TEXT("italic"), 0) ? BST_CHECKED : BST_UNCHECKED, 0);
SendMessage(GetDlgItem(hwnd, IDC_UNDERLINE), BM_SETCHECK, data->GetInt(TEXT("underline"), 0) ? BST_CHECKED : BST_UNCHECKED, 0);
SendMessage(GetDlgItem(hwnd, IDC_VERTICALSCRIPT), BM_SETCHECK, data->GetInt(TEXT("vertical"), 0) ? BST_CHECKED : BST_UNCHECKED, 0);
BOOL bUsePointFilter = data->GetInt(TEXT("pointFiltering"), 0) != 0;
SendMessage(GetDlgItem(hwnd, IDC_POINTFILTERING), BM_SETCHECK, bUsePointFilter ? BST_CHECKED : BST_UNCHECKED, 0);
//-----------------------------------------
CCSetColor(GetDlgItem(hwnd, IDC_BACKGROUNDCOLOR), data->GetInt(TEXT("backgroundColor"), 0xFF000000));
SendMessage(GetDlgItem(hwnd, IDC_BACKGROUNDOPACITY), UDM_SETRANGE32, 0, 100);
SendMessage(GetDlgItem(hwnd, IDC_BACKGROUNDOPACITY), UDM_SETPOS32, 0, data->GetInt(TEXT("backgroundOpacity"), 0));
//-----------------------------------------
bool bChecked = data->GetInt(TEXT("useOutline"), 0) != 0;
SendMessage(GetDlgItem(hwnd, IDC_USEOUTLINE), BM_SETCHECK, bChecked ? BST_CHECKED : BST_UNCHECKED, 0);
EnableWindow(GetDlgItem(hwnd, IDC_OUTLINETHICKNESS_EDIT), bChecked);
EnableWindow(GetDlgItem(hwnd, IDC_OUTLINETHICKNESS), bChecked);
EnableWindow(GetDlgItem(hwnd, IDC_OUTLINECOLOR), bChecked);
EnableWindow(GetDlgItem(hwnd, IDC_OUTLINEOPACITY_EDIT), bChecked);
EnableWindow(GetDlgItem(hwnd, IDC_OUTLINEOPACITY), bChecked);
SendMessage(GetDlgItem(hwnd, IDC_OUTLINETHICKNESS), UDM_SETRANGE32, 1, 20);
SendMessage(GetDlgItem(hwnd, IDC_OUTLINETHICKNESS), UDM_SETPOS32, 0, data->GetInt(TEXT("outlineSize"), 2));
CCSetColor(GetDlgItem(hwnd, IDC_OUTLINECOLOR), data->GetInt(TEXT("outlineColor"), 0xFF000000));
SendMessage(GetDlgItem(hwnd, IDC_OUTLINEOPACITY), UDM_SETRANGE32, 0, 100);
SendMessage(GetDlgItem(hwnd, IDC_OUTLINEOPACITY), UDM_SETPOS32, 0, data->GetInt(TEXT("outlineOpacity"), 100));
//-----------------------------------------
bChecked = data->GetInt(TEXT("useTextExtents"), 0) != 0;
SendMessage(GetDlgItem(hwnd, IDC_USETEXTEXTENTS), BM_SETCHECK, bChecked ? BST_CHECKED : BST_UNCHECKED, 0);
ConfigureTextProc(hwnd, WM_COMMAND, MAKEWPARAM(IDC_USETEXTEXTENTS, BN_CLICKED), (LPARAM)GetDlgItem(hwnd, IDC_USETEXTEXTENTS));
EnableWindow(GetDlgItem(hwnd, IDC_EXTENTWIDTH_EDIT), bChecked);
EnableWindow(GetDlgItem(hwnd, IDC_EXTENTHEIGHT_EDIT), bChecked);
EnableWindow(GetDlgItem(hwnd, IDC_EXTENTWIDTH), bChecked);
EnableWindow(GetDlgItem(hwnd, IDC_EXTENTHEIGHT), bChecked);
EnableWindow(GetDlgItem(hwnd, IDC_WRAP), bChecked);
bool bVertical = data->GetInt(TEXT("vertical"), 0) != 0;
SendMessage(GetDlgItem(hwnd, IDC_EXTENTWIDTH), UDM_SETRANGE32, MIN_TEX_SIZE_W, MAX_TEX_SIZE_W);
SendMessage(GetDlgItem(hwnd, IDC_EXTENTHEIGHT), UDM_SETRANGE32, MIN_TEX_SIZE_H, MAX_TEX_SIZE_H);
SendMessage(GetDlgItem(hwnd, IDC_EXTENTWIDTH), UDM_SETPOS32, 0, data->GetInt(TEXT("extentWidth"), MIN_TEX_SIZE_W));
SendMessage(GetDlgItem(hwnd, IDC_EXTENTHEIGHT), UDM_SETPOS32, 0, data->GetInt(TEXT("extentHeight"), MIN_TEX_SIZE_H));
bool bWrap = data->GetInt(TEXT("wrap"), 0) != 0;
SendMessage(GetDlgItem(hwnd, IDC_WRAP), BM_SETCHECK, bWrap ? BST_CHECKED : BST_UNCHECKED, 0);
bool bScrollMode = data->GetInt(TEXT("scrollMode"), 0) != 0;
SendMessage(GetDlgItem(hwnd, IDC_SCROLLMODE), BM_SETCHECK, bScrollMode ? BST_CHECKED : BST_UNCHECKED, 0);
EnableWindow(GetDlgItem(hwnd, IDC_ALIGN), bChecked && bWrap);
EnableWindow(GetDlgItem(hwnd, IDC_SCROLLMODE), bChecked && bWrap && !bVertical);
HWND hwndAlign = GetDlgItem(hwnd, IDC_ALIGN);
SendMessage(hwndAlign, CB_ADDSTRING, 0, (LPARAM)Str("Sources.TextSource.Left"));
SendMessage(hwndAlign, CB_ADDSTRING, 0, (LPARAM)Str("Sources.TextSource.Center"));
SendMessage(hwndAlign, CB_ADDSTRING, 0, (LPARAM)Str("Sources.TextSource.Right"));
int align = data->GetInt(TEXT("align"), 0);
ClampVal(align, 0, 2);
SendMessage(hwndAlign, CB_SETCURSEL, align, 0);
//-----------------------------------------
BOOL bUseFile = data->GetInt(TEXT("mode"), 0) == 1;
SendMessage(GetDlgItem(hwnd, IDC_USEFILE), BM_SETCHECK, bUseFile ? BST_CHECKED : BST_UNCHECKED, 0);
SendMessage(GetDlgItem(hwnd, IDC_USETEXT), BM_SETCHECK, bUseFile ? BST_UNCHECKED : BST_CHECKED, 0);
SetWindowText(GetDlgItem(hwnd, IDC_TEXT), data->GetString(TEXT("text")));
SetWindowText(GetDlgItem(hwnd, IDC_FILE), data->GetString(TEXT("file")));
EnableWindow(GetDlgItem(hwnd, IDC_TEXT), !bUseFile);
EnableWindow(GetDlgItem(hwnd, IDC_FILE), bUseFile);
EnableWindow(GetDlgItem(hwnd, IDC_BROWSE), bUseFile);
bInitializedDialog = true;
return TRUE;
}
case WM_DESTROY:
bInitializedDialog = false;
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDC_FONT:
if(bInitializedDialog)
{
if(HIWORD(wParam) == CBN_SELCHANGE || HIWORD(wParam) == CBN_EDITCHANGE)
{
ConfigTextSourceInfo *configInfo = (ConfigTextSourceInfo*)GetWindowLongPtr(hwnd, DWLP_USER);
if(!configInfo) break;
String strFont;
if(HIWORD(wParam) == CBN_SELCHANGE)
strFont = GetFontFace(configInfo, (HWND)lParam);
else
{
UINT id = FindFontName(configInfo, (HWND)lParam, GetEditText((HWND)lParam));
if(id != INVALID)
strFont = configInfo->fontFaces[id];
}
ImageSource *source = API->GetSceneImageSource(configInfo->lpName);
if(source && strFont.IsValid())
source->SetString(TEXT("font"), strFont);
}
}
break;
case IDC_OUTLINECOLOR:
case IDC_BACKGROUNDCOLOR:
case IDC_COLOR:
if(bInitializedDialog)
{
DWORD color = CCGetColor((HWND)lParam);
ConfigTextSourceInfo *configInfo = (ConfigTextSourceInfo*)GetWindowLongPtr(hwnd, DWLP_USER);
if(!configInfo) break;
ImageSource *source = API->GetSceneImageSource(configInfo->lpName);
if(source)
{
switch(LOWORD(wParam))
{
case IDC_OUTLINECOLOR: source->SetInt(TEXT("outlineColor"), color); break;
case IDC_BACKGROUNDCOLOR: source->SetInt(TEXT("backgroundColor"), color); break;
case IDC_COLOR: source->SetInt(TEXT("color"), color); break;
}
}
}
break;
case IDC_TEXTSIZE_EDIT:
case IDC_EXTENTWIDTH_EDIT:
case IDC_EXTENTHEIGHT_EDIT:
case IDC_BACKGROUNDOPACITY_EDIT:
case IDC_TEXTOPACITY_EDIT:
case IDC_OUTLINEOPACITY_EDIT:
case IDC_OUTLINETHICKNESS_EDIT:
case IDC_SCROLLSPEED_EDIT:
if(HIWORD(wParam) == EN_CHANGE && bInitializedDialog)
{
int val = (int)SendMessage(GetWindow((HWND)lParam, GW_HWNDNEXT), UDM_GETPOS32, 0, 0);
ConfigTextSourceInfo *configInfo = (ConfigTextSourceInfo*)GetWindowLongPtr(hwnd, DWLP_USER);
if(!configInfo) break;
ImageSource *source = API->GetSceneImageSource(configInfo->lpName);
if(source)
{
switch(LOWORD(wParam))
{
case IDC_TEXTSIZE_EDIT: source->SetInt(TEXT("fontSize"), val); break;
case IDC_EXTENTWIDTH_EDIT: source->SetInt(TEXT("extentWidth"), val); break;
case IDC_EXTENTHEIGHT_EDIT: source->SetInt(TEXT("extentHeight"), val); break;
case IDC_TEXTOPACITY_EDIT: source->SetInt(TEXT("textOpacity"), val); break;
case IDC_OUTLINEOPACITY_EDIT: source->SetInt(TEXT("outlineOpacity"), val); break;
case IDC_BACKGROUNDOPACITY_EDIT: source->SetInt(TEXT("backgroundOpacity"), val); break;
case IDC_OUTLINETHICKNESS_EDIT: source->SetFloat(TEXT("outlineSize"), (float)val); break;
case IDC_SCROLLSPEED_EDIT: source->SetInt(TEXT("scrollSpeed"), val); break;
}
}
}
break;
case IDC_BOLD:
case IDC_ITALIC:
case IDC_UNDERLINE:
case IDC_VERTICALSCRIPT:
case IDC_WRAP:
case IDC_SCROLLMODE:
case IDC_USEOUTLINE:
case IDC_USETEXTEXTENTS:
if(HIWORD(wParam) == BN_CLICKED && bInitializedDialog)
{
BOOL bChecked = SendMessage((HWND)lParam, BM_GETCHECK, 0, 0) == BST_CHECKED;
ConfigTextSourceInfo *configInfo = (ConfigTextSourceInfo*)GetWindowLongPtr(hwnd, DWLP_USER);
if(!configInfo) break;
ImageSource *source = API->GetSceneImageSource(configInfo->lpName);
if(source)
{
switch(LOWORD(wParam))
{
case IDC_BOLD: source->SetInt(TEXT("bold"), bChecked); break;
case IDC_ITALIC: source->SetInt(TEXT("italic"), bChecked); break;
case IDC_UNDERLINE: source->SetInt(TEXT("underline"), bChecked); break;
case IDC_VERTICALSCRIPT: source->SetInt(TEXT("vertical"), bChecked); break;
case IDC_WRAP: source->SetInt(TEXT("wrap"), bChecked); break;
case IDC_SCROLLMODE: source->SetInt(TEXT("scrollMode"), bChecked); break;
case IDC_USEOUTLINE: source->SetInt(TEXT("useOutline"), bChecked); break;
case IDC_USETEXTEXTENTS: source->SetInt(TEXT("useTextExtents"), bChecked); break;
}
}
if(LOWORD(wParam) == IDC_VERTICALSCRIPT)
{
bool bWrap = SendMessage(GetDlgItem(hwnd, IDC_WRAP), BM_GETCHECK, 0, 0) == BST_CHECKED;
bool bUseExtents = SendMessage(GetDlgItem(hwnd, IDC_USETEXTEXTENTS), BM_GETCHECK, 0, 0) == BST_CHECKED;
EnableWindow(GetDlgItem(hwnd, IDC_SCROLLMODE), bWrap && bUseExtents && !bChecked);
}
else if(LOWORD(wParam) == IDC_WRAP)
{
bool bVertical = SendMessage(GetDlgItem(hwnd, IDC_VERTICALSCRIPT), BM_GETCHECK, 0, 0) == BST_CHECKED;
EnableWindow(GetDlgItem(hwnd, IDC_ALIGN), bChecked);
EnableWindow(GetDlgItem(hwnd, IDC_SCROLLMODE), bChecked && !bVertical);
}
else if(LOWORD(wParam) == IDC_USETEXTEXTENTS)
{
EnableWindow(GetDlgItem(hwnd, IDC_EXTENTWIDTH_EDIT), bChecked);
EnableWindow(GetDlgItem(hwnd, IDC_EXTENTHEIGHT_EDIT), bChecked);
EnableWindow(GetDlgItem(hwnd, IDC_EXTENTWIDTH), bChecked);
EnableWindow(GetDlgItem(hwnd, IDC_EXTENTHEIGHT), bChecked);
EnableWindow(GetDlgItem(hwnd, IDC_WRAP), bChecked);
bool bWrap = SendMessage(GetDlgItem(hwnd, IDC_WRAP), BM_GETCHECK, 0, 0) == BST_CHECKED;
bool bVertical = SendMessage(GetDlgItem(hwnd, IDC_VERTICALSCRIPT), BM_GETCHECK, 0, 0) == BST_CHECKED;
EnableWindow(GetDlgItem(hwnd, IDC_ALIGN), bChecked && bWrap);
EnableWindow(GetDlgItem(hwnd, IDC_SCROLLMODE), bChecked && bWrap && !bVertical);
}
else if(LOWORD(wParam) == IDC_USEOUTLINE)
{
EnableWindow(GetDlgItem(hwnd, IDC_OUTLINETHICKNESS_EDIT), bChecked);
EnableWindow(GetDlgItem(hwnd, IDC_OUTLINETHICKNESS), bChecked);
EnableWindow(GetDlgItem(hwnd, IDC_OUTLINECOLOR), bChecked);
EnableWindow(GetDlgItem(hwnd, IDC_OUTLINEOPACITY_EDIT), bChecked);
EnableWindow(GetDlgItem(hwnd, IDC_OUTLINEOPACITY), bChecked);
}
}
break;
case IDC_ALIGN:
if(HIWORD(wParam) == CBN_SELCHANGE && bInitializedDialog)
{
int align = (int)SendMessage((HWND)lParam, CB_GETCURSEL, 0, 0);
if(align == CB_ERR)
break;
ConfigTextSourceInfo *configInfo = (ConfigTextSourceInfo*)GetWindowLongPtr(hwnd, DWLP_USER);
if(!configInfo) break;
ImageSource *source = API->GetSceneImageSource(configInfo->lpName);
if(source)
source->SetInt(TEXT("align"), align);
}
break;
case IDC_FILE:
case IDC_TEXT:
if(HIWORD(wParam) == EN_CHANGE && bInitializedDialog)
{
String strText = GetEditText((HWND)lParam);
ConfigTextSourceInfo *configInfo = (ConfigTextSourceInfo*)GetWindowLongPtr(hwnd, DWLP_USER);
if(!configInfo) break;
ImageSource *source = API->GetSceneImageSource(configInfo->lpName);
if(source)
{
switch(LOWORD(wParam))
{
case IDC_FILE: source->SetString(TEXT("file"), strText); break;
case IDC_TEXT: source->SetString(TEXT("text"), strText); break;
}
}
}
break;
case IDC_USEFILE:
if(HIWORD(wParam) == BN_CLICKED && bInitializedDialog)
{
EnableWindow(GetDlgItem(hwnd, IDC_TEXT), FALSE);
EnableWindow(GetDlgItem(hwnd, IDC_FILE), TRUE);
EnableWindow(GetDlgItem(hwnd, IDC_BROWSE), TRUE);
ConfigTextSourceInfo *configInfo = (ConfigTextSourceInfo*)GetWindowLongPtr(hwnd, DWLP_USER);
ImageSource *source = API->GetSceneImageSource(configInfo->lpName);
if(source)
source->SetInt(TEXT("mode"), 1);
}
break;
case IDC_USETEXT:
if(HIWORD(wParam) == BN_CLICKED && bInitializedDialog)
{
EnableWindow(GetDlgItem(hwnd, IDC_TEXT), TRUE);
EnableWindow(GetDlgItem(hwnd, IDC_FILE), FALSE);
EnableWindow(GetDlgItem(hwnd, IDC_BROWSE), FALSE);
ConfigTextSourceInfo *configInfo = (ConfigTextSourceInfo*)GetWindowLongPtr(hwnd, DWLP_USER);
if(!configInfo) break;
ImageSource *source = API->GetSceneImageSource(configInfo->lpName);
if(source)
source->SetInt(TEXT("mode"), 0);
}
break;
case IDC_BROWSE:
{
TCHAR lpFile[MAX_PATH+1];
zero(lpFile, sizeof(lpFile));
OPENFILENAME ofn;
zero(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.lpstrFile = lpFile;
ofn.hwndOwner = hwnd;
ofn.nMaxFile = MAX_PATH;
ofn.lpstrFilter = TEXT("Text Files (*.txt)\0*.txt\0");
ofn.nFilterIndex = 1;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
TCHAR curDirectory[MAX_PATH+1];
GetCurrentDirectory(MAX_PATH, curDirectory);
BOOL bOpenFile = GetOpenFileName(&ofn);
SetCurrentDirectory(curDirectory);
if(bOpenFile)
{
SetWindowText(GetDlgItem(hwnd, IDC_FILE), lpFile);
ConfigTextSourceInfo *configInfo = (ConfigTextSourceInfo*)GetWindowLongPtr(hwnd, DWLP_USER);
ImageSource *source = API->GetSceneImageSource(configInfo->lpName);
if(source)
source->SetString(TEXT("file"), lpFile);
}
}
break;
case IDOK:
{
ConfigTextSourceInfo *configInfo = (ConfigTextSourceInfo*)GetWindowLongPtr(hwnd, DWLP_USER);
if(!configInfo) break;
XElement *data = configInfo->data;
BOOL bUseTextExtents = SendMessage(GetDlgItem(hwnd, IDC_USETEXTEXTENTS), BM_GETCHECK, 0, 0) == BST_CHECKED;
BOOL bUseOutline = SendMessage(GetDlgItem(hwnd, IDC_USEOUTLINE), BM_GETCHECK, 0, 0) == BST_CHECKED;
float outlineSize = (float)SendMessage(GetDlgItem(hwnd, IDC_OUTLINETHICKNESS), UDM_GETPOS32, 0, 0);
int mode = SendMessage(GetDlgItem(hwnd, IDC_USEFILE), BM_GETCHECK, 0, 0) == BST_CHECKED;
String strText = GetEditText(GetDlgItem(hwnd, IDC_TEXT));
String strFile = GetEditText(GetDlgItem(hwnd, IDC_FILE));
UINT extentWidth = (UINT)SendMessage(GetDlgItem(hwnd, IDC_EXTENTWIDTH), UDM_GETPOS32, 0, 0);
UINT extentHeight = (UINT)SendMessage(GetDlgItem(hwnd, IDC_EXTENTHEIGHT), UDM_GETPOS32, 0, 0);
String strFont = GetFontFace(configInfo, GetDlgItem(hwnd, IDC_FONT));
UINT fontSize = (UINT)SendMessage(GetDlgItem(hwnd, IDC_TEXTSIZE), UDM_GETPOS32, 0, 0);
BOOL bBold = SendMessage(GetDlgItem(hwnd, IDC_BOLD), BM_GETCHECK, 0, 0) == BST_CHECKED;
BOOL bItalic = SendMessage(GetDlgItem(hwnd, IDC_ITALIC), BM_GETCHECK, 0, 0) == BST_CHECKED;
BOOL bVertical = SendMessage(GetDlgItem(hwnd, IDC_VERTICALSCRIPT), BM_GETCHECK, 0, 0) == BST_CHECKED;
BOOL pointFiltering = SendMessage(GetDlgItem(hwnd, IDC_POINTFILTERING), BM_GETCHECK, 0, 0) == BST_CHECKED;
String strFontDisplayName = GetEditText(GetDlgItem(hwnd, IDC_FONT));
if(strFont.IsEmpty())
{
UINT id = FindFontName(configInfo, GetDlgItem(hwnd, IDC_FONT), strFontDisplayName);
if(id != INVALID)
strFont = configInfo->fontFaces[id];
}
if(strFont.IsEmpty())
{
String strError = Str("Sources.TextSource.FontNotFound");
strError.FindReplace(TEXT("$1"), strFontDisplayName);
OBSMessageBox(hwnd, strError, NULL, 0);
break;
}
if(bUseTextExtents)
{
configInfo->cx = float(extentWidth);
configInfo->cy = float(extentHeight);
}
else
{
String strOutputText;
if(mode == 0)
strOutputText = strText;
else if(mode == 1)
{
XFile textFile;
if(strFile.IsEmpty() || !textFile.Open(strFile, XFILE_READ | XFILE_SHARED, XFILE_OPENEXISTING))
{
String strError = Str("Sources.TextSource.FileNotFound");
strError.FindReplace(TEXT("$1"), strFile);
OBSMessageBox(hwnd, strError, NULL, 0);
break;
}
textFile.ReadFileToString(strOutputText);
}
LOGFONT lf;
zero(&lf, sizeof(lf));
lf.lfHeight = fontSize;
lf.lfWeight = bBold ? FW_BOLD : FW_DONTCARE;
lf.lfItalic = bItalic;
lf.lfQuality = ANTIALIASED_QUALITY;
if(strFont.IsValid())
scpy_n(lf.lfFaceName, strFont, 31);
else
scpy_n(lf.lfFaceName, TEXT("Arial"), 31);
HDC hDC = CreateCompatibleDC(NULL);
Gdiplus::Font font(hDC, &lf);
if(!font.IsAvailable())
{
String strError = Str("Sources.TextSource.FontNotFound");
strError.FindReplace(TEXT("$1"), strFontDisplayName);
OBSMessageBox(hwnd, strError, NULL, 0);
DeleteDC(hDC);
break;
}
{
Gdiplus::Graphics graphics(hDC);
Gdiplus::StringFormat format(Gdiplus::StringFormat::GenericTypographic());
UINT formatFlags;
formatFlags = Gdiplus::StringFormatFlagsNoFitBlackBox
| Gdiplus::StringFormatFlagsMeasureTrailingSpaces;
if(bVertical)
formatFlags |= Gdiplus::StringFormatFlagsDirectionVertical
| Gdiplus::StringFormatFlagsDirectionRightToLeft;
format.SetFormatFlags(formatFlags);
format.SetTrimming(Gdiplus::StringTrimmingWord);
Gdiplus::RectF rcf;
graphics.MeasureString(strOutputText, -1, &font, Gdiplus::PointF(0.0f, 0.0f), &format, &rcf);
if(bUseOutline)
{
rcf.Height += outlineSize;
rcf.Width += outlineSize;
}
if(bVertical)
{
if(rcf.Width<fontSize)
rcf.Width = (float)fontSize;
}
else
{
if(rcf.Height<fontSize)
rcf.Height = (float)fontSize;
}
configInfo->cx = MAX(rcf.Width, 32.0f);
configInfo->cy = MAX(rcf.Height, 32.0f);
}
DeleteDC(hDC);
}
data->SetFloat(TEXT("baseSizeCX"), configInfo->cx);
data->SetFloat(TEXT("baseSizeCY"), configInfo->cy);
data->SetString(TEXT("font"), strFont);
data->SetInt(TEXT("color"), CCGetColor(GetDlgItem(hwnd, IDC_COLOR)));
data->SetInt(TEXT("fontSize"), fontSize);
data->SetInt(TEXT("textOpacity"), (UINT)SendMessage(GetDlgItem(hwnd, IDC_TEXTOPACITY), UDM_GETPOS32, 0, 0));
data->SetInt(TEXT("scrollSpeed"), (int)SendMessage(GetDlgItem(hwnd, IDC_SCROLLSPEED), UDM_GETPOS32, 0, 0));
data->SetInt(TEXT("bold"), bBold);
data->SetInt(TEXT("italic"), bItalic);
data->SetInt(TEXT("vertical"), bVertical);
data->SetInt(TEXT("wrap"), SendMessage(GetDlgItem(hwnd, IDC_WRAP), BM_GETCHECK, 0, 0) == BST_CHECKED);
data->SetInt(TEXT("scrollMode"), SendMessage(GetDlgItem(hwnd, IDC_SCROLLMODE), BM_GETCHECK, 0, 0) == BST_CHECKED);
data->SetInt(TEXT("underline"), SendMessage(GetDlgItem(hwnd, IDC_UNDERLINE), BM_GETCHECK, 0, 0) == BST_CHECKED);
data->SetInt(TEXT("pointFiltering"), pointFiltering);
data->SetInt(TEXT("backgroundColor"), CCGetColor(GetDlgItem(hwnd, IDC_BACKGROUNDCOLOR)));
data->SetInt(TEXT("backgroundOpacity"), (UINT)SendMessage(GetDlgItem(hwnd, IDC_BACKGROUNDOPACITY), UDM_GETPOS32, 0, 0));
data->SetInt(TEXT("useOutline"), bUseOutline);
data->SetInt(TEXT("outlineColor"), CCGetColor(GetDlgItem(hwnd, IDC_OUTLINECOLOR)));
data->SetFloat(TEXT("outlineSize"), outlineSize);
data->SetInt(TEXT("outlineOpacity"), (UINT)SendMessage(GetDlgItem(hwnd, IDC_OUTLINEOPACITY), UDM_GETPOS32, 0, 0));
data->SetInt(TEXT("useTextExtents"), bUseTextExtents);
data->SetInt(TEXT("extentWidth"), extentWidth);
data->SetInt(TEXT("extentHeight"), extentHeight);
data->SetInt(TEXT("align"), (int)SendMessage(GetDlgItem(hwnd, IDC_ALIGN), CB_GETCURSEL, 0, 0));
data->SetString(TEXT("file"), strFile);
data->SetString(TEXT("text"), strText);
data->SetInt(TEXT("mode"), mode);
}
case IDCANCEL:
if(LOWORD(wParam) == IDCANCEL)
DoCancelStuff(hwnd);
EndDialog(hwnd, LOWORD(wParam));
}
break;
case WM_CLOSE:
DoCancelStuff(hwnd);
EndDialog(hwnd, IDCANCEL);
}
return 0;
}
bool STDCALL ConfigureTextSource(XElement *element, bool bCreating)
{
if(!element)
{
AppWarning(TEXT("ConfigureTextSource: NULL element"));
return false;
}
XElement *data = element->GetElement(TEXT("data"));
if(!data)
data = element->CreateElement(TEXT("data"));
ConfigTextSourceInfo configInfo;
configInfo.lpName = element->GetName();
configInfo.data = data;
if(OBSDialogBox(hinstMain, MAKEINTRESOURCE(IDD_CONFIGURETEXTSOURCE), hwndMain, ConfigureTextProc, (LPARAM)&configInfo) == IDOK)
{
element->SetFloat(TEXT("cx"), configInfo.cx);
element->SetFloat(TEXT("cy"), configInfo.cy);
return true;
}
return false;
}