Trying again, refactoring with lambdas. Also adding optional Bitmap Effects

This commit is contained in:
shanselman 2008-06-13 18:16:03 +00:00
Родитель 008f710c28
Коммит 245a8edd27
15 изменённых файлов: 360 добавлений и 563 удалений

Просмотреть файл

@ -1,7 +1,61 @@
<Application x:Class="BabySmash.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Startup="Application_Startup"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:BabySmash="clr-namespace:BabySmash" Startup="Application_Startup"
>
<Application.Resources>
<Style x:Key="BabySmashBaseStyle" TargetType="Shape">
<Setter Property="StrokeThickness" Value="5"/>
<Setter Property="Stroke" Value="Black"/>
</Style>
<Style x:Key="trapezoid" TargetType="Path"
BasedOn="{StaticResource BabySmashBaseStyle}">
<Setter Property="Data" Value="F1 M 257.147,126.953L 543.657,126.953L 640.333,448.287L 160.333,448.287L 257.147,126.953 Z"/>
</Style>
<Style x:Key="star" TargetType="BabySmash:Star"
BasedOn="{StaticResource BabySmashBaseStyle}">
<Setter Property="NumberOfPoints" Value="5"/>
<Setter Property="Width" Value="400"/>
<Setter Property="Height" Value="400"/>
</Style>
<Style x:Key="square" TargetType="Rectangle"
BasedOn="{StaticResource BabySmashBaseStyle}">
<Setter Property="Width" Value="380"/>
<Setter Property="Height" Value="380"/>
</Style>
<Style x:Key="heart" TargetType="Path"
BasedOn="{StaticResource BabySmashBaseStyle}">
<Setter Property="Data" Value="F1 M 429,161.333C 506.333,88.6667 609,142.122 609,225.333C 609,308.544 429,462.667 429,462.667C 429,462.667 257,306.544 257,223.333C 257,140.123 356.138,88.4713 429,161.333 Z"/>
</Style>
<Style x:Key="path" TargetType="Path"
BasedOn="{StaticResource BabySmashBaseStyle}">
</Style>
<Style x:Key="circle" TargetType="Ellipse"
BasedOn="{StaticResource BabySmashBaseStyle}">
<Setter Property="Width" Value="400"/>
<Setter Property="Height" Value="400"/>
</Style>
<Style x:Key="triangle" TargetType="Polygon"
BasedOn="{StaticResource BabySmashBaseStyle}">
<Setter Property="Points" Value="200,50 400,400 0,400 200,50"/>
<Setter Property="Width" Value="400"/>
<Setter Property="Height" Value="400"/>
</Style>
<Style x:Key="rectangle" TargetType="Rectangle"
BasedOn="{StaticResource BabySmashBaseStyle}">
<Setter Property="Width" Value="380"/>
<Setter Property="Height" Value="160"/>
</Style>
</Application.Resources>
</Application>

Просмотреть файл

