wc3campaigns
WC3C Homepage - www.wc3c.netUser Control Panel (Requires Log-In)Engage in discussions with other users and join contests in the WC3C forums!Read one of our many tutorials, ranging in difficulty from beginner to advanced!Show off your artistic talents in the WC3C Gallery!Download quality models, textures, spells (vJASS/JASS), systems, and scripts!Download maps that have passed through our rigorous approval process!

Go Back   Wc3C.net > Warcraft III Modding > Developer's Corner > Warcraft Editing Tools
User Name
Password
Register Rules Get Hosted! Chat Pastebin FAQ and Rules Members List Calendar



Reply
 
Thread Tools Search this Thread
Old 10-19-2009, 06:23 PM   #1
Vestras
User


Project Member: LoC
 
Join Date: Dec 2007
Posts: 756

Submissions (4)

Vestras will become famous soon enough (40)Vestras will become famous soon enough (40)

Default Storm - IDE framework


Zoom (requires log in)
Moonlite, my IDE that I created with Storm (still WIP)

Introduction

I'm currently making an IDE application called Moonlite. When I started coding it, I looked for good, already existing code for creating IDEs. I found nothing. So when I was almost done with it (I'm not done with it yet, because of this framework taking all my time), I figured that I found it rather unfair that everyone should go through the same as I did for making such an application. (It took me 8 months of hard work - about 7 - 10 hours a day - to create this. Not because the main coding would've taken that long but because I had to figure how to do it and what was the most efficient solution) So I started Storm, and now that it is finished, I'm going to present it to you! :)

Notices

Please note that I did this of my own free will and my own free time. I would be happy if you could respect me and my work and leave me a comment on how to make it better, bug reports and so on. Thank you for your time :)

Using the code

Using the code is a simple task, simply drag-drop from the toolbox when you have referenced the controls you want, and that should be it. However, for those who want a more in-depth tutorial, go to the folder "doc" in the package and open "index.htm".

How it works

In this chapter I will mostly cover Docking, Plugins and TextEditor, since they are the most advanced ones. I will not cover Win32 and TabControl.
  • CodeCompletion
  • Docking
  • Plugins
  • TextEditor

CodeCompletion

The CodeCompletion relies on the TextEditor, and it really isn't as advanced as some may think. It's just a Control containing a GListBox, and the GListBox' items are managed by the CodeCompletion itself. The CodeCompletion handles the TextEditor's KeyUp event, and in that it displays members of the GListBox depending on what the user has typed in the TextEditor.

Every time it registers a key press, it updates a string containing the currently typed string by calling a method GetLastWord(), which returns the word that the user is currently on. How a string is splitted up in words is defined in the TextEditor as 'separators'. Everytime GetLastWord() is called, the CodeCompletion calls the native Win32 function 'LockWindowUpdate' along with the parent TextEditor's handle to prevent flickering as the OS renderers the TextEditor/CodeCompletion.

Actually the CodeCompletion does this when it auto completes a selected item in the child GListBox, too. Everytime the CodeCompletion registers a key that it doesn't recognize as a 'valid' character (any non-letter/digit character that isn't _), it calls the method SelectItem() along with a specific CompleteType.

Now, what is a CompleteType? You see, the CompleteType defines how the SelectItem() will act when auto completing a selected item in the GListBox. There are two modes - Normal and Parenthesis. When Normal is used, the SelectItem() method removes the whole currently typed word, Parenthesis, however, removes the whole currently typed word except the first letter. This might seem strange, but it is necessary when, for example, the user has typed a starting parenthesis. You might find yourself having a wrong auto completed word sometimes, too - this is where you should use Parenthesis instead of Normal as CompleteType. (You are able to define a custom CompleteType when you add a member item to the CodeCompletion)

Since the user defines the tooltip of member items theirselves, it is rather easy to display the description of items. When a new item is selected in the GListBox, a method which updates the currently displayed ToolTip to match the selected item's description/declaration fields. Since a normal TreeNode/ListBoxItem wouldn't be able to have multiple Tags, I created the GListBoxItem, which also contains ImageIndex for the parent GListBox' ImageList. The GListBoxItem contains a lot of values that are set by the user, either on initialization or through properties.

Each time the Control itself or its tooltip are displayed, their positions are updated. The formula for the tooltip is this: Y = CaretPosition.Y + FontHeight * CaretIndex + Math.Ceiling(FontHeight + 2) for Y. The setting of X is simply CaretPositon.X + 100 + CodeCompletion.Width + 2. The formula for the CodeCompletion's Y is the same as for the tooltip, however the X is different; X = CaretPosition.X + 100.

Docking

First I will start out with a Class Diagram to help me out:

Zoom (requires log in)

