How to get correct position in the std::string? - c++

I am creating a custom single line edit control, with a custom font in win32 api on windows 7, the font is not a fixed width font, and I need to move caret according to the mouse click, The edit control is not empty and if I know the horizontal position of the mouse click within the window, how do I calculate the number of characters after which I need to move caret to ?
I really am out of ideas, if it was a fixed width font, I would have divided the horizontal mouse click position with average character width, that would have been simpler, doing the same with not a fixed width font, is prone to errors.

Given that it's a single-line control, you probably don't plan on working with immensely long input (at least normally). That being the case, one possibility would be to just store the character positions in an array (or vector, etc.) Then you can use (for example) a binary search in that array to find character positions. Of course, you can do the same even for longer strings--though it can increase storage requirements quite a bit.

This is a familiar problem. You are in essence trying to do hit testing on text and for that you need the location on the screen of each character of the text.
My preferred strategy is to calculate an array of RECT, one for each character of displayed text. The array needs to be updated when text is added or deleted, but it easily handles single or multiple lines. The function GetCharWidth32 retrieves all the widths for a string of text in a particular font selected into a DC. For single line one call is enough, and calculating the array of RECTs is simple. It's not much harder to do multiline.
Handle the mouse down message, loop through the array and find the right character. A brute force search is plenty fast enough.
This method is simple and easily generalises to a range of similar problems.

Related

How can I copy a text from a sfml window?

I've got this sfml window that displays a text and now I want to make it markable so that you can copy the text.
Any ideas how to do that?
If you just want to copy everything then just use
sf::Clipboard::setString(your_string_here);
If you want more features, here are some I implemented when I programmed a Code Editor in SFML.
I stored two indexes, the first is where the selection begins, and the second is where the section ends.
So in the string Hello World!, if you wanted to select World you would set the begin index to 6, and the end index to 10 or 11 (depending on whether you include the final character or not).
I render this using an sf::RectangleShape, since my editor supported multiple line selection boxes the code is more complicated, but for your example you would want to get the position of each character. I used my own text renderer, but SFML's sf::Text::findCharacterPos() should be able to help with that.
Next the copy part, this is just
sf::Clipboard::setString(getSelected());
where getSelected() is
return std::string::substr(selection_begin, selection_end - selection_begin);
If you want pasting as well then it is also simple:
eraseSelected();
insertStringAtCursor(sf::Clipboard::getString());
Which are both simple string operations as well (std::string::erase and reset the selection indexes, and std::string::insert).
Finally, to let the user change what is selected, either holding shift and pressing the arrow keys or clicking and dragging are both common ways, the former being easier than the latter.
For the former, check if shift is held and then if left or right is pressed update the indexes.
For the latter, you will need to handle mouse events and dragging. When dragging begins, set one of the indexes, whilst the mouse is moving and is dragging set the other index.

Motif How to calculate or retrieve the font pixel size?

I am trying to write code in Motif to change a dialog warning box to resize size it if the box is not wide enough. The width and height is always being set by the calling classes and its not always wide enough for the message being displayed and the end of the line is truncated off. Instead of fixing everywhere to use auto sizing (i.e. width is 0 or not set at all) they want to figure out what the pixel width size is for a character in the dialog. They can then multiple the longest line X pixels width to get the lines length in pixels. Then we would see if the dialog declared width needs to be reset to stop the truncation. Only dialogs that are too short will be changed (dialogs too wide are not to be changed).
However; I can't find any example on how get the character width in pixels anywhere. I remember years ago I was on a project where they created some type of widget, inserted a character into it, and then did a XtGetValues to get the width and height so I think it can be done. So does anyone know how to do this?
That was a long time ago, but if memory serves, Xt doesn't have any specific support for fonts, it relies on plain libx11. You will need to call XQueryFont or XLoadQueryFont to get the XFontStruct describing your font, then grovel through the per_char array to find the extents of individual glyphs.

How to check if the length or width of Row in a window is greater than the width of its parent window C++