@ -6,96 +6,88 @@ using WinForms = System.Windows.Forms;
namespace BabySmash
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
private static IntPtr _hookID = IntPtr.Zero;
static InterceptKeys.LowLevelKeyboardProc _proc = HookCallback;
MainWindow mainWindow = null;
public App()
: base()
{
try
{
_hookID = InterceptKeys.SetHook(_proc);
this.ShutdownMode = ShutdownMode.OnLastWindowClose; //TODO: Should this be OnMainWindowClose?
mainWindow = new MainWindow();
MainWindow.WindowState = WindowState.Maximized; //Do it here, rather than in XAML otherwise multimon won't work.
mainWindow.Show();
}
catch (Exception e)
{
if (_hookID != null) //TODO: Logging?
InterceptKeys.UnhookWindowsHookEx(_hookID);
}
}
private void Application_Startup(object sender, StartupEventArgs e)
{
////UNDONE: Make a Window instance for each screen, position them, show them, then maximize them.
////TODO: Now, how to respond to events on all screens at once?
//foreach (WinForms.Screen s in WinForms.Screen.AllScreens)
//{
// if (s.Primary == false)
// {
// Window1 w = new Window1();
// w.WindowStartupLocation = WindowStartupLocation.Manual; //key!
// Debug.Write("Found screen: " + s.DeviceName);
// w.Left = s.WorkingArea.Left;
// Debug.Write(" Left: " + s.WorkingArea.Left);
// w.Top = s.WorkingArea.Top;
// Debug.Write(" Top: " + s.WorkingArea.Top);
// w.Width = s.WorkingArea.Width;
// Debug.Write(" Width: " + s.WorkingArea.Width);
// w.Height = s.WorkingArea.Height;
// Debug.Write("Height: " + s.WorkingArea.Height);
// w.WindowStyle = WindowStyle.None;
// w.Topmost = true;
// w.Owner = mainWindow;
// w.Show();
// w.WindowState = WindowState.Maximized;
// }
// mainWindow.Focus();
//};
mainWindow.Focus();
}
public static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0)
{
//Prevent ALT-TAB and CTRL-ESC by eating TAB and ESC. Also kill Windows Keys.
int vkCode = Marshal.ReadInt32(lParam);
if ((WinForms.Keys)vkCode == WinForms.Keys.LWin ||
(WinForms.Keys)vkCode == WinForms.Keys.RWin)
public partial class App : Application
{
private static IntPtr _hookID = IntPtr.Zero;
static InterceptKeys.LowLevelKeyboardProc _proc = HookCallback;
readonly MainWindow mainWindow = null;
public App()
{
try
{
return (IntPtr)1; //handled
_hookID = InterceptKeys.SetHook(_proc);
ShutdownMode = ShutdownMode.OnLastWindowClose; //TODO: Should this be OnMainWindowClose?
mainWindow = new MainWindow();
//MainWindow.WindowState = WindowState.Maximized; //Do it here, rather than in XAML otherwise multimon won't work.
mainWindow.Show();
}
bool Alt = (System.Windows.Forms.Control.ModifierKeys & WinForms.Keys.Alt) != 0;
bool Control = (System.Windows.Forms.Control.ModifierKeys & WinForms.Keys.Control) != 0;
if (Alt && (WinForms.Keys)vkCode == WinForms.Keys.Tab)
catch
{
return (IntPtr)1; //handled
if (_hookID != IntPtr.Zero)
InterceptKeys.UnhookWindowsHookEx(_hookID);
}
}
if (Alt && (WinForms.Keys)vkCode == WinForms.Keys.Space)
private void Application_Startup(object sender, StartupEventArgs e)
{
////UNDONE: Make a Window instance for each screen, position them, show them, then maximize them.
////TODO: Now, how to respond to events on all screens at once?
//foreach (WinForms.Screen s in WinForms.Screen.AllScreens)
//{
// if (s.Primary == false)
// {
// Window1 w = new Window1();
// w.WindowStartupLocation = WindowStartupLocation.Manual; //key!
// Debug.Write("Found screen: " + s.DeviceName);
// w.Left = s.WorkingArea.Left;
// Debug.Write(" Left: " + s.WorkingArea.Left);
// w.Top = s.WorkingArea.Top;
// Debug.Write(" Top: " + s.WorkingArea.Top);
// w.Width = s.WorkingArea.Width;
// Debug.Write(" Width: " + s.WorkingArea.Width);
// w.Height = s.WorkingArea.Height;
// Debug.Write("Height: " + s.WorkingArea.Height);
// w.WindowStyle = WindowStyle.None;
// w.Topmost = true;
// w.Owner = mainWindow;
// w.Show();
// w.WindowState = WindowState.Maximized;
// }
// mainWindow.Focus();
//};
mainWindow.Focus();
}
public static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0)
{
Debug.WriteLine("ATE ALT-SPACE: " + (WinForms.Keys)vkCode);
return (IntPtr)1; //handled
}
bool Alt = (System.Windows.Forms.Control.ModifierKeys & WinForms.Keys.Alt) != 0;
bool Control = (System.Windows.Forms.Control.ModifierKeys & WinForms.Keys.Control) != 0;
if (Control && (WinForms.Keys)vkCode == WinForms.Keys.Escape)
{
return (IntPtr)1; //handled
//Prevent ALT-TAB and CTRL-ESC by eating TAB and ESC. Also kill Windows Keys.
int vkCode = Marshal.ReadInt32(lParam);
if ((WinForms.Keys)vkCode == WinForms.Keys.LWin ||
(WinForms.Keys)vkCode == WinForms.Keys.RWin)
{
return (IntPtr)1; //handled
}
if (Alt && (WinForms.Keys)vkCode == WinForms.Keys.Tab)
{
return (IntPtr)1; //handled
}
if (Alt && (WinForms.Keys)vkCode == WinForms.Keys.Space)
{
return (IntPtr)1; //handled
}
if (Control && (WinForms.Keys)vkCode == WinForms.Keys.Escape)
{
return (IntPtr)1; //handled
}
}
//Debug.WriteLine("HOOKED: " + (WinForms.Keys)vkCode);
}
return InterceptKeys.CallNextHookEx(_hookID, nCode, wParam, lParam);
}
return InterceptKeys.CallNextHookEx(_hookID, nCode, wParam, lParam);
}
}
}
}

