Jump to content
  • Advertisement
Sign in to follow this  
  • entries
    23
  • comments
    28
  • views
    20318

Entries in this blog

 

Getting Back In The Game...

Heyo! Been forever and a day, but I'm back, and hopefully to stay. And be productive, because like most others here, I've a game idea I want to see come to fruition. As such, I've disconnected WoW and Guild Wars and other non-productive distractions, trying to get down to business. Part of getting down to business for me is 'accountability', which will likely be taking the form in at-least-weekly journal updates. For now I'll be using this /old/ journal, but if my game starts to see progress and take off, it will get its own separate journal. For now, the game's ideas and concepts shall remain hidden in mysterious shadowy shadows.

In the past week or so, in my spare time between whatnot, I've been researching what I'll need to be using to get the job done. It's a bit tricky since I've not done graphical game development in awhile, though I have been productive for a MUD of late, so I'm not really inexperienced, per se; however, I tend to like to reinvent the wheel, depending on the wheel, and learn best by failing. We'll see how this plays out. For now, the technologies and other stuff I've been looking at and thoughts regarding them (this is where I'd greatly appreciate feedback/criticism, for those so inclined):

C#/Mono - Language (client/server/everything)
Hopefully sidestepping Holy Wars and whatnot, I have some experience and memories of C# a few years ago, fond memories all. My language experience of late has largely been VBA, custom scripting language for the aforementioned MUD, and a bit of Java/Javascript/HTML/CSS. I'm more familiar with some of these, and other languages, but it has been a good while and I recall only more concepts than anything language specific, really. Regardless, my previous C# experience was all .NET, but as I would like for my game to be more cross-platform inclined, I've been looking at Mono and it seems to fit the bill, though I've yet to test how difficult it is to target to other platforms, just what I've seen on the web.

Awesomium - GUI
So one of the areas which I'd rather not reinvent the wheel too much if I can help it is the area of GUI. I had attempted some time ago to make a little coder control, and may end up picking that up again for all I know, but I realized that I got too caught up in the nuances and didn't make it very far. I honestly don't remember how far I made it, but I did learn a bunch of neat stuff, which I've since forgotten. Anyway, Awesomium looks to be a neat little HTML UI Engine for .Net/Mono. While I'm not sure of how badly this will effect performance, etc., I do like the idea of using HTML/CSS/javascript for GUIs in a game. Saves me a lot of trouble, and it can use existing technologies. I had looked at other such things, notably Chromium/Blink/etc, but they seemed...not as ready out of the box as I'd like at the moment, though I might end up using them in the future. Awesomium is free "for teams with
Google Cloud or Amazon Cloud - Servers/Databases
So my game idea certainly isn't a dreaded MMO idea (I recall comics about marrying the Hulk which were post here, some time ago), but it does require servers and databases. I know that I'd like for it to scale, both in case it does take off and in case it doesn't, the latter so I don't end up wasting money for unused resourced. I'm currently torn between Google Cloud and Amazon's Cloud, partly due to server ignorance since I've little to no experience with such things (I plan on starting out simple with the game, using it as a conduit to learning). I am somewhat of a Google fanboi, so I'm inclined to lean towards them, especially since I can just go all Google and use their APIs to handle any future purchasing abilities or to login, instead of having a separate username/password/whatever just to track and play. On the other hand, Amazon's seems to be more popular, and I honestly don't know if this is just a service thing or if Google's has yet to catch on. Another thing I guess I dread is setting all of this up for Google's only to have it be faded out like Google Wave and other such technologies.

SDL/OpenGL - Graphics
So this is where part of my reinventing the wheel issue comes in. I'm not so bad where I want to go all hardcore and use nitty gritty hardware calls, but I do want to write my own engine for handling things, partly because that's where I get my enjoyment. I will be open and say I've little 3D graphics experience, having written nothing more than a few tech demos almost, gosh, a decade ago (so old...). As with the server, I plan on starting out small and slowly implementing more of the custom engine using SDL/OpenGL over time. It will likely require occasional rewrite of the engine/code, but I honestly feel that code, or at least parts of it, should be rewritten entirely if new features and such have been slapped on over time.

So there you have it, at least one item I'm still not sure on, and all of them I'd love input before I get cracking. I realize there will likely be (quite) a few responses about starting out small on server/3D graphics stuff, but I'd like to at least try to learn as I go with the game, and failing that perhaps step back and write smaller demos working my way up. (I'm quite likely to sandbox newly learned stuff anyway, in small small demos, but then just slap that in the main game and rewrite it after it has a good bit slapped together).

Thanks for reading, and Cheers!

nerd_boy

nerd_boy

 

Crisis of Faith?

Right-o. This will be my last post on here for about a year. Or it should be if all goes well. As you may have known prior (or just after reading the bit at the top of the journal), I'll be heading off to the Air Force in February. ~95 days left till I ship from the day of this post, give or take a day.

As for my crisis of faith? Well, get ready for a n00bish excuse story. :|

I'd been dabbling in programming since I was 10. A couple years were on and off at the start of it. For various reasons, mostly my lack of discipline/willpower and just being easily distracted in general, I've never made anything worth mentioning. Ever. I've dabbled plenty in various areas. I've independently researched a handful of chipsets and early consoles. Read plenty of articles over the years on various aspects of programming and gamedev. I just don't seem able to *do* it. Like my code editor project, for instance. I've made plenty of progress on it two or three times, but I always end up rewriting it for some asinine reason. Or I'm torn between whether I should make it for WinForms? What about WPF? Silverlight? AIR? :| Once I thought it would be helpful if I dropped dabbling in programming so I'd miss it, but I never did. I mean, I could go a week or two and all I'd do was read an article or mess with some code in Visual Studio that didn't accomplish jack squat.

Don't get me wrong, I still have a "burning desire", if you will, to program/code/develop. But I just don't seem to appreciate it or something. *shrug* Anyway, I figure the 8 months between Basic Training and Tech School that I'll have away from computers/internets, both AF imposed at the start and probably self imposed at the end, will help, but an extra 3 months or so aren't going to hurt. So, as a test of my "crisis of faith" in programming, I figured I'll just drop pretty much everything. No coding. No article reading. Nothing. The most I'll do is maybe actually learn some decent maths, from calculus and onward. If after about a year (which it will be from now, if you include the ~30 days I get to spend home after Basic/Tech), I'm still interested, perhaps I'll appreciate it more. Besides, the discipline that BT will give me will likely help. And if I'm not still interested in programming...well, I dunno. I don't really see me not being interested in programming, but I suppose I could find some other hobby/activity to take up. It isn't really likely though. So perhaps my "test" isn't so much to test my desire to program, but rather to increase it? I dunno.

So anywho, you guys take care. After a day or so to check up on comments, I probably won't visit GameDev for a year. So don't forget me when I come back. XD

nerd_boy

nerd_boy

 

Livin' on the Wave

[Edit: Per the request of benryves, the apparent resident grammar expert, invite should not be used when invitation is available for usage. So I've changed it.]

Huzzah! Thanks to dohtem giving me an inviteinvitation, I've been fortunate enough to play around with Google Wave for the past...almost a week, I think. I've completely bitten the hype and I think it is super crazy awesome, etc. So much have I bitten the hype that I'm going to have a go at "living off the Wave" in so far as a site/blog(wlog? wavlog? ???) goes, aside from this journal. So now it is just a countdown until some domain sitter grabs my old one up. Hope it isn't some pron site. [disturbed]

So far as any of my projects go, nothing. Nada. Zip. Zero. Zilch. No progress. :| I really need to get some progress done. It isn't like I have a viable excuse such as a job, which I also need to get. Maybe. Only four months till I leave for Basic Training.

Maybe there will be something to report next time. Maybe.






FOUR MORE MONTHS! D:

[EDIT]
-------------------------------------------------------------------------------
Also, I've been playing around with the Google Wave gadgets thingy, only made one to display your XBox GamerCard. :| Any ideas would be appreciated.

nerd_boy

nerd_boy

 

Of rnfnCodeLite and Grammars, Part 2

Mirrored Here

What? Part 2 already? ZOMG! SRS BIZNIZ TIEM!
Anywho...

Righty-o. So in my previous post, I went over the rough draft of the rnfnBNF language. And now I'm supposed to go over "Intellisense, Scope, and AutoFormatting ideas/problems I have, as well as any changes I come up with and/or from feedback." Well there hasn't been any feedback at the time of this writing, so that bit is out the window. And I haven't come up with any changes overnight in my sleep. So this leaves us with my ideas/problems regarding IntelliSense, Scope, and AutoFormatting.

Scope
Scope is a bit problematic, at least I think it might be. I'm presuming/hoping scope only ever works in levels, with the innermost/lowest level being the one with the most access. If I presume this, then I can just deal with having _startScope() and _endScope(). This, at least, allows for a kind of "general" scope. I'm still thinking as to whether or not there is any benefit/disadvantage to having the scopes be named, for IntelliSense purposes.

IntelliSense
My ideas for handling IntelliSense still have a few holes. The first of which is handling scope, etc. Which is to say, while I may know every function in class FooBar of namespace Foo.Bar, I don't want the IntelliSense listing them as Foo.Bar.FooBar.classname in the suggestion modal. Rather, I need some form of scope division, which'll probably just be taken care of by assigning a scope seperator(s). Also, for something like using System.Windows.Forms, I need something in place to handle this "prefix" bit, though I suppose in conjunction with the scope seperator(s), I could have _addScopePrefix("System.Windows.Forms"). Of course, I need some manner of getting the unknown bit into it. That is to say, if the rule were using="using ", namespace, terminating-symbol;, for example, I'd need to get namespace in _addScopePrefix(...) somehow. At the moment, I'm debating between yet another function, such as _setParse(variable:rnfnBNF grammar), or something like variable:rnfnBNF grammar. So the difference would be between using="using ",_setParse(_namespace,namespace) _addScopePrefix(_namespace),terminating-symbol; and using="using ",_namespace:namespace _addScopePrefix(_namespace),terminating-symbol;. Personally, I'm liking the latter example at the moment.

Another problem with IntelliSense is building a "base" to work off of. For example, having the IntelliSense data for the .NET platform in a usable format for multiple languages. Or maybe I'll just let the program using the control provide this information. That'd probably be easiest/best. I still have to consider whether I want to allow for multi-language intellisense. >_>

AutoFormatting
Off the top of my head, the things that'd fall in this category mostly involve the placement of tabs, spaces, and/or newlines, the first two usually in regards to the level of scope that they take place. Something like _Scope()*'\t' would insert N tabs where N is the scope(or indention) level. As for actually making it part of AutoFormatting, and not just part of the rule definition, probably have something along the lines of _AutoFormat(rnfnBNF grammar), which would insert the rnfnBNF grammar if, and only if, AutoFormatting is turned on. Might throw in _AutoFormat(option=value:rnfnBNF grammar) to handle AutoFormatting options. Of course, I've have to come up with a safe way to generate a result for the rnfnBNF grammar, in case someone gets all funky with ORs and Optionals. I'll likely just take the first (left-most) of the ORs, disclude the optionals, etc.

Will there be a Part 3? Who knows...

nerd_boy

nerd_boy

 

Of rnfnCodeLite and Grammars, Part 1

Mirrored Here

Right, so in an effort to design a decent parser for rnfnCodeLite to use for syntax highlighting, as well as possibly IntelliSense and AutoFormatting, I need to write out what I need for it to do, and throw out some rudimentary ideas. For whatever reason, doing so in WordPress' tool seems somehow better than plain ol' notepad(or the plain text editor in VS, or any notepad clones). Plus, if I throw this in my GameDev Journal, where someone might actually read it, I might get some decent feedback.

rnfnBNF Specs
I was originally writing out what the rnfnBNF grammar, as I'm calling it, would need to do, and then I was going to specify the features after. However, this came off as confusing, or at least the way I was going about it. So instead, I'll list my idea of what the specs will be like, though they are certainly not set in stone.

EBNFesque
Since rnfnBNF is based somewhat off of EBNF, it will follow most, if not all, of the same rules(as seen on the wikipedia page):

Firstly, defining. Unlike EBNF, where it is just =;, rnfnBNF should also allow for the setting of variables/options. As it stands, I'll likely just use rule=definition; for rules, $variable=value; for global variables, and %option[type]=default-value;. Should [type] not be a recognizable value for rnfnBNF options(such as a boolean, Color, string, etc.), the option will be ignored. The main difference between the global variables and the options is that the options would be saved between instances of the rnfnCodeLite control, so such things as color preference could be altered in an Options/Preferences form of the control and used when the rnfnBNF spec file is used again. Global variables could either be used solely by the spec file, or if there is an underscore between the $ and the name of the variable, it would indicate a special variable used by rnfnCodeLite, such as the language(s) the rules are intended for, default color, etc. (Note: This probably won't have much bearing right now, but variables will be treated as references.)

For both rules and variables, the rest of the EBNF grammar would hold. (*...*) for comments, ?...? for special sequences, etc. I might consider making the concatenation symbol optional for easier reading, but possibly not. Fortunately, EBNF allows for two methods of extending it even further:

EBNF Functions
Since there is a concatenation symbol, something like foobar (whatsit) isn't considered legal, which allows for special functions to be thrown in. Should I make the concatenation symbol optional, I'll likely be making the parser check to see if foobar(whatsit) was one such function that it had. If so, it'd parse as a function, if not it'd be treated as a regular foobar,(whatsit).

