diff --git a/Output/Cover/Blue.xml b/Output/Cover/Blue.xml
index 9befe7d3..8afbbb3b 100644
--- a/Output/Cover/Blue.xml
+++ b/Output/Cover/Blue.xml
@@ -5,4 +5,41 @@
Blue
flokuep
+
+
+
+ Default
+
+
+ %TEXT%
+
+ Normal
+
+
+
+ 500
+
+
+
+
+ 1110.8
+
+
+
+ 24
+ 24
+
+
+ 100
+
+
+ 1111
+
+
+ EmptyCover.png
+
+ true
+
+ 0.75
+
diff --git a/Output/Fonts/Fonts.xml b/Output/Fonts/Fonts.xml
index 2bbf61c3..70102ffa 100644
--- a/Output/Fonts/Fonts.xml
+++ b/Output/Fonts/Fonts.xml
@@ -4,10 +4,12 @@
Normal
0,00
- 0,00
- 0,00
- 0,00
- 1,00
+
+ 0,00
+ 0,00
+ 0,00
+ 1,00
+
FreeSans
FreeSans.ttf
FreeSansBold.ttf
@@ -17,10 +19,12 @@
Outline
0,10
- 0,00
- 0,00
- 0,00
- 1,00
+
+ 0,00
+ 0,00
+ 0,00
+ 1,00
+
FreeSans
FreeSans.ttf
FreeSansBold.ttf
diff --git a/PartyModes/PartyModeChallenge/CPartyScreenChallengeMain.cs b/PartyModes/PartyModeChallenge/CPartyScreenChallengeMain.cs
index 22945876..ea025b8e 100644
--- a/PartyModes/PartyModeChallenge/CPartyScreenChallengeMain.cs
+++ b/PartyModes/PartyModeChallenge/CPartyScreenChallengeMain.cs
@@ -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();
- float delta = _Texts[_TextPosition].Height * 1.2f;
+ float delta = _Texts[_TextPosition].Rect.H * 1.2f;
float h = 0;
diff --git a/PartyModes/PartyModeChallengeMedley/CPartyScreenChallengeMedleyMain.cs b/PartyModes/PartyModeChallengeMedley/CPartyScreenChallengeMedleyMain.cs
index 47dcb43c..0a0240f1 100644
--- a/PartyModes/PartyModeChallengeMedley/CPartyScreenChallengeMedleyMain.cs
+++ b/PartyModes/PartyModeChallengeMedley/CPartyScreenChallengeMedleyMain.cs
@@ -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();
- float delta = _Texts[_TextPosition].Height * 1.2f;
+ float delta = _Texts[_TextPosition].Rect.H * 1.2f;
float h = 0;
diff --git a/Vocaluxe/Base/CBackgroundMusic.cs b/Vocaluxe/Base/CBackgroundMusic.cs
index 396eda6d..f8685ff9 100644
--- a/Vocaluxe/Base/CBackgroundMusic.cs
+++ b/Vocaluxe/Base/CBackgroundMusic.cs
@@ -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
diff --git a/Vocaluxe/Base/CConfig.cs b/Vocaluxe/Base/CConfig.cs
index 12d913a0..3e201c06 100644
--- a/Vocaluxe/Base/CConfig.cs
+++ b/Vocaluxe/Base/CConfig.cs
@@ -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;
}
diff --git a/Vocaluxe/Base/CCover.cs b/Vocaluxe/Base/CCover.cs
index 50293b3d..096e988f 100644
--- a/Vocaluxe/Base/CCover.cs
+++ b/Vocaluxe/Base/CCover.cs
@@ -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 _Covers = new Dictionary();
- private static readonly List _CoverThemes = new List();
+ private static readonly Dictionary _NoCoverGenerators = new Dictionary();
+ private static readonly List _CoverThemes = new List();
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;
+ }
+
///
/// 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();
+ }
}
///
/// Returns a SCoverTheme by cover-theme-name
///
- 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();
}
///
@@ -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
}
///
- /// Loads all cover which are defined in the cover config file.
+ /// Loads all covers from the theme
///
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++;
+ }
}
}
diff --git a/Vocaluxe/Base/CDraw.cs b/Vocaluxe/Base/CDraw.cs
index 782c3a86..2586ab5a 100644
--- a/Vocaluxe/Base/CDraw.cs
+++ b/Vocaluxe/Base/CDraw.cs
@@ -216,7 +216,8 @@ namespace Vocaluxe.Base
///
/// Requests updating a texture from a bitmap
- /// 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
+ /// Bitmap is freed after use
///
/// Reference to the texture to update
///
diff --git a/Vocaluxe/Base/CGraphics.cs b/Vocaluxe/Base/CGraphics.cs
index fd856374..6ec89672 100644
--- a/Vocaluxe/Base/CGraphics.cs
+++ b/Vocaluxe/Base/CGraphics.cs
@@ -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;
}
}
diff --git a/Vocaluxe/Base/CLanguage.cs b/Vocaluxe/Base/CLanguage.cs
index fb452747..9f529b4f 100644
--- a/Vocaluxe/Base/CLanguage.cs
+++ b/Vocaluxe/Base/CLanguage.cs
@@ -20,6 +20,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using VocaluxeLib;
+using VocaluxeLib.Xml;
namespace Vocaluxe.Base
{
diff --git a/Vocaluxe/Base/CMain.cs b/Vocaluxe/Base/CMain.cs
index 2618e74a..55e25b42 100644
--- a/Vocaluxe/Base/CMain.cs
+++ b/Vocaluxe/Base/CMain.cs
@@ -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);
}
}
diff --git a/Vocaluxe/Base/CNoCoverGenerator.cs b/Vocaluxe/Base/CNoCoverGenerator.cs
new file mode 100644
index 00000000..d92177e0
--- /dev/null
+++ b/Vocaluxe/Base/CNoCoverGenerator.cs
@@ -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 .
+#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
+{
+ ///
+ /// Class that generates Covers if the right Cover is missing
+ /// Themeable via the xml of the Cover theme
+ ///
+ 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;
+
+ ///
+ /// Split lines after special chars, descending priority
+ ///
+ 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 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 textParts = _SplitText(text);
+ List 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;
+ }
+
+ ///
+ /// Distributes the text among max. 3 lines maximizing the height of the line
+ /// Sets the Line field in the elements
+ ///
+ /// Text with set Width and Height
+ /// Image Width
+ /// Image Height
+ /// Factor for resizing the text (Maximizing this factor means maximizing the height)
+ private float _DistributeText(List 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;
+ }
+
+ ///
+ /// Returns the width of the elements with index from start to end of the list (inclusive) if they are put on 1 line
+ ///
+ ///
+ ///
+ ///
+ private static float _GetWidth(List list, int start)
+ {
+ return _GetWidth(list, start, list.Count - 1);
+ }
+
+ ///
+ /// Returns the width of the elements with index from start to end (inclusive) if they are put on 1 line
+ ///
+ ///
+ ///
+ ///
+ ///
+ private static float _GetWidth(List 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 list, int start, int end, int line)
+ {
+ for (int i = start; i <= end; i++)
+ list[i].Line = line;
+ }
+
+ ///
+ /// Find the element after which to split the line
+ ///
+ /// List with elements, width must be set
+ /// The requested line width
+ /// Split on one point or two
+ /// First element on line
+ /// Index of element AFTER which to split
+ private static int _GetSplitElement(List 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;
+ }
+
+ ///
+ /// Split the text in parts that can then be distributet among the lines
+ ///
+ ///
+ ///
+ private static IEnumerable _SplitText(string text)
+ {
+ Debug.Assert(!String.IsNullOrWhiteSpace(text));
+
+ text = text.Trim().TrimMultipleWs();
+ List lines = new List();
+ 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;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Vocaluxe/Base/CParty.cs b/Vocaluxe/Base/CParty.cs
index 469e8af9..87607df9 100644
--- a/Vocaluxe/Base/CParty.cs
+++ b/Vocaluxe/Base/CParty.cs
@@ -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 GetPartyModeInfos()
{
var infos = new List();
diff --git a/Vocaluxe/Base/CSkin.cs b/Vocaluxe/Base/CSkin.cs
index b5ac1f8f..c51ddd8d 100644
--- a/Vocaluxe/Base/CSkin.cs
+++ b/Vocaluxe/Base/CSkin.cs
@@ -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
{
diff --git a/Vocaluxe/Base/CSongCategorizer.cs b/Vocaluxe/Base/CSongCategorizer.cs
index 4c16bf3a..7104c795 100644
--- a/Vocaluxe/Base/CSongCategorizer.cs
+++ b/Vocaluxe/Base/CSongCategorizer.cs
@@ -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;
}
}
diff --git a/Vocaluxe/Base/CTheme.cs b/Vocaluxe/Base/CTheme.cs
index 783bfbb5..997bc9c1 100644
--- a/Vocaluxe/Base/CTheme.cs
+++ b/Vocaluxe/Base/CTheme.cs
@@ -24,6 +24,7 @@ using Vocaluxe.Base.Fonts;
using Vocaluxe.Lib.Video;
using VocaluxeLib;
using VocaluxeLib.Draw;
+using VocaluxeLib.Xml;
namespace Vocaluxe.Base
{
diff --git a/Vocaluxe/Base/Fonts/CFont.cs b/Vocaluxe/Base/Fonts/CFontStyle.cs
similarity index 54%
rename from Vocaluxe/Base/Fonts/CFont.cs
rename to Vocaluxe/Base/Fonts/CFontStyle.cs
index a9c31e7a..5bde6719 100644
--- a/Vocaluxe/Base/Fonts/CFont.cs
+++ b/Vocaluxe/Base/Fonts/CFontStyle.cs
@@ -24,48 +24,64 @@ using VocaluxeLib.Draw;
namespace Vocaluxe.Base.Fonts
{
- class CFont : IDisposable
+ class CFontStyle : IDisposable
{
- private readonly Dictionary _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 _Glyphs = new Dictionary();
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();
+ _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;
- }
}
\ No newline at end of file
diff --git a/Vocaluxe/Base/Fonts/CFonts.cs b/Vocaluxe/Base/Fonts/CFonts.cs
index 1fa9ee31..a2f0b4cb 100644
--- a/Vocaluxe/Base/Fonts/CFonts.cs
+++ b/Vocaluxe/Base/Fonts/CFonts.cs
@@ -15,216 +15,166 @@
// along with Vocaluxe. If not, see .
#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
{
+ ///
+ /// Struct used for describing a font family (a type of text with 4 different styles)
+ ///
+ 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 _Fonts = new List();
- private static int _CurrentFont;
- private static float _Height = 1f;
+ private static bool _IsInitialized;
+ private static readonly List _FontFamilies = new List();
+ private static readonly List _LoggedMissingFonts = new List();
- // 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)
+ ///
+ /// Draws a black text
+ ///
+ /// The text to be drawn
+ /// The texts font
+ /// The texts x-position
+ /// The texts y-position
+ /// The texts z-position
+ 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));
}
///
- /// Draws a text string
+ /// Draws a text
///
/// The text to be drawn
- /// The text's x-position
- /// The text's y-position
- /// The text's height
- /// The text's z-position
+ /// The texts font
+ /// The texts x-position
+ /// The texts y-position
+ /// The texts z-position
/// The text color
- 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;
- }
-
///
/// Calculates the bounds for a CText object
///
@@ -232,94 +182,172 @@ namespace Vocaluxe.Base.Fonts
/// RectangleF object containing the bounds
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;
}
///
- /// Calculates the bounds for a CText object
+ /// Load default fonts
///
- /// The CText object of which the bounds should be calculated for
- /// The height of the CText object
- /// RectangleF object containing the bounds
- public static RectangleF GetTextBounds(CText text, float height)
+ ///
+ 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)
+ ///
+ /// Loads theme fonts from skin file
+ ///
+ 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)
+ ///
+ /// Loads party mode fonts from skin file
+ ///
+ 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++;
}
- }
-
- ///
- /// Load default fonts
- ///
- ///
- 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));
- }
-
- ///
- /// Loads theme fonts from skin file
- ///
- public static void LoadThemeFonts(string themeName, string fontFolder, CXMLReader xmlReader)
- {
- _LoadFontFiles(xmlReader, fontFolder, themeName);
- CLog.StartBenchmark("BuildGlyphs");
- _BuildGlyphs();
- CLog.StopBenchmark("BuildGlyphs");
- }
-
- ///
- /// Loads party mode fonts from skin file
- ///
- 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");
}
}
}
\ No newline at end of file
diff --git a/Vocaluxe/Base/Fonts/CGlyph.cs b/Vocaluxe/Base/Fonts/CGlyph.cs
index 5ccb6a6e..6b949903 100644
--- a/Vocaluxe/Base/Fonts/CGlyph.cs
+++ b/Vocaluxe/Base/Fonts/CGlyph.cs
@@ -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;
diff --git a/Vocaluxe/Lib/Playlist/CPlaylistFile.cs b/Vocaluxe/Lib/Playlist/CPlaylistFile.cs
index ff86215f..d09c9b95 100644
--- a/Vocaluxe/Lib/Playlist/CPlaylistFile.cs
+++ b/Vocaluxe/Lib/Playlist/CPlaylistFile.cs
@@ -24,6 +24,7 @@ using Vocaluxe.Base;
using VocaluxeLib;
using VocaluxeLib.Menu;
using VocaluxeLib.Songs;
+using VocaluxeLib.Xml;
namespace Vocaluxe.Lib.Playlist
{
diff --git a/Vocaluxe/Program.cs b/Vocaluxe/Program.cs
index 2236aa0a..bcab90e4 100644
--- a/Vocaluxe/Program.cs
+++ b/Vocaluxe/Program.cs
@@ -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();
diff --git a/Vocaluxe/Screens/CScreenOptionsSound.cs b/Vocaluxe/Screens/CScreenOptionsSound.cs
index 1976d3ca..657b8c5f 100644
--- a/Vocaluxe/Screens/CScreenOptionsSound.cs
+++ b/Vocaluxe/Screens/CScreenOptionsSound.cs
@@ -160,7 +160,7 @@ namespace Vocaluxe.Screens
if (CConfig.BackgroundMusic == EBackgroundMusicOffOn.TR_CONFIG_ON)
CBackgroundMusic.Play();
else
- CBackgroundMusic.Pause();
+ CBackgroundMusic.Stop();
}
}
}
\ No newline at end of file
diff --git a/Vocaluxe/Screens/CScreenSing.cs b/Vocaluxe/Screens/CScreenSing.cs
index d3561f44..a7fcdf66 100644
--- a/Vocaluxe/Screens/CScreenSing.cs
+++ b/Vocaluxe/Screens/CScreenSing.cs
@@ -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;
diff --git a/Vocaluxe/Screens/CScreenSong.cs b/Vocaluxe/Screens/CScreenSong.cs
index b55968fd..57a5ed16 100644
--- a/Vocaluxe/Screens/CScreenSong.cs
+++ b/Vocaluxe/Screens/CScreenSong.cs
@@ -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);
diff --git a/Vocaluxe/Vocaluxe.csproj b/Vocaluxe/Vocaluxe.csproj
index 1d03291c..ff09e8ad 100644
--- a/Vocaluxe/Vocaluxe.csproj
+++ b/Vocaluxe/Vocaluxe.csproj
@@ -216,6 +216,7 @@
+
@@ -246,7 +247,7 @@
-
+
diff --git a/VocaluxeLib/CFont.cs b/VocaluxeLib/CFont.cs
new file mode 100644
index 00000000..bb8fed4e
--- /dev/null
+++ b/VocaluxeLib/CFont.cs
@@ -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 _Observers = new List();
+
+ 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);
+ }
+ }
+}
\ No newline at end of file
diff --git a/VocaluxeLib/Extensions.cs b/VocaluxeLib/Extensions.cs
index fd359b67..12f06137 100644
--- a/VocaluxeLib/Extensions.cs
+++ b/VocaluxeLib/Extensions.cs
@@ -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
///
public static bool IsInRange(this T val, T min, T max) where T : IComparable
{
+ 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, " ");
}
///
diff --git a/VocaluxeLib/IBasic.cs b/VocaluxeLib/IBasic.cs
index c473b8ba..c15b9a9d 100644
--- a/VocaluxeLib/IBasic.cs
+++ b/VocaluxeLib/IBasic.cs
@@ -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
diff --git a/VocaluxeLib/Menu/CBackground.cs b/VocaluxeLib/Menu/CBackground.cs
index 4e13179f..daac4bc0 100644
--- a/VocaluxeLib/Menu/CBackground.cs
+++ b/VocaluxeLib/Menu/CBackground.cs
@@ -20,6 +20,7 @@ using System.Xml.Serialization;
using System.Diagnostics;
using System.Collections.Generic;
using VocaluxeLib.Draw;
+using VocaluxeLib.Xml;
namespace VocaluxeLib.Menu
{
diff --git a/VocaluxeLib/Menu/CButton.cs b/VocaluxeLib/Menu/CButton.cs
index aa29891b..ca1f29c9 100644
--- a/VocaluxeLib/Menu/CButton.cs
+++ b/VocaluxeLib/Menu/CButton.cs
@@ -19,6 +19,7 @@ using System;
using System.Xml;
using System.Xml.Serialization;
using VocaluxeLib.Draw;
+using VocaluxeLib.Xml;
namespace VocaluxeLib.Menu
{
diff --git a/VocaluxeLib/Menu/CEqualizer.cs b/VocaluxeLib/Menu/CEqualizer.cs
index 03bbfce6..40daa2a6 100644
--- a/VocaluxeLib/Menu/CEqualizer.cs
+++ b/VocaluxeLib/Menu/CEqualizer.cs
@@ -18,6 +18,7 @@
using System;
using System.Xml;
using System.Xml.Serialization;
+using VocaluxeLib.Xml;
namespace VocaluxeLib.Menu
{
diff --git a/VocaluxeLib/Menu/CLyric.cs b/VocaluxeLib/Menu/CLyric.cs
index 18870f41..e2cd3460 100644
--- a/VocaluxeLib/Menu/CLyric.cs
+++ b/VocaluxeLib/Menu/CLyric.cs
@@ -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;
}
diff --git a/VocaluxeLib/Menu/CMenu.cs b/VocaluxeLib/Menu/CMenu.cs
index fe6189df..418819fa 100644
--- a/VocaluxeLib/Menu/CMenu.cs
+++ b/VocaluxeLib/Menu/CMenu.cs
@@ -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
{
diff --git a/VocaluxeLib/Menu/CNameSelection.cs b/VocaluxeLib/Menu/CNameSelection.cs
index 662621bc..a03aa0d3 100644
--- a/VocaluxeLib/Menu/CNameSelection.cs
+++ b/VocaluxeLib/Menu/CNameSelection.cs
@@ -22,6 +22,7 @@ using System.Xml;
using System.Xml.Serialization;
using VocaluxeLib.Draw;
using VocaluxeLib.Profile;
+using VocaluxeLib.Xml;
namespace VocaluxeLib.Menu
{
diff --git a/VocaluxeLib/Menu/CParticle.cs b/VocaluxeLib/Menu/CParticle.cs
index 5c69c721..a8c0e4d5 100644
--- a/VocaluxeLib/Menu/CParticle.cs
+++ b/VocaluxeLib/Menu/CParticle.cs
@@ -21,6 +21,7 @@ using System.Diagnostics;
using System.Xml;
using System.Xml.Serialization;
using VocaluxeLib.Draw;
+using VocaluxeLib.Xml;
namespace VocaluxeLib.Menu
{
diff --git a/VocaluxeLib/Menu/CPlaylist.cs b/VocaluxeLib/Menu/CPlaylist.cs
index b95a5e5d..b56db0b7 100644
--- a/VocaluxeLib/Menu/CPlaylist.cs
+++ b/VocaluxeLib/Menu/CPlaylist.cs
@@ -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
{
diff --git a/VocaluxeLib/Menu/CScreenSetting.cs b/VocaluxeLib/Menu/CScreenSetting.cs
index d2587e78..3990f523 100644
--- a/VocaluxeLib/Menu/CScreenSetting.cs
+++ b/VocaluxeLib/Menu/CScreenSetting.cs
@@ -19,6 +19,7 @@ using System;
using System.Xml;
using System.Xml.Serialization;
using VocaluxeLib.Draw;
+using VocaluxeLib.Xml;
namespace VocaluxeLib.Menu
{
diff --git a/VocaluxeLib/Menu/CSelectSlide.cs b/VocaluxeLib/Menu/CSelectSlide.cs
index 877624c4..8fb8e17b 100644
--- a/VocaluxeLib/Menu/CSelectSlide.cs
+++ b/VocaluxeLib/Menu/CSelectSlide.cs
@@ -20,6 +20,7 @@ using System.Collections.Generic;
using System.Drawing;
using System.Xml.Serialization;
using VocaluxeLib.Draw;
+using VocaluxeLib.Xml;
namespace VocaluxeLib.Menu
{
diff --git a/VocaluxeLib/Menu/CStatic.cs b/VocaluxeLib/Menu/CStatic.cs
index b34d80ac..28888543 100644
--- a/VocaluxeLib/Menu/CStatic.cs
+++ b/VocaluxeLib/Menu/CStatic.cs
@@ -19,6 +19,7 @@ using System;
using System.Xml;
using System.Xml.Serialization;
using VocaluxeLib.Draw;
+using VocaluxeLib.Xml;
namespace VocaluxeLib.Menu
{
diff --git a/VocaluxeLib/Menu/CText.cs b/VocaluxeLib/Menu/CText.cs
index 4cf92c24..b21c92ae 100644
--- a/VocaluxeLib/Menu/CText.cs
+++ b/VocaluxeLib/Menu/CText.cs
@@ -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;
+ }
}
}
\ No newline at end of file
diff --git a/VocaluxeLib/Menu/IMenuElement.cs b/VocaluxeLib/Menu/IMenuElement.cs
index dc805d70..391dd1ad 100644
--- a/VocaluxeLib/Menu/IMenuElement.cs
+++ b/VocaluxeLib/Menu/IMenuElement.cs
@@ -16,6 +16,7 @@
#endregion
using System.Xml;
+using VocaluxeLib.Xml;
namespace VocaluxeLib.Menu
{
diff --git a/VocaluxeLib/Menu/SingNotes/CSingNotes.cs b/VocaluxeLib/Menu/SingNotes/CSingNotes.cs
index bda44a04..276f586b 100644
--- a/VocaluxeLib/Menu/SingNotes/CSingNotes.cs
+++ b/VocaluxeLib/Menu/SingNotes/CSingNotes.cs
@@ -21,6 +21,7 @@ using System.Diagnostics;
using System.Xml.Serialization;
using VocaluxeLib.Draw;
using VocaluxeLib.Songs;
+using VocaluxeLib.Xml;
namespace VocaluxeLib.Menu.SingNotes
{
diff --git a/VocaluxeLib/Menu/SongMenu/CSongMenu.cs b/VocaluxeLib/Menu/SongMenu/CSongMenu.cs
index 529ec03b..1fcb9619 100644
--- a/VocaluxeLib/Menu/SongMenu/CSongMenu.cs
+++ b/VocaluxeLib/Menu/SongMenu/CSongMenu.cs
@@ -17,6 +17,7 @@
using System.Xml;
using VocaluxeLib.PartyModes;
+using VocaluxeLib.Xml;
namespace VocaluxeLib.Menu.SongMenu
{
diff --git a/VocaluxeLib/Menu/SongMenu/CSongMenuFramework.cs b/VocaluxeLib/Menu/SongMenu/CSongMenuFramework.cs
index 0a304a42..84c6a95a 100644
--- a/VocaluxeLib/Menu/SongMenu/CSongMenuFramework.cs
+++ b/VocaluxeLib/Menu/SongMenu/CSongMenuFramework.cs
@@ -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")] ///
+ ///
/// Number of tiles horizontal
///
- public int NumW;
+ [XmlElement("NumW")] public int NumW;
- [XmlElement("NumH")] ///
+ ///
/// Number of tiles vertical
///
- public int NumH;
+ [XmlElement("NumH")] public int NumH;
- [XmlElement("NumWsmall")] ///
+ ///
/// Number of tiles horizontal in small-modus
///
- public int NumWsmall;
+ [XmlElement("NumWsmall")] public int NumWsmall;
- [XmlElement("NumHsmall")] ///
+ ///
/// Number of tiles vertical in small-modus
///
- public int NumHsmall;
+ [XmlElement("NumHsmall")] public int NumHsmall;
- [XmlElement("SpaceW")] ///
+ ///
/// Space between tiles horizontal
///
- public float SpaceW;
+ [XmlElement("SpaceW")] public float SpaceW;
- [XmlElement("SpaceH")] ///
+ ///
/// Space between tiles vertical
///
- 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();
}
diff --git a/VocaluxeLib/Menu/SongMenu/CSongMenuTileBoard.cs b/VocaluxeLib/Menu/SongMenu/CSongMenuTileBoard.cs
index 6a3b1248..4a3d5030 100644
--- a/VocaluxeLib/Menu/SongMenu/CSongMenuTileBoard.cs
+++ b/VocaluxeLib/Menu/SongMenu/CSongMenuTileBoard.cs
@@ -23,6 +23,7 @@ using System.Xml;
using VocaluxeLib.Draw;
using VocaluxeLib.PartyModes;
using VocaluxeLib.Songs;
+using VocaluxeLib.Xml;
namespace VocaluxeLib.Menu.SongMenu
{
diff --git a/VocaluxeLib/PartyModes/CScreenPartyDummy.cs b/VocaluxeLib/PartyModes/CScreenPartyDummy.cs
index 4ac0d76d..26574458 100644
--- a/VocaluxeLib/PartyModes/CScreenPartyDummy.cs
+++ b/VocaluxeLib/PartyModes/CScreenPartyDummy.cs
@@ -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!";
diff --git a/VocaluxeLib/Profile/CProfile.cs b/VocaluxeLib/Profile/CProfile.cs
index cf03f5b0..95ad5d4f 100644
--- a/VocaluxeLib/Profile/CProfile.cs
+++ b/VocaluxeLib/Profile/CProfile.cs
@@ -18,6 +18,7 @@
using System;
using System.IO;
using System.Xml;
+using VocaluxeLib.Xml;
namespace VocaluxeLib.Profile
{
diff --git a/VocaluxeLib/Structs.cs b/VocaluxeLib/Structs.cs
index 4994ed96..5c9f9f3e 100644
--- a/VocaluxeLib/Structs.cs
+++ b/VocaluxeLib/Structs.cs
@@ -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
diff --git a/VocaluxeLib/VocaluxeLib.csproj b/VocaluxeLib/VocaluxeLib.csproj
index 4e3f0354..2f19c850 100644
--- a/VocaluxeLib/VocaluxeLib.csproj
+++ b/VocaluxeLib/VocaluxeLib.csproj
@@ -78,6 +78,7 @@
+
@@ -103,7 +104,8 @@
-
+
+
@@ -139,6 +141,7 @@
+
diff --git a/VocaluxeLib/CXMLReader.cs b/VocaluxeLib/Xml/CXMLReader.cs
similarity index 69%
rename from VocaluxeLib/CXMLReader.cs
rename to VocaluxeLib/Xml/CXMLReader.cs
index 65575e5c..50045800 100644
--- a/VocaluxeLib/CXMLReader.cs
+++ b/VocaluxeLib/Xml/CXMLReader.cs
@@ -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(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 GetNames(string xPath)
{
var values = new List();
diff --git a/VocaluxeLib/Xml/CXmlDeserializer.cs b/VocaluxeLib/Xml/CXmlDeserializer.cs
new file mode 100644
index 00000000..0b202c6b
--- /dev/null
+++ b/VocaluxeLib/Xml/CXmlDeserializer.cs
@@ -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;
+ }
+ }
+}
\ No newline at end of file
diff --git a/VocaluxeLib/Xml/CXmlReaderBase.cs b/VocaluxeLib/Xml/CXmlReaderBase.cs
new file mode 100644
index 00000000..152ecfad
--- /dev/null
+++ b/VocaluxeLib/Xml/CXmlReaderBase.cs
@@ -0,0 +1,61 @@
+using System;
+
+namespace VocaluxeLib.Xml
+{
+ ///
+ /// Base class that provides basic methods for reading xml, while the actual XML implementation is still abstract to allow different implementations
+ ///
+ 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(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);
+ }
+
+ ///
+ /// Gets a normalized (0<=x<=1) float value
+ ///
+ ///
+ ///
+ ///
+ /// True if exists and is normalized
+ 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;
+ }
+ }
+}
\ No newline at end of file