Просмотреть файл

@ -133,13 +133,12 @@
<Compile Include="Settings.cs" />
<Compile Include="Shapes\Figure.cs" />
<Compile Include="Shapes\FigureGenerator.cs" />
<Compile Include="Shapes\HiResTextBlock.cs" />
<Compile Include="Shapes\ShapeFactory.cs" />
<Compile Include="Shapes\Star.cs" />
<Compile Include="Utils.cs" />
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<None Include="app.config" />
<None Include="BabySmash_TemporaryKey.pfx" />

Просмотреть файл

@ -10,13 +10,11 @@
<local:FigureGenerator x:Key="figureGenerator"/>
</Window.Resources>
<Grid>
<Canvas x:Name="MainCanvas">
<TextBlock>
BabySmash by Scott Hanselman
<Hyperlink RequestNavigate="HelpUrlNavigated" NavigateUri="http://www.babysmash.com">http://www.babysmash.com</Hyperlink>
<LineBreak />Ctrl-Shift-Alt-O for options, ALT-F4 to exit</TextBlock>
<TextBlock>
BabySmash by Scott Hanselman
<Hyperlink RequestNavigate="HelpUrlNavigated" NavigateUri="http://www.babysmash.com">http://www.babysmash.com</Hyperlink>
<LineBreak />Ctrl-Shift-Alt-O for options, ALT-F4 to exit</TextBlock>
</Canvas>
<ItemsControl Name="figures" ItemsSource="{Binding Source={StaticResource figureGenerator},Path=Figures}">
<ItemsControl.ItemTemplate>
<DataTemplate>

Просмотреть файл

