2009-04-20 09:20:25 +02:00
|
|
|
|
using System;
|
2009-04-20 11:48:33 +02:00
|
|
|
|
using System.Diagnostics;
|
2009-04-20 09:20:25 +02:00
|
|
|
|
using System.Drawing;
|
2009-04-20 11:48:33 +02:00
|
|
|
|
using System.Drawing.Text;
|
2009-04-20 09:20:25 +02:00
|
|
|
|
using System.Reflection;
|
2009-04-20 11:48:33 +02:00
|
|
|
|
using System.Windows.Forms;
|
2009-04-20 09:20:25 +02:00
|
|
|
|
using Examples.Properties;
|
|
|
|
|
|
|
|
|
|
namespace Examples
|
|
|
|
|
{
|
|
|
|
|
public partial class ExampleBrowser : Form
|
|
|
|
|
{
|
|
|
|
|
#region Fields
|
|
|
|
|
|
|
|
|
|
PrivateFontCollection font_collection = new PrivateFontCollection();
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Constructors
|
|
|
|
|
|
|
|
|
|
public ExampleBrowser()
|
|
|
|
|
{
|
|
|
|
|
Font = SystemFonts.DialogFont;
|
|
|
|
|
|
|
|
|
|
InitializeComponent();
|
|
|
|
|
|
|
|
|
|
// Windows 6 (Vista) and higher come with Consolas, a high-quality monospace font. Use that or fallback to the generic
|
|
|
|
|
// monospace font on other systems.
|
|
|
|
|
if (System.Environment.OSVersion.Platform == PlatformID.Win32NT && System.Environment.OSVersion.Version.Major >= 6)
|
|
|
|
|
{
|
|
|
|
|
richTextBoxSource.Font = new Font("Consolas", 10.0f, FontStyle.Regular);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
richTextBoxSource.Font = new Font(FontFamily.GenericMonospace, 10.0f, FontStyle.Regular);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Protected Members
|
|
|
|
|
|
|
|
|
|
protected override void OnLoad(EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
base.OnLoad(e);
|
2009-04-20 11:48:33 +02:00
|
|
|
|
|
2009-04-20 09:20:25 +02:00
|
|
|
|
Debug.Listeners.Add(new TextBoxTraceListener(textBoxOutput));
|
|
|
|
|
treeViewSamples.TreeViewNodeSorter = new SamplesTreeViewSorter();
|
2009-04-20 11:48:33 +02:00
|
|
|
|
|
|
|
|
|
LoadSamplesFromAssembly(Assembly.GetExecutingAssembly());
|
2009-04-20 09:20:25 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Private Members
|
|
|
|
|
|
|
|
|
|
#region Events
|
|
|
|
|
|
|
|
|
|
#region TreeView
|
|
|
|
|
|
|
|
|
|
private void treeViewSamples_AfterSelect(object sender, TreeViewEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (e.Node.Tag != null && !String.IsNullOrEmpty(((ExampleInfo)e.Node.Tag).Attribute.Documentation))
|
|
|
|
|
{
|
|
|
|
|
richTextBoxDescription.Rtf = (string)Resources.ResourceManager.GetObject(((ExampleInfo)e.Node.Tag).Attribute.Documentation + "Doc");
|
|
|
|
|
richTextBoxSource.Text = (string)Resources.ResourceManager.GetObject(((ExampleInfo)e.Node.Tag).Attribute.Documentation);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
richTextBoxDescription.Rtf = String.Empty;
|
2009-04-20 11:48:33 +02:00
|
|
|
|
richTextBoxDescription.Text = "Documentation has not been entered.";
|
2009-04-20 09:20:25 +02:00
|
|
|
|
richTextBoxSource.Rtf = String.Empty;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void treeViewSamples_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (e.Node.Tag != null)
|
|
|
|
|
{
|
|
|
|
|
ActivateNode(e.Node);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void treeViewSamples_KeyDown(object sender, KeyEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
// The enter key activates a node (either expands/collapses or executes its sample).
|
|
|
|
|
switch (e.KeyCode)
|
|
|
|
|
{
|
|
|
|
|
case Keys.Enter:
|
|
|
|
|
ActivateNode(treeViewSamples.SelectedNode);
|
|
|
|
|
e.Handled = true;
|
|
|
|
|
e.SuppressKeyPress = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void treeViewSamples_MouseDown(object sender, MouseEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
// Make sure that right-clicking a new node will select that node before displaying
|
|
|
|
|
// the context menu. Without this, right-clicking a node does not select it, which
|
|
|
|
|
// is completely disorienting.
|
|
|
|
|
// As a bonus, make any mouse button select the underlying node,
|
|
|
|
|
TreeNode node = treeViewSamples.HitTest(e.Location).Node;
|
|
|
|
|
if (node != null)
|
|
|
|
|
treeViewSamples.SelectedNode = node;
|
|
|
|
|
|
|
|
|
|
// Middle click selects and activates a node (either expands/collapses or executes its sample).
|
|
|
|
|
// Right button displays the context menu.
|
|
|
|
|
// All other mouse buttons simply select the underlying node.
|
|
|
|
|
switch (e.Button)
|
|
|
|
|
{
|
|
|
|
|
case MouseButtons.Middle:
|
|
|
|
|
ActivateNode(node);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case MouseButtons.Right:
|
|
|
|
|
treeViewSamples.ContextMenuStrip.Show(sender as Control, e.Location);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void treeViewSamples_AfterExpand(object sender, TreeViewEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
foreach (TreeNode child in e.Node.Nodes)
|
|
|
|
|
child.EnsureVisible();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void contextMenuStripSamples_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
switch (e.ClickedItem.Text)
|
|
|
|
|
{
|
|
|
|
|
case "&Run Sample": RunSample(this, (ExampleInfo)treeViewSamples.SelectedNode.Tag); break;
|
|
|
|
|
case "View Description": tabControlSample.SelectedTab = tabDescription; break;
|
|
|
|
|
case "View Source Code": tabControlSample.SelectedTab = tabSource; break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Description
|
|
|
|
|
|
|
|
|
|
private void richTextBoxDescription_MouseDown(object sender, MouseEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (e.Button == MouseButtons.Right)
|
|
|
|
|
{
|
|
|
|
|
richTextBoxDescription.ContextMenuStrip.Show(sender as Control, e.X, e.Y);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void contextMenuStripDescription_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (e.ClickedItem.Text == "&Copy")
|
|
|
|
|
{
|
|
|
|
|
Clipboard.SetText(richTextBoxDescription.SelectedRtf, TextDataFormat.Rtf);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Source Code
|
|
|
|
|
|
|
|
|
|
private void richTextBoxSource_MouseDown(object sender, MouseEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (e.Button == MouseButtons.Right)
|
|
|
|
|
{
|
|
|
|
|
richTextBoxSource.ContextMenuStrip.Show(sender as Control, e.X, e.Y);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void contextMenuStripSource_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (e.ClickedItem.Text == "&Copy")
|
|
|
|
|
{
|
|
|
|
|
Clipboard.SetText(richTextBoxSource.SelectedText, TextDataFormat.Text);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Actions
|
|
|
|
|
|
|
|
|
|
void LoadSamplesFromAssembly(Assembly assembly)
|
|
|
|
|
{
|
|
|
|
|
if (assembly == null)
|
|
|
|
|
throw new ArgumentNullException("assembly");
|
|
|
|
|
|
|
|
|
|
Type[] types = assembly.GetTypes();
|
|
|
|
|
foreach (Type type in types)
|
|
|
|
|
{
|
|
|
|
|
object[] attributes = type.GetCustomAttributes(false);
|
|
|
|
|
ExampleAttribute example = null;
|
|
|
|
|
foreach (object attr in attributes)
|
|
|
|
|
{
|
|
|
|
|
if (attr is ExampleAttribute)
|
|
|
|
|
{
|
|
|
|
|
example = (ExampleAttribute)attr;
|
|
|
|
|
|
|
|
|
|
if (example.Visible)
|
|
|
|
|
{
|
|
|
|
|
// Add this example to the sample TreeView.
|
|
|
|
|
// First check whether the ExampleCategory exists in the tree (and add it if it doesn't).
|
|
|
|
|
// Then add the example as a child node on this category.
|
|
|
|
|
|
|
|
|
|
if (!treeViewSamples.Nodes.ContainsKey(example.Category.ToString()))
|
|
|
|
|
{
|
|
|
|
|
int category_index = GetImageIndexForSample(imageListSampleCategories, example.Category.ToString(), String.Empty);
|
|
|
|
|
treeViewSamples.Nodes.Add(example.Category.ToString(), String.Format("{0} samples", example.Category),
|
|
|
|
|
category_index, category_index);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int image_index = GetImageIndexForSample(imageListSampleCategories, example.Category.ToString(), example.Subcategory);
|
|
|
|
|
TreeNode node = new TreeNode(example.Title, image_index, image_index);
|
|
|
|
|
node.Name = example.Title;
|
|
|
|
|
node.Tag = new ExampleInfo(type, example);
|
|
|
|
|
treeViewSamples.Nodes[example.Category.ToString()].Nodes.Add(node);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
treeViewSamples.Sort();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ActivateNode(TreeNode node)
|
|
|
|
|
{
|
|
|
|
|
if (node == null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (node.Tag == null)
|
|
|
|
|
{
|
|
|
|
|
if (node.IsExpanded)
|
|
|
|
|
node.Collapse();
|
|
|
|
|
else
|
|
|
|
|
node.Expand();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
tabControlSample.SelectedTab = tabPageOutput;
|
|
|
|
|
textBoxOutput.Clear();
|
|
|
|
|
RunSample(node.TreeView.TopLevelControl, (ExampleInfo)node.Tag);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int GetImageIndexForSample(ImageList list, string category, string subcategory)
|
|
|
|
|
{
|
|
|
|
|
if (list == null)
|
|
|
|
|
throw new ArgumentNullException("list");
|
|
|
|
|
|
|
|
|
|
if (list.Images.ContainsKey(subcategory.ToString() + ".jpg"))
|
|
|
|
|
return list.Images.IndexOfKey(subcategory.ToString() + ".jpg");
|
|
|
|
|
if (list.Images.ContainsKey(category.ToString() + ".jpg"))
|
|
|
|
|
return list.Images.IndexOfKey(category.ToString() + ".jpg");
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void RunSample(Control parent, ExampleInfo e)
|
|
|
|
|
{
|
|
|
|
|
if (e == null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
MethodInfo main =
|
|
|
|
|
e.Example.GetMethod("Main", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) ??
|
|
|
|
|
e.Example.GetMethod("Main", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof(object), typeof(object) }, null);
|
|
|
|
|
if (main != null)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (parent != null)
|
|
|
|
|
{
|
|
|
|
|
parent.Visible = false;
|
|
|
|
|
Application.DoEvents();
|
|
|
|
|
}
|
|
|
|
|
Trace.WriteLine(String.Format("Launching sample: \"{0}\"", e.Attribute.Title));
|
|
|
|
|
Trace.WriteLine(String.Empty);
|
|
|
|
|
main.Invoke(null, null);
|
|
|
|
|
}
|
|
|
|
|
catch (TargetInvocationException expt)
|
|
|
|
|
{
|
|
|
|
|
string ex_info;
|
|
|
|
|
if (expt.InnerException != null)
|
|
|
|
|
ex_info = expt.InnerException.ToString();
|
|
|
|
|
else
|
|
|
|
|
ex_info = expt.ToString();
|
|
|
|
|
MessageBox.Show(ex_info, "An OpenTK example encountered an error.", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
|
|
|
|
|
|
|
|
|
Debug.Print(expt.ToString());
|
|
|
|
|
}
|
|
|
|
|
catch (NullReferenceException expt)
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show(expt.ToString(), "The Example launcher failed to load the example.", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
if (parent != null)
|
|
|
|
|
{
|
|
|
|
|
parent.Visible = true;
|
|
|
|
|
Application.DoEvents();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show("The selected example does not define a Main method", "Entry point not found", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
}
|
|
|
|
|
}
|