I am custom drawing a text box and now I am implementing the part where the user can click on a line and have the cursor move to where he clicked.
I know how to get the row of text he clicked on because the character height is constant across all fonts, but not the column, because I'm not sure how to say "get me all the text that can be drawn before this amount of pixels," and because character width is not consistent unless you're using a fixed-width font, which is not a guarantee.
So I have the point from which I'm drawing the string (0) then I have the point that the user clicked. How do I get the string index of the character they clicked on?
Extra info: I am drawing the text by storing the lines in a List then iterating the list and using Graphics.DrawString on each line.
There is no simple method to find the character at a pixel.
However you can find the pixels that a string will fill. Use the Graphics.MeasureCharacterRanges method. You can perform a binary search on your string until you find the string where MeasureCharacterRanges returns your cursor position.
Note: You might see the Graphics.MeasureString method and be tempted to use that. DON'T! That method doesn't return accurate measurements. I can't remember why, but you will do your head in if you try!
Related
I have an icon I want to appear exactly at the end of a paragraph. For example:
You throw the ice cube at the monster.
The monster falls over dead. *
where * represents the icon I want to appear at the end. This can be any char or image converted to a sprite.
This icon must flash in color to indicate a picture is still loading and can't be moused over yet. The rest of the text should not flash in color.
Only two approaches come to mind:
Use rich text: Cannot lerp via rich text unless you constantly change the <color> string which I imagine must be extremely inefficient and freeze the game
Represent the icon separately from the text: I can lerp this easily, but am unable to determine the position of the icon relative to the text. I could just always put it below, but that wastes space.
If this is a TMP_Text (e.g. TextMeshProUGUI) you can go through the
TMP_TextInfo textInfo = yourText.textInfo;
The TMP_TextInfo holds all kind of information about the displayed text. E.g. the
TMP_LineInfo lastLine = textInfo.lineInfo[textInfo.lineCount - 1];
From that TMP_LineInfo you can now get e.g. the
float width = lastLine.width;
Having that information you should be able to go with option 2 and position an individual icon/text accordingly
I'm currently working on an educational Windows store app in which the user will be able to trace over letters (e.g., A, B, C, but not limited to English) to learn the basics of writing.
How can I detect input and then compare it to an image mask of a letter using C# and XAML?
To do this you will need to have some way to rasterize your text that you want the user to trace over. Then, in order to provide feedback on whether they traced it correctly you'll need to continuously listen for the draw event and compare the input to what they should be drawing.
Basically, if a user draws a certain path or set of paths on a canvas, you'll want to be able to provide instant feedback on if they got it right yet. To give you some direction for this, I recommend you read this answer on SO, which roughly describes how to capture input and draw it on a canvas.
From there you should be thinking in terms of matching the user's input to an image of the letter they're supposed to be drawing. This requires some amount of image matching. To get you started, I recommend reading through all the answers to this post on SO.
Since you seem to be lacking direction in general, here's an idea of how your program could be structured:
Load the current letter to be drawn, and make sure to perform the appropriate calculations to pre-determine as much as possible for comparing to the input. Based on the second link above, this means you should call GetPixel for the letter to be drawn before the user is allowed to start tracing it (also note that you may want to downscale the image for better performance). You will also need to decide what your match threshold will be. Try starting with something like 70%.
Capture the user's input on a canvas, as explained in the first link. You'll probably want to adjust the brush width, but that post is a great start.
In the MouseMove event, you will also want to occasionally check to see how well it matches with the letter they're supposed to be drawing.
Once the user's input is within your match threshold, move on to the next letter. You may want to consider providing them with how well they did, based on the match percentage.
Experiment with values such as the brush width, image resolution, and how often you compare the input to the letter. Also try to do as much of the image processing as you can while displaying a 'loading' prompt when moving to the next letter to be drawn.
So, I am writing some text into a PDF file using iTextSharp.
After having added a few paragraphs and phrases to the PDF document, I want to:
Draw the next piece of text on top of a rectangle that has a fill color, say, red.
I can compute the required width and height that the rectangle must have based on the text metrics of the text I am going to write on top of it. But how do I tell the Rectangle API what is top and left coordinates are, as in where it must be drawn?
Seems that you are looking for the Chunk.setBackground() method. This draws a colored background underneath some text. There's also a variation of the method that takes extra parameters if you need a larger or smaller rectangle.
Suppose that you don't want a colored rectangle, but a custom type of shape, then you'd use the page event onGenericTag(). See Chunk > Generic tag for more info.
The onGenericTag() method is triggered every time a Chunk that is marked as generic (using the setGenericTag() method) is rendered to a page. Your implementation of the page event can then use the Rectangle value that is passed to the event method. It is important to understand that a single Chunk marked as a generic tag can result in multiple invocations of this method: if the contents of a single Chunk needs to be distributed over different lines, the event will be triggered as many times as there are lines (giving you a separate Rectangle value for every separate line).
I set up a draw rectangle to draw simple formatted text first aligned to the left as
*item 1
[1]Something
content
[2]Something else
<a> subsomething else
content
<b> another subsomething else
content
*item 2
The end.
and I would also like it to automatically create a new column (after checking for the longest string in the first column [drawn stuff on the left hand side]) to draw the rest into it.
In order to keep track of the paddings and itemized sections and subsections, I think of using a stack which I can push and pop the current and next positions needed to draw a text line each time I leave a content. Yet, I can't figure out how to jump back to a certain subsection position because stack doesn't offer an inline sub-scripting method.
Then I look into a hash-map (in C# I have tried Dictionary) to keep track of it and to access the value via specific key. For that I also use a external global variable to maintain the number of subsections the user may have entered and increase one each time a new subsection is created; and the float value is used to store the x-coordinate value for the drawstring to be done. This is complicated to me at least at present when I don't really have a nerve to go into it anymore. I can only receive false simulated outcomes.
So I am asking for an easier approach to tackle this problem, which I think is simple to many of you sure experiencing the same situation. I am desperately looking forward to seeing a short easy method to do this.
Draw formatted text using ..
..whatever works. I suggest a JLabel, which will render (simple) HTML/CSS formatted content.
See LabelRenderTest.java for an example.
So I'm building a custom control in C# (not WPF), and I basically want to implement text highlighting with the mouse.
How do I efficiently find the character at a given Point (say where the mouse is clicked) in a string? I have the layout rectangle of the string as it was drawn and I could calculate the length of the string up to every character until I find the one closest to where the mouse is clicked... but there has to be a better way. Any suggestions?
If I had to do this, I would look at it backward.
I'd keep the text entered as a string member in the control, so at all times I know what is actually entered in the control (like the Text property in a TextBox).
Then I would use the TextRenderer.MeasureText() method (http://msdn.microsoft.com/en-us/library/7sy6awsb.aspx) and I would keep measuring the length of the string repeatedly until I pass the X coordinate of the mouse within the control, right then I know how many characters are chosen.
For example, assume the user has the text Hello written in the control.
And the X coordinate hit right between the l and the o, which could be of value 20.
Then I would repeatedly calling MeasureText() on the following strings:
H: width of 5 pixels.
He: width of 10 pixels.
Hel: width of 14 pixels.
Hell: width of 17 pixels.
Hello: width of 22 pixels.
Then I know the mouse was hit between the l and the o, so I would then highlight the text Hell.
Sorry for the distasteful example =)
UPDATE:
You can optimize this a bit by calculating the lengths in a binary-search-tree-like fashion.
Just like you would look up a name in the phonebook, you don't look page by page, but rather split in half as you go along, getting closer and closer until it's definitely between these two pages.
Similarly, especially for long string values of the control, calculate the width of the entire string, then half its length, and split there. I think that would be O(n log n) at that point.
Of course it would be O(1) if the text is of fixed width =)
Another thing you can do to build upon BeemerGuy's great suggestion is to precalculate an array of offsets. As the string is changed (the user types or the property is set in code) you can recalculate the offset array. That will save you the call to MeasureFont on the mouse clicks and will make finding the character trivial. You basically iterate the array until you find the nearest character. Since the offsets are implicitly sorted by value you can even use a binary search to make it more effective.