@ -1,13 +1,7 @@
using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using WinForms = System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Threading;
using System.Windows.Media.Animation;
using System.Windows.Navigation;
using System.Speech.Synthesis;
using System.Collections.Specialized;
@ -18,14 +12,13 @@ namespace BabySmash
{
public partial class MainWindow : Window
{
private int numberOfShapes = 0;
private SpeechSynthesizer objSpeech = null;
private FigureGenerator figureGenerator;
private SpeechSynthesizer objSpeech;
private readonly FigureGenerator figureGenerator;
public MainWindow()
{
InitializeComponent();
figureGenerator = (FigureGenerator)this.Resources["figureGenerator"];
figureGenerator = (FigureGenerator)Resources["figureGenerator"];
figureGenerator.ClearAfter = Properties.Settings.Default.ClearAfter;
ICollectionView collectionView = CollectionViewSource.GetDefaultView(figureGenerator.Figures);
collectionView.CollectionChanged += FiguresCollectionChanged;
@ -47,17 +40,22 @@ namespace BabySmash
public double ShapeLeft
{
//TODO: Feels weird...we need to know the actualwidth of the canvas and of the figure....
// ideally: Utils.RandomBetweenTwoNumbers(0, Convert.ToInt32(canvas.ActualWidth - figure.ActualWidth)
// ideally: Utils.RandomBetweenTwoNumbers(0,
// Convert.ToInt32(canvas.ActualWidth - figure.ActualWidth)
// Perhaps this belongs elsewhere?
get { return Utils.RandomBetweenTwoNumbers(-100, Convert.ToInt32(figures.ActualWidth) - 200); }
get { return Utils.RandomBetweenTwoNumbers(-100,
Convert.ToInt32(figures.ActualWidth) - 200); }
}
public double ShapeTop
{
//TODO: Feels weird...we need to know the actualwidth of the canvas and of the figure....
// ideally: Utils.RandomBetweenTwoNumbers(0, Convert.ToInt32(canvas.ActualWidth - figure.ActualWidth)
// ideally: Utils.RandomBetweenTwoNumbers(0,
// Convert.ToInt32(canvas.ActualWidth - figure.ActualWidth)
// Perhaps this belongs elsewhere?
get { return Utils.RandomBetweenTwoNumbers(-100, Convert.ToInt32(figures.ActualHeight) - 300); }
get { return Utils.RandomBetweenTwoNumbers(
-100,
Convert.ToInt32(figures.ActualHeight) - 300); }
}
private void Window_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
@ -70,25 +68,18 @@ namespace BabySmash
//TODO: Might be able to remove this: http://www.ageektrapped.com/blog/using-commands-in-babysmash/
if (Alt && Control && Shift && e.Key == Key.O)
{
Options o = new Options();
var o = new Options();
o.ShowDialog();
e.Handled = true;
return;
}
numberOfShapes++;
if (numberOfShapes > Properties.Settings.Default.ClearAfter)
{
numberOfShapes = 1;
MainCanvas.Children.Clear();
}
string s = e.Key.ToString();
if (s.Length == 2 && s[0] == 'D') s = s[1].ToString(); //HACK: WTF? Numbers start with a "D?" as in D1?
figureGenerator.Generate(this, s);
}
private void PlayLaughter()
private static void PlayLaughter()
{
if (Properties.Settings.Default.Sounds == "Laughter")
{
@ -98,13 +89,12 @@ namespace BabySmash
private void SpeakString(string s)
{
if (objSpeech != null && Properties.Settings.Default.Sounds == "Speech")
{
objSpeech.SpeakAsyncCancelAll();
objSpeech.Rate = -1;
objSpeech.Volume = 100;
objSpeech.SpeakAsync(s);
}
if (objSpeech == null || Properties.Settings.Default.Sounds != "Speech") return;
objSpeech.SpeakAsyncCancelAll();
objSpeech.Rate = -1;
objSpeech.Volume = 100;
objSpeech.SpeakAsync(s);
}
private void HelpUrlNavigated(object sender, RequestNavigateEventArgs e)
@ -117,7 +107,7 @@ namespace BabySmash
objSpeech = new SpeechSynthesizer();
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
private void Window_Closing(object sender, CancelEventArgs e)
{
Application.Current.Shutdown();
}

Просмотреть файл

@ -4,7 +4,7 @@
xmlns:local="clr-namespace:BabySmash.Properties"
xmlns:l="clr-namespace:BabySmash"
Title="Baby Smash! - Options"
Height="196" Width="268"
Height="210" Width="268"
ShowInTaskbar="True"
Topmost="True"
WindowStartupLocation="CenterScreen"
@ -22,6 +22,7 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
@ -45,7 +46,11 @@
IsChecked="{Binding Path=Default.FadeAway,Mode=TwoWay}" >
Fade Away
</CheckBox>
<StackPanel Orientation="Horizontal" Grid.Row="4" Grid.ColumnSpan="2" HorizontalAlignment="Right">
<CheckBox Grid.Row="4" Grid.Column="1" Margin="15,0,0,0"
IsChecked="{Binding Path=Default.BitmapEffects,Mode=TwoWay}" >
Bitmap Effects
</CheckBox>
<StackPanel Orientation="Horizontal" Grid.Row="5" Grid.ColumnSpan="2" HorizontalAlignment="Right">
<Button Name="okButton" IsDefault="True" Margin="0,7,10,7" Padding="30,0,30,0" Click="OK_Click" >OK</Button>
<Button IsCancel="True" Margin="5,7,7,7" Padding="15,0,15,0" Click="Cancel_Click" Width="77">Cancel</Button>
</StackPanel>

Просмотреть файл

@ -12,13 +12,13 @@ namespace BabySmash
private void OK_Click(object sender, RoutedEventArgs e)
{
Properties.Settings.Default.Save();
this.Close();
Close();
}
private void Cancel_Click(object sender, RoutedEventArgs e)
{
Properties.Settings.Default.Reload();
this.Close();
Close();
}
}
}

12
Properties/Settings.Designer.cs сгенерированный
Просмотреть файл

@ -70,5 +70,17 @@ namespace BabySmash.Properties {
this["FadeAway"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool BitmapEffects {
get {
return ((bool)(this["BitmapEffects"]));
}
set {
this["BitmapEffects"] = value;
}
}
}
}

Просмотреть файл

@ -14,5 +14,8 @@
<Setting Name="FadeAway" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="BitmapEffects" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
</Settings>
</SettingsFile>

Просмотреть файл

@ -2,179 +2,122 @@ using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Shapes;
using Drawing = System.Drawing;
using System.Globalization;
namespace BabySmash
{
public abstract class Figure
{
private UIElement shape;
private readonly string name;
private readonly string color;
protected Figure(Brush fill, string name)
protected Figure(Brush fill, string name, Shape s)
{
this.color = Utils.BrushToString(fill);
this.name = name;
this.Shape = s;
s.Fill = fill;
s.Style = Application.Current.Resources[Name] as Style;
}
public UIElement Shape
{
get { return shape; }
protected set { shape = value; }
}
public UIElement Shape { get; protected set; }
public string Name { get { return name; } }
public string Color { get { return color; } }
}
public class LetterFigure : Figure
{
public LetterFigure(Brush fill, string name)
: base(fill, name)
{
string nameToDisplay;
if (Properties.Settings.Default.ForceUppercase)
{
nameToDisplay = name;
}
else
{
if (Utils.GetRandomBoolean())
nameToDisplay = name;
else
nameToDisplay = name.ToLowerInvariant();
}
Shape = DrawCharacter(400, nameToDisplay, fill);
}
private UIElement DrawCharacter(double fontSize, string textString, Brush brush)
{
HiResTextBlock textBlock = new HiResTextBlock()
{
FontSize = fontSize, //pick better size
Fill = brush,
Text = textString,
StrokeThickness = 5,
};
return textBlock;
}
}
public class SquareFigure : Figure
{
public SquareFigure(Brush fill)
: base(fill, "square")
{
Shape = new Rectangle()
{
Fill = fill,
Height = 380,
Width = 380,
StrokeThickness = 5,
Stroke = Brushes.Black,
};
}
public SquareFigure(Brush fill)
: base(fill, "square", new Rectangle()){}
}
public class RectangleFigure : Figure
{
public RectangleFigure(Brush fill)
: base(fill, "rectangle")
{
Shape = new Rectangle()
{
Fill = fill,
Height = 160,
Width = 380,
StrokeThickness = 5,
Stroke = Brushes.Black,
};
}
: base(fill, "rectangle", new Rectangle()){}
}
public class CircleFigure : Figure
{
public CircleFigure(Brush fill)
: base(fill, "circle")
{
Shape = new Ellipse()
{
Fill = fill,
Height = 400,
Width = 400,
StrokeThickness = 5,
Stroke = Brushes.Black,
};
}
: base(fill, "circle", new Ellipse()){}
}
public class TriangleFigure : Figure
{
public TriangleFigure(Brush fill)
: base(fill, "triangle")
{
Shape = new Polygon()
{
Points = new PointCollection(new Point[]{
new Point(200,50),
new Point(400,400),
new Point(0,400),
new Point(200,50)}),
Height = 400,
Width = 400,
Fill = fill,
StrokeThickness = 5,
Stroke = Brushes.Black,
};
}
: base(fill, "triangle", new Polygon()){}
}
public class StarFigure : Figure
{
public StarFigure(Brush fill)
: base(fill, "star")
{
Shape = new Star()
{
NumberOfPoints = 5,
Height = 400,
Width = 400,
Fill = fill,
StrokeThickness = 5,
Stroke = Brushes.Black,
};
}
: base(fill, "star", new Star()){}
}
public class TrapezoidFigure : Figure
{
public TrapezoidFigure(Brush fill)
: base(fill, "trapezoid")
: base(fill, "trapezoid", new Path())
{
Shape = new Path()
{
Data = Geometry.Parse("F1 M 257.147,126.953L 543.657,126.953L 640.333,448.287L 160.333,448.287L 257.147,126.953 Z "),
Fill = fill,
Stroke = Brushes.Black,
StrokeThickness = 5,
};
}
}
public class HeartFigure : Figure
{
public HeartFigure(Brush fill)
: base(fill, "heart")
{
Shape = new Path()
{
Data = Geometry.Parse("F1 M 429,161.333C 506.333,88.6667 609,142.122 609,225.333C 609,308.544 429,462.667 429,462.667C 429,462.667 257,306.544 257,223.333C 257,140.123 356.138,88.4713 429,161.333 Z "),
Fill = fill,
Stroke = Brushes.Black,
StrokeThickness = 5,
};
}
: base(fill, "heart", new Path())
{}
}
}
public class LetterFigure : Figure
{
public LetterFigure(Brush fill, string name)
: base(fill, "BabySmashBaseStyle",
new Path()
{
Data = MakeCharacterGeometry(
GetLetterCharacter(name)),
Height = 400
}
)
{
}
private static string GetLetterCharacter(string name)
{
string nameToDisplay;
if (Properties.Settings.Default.ForceUppercase)
{
nameToDisplay = name;
}
else
{
nameToDisplay = Utils.GetRandomBoolean() ? name : name.ToLowerInvariant();
}
return nameToDisplay;
}
private static Geometry MakeCharacterGeometry(string t)
{
FormattedText fText = new FormattedText(
t,
CultureInfo.CurrentCulture,
FlowDirection.LeftToRight,
new Typeface(
new FontFamily("Arial"),
FontStyles.Normal,
FontWeights.Heavy,
FontStretches.Normal),
300,
Brushes.Black
);
return fText.BuildGeometry(new Point(0, 0)).GetAsFrozen() as Geometry;
}
}
}

Просмотреть файл

@ -4,89 +4,104 @@ using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Media.Effects;
using System.Windows.Shapes;
using System.Windows.Media;
using System.Windows.Media.Animation;
using BabySmash;
namespace BabySmash
{
public class FigureGenerator
{
private int clearAfter;
private readonly ObservableCollection<Figure> figures = new ObservableCollection<Figure>();
public int ClearAfter
{
get { return clearAfter; }
set { clearAfter = value; }
}
public class FigureGenerator
{
private int clearAfter;
private readonly ObservableCollection<Figure> figures = new ObservableCollection<Figure>();
public ObservableCollection<Figure> Figures
{
get { return figures; }
}
public int ClearAfter
{
get { return clearAfter; }
set { clearAfter = value; }
}
public void Generate(FrameworkElement container, string letter)
{
if (figures.Count == clearAfter)
figures.Clear();
Figure f = GenerateFigure(letter);
Storyboard s = CreateStoryboardAnimation(container, f.Shape, Shape.OpacityProperty);
figures.Add(f);
if (Properties.Settings.Default.FadeAway) s.Begin(container);
}
public ObservableCollection<Figure> Figures
{
get { return figures; }
}
private Storyboard CreateStoryboardAnimation(FrameworkElement container, UIElement shape, DependencyProperty dp)
{
Storyboard st = new Storyboard();
NameScope.SetNameScope(container, new NameScope());
container.RegisterName("shape", shape);
public void Generate(FrameworkElement container, string letter)
{
if (figures.Count == clearAfter)
figures.Clear();
Figure f = GenerateFigure(letter);
Storyboard s = CreateStoryboardAnimation(container, f.Shape, Shape.OpacityProperty);
DoubleAnimation d = new DoubleAnimation();
d.From = 1.0;
d.To = 0.0;
d.Duration = new Duration(TimeSpan.FromSeconds(5));
d.AutoReverse = false;
//We'll wait for Hardware Accelerated Shader Effects in SP1
if (Properties.Settings.Default.BitmapEffects)
f.Shape.BitmapEffect = GetRandomBitmapEffect();
st.Children.Add(d);
Storyboard.SetTargetName(d, "shape");
Storyboard.SetTargetProperty(d, new PropertyPath(dp));
return st;
}
figures.Add(f);
if (Properties.Settings.Default.FadeAway) s.Begin(container);
}
private Figure GenerateFigure(string letter)
{
//TODO: Should this be in XAML? Would that make it better?
Brush fill = Utils.GetRandomColoredBrush();
if (letter.Length == 1 && Char.IsLetterOrDigit(letter[0]))
{
return new LetterFigure(fill, letter);
}
else
{
int shape = Utils.RandomBetweenTwoNumbers(0, 6);
//TODO: Should I change the height, width and stroke to be relative to the screen size?
//TODO: I think I need a shapefactory?
//TODO: Where can I get REALLY complex shapes like animal vectors or custom pics? Where do I store them?
switch (shape)
private BitmapEffect GetRandomBitmapEffect()
{
int e = Utils.RandomBetweenTwoNumbers(0, 3);
switch (e)
{
case 0:
return new SquareFigure(fill);
case 1:
return new CircleFigure(fill);
case 2:
return new TriangleFigure(fill);
case 3:
return new StarFigure(fill);
case 4:
return new HeartFigure(fill);
case 5:
return new TrapezoidFigure(fill);
case 6:
return new RectangleFigure(fill);
case 0:
return new BevelBitmapEffect();
case 1:
return new DropShadowBitmapEffect();
case 2:
return new EmbossBitmapEffect();
case 3:
return new OuterGlowBitmapEffect();
}
}
return null;
}
}
return new BevelBitmapEffect();
}
private static Storyboard CreateStoryboardAnimation(FrameworkElement container, UIElement shape, DependencyProperty dp)
{
var st = new Storyboard();
NameScope.SetNameScope(container, new NameScope());
container.RegisterName("shape", shape);
var d = new DoubleAnimation();
d.From = 1.0;
d.To = 0.0;
d.Duration = new Duration(TimeSpan.FromSeconds(7));
d.AutoReverse = false;
st.Children.Add(d);
Storyboard.SetTargetName(d, "shape");
Storyboard.SetTargetProperty(d, new PropertyPath(dp));
return st;
}
//TODO: Should this be in XAML? Would that make it better?
//TODO: Should I change the height, width and stroke to be relative to the screen size?
//TODO: Where can I get REALLY complex shapes like animal vectors or custom pics? Where do I store them?
private static readonly List<Func<Brush, Figure>> listOfPotentialFigures = new List<Func<Brush, Figure>>
{
x => new SquareFigure(x),
x => new CircleFigure(x),
x => new TriangleFigure(x),
x => new StarFigure(x),
x => new HeartFigure(x),
x => new TrapezoidFigure(x),
x => new RectangleFigure(x)
};
private static Figure GenerateFigure(string letter)
{
var fill = Utils.GetRandomColoredBrush();
if (letter.Length == 1 && Char.IsLetterOrDigit(letter[0]))
return new LetterFigure(fill, letter);
var myFunc = listOfPotentialFigures[
Utils.RandomBetweenTwoNumbers(0, listOfPotentialFigures.Count - 1)];
return myFunc(fill);
}
}
}

Просмотреть файл

@ -1,207 +0,0 @@
using System.Globalization;
using System.Windows;
using System.Windows.Media;
namespace BabySmash
{
class HiResTextBlock : FrameworkElement
{
public HiResTextBlock()
: base()
{
RenderOptions.SetEdgeMode(this, EdgeMode.Unspecified);
this.SnapsToDevicePixels = true;
}
Geometry m_textg;
static Pen m_pen;
protected override void OnRender(DrawingContext drawingContext)
{
drawingContext.DrawGeometry(Fill, m_pen, m_textg);
}
private static void OnTextInvalidated(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
m_pen = new Pen(((HiResTextBlock)d).Stroke, ((HiResTextBlock)d).StrokeThickness);
m_pen.LineJoin = PenLineJoin.Round;
m_pen.MiterLimit = 1;
m_pen = m_pen.GetAsFrozen() as Pen;
((HiResTextBlock)d).GenerateText();
}
private void GenerateText()
{
if (Font == null)
Font = new FontFamily("Arial");
FormattedText fText = new FormattedText(
Text,
CultureInfo.CurrentCulture,
FlowDirection.LeftToRight,
new Typeface(
Font,
FontStyles.Normal,
FontWeights.Heavy,
FontStretches.Normal),
FontSize,
Brushes.Black
);
m_textg = fText.BuildGeometry(new Point(0, 0)).GetAsFrozen() as Geometry;
}
#region DPs
public Brush Stroke
{
get
{
return (Brush)GetValue(StrokeProperty);
}
set
{
SetValue(StrokeProperty, value);
}
}
public static readonly DependencyProperty StrokeProperty = DependencyProperty.Register(
"Stroke",
typeof(Brush),
typeof(HiResTextBlock),
new FrameworkPropertyMetadata(
new SolidColorBrush(Colors.Black),
FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(OnTextInvalidated),
null
)
);
public ushort StrokeThickness
{
get
{
return (ushort)GetValue(StrokeThicknessProperty);
}
set
{
SetValue(StrokeThicknessProperty, value);
}
}
public static readonly DependencyProperty StrokeThicknessProperty = DependencyProperty.Register(
"StrokeThickness",
typeof(ushort),
typeof(HiResTextBlock),
new FrameworkPropertyMetadata(
(ushort)1,
FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(OnTextInvalidated),
null
)
);
public string Text
{
get
{
return (string)GetValue(TextProperty);
}
set
{
SetValue(TextProperty, value);
}
}
public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
"Text",
typeof(string),
typeof(HiResTextBlock),
new FrameworkPropertyMetadata(
"",
FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(OnTextInvalidated),
null
)
);
public double FontSize
{
get
{
return (double)GetValue(FontSizeProperty);
}
set
{
SetValue(FontSizeProperty, value);
}
}
public static readonly DependencyProperty FontSizeProperty = DependencyProperty.Register(
"FontSize",
typeof(double),
typeof(HiResTextBlock),
new FrameworkPropertyMetadata(
(double)12,
FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(OnTextInvalidated),
null
)
);
public Brush Fill
{
get
{
return (Brush)GetValue(FillProperty);
}
set
{
SetValue(FillProperty, value);
}
}
public static readonly DependencyProperty FillProperty = DependencyProperty.Register(
"Fill",
typeof(Brush),
typeof(HiResTextBlock),
new FrameworkPropertyMetadata(
new SolidColorBrush(Colors.White),
FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(OnTextInvalidated),
null
)
);
public FontFamily Font
{
get
{
return (FontFamily)GetValue(FontProperty);
}
set
{
SetValue(FontProperty, value);
}
}
public static readonly DependencyProperty FontProperty = DependencyProperty.Register(
"Font",
typeof(FontFamily),
typeof(HiResTextBlock),
new FrameworkPropertyMetadata(
new FontFamily("Arial"),
FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(OnTextInvalidated),
null
)
);
#endregion
}
}

