Merge branch 'develop' into Better_Graphics_Handling

Conflicts:
	VocaluxeLib/Menu/CNameSelection.cs
	VocaluxeLib/Menu/CPlaylist.cs
	VocaluxeLib/Menu/CText.cs
	VocaluxeLib/Menu/SongMenu/CSongMenuFramework.cs
	VocaluxeLib/Structs.cs
	VocaluxeLib/VocaluxeLib.csproj
	VocaluxeLib/Xml/CXMLReader.cs
This commit is contained in:
Flamefire committed 2014-10-05 15:09:52 +02:00
commit 355d7b4b5f
52 files changed
+1407 -653

No files matched your search

+37
View File
@@ -5,4 +5,41 @@
<Folder>Blue</Folder>
<Author>flokuep</Author>
</Info>
<!--Cover definitions when a category is missing a cover-->
<CoverGenerator1>
<!--Possible types are: Default, Artist, Letter, Edition, Genre, Language, Year, Decade, Date -->
<Type>Default</Type>
<Text>
<!--<Text>: Text to be shown, %TEXT% will be replace by the category name-->
<Text>%TEXT%</Text>
<Font>
<Name>Normal</Name>
<!--<Style>: Text style: Normal, Italic, Bold, BoldItalic-->
<Style>Bold</Style>
<!--<Size> Maximum size of the text in px-->
<Size>500</Size>
</Font>
<!--<Color>: Text color from ColorScheme (high priority)-->
<!--or <R>, <G>, <B>, <A> (lower priority)-->
<Color>
<R>1</R><G>1</G><B>1</B><A>0.8</A>
</Color>
<!--<Margin>: Spacing of the text from the borders of the image in px-->
<Margin>
<Default>24</Default>
<Left>24</Left>
</Margin>
<!--<Indent>: Indentation of the text for multiple lines-->
<Indent>100</Indent>
</Text>
<BackgroundColor>
<R>1</R><G>1</G><B>1</B><A>1</A>
</BackgroundColor>
<!--<Image>: Background image for the cover-->
<Image>EmptyCover.png</Image>
<!--<ShowFirstCover>Whether the first cover of a category should be shown(optional)-->
<ShowFirstCover>true</ShowFirstCover>
<!--<ImageAlpha>Alpha value of the image in case the first cover is shown(optional)-->
<ImageAlpha>0.75</ImageAlpha>
</CoverGenerator1>
</root>
+12 -8
View File
@@ -4,10 +4,12 @@
<Font1>
<Name>Normal</Name>
<Outline>0,00</Outline>
<OutlineColorR>0,00</OutlineColorR>
<OutlineColorG>0,00</OutlineColorG>
<OutlineColorB>0,00</OutlineColorB>
<OutlineColorA>1,00</OutlineColorA>
<OutlineColor>
<R>0,00</R>
<G>0,00</G>
<B>0,00</B>
<A>1,00</A>
</OutlineColor>
<Folder>FreeSans</Folder>
<FileNormal>FreeSans.ttf</FileNormal>
<FileBold>FreeSansBold.ttf</FileBold>
@@ -17,10 +19,12 @@
<Font2>
<Name>Outline</Name>
<Outline>0,10</Outline>
<OutlineColorR>0,00</OutlineColorR>
<OutlineColorG>0,00</OutlineColorG>
<OutlineColorB>0,00</OutlineColorB>
<OutlineColorA>1,00</OutlineColorA>
<OutlineColor>
<R>0,00</R>
<G>0,00</G>
<B>0,00</B>
<A>1,00</A>
</OutlineColor>
<Folder>FreeSans</Folder>
<FileNormal>FreeSans.ttf</FileNormal>
<FileBold>FreeSansBold.ttf</FileBold>
@@ -446,7 +446,7 @@ namespace VocaluxeLib.PartyModes.Challenge
_RoundsTableScrollArea.Y = numberY;
_RoundsTableScrollArea.W = CBase.Settings.GetRenderW() - _Texts[_TextRoundNumber].X - 20;
float delta = _Texts[_TextRoundNumber].Height;
float delta = _Texts[_TextRoundNumber].Rect.H;
//Update statics and texts for rounds
foreach (CRoundsTableRow roundRow in _RoundsTable)
@@ -479,7 +479,7 @@ namespace VocaluxeLib.PartyModes.Challenge
roundRow.TextScores[column].Y = numberY + delta;
roundRow.TextScores[column].MaxWidth = maxw;
}
numberY = numberY + delta + delta;
numberY = numberY + 2*delta;
}
numberY = numberY + delta / 2;
}
@@ -532,7 +532,7 @@ namespace VocaluxeLib.PartyModes.Challenge
_PlayerTableScrollArea = new SRectF {X = _Texts[_TextPosition].X, Y = _Texts[_TextPosition].Y, W = _Texts[_TextGamePoints].X - _Texts[_TextPosition].X};
_PlayerTable = new List<STableRow>();
float delta = _Texts[_TextPosition].Height * 1.2f;
float delta = _Texts[_TextPosition].Rect.H * 1.2f;
float h = 0;
@@ -446,7 +446,7 @@ namespace VocaluxeLib.PartyModes.ChallengeMedley
_RoundsTableScrollArea.Y = numberY;
_RoundsTableScrollArea.W = CBase.Settings.GetRenderW() - _Texts[_TextRoundNumber].X - 20;
float delta = _Texts[_TextRoundNumber].Height;
float delta = _Texts[_TextRoundNumber].Rect.H;
//Update statics and texts for rounds
foreach (CRoundsTableRow roundRow in _RoundsTable)
@@ -532,7 +532,7 @@ namespace VocaluxeLib.PartyModes.ChallengeMedley
_PlayerTableScrollArea = new SRectF {X = _Texts[_TextPosition].X, Y = _Texts[_TextPosition].Y, W = _Texts[_TextGamePoints].X - _Texts[_TextPosition].X};
_PlayerTable = new List<STableRow>();
float delta = _Texts[_TextPosition].Height * 1.2f;
float delta = _Texts[_TextPosition].Rect.H * 1.2f;
float h = 0;
+1 -1
View File
@@ -193,7 +193,7 @@ namespace Vocaluxe.Base
if (_PlaysPreview)
_PreviewPlayer.Play();
else if (CConfig.BackgroundMusic == EBackgroundMusicOffOn.TR_CONFIG_OFF)
else if(CConfig.BackgroundMusic == EBackgroundMusicOffOn.TR_CONFIG_ON)
{
if (_SongPlayer.SongLoaded)
//Resume
+2 -1
View File
@@ -28,6 +28,7 @@ using Vocaluxe.Lib.Sound.Record;
using Vocaluxe.Lib.Webcam;
using VocaluxeLib;
using VocaluxeLib.Profile;
using VocaluxeLib.Xml;
namespace Vocaluxe.Base
{
@@ -840,7 +841,7 @@ namespace Vocaluxe.Base
break;
case "oldtheme":
if(value == "yes")
if (value == "yes")
LoadOldThemeFiles = true;
break;
}
+99 -13
View File
@@ -17,23 +17,29 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Threading.Tasks;
using VocaluxeLib;
using VocaluxeLib.Draw;
using VocaluxeLib.Songs;
using VocaluxeLib.Xml;
namespace Vocaluxe.Base
{
struct SCoverTheme
struct SThemeCover
{
public string Name;
public string Folder;
public string File;
public string Name, Folder;
public string FilePath;
}
static class CCover
{
private const string _NoCoverName = "No Cover";
private const string _NoCoverNameAlt = "NoCover";
private static readonly Dictionary<string, CTextureRef> _Covers = new Dictionary<string, CTextureRef>();
private static readonly List<SCoverTheme> _CoverThemes = new List<SCoverTheme>();
private static readonly Dictionary<ECoverGeneratorType, CNoCoverGenerator> _NoCoverGenerators = new Dictionary<ECoverGeneratorType, CNoCoverGenerator>();
private static readonly List<SThemeCover> _CoverThemes = new List<SThemeCover>();
public static CTextureRef NoCover { get; private set; }
@@ -92,6 +98,26 @@ namespace Vocaluxe.Base
}
}
public static CTextureRef GenerateCover(string text, ESongSorting sorting, CCategory category)
{
CSong firstSong = category.GetSong(0);
CTextureRef texture = CDraw.CopyTexture(NoCover);
Task.Factory.StartNew(() =>
{
ECoverGeneratorType type = _SongSortingToType(sorting);
Bitmap coverBmp = !_NoCoverGenerators.ContainsKey(type)?null:_NoCoverGenerators[type].GetCover(text, firstSong != null ? Path.Combine(firstSong.Folder, firstSong.CoverFileName) : null);
if (coverBmp == null && _NoCoverGenerators.ContainsKey(ECoverGeneratorType.Default))
coverBmp = _NoCoverGenerators[ECoverGeneratorType.Default].GetCover(text, firstSong != null ? Path.Combine(firstSong.Folder, firstSong.CoverFileName) : null);
if (coverBmp != null)
CDraw.EnqueueTextureUpdate(texture, coverBmp);
});
lock (_Covers)
{
_Covers.Add(text, texture);
}
return texture;
}
/// <summary>
/// Returns true if a cover with the given name exists.
/// MUST HOLD _Covers lock at this point
@@ -121,19 +147,23 @@ namespace Vocaluxe.Base
}
_Covers.Clear();
}
lock (_NoCoverGenerators)
{
_NoCoverGenerators.Clear();
}
}
/// <summary>
/// Returns a SCoverTheme by cover-theme-name
/// </summary>
private static SCoverTheme _CoverTheme(string coverThemeName)
private static SThemeCover _CoverTheme(string coverThemeName)
{
for (int i = 0; i < _CoverThemes.Count; i++)
{
if (_CoverThemes[i].Name == coverThemeName)
return _CoverThemes[i];
}
return new SCoverTheme();
return new SThemeCover();
}
/// <summary>
@@ -152,14 +182,14 @@ namespace Vocaluxe.Base
if (xmlReader != null)
{
var coverTheme = new SCoverTheme();
var coverTheme = new SThemeCover();
xmlReader.GetValue("//root/Info/Name", out coverTheme.Name, String.Empty);
xmlReader.GetValue("//root/Info/Folder", out coverTheme.Folder, String.Empty);
if (coverTheme.Folder != "" && coverTheme.Name != "")
{
coverTheme.File = file;
coverTheme.FilePath = xmlReader.FilePath;
_CoverThemes.Add(coverTheme);
}
@@ -168,11 +198,11 @@ namespace Vocaluxe.Base
}
/// <summary>
/// Loads all cover which are defined in the cover config file.
/// Loads all covers from the theme
/// </summary>
private static void _LoadCovers(string coverThemeName)
{
SCoverTheme coverTheme = _CoverTheme(coverThemeName);
SThemeCover coverTheme = _CoverTheme(coverThemeName);
if (String.IsNullOrEmpty(coverTheme.Name))
return;
@@ -184,8 +214,64 @@ namespace Vocaluxe.Base
{
foreach (string file in files)
_AddCover(Path.GetFileNameWithoutExtension(file), file);
if (_CoverExists("No Cover"))
NoCover = _Covers["No Cover"];
if (_CoverExists(_NoCoverName))
NoCover = _Covers[_NoCoverName];
else if (_CoverExists(_NoCoverNameAlt))
NoCover = _Covers[_NoCoverNameAlt];
else
CBase.Log.LogError("Covertheme \"" + coverThemeName + "\" does not include a cover file named \"" + _NoCoverName + "\" and cannot be used!", true, true);
}
_LoadNoCoverThemes(coverTheme);
}
private static ECoverGeneratorType _SongSortingToType(ESongSorting sorting)
{
switch (sorting)
{
case ESongSorting.TR_CONFIG_NONE:
return ECoverGeneratorType.Default;
case ESongSorting.TR_CONFIG_FOLDER:
return ECoverGeneratorType.Folder;
case ESongSorting.TR_CONFIG_ARTIST:
return ECoverGeneratorType.Artist;
case ESongSorting.TR_CONFIG_ARTIST_LETTER:
case ESongSorting.TR_CONFIG_TITLE_LETTER:
return ECoverGeneratorType.Letter;
case ESongSorting.TR_CONFIG_EDITION:
return ECoverGeneratorType.Edition;
case ESongSorting.TR_CONFIG_GENRE:
return ECoverGeneratorType.Genre;
case ESongSorting.TR_CONFIG_LANGUAGE:
return ECoverGeneratorType.Language;
case ESongSorting.TR_CONFIG_YEAR:
return ECoverGeneratorType.Year;
case ESongSorting.TR_CONFIG_DECADE:
return ECoverGeneratorType.Decade;
case ESongSorting.TR_CONFIG_DATEADDED:
return ECoverGeneratorType.Date;
default:
throw new ArgumentOutOfRangeException("sorting");
}
}
private static void _LoadNoCoverThemes(SThemeCover coverTheme)
{
CXMLReader xmlReader = CXMLReader.OpenFile(coverTheme.FilePath);
string coverPath = Path.Combine(CSettings.ProgramFolder, CSettings.FolderNameCover, coverTheme.Folder);
lock (_NoCoverGenerators)
{
int i = 1;
while(xmlReader.ItemExists("//root/CoverGenerator"+i)){
SThemeCoverGenerator theme;
if (xmlReader.Read("//root/CoverGenerator" + i, out theme))
{
if (_NoCoverGenerators.ContainsKey(theme.Type))
continue;
CNoCoverGenerator el = new CNoCoverGenerator(theme, coverPath);
_NoCoverGenerators.Add(theme.Type, el);
}
i++;
}
}
}
+2 -1
View File
@@ -216,7 +216,8 @@ namespace Vocaluxe.Base
/// <summary>
/// Requests updating a texture from a bitmap<br />
/// Use this if you add textures from another thread or don't need it immediatelly
/// Use this if you add textures from another thread or don't need it immediatelly <br />
/// Bitmap is freed after use
/// </summary>
/// <param name="textureRef">Reference to the texture to update</param>
/// <param name="bmp"></param>
+4 -5
View File
@@ -658,16 +658,15 @@ namespace Vocaluxe.Base
}
}
}
CFonts.Style = EStyle.Normal;
CFonts.SetFont("Normal");
CFonts.Height = 25;
CFont font=new CFont("Normal",EStyle.Normal, 25);
SColorF gray = new SColorF(1f, 1f, 1f, 0.5f);
float y = 0;
foreach (string txt in debugOutput)
{
RectangleF rect = new RectangleF(CSettings.RenderW - CFonts.GetTextWidth(txt), y, CFonts.GetTextWidth(txt), CFonts.GetTextHeight(txt));
float textWidth = CFonts.GetTextWidth(txt, font);
RectangleF rect = new RectangleF(CSettings.RenderW - textWidth, y, textWidth, CFonts.GetTextHeight(txt,font));
CDraw.DrawRect(gray, new SRectF(rect.X, rect.Top, rect.Width, rect.Height, CSettings.ZNear));
CFonts.DrawText(txt, rect.X, rect.Y, CSettings.ZNear);
CFonts.DrawText(txt, font, rect.X, rect.Y, CSettings.ZNear);
y += rect.Height;
}
}
+1
View File
@@ -20,6 +20,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using VocaluxeLib;
using VocaluxeLib.Xml;
namespace Vocaluxe.Base
{
+6 -21
View File
@@ -507,39 +507,24 @@ namespace Vocaluxe.Base
class CBfonts : IFonts
{
public void SetFont(string fontName)
{
CFonts.SetFont(fontName);
}
public void SetStyle(EStyle fontStyle)
{
CFonts.Style = fontStyle;
}
public RectangleF GetTextBounds(CText text)
{
return CFonts.GetTextBounds(text);
}
public RectangleF GetTextBounds(CText text, float textHeight)
public void DrawText(string text, CFont font, float x, float y, float z, SColorF color)
{
return CFonts.GetTextBounds(text, textHeight);
CFonts.DrawText(text, font, x, y, z, color);
}
public void DrawText(string text, float textHeight, float x, float y, float z, SColorF color)
public void DrawTextReflection(string text, CFont font, float x, float y, float z, SColorF color, float reflectionSpace, float reflectionHeight)
{
CFonts.DrawText(text, textHeight, x, y, z, color);
CFonts.DrawTextReflection(text, font, x, y, z, color, reflectionSpace, reflectionHeight);
}
public void DrawTextReflection(string text, float textHeight, float x, float y, float z, SColorF color, float reflectionSpace, float reflectionHeight)
public void DrawText(string text, CFont font, float x, float y, float z, SColorF color, float begin, float end)
{
CFonts.DrawTextReflection(text, textHeight, x, y, z, color, reflectionSpace, reflectionHeight);
}
public void DrawText(string text, float textHeight, float x, float y, float z, SColorF color, float begin, float end)
{
CFonts.DrawText(text, textHeight, x, y, z, color, begin, end);
CFonts.DrawText(text, font, x, y, z, color, begin, end);
}
}
+495
View File
@@ -0,0 +1,495 @@
#region license
// This file is part of Vocaluxe.
//
// Vocaluxe 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 3 of the License, or
// (at your option) any later version.
//
// Vocaluxe 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 Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
#endregion
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Drawing.Text;
using System.IO;
using Vocaluxe.Base.Fonts;
using VocaluxeLib;
using System.Linq;
namespace Vocaluxe.Base
{
/// <summary>
/// Class that generates Covers if the right Cover is missing
/// Themeable via the xml of the Cover theme
/// </summary>
class CNoCoverGenerator
{
private readonly bool _Valid;
private readonly SThemeCoverGenerator _Theme;
private readonly string _Image;
private readonly SColorF _TextColor;
private readonly SColorF _BGColor;
private const int _LineSpace = 5;
/// <summary>
/// Split lines after special chars, descending priority
/// </summary>
private static readonly char[] _SplitCharPreferences = {':', '/', '-'};
private static readonly char[] _SplitCharAfter = {':', '/', '-', ' ', ')', '.', '*', ','};
private static readonly char[] _SplitCharBefore = {'('};
public CNoCoverGenerator(SThemeCoverGenerator theme, string basePath)
{
_Theme = theme;
_Valid = true;
_Valid &= _Theme.Text.Color.Get(-1, out _TextColor);
_Valid &= _Theme.BackgroundColor.Get(-1, out _BGColor);
if (_Valid)
{
_Image = Path.Combine(basePath, _Theme.Image);
_Valid = File.Exists(_Image);
}
}
private class CTextElement
{
public readonly string Text;
public float Width, Height;
private readonly Graphics _Graphics;
private readonly Font _Font;
private float _WidthTrimmed = -1;
public float WidthTrimmed
{
get
{
if (_WidthTrimmed < 0f)
{
string text = Text.TrimEnd(null);
_WidthTrimmed = text.Length == Text.Length ? Width : _Graphics.MeasureString(text, _Font, -1, StringFormat.GenericTypographic).Width;
}
return _WidthTrimmed;
}
}
public int Line;
public CTextElement(string text, Graphics g, Font font)
{
Text = text;
SizeF dimensions = g.MeasureString(text, font, -1, StringFormat.GenericTypographic);
Width = dimensions.Width;
Height = (dimensions.Height + font.Height) / 2;
_Graphics = g;
_Font = font;
}
public void AdjustSize(float factor)
{
Width *= factor;
_WidthTrimmed *= factor;
Height *= factor;
}
}
private void _DrawBackground(Graphics g, Bitmap bmpBackground, String firstCoverPath)
{
g.Clear(_BGColor.AsColor());
ImageAttributes ia = null;
if (_Theme.ShowFirstCover && !String.IsNullOrEmpty(firstCoverPath) && File.Exists(firstCoverPath))
{
using (Bitmap bmp2 = new Bitmap(firstCoverPath))
g.DrawImage(bmp2, bmpBackground.GetRect(), 0, 0, bmp2.Width, bmp2.Height, GraphicsUnit.Pixel);
ColorMatrix cm = new ColorMatrix {Matrix33 = _Theme.ImageAlpha};
ia = new ImageAttributes();
ia.SetColorMatrix(cm);
}
g.DrawImage(bmpBackground, bmpBackground.GetRect(), 0, 0, bmpBackground.Width, bmpBackground.Height, GraphicsUnit.Pixel, ia);
}
private void _DrawText(Graphics g, Size bmpSize, CFont font, List<CTextElement> elements)
{
Font fo = CFonts.GetSystemFont(font);
float maxHeight = elements.Select(el => el.Height).Max();
int lineCount = elements.Last().Line + 1;
//Have to use size in em not pixels!
float emSize = fo.Size * fo.FontFamily.GetCellAscent(fo.Style) / fo.FontFamily.GetEmHeight(fo.Style);
float outlineSize = CFonts.GetOutlineSize(font) * font.Height;
SColorF outlineColorF = CFonts.GetOutlineColor(font);
outlineColorF.A = outlineColorF.A * _TextColor.A;
using (var path = new GraphicsPath())
using (var pen = new Pen(outlineColorF.AsColor(), outlineSize / 2))
{
pen.LineJoin = LineJoin.Round;
pen.Alignment = PenAlignment.Outset;
float top = (bmpSize.Height - _Theme.Text.Margin.Bottom - _Theme.Text.Margin.Top - maxHeight * lineCount) / 2 + _Theme.Text.Margin.Top;
int nextLineEl = 0;
for (int i = 0; i < lineCount; i++)
{
int firstEl = nextLineEl;
for (; nextLineEl < elements.Count; nextLineEl++)
{
if (elements[nextLineEl].Line > i)
break;
}
string line = elements.GetRange(firstEl, nextLineEl - firstEl).Aggregate("", (current, element) => current + element.Text);
float left;
if (lineCount == 1 || (i == 1 && lineCount == 3))
{
//Center Text if this is the only line or the middle line
float width = _GetWidth(elements, firstEl, nextLineEl - 1);
left = (bmpSize.Width - _Theme.Text.Margin.Left - _Theme.Text.Margin.Right - width) / 2 + _Theme.Text.Margin.Left;
}
else if (i == lineCount - 1)
{
//Place last line at right
float width = _GetWidth(elements, firstEl, nextLineEl - 1);
left = bmpSize.Width - width - _Theme.Text.Margin.Right;
}
else
left = _Theme.Text.Margin.Left;
//g.DrawString(line, fo, new SolidBrush(_TextColor.AsColor()), left, top, StringFormat.GenericTypographic);
path.AddString(line, fo.FontFamily, (int)fo.Style, emSize, new PointF(left, top), StringFormat.GenericTypographic);
top += maxHeight + _LineSpace;
}
g.DrawPath(pen, path);
g.FillPath(new SolidBrush(_TextColor.AsColor()), path);
}
}
public Bitmap GetCover(string text, string firstCoverPath)
{
if (!_Valid)
return null;
text = CLanguage.Translate(_Theme.Text.Text.Replace("%TEXT%", text));
using (Bitmap bmpImage = new Bitmap(_Image))
{
Bitmap bmp = new Bitmap(bmpImage.Width, bmpImage.Height, PixelFormat.Format32bppArgb);
try
{
using (Graphics g = Graphics.FromImage(bmp))
{
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.TextRenderingHint = TextRenderingHint.AntiAlias;
_DrawBackground(g, bmpImage, firstCoverPath);
if (text != "")
{
CFont font = new CFont(_Theme.Text.Font);
Font fo = CFonts.GetSystemFont(font);
IEnumerable<string> textParts = _SplitText(text);
List<CTextElement> elements = textParts.Select(line => new CTextElement(line, g, fo)).ToList();
float factor = _DistributeText(elements, bmp.Width, bmp.Height);
foreach (CTextElement element in elements)
element.AdjustSize(factor);
font.Height *= factor / (1f + CFonts.GetOutlineSize(font)); //Adjust for outline size
_DrawText(g, bmp.GetSize(), font, elements);
}
}
return bmp;
}
catch (Exception)
{
bmp.Dispose();
}
}
return null;
}
/// <summary>
/// Distributes the text among max. 3 lines maximizing the height of the line<br />
/// Sets the Line field in the elements
/// </summary>
/// <param name="elements">Text with set Width and Height</param>
/// <param name="width">Image Width</param>
/// <param name="height">Image Height</param>
/// <returns>Factor for resizing the text (Maximizing this factor means maximizing the height)</returns>
private float _DistributeText(List<CTextElement> elements, int width, int height)
{
int availableWidth = width - _Theme.Text.Margin.Left - _Theme.Text.Margin.Right;
int availableHeight = height - _Theme.Text.Margin.Top - _Theme.Text.Margin.Bottom;
float textHeight = elements.Select(el => el.Height).Max();
//Try 1 line:
float textWidth = _GetWidth(elements, 0);
int maxHeight = Math.Min(availableHeight, (int)_Theme.Text.Font.Size);
float factorH = maxHeight / textHeight;
float factorW = availableWidth / textWidth;
if (factorH <= factorW)
return factorH; //Limited by Height
float factor1 = factorW;
//Try 2 lines
if (elements.Count == 1)
{
//Only 1 element -> 1 line
return factor1;
}
availableWidth -= _Theme.Text.Indent;
maxHeight = Math.Min(availableHeight / 2 - _LineSpace, (int)_Theme.Text.Font.Size);
factorH = maxHeight / textHeight;
if (factorH <= factor1)
return factor1; //Cannot get any bigger with more lines
int splitEl = _GetSplitElement(elements, textWidth / 2);
Debug.Assert(splitEl >= 0 && splitEl < elements.Count - 1);
float width1 = _GetWidth(elements, 0, splitEl);
float width2 = _GetWidth(elements, splitEl + 1);
factorW = availableWidth / Math.Max(width1, width2);
if (factorH <= factorW)
{
// Assertion: factorH>factor1 (check above) && factorH<=factorW --> Min(factorH,factorW)>factor 1
// but for 2 lines it is limited by height
// --> Use 2 lines
_SetLine(elements, splitEl + 1, elements.Count - 1, 1);
return factorH;
}
// factor2 < factorH && factorH>factor1
float factor2 = factorW;
//Try 3 lines
maxHeight = Math.Min(availableHeight / 3 - 2 * _LineSpace, (int)_Theme.Text.Font.Size);
factorH = maxHeight / textHeight;
if (elements.Count == 2 || factorH <= Math.Max(factor1, factor2))
{
//Only 2 elements or cannot get any bigger
if (factor2 <= factor1)
return factor1;
_SetLine(elements, splitEl + 1, elements.Count - 1, 1);
return factor2;
}
int splitEl21 = _GetSplitElement(elements, textWidth / 3, false);
int splitEl22 = _GetSplitElement(elements, textWidth / 3, true, splitEl21 + 1);
Debug.Assert(splitEl21 >= 0 && splitEl21 < splitEl22 && splitEl22 < elements.Count - 1);
float width21 = _GetWidth(elements, 0, splitEl21);
float width22 = _GetWidth(elements, splitEl21 + 1, splitEl22);
float width23 = _GetWidth(elements, splitEl22 + 1);
factorW = availableWidth / Math.Max(Math.Max(width21, width22), width23);
float factor3 = Math.Min(factorH, factorW);
if (factor3 > Math.Max(factor1, factor2))
{
_SetLine(elements, splitEl21 + 1, splitEl22, 1);
_SetLine(elements, splitEl22 + 1, elements.Count - 1, 2);
return factor3;
}
if (factor2 > factor1)
{
_SetLine(elements, splitEl + 1, elements.Count - 1, 1);
return factor2;
}
return factor1;
}
/// <summary>
/// Returns the width of the elements with index from start to end of the list (inclusive) if they are put on 1 line
/// </summary>
/// <param name="list"></param>
/// <param name="start"></param>
/// <returns></returns>
private static float _GetWidth(List<CTextElement> list, int start)
{
return _GetWidth(list, start, list.Count - 1);
}
/// <summary>
/// Returns the width of the elements with index from start to end (inclusive) if they are put on 1 line
/// </summary>
/// <param name="list"></param>
/// <param name="start"></param>
/// <param name="end"></param>
/// <returns></returns>
private static float _GetWidth(List<CTextElement> list, int start, int end)
{
if (start < 0)
start = 0;
if (end >= list.Count)
end = list.Count - 1;
if (start > end)
return 0f;
float width = list.GetRange(start, end - start).Select(el => el.Width).Sum();
return width + list[end].WidthTrimmed;
}
private static void _SetLine(List<CTextElement> list, int start, int end, int line)
{
for (int i = start; i <= end; i++)
list[i].Line = line;
}
/// <summary>
/// Find the element after which to split the line
/// </summary>
/// <param name="elements">List with elements, width must be set</param>
/// <param name="requestedWidth">The requested line width</param>
/// <param name="singleSplit">Split on one point or two</param>
/// <param name="startElement">First element on line</param>
/// <returns>Index of element AFTER which to split</returns>
private static int _GetSplitElement(List<CTextElement> elements, float requestedWidth, bool singleSplit = true, int startElement = 0)
{
//Assert we have enough elements
Debug.Assert(singleSplit && elements.Count - startElement >= 2 || !singleSplit && elements.Count - startElement >= 3);
float curWidth = 0f;
int splitEl;
for (splitEl = startElement; splitEl < elements.Count; splitEl++)
{
curWidth += elements[splitEl].Width;
if (curWidth >= requestedWidth)
break;
}
// At this point we can either keep splitEl on this line for move it to the next line
// ==> line with splitEl is to long, without it is to short. so find the best option
// Check if line starts or ends with a long word, than put that on a single line
if (splitEl == startElement)
return splitEl;
// These 2 conditions also cover if the text fits on 1 line
if (!singleSplit && splitEl >= elements.Count - 2)
return elements.Count - 3; // Make sure we have 2 elements left if in multi split mode!
if (splitEl >= elements.Count - 1)
return elements.Count - 2; // Make sure we have 1 element left!
float diffWith = curWidth - requestedWidth;
float diffWithout = requestedWidth - (curWidth - elements[splitEl].Width);
if (!singleSplit)
{
// If we split in 3 lines, add the error of the next 2 lines to the current error for both cases
int splitEl2 = _GetSplitElement(elements, requestedWidth, true, splitEl + 1);
int splitEl3 = _GetSplitElement(elements, requestedWidth, true, splitEl);
diffWith += Math.Abs(requestedWidth - _GetWidth(elements, splitEl + 1, splitEl2)) + Math.Abs(requestedWidth - _GetWidth(elements, splitEl2 + 1));
diffWithout += Math.Abs(requestedWidth - _GetWidth(elements, splitEl, splitEl3)) + Math.Abs(requestedWidth - _GetWidth(elements, splitEl3 + 1));
}
float diff = diffWith - diffWithout;
//Differences below this value are considered acceptable
float equalDist = requestedWidth * 0.025f;
if (diff > equalDist)
return splitEl - 1; // width error with element is much higher than without -> put element on next line
if (diff < -equalDist)
return splitEl; // width error with element is much less than without -> keep element on line
//The real split would be somewhere in the middle of the element so we can move it to either line
string tmp = elements[splitEl].Text.TrimEnd(null);
char lastCharWith = tmp[tmp.Length - 1];
tmp = elements[splitEl - 1].Text.TrimEnd(null);
char lastCharWithout = tmp[tmp.Length - 1];
//Check if last chars are special chars
if (Char.IsLetterOrDigit(lastCharWith))
{
if (Char.IsLetterOrDigit(lastCharWithout))
return startElement == 0 ? splitEl : splitEl - 1; //Both are alphanumeric, favor longer first lines but shorter middle lines
return splitEl - 1; //Split after non-alphanumeric char
}
if (Char.IsLetterOrDigit(lastCharWithout))
return splitEl; //Split after non-alphanumeric char
int indexWith = Array.IndexOf(_SplitCharPreferences, lastCharWith);
int indexWithout = Array.IndexOf(_SplitCharPreferences, lastCharWithout);
if (indexWith <= indexWithout)
return startElement == 0 ? splitEl : splitEl - 1; //favor longer first lines but shorter middle lines
return splitEl - 1;
}
/// <summary>
/// Split the text in parts that can then be distributet among the lines
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
private static IEnumerable<string> _SplitText(string text)
{
Debug.Assert(!String.IsNullOrWhiteSpace(text));
text = text.Trim().TrimMultipleWs();
List<string> lines = new List<string>();
if (text.Length == 1)
{
lines.Add(text);
return lines;
}
//Split the text on non-letter chars
int curStart = 0;
for (int i = 1; i < text.Length - 1; i++)
{
if ((Array.IndexOf(_SplitCharAfter, text[i]) >= 0 && (Char.IsLetterOrDigit(text, i + 1) || Array.IndexOf(_SplitCharBefore, text[i + 1]) >= 0)) ||
(Char.IsLetterOrDigit(text, i) && Array.IndexOf(_SplitCharBefore, text[i + 1]) >= 0))
{
lines.Add(text.Substring(curStart, i - curStart + 1));
curStart = ++i;
}
}
//Add the rest
lines.Add(text.Substring(curStart));
//Check for initials (like J. R.R. Tolkien) and join them
curStart = -1;
string curText = "";
for (int i = 0; i < lines.Count; i++)
{
string part = lines[i].Trim();
if (part.Length == 2 && part[1] == '.')
{
//Initials found, continue or start new
if (curStart < 0)
curStart = i;
curText += lines[i];
}
else if (curStart >= 0)
{
//Initials end
if (curStart < i - 1)
{
//More than 1 part
lines[curStart] = curText;
lines.RemoveRange(curStart + 1, i - curStart - 1);
i = curStart;
}
curText = "";
curStart = -1;
}
}
//Handle last part
if (curStart >= 0)
{
//Initials end
if (curStart < lines.Count - 1)
{
//More than 1 part
lines[curStart] = curText;
lines.RemoveRange(curStart + 1, lines.Count - curStart - 1);
}
}
// Remove single char lines
for (int i = 0; i < lines.Count; i++)
{
string part = lines[i];
if (part.Trim().Length == 1)
{
lines.RemoveAt(i);
if (i == 0)
lines[0] = part + lines[0];
else
{
lines[i - 1] += part;
i--;
}
}
}
return lines;
}
}
}
+1 -1
View File
@@ -23,6 +23,7 @@ using System.Reflection;
using VocaluxeLib;
using VocaluxeLib.Menu;
using VocaluxeLib.PartyModes;
using VocaluxeLib.Xml;
namespace Vocaluxe.Base
{
@@ -99,7 +100,6 @@ namespace Vocaluxe.Base
pair.Value.PartyMode.SaveScreens();
}
public static List<SPartyModeInfos> GetPartyModeInfos()
{
var infos = new List<SPartyModeInfos>();
+1 -1
View File
@@ -3,9 +3,9 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Xml;
using Vocaluxe.Lib.Video;
using VocaluxeLib;
using VocaluxeLib.Draw;
using VocaluxeLib.Xml;
namespace Vocaluxe.Base
{
+4
View File
@@ -178,7 +178,11 @@ namespace Vocaluxe.Base
}
foreach (CCategory cat in _Categories)
{
cat.CoverTextureSmall = CCover.Cover(cat.Name);
if (cat.CoverTextureSmall == CCover.NoCover)
cat.CoverTextureSmall = CCover.GenerateCover(cat.Name, CSongs.Sorter.SongSorting, cat);
}
_Changed = false;
}
}
+1
View File
@@ -24,6 +24,7 @@ using Vocaluxe.Base.Fonts;
using Vocaluxe.Lib.Video;
using VocaluxeLib;
using VocaluxeLib.Draw;
using VocaluxeLib.Xml;
namespace Vocaluxe.Base
{
@@ -24,48 +24,64 @@ using VocaluxeLib.Draw;
namespace Vocaluxe.Base.Fonts
{
class CFont : IDisposable
class CFontStyle : IDisposable
{
private readonly Dictionary<char, CGlyph> _Glyphs;
private readonly string _FilePath;
private readonly EStyle _Style;
public readonly float Outline; //0..1, 0=not outline 1=100% outline
public readonly SColorF OutlineColor;
private readonly float _MaxGlyphHeight;
private readonly Dictionary<char, CGlyph> _Glyphs = new Dictionary<char, CGlyph>();
private PrivateFontCollection _Fonts;
private FontFamily _Family;
private readonly float _MaxGlyphHeight;
private readonly string _FilePath;
private bool _Disposed;
public CFont(string file)
public CFontStyle(string file, EStyle style, float outline, SColorF outlineColor)
{
_FilePath = file;
_Glyphs = new Dictionary<char, CGlyph>();
_Style = style;
Outline = outline;
OutlineColor = outlineColor;
switch (CConfig.TextureQuality)
{
case ETextureQuality.TR_CONFIG_TEXTURE_LOWEST:
_MaxGlyphHeight = 25f;
_MaxGlyphHeight = 20f;
break;
case ETextureQuality.TR_CONFIG_TEXTURE_LOW:
_MaxGlyphHeight = 50f;
_MaxGlyphHeight = 40f;
break;
case ETextureQuality.TR_CONFIG_TEXTURE_MEDIUM:
_MaxGlyphHeight = 100f;
_MaxGlyphHeight = 60f;
break;
case ETextureQuality.TR_CONFIG_TEXTURE_HIGH:
_MaxGlyphHeight = 200f;
_MaxGlyphHeight = 80f;
break;
case ETextureQuality.TR_CONFIG_TEXTURE_HIGHEST:
_MaxGlyphHeight = 400f;
break;
default:
_MaxGlyphHeight = 100f;
break;
default:
_MaxGlyphHeight = 60f;
break;
}
_MaxGlyphHeight = 50;
}
public Font GetFont()
private FontStyle _GetSystemFontStyle()
{
switch (_Style)
{
case EStyle.Normal:
return FontStyle.Regular;
case EStyle.Italic:
return FontStyle.Italic;
case EStyle.Bold:
return FontStyle.Bold;
case EStyle.BoldItalic:
return FontStyle.Bold | FontStyle.Italic;
}
throw new ArgumentException("Invalid style: " + _Style);
}
public Font GetSystemFont(float height)
{
if (_Fonts == null)
{
@@ -80,100 +96,83 @@ namespace Vocaluxe.Base.Fonts
CLog.LogError("Error opening font file " + _FilePath + ": " + e.Message);
}
}
return new Font(_Family, CFonts.Height, CFonts.GetFontStyle(), GraphicsUnit.Pixel);
return new Font(_Family, height, _GetSystemFontStyle(), GraphicsUnit.Pixel);
}
public void DrawGlyph(char chr, float x, float y, float z, SColorF color)
public void DrawGlyph(char chr, float fontHeight, float x, float y, float z, SColorF color)
{
CTextureRef texture;
SRectF rect;
GetOrAddGlyph(chr).GetTextureAndRect(x, y, z, out texture, out rect);
GetOrAddGlyph(chr, fontHeight).GetTextureAndRect(fontHeight, x, y, z, out texture, out rect);
CDraw.DrawTexture(texture, rect, color);
}
public void DrawGlyph(char chr, float x, float y, float z, SColorF color, float begin, float end)
public void DrawGlyph(char chr, float fontHeight, float x, float y, float z, SColorF color, float begin, float end)
{
CTextureRef texture;
SRectF rect;
GetOrAddGlyph(chr).GetTextureAndRect(x, y, z, out texture, out rect);
GetOrAddGlyph(chr, fontHeight).GetTextureAndRect(fontHeight, x, y, z, out texture, out rect);
CDraw.DrawTexture(texture, rect, color, begin, end);
}
public void DrawGlyphReflection(char chr, float x, float y, float z, SColorF color, float rspace, float rheight)
public void DrawGlyphReflection(char chr, float fontHeight, float x, float y, float z, SColorF color, float rspace, float rheight)
{
CTextureRef texture;
SRectF rect;
GetOrAddGlyph(chr).GetTextureAndRect(x, y, z, out texture, out rect);
GetOrAddGlyph(chr, fontHeight).GetTextureAndRect(fontHeight, x, y, z, out texture, out rect);
CDraw.DrawTextureReflection(texture, rect, color, rect, rspace, rheight);
}
public float GetWidth(char chr)
public float GetWidth(char chr, float height)
{
return GetOrAddGlyph(chr).Width;
return GetOrAddGlyph(chr, height).GetWidth(height);
}
public float GetHeight(char chr)
public float GetHeight(char chr, float height)
{
return GetOrAddGlyph(chr).Height;
return GetOrAddGlyph(chr, height).GetHeight(height);
}
public CGlyph GetOrAddGlyph(char chr)
public CGlyph GetOrAddGlyph(char chr, float height)
{
CGlyph glyph;
if (!_Glyphs.TryGetValue(chr, out glyph))
{
glyph = new CGlyph(chr, _MaxGlyphHeight);
float maxHeight = (height < 0 || _MaxGlyphHeight + 50 >= height) ? _MaxGlyphHeight : (float)Math.Round(height / 50) * 50;
glyph = new CGlyph(chr, this, maxHeight);
_Glyphs.Add(chr, glyph);
}
if (glyph.MaxHeight + 50 < CFonts.Height)
if (glyph.MaxHeight + 50 < height)
{
glyph.UnloadTexture();
glyph = new CGlyph(chr, (float)Math.Round(CFonts.Height / 50) * 50);
glyph = new CGlyph(chr, this, (float)Math.Round(height / 50) * 50);
_Glyphs[chr] = glyph;
}
return glyph;
}
public void UnloadGlyphs()
private void _UnloadGlyphs()
{
foreach (CGlyph glyph in _Glyphs.Values)
glyph.UnloadTexture();
_Glyphs.Clear();
}
private bool _Disposed;
public void Dispose()
{
if (!_Disposed)
{
if (_Fonts != null)
{
_Fonts.Dispose();
UnloadGlyphs();
_Fonts = null;
}
_UnloadGlyphs();
_Disposed = true;
}
GC.SuppressFinalize(this);
}
}
struct SFont
{
public string Name;
public bool IsThemeFont;
public int PartyModeID;
public string ThemeName;
public string Folder;
public string FileNormal;
public string FileItalic;
public string FileBold;
public string FileBoldItalic;
public float Outline; //0..1, 0=not outline 1=100% outline
public SColorF OutlineColor;
public CFont Normal;
public CFont Italic;
public CFont Bold;
public CFont BoldItalic;
}
}
+259 -321
View File
@@ -15,216 +15,166 @@
// along with Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
#endregion
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Xml;
using VocaluxeLib;
using VocaluxeLib.Menu;
using VocaluxeLib.Xml;
namespace Vocaluxe.Base.Fonts
{
/// <summary>
/// Struct used for describing a font family (a type of text with 4 different styles)
/// </summary>
struct SFontFamily
{
public string Name;
public int PartyModeID;
public string ThemeName;
public string Folder;
public string FileNormal;
public string FileItalic;
public string FileBold;
public string FileBoldItalic;
public float Outline; //0..1, 0=not outline 1=100% outline
public SColorF OutlineColor;
public CFontStyle Normal;
public CFontStyle Italic;
public CFontStyle Bold;
public CFontStyle BoldItalic;
public void Dispose()
{
Normal.Dispose();
Italic.Dispose();
Bold.Dispose();
BoldItalic.Dispose();
}
}
static class CFonts
{
private static readonly List<SFont> _Fonts = new List<SFont>();
private static int _CurrentFont;
private static float _Height = 1f;
private static bool _IsInitialized;
private static readonly List<SFontFamily> _FontFamilies = new List<SFontFamily>();
private static readonly List<String> _LoggedMissingFonts = new List<string>();
// ReSharper disable MemberCanBePrivate.Global
public static int PartyModeID { get; set; }
// ReSharper restore MemberCanBePrivate.Global
public static EStyle Style = EStyle.Normal;
public static float Height
public static bool Init()
{
get { return _Height; }
set { _Height = value < 0f ? 0f : value; }
}
public static float Outline
{
get { return _Fonts[_CurrentFont].Outline; }
}
public static SColorF OutlineColor
{
get { return _Fonts[_CurrentFont].OutlineColor; }
}
public static void Init()
{
_CurrentFont = 0;
if (_IsInitialized)
return false;
PartyModeID = -1;
_BuildFonts();
return _LoadDefaultFonts();
}
private static void _BuildFonts()
public static void Close()
{
foreach (SFont font in _Fonts)
{
font.Normal.Dispose();
font.Bold.Dispose();
font.Italic.Dispose();
font.BoldItalic.Dispose();
}
_Fonts.Clear();
_CurrentFont = 0;
_LoadFontList();
}
public static Font GetFont()
{
return _GetCurrentFont().GetFont();
}
private static CFont _GetCurrentFont()
{
switch (Style)
{
case EStyle.Normal:
return _Fonts[_CurrentFont].Normal;
case EStyle.Italic:
return _Fonts[_CurrentFont].Italic;
case EStyle.Bold:
return _Fonts[_CurrentFont].Bold;
case EStyle.BoldItalic:
return _Fonts[_CurrentFont].BoldItalic;
}
//Just in case...
return _Fonts[_CurrentFont].Normal;
foreach (SFontFamily font in _FontFamilies)
font.Dispose();
_FontFamilies.Clear();
_IsInitialized = false;
}
#region DrawText
public static void DrawText(string text, int x, int y, int h)
/// <summary>
/// Draws a black text
/// </summary>
/// <param name="text">The text to be drawn</param>
/// <param name="font">The texts font</param>
/// <param name="x">The texts x-position</param>
/// <param name="y">The texts y-position</param>
/// <param name="z">The texts z-position</param>
public static void DrawText(string text, CFont font, float x, float y, float z)
{
DrawText(text, h, x, y, 0f, new SColorF(0f, 0f, 0f, 1f));
}
public static void DrawText(string text, float x, float y, float z)
{
DrawText(text, Height, x, y, z, new SColorF(0f, 0f, 0f, 1f));
DrawText(text, font, x, y, z, new SColorF(0f, 0f, 0f, 1f));
}
/// <summary>
/// Draws a text string
/// Draws a text
/// </summary>
/// <param name="text">The text to be drawn</param>
/// <param name="x">The text's x-position</param>
/// <param name="y">The text's y-position</param>
/// <param name="h">The text's height</param>
/// <param name="z">The text's z-position</param>
/// <param name="font">The texts font</param>
/// <param name="x">The texts x-position</param>
/// <param name="y">The texts y-position</param>
/// <param name="z">The texts z-position</param>
/// <param name="color">The text color</param>
public static void DrawText(string text, float h, float x, float y, float z, SColorF color)
public static void DrawText(string text, CFont font, float x, float y, float z, SColorF color)
{
if (h <= 0f)
if (font.Height <= 0f || text == "")
return;
if (text == "")
return;
Height = h;
CFont font = _GetCurrentFont();
CFontStyle fontStyle = _GetFontStyle(font);
float dx = x;
foreach (char chr in text)
{
font.DrawGlyph(chr, dx, y, z, color);
dx += font.GetWidth(chr);
fontStyle.DrawGlyph(chr, font.Height, dx, y, z, color);
dx += fontStyle.GetWidth(chr, font.Height);
}
}
public static void DrawTextReflection(string text, float h, float x, float y, float z, SColorF color, float rspace, float rheight)
public static void DrawTextReflection(string text, CFont font, float x, float y, float z, SColorF color, float rspace, float rheight)
{
if (h <= 0f)
if (font.Height <= 0f || text == "")
return;
if (text == "")
return;
Height = h;
CFont font = _GetCurrentFont();
CFontStyle fontStyle = _GetFontStyle(font);
float dx = x;
foreach (char chr in text)
{
font.DrawGlyphReflection(chr, dx, y, z, color, rspace, rheight);
dx += font.GetWidth(chr);
fontStyle.DrawGlyphReflection(chr, font.Height, dx, y, z, color, rspace, rheight);
dx += fontStyle.GetWidth(chr, font.Height);
}
}
public static void DrawText(string text, float h, float x, float y, float z, SColorF color, float begin, float end)
public static void DrawText(string text, CFont font, float x, float y, float z, SColorF color, float begin, float end)
{
if (h <= 0f)
if (font.Height <= 0f || text == "")
return;
if (text == "")
return;
Height = h;
float dx = x;
float w = GetTextWidth(text);
float w = GetTextWidth(text, font);
if (w <= 0f)
return;
float x1 = x + w * begin;
float x2 = x + w * end;
float xStart = x + w * begin;
float xEnd = x + w * end;
float xCur = x;
CFont font = _GetCurrentFont();
CFontStyle fontStyle = _GetFontStyle(font);
foreach (char chr in text)
{
float w2 = font.GetWidth(chr);
float b = (x1 - dx) / w2;
float w2 = fontStyle.GetWidth(chr, font.Height);
float b = (xStart - xCur) / w2;
if (b < 1f)
{
if (b < 0f)
b = 0f;
float e = (x2 - dx) / w2;
float e = (xEnd - xCur) / w2;
if (e > 0f)
{
if (e > 1f)
e = 1f;
font.DrawGlyph(chr, dx, y, z, color, b, e);
fontStyle.DrawGlyph(chr, font.Height, xCur, y, z, color, b, e);
}
}
dx += w2;
xCur += w2;
}
}
#endregion DrawText
public static FontStyle GetFontStyle()
{
switch (Style)
{
case EStyle.Normal:
return FontStyle.Regular;
case EStyle.Italic:
return FontStyle.Italic;
case EStyle.Bold:
return FontStyle.Bold;
case EStyle.BoldItalic:
return FontStyle.Bold | FontStyle.Italic;
default:
return FontStyle.Regular;
}
}
public static void SetFont(string fontName)
{
int index = _GetPartyFontIndex(PartyModeID, fontName);
if (index < 0)
index = _GetThemeFontIndex(CConfig.Theme, fontName);
if (index < 0)
index = _GetFontIndex(fontName);
if (index >= 0)
_CurrentFont = index;
}
/// <summary>
/// Calculates the bounds for a CText object
/// </summary>
@@ -232,94 +182,172 @@ namespace Vocaluxe.Base.Fonts
/// <returns>RectangleF object containing the bounds</returns>
public static RectangleF GetTextBounds(CText text)
{
return GetTextBounds(text, text.Height);
return new RectangleF(text.X, text.Y, GetTextWidth(text.TranslatedText, text.Font), GetTextHeight(text.TranslatedText, text.Font));
}
public static Font GetSystemFont(CFont font)
{
return _GetFontStyle(font).GetSystemFont(font.Height);
}
public static float GetOutlineSize(CFont font)
{
return _FontFamilies[_GetFontIndex(font.Name)].Outline;
}
public static SColorF GetOutlineColor(CFont font)
{
return _FontFamilies[_GetFontIndex(font.Name)].OutlineColor;
}
private static CFontStyle _GetFontStyle(CFont font)
{
int index = _GetFontIndex(font.Name);
switch (font.Style)
{
case EStyle.Normal:
return _FontFamilies[index].Normal;
case EStyle.Italic:
return _FontFamilies[index].Italic;
case EStyle.Bold:
return _FontFamilies[index].Bold;
case EStyle.BoldItalic:
return _FontFamilies[index].BoldItalic;
}
throw new ArgumentException("Invalid Style: " + font.Style);
}
public static float GetTextWidth(string text, CFont font)
{
CFontStyle fontStyle = _GetFontStyle(font);
return text.Sum(chr => fontStyle.GetWidth(chr, font.Height));
}
public static float GetTextHeight(string text, CFont font)
{
CFontStyle fontStyle = _GetFontStyle(font);
return text == "" ? 0 : text.Select(chr => fontStyle.GetHeight(chr, font.Height)).Max();
}
private static int _GetFontIndex(string fontName)
{
if (fontName != "")
{
int index = _GetPartyFontIndex(fontName, PartyModeID);
if (index < 0)
index = _GetThemeFontIndex(fontName, CConfig.Theme);
if (index >= 0)
return index;
for (int i = 0; i < _FontFamilies.Count; i++)
{
if (_FontFamilies[i].Name == fontName)
return i;
}
if (!_LoggedMissingFonts.Contains(fontName))
{
_LoggedMissingFonts.Add(fontName);
CLog.LogError("Font \"" + fontName + "\" not found!");
}
}
else
CLog.LogError("Empty fontName requested", false, false, new Exception());
if (_FontFamilies.Count == 0)
CLog.LogError("No fonts found!", true, true);
return 0;
}
private static int _GetThemeFontIndex(string fontName, string themeName)
{
Debug.Assert(fontName != "" && themeName != "");
for (int i = 0; i < _FontFamilies.Count; i++)
{
if (_FontFamilies[i].Name == fontName && _FontFamilies[i].ThemeName == themeName)
return i;
}
return -1;
}
private static int _GetPartyFontIndex(string fontName, int partyModeID)
{
Debug.Assert(fontName != "");
for (int i = 0; i < _FontFamilies.Count; i++)
{
if (_FontFamilies[i].PartyModeID == partyModeID && _FontFamilies[i].Name == fontName)
return i;
}
return -1;
}
/// <summary>
/// Calculates the bounds for a CText object
/// Load default fonts
/// </summary>
/// <param name="text">The CText object of which the bounds should be calculated for</param>
/// <param name="height">The height of the CText object</param>
/// <returns>RectangleF object containing the bounds</returns>
public static RectangleF GetTextBounds(CText text, float height)
/// <returns></returns>
private static bool _LoadDefaultFonts()
{
float oldHeight = Height;
int oldFont = _CurrentFont;
EStyle oldStyle = Style;
Height = height;
SetFont(text.Font);
Style = text.Style;
var result = new RectangleF(text.X, text.Y, GetTextWidth(CLanguage.Translate(text.Text, text.TranslationID)),
GetTextHeight(CLanguage.Translate(text.Text, text.TranslationID)));
//restore old values
Height = oldHeight;
_CurrentFont = oldFont;
Style = oldStyle;
return result;
CXMLReader xmlReader = CXMLReader.OpenFile(Path.Combine(CSettings.ProgramFolder, CSettings.FolderNameFonts, CSettings.FileNameFonts));
if (xmlReader == null)
return false;
return _LoadFontFile(xmlReader, Path.Combine(CSettings.ProgramFolder, CSettings.FolderNameFonts));
}
public static float GetTextWidth(string text)
/// <summary>
/// Loads theme fonts from skin file
/// </summary>
public static bool LoadThemeFonts(string themeName, string fontFolder, CXMLReader xmlReader)
{
CFont font = _GetCurrentFont();
return text.Sum(chr => font.GetWidth(chr));
bool ok = _LoadFontFile(xmlReader, fontFolder, themeName);
CLog.StartBenchmark("BuildGlyphs");
_BuildGlyphs();
CLog.StopBenchmark("BuildGlyphs");
return ok;
}
public static float GetTextHeight(string text)
/// <summary>
/// Loads party mode fonts from skin file
/// </summary>
public static bool LoadPartyModeFonts(int partyModeID, string fontFolder, CXMLReader xmlReader)
{
//return TextRenderer.MeasureText(text, GetFont()).Height;
CFont font = _GetCurrentFont();
return text == "" ? 0 : text.Select(font.GetHeight).Max();
bool ok = _LoadFontFile(xmlReader, fontFolder, "", partyModeID);
CLog.StartBenchmark("BuildGlyphs");
_BuildGlyphs();
CLog.StopBenchmark("BuildGlyphs");
return ok;
}
private static void _LoadFontFiles(CXMLReader xmlReader, string fontFolder, string themeName = "", int partyModeId = -1)
private static bool _LoadFontFile(CXMLReader xmlReader, string fontFolder, string themeName = "", int partyModeId = -1)
{
string value = string.Empty;
string value;
int i = 1;
while (xmlReader.GetValue("//root/Fonts/Font" + i + "/Folder", out value, value))
while (xmlReader.GetValue("//root/Fonts/Font" + i + "/Folder", out value))
{
var sf = new SFont {Folder = value, IsThemeFont = themeName != "", ThemeName = themeName, PartyModeID = partyModeId};
var sf = new SFontFamily {Folder = value, ThemeName = themeName, PartyModeID = partyModeId};
bool ok = true;
string name;
ok &= xmlReader.GetValue("//root/Fonts/Font" + i + "/Name", out name, value);
sf.Name = name;
ok &= xmlReader.GetValue("//root/Fonts/Font" + i + "/FileNormal", out value, value);
sf.FileNormal = value;
value = Path.Combine(fontFolder, Path.Combine(sf.Folder, value));
var f = new CFont(value);
sf.Normal = f;
ok &= xmlReader.GetValue("//root/Fonts/Font" + i + "/FileItalic", out value, value);
sf.FileItalic = value;
value = Path.Combine(fontFolder, Path.Combine(sf.Folder, value));
f = new CFont(value);
sf.Italic = f;
ok &= xmlReader.GetValue("//root/Fonts/Font" + i + "/FileBold", out value, value);
sf.FileBold = value;
value = Path.Combine(fontFolder, Path.Combine(sf.Folder, value));
f = new CFont(value);
sf.Bold = f;
ok &= xmlReader.GetValue("//root/Fonts/Font" + i + "/FileBoldItalic", out value, value);
sf.FileBoldItalic = value;
value = Path.Combine(fontFolder, Path.Combine(sf.Folder, value));
f = new CFont(value);
sf.BoldItalic = f;
sf.Outline = 0f;
ok &= xmlReader.TryGetFloatValue("//root/Fonts/Font" + i + "/Outline", ref sf.Outline);
sf.OutlineColor = new SColorF(0f, 0f, 0f, 1f);
ok &= xmlReader.TryGetFloatValue("//root/Fonts/Font" + i + "/OutlineColorR", ref sf.OutlineColor.R);
ok &= xmlReader.TryGetFloatValue("//root/Fonts/Font" + i + "/OutlineColorG", ref sf.OutlineColor.G);
ok &= xmlReader.TryGetFloatValue("//root/Fonts/Font" + i + "/OutlineColorB", ref sf.OutlineColor.B);
ok &= xmlReader.TryGetFloatValue("//root/Fonts/Font" + i + "/OutlineColorA", ref sf.OutlineColor.A);
ok &= xmlReader.GetValue("//root/Fonts/Font" + i + "/Name", out sf.Name);
ok &= xmlReader.GetValue("//root/Fonts/Font" + i + "/FileNormal", out sf.FileNormal);
ok &= xmlReader.GetValue("//root/Fonts/Font" + i + "/FileItalic", out sf.FileItalic);
ok &= xmlReader.GetValue("//root/Fonts/Font" + i + "/FileBold", out sf.FileBold);
ok &= xmlReader.GetValue("//root/Fonts/Font" + i + "/FileBoldItalic", out sf.FileBoldItalic);
ok &= xmlReader.TryGetNormalizedFloatValue("//root/Fonts/Font" + i + "/Outline", ref sf.Outline);
ok &= xmlReader.TryGetColorFromRGBA("//root/Fonts/Font" + i + "/OutlineColor", out sf.OutlineColor);
if (ok)
_Fonts.Add(sf);
{
sf.Normal = new CFontStyle(Path.Combine(fontFolder, sf.Folder, sf.FileNormal), EStyle.Normal, sf.Outline, sf.OutlineColor);
sf.Italic = new CFontStyle(Path.Combine(fontFolder, sf.Folder, sf.FileItalic), EStyle.Italic, sf.Outline, sf.OutlineColor);
sf.Bold = new CFontStyle(Path.Combine(fontFolder, sf.Folder, sf.FileBold), EStyle.Bold, sf.Outline, sf.OutlineColor);
sf.BoldItalic = new CFontStyle(Path.Combine(fontFolder, sf.Folder, sf.FileBoldItalic), EStyle.BoldItalic, sf.Outline, sf.OutlineColor);
_FontFamilies.Add(sf);
}
else
{
string fontTypes;
@@ -330,170 +358,80 @@ namespace Vocaluxe.Base.Fonts
else
fontTypes = "basic fonts";
CLog.LogError("Error loading " + fontTypes + ": Error in Font" + i);
return false;
}
i++;
}
}
/// <summary>
/// Load default fonts
/// </summary>
/// <returns></returns>
private static void _LoadFontList()
{
CXMLReader xmlReader = CXMLReader.OpenFile(Path.Combine(CSettings.ProgramFolder, CSettings.FolderNameFonts, CSettings.FileNameFonts));
if (xmlReader == null)
return;
_LoadFontFiles(xmlReader, Path.Combine(CSettings.ProgramFolder, CSettings.FolderNameFonts));
}
/// <summary>
/// Loads theme fonts from skin file
/// </summary>
public static void LoadThemeFonts(string themeName, string fontFolder, CXMLReader xmlReader)
{
_LoadFontFiles(xmlReader, fontFolder, themeName);
CLog.StartBenchmark("BuildGlyphs");
_BuildGlyphs();
CLog.StopBenchmark("BuildGlyphs");
}
/// <summary>
/// Loads party mode fonts from skin file
/// </summary>
public static void LoadPartyModeFonts(int partyModeID, string fontFolder, CXMLReader xmlReader)
{
_LoadFontFiles(xmlReader, fontFolder, "", partyModeID);
CLog.StartBenchmark("BuildGlyphs");
_BuildGlyphs();
CLog.StopBenchmark("BuildGlyphs");
return true;
}
public static void SaveThemeFonts(string themeName, XmlWriter writer)
{
if (_Fonts.Count == 0)
if (_FontFamilies.Count == 0)
return;
int index = 0;
writer.WriteStartElement("Fonts");
int fontNr = 1;
bool setStart = false;
while (index < _Fonts.Count)
foreach (SFontFamily font in _FontFamilies)
{
if (_Fonts[index].IsThemeFont && _Fonts[index].ThemeName == themeName)
if (font.ThemeName == themeName)
{
if (!setStart)
{
writer.WriteStartElement("Fonts");
setStart = true;
}
writer.WriteStartElement("Font" + fontNr);
writer.WriteElementString("Name", _Fonts[index].Name);
writer.WriteElementString("Folder", _Fonts[index].Folder);
writer.WriteElementString("Name", font.Name);
writer.WriteElementString("Folder", font.Folder);
writer.WriteElementString("Outline", _Fonts[index].Outline.ToString("#0.00"));
writer.WriteElementString("OutlineColorR", _Fonts[index].OutlineColor.R.ToString("#0.00"));
writer.WriteElementString("OutlineColorG", _Fonts[index].OutlineColor.G.ToString("#0.00"));
writer.WriteElementString("OutlineColorB", _Fonts[index].OutlineColor.B.ToString("#0.00"));
writer.WriteElementString("OutlineColorA", _Fonts[index].OutlineColor.A.ToString("#0.00"));
writer.WriteElementString("Outline", font.Outline.ToString("#0.00"));
writer.WriteStartElement("OutlineColor");
writer.WriteElementString("R", font.OutlineColor.R.ToString("#0.00"));
writer.WriteElementString("G", font.OutlineColor.G.ToString("#0.00"));
writer.WriteElementString("B", font.OutlineColor.B.ToString("#0.00"));
writer.WriteElementString("A", font.OutlineColor.A.ToString("#0.00"));
writer.WriteEndElement();
writer.WriteElementString("FileNormal", _Fonts[index].FileNormal);
writer.WriteElementString("FileBold", _Fonts[index].FileBold);
writer.WriteElementString("FileItalic", _Fonts[index].FileItalic);
writer.WriteElementString("FileBoldItalic", _Fonts[index].FileBoldItalic);
writer.WriteElementString("FileNormal", font.FileNormal);
writer.WriteElementString("FileBold", font.FileBold);
writer.WriteElementString("FileItalic", font.FileItalic);
writer.WriteElementString("FileBoldItalic", font.FileBoldItalic);
writer.WriteEndElement();
fontNr++;
}
index++;
}
if (setStart)
writer.WriteEndElement();
writer.WriteEndElement();
}
public static void UnloadThemeFonts(string themeName)
{
int index = 0;
while (index < _Fonts.Count)
while (index < _FontFamilies.Count)
{
if (_Fonts[index].IsThemeFont && _Fonts[index].ThemeName == themeName)
if (_FontFamilies[index].ThemeName == themeName)
{
_Fonts[index].Normal.UnloadGlyphs();
_Fonts[index].Italic.UnloadGlyphs();
_Fonts[index].Bold.UnloadGlyphs();
_Fonts[index].BoldItalic.UnloadGlyphs();
_Fonts.RemoveAt(index);
_FontFamilies[index].Dispose();
_FontFamilies.RemoveAt(index);
}
else
index++;
}
}
private static int _GetFontIndex(string fontName)
{
for (int i = 0; i < _Fonts.Count; i++)
{
if (!_Fonts[i].IsThemeFont && _Fonts[i].Name == fontName)
return i;
}
return -1;
}
private static int _GetThemeFontIndex(string themeName, string fontName)
{
if (themeName == "" || fontName == "")
return -1;
for (int i = 0; i < _Fonts.Count; i++)
{
if (_Fonts[i].IsThemeFont && _Fonts[i].Name == fontName && _Fonts[i].ThemeName == themeName)
return i;
}
return -1;
}
private static int _GetPartyFontIndex(int partyModeID, string fontName)
{
if (partyModeID == -1 || fontName == "")
return -1;
for (int i = 0; i < _Fonts.Count; i++)
{
if (!_Fonts[i].IsThemeFont && _Fonts[i].PartyModeID == partyModeID && _Fonts[i].Name == fontName)
return i;
}
return -1;
}
private static void _BuildGlyphs()
{
const string text = " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
for (int i = 0; i < _Fonts.Count; i++)
foreach (SFontFamily fontFamily in _FontFamilies)
{
_CurrentFont = i;
foreach (char chr in text)
{
Style = EStyle.Normal;
_Fonts[_CurrentFont].Normal.GetOrAddGlyph(chr);
Style = EStyle.Bold;
_Fonts[_CurrentFont].Bold.GetOrAddGlyph(chr);
Style = EStyle.Italic;
_Fonts[_CurrentFont].Italic.GetOrAddGlyph(chr);
Style = EStyle.BoldItalic;
_Fonts[_CurrentFont].BoldItalic.GetOrAddGlyph(chr);
fontFamily.Normal.GetOrAddGlyph(chr, -1);
fontFamily.Bold.GetOrAddGlyph(chr, -1);
fontFamily.Italic.GetOrAddGlyph(chr, -1);
fontFamily.BoldItalic.GetOrAddGlyph(chr, -1);
}
}
Style = EStyle.Normal;
SetFont("Normal");
}
}
}
+19 -23
View File
@@ -36,26 +36,13 @@ namespace Vocaluxe.Base.Fonts
private readonly RectangleF _DrawBounding;
public readonly float MaxHeight;
public float Width
{
get { return _BoundingBox.Width * _GetFactor(); }
}
public float Height
{
get { return _BoundingBox.Height * _GetFactor(); }
}
public CGlyph(char chr, float maxHeight)
public CGlyph(char chr, CFontStyle fontStyle, float maxHeight)
{
MaxHeight = maxHeight;
float oldHeight = CFonts.Height;
float outline = CFonts.Outline;
float outlineSize = outline * maxHeight;
float outlineSize = fontStyle.Outline * maxHeight;
string chrString = chr.ToString();
CFonts.Height = maxHeight;
Font fo = CFonts.GetFont();
Font fo = fontStyle.GetSystemFont(maxHeight);
SizeF fullSize;
Size bmpSize;
using (Graphics g = Graphics.FromHwnd(IntPtr.Zero))
@@ -64,7 +51,7 @@ namespace Vocaluxe.Base.Fonts
if (chr != ' ')
{
//Gets exact height and width for drawing more than 1 char. But width is to small to draw char on bitmap as e.g. italic chars will get cropped
_BoundingBox = g.MeasureString(chrString, fo, -1, new StringFormat(StringFormat.GenericTypographic));
_BoundingBox = g.MeasureString(chrString, fo, -1, StringFormat.GenericTypographic);
// ReSharper disable CompareOfFloatsByEqualityOperator
if (_BoundingBox.Height == 0)
// ReSharper restore CompareOfFloatsByEqualityOperator
@@ -105,7 +92,7 @@ namespace Vocaluxe.Base.Fonts
float emSize = fo.Size * fo.FontFamily.GetCellAscent(fo.Style) / fo.FontFamily.GetEmHeight(fo.Style);
path.AddString(chrString, fo.FontFamily, (int)fo.Style, emSize, point, new StringFormat());
using (var pen = new Pen(CFonts.OutlineColor.AsColor(), outlineSize))
using (var pen = new Pen(fontStyle.OutlineColor.AsColor(), outlineSize))
{
pen.LineJoin = LineJoin.Round;
g.DrawPath(pen, path);
@@ -134,7 +121,6 @@ namespace Vocaluxe.Base.Fonts
}
}
}
CFonts.Height = oldHeight;
}
public void UnloadTexture()
@@ -142,15 +128,25 @@ namespace Vocaluxe.Base.Fonts
CDraw.RemoveTexture(ref _Texture);
}
private float _GetFactor()
private float _GetFactor(float fontHeight)
{
return CFonts.Height / _BoundingBox.Height;
return fontHeight / _BoundingBox.Height;
}
public void GetTextureAndRect(float x, float y, float z, out CTextureRef texture, out SRectF rect)
public float GetWidth(float fontHeight)
{
return _BoundingBox.Width * _GetFactor(fontHeight);
}
public float GetHeight(float fontHeight)
{
return _BoundingBox.Height * _GetFactor(fontHeight);
}
public void GetTextureAndRect(float fontHeight, float x, float y, float z, out CTextureRef texture, out SRectF rect)
{
texture = _Texture;
float factor = _GetFactor();
float factor = _GetFactor(fontHeight);
x += _DrawBounding.X * factor;
y += _DrawBounding.Y * factor;
float h = _DrawBounding.Height * factor;
+1
View File
@@ -24,6 +24,7 @@ using Vocaluxe.Base;
using VocaluxeLib;
using VocaluxeLib.Menu;
using VocaluxeLib.Songs;
using VocaluxeLib.Xml;
namespace Vocaluxe.Lib.Playlist
{
+13 -11
View File
@@ -173,17 +173,11 @@ namespace Vocaluxe
Application.DoEvents();
// Init Font
CLog.StartBenchmark("Init Font");
CFonts.Init();
CLog.StopBenchmark("Init Font");
Application.DoEvents();
// Load Cover
CLog.StartBenchmark("Init Cover");
CCover.Init();
CLog.StopBenchmark("Init Cover");
// Init Fonts
CLog.StartBenchmark("Init Fonts");
if (!CFonts.Init())
throw new CLoadingException("fonts");
CLog.StopBenchmark("Init Fonts");
Application.DoEvents();
@@ -195,6 +189,13 @@ namespace Vocaluxe
Application.DoEvents();
// Load Cover
CLog.StartBenchmark("Init Cover");
CCover.Init();
CLog.StopBenchmark("Init Cover");
Application.DoEvents();
// Init Screens
CLog.StartBenchmark("Init Screens");
CGraphics.Init();
@@ -265,6 +266,7 @@ namespace Vocaluxe
CGraphics.Close();
CTheme.Close();
CCover.Close();
CFonts.Close();
CBackgroundMusic.Close();
CWebcam.Close();
CDataBase.Close();
+1 -1
View File
@@ -160,7 +160,7 @@ namespace Vocaluxe.Screens
if (CConfig.BackgroundMusic == EBackgroundMusicOffOn.TR_CONFIG_ON)
CBackgroundMusic.Play();
else
CBackgroundMusic.Pause();
CBackgroundMusic.Stop();
}
}
}
+6 -5
View File
@@ -18,6 +18,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Windows.Forms;
@@ -995,13 +996,13 @@ namespace Vocaluxe.Screens
float partSeconds = timeDiff - fullSeconds;
_Texts[_TextMedleyCountdown].Visible = true;
_Texts[_TextMedleyCountdown].Text = fullSeconds.ToString();
float h = partSeconds * CSettings.RenderH;
float w = CFonts.GetTextBounds(_Texts[_TextMedleyCountdown], h).Width;
float x = CSettings.RenderW / 2 - w / 2;
float y = CSettings.RenderH / 2 - h / 2;
_Texts[_TextMedleyCountdown].Font.Height = partSeconds * CSettings.RenderH;
RectangleF textBounds = CFonts.GetTextBounds(_Texts[_TextMedleyCountdown]);
float x = CSettings.RenderW / 2 - textBounds.Width / 2;
float y = CSettings.RenderH / 2 - textBounds.Height / 2;
_Texts[_TextMedleyCountdown].X = x;
_Texts[_TextMedleyCountdown].Y = y;
_Texts[_TextMedleyCountdown].Height = h;
}
else
_Texts[_TextMedleyCountdown].Visible = false;
+1 -1
View File
@@ -714,7 +714,7 @@ namespace Vocaluxe.Screens
_SongMenu.OnHide();
if (CGraphics.NextScreen != EScreens.ScreenNames)
if (CGraphics.NextScreen != EScreens.ScreenNames || CConfig.BackgroundMusic == EBackgroundMusicOffOn.TR_CONFIG_OFF)
{
CBackgroundMusic.Disabled = false;
CSound.SetGlobalVolume(CConfig.BackgroundMusicVolume);
+2 -1
View File
@@ -216,6 +216,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Base\CBackgroundMusic.cs" />
<Compile Include="Base\CNoCoverGenerator.cs" />
<Compile Include="Base\CPlaylistElement.cs" />
<Compile Include="Base\CRecord.cs" />
<Compile Include="Base\CVideoPlayer.cs" />
@@ -246,7 +247,7 @@
<Compile Include="Base\CDraw.cs" />
<Compile Include="Lib\Sound\Playback\PortAudio\CPt1.cs" />
<Compile Include="Lib\Sound\Playback\PortAudio\CSyncTimer.cs" />
<Compile Include="Base\Fonts\CFont.cs" />
<Compile Include="Base\Fonts\CFontStyle.cs" />
<Compile Include="Base\CGame.cs" />
<Compile Include="Base\CController.cs" />
<Compile Include="Base\CLanguage.cs" />
+95
View File
@@ -0,0 +1,95 @@
using System;
using System.Collections.Generic;
using System.Xml.Serialization;
namespace VocaluxeLib
{
public interface IFontObserver
{
void FontChanged();
}
public struct SThemeFont
{
public string Name;
public EStyle Style;
public float Size;
}
public class CFont
{
private string _Name;
private EStyle _Style;
private float _Height;
private readonly List<IFontObserver> _Observers = new List<IFontObserver>();
public string Name
{
get { return _Name; }
set
{
if (_Name == value)
return;
_Name = value;
foreach (IFontObserver observer in _Observers)
observer.FontChanged();
}
}
public EStyle Style
{
get { return _Style; }
set
{
if (_Style == value)
return;
_Style = value;
foreach (IFontObserver observer in _Observers)
observer.FontChanged();
}
}
public float Height
{
get { return _Height; }
set
{
if (Math.Abs(_Height - value) < 0.001)
return;
_Height = value;
foreach (IFontObserver observer in _Observers)
observer.FontChanged();
}
}
public CFont()
{
_Name = "Normal";
_Style = EStyle.Normal;
_Height = 25f;
}
public CFont(SThemeFont font)
{
_Name = font.Name;
_Style = font.Style;
_Height = font.Size;
}
public CFont(string fontFamily, EStyle style, float h)
{
_Name = fontFamily;
_Style = style;
_Height = h;
}
public void AddObserver(IFontObserver observer)
{
if (!_Observers.Contains(observer))
_Observers.Add(observer);
}
public void RemoveObserver(IFontObserver observer)
{
_Observers.Remove(observer);
}
}
}
+5 -18
View File
@@ -22,6 +22,7 @@ using System.Drawing;
using System.Drawing.Drawing2D;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
namespace VocaluxeLib
{
@@ -77,6 +78,7 @@ namespace VocaluxeLib
/// <returns></returns>
public static bool IsInRange<T>(this T val, T min, T max) where T : IComparable<T>
{
Debug.Assert(min.CompareTo(max) <= 0);
return min.CompareTo(val) <= 0 && max.CompareTo(val) >= 0;
}
@@ -147,28 +149,13 @@ namespace VocaluxeLib
return value.IndexOf(other, StringComparison.CurrentCultureIgnoreCase) >= 0;
}
private static Regex _MultipleWhiteSpaceRegEx = new Regex(@" {2,}");
public static string TrimMultipleWs(this string value)
{
if (string.IsNullOrEmpty(value))
return "";
int start = 0;
int len = value.Length;
while (value[start] == ' ')
{
start++;
if (start >= len)
return "";
}
if (start > 0)
start--;
int end = --len;
while (value[end] == ' ')
end--;
if (end < len)
end++;
if (end - start < len)
value = value.Substring(start, end - start + 1);
return value;
return _MultipleWhiteSpaceRegEx.Replace(value, " ");
}
/// <summary>
+3 -7
View File
@@ -174,15 +174,11 @@ namespace VocaluxeLib
public interface IFonts
{
void SetFont(string fontName);
void SetStyle(EStyle fontStyle);
RectangleF GetTextBounds(CText text);
RectangleF GetTextBounds(CText text, float textHeight);
void DrawText(string text, float textHeight, float x, float y, float z, SColorF color);
void DrawTextReflection(string text, float textHeight, float x, float y, float z, SColorF color, float reflectionSpace, float reflectionHeight);
void DrawText(string text, float textHeight, float x, float y, float z, SColorF color, float begin, float end);
void DrawText(string text, CFont font, float x, float y, float z, SColorF color);
void DrawTextReflection(string text, CFont font, float x, float y, float z, SColorF color, float reflectionSpace, float reflectionHeight);
void DrawText(string text, CFont font, float x, float y, float z, SColorF color, float begin, float end);
}
public interface ILanguage
+1
View File
@@ -20,6 +20,7 @@ using System.Xml.Serialization;
using System.Diagnostics;
using System.Collections.Generic;
using VocaluxeLib.Draw;
using VocaluxeLib.Xml;
namespace VocaluxeLib.Menu
{
+1
View File
@@ -19,6 +19,7 @@ using System;
using System.Xml;
using System.Xml.Serialization;
using VocaluxeLib.Draw;
using VocaluxeLib.Xml;
namespace VocaluxeLib.Menu
{
+1
View File
@@ -18,6 +18,7 @@
using System;
using System.Xml;
using System.Xml.Serialization;
using VocaluxeLib.Xml;
namespace VocaluxeLib.Menu
{
+6 -8
View File
@@ -18,6 +18,7 @@
using System;
using System.Xml.Serialization;
using VocaluxeLib.Songs;
using VocaluxeLib.Xml;
namespace VocaluxeLib.Menu
{
@@ -187,10 +188,7 @@ namespace VocaluxeLib.Menu
private void _SetText(CSongNote note)
{
_Text.Text = note.Text;
_Text.Style = EStyle.Bold;
if (note.Type == ENoteType.Freestyle)
_Text.Style = EStyle.BoldItalic;
_Text.Font.Style = (note.Type == ENoteType.Freestyle) ? EStyle.BoldItalic : EStyle.Bold;
}
public void Clear()
@@ -332,11 +330,11 @@ namespace VocaluxeLib.Menu
p = 1f - p;
float ty = _Text.Y;
float th = _Text.Height;
float th = _Text.Font.Height;
float tz = _Text.Z;
SRectF normalRect = _Text.Rect;
_Text.Height += _Text.Height * p * 0.4f;
_Text.Font.Height *= 1f + p * 0.4f;
_Text.X -= (_Text.Rect.W - normalRect.W) / 2f;
_Text.Y -= (_Text.Rect.H - normalRect.H) / 2f;
_Text.Z -= 0.1f;
@@ -346,7 +344,7 @@ namespace VocaluxeLib.Menu
_Text.Draw();
_Text.Y = ty;
_Text.Height = th;
_Text.Font.Height = th;
_Text.Z = tz;
}
}
@@ -438,7 +436,7 @@ namespace VocaluxeLib.Menu
else
{
float y = _Text.Y;
_Text.Y -= _Text.Height * 0.1f * p;
_Text.Y -= _Text.Font.Height * 0.1f * p;
_Text.Draw();
_Text.Y = y;
}
+1
View File
@@ -25,6 +25,7 @@ using System.Xml.Serialization;
using VocaluxeLib.Draw;
using VocaluxeLib.Menu.SingNotes;
using VocaluxeLib.Menu.SongMenu;
using VocaluxeLib.Xml;
namespace VocaluxeLib.Menu
{
+1
View File
@@ -22,6 +22,7 @@ using System.Xml;
using System.Xml.Serialization;
using VocaluxeLib.Draw;
using VocaluxeLib.Profile;
using VocaluxeLib.Xml;
namespace VocaluxeLib.Menu
{
+1
View File
@@ -21,6 +21,7 @@ using System.Diagnostics;
using System.Xml;
using System.Xml.Serialization;
using VocaluxeLib.Draw;
using VocaluxeLib.Xml;
namespace VocaluxeLib.Menu
{
+1
View File
@@ -20,6 +20,7 @@ using System.Collections.Generic;
using System.Windows.Forms;
using System.Xml.Serialization;
using VocaluxeLib.Songs;
using VocaluxeLib.Xml;
namespace VocaluxeLib.Menu
{
+1
View File
@@ -19,6 +19,7 @@ using System;
using System.Xml;
using System.Xml.Serialization;
using VocaluxeLib.Draw;
using VocaluxeLib.Xml;
namespace VocaluxeLib.Menu
{
+1
View File
@@ -20,6 +20,7 @@ using System.Collections.Generic;
using System.Drawing;
using System.Xml.Serialization;
using VocaluxeLib.Draw;
using VocaluxeLib.Xml;
namespace VocaluxeLib.Menu
{
+1
View File
@@ -19,6 +19,7 @@ using System;
using System.Xml;
using System.Xml.Serialization;
using VocaluxeLib.Draw;
using VocaluxeLib.Xml;
namespace VocaluxeLib.Menu
{
+46 -79
View File
@@ -17,8 +17,8 @@
using System;
using System.Drawing;
using System.Xml;
using System.Xml.Serialization;
using VocaluxeLib.Xml;
namespace VocaluxeLib.Menu
{
@@ -30,19 +30,19 @@ namespace VocaluxeLib.Menu
[XmlElement("X")] public float X;
[XmlElement("Y")] public float Y;
[XmlElement("Z")] public float Z;
[XmlElement("H")] public float Height;
[XmlElement("H")] public float FontHeight;
[XmlElement("MaxW")] public float MaxWidth;
public SThemeColor Color;
public SThemeColor SColor; //for Buttons
[XmlElement("Align")] public EAlignment Align;
[XmlElement("ResizeAlign")] public EHAlignment ResizeAlign;
[XmlElement("Style")] public EStyle Style;
[XmlElement("Font")] public string Font;
[XmlElement("Style")] public EStyle FontStyle;
[XmlElement("Font")] public string FontFamily;
[XmlElement("Text")] public string Text;
public SReflection Reflection;
}
public class CText : IMenuElement
public class CText : IMenuElement, IFontObserver
{
private SThemeText _Theme;
private bool _ThemeLoaded;
@@ -99,20 +99,6 @@ namespace VocaluxeLib.Menu
set { _Z = value; }
}
private float _Height;
public float Height
{
get { return _Height; }
set
{
if (Math.Abs(_Height - value) > 0.01)
{
_Height = value;
_PositionNeedsUpdate = true;
}
}
}
private float _MaxWidth;
public float MaxWidth
{
@@ -155,29 +141,17 @@ namespace VocaluxeLib.Menu
}
}
private EStyle _Style = EStyle.Normal;
public EStyle Style
{
get { return _Style; }
set
{
if (_Style != value)
{
_Style = value;
_PositionNeedsUpdate = true;
}
}
}
private string _Font = String.Empty;
public string Font
private CFont _Font = new CFont();
public CFont Font
{
get { return _Font; }
set
{
if (_Font != value)
if (!_Font.Equals(value))
{
_Font.RemoveObserver(this);
_Font = value;
_Font.AddObserver(this);
_PositionNeedsUpdate = true;
}
}
@@ -216,10 +190,16 @@ namespace VocaluxeLib.Menu
_Text = translation;
if (_EditMode)
_Text += "|";
//Reset height, it might have been reduced in _UpdatePosition
Font.Height = _Theme.FontHeight;
_PositionNeedsUpdate = true;
}
}
}
public string TranslatedText
{
get { return _Text; }
}
public int PartyModeID
{
@@ -263,7 +243,7 @@ namespace VocaluxeLib.Menu
{
_PartyModeID = partyModeID;
_TranslationID = _PartyModeID;
_Font = "Normal";
_Font.AddObserver(this);
}
public CText(CText text)
@@ -274,12 +254,10 @@ namespace VocaluxeLib.Menu
_X = text._X;
_Y = text._Y;
_Z = text._Z;
_Height = text._Height;
_MaxWidth = text._MaxWidth;
_Align = text._Align;
_ResizeAlign = text._ResizeAlign;
_Style = text._Style;
_Font = text._Font;
Font = text.Font; //Use setter to set observer
Color = new SColorF(text.Color);
SelColor = new SColorF(text.SelColor);
@@ -294,24 +272,23 @@ namespace VocaluxeLib.Menu
_EditMode = text._EditMode;
}
public CText(float x, float y, float z, float h, float mw, EAlignment align, EStyle style, string font, SColorF col, string text, int partyModeID = -1, float rheight = 0,
float rspace = 0)
public CText(float x, float y, float z, float h, float mw, EAlignment align, EStyle style, string fontFamily, SColorF col, string text, int partyModeID = -1,
float rheight = 0,
float rspace = 0) : this(partyModeID)
{
_Theme = new SThemeText();
_Theme = new SThemeText {FontFamily = fontFamily, FontStyle = style, FontHeight = h, Text = text};
_ThemeLoaded = false;
_ButtonText = false;
_PartyModeID = partyModeID;
_TranslationID = _PartyModeID;
X = x;
Y = y;
Z = z;
Height = h;
MaxWidth = mw;
Align = align;
ResizeAlign = EHAlignment.Center;
Style = style;
Font = font;
_Font.Name = fontFamily;
_Font.Style = style;
_Font.Height = h;
Color = col;
SelColor = new SColorF(col);
@@ -351,7 +328,6 @@ namespace VocaluxeLib.Menu
if (!buttonText)
_ThemeLoaded &= xmlReader.TryGetFloatValue(item + "/Z", ref _Z);
_ThemeLoaded &= xmlReader.TryGetFloatValue(item + "/H", ref _Height);
xmlReader.TryGetFloatValue(item + "/MaxW", ref _MaxWidth);
if (xmlReader.GetValue(item + "/Color", out _Theme.Color.Name, String.Empty))
@@ -378,8 +354,9 @@ namespace VocaluxeLib.Menu
_ThemeLoaded &= xmlReader.TryGetEnumValue(item + "/Align", ref _Align);
xmlReader.TryGetEnumValue(item + "/ResizeAlign", ref _ResizeAlign);
_ThemeLoaded &= xmlReader.TryGetEnumValue(item + "/Style", ref _Style);
_ThemeLoaded &= xmlReader.GetValue(item + "/Font", out _Font, "Normal");
_ThemeLoaded &= xmlReader.TryGetFloatValue(item + "/H", ref _Theme.FontHeight);
_ThemeLoaded &= xmlReader.TryGetEnumValue(item + "/Style", ref _Theme.FontStyle);
_ThemeLoaded &= xmlReader.GetValue(item + "/Font", out _Theme.FontFamily);
_ThemeLoaded &= xmlReader.GetValue(item + "/Text", out _Theme.Text, String.Empty);
@@ -396,15 +373,12 @@ namespace VocaluxeLib.Menu
_Theme.Name = elementName;
_Theme.Align = _Align;
_Theme.Color.Color = Color;
_Theme.Font = _Font;
_Theme.ResizeAlign = _ResizeAlign;
_Theme.SColor.Color = SelColor;
_Theme.Style = _Style;
_Theme.MaxWidth = _MaxWidth;
_Theme.X = _X;
_Theme.Y = _Y;
_Theme.Z = _Z;
_Theme.Height = _Height;
_ButtonText = buttonText;
_PositionNeedsUpdate = true;
@@ -422,16 +396,13 @@ namespace VocaluxeLib.Menu
// Update Text
Text = Text;
CBase.Fonts.SetFont(Font);
CBase.Fonts.SetStyle(Style);
SColorF currentColor = (Selected) ? SelColor : Color;
var color = new SColorF(currentColor.R, currentColor.G, currentColor.B, currentColor.A * Alpha);
CBase.Fonts.DrawText(_Text, Rect.H, Rect.X, Rect.Y, Z, color);
CBase.Fonts.DrawText(_Text, Font, Rect.X, Rect.Y, Z, color);
if (ReflectionHeight > 0)
CBase.Fonts.DrawTextReflection(_Text, Rect.H, Rect.X, Rect.Y, Z, color, ReflectionSpace, ReflectionHeight);
CBase.Fonts.DrawTextReflection(_Text, Font, Rect.X, Rect.Y, Z, color, ReflectionSpace, ReflectionHeight);
if (Selected && (CBase.Settings.GetProgramState() == EProgramState.EditTheme))
CBase.Drawing.DrawRect(new SColorF(0.5f, 1f, 0.5f, 0.5f), new SRectF(Rect.X, Rect.Y, Rect.W, Rect.H, Z));
@@ -439,13 +410,10 @@ namespace VocaluxeLib.Menu
public void Draw(float begin, float end)
{
CBase.Fonts.SetFont(Font);
CBase.Fonts.SetStyle(Style);
SColorF currentColor = (Selected) ? SelColor : Color;
var color = new SColorF(currentColor.R, currentColor.G, currentColor.B, currentColor.A * Alpha);
CBase.Fonts.DrawText(Text, Rect.H, Rect.X, Rect.Y, Z, color, begin, end);
CBase.Fonts.DrawText(Text, Font, Rect.X, Rect.Y, Z, color, begin, end);
if (ReflectionHeight > 0)
{
@@ -486,12 +454,10 @@ namespace VocaluxeLib.Menu
_X = _Theme.X;
_Y = _Theme.Y;
_Z = _Theme.Z;
_Height = _Theme.Height;
_MaxWidth = _Theme.MaxWidth;
_Align = _Theme.Align;
_ResizeAlign = _Theme.ResizeAlign;
_Style = _Theme.Style;
_Font = _Theme.Font;
Font = new CFont(_Theme.FontFamily, _Theme.FontStyle, _Theme.FontHeight);
if (_Theme.Reflection.Enabled)
{
@@ -522,17 +488,16 @@ namespace VocaluxeLib.Menu
X += stepX;
Y += stepY;
_Theme.X += stepX;
_Theme.Y += stepY;
_Theme.X = X;
_Theme.Y = Y;
}
public void ResizeElement(int stepW, int stepH)
{
Height += stepH;
if (Height <= 0)
Height = 1;
_Theme.Height = _Height;
_Theme.FontHeight += stepH;
if (_Theme.FontHeight <= 0)
_Theme.FontHeight = 1;
_Font.Height = _Theme.FontHeight;
}
#endregion ThemeEdit
@@ -541,10 +506,7 @@ namespace VocaluxeLib.Menu
if (_Text == "")
return;
CBase.Fonts.SetFont(Font);
CBase.Fonts.SetStyle(Style);
float h = Height;
float h = Font.Height;
float y = Y;
RectangleF bounds = CBase.Fonts.GetTextBounds(this);
@@ -565,8 +527,8 @@ namespace VocaluxeLib.Menu
y += step * 0.75f;
break;
}
bounds = CBase.Fonts.GetTextBounds(this, h);
Font.Height = h;
bounds = CBase.Fonts.GetTextBounds(this);
}
float x = X;
@@ -587,5 +549,10 @@ namespace VocaluxeLib.Menu
_PositionNeedsUpdate = false;
}
public void FontChanged()
{
_PositionNeedsUpdate = true;
}
}
}
+1
View File
@@ -16,6 +16,7 @@
#endregion
using System.Xml;
using VocaluxeLib.Xml;
namespace VocaluxeLib.Menu
{
+1
View File
@@ -21,6 +21,7 @@ using System.Diagnostics;
using System.Xml.Serialization;
using VocaluxeLib.Draw;
using VocaluxeLib.Songs;
using VocaluxeLib.Xml;
namespace VocaluxeLib.Menu.SingNotes
{
+1
View File
@@ -17,6 +17,7 @@
using System.Xml;
using VocaluxeLib.PartyModes;
using VocaluxeLib.Xml;
namespace VocaluxeLib.Menu.SongMenu
{
+14 -13
View File
@@ -23,6 +23,7 @@ using System.Xml.Serialization;
using VocaluxeLib.Draw;
using VocaluxeLib.PartyModes;
using VocaluxeLib.Songs;
using VocaluxeLib.Xml;
namespace VocaluxeLib.Menu.SongMenu
{
@@ -60,35 +61,35 @@ namespace VocaluxeLib.Menu.SongMenu
public struct SThemeSongMenuTileBoard
{
[XmlElement("NumW")] /// <summary>
/// <summary>
/// Number of tiles horizontal
/// </summary>
public int NumW;
[XmlElement("NumW")] public int NumW;
[XmlElement("NumH")] /// <summary>
/// <summary>
/// Number of tiles vertical
/// </summary>
public int NumH;
[XmlElement("NumH")] public int NumH;
[XmlElement("NumWsmall")] /// <summary>
/// <summary>
/// Number of tiles horizontal in small-modus
/// </summary>
public int NumWsmall;
[XmlElement("NumWsmall")] public int NumWsmall;
[XmlElement("NumHsmall")] /// <summary>
/// <summary>
/// Number of tiles vertical in small-modus
/// </summary>
public int NumHsmall;
[XmlElement("NumHsmall")] public int NumHsmall;
[XmlElement("SpaceW")] /// <summary>
/// <summary>
/// Space between tiles horizontal
/// </summary>
public float SpaceW;
[XmlElement("SpaceW")] public float SpaceW;
[XmlElement("SpaceH")] /// <summary>
/// <summary>
/// Space between tiles vertical
/// </summary>
public float SpaceH;
[XmlElement("SpaceH")] public float SpaceH;
[XmlElement("TileRect")] public SRectF TileRect;
[XmlElement("TileRectSmall")] public SRectF TileRectSmall;
@@ -270,7 +271,7 @@ namespace VocaluxeLib.Menu.SongMenu
public virtual void OnHide()
{
if (CBase.Graphics.GetNextScreen() != EScreens.ScreenNames)
if(CBase.Graphics.GetNextScreen() != EScreens.ScreenNames || CBase.Config.GetBackgroundMusicStatus() == EBackgroundMusicOffOn.TR_CONFIG_OFF)
_ResetPreview();
}
@@ -23,6 +23,7 @@ using System.Xml;
using VocaluxeLib.Draw;
using VocaluxeLib.PartyModes;
using VocaluxeLib.Songs;
using VocaluxeLib.Xml;
namespace VocaluxeLib.Menu.SongMenu
{
+1 -3
View File
@@ -32,11 +32,9 @@ namespace VocaluxeLib.PartyModes
public override void LoadTheme(string xmlPath)
{
_Warning = GetNewText();
_Warning.Height = 100f;
_Warning.Font.Height = 100f;
_Warning.X = 150;
_Warning.Y = 300;
_Warning.Font = "Normal";
_Warning.Style = EStyle.Normal;
_Warning.Color = new SColorF(1f, 0f, 0f, 1f);
_Warning.SelColor = new SColorF(1f, 0f, 0f, 1f);
_Warning.Text = "SOMETHING WENT WRONG!";
+1
View File
@@ -18,6 +18,7 @@
using System;
using System.IO;
using System.Xml;
using VocaluxeLib.Xml;
namespace VocaluxeLib.Profile
{
+38
View File
@@ -26,6 +26,44 @@ using VocaluxeLib.Songs;
namespace VocaluxeLib
{
public enum ECoverGeneratorType
{
Default,
Folder,
Artist,
Letter,
Edition,
Genre,
Language,
Year,
Decade,
Date
}
public struct SMargin
{
public int Default;
public int Left, Right, Top, Bottom;
}
public struct SThemeCoverGeneratorText
{
public string Text;
public SThemeFont Font;
public SThemeColor Color;
public SMargin Margin;
public int Indent;
}
public struct SThemeCoverGenerator
{
public ECoverGeneratorType Type;
public SThemeCoverGeneratorText Text;
public SThemeColor BackgroundColor;
public string Image;
public float ImageAlpha;
public bool ShowFirstCover;
}
#region Drawing
public struct SColorF
+4 -1
View File
@@ -78,6 +78,7 @@
<ItemGroup>
<Compile Include="CEncoding.cs" />
<Compile Include="CFading.cs" />
<Compile Include="CFont.cs" />
<Compile Include="CVideoStream.cs" />
<Compile Include="Extensions.cs" />
<Compile Include="GlobalSuppressions.cs" />
@@ -103,7 +104,8 @@
<Compile Include="Menu\CText.cs" />
<Compile Include="Menu\CScreenSetting.cs" />
<Compile Include="Draw\CTextureRef.cs" />
<Compile Include="CXMLReader.cs" />
<Compile Include="Xml\CXmlDeserializer.cs" />
<Compile Include="Xml\CXMLReader.cs" />
<Compile Include="Enums.cs" />
<Compile Include="Menu\IMenu.cs" />
<Compile Include="Menu\IMenuElement.cs" />
@@ -139,6 +141,7 @@
<Compile Include="Utils\CWavFile.cs" />
<Compile Include="Utils\Player\CSongPlayer.cs" />
<Compile Include="Utils\Player\CSoundPlayer.cs" />
<Compile Include="Xml\CXmlReaderBase.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
@@ -19,9 +19,9 @@ using System;
using System.Collections.Generic;
using System.Xml.XPath;
namespace VocaluxeLib
namespace VocaluxeLib.Xml
{
public class CXMLReader
public class CXMLReader : CXmlDeserializer
{
private readonly XPathNavigator _Navigator;
private readonly String _FilePath;
@@ -57,56 +57,18 @@ namespace VocaluxeLib
}
}
public bool TryGetEnumValue<T>(string xPath, ref T value)
where T : struct
{
string val;
if (GetValue(xPath, out val, Enum.GetName(typeof(T), value)))
return CHelper.TryParse(val, out value, true);
return false;
}
public bool TryGetIntValue(string xPath, ref int value)
{
string val;
if (GetValue(xPath, out val, value.ToString()))
return int.TryParse(val, out value);
return false;
}
public bool TryGetIntValueRange(string xPath, ref int value, int min = 0, int max = 100)
{
bool result = TryGetIntValue(xPath, ref value);
if (result)
value = value.Clamp(min, max);
return result;
}
public bool TryGetFloatValue(string xPath, ref float value)
{
string val;
return GetValue(xPath, out val, value.ToString()) && CHelper.TryParse(val, out value);
}
public bool TryGetColorFromRGBA(string xPath, out SColorF value)
{
value = new SColorF();
bool result = true;
result &= TryGetFloatValue(xPath + "/R", ref value.R);
result &= TryGetFloatValue(xPath + "/G", ref value.G);
result &= TryGetFloatValue(xPath + "/B", ref value.B);
result &= TryGetFloatValue(xPath + "/A", ref value.A);
if (result)
{
value.R = value.R.Clamp(0f, 1f);
value.G = value.G.Clamp(0f, 1f);
value.B = value.B.Clamp(0f, 1f);
value.A = value.A.Clamp(0f, 1f);
}
result &= TryGetNormalizedFloatValue(xPath + "/R", ref value.R);
result &= TryGetNormalizedFloatValue(xPath + "/G", ref value.G);
result &= TryGetNormalizedFloatValue(xPath + "/B", ref value.B);
result &= TryGetNormalizedFloatValue(xPath + "/A", ref value.A);
return result;
}
public bool GetValue(string xPath, out string value, string defaultValue = "")
public override bool GetValue(string xPath, out string value, string defaultValue = "")
{
int resultCt = 0;
string val = string.Empty;
@@ -129,6 +91,19 @@ namespace VocaluxeLib
return true;
}
public override bool GetAttribute(string xPath, string attribute, out string value)
{
_Navigator.MoveToRoot();
XPathNodeIterator iterator = _Navigator.Select(xPath);
if (iterator.MoveNext())
{
value = iterator.Current.GetAttribute(attribute, "");
return true;
}
value = "";
return false;
}
public List<string> GetNames(string xPath)
{
var values = new List<string>();
+68
View File
@@ -0,0 +1,68 @@
using System.Linq;
namespace VocaluxeLib.Xml
{
public abstract class CXmlDeserializer : CXmlReaderBase
{
public bool Read(string xPath, out SThemeFont el)
{
el = new SThemeFont();
bool ok = true;
ok &= GetValue(xPath + "/Name", out el.Name);
ok &= TryGetFloatValue(xPath + "/Size", ref el.Size);
ok &= TryGetEnumValue(xPath + "/Style", ref el.Style);
return ok;
}
public bool Read(string xPath, out SMargin el)
{
el = new SMargin();
bool ok = true;
bool defOk = TryGetIntValue(xPath + "/Default", ref el.Default);
ok &= TryGetIntValue(xPath + "/Left", ref el.Left, el.Default);
ok &= TryGetIntValue(xPath + "/Right", ref el.Right, el.Default);
ok &= TryGetIntValue(xPath + "/Top", ref el.Top, el.Default);
ok &= TryGetIntValue(xPath + "/Bottom", ref el.Bottom, el.Default);
return ok || defOk;
}
public bool Read(string xPath, out SThemeCoverGeneratorText el)
{
el = new SThemeCoverGeneratorText();
bool ok = true;
ok &= GetValue(xPath + "/Text", out el.Text);
ok &= Read(xPath + "/Font", out el.Font);
ok &= Read(xPath + "/Color", out el.Color);
ok &= Read(xPath + "/Margin", out el.Margin);
if (ok)
TryGetIntValue(xPath + "/Indent", ref el.Indent, 6 * (el.Margin.Left + el.Margin.Right) / 2);
return ok;
}
public bool Read(string xPath, out SThemeColor el)
{
el = new SThemeColor();
bool ok = true;
ok &= TryGetNormalizedFloatValue(xPath + "/R", ref el.Color.R);
ok &= TryGetNormalizedFloatValue(xPath + "/G", ref el.Color.G);
ok &= TryGetNormalizedFloatValue(xPath + "/B", ref el.Color.B);
ok &= TryGetNormalizedFloatValue(xPath + "/A", ref el.Color.A);
if (!ok)
ok = GetValue(xPath, out el.Name) && !el.Name.Contains('<');
return ok;
}
public bool Read(string xPath, out SThemeCoverGenerator el)
{
el = new SThemeCoverGenerator();
bool ok = true;
ok &= TryGetEnumValue(xPath + "/Type", ref el.Type);
ok &= Read(xPath + "/Text", out el.Text);
ok &= Read(xPath + "/BackgroundColor", out el.BackgroundColor);
ok &= GetValue(xPath + "/Image", out el.Image);
TryGetNormalizedFloatValue(xPath + "/ImageAlpha", ref el.ImageAlpha, 0.5f);
TryGetBoolValue(xPath + "/ShowFirstCover", out el.ShowFirstCover);
return ok;
}
}
}
+61
View File
@@ -0,0 +1,61 @@
using System;
namespace VocaluxeLib.Xml
{
/// <summary>
/// Base class that provides basic methods for reading xml, while the actual XML implementation is still abstract to allow different implementations
/// </summary>
public abstract class CXmlReaderBase
{
public abstract bool GetValue(string xPath, out string value, string defaultValue = "");
public abstract bool GetAttribute(string xPath, string attribute, out string value);
public bool TryGetBoolValue(string xPath, out bool value, bool defaultValue = false)
{
value = defaultValue;
string val;
return GetValue(xPath, out val) && bool.TryParse(val, out value);
}
public bool TryGetIntValue(string xPath, ref int value, int? defaultValue = null)
{
string val;
bool ok = GetValue(xPath, out val) && int.TryParse(val, out value);
if (!ok && defaultValue.HasValue)
value = defaultValue.Value;
return ok;
}
public bool TryGetFloatValue(string xPath, ref float value)
{
string val;
return GetValue(xPath, out val, value.ToString()) && CHelper.TryParse(val, out value);
}
public bool TryGetEnumValue<T>(string xPath, ref T value) where T : struct
{
string val;
return GetValue(xPath, out val, Enum.GetName(typeof(T), value)) && CHelper.TryParse(val, out value, true);
}
public bool TryGetIntValueRange(string xPath, ref int value, int min = 0, int max = 100)
{
return TryGetIntValue(xPath, ref value) && value.IsInRange(min, max);
}
/// <summary>
/// Gets a normalized (0&lt;=x&lt;=1) float value
/// </summary>
/// <param name="xPath"></param>
/// <param name="value"></param>
/// <param name="defaultValue"></param>
/// <returns>True if exists and is normalized</returns>
public bool TryGetNormalizedFloatValue(string xPath, ref float value, float defaultValue = 0)
{
bool ok = TryGetFloatValue(xPath, ref value) && value.IsInRange(0f, 1f);
if (!ok)
value = defaultValue;
return ok;
}
}
}