Since "," is already in use, and I might want to allow for rnfnBNF grammar to be used as an argument inside a function without tedious quotation marks, I'll likely use another character for argument seperation. For now, I'll use the ":" character, but that isn't concrete.

A few functions I'm toying around with having included are:

_if(variable=value:rnbnBNF grammar)
_elseif(variable=value:rnbnBNF grammar)
_else(rnbnBNF grammar)
_ifexists(variable:rnfnBNF grammar)
_create(variable:value)
_delete(variable)
_regexp(.NET regexp pattern)(iffy)
functions in respect to scope/level
functions in respect to intellisense
functions in respect to autoformatting


EBNF Special Sequence
Normally, the ?...? sequence seems to be meant for including characters or somesuch that aren't easily accessible by the keyboard, etc. Such as ?PI? might stand for the UTF representation of pi(that I'm too lazy to look up right now). However, rnfnBNF will use it not as an extender of the grammar, but as an extender of the rule. This is to say, anything in ?...? isn't part of the definition of the rule, but something that pertains to the rule in itself. This could include details to the Intellisense to track any instances of this rule in the language(such as declaring a function), setting options specific to this rule(color/back color of a number), etc.

Context-Free Free?
Not having researched context grammars very much, but looking at the Definite clause grammar, it seems that allowing a rule to have arguments, it can allow for context-sensitive grammars. I'm leaning towards implementing this right now, but if I do I might make paramter/local variables to a rule be preceded by a special character, maybe "_"? rule(_foobar)=something | _if(_foobar="yay":somethingAdditional); doesn't look too terribly bad. Plus, you can know if a variable is local or not just by looking.

Part 1, Fin
It is getting late, and I've been writing and rewriting this post for awhile now. I'll leave it as it is for the most part. Might make some minor changes if I notice 'em, but anything else will have to wait for Part 2. Hope the writing isn't too "splotchy", as I jumped around quite a bit.

Part 2 will likely cover Intellisense, Scope, and AutoFormatting ideas/problems I have, as well as any changes I come up with and/or from feedback. At this rate, however, this grammar is getting incredibly complex. I'll have to look at it and see if I can't implement it in a fashion where it is easy/simple, but not take up too much room. I'm toying with treating variables and rules all as one element, at the moment. This would mean I could handle them the same. This would also mean that variables could be functions. i.e., foobar and foobar(bleh) could be defined. Or maybe I'll just throw away variables, consider them to be rules, and just have rules and options. I might do that.

Anywho, before I digress any further, thanks for reading, and please leave feedback if you have it on the grammar ideas.

nerd_boy

nerd_boy

 

Closing In

Righty-o! I'm closing in on getting the control finished up. Progress moves a bit faster when one actually works on the project. Granted, I'm only working a little on it, but that is a little more than what I was. Just gotta keep trucking. Etc.

Horizontal scrolling is now implemented in rnfnCodeLite. It has yet to be tested for large quantities of lines, but the tests I performed on a few lines seems to indicate that it is working quite nicely. I'm sure it could be optimized, but it increases/decreases the horizontal scrollbar's maximum value appropriately for now. A few 'weird' bits that I may or may not work on, depending. For example, it takes a few characters before the scrollbar provides any scrolling. This is possibly due to my having it's LargeChange value set to text area's width, which seems a bit large. I think Visual Studio's is using something like 1/5th of the width? Or maybe it is just an arbitrary number. Not sure, but it definately seems to not be the text area's width.

Thinking about toying around with allowing the code editor's contents to be printed via System.Drawing.Printing.PrintDocument, but currently in a bit of a rut regarding GDI and the resolution of the page being printed. If I don't find a nice workaround, I may just ditch it, as it isn't essential, but would be really nice.

The next step I've got to making it a nice little text editor is implementing text selection. I've been toying with various ideas for this in my head, and I'm pretty sure I'm going to settle for multiple selections. This would allow for quick find/replace that I'll also probably be implementing. The only drawback to using it for this would be if the user hit the backspace key, though I suppose a quick CTRL+Z would solve that.

