Subversion Repositories AndroidProjects

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1452 chris 1
#region License
2
//
3
// The Open Toolkit Library License
4
//
5
// Copyright (c) 2006 - 2009 the Open Toolkit library.
6
//
7
// Permission is hereby granted, free of charge, to any person obtaining a copy
8
// of this software and associated documentation files (the "Software"), to deal
9
// in the Software without restriction, including without limitation the rights to 
10
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11
// the Software, and to permit persons to whom the Software is furnished to do
12
// so, subject to the following conditions:
13
//
14
// The above copyright notice and this permission notice shall be included in all
15
// copies or substantial portions of the Software.
16
//
17
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24
// OTHER DEALINGS IN THE SOFTWARE.
25
//
26
#endregion
27
 
28
using System;
29
using System.Diagnostics;
30
using System.Drawing;
31
using System.Drawing.Text;
32
using System.Reflection;
33
using System.Windows.Forms;
34
using OpenTK.Examples.Properties;
35
using System.Threading;
36
using System.IO;
37
 
38
namespace Examples
39
{
40
    public partial class ExampleBrowser : Form
41
    {
42
        #region Fields
43
 
44
        //PrivateFontCollection font_collection = new PrivateFontCollection();
45
 
46
        bool show_warning = true;
47
 
48
        static readonly string SourcePath = FindSourcePath();
49
 
50
        #endregion
51
 
52
        #region Constructors
53
 
54
        public ExampleBrowser()
55
        {
56
            Font = SystemFonts.DialogFont;
57
 
58
            InitializeComponent();
59
            Icon = Resources.App;
60
 
61
            // Windows 6 (Vista) and higher come with Consolas, a high-quality monospace font. Use that or fallback to
62
            // the generic monospace font on other systems.
63
            if (System.Environment.OSVersion.Platform == PlatformID.Win32NT &&
64
                System.Environment.OSVersion.Version.Major >= 6)
65
            {
66
                textBoxOutput.Font = richTextBoxSource.Font = new Font("Consolas", 10.0f, FontStyle.Regular);
67
            }
68
            else
69
            {
70
                textBoxOutput.Font = richTextBoxSource.Font =
71
                    new Font(FontFamily.GenericMonospace, 10.0f, FontStyle.Regular);
72
            }
73
        }
74
 
75
        #endregion
76
 
77
        #region Protected Members
78
 
79
        protected override void OnLoad(EventArgs e)
80
        {
81
            base.OnLoad(e);
82
 
83
            // Add those by hand, because using the designer results in an empty
84
            // image list when cross-compiling on Mono.
85
            imageListSampleCategories.Images.Add("OpenAL", Resources.OpenAL);
86
            imageListSampleCategories.Images.Add("OpenGL", Resources.OpenGL);
87
            imageListSampleCategories.Images.Add("OpenGLES", Resources.OpenGLES);
88
            imageListSampleCategories.Images.Add("OpenCL", Resources.OpenCL);
89
            imageListSampleCategories.Images.Add("OpenTK", Resources.OpenTK);
90
            imageListSampleCategories.Images.Add("1.x", Resources.v1x);
91
            imageListSampleCategories.Images.Add("2.x", Resources.v2x);
92
            imageListSampleCategories.Images.Add("3.x", Resources.v3x);
93
            imageListSampleCategories.Images.Add("4.x", Resources.v4x);
94
 
95
            Debug.Listeners.Add(new TextBoxTraceListener(textBoxOutput));
96
            treeViewSamples.TreeViewNodeSorter = new SamplesTreeViewSorter();
97
 
98
            LoadSamplesFromAssembly(Assembly.GetExecutingAssembly());
99
        }
100
 
101
        protected override void OnShown(EventArgs e)
102
        {
103
            if (show_warning)
104
            {
105
                //MessageBox.Show("The new Sample Browser is not complete. Please report any issues at http://www.opentk.com/project/issues.",
106
                //    "Work in Progress", MessageBoxButtons.OK, MessageBoxIcon.Information);
107
                show_warning = false;
108
            }
109
        }
110
 
111
        #endregion
112
 
113
        #region Private Members
114
 
115
        #region Events
116
 
117
        #region TreeView
118
 
119
        private void treeViewSamples_AfterSelect(object sender, TreeViewEventArgs e)
120
        {
121
            const string no_docs = "Documentation has not been entered.";
122
            const string no_source = "Source code has not been entered.";
123
 
124
            if (e.Node.Tag != null && !String.IsNullOrEmpty(((ExampleInfo)e.Node.Tag).Attribute.Documentation))
125
            {
126
                string docs = null;
127
                string source = null;
128
 
129
                ExampleInfo einfo = (ExampleInfo)e.Node.Tag;
130
                string sample = einfo.Attribute.Documentation;
131
                string category = einfo.Attribute.Category.ToString();
132
                string subcategory = einfo.Attribute.Subcategory;
133
 
134
                string path = Path.Combine(Path.Combine(Path.Combine(SourcePath, category), subcategory), sample);
135
                string sample_rtf = Path.ChangeExtension(path, "rtf");
136
                string sample_cs = Path.ChangeExtension(path, "cs");
137
 
138
                if (File.Exists(sample_rtf))
139
                {
140
                    docs = File.ReadAllText(sample_rtf);
141
                }
142
 
143
                if (File.Exists(sample_cs))
144
                {
145
                    source = File.ReadAllText(sample_cs);
146
                }
147
 
148
                if (String.IsNullOrEmpty(docs))
149
                    richTextBoxDescription.Text = String.Format("File {0} not found.", sample_rtf);
150
                else
151
                    richTextBoxDescription.Rtf = docs;
152
 
153
                if (String.IsNullOrEmpty(source))
154
                    richTextBoxSource.Text = String.Format("File {0} not found.", sample_cs);
155
                else
156
                    richTextBoxSource.Text = source;
157
            }
158
            else
159
            {
160
                richTextBoxDescription.Text = no_docs;
161
                richTextBoxSource.Text = no_source;
162
            }
163
        }
164
 
165
        private void treeViewSamples_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
166
        {
167
            if (e.Node.Tag != null)
168
            {
169
                ActivateNode(e.Node);
170
            }
171
        }
172
 
173
        private void treeViewSamples_KeyDown(object sender, KeyEventArgs e)
174
        {
175
            // The enter key activates a node (either expands/collapses or executes its sample).
176
            switch (e.KeyCode)
177
            {
178
                case Keys.Enter:
179
                    ActivateNode(treeViewSamples.SelectedNode);
180
                    e.Handled = true;
181
                    e.SuppressKeyPress = true;
182
                    break;
183
            }
184
        }
185
 
186
        private void treeViewSamples_MouseDown(object sender, MouseEventArgs e)
187
        {
188
            // Make sure that right-clicking a new node will select that node before displaying
189
            // the context menu. Without this, right-clicking a node does not select it, which
190
            // is completely disorienting.
191
            // As a bonus, make any mouse button select the underlying node,
192
            TreeNode node = treeViewSamples.HitTest(e.Location).Node;
193
            if (node != null)
194
                treeViewSamples.SelectedNode = node;
195
 
196
            // Middle click selects and activates a node (either expands/collapses or executes its sample).
197
            // Right button displays the context menu.
198
            // All other mouse buttons simply select the underlying node.
199
            switch (e.Button)
200
            {
201
                case MouseButtons.Middle:
202
                    ActivateNode(node);
203
                    break;
204
 
205
                case MouseButtons.Right:
206
                    treeViewSamples.ContextMenuStrip.Show(sender as Control, e.Location);
207
                    break;
208
            }
209
        }
210
 
211
        private void treeViewSamples_AfterExpand(object sender, TreeViewEventArgs e)
212
        {
213
            foreach (TreeNode child in e.Node.Nodes)
214
                child.EnsureVisible();
215
        }
216
 
217
        private void contextMenuStripSamples_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
218
        {
219
            switch (e.ClickedItem.Text)
220
            {
221
                case "&Run Sample": RunSample(this, (ExampleInfo)treeViewSamples.SelectedNode.Tag); break;
222
                case "View Description": tabControlSample.SelectedTab = tabDescription; break;
223
                case "View Source Code": tabControlSample.SelectedTab = tabSource; break;
224
            }
225
        }
226
 
227
        #endregion
228
 
229
        #region Description
230
 
231
        private void richTextBoxDescription_MouseDown(object sender, MouseEventArgs e)
232
        {
233
            if (e.Button == MouseButtons.Right)
234
            {
235
                richTextBoxDescription.ContextMenuStrip.Show(sender as Control, e.X, e.Y);
236
            }
237
        }
238
 
239
        private void contextMenuStripDescription_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
240
        {
241
            if (e.ClickedItem.Text == "&Copy")
242
            {
243
                Clipboard.SetText(richTextBoxDescription.SelectedRtf, TextDataFormat.Rtf);
244
            }
245
        }
246
 
247
        #endregion
248
 
249
        #region Source Code
250
 
251
        private void richTextBoxSource_MouseDown(object sender, MouseEventArgs e)
252
        {
253
            if (e.Button == MouseButtons.Right)
254
            {
255
                richTextBoxSource.ContextMenuStrip.Show(sender as Control, e.X, e.Y);
256
            }
257
        }
258
 
259
        private void contextMenuStripSource_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
260
        {
261
            if (e.ClickedItem.Text == "&Copy")
262
            {
263
                Clipboard.SetText(richTextBoxSource.SelectedText, TextDataFormat.Text);
264
            }
265
        }
266
 
267
        #endregion
268
 
269
        #endregion
270
 
271
        #region Actions
272
 
273
        void LoadSamplesFromAssembly(Assembly assembly)
274
        {
275
            if (assembly == null)
276
                throw new ArgumentNullException("assembly");
277
 
278
            Type[] types = assembly.GetTypes();
279
            foreach (Type type in types)
280
            {
281
                object[] attributes = type.GetCustomAttributes(false);
282
                ExampleAttribute example = null;
283
                foreach (object attr in attributes)
284
                {
285
                    if (attr is ExampleAttribute)
286
                    {
287
                        example = (ExampleAttribute)attr;
288
 
289
                        if (example.Visible)
290
                        {
291
                            // Add this example to the sample TreeView.
292
                            // First check whether the ExampleCategory exists in the tree (and add it if it doesn't).
293
                            // Then add the example as a child node on this category.
294
 
295
                            if (!treeViewSamples.Nodes.ContainsKey(example.Category.ToString()))
296
                            {
297
                                int category_index = GetImageIndexForSample(imageListSampleCategories, example.Category.ToString(), String.Empty);
298
                                treeViewSamples.Nodes.Add(example.Category.ToString(), String.Format("{0} samples", example.Category),
299
                                    category_index, category_index);
300
                            }
301
 
302
                            int image_index = GetImageIndexForSample(imageListSampleCategories, example.Category.ToString(), example.Subcategory);
303
                            TreeNode node = new TreeNode(example.Title, image_index, image_index);
304
                            node.Name = example.Title;
305
                            node.Tag = new ExampleInfo(type, example);
306
                            treeViewSamples.Nodes[example.Category.ToString()].Nodes.Add(node);
307
                        }
308
                    }
309
                }
310
            }
311
 
312
            treeViewSamples.Sort();
313
        }
314
 
315
        void ActivateNode(TreeNode node)
316
        {
317
            if (node == null)
318
                return;
319
 
320
            if (node.Tag == null)
321
            {
322
                if (node.IsExpanded)
323
                    node.Collapse();
324
                else
325
                    node.Expand();
326
            }
327
            else
328
            {
329
                tabControlSample.SelectedTab = tabPageOutput;
330
                textBoxOutput.Clear();
331
                RunSample(node.TreeView.TopLevelControl, (ExampleInfo)node.Tag);
332
            }
333
        }
334
 
335
        static int GetImageIndexForSample(ImageList list, string category, string subcategory)
336
        {
337
            if (list == null)
338
                throw new ArgumentNullException("list");
339
 
340
            foreach (string extension in new string[] { "", ".png", ".jpg" })
341
            {
342
                string name = subcategory.ToString() + extension;
343
                if (list.Images.ContainsKey(name))
344
                    return list.Images.IndexOfKey(name);
345
 
346
                name = category.ToString() + extension;
347
                if (list.Images.ContainsKey(name))
348
                    return list.Images.IndexOfKey(name);
349
            }
350
 
351
            return -1;
352
        }
353
 
354
        static void RunSample(Control parent, ExampleInfo e)
355
        {
356
            if (e == null)
357
                return;
358
 
359
            MethodInfo main =
360
                e.Example.GetMethod("Main", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) ??
361
                e.Example.GetMethod("Main", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof(object), typeof(object) }, null);
362
            if (main != null)
363
            {
364
                try
365
                {
366
                    if (parent != null)
367
                    {
368
                        parent.Visible = false;
369
                        Application.DoEvents();
370
                    }
371
                    Trace.WriteLine(String.Format("Launching sample: \"{0}\"", e.Attribute.Title));
372
                    Trace.WriteLine(String.Empty);
373
 
374
                    Thread thread = new Thread((ThreadStart)delegate
375
                    {
376
                        try
377
                        {
378
                            main.Invoke(null, null);
379
                        }
380
                        catch (TargetInvocationException expt)
381
                        {
382
                            string ex_info;
383
                            if (expt.InnerException != null)
384
                                ex_info = expt.InnerException.ToString();
385
                            else
386
                                ex_info = expt.ToString();
387
                            MessageBox.Show(ex_info, "An OpenTK example encountered an error.", MessageBoxButtons.OK, MessageBoxIcon.Warning);
388
 
389
                            Debug.Print(expt.ToString());
390
                        }
391
                        catch (NullReferenceException expt)
392
                        {
393
                            MessageBox.Show(expt.ToString(), "The Example launcher failed to load the example.", MessageBoxButtons.OK, MessageBoxIcon.Warning);
394
                        }
395
                    });
396
                    thread.IsBackground = true;
397
                    thread.Start();
398
                    thread.Join();
399
                }
400
                finally
401
                {
402
                    if (parent != null)
403
                    {
404
                        parent.Visible = true;
405
                        Application.DoEvents();
406
                    }
407
                }
408
            }
409
            else
410
            {
411
                MessageBox.Show("The selected example does not define a Main method", "Entry point not found", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
412
            }
413
        }
414
 
415
        // Tries to detect the path that contains the source for the examples.
416
        static string FindSourcePath()
417
        {
418
            string current_dir = Directory.GetCurrentDirectory();
419
 
420
            // Typically, our working directory is either "[opentk]/Binaries/OpenTK/[config]" or "[opentk]".
421
            // The desired source path is "[opentk]/Source/Examples/[ExampleCategory]"
422
 
423
            string guess = current_dir;
424
            if (CheckPath(ref guess))
425
                return guess; // We were in [opentk] after all
426
 
427
            guess = current_dir;
428
            for (int i = 0; i < 3; i++)
429
            {
430
                DirectoryInfo dir = Directory.GetParent(guess);
431
                if (!dir.Exists)
432
                    break;
433
                guess = dir.FullName;
434
            }
435
 
436
            if (CheckPath(ref guess))
437
                return guess; // We were in [opentk]/Binaries/OpenTK/[config] after all
438
 
439
            throw new DirectoryNotFoundException();
440
        }
441
 
442
        static bool CheckPath(ref string path)
443
        {
444
            string guess = path;
445
            if (Directory.Exists(guess))
446
            {
447
                guess = Path.Combine(guess, "Source");
448
                if (Directory.Exists(guess))
449
                {
450
                    guess = Path.Combine(guess, "Examples");
451
                    if (Directory.Exists(guess))
452
                    {
453
                        // We are have found [opentk]/Source/Examples
454
                        path = guess;
455
                        return true;
456
                    }
457
                }
458
            }
459
            return false;
460
        }
461
 
462
       #endregion
463
 
464
        #endregion
465
    }
466
}