|
OK, this is great, I think I'm on the right track now. I got it to display the Cursor X and Y when the TextEditor recieves focus, so I suppose I should convert those values into row and columns in the text, right? And if the the row and column values are invalid, jump to the last available row and column?
I think I get everything, however, how would I convert X and Y values into row and columns? You got a formula for that I should I try myself?
Thanks for everything so far!
|
|
|
|
|
Hi,
with monospaced fonts, the formula are ver simple:
xPixel=(textColumnNumber-horizontalScrollCount)*textCharacterWidth;
yPixel=(textLineNumber-verticalScrollCount)*textLineHeight;
which is assuming all characters have same width and height, and all scrolling is by integral lines and characters. Which I prefer anyway.
The above are text position to screen position (as for displaying stuff); invert them for editing (mouse to text).
Luc Pattyn [Forum Guidelines] [My Articles]
The quality and detail of your question reflects on the effectiveness of the help you are likely to get.
Show formatted code inside PRE tags, and give clear symptoms when describing a problem.
|
|
|
|
|
Hmm, like this?
colNum = (Cursor.Position.X + this.stormParent.HorizontalScroll.Value) / charWidth;<br />
rowNum = (Cursor.Position.Y + this.stormParent.VerticalScroll.Value) / charHeight;
Because that simply gives me the same values except in minus. (261 290 becomes -261 -290 for example)
I feel sooooo stupid :s
|
|
|
|
|
Vestras wrote: like this?
obviously not. Put those gray cells to work!
Luc Pattyn [Forum Guidelines] [My Articles]
The quality and detail of your question reflects on the effectiveness of the help you are likely to get.
Show formatted code inside PRE tags, and give clear symptoms when describing a problem.
|
|
|
|
|
Ahh I finally figured out what the thing was! Yours is linenumber, mine isn't.
But ehh... don't I need to know the col and row to figure out the line number? >__<
Hmm... and wouldn't the textLineHeight be the same as charHeight?
|
|
|
|
|
Vestras wrote: wouldn't the textLineHeight be the same as charHeight?
maybe, maybe not.
when you do Graphics.DrawString("abc",...) the font is in charge of the character spacing.
when you paint individual text lines (or parts thereof as you are going to perform syntax coloring), you are in charge of the vertical line distance, it does not directly relate to the font height (whatever that is) as long as it is large enough.
Luc Pattyn [Forum Guidelines] [My Articles]
The quality and detail of your question reflects on the effectiveness of the help you are likely to get.
Show formatted code inside PRE tags, and give clear symptoms when describing a problem.
|
|
|
|
|
OK, I can't figure it out... my gray brain cells are dead
Can't you, please, post the correct formula? I tried everything (obviously not, but I tried what my brain could make up)
Gosh...
|
|
|
|
|
Sorry I won't.
This is what you shall do:
1. take pencil and paper
2. copy one formula exactly as it is (you are allowed shorter names, as long as they are clear)
3. locate the position of the unknown variable
4. copy the previous formula but now either add/subtract/multiply/divide by something on both sides (hence keeping the equality), so that the side where the unknown is becomes simpler
5. repeat step 4 until you've got it.
Luc Pattyn [Forum Guidelines] [My Articles]
The quality and detail of your question reflects on the effectiveness of the help you are likely to get.
Show formatted code inside PRE tags, and give clear symptoms when describing a problem.
|
|
|
|
|
OK I'll start from the beginning again...
Is this true?
xPixel = (textColumnNumber - horizontalScrollCount) * textCharacterWidth;
yPixel = (textLineNumber - verticalScrollCount) * textLineHeight;
______/\______ ___________/\__________
Unknown Vars Unknown Var(S)?
|
|
|
|
|
You choose a font size, hence you get a charwidth and a charheight; you choose a textLineHeight equal to or slightly larger than the charheight.
On (mouse) input you know xPixel and yPixel and want to know textLineNumber and textColumnNumber
on (display) output you know textLineNumber and textColumnNumber and want to know xPixel and yPixel.
Luc Pattyn [Forum Guidelines] [My Articles]
The quality and detail of your question reflects on the effectiveness of the help you are likely to get.
Show formatted code inside PRE tags, and give clear symptoms when describing a problem.
|
|
|
|
|
Luc, can't you please, please help me? The closest I could come was this, and it's still pathetic:
colNum = (Cursor.Position.X - this.stormParent.HorizontalScroll.Value) / charWidth - charWidth;
lineNum = (Cursor.Position.Y - this.stormParent.VerticalScroll.Value) / (int)this.Font.Size - (int)this.Font.Size;
I tried for nearly 9 hours :s
|
|
|
|
|
Hi,
I gave you
xPixel=(textColumnNumber-horizontalScrollCount)*textCharacterWidth;
and you now want textColumnNumber=a*xPixel+b right?
The only problem is determining the coefficients a and b. Take the recipe I gave earlier, make the factors and terms on the textColumnNumber disappear by adding/subtracting/multiplying/dividing both sides of thee equation appropriately.
The first thing to go is "*textCharacterWidth" because that is what you perform last in the original equation;
then the remaining "-horizontalScrollCount"
Luc Pattyn [Forum Guidelines] [My Articles]
The quality and detail of your question reflects on the effectiveness of the help you are likely to get.
Show formatted code inside PRE tags, and give clear symptoms when describing a problem.
|
|
|
|
|
Is it something like this? It's the closest I can get. (And this time I even got help, lol, I suck at math)
colNum = (Cursor.Position.X / charWidth) + this.stormParent.HorizontalScroll.Value;
|
|
|
|
|
Congratulations are in order.
When a formula is correct, you can read it and see it makes sense, in this case, using horizontal character positions as a unit of measure, it says:
the column you're at equals your cursor position (in pixels) divided by the width of a character (in pixels, we divide to get rid of those pixels), plus whatever number of characters that have been scrolled away.
So now you have two ways to come up with a formula:
- start from an existing one and invert it, by moving annoying terms and factors to the other side (undoing multiplication by a division, addition by a subtraction);
- or write down a logical statement, as in the above example.
Luc Pattyn [Forum Guidelines] [My Articles]
The quality and detail of your question reflects on the effectiveness of the help you are likely to get.
Show formatted code inside PRE tags, and give clear symptoms when describing a problem.
|
|
|
|
|
Yay, I did something correct!
However, it still seems a little off, for example what should have given me char 1, line 1, give sme char 18, line 24. This is what I have:
colNum = (Cursor.Position.X / charWidth) + this.stormParent.VerticalScroll.Value;
lineNum = (Cursor.Position.Y / (int)this.stormParent.Font.Size) + this.stormParent.HorizontalScroll.Value;
As I said, math isn't my strongest side xD I'm more at app design and such.
|
|
|
|
|
Hi,
Cursor.Position gives a location in screen coordinates, i.e. relative to the top left corner of the screen (as it doesn't take any Control parameter, all it can do is return absolutes).
You probably want relative to your control; there is a PointToClient() method to transform them.
Luc Pattyn [Forum Guidelines] [My Articles]
The quality and detail of your question reflects on the effectiveness of the help you are likely to get.
Show formatted code inside PRE tags, and give clear symptoms when describing a problem.
|
|
|
|
|
Hey dude, thanks! It seems like it gives the totally perfect coords (increases correctly and so on), however now it says char 15, line 18 instead of char 1, line 1. :s
Point p = this.PointToClient(Cursor.Position);
colNum = (p.X / charWidth) + this.stormParent.VerticalScroll.Value;
lineNum = (p.Y / (int)this.stormParent.Font.Size) + this.stormParent.HorizontalScroll.Value;
Btw: can you tell if this is correct?:
The original RichTextBox redraws the whole text every time a color has changed, so if I have 5000 words it redraws 5000 times every time I edit the text. Now, the reason this is more efficient, is because the text natively is given the intended colors instead of changing it when it has been drawn already. Now, to highlight a line, I'd use a code somewhat like this:
namespace Storm.TextBox
{
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
#region Keyword class
public class Keyword
{
private string _kword = "";
private Color _kcol = SystemColors.ControlText;
private Font _kfont = new Font(new Font("Courier New", 10), FontStyle.Regular);
public Keyword(string keyword, Color color, Font font)
{
_kword = keyword;
_kcol = color;
_kfont = font;
}
public string Keyword
{
get { return _kword; }
set { _kword = value; }
}
public Color KeywordColor
{
get { return _kcol; }
set { _kcol = value; }
}
public Font KeywordFont
{
get { return _kfont; }
set { _kfont = value; }
}
}
#endregion
public class HighlightingSetup
{
#region Members
private TextEditor stormParent = null;
private Dictionary<string, Keyword> keywordDic;
#endregion
#region Methods
public void Add(string keyword, Color color, FontStyle fontstyle)
{
keywordDic.Add(keyword, new Keyword(keyword, color,
new Font(stormParent.Font, fontstyle)));
}
public Keyword KeywordFromString(string keyword)
{
if (keywordDic.ContainsKey(keyword))
return keywordDic[keyword];
return null;
}
public void Remove(string keyword)
{
if (keywordDic.ContainsKey(keyword))
keywordDic.Remove(keyword);
}
#endregion
public HighlightingSetup(TextEditor parent)
{
stormParent = parent;
keywordDic = new Dictionary<string, Keyword>();
}
}
}
private Color[] kColors;
private Font[] kFonts;
private char[] Splitters = { ' ', '(', ')', '[', ']', '{', '}', '!', '"',
'#', '$', '%', '&', '/', '=', '?', '+', '-',
'*', '^', '_', ':', ';', '<', '>', '\\'};
private string tempLine = "";
private int maxKeywordCount = 0;
private void HighlightLine(int lineNum)
{
string splitString = doc.GetLineFromIndex(lineNum);
string[] keywords = splitString.Split(Splitters);
int keywordCount = 0;
foreach (string keyword in keywords)
{
Keyword kw = setup.KeywordFromString(keyword);
kColors[keywordCount] = kw.KeywordColor;
kFonts[keywordCount] = kw.KeywordFont;
tempLine += keyword + "+";
keywordCount++;
}
maxKeywordCount = keywordCount;
tempLine = tempLine.Substring(0, tempLine.Length - 1);
this.Invalidate();
}
private void onRepaint(object sender, PaintEventArgs e)
{
string splitString = tempLine;
string[] keywords = splitString.Split('+');
int keywordCount = 0;
foreach (string keyword in keywords)
{
Keyword kw = setup.KeywordFromString(keyword);
Color kcolor = kw.KeywordColor;
Font kfont = kw.KeywordFont;
StringFormat strFormat = new StringFormat(StringFormatFlags.NoWrap);
Rectangle posRect = new Rectangle(0, 0, 0, 0);
ControlPaint.DrawStringDisabled(e.Graphics, keyword, kfont, kcolor,
posRect, strFormat);
ControlPaint.DrawStringDisabled(e.Graphics, " ", this.Font, kcolor,
posRect, strFormat);
keywordCount++;
}
}
|
|
|
|
|
Hi,
I haven't read all that in detail, here are some comments for you:
1. you seem to create a new Font for each new keyword; that is a waste, most of those fonts would be identical (maybe there is a regular and a bold, but not dozens of variations)
2. your "parser" seems to split a line by all kinds of special symbols, which will chop a line in many parts, e.g. two-character operators will be split, which isn't necessary (and maybe not what you want, you probably will end up coloring operators too)
3. your "parser" seems ignorant about digits. Not sure that will work well.
4. you are parsing and storing results in arrays. Why? Arrays are trouble, since you must declare them (you forgot that part) and set an arbitrary size. Sooner or later someone will enter a line that exceeds your parsing capabilities. If you must store an unknown number of items, use a List. However there is no need to store the data, you can paint line parts as you go, while parsing! Yes my parser sits inside my Paint handler, however it only parses the visible lines.
I'm sure the list isn't complete however you have to come up with ideas and critical thinking yourself.
One advice: don't keep adding code while existing code isn't compiling/running/running almost correctly. It may soon grow well above your head and become unmanageable.
Luc Pattyn [Forum Guidelines] [My Articles]
The quality and detail of your question reflects on the effectiveness of the help you are likely to get.
Show formatted code inside PRE tags, and give clear symptoms when describing a problem.
|
|
|
|
|
OK, thanks for those tips
I'm going on vacation today, and I'll be home in 3 weeks or so. So I won't reply in that time, sorry.
When I get back I'll update my code
|
|
|
|
|
Hey Luc,
I'm back! I'm going to update my parser tomorrow, but that was simply a demo
Now, could you please tell me why this:
Point p = this.PointToClient(Cursor.Position);
colNum = (p.X / charWidth) + this.stormParent.VerticalScroll.Value;
lineNum = (p.Y / (int)this.stormParent.Font.Size) + this.stormParent.HorizontalScroll.Value;
Gives me wrong X and Y locations? It increases and decreases the X and Y locations correctly, however it gives me 15x and 18y when it should've given me 1x and 1y.
Thanks
|
|
|
|
|
Vestras wrote: Gives me wrong X and Y locations
Then you did something wrong. Learn to debug, i.e. observe the details, formulate a hypothesis, check its correctness, and act on it.
When wrong, try again.
Luc Pattyn [Forum Guidelines] [My Articles]
The quality and detail of your question reflects on the effectiveness of the help you are likely to get.
Show formatted code inside PRE tags, and give clear symptoms when describing a problem.
|
|
|
|
|
Is it possible to get a copy of your syntax coloring control?
Everything makes sense in someone's mind
|
|
|
|
|
I would really like to take a look at your source if you could post it or send me an email i would really appreciate it.
|
|
|
|
|
I'm passing an array of structs to an unmanaged method and just want to make sure that what I'm doing is correct.
Let's assume I have a struct defined as
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct MyStruct
{
public MyStruct(string Name, uint Index, MyEnum flag)
{
}
[MarshalAs(UnmanagedType.LPTStr)]
public string mName;
public uint sIndex;
[MarshalAs(UnmanagedType.U4)]
public MyEnum mflag;
}
where MyEnum is some enum deriving from uint.
The calling code creates an array of these structs like this:
MyStruct [] structs =
{
new MyStruct("BEN", 0, MyEnum.FIRST),
new MyStruct("VAL", 1, MyEnum.FOURTH),
new MyStruct("ROG", 2, MyEnum.SECOND)
};
I then pass this array to the managed function which looks like this:
public static extern int SetMyStructs([MarshalAs(UnmanagedType.LPArray)] MyStruct [] structs)
which is supposed to map to the unmanaged function of:
int SetMyStructs(MyStruct * structs)
SetMyStructs is returning values indicating that the function is not executing correctly. Is passing an array of structs containing strings and integers possible and if so am I using the correct marshalling attributes? I just want to eliminate this array of structs as a possible reason for the failing function.
|
|
|
|
|
I have a ToolStripTextBox, I'd like to customize such that when there's no text in it, it draws some background text, in different color that's not editable. Once the user starts typing this goes away. The OnPaint method doesn't cut it, further looking shows that the ToolStripTextBox apparently hosts an internal TextBox control. The ToolStripTextBox.Paint handler (unsurprisingly) does nothing. The docs for the TextBox class claim that the Paint handler is not to be used. Is it not possible to do this in .Net?
|
|
|
|
|