As you can see, there's a lot of classes. A DockPane can contain DockPanels, and DockPanels are the panels that are docked inside the DockPane. A DockPanel contains a Form, DockCaption and DockTab. When a DockPanel's Form property is set, the DockPanel updates the Form to match the settings needed for it to act as a docked Form.

A DockCaption is a custom drawn panel. It contains two Glyphs - OptionsGlyph and CloseGlyph - both inheriting the Glyph class, which contains rendering logic for a general Glyph. The OptionsGlyph and CloseGlyph contains images that are supposed to have transparent background. A lot of people use very complex solutions for this, however I found a very, very simple and short solution:

Code:
    /// <summary>
    /// Represents an image with a transparent background.
    /// </summary>
    [ToolboxItem(false)]
    public class TransImage
        : Panel
    {
        #region Properties

        /// <summary>
        /// Gets or sets the image of the TransImage.
        /// </summary>
        public Image Image
	{
	    get { return this.BackgroundImage; }
	    set
	    {
                if (value != null)
                {
                    Bitmap bitmap = new Bitmap(value);
                    bitmap.MakeTransparent();

                    this.BackgroundImage = bitmap;
                    Size = bitmap.Size;
                }
	    }
        }

        #endregion

        /// <summary>
	/// Initializes a new instance of TransImage.
	/// </summary>
	/// <param name="image">Image that should have a transparent background.</param>
	public TransImage(Image image)
	{
            // Set styles to enable transparent background
	    this.SetStyle(ControlStyles.Selectable, false);
	    this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);

	    this.BackColor = Color.Transparent;
	    this.Image = image;
	}
    }

As simple as that. A basic panel with transparent background, and of course an Image property - Bitmap.MakeTransparent() does the rest. Panel is indeed a lovable Control. As we proceed in this article you'll find that I base most of my Controls on Panel.

Well, the DockCaption handles the undocking of the DockPanel and the moving of the DockForm. Yeah, DockForm. When a DockPanel is undocked from its DockPane container, a DockForm is created, and the DockPanel is added to it. The DockForm is a custom drawn Form which can be resized and moved, and looks much like the Visual Studio 2010 Docking Form.

Since the caption bar has been removed from the DockForm, the DockCaption takes care of the moving. This is where Win32 gets into our way - SendMessage and ReleaseCapture are used to do this.

When a DockPanel is added to a DockPane, and there's already a DockPanel docked to the side that the user wants to dock the new DockPanel, the DockPane uses the already docked DockPanel's DockTab to add the new DockPanel as a TabPage. The user can then switch between DockPanels.

The DockTab inherits the normal TabControl, and overrides its drawing methods. This means that is completely customizable for the user and very flexible for us to use.

Plugins

The Plugins library is one of the shorter, however it is probably the most complex too. Since the PluginManager class has to locate dynamic link libraries, check whether they are actual plugins, check if they use the optional plugin attribute and if they do, store the found information in an IPlugin, and add the found Plugin to the Form given by the user if it's a UserControl.

So basically, most of these processes happen in the LoadPlugins method. However, the LoadPlugins method is just a wrapper that calls LoadPluginsInDirectory with the PluginsPath set by the user. Now, the LoadPluginsInDirectory method loops through all files in the specific folder, checks whether their file extension is ".dll" (which indicates that the file is a code library), and then starts the whole "check if library contains plugins and check if the plugins has any attributes"-process:

This is done with the Assembly class, located in the System.Reflection namespace:

Code:
Assembly a = Assembly.LoadFile(file);

Then an array of System.Type is declared, which is set to a.GetTypes(). This gives us an array of all types (class, enums, interfaces, etc.) in the assembly. We can then loop through each Type in the Type array and check whether it is an actual plugin by using this little trick:

Code:
(t.IsSubclassOf(typeof(IPlugin)) == true || t.GetInterfaces().Contains(typeof(IPlugin)) == true)

Yeah - simple - this simply can't go wrong. Well, we all know that interfaces can't get initialized like normal classes. So, instead we use the System.Activator class' CreateInstance method:

Code:
IPlugin currentPlugin = (IPlugin)Activator.CreateInstance(t);

Boom. We just initialized an interface like we would with a normal class. Neat, huh? Now we just need to setup the initialized interface's properties to match the options of the PluginManager and the current environment. This can by used by the creator of plugins to create more interacting plugins. When we've done this, we simply add the IPlugin to the list of loaded plugins in the PluginManager.

However, the plugins loaded by the PluginManager isn't enabled by default. This is where the user has to do some action. The user has to loop through all the IPlugins in the PluginManager.LoadedPlugins list, and call the PluginManager.EnablePlugin(plugin) method on it.

Now, if you have for example a plugin managing Form in your application, like Firefox for example, you can use the PluginManager.GetPluginAttribute method to get an attribute containing information about the plugin, if provided by the creator of the plugin.