Speaking of CTRL+Z, I also have to implement an Undo/Redo system. Through numerous mental evolutions, I've decided it is going to be selection based. If there is no text selected, it'd operate just like a regular Undo/Redo would. However, if text were selected, it would perform the most recent Undo/Redo(as appropriate) for that text and only in regards the selected text. Previously, it was going to Undo/Redo the entire operation if it had occurred on a line that was in the text selection, but upon explaining this to a friend, he pointed out that it would get a bit confusing. So, if I do go this route (there is always the chance it'll prove not worth the effort), it is likely that only part of the action would be redone/undone. For example, if I'd pasted "foobarbiz" in the middle of "tutu", highlighted "barbiztu", and then hit CTRL+Z, the result would be the text "tufootu" with the next undo action being to remove the "foo" bit. In theory, I don't think it'll be too bad going backwards through the collection to find the appropriate area of text, nor altering the undo/redo action if it is only a partial undo/redo. The problem I'm currently thinking on is whether to allow for infinite undo/redo. I haven't done any testing on it, but surely it isn't going to suffice just storing it all in memory? And I can't really store older parts of it in a file since any performance benefits would be lost with this "partial-selected-text" undo/redo scheme. Hmmm.....

So, yeah. When I get those two done, debugged, and tweaked, all I should have to do is add ContextMenu support and it'll be a nice little text editor. The only other major thing after that, that I can recall, will be to implement a keyword syntax highlighter to go along with the default text 'engine' as two in-package CodeEngine's. Hopefully others'll take an interest and start writing better CodeEngine's, whether they are all encompassing or just for a specific language. For this post's code snippet, I think I'll show what the CodeEngine class is so far, from Reflector's point of view:
public abstract class CodeEngine
{
// Fields
internal rnfnCodeLiteData data;

// Methods
public CodeEngine(rnfnCodeLite master);
public virtual bool CanPrint();
public abstract int CaretCharOffset(Graphics graphics, Line line, int caretPixelOffset);
public abstract int CaretPixelOffset(Graphics graphics, Line line, int caretCharOffset);
public abstract void Draw(Graphics graphics, Line line, Rectangle area);
protected int FindAfter(Line line, string query);
protected int FindBefore(Line line, string query);
protected Line GetLine(int linenumber);
protected Line[] GetLines(int lineNumber, int lines);
public virtual void MouseClick(rnfnCodeLite control, MouseEventArgs e);
public virtual void MouseDoubleClick(rnfnCodeLite control, MouseEventArgs e);
public virtual void MouseHover(rnfnCodeLite control, EventArgs e);
public virtual void OnHelpRequested(HelpEventArgs hevent);
private void OnLineChanged(int lineNumber);
public virtual void Print(CodeEnginePrintDocument document, PrintPageEventArgs e);
public virtual void Replacing(ref int startLine, ref int startOffset, ref int length, ref string text);
protected void SetCollapseData(Line line, int linesToSkip);
protected void SetIcon(Line line, Icon icon);

// Properties
protected Color BackColor { get; set; }
protected Font Font { get; set; }
protected Color ForeColor { get; set; }
protected int LineCount { get; }
protected bool ShowCollapseArea { get; set; }
protected bool ShowColoredIndicator { get; set; }
protected bool ShowIconGutter { get; set; }
protected bool ShowLineNumbers { get; set; }
protected TextFormatFlags TextFormatFlags { get; }

// Nested Types
public abstract class CodeEngineData
{
// Methods
protected CodeEngineData();
}

[StructLayout(LayoutKind.Sequential)]
public struct Line
{
internal LinkedListNode line;
internal Line(Text.Line data);
internal Line(LinkedListNode line);
public int CollapseData { get; }
public Icon Icon { get; }
public string Text { get; }
public CodeEngine.CodeEngineData Data { get; set; }
}
}


Also, if you're still sticking around and are interested, here is the DefaultText bit, a 'basic' implementation of a CodeEngine that acts as the default engine for the control:
public class DefaultText:CodeEngine
{
public DefaultText(rnfnCodeLite master):base(master){}
public override void Draw(Graphics graphics,Line line,Rectangle area)
{
TextRenderer.DrawText(graphics,line.Text,Font,area,ForeColor,TextFormatFlags);
}
public override bool CanPrint()
{
return true;
}
public override int CaretCharOffset(Graphics graphics,CodeEngine.Line line,int caretPixelOffset)
{
//Past the end
if(caretPixelOffset>TextRenderer.MeasureText(graphics,line.Text,Font,new Size(),TextFormatFlags).Width)
return line.Text.Length;

//At the start
if(caretPixelOffset0)
return 0;

//Iterative Binary Search
int low=0;
int high=line.Text.Length;
int mid=0;

while(low {
mid=low+(high-low)/2;

if(TextRenderer.MeasureText(graphics,line.Text.Substring(0,mid),Font,new Size(),TextFormatFlags).Width low=mid+1;
else
high=mid;
}

int middleDiff=Math.Abs(TextRenderer.MeasureText(graphics,line.Text.Substring(0,mid),Font,new Size(),TextFormatFlags).Width-caretPixelOffset);
int lowerDiff=middleDiff;
try{lowerDiff=Math.Abs(TextRenderer.MeasureText(graphics,line.Text.Substring(0,mid-1),Font,new Size(),TextFormatFlags).Width-caretPixelOffset);}catch(Exception exception){}
int higherDiff=middleDiff;
try{higherDiff=Math.Abs(TextRenderer.MeasureText(graphics,line.Text.Substring(0,mid+1),Font,new Size(),TextFormatFlags).Width-caretPixelOffset);}catch(Exception exception){}

if(lowerDiffreturn mid-1;
if(higherDiffreturn mid+1;
return mid;
}
public override int CaretPixelOffset(Graphics graphics,Line line,int caretCharOffset)
{
if(caretCharOffset return TextRenderer.MeasureText(graphics,line.Text.Substring(0,caretCharOffset),Font,new Size(),TextFormatFlags).Width;
else
return TextRenderer.MeasureText(graphics,line.Text,Font,new Size(),TextFormatFlags).Width;
}
public override void Print(CodeEnginePrintDocument document,PrintPageEventArgs e)
{
if(document["page"]==null)
{
//Haven't done any printing yet.
document["page"]=1;
document["line"]=1;
document["char"]=1;
}
}
public override string ToString()
{
return "Default Text";
}

internal bool ShouldSerializeFont()
{
return !Font.Equals(Control.DefaultFont);
}
public new Font Font
{
get{return base.Font;}
set{base.Font=value;}
}
[DefaultValue(typeof(Color),"ControlLightLight")]
public Color BackgroundColor
{
get{return BackColor;}
set{BackColor=value;}
}
[DefaultValue(typeof(Color),"ControlText")]
public Color TextColor
{
get{return ForeColor;}
set{ForeColor=value;}
}
}


I'll likely wait to explain everything properly when I get around to writing the documentation for making one's own CodeEngine, which will be after I write up some Intellisense-type stuff, if I even bother with that. Also, the Print function is a bit lacking since I'm, again, having problems with that.

Please feel free to comment, critique, question, etc.

Mirrored here

[Edit: Fixed my not having swapped pre tags for source]

nerd_boy

nerd_boy

 

.NET Designer Fun

Had a good bit of fun today implementing the Visual Studio Designer end of CodeEngine. Prior to this, the Engine property of my rnfnCodeLite control had been non-interactive in the Designer. Now you can select all known classes that inherit CodeEngine, and aren't abstract. You can also set the properties of the class from the PropertyGrid. Implementing this was annoying as heck at times, but I managed to get it all done in one day, and I'd say that's a fair bit of work, especially considering the lack of it of late. :p

Firstly, the bit about selecting known classes that inherit CodeEngine:
internal class CodeEngineUITypeEditor:UITypeEditor
{
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
{
return UITypeEditorEditStyle.DropDown;
}
public override object EditValue(ITypeDescriptorContext context,IServiceProvider provider,object value)
{
if(context!=null&&provider!=null)
{
IWindowsFormsEditorService editorService=(IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));

if(editorService!=null)
{
CodeEngineListBox listBox=new CodeEngineListBox(editorService,context);
editorService.DropDownControl(listBox);
return listBox.SelectedItem;
}
}
return base.EditValue(context,provider,value);
}
}
internal class CodeEngineListBox:ListBox
{
IWindowsFormsEditorService editorService=null;

public CodeEngineListBox(IWindowsFormsEditorService service,ITypeDescriptorContext context)
{
editorService=service;
Sorted=true;
foreach(Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
foreach(Type type in assembly.GetTypes())
if(type.IsSubclassOf(typeof(CodeEngine)))
Items.Add(Activator.CreateInstance(type,(context.Instance as rnfnCodeLite)));
SelectedIndexChanged+=OnSelectedIndexChanged;
}

void OnSelectedIndexChanged(object sender,EventArgs e)
{
editorService.CloseDropDown();
}

}



Two bits here. The CodeEngineUITypeEditor bit just tells the property grid that we're a drop-down UITypeEditor(meaning we're to be used "within" the property grid, versus being a dialog window) and what to do when we're being used. The only thing we do is add a CodeEngineListBox, which is our second bit. All this does is extend System.Windows.Forms.ListBox and displays every implementable type that is a subclass of CodeEngine. The only downside, at the moment, is the first time you click it in the Designer, it takes quite a few seconds to go through all the assemblies looking for appropriate types. It gets faster the more you use it(or at least in my quick two-minute testing), but the first time is still a doozy. JPatrick in #gamedev@AfterNET.org was discussing it with me, and I think he said there was a way to get all the types from TypeDescriptor.GetEditor, but I didn't really understand all of it. :x

Right, so apparently what I wanted already existed. Imagine that. :p System.ComponentModel.ExpandableObjectConverter for those of you interested.
Secondly, I wanted to be able to implement any and all properties of any and all classes that inherited CodeEngine. I'm treating any properties visible to the property grid in these classes as being options/settings for the engine. I've already implemented a runtime feature where right-clicking on the 'deadspace' area between the scrollbars pops up a dialog window showing a property grid with the properties for the engine, so everything is all set runtime. I wasn't quite sure how I wanted to do this in the Designer until I took a look at the property grid, and noticed that some properties had sub-properties, such as Font, Size, and Rectangle types. After a bit of research, I found out this was due to having a TypeConvertor, which is implemented here:
internal class CodeEngineConverter:TypeConverter
{
public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context,object value,Attribute[] attributes)
{
return TypeDescriptor.GetProperties(value).Sort();
}
public override bool GetPropertiesSupported(ITypeDescriptorContext context)
{
return true;
}
public override bool GetCreateInstanceSupported(ITypeDescriptorContext context)
{
return context.Instance.GetType().IsSubclassOf(typeof(rnfnCodeLite));
}
public override object CreateInstance(ITypeDescriptorContext context,System.Collections.IDictionary propertyValues)
{
if(propertyValues==null)
throw new ArgumentException("propertyValues");

CodeEngine engine=Activator.CreateInstance((context.Instance as rnfnCodeLite).Engine.GetType(),(context.Instance as rnfnCodeLite)) as CodeEngine;
foreach(PropertyInfo info in engine.GetType().GetProperties())
{
if(propertyValues[info.Name]!=null)
info.SetValue(engine,propertyValues[info.Name],null);
}

return engine;
}
public override bool CanConvertFrom(ITypeDescriptorContext context,Type sourceType)
{
return((sourceType==typeof(string)||base.CanConvertFrom(context,sourceType))&&context.Instance.GetType().IsSubclassOf(typeof(rnfnCodeLite)));
}
public override object ConvertFrom(ITypeDescriptorContext context,System.Globalization.CultureInfo culture,object value)
{
if(!String.IsNullOrEmpty((string)value)&&context.Instance.GetType().IsSubclassOf(typeof(rnfnCodeLite)))
{
string[] str=(value as string).Trim().Split(culture.TextInfo.ListSeparator[0]);

CodeEngine engine=Activator.CreateInstance((context.Instance as rnfnCodeLite).Engine.GetType(),(context.Instance as rnfnCodeLite)) as CodeEngine;
PropertyInfo[] propertyInfo=engine.GetType().GetProperties();

if(propertyInfo.Length==str.Length)
{
for(int i=0;i propertyInfo.SetValue(engine,TypeDescriptor.GetConverter(propertyInfo).ConvertFromString(context,culture,str),null);

return engine;
}
}
return base.ConvertFrom(context, culture, value);
}
}


Bleh. Seems like WordPress's Visual editor doesn't like the ""bit, even in tags. So I lost all my typing after it since it tried to turn it into a flash object. Anywho, implementing TypeConverter so that the property grid likes it took a bit of hacking and cookbooking. The msdn documentation on how to do it didn't seem to be sufficient, so I had to cobble something together from that and Reflection. So I'm not sure how it'll hold under heavy testing, but it seems to work so far. The only thing that I can see off the top of my head is if any property is of a type that doesn't have a TypeConverter, it might break.

Oh, yeah, a bit I lost due to WordPress: I'm using properties that are visible by the property grid as options/settings for any CodeEngine class. I thought it'd be neat to be able to do it in the property grid design time. Run time wise, I've already implemented it. My little "deadspace feature" is now overloaded. When left-clicked, it'll pop-out an external editor or toggle whether the current external editor is on-top or not. Now when it is right-clicked, it'll show a dialog window with a property grid displaying the properties of the current engine.

In closing, I'm quite proud of the get/set-all-the-properties in my custom TypeConverter. With a bit of work and polish, I think there is a good ObjectTypeConvertor lurking in there for the property grid.
Mirrored here

nerd_boy

nerd_boy

 

Status? Nil.

Having put in my notice a while ago to my current job, this coming Thursday is my last day there. While I do feel somewhat guilty, and a lot foolish, when I think about various people being laid off due to the lovely economic conditions at present who might love to have my job, and would definitely yell at me to keep it, I've got enough to get by without income for two to three months. If I've not accomplished anything near this time, or prior if something unexpected comes up, I'll likely try to join the US Air Force, but only as a final course of action. Which is probably what I'll end up doing anyway. [smile] I figure I'll need to either get a job before then, though the offerings are undoubtedly sparse and only getting sparser, or have a go at indie development. Fear not of my becoming one of those who end up living in their parent's basement playing video games when they're claiming to be coding. My parents don't have a basement.

So I'll be doing the indie biz stuff, provided things don't get too bleak and/or an awesome job opportunity doesn't present itself. I've decided I won't officially be doing this till this coming Monday. In the meanwhile, I'll be working out various plans and whatnot. I'll need to work on my site, come up with various projects that will net me in some monies, and work on any actual business methods. Should things work out in the first two months, which I realize is asking a lot, I might well stick with this line of work and LLC myself, though I understand that can cost ~1k USD to get a lawyer to do, so it'd have to be pretty successful to get that done at the end of two months. So I'll have to take things a bit at a time, baby steps as it were.

My site is currently just a Word Press blog with some nifty plug-ins: a syntax highlighter and a file explorer. I'm making current use of the iNove theme, which is quite nice, especially the menu bit at the top. I do have several ideas for things I'd like to change, and I'm highly tempted to just roll my own theme just for [rnfn]. However, on the list of priorities, this is something that is likely to occur if/when I do the whole LLC bit. Or, actually, I might just roll a custom site, depending on the business methods I decide on.

Stuff I'll be working on. I'd really like to finish up the text editor I'm working on. This will probably be greatly aided with it taking full-time precedence. That and if I stop rewriting everything every flippin' moment. Depending on how that goes, and whether I make any monies from that, I might go ahead and make a pixel editor control. Not so much along the lines of paint, though that may very well be what the first version resembles, but rather a simplified GIMP, or Graphics Gale if you're familiar with that. Barring that, I'm not quite sure yet *what* I'd be working on. Some of the ideas I've thrown around include the ever-increasingly-saturated casual games market. But I'd have to really stand out in the crowd for that. A few game ideas have been bouncing off the walls of my brain, mostly revolving around games where, instead of MMO type multi-player, it is only 2-4 people, or even more if the game calls for it. I personally would love to see some of these, though I'm not quite sure if they'd be overly popular. One example of what I'm talking about would be a 2d-rpg game, along the lines of Zelda's Four Swords, where 2(or 1?)-4 players would play against each other and/or interact. A better, yet more complex, game would be along the lines of D&D, where the DM uses a world editor to construct the world before hand and has a separate client/mode during game play where they can do things that might be expected of DMs. Or they can just play along as well.

Business methods. I'm definitely not going to be employing DRM stuff if I can help it. I'm tempted to throw most of my stuff, if I personally distribute the majority of it, under an MIT license(the source, at least), and have it say something along the lines of likeware, or whatever the name for it would be. "This is free, use it all you want, if you like it please consider paying for it." Then again, I'm not overly sure how popular something like that would be, and it definitely probably wouldn't go over well with any publishers, so I'd have to redo my site to make it more like it published stuff. If I do go through a separate party to publish/sell the product, which in this case would most likely be games, I likely wouldn't use this method, but charge a low fee. But enough to make some profit.

It'd be really grand to be in the margin of indie devs that actually succeed.

mirrored here

nerd_boy

nerd_boy

 

Rewrite's Redsign

Jumping on yet another bandwagon, you can also see this post at my blog Any comments there(if, for some weird reason, you decide to comment there instead of here) may take a bit to go through the approval process since I may not check it very often.
Since I'm working on the second official (official here being a word meaning "to appear in rnfnCodeLite's GoogleCode SVN") rewrite, some redesigning is being done as well. For starters, instead of having the control and all of its classes appear in the rnfn.Control.CodeLite namespace, where the user would have to access rnfn.Controls.CodeLite.rnfnCodeLite(which I consider to be somewhat redundant), rnfnCodeLite is now under the namespace rnfn.Controls and contains the various subclasses, both public and internal, across multiple files as a partial class. I've heard that some dislike partial classes, but this seems to best suit my purposes of having the control be a single 'entity' for the user to access as well as not cluttering up rnfn.Controls.

Part of the focus of the redesign is putting the 'lite' back in rnfnCodeLite, both in the size of the dll as well as the memory footprint. So far, haven't done much in that regards, but I haven't gone far into the rewrite either. I have reduced TextNode down to two members, losing the internal bool linked; member and instead adding two more values to the TextNode.Activity enum that are more descriptive and perform the same function, in effect, as the linked bool did.

A major design change is how I'm handling the syntax highlighting and intellisense portions. Prior to this rewrite, I had this:
internal class Syntax:LinkedList
{
public class SyntaxNode
{
internal string text;
internal SyntaxStyle style;

public SyntaxNode(string text,SyntaxStyle style)
{
this.text=text;
this.style=style;
}
}

public class SyntaxStyle
{
internal Pen forePen;
internal Pen backPen;

public SyntaxStyle(Pen forePen,Pen backPen)
{
this.forePen=forePen;
this.backPen=backPen;
}
}
}

I had the intent of expanding upon Syntaxstyle to include numerous common syntax highlighting types, as well as setting up something to allow for custom drawing(per benryves). However, this got all borked up when I realized that some of the features I was going to have in Syntaxstyle would work if they were broken up. For example, a dashed bounding box couldn't be drawn around if(this>that) since the 'if' bit, if nothing else, would probably be drawn a different color, and the box would be two seperate boxes if set for both the 'if' and the rest of the string. So, I'm doing away with Syntax* entirely. TextNode will no longer keep track of syntax data, there will be no syntax styles. As far as rnfnCodeLite is concerned, with this implementation, it will not deal with drawing the text at all. Instead, and doing away with Lexer and Library from the pre-rewrite(which I'd merged into Language or something shortly before this rewrite), CodeEngine will be the combination of anything related to the drawing of the text/code and any intellisense features thereof. It will be similiar to System.Windows.Forms.Control, having a PaintLine, or maybe it will just be Paint, event that will be fired when a line needs to be redrawn. rnfnCodeLite will still keep track of what needs to be redrawn and when, though CodeEngine will be able to flag lines as being needed to be redrawn, which will be redrawn if they are viewable. That code is already in place(at least the tracking of lines, not the drawing).

CodeEngine will probably be the bulk of the editor, and I'm still considering on how much customizing should be done. I'll need to have it be able to access as much of the text as it should be allowed to via properties and what not. I'm still not sure on what events it should have at its disposal... Should I include everything, including keyboard/mouse input? If I include the input, should I already handle it, or let CodeEngine handle it? I suppose I could take a page from System.Windows.Forms again and have an Handled property, where if it is false after having been fired, I'll just go ahead and handle it myself. At least I'll do it for the keyboard input. I might leave the mouse input alone, as the only use for that, that I can see, would be for intellisense, which it *should* be using its own controls for that. Hopefully I'll find a nice balance between customization and ease of use, so one isn't overly limited to what they can do, but they aren't required to handle all sorts of 'default' things if they don't want to.

As far as what implementations of CodeEngine(which is abstract, btw) will come with rnfnCodeLite, I know for a fact it will have something akin to DefaultEngine where all the text will be drawn with the ForeColor of the control. As with the pre-rewrite, this will be what the code engine is set to when set to null in rnfnCodeLite. Beyond that, I'm not sure. In the pre-rewrite(getting tired of that silly word), I was planning to have some sort of general syntax keyword engine, where it had the data for a few common languages(C,C++,C#,Java,Python, various flavours of Basic and asm, maybe more). Depending on how much space that'd take up, however(yeah yeah, I know, space shouldn't be a concern), I may end up making the various languages' data available seperately for download, and, quite possibly, the keyword engine itself. I'll only do this if it takes up a significant amount of space, however. Say, over 5-10kb.

Feedback is much appreciated.

nerd_boy

nerd_boy

 

Quicky

Just a quicky before I leave for work, so no page length entry today. [smile]

Word wrap still hasn't been implemented in the drawing code, not sure if the caret down problem I mentioned last time will be a problem at all, now that I think about it again.

Took care of the lines to be parsed problem by adding a List variable to Text of lines that needs to be parsed, though I imagine I'll be moving that to the rnfnCodeLiteData class before long.

Through some major/minor changes to the code and whatnot, the Invalidated event being sent to all instances of the control is no longer a problem. rnfnCodeLiteData now contains another event, TextChanged, that can be fired by any other class via the suitably named FireTextChangedEvent() method. Every instance of rnfnCodeLite listens in on TextChanged and performs the necessary actions, including but not limited to firing off the Invalidated event(via Invalidate(), of course).

Added TextSegment so there is no long a passing of three seperate variables to indicate one segment of text, and updated all Text methods to use it that need to use it.

Added ReplaceText method to Text so that actions such as writing in insert mode and, in the future, pasting text over highlighted text no longer require two undos to return it to its original state.

Still need to do text selection and mouse movements. May hit tonight, depending what time I work tomorrow(still haven't looked at my schedule for next week, yay me). Have to implement a few caret/mouse methods first if I do.

Thanks for reading, etc., whatnot.

nerd_boy

nerd_boy

 

Blargh

First off, big thanks to both shawn in #gamedev and EqualityAssignment here. shawn assisted me with certain event firing(the whole problem/solution was made obsolete by some other changes I made, but still), and EqualityAssignment pointed out an error I had with my UndoRedo collection. I've made a few quasi-major changes to the way things work, implemented a few more things, and discovered that a few more quasi-major changes might have to be made.
rnfnCodeLite
A Few Quasi-Major Changes
CodeView is no more...
I had originally seperated the CodeView and rnfnCodeLite controls so that there could be a base control and an 'external' control when the external editor was used(I'm calling the popout editor the external editor for now.) However, I was going to have CodeView kinda split whenever the splitview was activated, which would ultimately mean CodeView would add two of itself inside the first one, acting as a split panel container thing whatever-the-deuce-it-is-called. Then it hit me, if CodeView is going to have to be aware of multiple instances of itself, why not just do the same with rnfnCodeLite and do away with CodeView? And so I did. rnfnCodeLite is now self-aware of whether it is the original/base control or whether it is a secondary/child control, mainly by which constructor is called. public rnfnCodeLite() would be the default used by Designer as well as the programmer, thus the base control, and internal rnfnCodeLite(rnfnCodeLiteData) is the constructor to be called when the control is an 'child' control.

Let there be rnfnCodeLiteData...
So, even though CodeView was swallowed up by the rnfnCodeLite class, there still existed a need for a common shared data between the controls and other classes dependant on the data. Thus was rnfnCodeLiteData born, an original name if ever there was one:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;

namespace rnfn.Controls.CodeLite
{
internal sealed class rnfnCodeLiteData
{
internal Text text;
internal Library library;
internal Lexer lexer;
internal Font font;
internal Pen borderPen;
internal Pen gutterPen;
internal Pen backlightPen;
internal Pen unfocusedBacklightPen;
internal Pen linenumberPen;
internal Pen caretPen;
internal Pen optimizedCaretPen;
internal Pen selectionBackPen;
internal Pen selectionForePen;
internal Pen backgroundPen;
internal Pen textPen;
internal Timer caretTimer;
internal bool caretVisible;
internal TextFormatFlags stdFormatFlags=TextFormatFlags.NoPadding|
TextFormatFlags.ExpandTabs|
TextFormatFlags.PreserveGraphicsClipping|
TextFormatFlags.NoPrefix;
internal string externalEditorTitle;
internal bool overwriteMode;
internal ContextMenuStrip textContextMenu;
internal ContextMenuStrip iconContextMenu;
internal Icon iconCollapsed;
internal Icon iconCollapsable;
internal Icon iconCollapsableRegion;
internal Icon iconCollapseEnd;
internal Icon iconExternalEditor;
internal Image imagePopOut;
internal Image imageSticky;
internal bool optionVirtualSpace;
internal bool optionOptimizeCaretDrawing;
internal bool optionShowBar;
internal bool optionShowCollapse;
internal bool optionShowIcons;
internal bool optionShowNumbers;
internal bool optionAutoIndent;
internal bool optionNoTabs;
internal bool optionWordWrap;
internal bool optionAnnoyingBeep;
internal event EventHandler DeadspaceImageChanged;
internal event EventHandler TextPenChanged;
internal event EventHandler FontChanged;
internal event EventHandler BackgroundPenChanged;

internal void FireDeadspaceImageChangedEvent()
{
if(DeadspaceImageChanged!=null)
DeadspaceImageChanged(this,new EventArgs());
}
internal void FireTextPenChangedEvent()
{
if(TextPenChanged!=null)
TextPenChanged(this,new EventArgs());
}
internal void FireFontChangedEvent()
{
if(FontChanged!=null)
FontChanged(this,new EventArgs());
}
internal void FireBackgroundPenChangedEvent()
{
if(BackgroundPenChanged!=null)
BackgroundPenChanged(this,new EventArgs());
}
}
}

And there it is as it currently stands. Mostly options and customization vars there, plus some event firers. Cause, apparently, you can't fire an event *outside* of the class it is inside of. o_O So, yeah, rnfnCodeLiteData is shared between all the rnfnCodeLite instances of the base rnfnCodeLite, and the base is responsible for the initialization of all the contents within the common rnfnCodeLiteData var. All other classes dependent on the data within have been altered as needed.

A Few Things Implemented
Your Input Is Requested...
Implemented most of the non-character keys, such as Enter, the directional keys, Tab, and whatnot. Would probably have gotten more done, but I spent an hour trying to figure out why the Tab key was getting ignored when it turned out that I wasn't moving the caret whenever I was tabbing, so the tab was essentially placed after the caret. :/

Carets...
The caret drawing stuff has been more fully implemented and fixed a few buggies that snuck in. I can't immediately recall if I implemented the code for when optionOptimizedCaretDrawing is set. What I call 'Optimized Caret Drawing' is just drawing over the caret with another color instead of calling Invalidate(), which would redraw the whole control. More on the redrawing of the whole control in a bit...

Word Wrap...
I've stared the implementation of the smart word wrapping option/feature. Currently, the DefaultLexer will wrap on whitespace only, though I may change this at some point. The 'smart' bit comes in with the lexers, though. I've added another abstract method to the Lexer class that is called if word wrap is turned on. This method is to return a string[] that contains the line of text divided up into the desire segments that will then be compounded into the maximum sized segments that won't scroll off the screen.

The only downside to this is that it removes part of the 'smart' from the equation, as the segments won't know how to indent properly/smartly. What I'll probably end up doing is sending an int length argument too, so it can use TextRenderer.MeasureText to get the proper size and indent the text accordingly. Note that the actual text of the line will not be altered, just the drawn.

I just realize, though, that none of the caret-moving code has been modified to handle moving on a word-wrapped line. As in, as it stands, if the word-wrap code were implemented sufficiently, pressing the down key would take you to the next line below, not the next portion of the same line... :/ Dangit, something else to mull over.

Mangled Code...
I'll probably have to go through the code before long since I was mangling it a bit trying to figure out why a few things were doing what they weren't supposed to and weren't doing what they *were* supposed to, etc. :/ Nothing major, but a few tweaks certainly wouldn't hurt things. Sadly, and partly due to the dial-up connection being in use by other parties, I didn't get to commit anything between my last edit and tonight, so there was only one grand SVN commit for all my changes. Yay.

A Few Quasi-Major Changes To Make
On Invalidate()...
As it currently stands, when a change is made to the control, whether the color of the line numbers, or a period added to the second line, way above the view of the screen, or the blink of the caret, the screen is completely being redrawn(only the valid lines, mind you, but redrawn nonetheless.) I'm pretty sure I probably shouldn't be redrawing the client area each time a minor event occurs. Particularly if it changes nothing on the screen. I'm not quite sure how to go about it, though either. I haven't had any experience at redrawing only a small portion of an area and having it be kept insync with the rest of it. I'll have to ask around for advice(or, you know, you could just leave a comment...) or something.

Speaking of Invalidate(), whenever a change is made in one rnfnCodeLite control, whether the base/main one or one of the external editor ones, the changes aren't being made to the other visible controls. So this means that I'll have to setup some sort of event listening thing so that the other controls know when a change has been made where they should redraw. Of course, this brings us back to the potentially needless redrawing of not one, but *multiple* client areas. Blargh.

On Parsing...
Currently, whenever a KeyPress or KeyDown event is fired, the resulting code knows what lines are altered, so knows what lines to send to be reparsed by the lexer. However, I noticed earlier when testing the UndoRedo collection that when undo-ing and redo-ing, it isn't, at least yet, aware of what lines need to be reparsed. So this means that I'll have to come up with some way of flagging the lines to be reparsed. In the very least, I suppose, I could only redraw an area when the lines need to look different than they do. That would still leave the non-optimized blinking caret Invalidate()ing the control every so often, whenever the system is set to have it blink. If it does at all. I nearly missed including the code to handle a blink rate of none.

On Text Selection...
Yes, this is coming up once more. Kinda what threw me off last time, hopefully I'll have a better go at it, and actually get a decent version implemented, once I fix the current 'problems'. I plan on implementing both vertical and horizontal text selecting, and still have to implement the code for keyboard input when dealing with selecting/selected text.
Blargh. A lot of stuff to do and fix, and I'm still aways away. The control's .dll is about 30kb, not sure if I'll get to keep it under the desired 50kb, but oh well.

Apologies if the journal entry seems...pieced together, as it kinda was. Not sure I covered everything, but I think the entry is big enough. If I forgot anything 'important', there is always next time.

Thanks for reading!

nerd_boy

nerd_boy

 

Easier than I'd have thought...

Hullo again. Nothing major to update, but here goes.
rnfnCodeLite
Current 'Public' View
public sealed class rnfnCodeLite : Control
{
// Methods
public rnfnCodeLite();

// Properties
public bool AutoIndent { get; set; }
public Color BacklightColor { get; set; }
public Color BorderColor { get; set; }
public Color CaretColor { get; set; }
public Icon CollapsableIcon { get; set; }
public Icon CollapsableRegionIcon { get; set; }
public Icon CollapsedIcon { get; set; }
public Icon CollapseEndIcon { get; set; }
public string ExternalEditorTitle { get; set; }
public Color GutterColor { get; set; }
public Lexer Lexer { get; set; }
public Library Library { get; set; }
public Color LineNumberColor { get; set; }
public bool NoTabInput { get; set; }
public bool OptimizeCaretDrawing { get; set; }
public Color OptimizedCaretColor { get; set; }
public Image PopOutImage { get; set; }
public Color SelectionBackColor { get; set; }
public Color SelectionForeColor { get; set; }
public bool ShowBar { get; set; }
public bool ShowCollapse { get; set; }
public bool ShowIcons { get; set; }
public bool ShowLineNumbers { get; set; }
public Image StickyImage { get; set; }
public Color UnfocusedBacklightColor { get; set; }
public bool VirtualSpace { get; set; }
}




As you can tell, most of the interaction with the control will be via properties, in addition to the methods provided by System.Windows.Forms.Control. Note that these aren't all the properties, as I still plan on overloading Text(and in fact have the code still from before the rewrite) so that the line-by-line format implemented inside rnfn.Controls.CodeLite.Text will be transparent to the user. The actual text will be sent and received as a String type. Granted, this may change at some point as it deters from the ability to read large files. If it does, it probably won't be till after the first 'major' release of the control.

Scrollbar Deadspace
I talked about this in my last post. I've actually implemented it(thus the title of the post) already, and it is functional. I went with the popup function in the 'root' class and the ability to toggle whether the form/window is on top. At the moment, there are just two ugly icons(both 16x16 and monochromatic), but, like the icons used in the collapsing code feature, they can be changed(though, if you'll notice, the properties say image, not icon). Also, there is currently no 'seperate' icon to help indicate whether the external editor is on top or not(it seems it would be fairly obvious whether it was or not, but I might end up putting this 'feature' in as well.)

While you can change the title of the external editors' forms/windows, you can not, as of yet, change the icon displayed in the taskbar. I'm currently debating whether or not I should allow this to be set like the other image/icons or whether I should just remove the external editor from the taskbar display.

Other things I'm currently considering with the external editor feature involve the code-end of the control. For now, there is no keeping track of the external editors, which means you can't bring them all to the front nor can you close them all if the user so wishes. This is probably something I should implement... Also, there is the fact that this is 'forced' upon the person using the control in their application. Should this be a 'forced' feature, or should it be optional, and if it isn't turned on, just leave the deadspace dead? It'd be easier for it to be forced. :/

LITE aspect
I haven't really been giving any specs about the LITE aspect of rnfnCodeLite, so here goes. At the moment, with everything mostly-untestedly implemented except for keyboard and mouse interactions(as far as I can recall, at the moment), the Release .dll of the control is 25,600 bytes(28,672 bytes on disk, about 10kb compressed). Not overly large, and I'm hoping to keep it under, say, 50-64kb overall. Definately don't want it going over 100kb, personally. Note that this includes the resources, which are currently six monochromatic 16x16 icons. I believe this accounts for ~3kb.

As far as memory usage, I haven't been testing that, really. I've noticed that an empty Form runs at about 7-8MB on my computer, while throwing in the control bumps that up to 11-12MB. So I'd say it is roughly about 4MB of memory used, and we haven't even gotten to the actual text editing part! I'm not sure how this rates, whether it is good or bad, and what I can do to fix it, but I'm not wanting it to be overly large in memory usage, either.
[Edit: Silly me. The form was running in visual studio's host. When run from a compiled executable, the entire thing is about 4MB, form and control. Granted, this is after minimizing/restoring the window, but still. A quick test shows that removing the control from the form, and minimizing/restoring it, causes the mem usage to be about 3MB. So I guess the control, at the moment, takes about 1MB up. Not as bad as I'd thought.]

I've got all night, if I don't blow it, and most of tomorrow to work on this, so if I buckle down(HA!), I should be able to get a substantial amount done.
Also, somebody needs to tell benryves that he needs to post more.

nerd_boy

nerd_boy

 

Too many updates?

I'm beginning to think I'm updating a tad too much, even though this whole writing thing is helping flesh things out. I'm afraid the quantity will take away from the the quality. What little there is.

rnfnCodeLite
Yay. Worked on it a bit more. Per the linebreak support I mentioned last time, I think I'll just have a property or some such that will set the newline character(s) in regards to exporting/importing the text. The internal newline character will continue to be '\n'.

GUI Features
GUI features are aiming to emulate VS's. So it has the gutter area for icons, the line numbers, the thin colored bar, and the collapse area. The collapse area and the line numbers can be completely "in house", so no relying on external code or supporting "plugins" for them. The gutter area will probably have EventHandlers for mouse clicks, and possibly hovers as well, so it will rely on externals, too. It would probably make sense for the gutter "plugin" to be built into the Lexer, as that is the only way it'll be able to change the syntax highlighting if needs be(at least right now.) I suppose I could have a default gutter "plugin" that did the standard breakpoint thing...

The other possibly-not-totally-first-party GUI feature is the thin colored bar. I've never found out what the 'technical' term for that is, or if I did, I've forgotten it. I think benryves called his MarkDirty or somesuch. The only thing I recall having seen it ever do is just turn yellow when a line has been edited, green when the edited line has been saved, and possibly red if the line has an error. So I'm currently debating between keeping it in house and having a method to be called whenever the text is saved/committed/whatever that will turn the yellow lines green, or just having it be external. Heck, I should just have an option for the inhouse green/yellow to be toggled and allow for other classes to change the color of the line. It'd probably, again, be tied in either with the Lexer or Library classes. Yay on-the-fly-decision-making.

Split View
In order to allow for split viewing as well as another feature(mentioned in the next paragraph), I've seperated the "common" variables of the code editor from the "view specific" ones, and created a CodeView class that will be seperate from the rnfnCodeLite class. Now rnfnCodeLite can be considered the parent of one or more CodeViews. As for the actual split implementing, I'm again debating(any feedback on any of my self-debates in this journal is more than welcome). VSExpress only allows for horizontal splitting of the code editor, and only one split at that. I'm torn between that, and allowing each CodeView to be turned into a container for two more CodeViews of either horizontal or vertical nature(not both). The parent CodeView would not be drawn in this case, but act as the host for the two subs. The downside to this is that it can get messy fast and I don't really see any major need for it. Particularly considering the next feature...

Scrollbar Deadspace
Ever since I'd started working on this editor, however long ago that has been, I'd wanted to do something with that deadspace square stuck in the bottom right corner between the horizontal scrollbar and vertical scrollbar. It is empty and has no use, except on occasion it gets used as a resize handle, but that wouldn't work well in the case of an editor control. I'd thought about just having a window pop up that allowed the user to change preferences, but conversations on #gamedev(mainly with benryves, again) showed some potential problems with this. I've since decided upon another use for it, however. An icon/button(whichever looks best in that little square) will be placed there that will open up a form that contains the code editor in it. This way, you can edit the code in the actual control that is part of the running application as well as have a seperate window(s) with the same code. Changes of course would be across all of the displays.

The benefit of this being that you can have a small window that you can code in while, say, looking at code on the interwebs, without the 'bulk' of the rest of the application getting in the way. When I'd discussed it with benryves, he mentioned it'd be a good idea for it to be a modal window(over top of the others; I just use the less technical term of "stickiefied"). I might end up doing that, but it seems to force the user into having to use it only in modal form. What I might end up doing is, instead of having the same button in the scrollbar deadspace on the modal window's control, have another more-different looking button that toggles whether the modal window is in fact modal or not. If I want to get really fancy, and this idea just occured to me so I've not had a chance to think it through to problems, is also allow the button to be 'dragged' off, and whatever window, if any, you 'drop' it on, the window will become 'attached' to that window. So instead of being overtop everything, it'll just be overtop that one window and pulled up with that one window. Then again, that'd probably be insanely difficult to implement.

Other Ideas
Of course, I've managed to think up of some more stuff I'd like to do/implement/whatever that I'll probably forget about and/or never actually do.

GDnet Journal Viewer Thingy
Inspired a bit by Daerax's Journal Comment thingy, I've toyed with the idea of making a custom Journal reader for GDnet. You'd have your favourites/bookmarks off to the side, and an option to check on the most recent journals. Based on your bookmarked journals, it'd check ever so often for journal updates(maybe once an hour?) and comment updates(every 20-30 minutes?), both of which you could read and reply to from within the application. Of course, most people will probably think this is somewhat stupid. Regardless, since there is rumour of the site being redone some time, I'll probably wait till it is redone in case either the format is majorly changed or something is implemented about being notified when someone comments in your journal. wink wink nudge nudge

TiddlyWiki Documentation Exporter
I don't think TiddlyWiki gets enough praise/use. It seems to have quite a bit of potential for, in the very least, small teams. If I ever get around to it, I think it'd be nice to build a library for writing a TiddlyWiki based off of articles or whatnot. Once having gotten that done, I might add onto the library with a code documenter.

Microsoft Document Explorer Replacement?
In line with documentation programs, I'd thought about this awhile back. Microsoft Document Explorer does seem somewhat useful, but it seems to be mostly for Microsoft. Quick Google searches indicate that it isn't redistributable. The "unofficial" viewers that I saw explicetly stated source code wouldn't be available *and* it wouldn't work with just the .NET Framework SDK installed, which leads me to presume it won't be used by non-.NET proggers. So perhaps a competitor is in order(if you know of any, please tell me; I haven't been able to find any, really).

It'd have to have improvements over Microsoft's Document Explorer, becoming a bit modern. I was thinking along the lines of wiki-izing it(and removing its dependancy on IE, perhaps) while retaining the search, index, how-do-I, and contents to some degree. Mostly just the search and index. Now, by wiki-izing it, that may raise the concern that 'critical' and relevant data can be overwritten accidentally, which would be *bad* unless some form of revision was kept in the file format, too. So it'd probably be the original help page couldn't be edited, but you could add your own 'notes' or paragraphs to the main page or the individual sections of a page. This would allow things to be personalized, whether for comments on the stupidity of a requirement to the marking of a specs error.

Geyser
As long as I'm spouting(no pun intended(maybe)) out these wacky ideas(which, if you like, please, feel free to use!), here is another one. Steam's popularity as a digital distribution program got me to thinking about whether or not there was a need for a 'free' digital distributor for freeware/shareware/demoware and possibly commercialware, too. Instead of having a central server(s), it'd be use a form of RSS/XML. Links could be posted to it from websites or from an installed game/application. Or, when a game/application was installed, it could register the link with Geyser(the name of the program), which would then non invasively ask the user, next time they're looking at Geyser, if they would like to use Geyser with that link. If so, it'd be added with the rest of the links.

These links, always updated, would allow updates, mods, new games to be announced(again, non-invasively) in the program. On occasion, they might suggest a similiar site's link, which could be accepted or rejected. The persons providing the links would have to host the content on their own servers, of course, with possibly a 'key' to prevent others from hotlinking if they so desire. Non-commercialware could be directly downloaded via Geyser, but to start out with, commercialware would redirect to the appropriate page for the user to buy the software.

Thanks for reading! And any feedback is always welcome. :]
Thrice blasted spelling errors! I'm going to have to start using FireFox instead of Opera to write these entries.

nerd_boy

nerd_boy

 

Twas the night before Christmas...

Well, technically tis the "almost evening before Christmas", but whatever.

rnfnCodeLite
CollapseData has been added, but still needs fleshing out, probably when I implement the collapsing code. TextNode should be done. I made a little undo/redo engine, wittly named UndoRedo. Text, too, should be done.

rnfn.Collections.UndoRedo
Here is the source for it(seriously, though, why the blazing freaking blasted deuce isn't "Select All" on the menu that pops up when you right-click the text area in VS? It doesn't make any sense for it not to be there![disturbed]):
using System;
using System.Collections;

namespace rnfn.Collections
{
internal class UndoRedo
{
private ArrayList undoStack;
private ArrayList redoStack;
private bool ignorePushes;

public UndoRedo()
{
undoStack=new ArrayList();
redoStack=new ArrayList();
ignorePushes=false;
}

public T PopUndo()
{
if(undoStack.Count==0)
return default(T);

T temp=(T)undoStack[undoStack.Count-1];
undoStack.RemoveAt(undoStack.Count-1);
redoStack.Add(temp);
return temp;
}

public T Undo()
{
return PopUndo();
}

public T PeekUndo()
{
if(undoStack.Count==0)
return default(T);
return (T)undoStack[undoStack.Count-1];
}

public T[] PeekAllUndo()
{
if(undoStack.Count==0)
return default(T[]);
return (T[])undoStack.ToArray(typeof(T));
}

public void PushUndo(T data)
{
if(!ignorePushes)
{
undoStack.Add(data);
redoStack.Clear();
}
}

public void PushUndo(T[] data)
{
if(!ignorePushes)
if(data!=null)
undoStack.AddRange(data);
}

public T PopRedo()
{
if(redoStack.Count==0)
return default(T);

T temp=(T)redoStack[redoStack.Count-1];
redoStack.RemoveAt(redoStack.Count-1);
undoStack.Add(temp);
return temp;
}

public T Redo()
{
return PopRedo();
}

public T PeekRedo()
{
if(redoStack.Count==0)
return default(T);
return (T)redoStack[redoStack.Count-1];
}

public T[] PeekAllRedo()
{
if(redoStack.Count==0)
return null;
return (T[])redoStack.ToArray(typeof(T));
}

public void PushRedo(T data)
{
if(!ignorePushes)
redoStack.Add(data);
}

public void PushRedo(T[] data)
{
if(!ignorePushes)
if(data!=null)
redoStack.AddRange(data);
}

public bool IgnorePushes
{
get{return ignorePushes;}
set{ignorePushes=value;}
}
}
}

It seemed simple enough to write. You might say...overly simple. If you see any mistakes or problems with it, pointing them out would be much appreciated. I used two arrays to allow multiple items to be peeked or pushed without too much trouble. The only multiple action that I didn't include was the actual undoing/redoing, as I thought it might lead to a wee bit o' confusion. Though I might end up adding that feature before all is said and done with. I think I got the push/peek/pop terms correctly. Embarrasingly enough, I was 75% of the way done with this code when I realized I'd borked it up by having poke in there instead one of them(I think pop?), so meh.

The main thing, though, that I would like to point out is the IgnorePushes property. The reason I added this is because the Text code that is called to undo/redo the text merely sends the data to either the AddText or RemoveText, depending on which is appropriate, both of which in turn make use of the undo/redo engine. To avoid problems where multiple undoing would just toggle between two actions, the undo/redo functions set the undo/redo engine to ignore the pushes, so no toggling.

rnfn.Controls.CodeLite.Text
using System;
using System.Collections.Generic;
using System.Text;

using rnfn.Collections;

namespace rnfn.Controls.CodeLite
{
internal class Text
{
internal class TextAction
{
internal enum Activity{ADDING,REMOVING};
public int line;
public int charOffset;
public Activity activity;
public string text;

internal TextAction(int line,int charOffset,Activity activity,string text)
{
this.line=line;
this.charOffset=charOffset;
this.activity=activity;
this.text=text;
}

internal static TextAction AddText(int line,int charOffset,string text)
{
return new TextAction(line,charOffset,Activity.ADDING,text);
}

internal static TextAction DeleteText(int line,int charOffset,string text)
{
return new TextAction(line,charOffset,Activity.REMOVING,text);
}
}

private LinkedList text;
private UndoRedo undoredoEngine;

public Text()
{
text=new LinkedList();
text.AddFirst(new TextNode());
}

public void Undo()
{
TextAction temp=undoredoEngine.Undo();

if(temp==null)
return;

undoredoEngine.IgnorePushes=true;

if(temp.activity==TextAction.Activity.ADDING)
{
RemoveText(GetLineFromNumber(temp.line),temp.charOffset,temp.text.Length);
}
else if(temp.activity==TextAction.Activity.REMOVING)
{
AddText(GetLineFromNumber(temp.line),temp.charOffset,temp.text);
}

undoredoEngine.IgnorePushes=false;
}
public void Redo()
{
TextAction temp=undoredoEngine.Redo();

if(temp==null)
return;

undoredoEngine.IgnorePushes=true;

if(temp.activity==TextAction.Activity.ADDING)
{
AddText(GetLineFromNumber(temp.line),temp.charOffset,temp.text);
}
else if(temp.activity==TextAction.Activity.REMOVING)
{
RemoveText(GetLineFromNumber(temp.line),temp.charOffset,temp.text.Length);
}

undoredoEngine.IgnorePushes=false;
}

//TODO: Optimize
public int GetNumberFromLine(LinkedListNode node)
{
int line=0;
LinkedListNode temp=text.First;

while(temp!=node)
{
if(temp.Next==null)
return -1;
temp=temp.Next;
line++;
}
return line;
}
//TODO: Optimize
public LinkedListNode GetLineFromNumber(int lineNumber)
{
if(lineNumber0)
return null;

LinkedListNode temp=text.First;

for(int i=1;i temp=temp.Next;

return temp;
}

public void AddText(LinkedListNode line,int charOffset,string text)
{
line.Value.text=line.Value.text.PadRight(charOffset,' ')+text;

if(line.Next!=null)
{
line.Value.text+="\n"+line.Next.Value.text;
this.text.Remove(line.Next);
}

UnNewlineify(line);
}
public void RemoveText(LinkedListNode line,int charOffset,int length)
{
int tempLength=0,tempLines=0;
LinkedListNode tempNode=line;
tempLength=line.Value.text.Length-charOffset;

while(tempLength {
if(tempNode.Next!=null)
{
tempNode=tempNode.Next;
tempLength+=tempNode.Value.text.Length;
}
else
{
length=tempLength;
}
}

Newlineify(line,tempLines);
line.Value.text.Remove(charOffset,length+tempLines);
//HACK: Shouldn't need this line...
UnNewlineify(line);
}

private void UnNewlineify(LinkedListNode node)
{
string[] temp=node.Value.text.Split('\n');

for(int i=temp.Length-1;i>0;i--)
text.AddAfter(node,new TextNode(temp));

node.Value.text=temp[0];
}
private void Newlineify(LinkedListNode node,int lines)
{
while(node.Next!=null && --lines>0)
{
node.Value.text=node.Next.Value.text;
text.Remove(node.Next);
}
}

public static string CRLN2LN(string text)
{
return text.Replace("\r\n","\n");
}
public static string LN2CRLN(string text)
{
//The double replace is in case there are mixed line feeds provided,
// in which case an "\r\n" would become "\r\r\n" under one replace.
return text.Replace("\r\n","\n").Replace("\n","\r\n");
}
}
}

This is my current Text class, very much modified from my previous one, for those of you that recall it. If any of you do. Keep in mind, that none of it is tested, yet, so there may be glaring bugs to you that I've yet to stumble upon.

TextAction is for UndoRedo. It did have an extra field, public string message;, but since undo/redo will, at this point in time, be handled on a character by character basis(except for the instances where portions of text are added, such as pastes or code-side adding), so having a message with the value of "Added the text:'c'" and the text field having a value of "c" makes very little sense. I'll probably add extra values to the Activity enum for events such as copying/cutting/pasted/etc.

GetLineFromNumber and GetNumberFromLine are still used to convert a LinkedListNode to a line number, and vice versa.

AddText and RemoveText are my biggest 'concern' in terms of bugginess. AddText is pretty much based on the old AddText, and RemoveText was designed...'inversely' to it, in a sense. It just seems to clean, and a bit smooth with the Undo and Redo functions, for it to be real for me. There has got to be a glaring bug I'm not seeing. Oh well, guess I'll just have to test it a few times.

Newlineify and UnNewlineify are used by AddText and RemoveText to handle the possibility of the adding or removal of the line feed character, '\n'. '\n' is the 'officialy' newline char for the control, but, of course, it can't really be part of any line.

CRLN2LN and LN2CRLN are my first and current attempts at also supporting other versions of newline seperators(are there any other accepted ones, other than the two here?) while maintaining the internal '\n' as the line seperator. I don't think I've used either of these, but there will be an option to add and view text with the "\r\n" newline as well as "\n". Again, these are my first, horrid attempts at this, so they'll probably be redone or altered or something at somepoint.

No rants, or anything else, really, today. I've got coding to do and gaming to game.

Thanks for reading, and have a very Merry Chrismahanakwanzika!
[Disclaimer: No review for errors was made after the writing of this post. I've got other things to do tonight!]

nerd_boy

nerd_boy

 

Almost...

It is about 11:35pm EST, so I'm not quite sure whether this posting will make Friday or Saturday in GDNet world, but I'm close! Also, I'm attempting a cleaner, more professional look via formatting and the todo list above (code stolen directly from Evil Steve's journal and then prettified/modified) so that my big globs of text don't hurt your eyes. In an attempt at my defense, I had been considering making use of the tag as of this morning, but I just think now I'll steal more ideas from Evil Steve's (and others') journal(s) and throw in headers and junk. Just to mix things up and make it readable, for a change.


rnfnCodeLite Status
In so far as my status since yesterday, I haven't gotten to work on it much. I think I wrote(and possibly rewrote) some things early this morning before I went to work, but nothing noticable. I did catch benryves on IRC this morning, though. Apparently I'd misunderstood his comment on allowing for custom drawing on the text.

I'd thought he had wanted the ability to handle drawing the text or other items in the middle of the text. Which is to say, instead of a simple line of "Sally sold seashells on the seashore.", with custom drawing one might add pictures. Such as: "Sally sold seashells on the seashore." Apparently all he'd been talking about was being allowed to draw behind and on top of the text, not drawing anything in addition to. This is by no means going to cause the problem I mentioned in my previous entry, so I'll probably do it. The only thing is, though, that I might incorporate it into the Lexer and Library classes, since those two would already have the data necessary in each TextNode to know what to draw. In the case of the KeywordLexer and KeywordLibrary, I'll probably allow some sort of drawing if I can work it in. Otherwise, anyone wanting their own custom drawing may have to end up either writing a new Lexer/Library(depending on context) or inheriting the Keyword... variant of either.


Operating Systems Rant, Part 1
I had mentioned something about a rant on the state of operating systems, but since I just woke up from my nap, I'm feeling somewhat relaxed. That and I'm not about to attempt to completely undermine the current OSes seeing as they actually have something that does something. I'm not going to pretend to have sufficient understanding of drivers, file systems, memory management, and other components of an operating system. I've a general idea about these things, but not sufficient to start berating the current setup. That being said...

What with three major operating system, all having been around for a good while in computer years, one or two followups(I'm thinking maybe FreeBSD?), and plenty of smaller ones, there are plenty of OSes. Heck, there are plenty of Linux distributions, alone. But there hasn't been a major new player, as it were, since Linux(which came out, what, 1991?) If nothing else, even if it were based on one of the three major ones, a fresh rewrite/outlook of one of these three might be welcome.

One thing this new OS shouldn't be, though, is a browser. I'd thought it would be nice in the past if there was an OS that was basically a consistently up-to-date browser, and still do to some degree, but that shouldn't be the sole...purpose of the OS. If it were to be incorporated into the new OS, it should be more of a 'mode'. You could, say, swap from desktop mode to web mode, and have your applications in desktop mode either running in the background or suspended completely(such as when the computer is put on sleep mode) depending on preferences set. This web mode wouldn't have to look overly different than your desktop mode, though. Instead of program icons on your desktop, you could have bookmark icons on your 'webtop'. Each webpage or application could have its own window or be tabbed in the same window(I'm thinking of Google Chrome's tabbing, where it is done in the titlebar). So while the entire OS isn't geared towards web surfing, it does basically allow it. The only major thing, and possibly its pitfall, is that it should by default adhere *perfectly* with the then-current web standards while also allowing for 'modes' that emulate another browser, if possible, should quirks still arise from sites designed for browser 'X'.


Trying to keep from ranting forever, I'll just break my OS rant up into parts, not necessarily putting a part into every entry. And hopefully this format will make things more readable, though is subject to change until I settle into a 'groove' with it.

Thanks for reading!

[EDIT: Something freaky weird is going on with the times. The time this journal is listed as being posted is neither the time I started writing it (11:35EST) nor the time I submitted it (~12:23EST). :o]

nerd_boy

nerd_boy

 

Y HALO THAR

It would seem that I'd fallen off the face of JournalWorld for a bit. Or maybe I just broke through its space-time continuum. We may never know.


In regards to any actual progress I may or may not have made on my rnfnCodeLite project, I must say not much. I don't think I've worked on it, really, for almost a month and a half. :[ Yay procrastination.

So in order to get myself familiar once more with my code, and because there are areas that needed rethinking/reworking/rewhatevering, I saved copies of the code elsewhere and am writing it from scratch. The good news is that it won't take nearly as long as it did originally to write since I already have it(along with printed copies of the three main bodies) to look/copy from. The bad news is that feature creep may creep in, and I'm already trying to rewrite everything. :/ Fortunately, if I do get tired of it and want to start over, I *did* remember to make a commit to the SVN on the project's GoogleCode...thing before starting over. Go me.


A few main areas that I'm wanting to change are as follows:

Firstly, I'd originaly been writing it with the idea in my mind that I might allow third-party extensions and plugins to be made for it outside of the syntax/intellisense "plugin" system, if it can be called a plugin system. I'm sure I was doing it wrong, plus there were events being fired all over the place and events not being fired where I'm sure there should be. So I've decided to ditch the whole plugin thing. In order to make it lite and fast, any features/'extensions' would be worked in directly with the code. If someone really wanted a custom feature bad enough, the code would be available for them to download and alter(like that's a good idea!)

Secondly, in my previous post long long ago(possibly somewhere on the other side of JournalWorld's continuum), benryves had made a comment about wanting to draw a little box around text and I'd responded by stating I'd thrown in a way for custom drawing to be done. I KINDA LIED. All I had done was added a delegate that could be set and would receive the Graphics and boundary for the text to be done. Nothing else was added in the code to handle this. Seeing as all my code had relied on solely text being in the data for the syntax, this would screw everything up. Prior to the delegate, each SyntaxNode node had variable for the text, the fore color and the back color(background). So "foobarbiz" with bar colored differently than "foo" or "biz" would be split into "foo"-"bar"-"biz" in a LinkedList data structure(one of these was in each TextNode which was, subsequently, thrown in its own LinkedList under Text) along with their associated colors. I had intended on adding options for certain common intellisense drawings such as dashed lines, jagged lines, a box, a dashed box, underlined, italics, bold, weblink, etc., all along with their own colors. These 'enhancements' would have been contained within the Rectangle bounds of the string in question, so any and all width concerns would have been based solely on the text. The entirety of the text contained within the various SyntaxNodes of a TextNode was kept in a seperate StringBuilder in its entirety, which, when changed, would reparse the whole line(might have-been/will-be changed as a flag so multiple edits can be done between renderings without being parsed between each edit), creating a new LinkedList for the DrawLine function to in turn parse and render onto the screen where appropriate. Throwing the delegate in there means that I would have to have some manner of calculating the drawn area seperately and calculating the width of each SyntaxNode seperately, regardless of whether it is custom data or a string(I've toyed with adding icons, which might not cause the same problem since I would draw them as a square, with a width/height of the Font property's height), causing more calculations. In addition the the extra work, I would also not be able to properly use TextRender.MeasureText's results as they would probably be incorrect due to the fact that I would have access to the Graphics of the control itself withing either SyntaxNode or a wrapper class I considered writing, Syntax. I might just throw it out and try to offer as many common drawing features as possible.

Now, after that long flippin' a** paragraph(I apologize to the grammar sensitive), on to number thirdly. Wait, I'm not sure I've gotten far enough in my rewrite for there to be a thirdly... If there were, I'd probably say... that dratted text selection thing I never got to. I think putting that off is why I haven't worked on this thing in forever. :/ Meh. Maybe I should just yank out the event firings, the custom drawing, and keep the rest of the code, and go ahead and get text selection working. Except, if I *were* to take out the event firings, that leads us to my fourthly...

Fourthly(and here I wasn't sure if I even had a thirdly), the undo/redo engine. It was going to depend on the event firings, although I'm tempted to just incorporate it directly into the Text class, so whenever the text *is* edited(all of the string manipulating/editing is done, of course, through Text), it would just be all *voila!* and whatnot. Except then I wouldn't know what event(copy/paste/cut/backspace/delete/whateverelse) was the reason for this undo action. :/ Unless, of course, I were to make Text access the clipboard in place of the control, so the control would call, say, CopyFromClipBoardToLine(23)(No, I don't actually write my functions like that. At least, not usually.) and Text would actually know it was a Copy event and could tell the Undo/Redo engine that... Hmmmm... >_> I might have to start using this journal more often to get these ideas.

So that's basically it for the rnfnCodeLite project right now. I hope to work on it more this evening once I finish this horrificily long journal entry(making up for all this lost time!)(and no, it isn't quite done, either!)


In news of other projects, I did get this little ditty done:

Pakiz was just a quick thing I did one day so I actually had a finished project to my name that I hadn't written when I was 18 or under. :D It just allows for you to alter the Accessed/Written/Created time of a file. The only 'problem' that I've noticed so far is that when you alter any of the three, other than the Accessed time, the Accessed time itself is changed to whenever you changed the other two. Probably something I should change, if I thought anyone would ever use the program(though I did put some actual work into designing the GUI, believe it or not.)

I have been tossing around the idea, and have already worked on it to some extremely small degree, of a task/idea management program, called Mnemosyne's Tablet(Clicky for those who don't know who Mnemosyne is.) Instead of displaying tasks/ideas as a list or other linear structure, I was thinking along the lines of having the actual program divided into two seperate "halves". Really three areas shared between two controls(e.g., when the mouse was over or had been over one side, that side expanded to take up 2/3's of the program's client area, while the other side shrunk to 1/3, and vice versa). The right side would contain the actual data of a task/idea. I hadn't actually decided as to what the data would be, but I was debating between either plain text and a wiki type setup. Plain text would probably be easiest/least-problematic, but the wiki type setup would allow more types of data to be shown(but then I'd feel the need to include all non-web data(images,files,etc) in the task's file). The left side would be the actual task/idea layout area. It'd basically be an open space with the tasks position in there(I was planning on going for a cloud/elliptical border around the task/idea names). These could be dragged around on the space to allow for a certain order, should the user choose, that their eye would place some importance too(say for a game project, artistic types to one side, programming types to the other). Lines would be drawn between the tasks/ideas depending on the dependency of the tasks. And so on and so force. Clicking on a task/idea would bring up its data on the rightside pane. Double clicking would cause the control to zoom in, as it were, from the general plane to the plane of the task in question. This would allow multiple levels of tasks/ideas. On the top most plane, you could have basic tasks such as "Finish rnfnCodeLite" and "Advertise for rnfnCodeLite". Zooming in on "Finish rnfnCodeLite"(possibly being shown at 45% completion) would reveal the tasks for it. Say one of them were "Undo/Redo engine". Double clicking that(taking us to, basically, "root"/"Finish rnfnCodeLite"/"Undo/Redo engine") would reveal the various tasks that were required for this task. Not sure if I'll ever finish it, as the only reason I started was the delay of capnmidnight's management software(cause, you know, he just has to have a life outside of coding)'s release. Not sure if the idea is even a good one.

I was going to rant and rant about something I talked about in #gamedev today, OSes, their current state, the 'need' for a new one, and the things it would/should/could do and implement to be a better OS, but I think this is a long enough entry for one day(hope I don't break any size restrictions[disturbed]), and it'll give me something to talk about tomorrow, so I don't wait eons between my posts.

Thanks for reading! :D

[EDIT: Grrrrgrgrgrrrr! [disturbed] I keep finding another grammatical error everytime I read this dratted thing!]

nerd_boy

nerd_boy

 

Updates all around!

Urg... I made quite a few spelling/grammar mistakes in that. The only 'information' mistake that I've noticed is that I said mouse operations other than right-clicking, scrolling, and cursor placment have been implemented. That should be have been *not* implemented. [disturbed]

nerd_boy

nerd_boy

 

Yay

Haven't done a whole lot, but I managed to fix some things in the past day or so. Most of it had to do with my ignorance of things. Imagine that.

The backspace key now works. Apparently Control.IsInputChar states that the backspace should count as a char. I didn't notice this until I started playing around with using TextRenderer.DrawText to draw the text instead of Graphics's lovely-yet-flawed DrawString method(see following paragraph). DrawText was displaying what I presume was the 0x08(backspace) ASCII char. My fix at the moment is just to call my class's override of the IsInputChar method when handling keyboard events. Backspacing works quite fine, now.

In regards to the problem I mentioned in my previous(and previous previous, I'm sure) post about the caret going off to the left and not being where it is supposed to in the line, I've solved that. Graphics's differences between MeasureString and DrawString have apparently existed since .NET 1.1, but Microsoft is refusing to fix it on the grounds that it would break already deployed applications[Clicky]. They came up with TextRenderer to solve the problem. I found this out by reading various forum posts. That still didn't work for me, following what was stated in the forums. Turns out that both MeasureText and DrawText need to be passed TextFormatFlags.NoPadding, or else spaces are thrown on the sides. I swear I didn't see this when I was researching it. :/

Also, when I was playing around with the actual control in a form the other day, testing and debugging, etc., I found out that when the control's width was increased(the height didn't seem to factor in; at least not noticeably), there was an extremely obvious slow down in the drawing. At least a second or two would go between the keypress and the char showing when it was fullscreen. Definately not good for a text editor. I changed the OnPaint method to draw straight to the double-buffered e.Graphics provided as an argument. I had been drawing to a Bitmap and then drawing that to the screen when done. Turns out that considerably speeded things up, and there is no delay that I can see now. Also turns out that as soon as you start typing, the line underneath doesn't draw. All the other lines do, but not that one. Just gotta figure that out, now.

Still have to implement highlight selection, scrollbars, and proper virtual space, and undo/redo. I'll be focusing solely on the text editing bit until it is 'standard' with the TextBox control. Then I'll focus on the code editing bits, most of which is implemented already. Shouldn't be too difficult, as the 'worst' bit will be implementing clicking of the line icons. After that, since things should be pretty much done, I'll clean it up and write up a basic Lexer and Library that should work for most syntax highlighting and intellisense operations.

nerd_boy

nerd_boy

 

Almost a month...

I seriously need to post more in this thing. And stop playing Oblivion. At this rate, I'm paying ~$4 a post.

I've redesigned everything and each different subclass, as well as the CodeLite class itself, has its own file. Here is a regurgitation of Lutz Roeder's .NET Reflector's dissassembly of the dll (Freaking awesome tool, by the way, for anyone who lives underneath a rock):


public class CodeLite : Panel
{
// Fields
private Pen borderPen;
private Lexer lexer;
private Library library;
private ViewPanel mainViewPanel;
private bool showBorder;
private bool showLineBarColors;
private bool showLineCollapse;
private bool showLineIcons;
private bool showLineNumbers;
private StringFormat stringFormat;
private Text text;
private EventHandler TextEdited;

// Events
public event EventHandler TextEdited;

// Methods
public CodeLite();
private void OnInvalidate(object sender, InvalidateEventArgs e);
private void OnPaint(object sender, PaintEventArgs e);
private void OnResize(object sender, EventArgs e);
internal void OnTextEdited(object sender, Text.TextEditedEventArgs e);

// Properties
public bool ShowBorder { get; set; }
public bool ShowLineBarColors { get; set; }
public bool ShowLineCollapse { get; set; }
public bool ShowLineIcons { get; set; }
public bool ShowLineNumbers { get; set; }

// Nested Types
public abstract class Lexer
{
// Fields
protected Pen defaultPen;

// Methods
protected Lexer();
public abstract void ParseLine(CodeLite.TextNode line);

// Properties
public Pen DefaultPen { get; set; }
}

public class LexerData
{
// Methods
public LexerData();
}

public class Lexers
{
// Methods
public Lexers();

// Nested Types
public class DefaultLexer : CodeLite.Lexer
{
// Methods
public DefaultLexer(Pen defaultPen);
public override void ParseLine(CodeLite.TextNode line);
}
}

public static class Libraries
{
}

public abstract class Library
{
// Methods
protected Library();
}

public class LibraryData
{
// Methods
public LibraryData();
}

public class SyntaxNode
{
// Fields
public Pen color;
public string text;

// Methods
public SyntaxNode(string text, Pen color);
}

public class Text
{
// Fields
private int caretOffset;
private LinkedListNode currentLine;
private EventHandler FocusChanged;
private LinkedList text;
private EventHandler TextEdited;
private EventHandler TextNodePropertiesChanged;

// Events
public event EventHandler FocusChanged;
public event EventHandler TextEdited;
public event EventHandler TextNodePropertiesChanged;

// Methods
public Text();
private void AddLineAfter(LinkedListNode line);
public void AddLineAfter(int lineNumber);
public void AddLineAfterCurrentLine();
private void AddLineBefore(LinkedListNode line);
public void AddLineBefore(int lineNumber);
public void AddLineBeforeCurrentLine();
private void AddText(LinkedListNode line, int charOffset, string text);
public void AddText(int lineNumber, int offset, string text);
public void AddTextAtCaret(string text);
public void AddTextOnCurrentLine(int offset, string text);
public void AdvanceCaret();
public void AdvanceCurrentLine();
public void DeleteCurrentLine();
private void DeleteLine(LinkedListNode line);
public void DeleteLine(int lineNumber);
public void DeleteLineAfter(int lineNumber);
public void DeleteLineAfterCurrentLine();
public void DeleteLineBefore(int lineNumber);
public void DeleteLineBeforeCurrentLine();
public CodeLite.TextNode GetCurrentTextNode();
protected LinkedListNode GetLineFromNumber(int lineNumber);
protected int GetNumberFromLine(LinkedListNode node);
public string[] GetTextFromCurrentLine(int lines);
private CodeLite.TextNode GetTextNode(LinkedListNode line);
public CodeLite.TextNode GetTextNode(int lineNumber);
public string GetTextOnCurrentLine();
private string GetTextOnLine(LinkedListNode line);
public string GetTextOnLine(int lineNumber);
private string[] GetTextOnLines(LinkedListNode line, int number);
public string[] GetTextOnLines(int startLineNumber, int endLineNumber);
private void RegisterTextNodeEventHandler(CodeLite.TextNode node);
public void RemoveText(int lineNumber, int startOffset, int endOffset);
private void RemoveText(LinkedListNode startLine, LinkedListNode endLine, int startCharOffset, int endCharOffset);
public void RemoveText(int startLineNumber, int endLineNumber, int startOffset, int endOffset);
public void RemoveTextAfterCaret(int charsToRemove);
public void RemoveTextBeforeCaret(int charsToRemove);
public void RemoveTextOnCurrentLine(int startOffset, int endOffset);
public void RemoveTextOnCurrentLine(int endLineNumber, int startOffset, int endOffset);
public void RetreatCaret();
public void RetreatCurrentLine();
private CodeLite.TextNode SetupNewTextNode();
[EditorBrowsable(EditorBrowsableState.Never), Browsable(false)]
private void TextNodeChanged(object sender, CodeLite.TextNode.NodeEventArgs e);
protected void UnNewLineText(LinkedListNode line);

// Properties
public int CaretOffset { get; set; }
public int CurrentLine { get; set; }
public int LineCount { get; }

// Nested Types
[Serializable]
public class LineDoesNotExistException : Exception
{
// Fields
private int lineNumber;

// Methods
public LineDoesNotExistException();
public LineDoesNotExistException(int lineNumber);
public LineDoesNotExistException(string message);
protected LineDoesNotExistException(SerializationInfo info, StreamingContext context);
public LineDoesNotExistException(string message, Exception inner);

// Properties
public int LineNumber { get; }
}

public class TextEditedEventArgs : EventArgs
{
// Fields
private TextEditingActions action;
private int startLine;
private int startOffset;
private string[] text;

// Methods
public TextEditedEventArgs(int startLine, int startOffset, string text, TextEditingActions action);

// Properties
public TextEditingActions Action { get; }
public int EndCharOffset { get; }
public int EndlineNumber { get; }
public int StartCharOffset { get; }
public int StartlineNumber { get; }
public string String { get; }
public string[] StringSplitIntoLines { get; }

// Nested Types
public enum TextEditingActions
{
ADDED,
REMOVED,
REPLACED
}
}
}

public class TextNode
{
// Fields
private Color barColor;
private int collapseData;
private CodeLite.LexerData lexerData;
private CodeLite.LibraryData libraryData;
private Bitmap lineIcon;
private EventHandler NodeDataChanged;
internal LinkedList syntaxData;
internal string text;

// Events
public event EventHandler NodeDataChanged;

// Methods
public TextNode();

// Properties
public Color BarColor { get; set; }
public int CollapseData { get; set; }
public CodeLite.LexerData LexerData { get; set; }
public CodeLite.LibraryData LibraryData { get; set; }
public Bitmap LineIcon { get; set; }
public LinkedList SyntaxData { set; }

// Nested Types
public class NodeEventArgs : EventArgs
{
// Fields
protected NodeDatatypes datatype;

// Methods
public NodeEventArgs(NodeDatatypes type);

// Properties
public NodeDatatypes DataType { get; }

// Nested Types
public enum NodeDatatypes
{
SYNTAXDATA,
LEXERDATA,
LIBRARYDATA,
COLLAPSEDATA,
COLOR,
ICON,
TEXT
}
}
}

public class ViewPanel : Control
{
// Fields
protected bool caretShow;
protected Timer caretTimer;
protected ScrollBar hscroll;
private string inputChars;
protected CodeLite master;
protected Panel panelDeadspace;
protected Menu selectionContextMenu;
protected int topLine;
protected ScrollBar vscroll;

// Methods
public ViewPanel(CodeLite master);
private int CalculateNonTextOffset(Graphics graphics);
protected void DrawLine(Graphics graphics, int lineNumber);
protected override bool IsInputChar(char charCode);
protected override bool IsInputKey(Keys keyData);
private void OnCaretTimerTick(object sender, EventArgs e);
private void OnKeyDown(object sender, KeyEventArgs e);
private void OnKeyPress(object sender, KeyPressEventArgs e);
private void OnKeyUp(object sender, KeyEventArgs e);
private void OnMouseDown(object sender, MouseEventArgs e);
private void OnMouseMove(object sender, MouseEventArgs e);
private void OnMouseUp(object sender, MouseEventArgs e);
private void OnMouseWheel(object sender, MouseEventArgs e);
private void OnPaint(object sender, PaintEventArgs e);
private void OnResize(object sender, EventArgs e);
protected void ResizeScrollBars();
protected void UpdateScrollbars();
private void UpdateScrollbarValues(object sender, CodeLite.Text.TextEditedEventArgs e);

// Properties
public Panel DeadspacePanel { get; set; }
}
}



Since things are a bit more organized, perhaps, I think I'll go ahead and (re)explain things.

TextNode
Contains basic properties for each line in the code editor(and was previously Node, which was pointed out as an incredibly nondescript name.) The actual text of the line is kept internal and is only accessed by Text. syntaxData is set by the control's designated lexer and is used when drawing the text. It is basically a linkedlist(could have been an array, I suppose; might yet) of text and its color, though other features may be added to support the wavey/spikey underlining of words, etc. lexerData and libraryData are to be used by the designated lexer and library so it doesn't necessarily have to reparse the whole line when a change is made(perhaps stores the syntaxData equiv when commented and restored when uncommented). The rest are GUI based elements, and should be self-explanatory.

Text
Text is now neither solely LinkedList nor my own collection. Risking the chance of having certain personages tell me that they told me so, I went ahead and used a wrapper for LinkedList. It may look like an insane amount of functions(and redundant at that), but Line(...),CurrentLine(...),Caret(...) all pretty much a private version of Line(...) with different parameters. CurrentLine(...) will be faster than Line(...) since the latter has to take the line number specified in the arguments and get the correlating LinkedListNode, whereas currentLine keeps track of the current line, etc. This class probably isn't entirely done, as I'm adding, changing, and debugging as I'm using it.

Lexer and Library
These two are 'wrapper' classes for customized Lexers and Libraries. A default of each is intended to be 'shipped' with the end control. Lexer will have two, one of which, Lexers.DefaultLexer is already written. DefaultLexer is for non-syntax highlighting. All the text in a line is set to the color of the defaultPen. An addition lexer, Lexers.KeywordLexer is planned, where an array of keywords and their colors is passed, and the text is highlighted accordingly. It will probably not support multi-line comments(for now).

Libraries are meant to be the intellisense bit(I dropped the old DumbSense thing). While the functionality still has yet to be added(or completely thought out) into the code, the plan so far is to just send the current line that the caret is on with the caret position. It would be up to the set library to determine what intellisense it should provide. I'll more than likely be adding the necessary functionality to handle displaying the suggestions and tool-tips to keep the look-and-feel of the control the same and to make it easier to make customised libraries. I'm toying with having multiple libraries(versus just the one lexer) so they can be stacked. Which is to say, one library could just cover, say, System.Windows.Forms, while another could cover System.Drawing, and the two could be combined in some manner.

CodeLite and ViewPanel
A few of the problems I mentioned last time(foreverago) have been resolved quite nicely(actually, most of the work mentioned above was done today; I was quite surprised at how much I could accomplish on my day off without playing Oblivion or watching movies :|).
Simply having CodeLite extend Panel instead of Control passed the keystrokes to ViewPanel, though I couldn't for the life of me figure out the code that *actually did it*.
And the cursor lines up(or pretty darn close, as far as I can tell) with the text. Turns out both MeasureString and DrawString needed to be passed basically the same StringFormat that is pretty much StringFormat.GenericDefaultTypographic(presuming I spelled that correctly), but mine set one of the format flags to include the handling of spaces, since MeasureString, by default, ignores the trailing space(s). Also, even though MSDN, in its infinite wisdom and knowledge, said it would be best to set the RenderingHint in the Graphics variable to AntiAlias(which looked freakin' horrible), I actually got the best results by setting it to SystemDefault(which, oddly enough, did better than not setting it at all). Now just to see whether or not it holds on anyone else's computer.
Also also, you can type in ViewPanel, and some edit keys work(Left,Right,Up,Down,Enter,Home, and End). Backspace only works with one character till you move the cursor, which is weird. I'll probably try to figure that out first thing tomorrow or the day after.

That is pretty much it for today. I probably won't get much done tomorrow between work(4am to 1pm), my exam(5:30pm to 8pm), and the homework I've got to do between before the exam that I put off a bit. [disturbed] I'll have Wednesday off in its entirety, though, so I should be able to get a good bit done then.

/* Standard Disclaimer: All this was written at about 10:30pm, and I've been up since 6:30am. Any problems, inaccuracies, or errors, then, I won't and don't care about until I get some sleep. */

nerd_boy

nerd_boy

 

WOW! AN UPDATE!

Wow. Been forever since I've updated. Probably cause I've not had time to work on the control much.

Not a whole lot has been done. A lot of time was 'wasted' on 'trivial' things that are mostly cosmetic, but *will* have to be handled before release(if that ever comes). Included in the list are things such as CodeLite not being able to pass keystrokes to the 'current' ViewPanel at this time(more on the ViewPanel bit later);not being able to get the ViewPanel control to be viewable when Location and Size are set(SetBounds was working for a bit, but it seems I managed to bork that up as well), so for now the Dock property is just set to Dockstyle.Fill.

A few things have been done. And by done I mean started to some extent that they are present but not 100% operational. In other words, half-assed.


ViewPanel
In order to allow a split view, as well as the possibility of other panels whether by default or by some manner of plugin(i.e, hex view/edit), the code that drew the control was removed from CodeLite and put in a new control class, CodeLite.ViewPanel.

Allowed Characters
This one was suggested by benryves. The property CodeLite.AllowedCharacters can be get/set with a String of characters that represent the allowed characters for the code. For example, if you were using BrainF*ck and did not wish to allow comments for whatever stupid reason, you would just do something along the lines of codeLiteControl.AllowedCharacters="+-.,[]>, or whatever the BF commands are(too lazy to look them up right now). If any key was pressed other than what was included in the string, it wouldn't be added to the text of the control. The only downside that I see to this(just now, sadly) is in regards to comments, where 'unauthorized' characters wouldn't impact the compiler terribly so. Unless I can think of a good way to determine whether or not the character is being added to a comment area(although the comment token could just be removed) or whether to make it optional(perhaps null is equivalent to allowing all characters?), I may just remove it.

Event Triggers
Either instead of or in complement of a simple plugin system, event triggers for all/most operations. This would include GUI changes(such as if displaying the line numbers or icons where toggled) to text changes(the addition/deletion of lines/chars). Some have been implemented, but not in their entirety. The ones that have been implemented will probably be redone, as the entire codebase will before long(starting to look a bit ugly).

CursorCaret and Text
Yes! I have actually and finally added this, although it still has a good bit of work yet to be done. The cursorcaret seems to want to drift after terribly long, and I've still to implement input keys such as Tab,Backspace,the arrow keys. You know, basic, everyday text editor keys. :/



So far all the code for CodeLite,Node, and ViewPanel are all included in CodeLite.cs. I have a seperate file set aside for both the Lexer and the Intellisense classes that I've yet to really touch. While not necessarily a problem for a single coder, it probably will be if I get a released version. That is to say, if anyone wanted to maintain, optimize, and possibly addon to a released, working version of this. In which case I'd get to learn how SVN works and get some actual team experience, something I lack. Very much so.

For next time, I hope to have the code cleaned up a bit, as much as is possible. Quite a few ugly work arounds were made so I could stop beating my head against a wall(mainly the CodeLite control directly called the KeyDown and KeyPress event handlers of the 'main' ViewPanel), and they'll probably stay for a bit until things get moving along and I can devote some time to that. I also hope to have the input keys implemented, at least crudely.

Until next time!
~nerd_boy

P.S. No fancy .gifs to see here. I hear benryves' journal has plenty, though.

nerd_boy

nerd_boy

 

Benryves' Chagrin

Much to benryves' chagrin, I've yet to give up on attempting to make Text my own little collection instead of using LinkedList or StringCollection. This iteration of 'design' is somewhat better than the last IMHO.

public class Text:System.Collections.IList where T:Text.TextNode
{
public class TextNode:ICloneable
{
public string text;
internal TextNode prev;
internal TextNode next;

public void PushPrevious(TextNode insertee){...}
public void PushNext(TextNode insertee){...}
public TextNode PopPrevious(){...}
public TextNode PopNext(){...}
public TextNode Pop(){...}
}

private T rootTextNode;
private T currentTextNode;

// Rest of Text code
}



For review of what my previous one looked like:
public class TextLine
{
public String data;
public T extradata;
public TextLine nextNode;
public TextLine prevNode;

public TextLine(){...}
public TextLine(String text){...}
public TextLine(T data){...}
public TextLine(String text,T data){...}
public TextLine(TextLine previous,TextLine next){...}
public TextLine(String text,TextLine previous,TextLine next){...}
public TextLine(T data,TextLine previous,TextLine next){...}
public TextLine(String text,T data,TextLine previous,TextLine next){...}
protected void QuickSetup(String text,T data,TextLine previous,TextLine next){...}
}



No freakin' idea what I was thinking. Apparently to insert or remove a node, you had to make a new one at the specified spot. Like singletonesque nodes or something... [headshake] Washu is going to kill me.

Anyway, now I should just have to implement System.Collections.IList in it and it *should* be good to go. The only problem I've met so far is the some of the methods receive arguements of the type object. I scanned through the available exceptions for something akin to TypeNotSupportedException, but didn't find any. I went ahead and made up my own, but if there is a standard procedure for handling something like this, I'd be grateful if someone could leave it in a comment or message me. Thanks.

Edit: Or, in freaking retrospect, I could just implement IList and IList instead. :/

nerd_boy

nerd_boy

 

Introductions

First post! Woot! Etc!

Firstly, introductions. I'm nerd_boy. Sadly, I've never really coded anything bigger/better/greater than Asteroids(DirectX 8, I believe). I've spent perhaps the past year not doing much coding at all, starting to for a couple of hours then stopping. I've told benryves countless times that I was finally starting on my hopeful code editor. Usually I'd code a couple hundred lines, find something I didn't like, and wipe the whole thing. Something I'll have to stop doing. [disturbed] Anyway, since I don't like my current situation of working at Wal*Mart, not having been to college for two semesters, and still living with my parents(fun times, I can tell you), I really need to start doing something. Like coding.

Enough emoing.

I've decided to have a go at a lite weight editor control for the .NET platform, aptly named CodeLite. There seems to be a huge lack of these unless you want to shell out a couple hundred dollars. The main features it will include, hopefully, are:

Line Numbering Syntax Highlighting Basic Code Suggestion Line Color Strip Line Icon

The line color strip and line icon are whatever the heck those things in Visual Studio's gutter are. The icon is easy to describe, being the same height as the line and is pictured before the line numbers in my copy of VS. The line color strip is between the actual text and the line numbers in my copy as well. Green if its been saved and not edited, yellow if its been edited, etc. Functionality for it wouldn't be built in, though, just methods to change the color and icon.

So anyway, I've been focusing on the actual Text portion of the control. As many times as I've wiped it and redone it, you'd think I'd have something wonderful, but meh. The Text portion is going to be set aside from the CodeLite and be part of the 'core' system for the RNFN namespace. Currently just that, though I might throw some components of the syntax highlighter engine in there as well, depending on the final design. Currently, the nodes of the text linked list, RNFN.Collections.Text.TextLine, look like this:
public class TextLine
{
public String data;
public T extradata;
public TextLine nextNode;
public TextLine prevNode;

public TextLine()
{
QuickSetup("",default(T),null,null);
}

public TextLine(String text)
{
QuickSetup(text,default(T),null,null);
}

public TextLine(T data)
{
QuickSetup("",data,null,null);
}

public TextLine(String text,T data)
{
QuickSetup(text,data,null,null);
}

public TextLine(TextLine previous,TextLine next)
{
QuickSetup("",default(T),previous,next);
}

public TextLine(String text,TextLine previous,TextLine next)
{
QuickSetup(text,default(T),previous,next);
}

public TextLine(T data,TextLine previous,TextLine next)
{
QuickSetup("",data,previous,next);
}

public TextLine(String text,T data,TextLine previous,TextLine next)
{
QuickSetup(text,data,previous,next);
}

protected void QuickSetup(String text,T data,TextLine previous,TextLine next)
{
this.data=text;
this.extradata=data;
if(previous!=null)
previous.nextNode=this;
this.prevNode=previous;
this.nextNode=next;
if(next!=null)
next.prevNode=this;
}
}



As is probably obvious, the T bit is for extra data of the text that must be kept track of per line(in the case of CodeLite, line numbers, line strip and icon, etc.) Now the main odd thing about this, that I'd really like to have critiqued to death as I want CodeLite to be pretty decent, is having the nodes linked when they're created. (Note: The reason I have the TextLine a class instead of a struct(like most nodes I've ever seen) is so I don't have to mark the bloody thing unsafe and use pointers and possibly fudge something up.) This is remarkably unsafe, but I figure that anything that if anything other than RNFN.Collections.Text uses it, it would/should have the root node protected, and not really give anything other than a copy away in an accessor. It also allows for some unusual code:
protected void SetupText(String defaultString,T defaultT)
{
// Setup default value of T
this.defaultValue=defaultT;

roottextline=new TextLine(":root:",defaultT);
currenttextline=roottextline;

// Setup the string
String[] text=defaultString.Split("\n".ToCharArray());

foreach(String line in text)
{
new TextLine(line,defaultValue,currenttextline,null);
currenttextline=currenttextline.nextNode;
lines++;
}
}




Again, please critique this to death so I can make it better. But something just seems good about having the node linked with what it is supposed to the moment I create it.

----------
Edit 1:
Just occurred to me to add a destructor to the node that automagically unlinks it and links the prevNode and nextNode to each other. Now just deleting a node takes care of linking too. Yay.

---------
Edit 2:
And apparently C# doesn't have a delete keyword. Drat these languages that are so similiar to others that I feel I don't need to buy a book on the subject only to get bitten by my ignorance. Trial by fire. Time to change that Deconstructor to a deleteor.

nerd_boy

nerd_boy

Sign in to follow this  
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!