How can I copy a text from a sfml window? - c++

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.

Related

Scrolling but wrapped pad in NCurses

I'm trying to make a text reader/pseudo-command-line a la man, but I'm having difficulty making the text scroll the way I'd like it to. At first I was having trouble getting new text to appear while scrolling, but eventually I found that pads would fix that for me, and I'm currently integrating them.
My question is, how can I get text to wrap within the pad? My program currently automatically refreshes when it is resized, so defining the pad to have as many columns as the terminal wouldn't fix everything. Can I get the pad to automatically resize itself as needed when my terminal receives a KEY_RESIZE? Not just the displayed size, but the size of the pad as well, such that text is pushed down a row due to the end of the pad. Additionally, will resizing it still keep the text, moving it down rows if necessary, or will I need to refresh the content of the pad?
Unfortunately, I'm having trouble finding resources with these details, and the documentation in ncurses doesn't elaborate on the behavior of resizing a pad.
Thanks a lot!
Edit after answered: ncurses doesn't do this, so I'm going to try instead making some arrays of strings, one to store the text from the file (broken at \n), and another for the line wrapping (refreshed on KEY_RESIZE, with each string having a max length of the terminal rows), parts of which are printed to the body window based on scrolling position and such. I'm making this edit so anyone else seeing this problem in the future can see what my solution is. I haven't done this yet, so I'll edit this again if it fails. Thanks again to Stack Overflow for helping with this!
ncurses will not do what you intend in this case:
A pad is like a window, true, and addch will wrap -- but the viewport which you are using to display data in the pad is not a window, and wrapping at the right side of the pad is not necessarily related to that viewport.
Once the text has wrapped, ncurses will not remember what that was, and re-wrap text if you resize the window (or pad).
A pad is mainly useful when you want to display just part of a window, e.g., if the screen is not large enough for the text you want to display.
If you want to resize and re-wrap, your program should allow for rewriting all of the text in the window (to lay it out as you intend) and not rely on ncurses to decide how to re-wrap text.

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?

How to get correct position in the std::string?

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.

How do I move a text character across the screen in c++

I am trying to make a program where I can use the arrow keys or the WASD keys to move a character across the screen (rpg style). I dont have any clue how to redraw the board in an easy way since there would be so many possible positions. I was thinking about creating a 2d array which would hold the positions. I am not asking for you all to write the code, I am asking simply. Is it possible to make the text character move along positions across the array?
One way would be to clear the "screen" and redraw the "map" at every change. Another might be to only redraw the lines that have changed. Yet another might be to position the cursor after the character you want to "move", print a backspace followed by e.g. a space, then reposition the cursor to after where you want the new character to be, print another backspace and then the character.
Or simply use a library such as ncurses.
On Windows, you can use the SetConsoleCursorPosition function to move the cursor to any arbitrary XY coordinates that you like.
TO do this, you need a HANDLE to the console, which is fairly easy to get
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
More Windows Console functions.
See here for an example

Right-to-left reading order: why isn't this calculated automatically?

In Visual Studio you need to set the extended window style to get a reading-order of right to left (WS_EX_LAYOUTRTL). Why is this required since if I'm using UNICODE and displaying Arabic characters the only possible way to display it is right-to-left? I'm surprised the system doesn't simply render it the correct way around. To note: this is on a Windows Mobile system where I've copied the Arial Unicode MS font onto it, which perhaps might explain why it can't cope.
Windows' support for RTL is more complex than just the text: WS_EX_LAYOUTRTL is actually about controling the layout of other elements in the window - from MSDN:
The window layout applies to text but also affects the other GDI elements of the window, including bitmaps, icons, the location of the origin, buttons, cascading tree controls, and whether the horizontal coordinate increases as you go left or right. For example, after an application has set RTL layout, the origin is positioned at the right edge of the window or device, and the number representing the horizontal coordinate increases as you move left.
So if you create a dialog that has this, the dialog will be "flipped" automatically (because the coordinates are reversed). If a scrollbar is present, it will be on the left side of the window, not the right. Treeviews will have the expand/collapse box and connecting lines on the right side, not the left - and so on.
In the case of a static, which doesn't contain other windows, the style may not appear to make much difference - but it likely will flip the justification: a static that is right-justified using SS_RIGHT would likely end up actually left-justified when WS_EX_LAYOUTRTL is used.
Also, as the other answer notes, not all text is spans of a single language. It's possible to have a single string that mixes scripts: you can have L-to-R spans within R-to-L, and vice versa, so having Windows "do the right thing" based on the text used would be very fragile.
Also consider the case of a treeview that displays the filenames running on an Arabic system: the treeview should keep a right-to-left layout (aligned against the right side) even if the user just happens to be browsing a directory or file system that happens to have english filenames.
Long story short: WS_EX_LAYOUTRTL is really about overall window layout, not specifically text direction itself. Even without this flag, you should still get Arabic/Hebrew rendered correctly as R-to-L if using the standard APIs/controls.
Presumably because it can't be determined what you're going to display at the window level - you could be displaying nothing, a language read left to right or a language read right to left. Thus you need to set it explicitly rather than having it attempt to deduce based off incomplete information.