The way this works, is by creating an object array and set it to the System.Type method GetCustomAttributes(). The variable "type" is set to be the plugin's Type property, which is set in the loading of a plugin.

Code:
object[] pAttributes = type.GetCustomAttributes(typeof(Plugin), false);

Add it to the list of plugins:

Code:
attributes.Add(pAttributes[0] as Plugin); 

And when we're done looping, we'll finally return the list of found attributes.

TextEditor

Since I love my TextEditor, I will give you a little preview of what it's capable of. And it's not a little ;)

Zoom (requires log in)

As you might have pictured already, this library has incredibly many classes/enums/interfaces/namespaces. Actually there's so many that I won't put up a class diagram, nor explain the links between all the classes.

The TextEditor is basically just a container of the class TextEditorBase, it is actually TextEditorBase that contains all the logic for doing whatever you do in the TextEditor. The TextEditor only manages its 4 TextEditorBases along with splitters when you've split up the TextEditor in 2 or more split views.

However, the TexteditorBase doesn't take care of the drawing, it simply contains a GDIPainter field which contains logic for rendering all the different stuff. Whenever drawing is needed, the TextEditorBase calls the appropriate rendering methods in the GDIPainter. The GDIPainter also contains a method named RenderAll which, as you might've thought about already, renders all the things that are supposed to be rendered in the TextEditor.

Since the different highlighting modes are defined in XML sheets, an XML sheet reader is required. The LanguageReader parses a given XML sheet and tells the parser how to parse each token it finds in the typed text in the TextEditor. A user does not use the LanguageReader directly, the user can either use the SetHighlighting method of a TextEditor, which is a wrapper, or use the TextEditorSyntaxLoader.SetSyntax method.

Unfortunately, I can't take credit for it all. I based it on DotNetFireball's CodeEditor, however the code were so ugly, inefficient and unstructured that it would probably have taken me less time to remake it from scratch than fix all these things. The code still isn't really that nice, however it is certainly better than before.

I should probably mention that DotNetFireball DID NOT create the CodeEditor. They simply took another component, the SyntaxBox and changed its name. Just for your information.

Conclusion

So, as you can see, (or, I certainly hope you can) it is a gigantic project, which is hard to manage, and I have one advice to you; don't do this at home. It has taken so incredibly much of time, not saying that I regret it, but really, if such a framework already exist, why not use it? Making your own would be lame.

Not saying this for my own fault, so I can get more users, I'm saying this because I don't want you to go through the same things as I did for such 'basic' things. (Not really basic, but stuff that modern users require applications to have)

So yeah, I suppose that this is it. The place where you say 'enjoy' and leave the last notes, etc. Yeah, enjoy it and make good use to it - and let me see some awesome applications made with this, please :)
Planned Updates
  • Add AutoHide feature to Storm.Docking;
  • Add Designer support to Storm.Docking;
  • Remake the TabStrip from scratch.

History

1.0.0.0
  • Initial release.
Attached Images
File Type: png Moonlite preview.png (102.0 KB, 178 views)
File Type: jpg Storm.Docking Diagram.jpg (104.8 KB, 124 views)
File Type: png Storm.TextEditor.png (136.0 KB, 120 views)

Last edited by Vestras : 11-16-2009 at 06:01 AM.
Vestras is offline   Reply With Quote
Sponsored Links - Login to hide this ad!
Old 10-19-2009, 06:55 PM   #2
akolyt0r
In Flames
 
akolyt0r's Avatar
 
Join Date: Jan 2006
Posts: 1,153

Submissions (3)

akolyt0r has a spectacular aura about (120)

Default

sounds cool...

Had you had a look at Scintilla ?
__________________
akolyt0r is offline   Reply With Quote
Old 10-19-2009, 07:26 PM   #3
aualin
User
 
Join Date: Mar 2008
Posts: 11

aualin has little to show at this moment (0)

Default

Absolutely beautiful! Would have loven cross platform java, but i guess mono does it :)
Again, awesome work.
aualin is offline   Reply With Quote
Old 10-19-2009, 08:39 PM   #4
Seshiro
User
 
Seshiro's Avatar
 
Join Date: Aug 2008
Posts: 158

Submissions (1)

Seshiro is on a distinguished road (20)

Default

God you made me cum on my keyboard! :D +rep
I'll check it someday!
Is this .NET 4.0? with those Ribbons?
Seshiro is offline   Reply With Quote
Old 10-19-2009, 09:48 PM   #5
TriggerHappy
 
Join Date: Feb 2008
Posts: 405

Submissions (2)

TriggerHappy will become famous soon enough (43)TriggerHappy will become famous soon enough (43)

Default

Cool, the header looks like it windows 7 wordpad.
TriggerHappy is offline   Reply With Quote
Old 10-20-2009, 05:27 AM   #6
Vestras
User