Просмотреть файл

@ -27,23 +27,18 @@ namespace BabySmash
public Geometry CreateStarGeometry(int numberOfPoints)
{
GeometryGroup group = new GeometryGroup();
group.FillRule = FillRule.Nonzero;
Geometry triangle = PathGeometry.Parse("M 0,-300 L 90,90 -90,90 0,-300");
group.Children.Add(triangle);
double deltaAngle = 360 / numberOfPoints;
double currentAngle = 0;
for (int index = 1; index < numberOfPoints; index++)
{
currentAngle += deltaAngle;
triangle = triangle.CloneCurrentValue();
triangle.Transform = new RotateTransform(currentAngle, 0, 0);
group.Children.Add(triangle);
}
Geometry outlinePath = group.GetOutlinedPathGeometry();
return outlinePath;
const double outerRadius = 300;
const double innerRadius = 90;
Point[] points = new Point[numberOfPoints * 2 - 1];
for (int i = 0; i < numberOfPoints * 2 - 1; ++i)
{
double radius = ((i & 1) == 0) ? innerRadius : outerRadius;
double angle = Math.PI * (i + 1) / numberOfPoints;
points[i] = new Point(radius * Math.Sin(angle), -radius * Math.Cos(angle));
}
PolyLineSegment segment = new PolyLineSegment(points, true);
PathFigure starFigure = new PathFigure(new Point(0, -outerRadius), new PathSegment[] { segment }, true);
return new PathGeometry(new PathFigure[] { starFigure });
}
}
}