I wanted to wrap the existing text of checkbox into multiline if the width of row exceeds the width of its parent window. I am not really sure how to do that.
The image I want to show the checkbox string
The image where the string is cropped and only shows if window is resized or maximized
You are going to have a problem with this I am afraid.
The setting for making a checkbox multiline is ES_MULTILINE and if you look here you will see that it states:
To create an edit control using the CreateWindow or CreateWindowEx function, specify the EDIT class, appropriate window style constants, and a combination of the following edit control styles. After the control has been created, these styles cannot be modified, except as noted.
So, it would seem to me that you have three ways forward, depending on what you feel is the best or most elegant for you.
Set your control in the resource editor as multiline anyway. Then it doesn't matter and will wrap. No need to have to change the setting.
Implement the needed functionality to limit the size the window can be reduced to. I can show you how if you are interested. This way, if you set the control resize properties correctly it can resize larger but only reduce down the a known dimension (ie: the dimensions you created it in the resource editor).
Possibly have two controls in the same place, one as multiline and one as single. And when you decide which you want to show, swap the visibility. But I think this is a bad idea, bit of a headache, and not worth the hassle.
IMHO I would do both ideas 1 and 2 and I would happily extend my answer to provide more information.
Update
Having looked at your images and the comments about translations then there is a fourth idea. If you use a third party application to manage the translations and use satellite DLL files then you can adjust the resources on a language by language basis. I sometimes have to make the default width for some windows wider due to their verbose nature.
I have set BS_MULTILINE for the checkbox. The minimum size of the window is fixed but I just want the checkbox to fit in that. I expect it to show at least one word in the same line as other labels and remaining words in second line. So I am checking if the total width of the first row is greater than the width of window then show the string with \r\n in it else show normal string. However, I want to align first line or the first word of the checkbox with the checkbox and remaining words should come below the first word. Currently, the checkbox is in between two lines which looks weird. Is there anyway I can do this?

Vertical centering of multi-line cstatic text in MFC

How can one make a CStatic with text auto-wrap (multiline) which vertically centeres the result in the control's rectangle?
The problem I'm trying to solve is this: I have a CStatic control next to a CComboBox which updates information text depending on the choice. This text can be either short or long, requiring the CStatic to sometimes use multi-lines, and sometimes not. I want the info-text be vertically center-aligned with the CComboBox.
Now here is the problem:
If I make the CStatic only 1 textline high, it looks good for 1-line texts, but multi-lines do not fit and are not displayed.
If I make the CStatic higher to fit 2 lines, it looks good for long texts (with 2 lines), but 1-line-texts are shifted upwards, as the CStatic aligns the text on the top. A CStatic with the behavior mentioned in the question would solve this...
If I can't easily get a vertically centered CStatic multi-line control, the alternative would be to resize the control rect depending on the amount of text in it. But in this case I have a different problem:
How can I programatically find out how many lines a text will need in a CStatic of specific width?
Unfortunately you can't vcenter multi-line text in a CStatic.
Your next question has a solution but it's a bit of a pain to use. What you do is you use CDC::DrawTextEx with the DT_CALCRECT flag to get the size (in pixels) of the text you want to format. By dividing that by the height of a line of text (given in the font info you can get from the DC, plus some spacing which I'm not sure of how much that is - presumably it's a fixed amount, I don't think you can specify line spacing with DrawText), you will get (an approximation of) the number of lines you will get. You can then resize the control rect.
Come to think of it, you are probably better off not converting to lines and just resize your control to the extent you get from DrawTextEx :)
Things like this usually require some experimentation to get exactly right, and sometimes behave differently between OS versions. Proceed with caution.

Correct way to render cursor in custom text area?

I am using SDL and libfreetype and constructing a very basic GUI, I'm implementing a textBox, but I haven't been able to figure out how I'm supposed to generate the standard blinking cursor part. It doesn't seem to be exactly the same as a | character. And moreover if I draw it as a | character that changes the text width.
What's the canonically correct way to render text in a textbox with a cursor?
The easiest way is to just draw a line primitive, this gives you a lot more control over the spacing, length and width of the caret.
And if you want to keep it as a text character in your font system, you can do a render-to-texture and copy it out, or do a simple memory blit onto your font atlas (so you can can keep pipe character separate, an use a control char like 0x01 for the caret).