Project Member: LoC
 
Join Date: Dec 2007
Posts: 756

Submissions (4)

Vestras will become famous soon enough (40)Vestras will become famous soon enough (40)

Default

Nope, framework 3.5. That Ribbon is made from scratch.
Yes, I've had a look at scintilla, not anything I like.

Bump
Vestras is offline   Reply With Quote
Old 10-20-2009, 04:36 PM   #7
TriggerHappy
 
Join Date: Feb 2008
Posts: 405

Submissions (2)

TriggerHappy will become famous soon enough (43)TriggerHappy will become famous soon enough (43)

Default

Is the ribbon the header? Because as I said before it looks like windows 7 wordpad.

TriggerHappy is offline   Reply With Quote
Old 10-21-2009, 05:27 AM   #8
Vestras
User


Project Member: LoC
 
Join Date: Dec 2007
Posts: 756

Submissions (4)

Vestras will become famous soon enough (40)Vestras will become famous soon enough (40)

Default

If you by header mean toolbar or anything like that, then yes. It's supposed to be used like the Word 2007 Ribbon.
Vestras is offline   Reply With Quote
Old 10-21-2009, 09:36 PM   #9
thelifelessone
User
 
thelifelessone's Avatar
 
Join Date: Jul 2009
Posts: 91

thelifelessone has little to show at this moment (4)

Default

Wait, what is this?
thelifelessone is offline   Reply With Quote
Old 10-21-2009, 10:32 PM   #10
akolyt0r
In Flames
 
akolyt0r's Avatar
 
Join Date: Jan 2006
Posts: 1,153

Submissions (3)

akolyt0r has a spectacular aura about (120)

Default

i hate those ribbons
__________________
akolyt0r is offline   Reply With Quote
Old 10-22-2009, 07:25 AM   #11
Vestras
User


Project Member: LoC
 
Join Date: Dec 2007
Posts: 756

Submissions (4)

Vestras will become famous soon enough (40)Vestras will become famous soon enough (40)

Default

Quote:
Originally Posted by akolyt0r
i hate those ribbons

Well, they're great for having a lot of stuff in a little space.

Quote:
Originally Posted by thelifelessone
Wait, what is this?

It's a framework for creating IDE applications.
Vestras is offline   Reply With Quote
Old 10-22-2009, 07:32 AM   #12
thelifelessone
User
 
thelifelessone's Avatar
 
Join Date: Jul 2009
Posts: 91

thelifelessone has little to show at this moment (4)

Default

And what's an IDE? (New to programming. I just learnt the bare-basics of Python today.)
I mean, what's it do, what's it used for, etc...

Last edited by thelifelessone : 10-22-2009 at 07:33 AM.
thelifelessone is offline   Reply With Quote
Old 10-22-2009, 01:28 PM   #13
Vestras
User


Project Member: LoC
 
Join Date: Dec 2007
Posts: 756

Submissions (4)

Vestras will become famous soon enough (40)Vestras will become famous soon enough (40)

Default

Quote:
Originally Posted by thelifelessone
And what's an IDE? (New to programming. I just learnt the bare-basics of Python today.)
I mean, what's it do, what's it used for, etc...

Integrated Development Environment. It's what you code in when you code in a programming language, e.g Microsoft Visual Studio is an IDE.
Vestras is offline   Reply With Quote
Old 10-22-2009, 03:55 PM   #14
PurplePoot
User


Official Map Reviewer
 
Join Date: Jan 2006
Posts: 363

PurplePoot will become famous soon enough (60)PurplePoot will become famous soon enough (60)PurplePoot will become famous soon enough (60)

Default

Quote:
Originally Posted by Vestras
Integrated Development Environment. It's what you code in when you code in a programming language, e.g Microsoft Visual Studio is an IDE.
A text editor isn't really an IDE.
PurplePoot is offline   Reply With Quote
Old 10-22-2009, 05:46 PM   #15
thelifelessone
User
 
thelifelessone's Avatar
 
Join Date: Jul 2009
Posts: 91

thelifelessone has little to show at this moment (4)

Default

Quote:
Originally Posted by Vestras
Integrated Development Environment. It's what you code in when you code in a programming language, e.g Microsoft Visual Studio is an IDE.

Okay, that makes sense... So this allows for syntax highlighting (and other things)?
Meaning people can download it or whatnot and then use it to make a syntax highlighter.
thelifelessone is offline   Reply With Quote
Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off


All times are GMT. The time now is 09:23 AM.


Affiliates
The Hubb The JASS Vault Clan WEnW Campaign Creations Clan CBS GamesModding Flixreel Videos

Powered by vBulletin (Copyright ©2000 - 2018, Jelsoft Enterprises Ltd).
Hosted by www.OICcam.com
IT Support and Services provided by Executive IT Services