Просмотреть файл

@ -1,6 +1,4 @@
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Collections.Generic;
@ -8,18 +6,9 @@ namespace BabySmash
{
class Utils
{
private static Brush[] someBrushes = { Brushes.Red,
Brushes.Blue,
Brushes.Yellow,
Brushes.Green,
Brushes.Purple,
Brushes.Pink,
Brushes.Orange,
Brushes.Tan,
Brushes.Gray};
private static Dictionary<Brush, string> brushToString = new Dictionary<Brush, string> {
{ Brushes.Red, "Red" },
static Utils()
{
brushToString = new Dictionary<Brush, string> { { Brushes.Red, "Red" },
{ Brushes.Blue, "Blue" },
{ Brushes.Yellow, "Yellow" },
{ Brushes.Green, "Green" },
@ -30,7 +19,14 @@ namespace BabySmash
{ Brushes.Gray, "Gray" }
};
private static string[] sounds = { "giggle.wav",
someBrushes = new Brush[brushToString.Count];
brushToString.Keys.CopyTo(someBrushes, 0);
}
private static Brush[] someBrushes;
private static Dictionary<Brush, string> brushToString;
private static readonly string[] sounds = { "giggle.wav",
"babylaugh.wav",
"babygigl2.wav",
"ccgiggle.wav",
@ -58,11 +54,10 @@ namespace BabySmash
{
if (lRandom.Next(0, 2) == 0)
return false;
else
return true;
return true;
}
private static Random lRandom = new Random();
private static readonly Random lRandom = new Random();
public static int RandomBetweenTwoNumbers(int min, int max)
{

Просмотреть файл

@ -8,7 +8,7 @@
<userSettings>
<BabySmash.Properties.Settings>
<setting name="ClearAfter" serializeAs="String">
<value>20</value>
<value>30</value>
</setting>
<setting name="ForceUppercase" serializeAs="String">
<value>True</value>
@ -19,6 +19,9 @@
<setting name="FadeAway" serializeAs="String">
<value>True</value>
</setting>
<setting name="BitmapEffects" serializeAs="String">
<value>False</value>
</setting>
</BabySmash.Properties.Settings>
</userSettings>
</configuration>