Scrolling but wrapped pad in NCurses - c++

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.

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.

Text deleted by backspace is not being updated on my arduino tft display (adafruit gfx library)

For university, we need to make a game in Unity that is controlled with an Arduino. My idea was a hacking game where the Arduino acts as the 'hacking device' when hacking something in the game. The arduino would have a screen and on that screen would be a basic command-line interface that lets me input simple commands to 'hack' but I've been having trouble regarding text and clearing it.
I've been able to use unity to send typed characters to the display as-well as a backspace function (pressing backspace would remove last character in the string)
I first had issue with clearing all the text when writing (calling tft.print doesn't clear any previous text). I was using fillScreen which was slow. I found out setTextColor had a second argument that let me just set all certain colored text to a different color. Setting it to black would essentially clear it.
This made it update pretty much instantly when writing to the screen but I now had a new issue, backspace would no longer would.
My understand is that when removing the character, it's color won't be updated when calling setTextColor leaving it on the screen until a restart/fillScreen is called.
I'm not really sure how to solve this and all google searches turn up little to no help.
Here's my code for updating the text:
void updateString(char c){
tft.setTextColor(WHITE,BLACK);
if(c!='<'){
//Add new character to end of string
str.concat(String(c));
}
else if(c=='<' && str.length()>2){
//Remove last character in string
str.remove(str.length()-1);
}
//Set cursor back to 0,0
tft.setCursor(0,0);
//Display text
tft.print(str);
}
I'd appreciate any help.
Maybe, use a similar function to tft.clear() each time you refresh the screen or you can draw a filled square of the background on the text so it looks like it has been erased then you rewrite the text.
Sounds like you are using proportionally-spaced fonts instead of the original classic fonts that ships with Adafruit_GFX. Historically, when using the default classic fonts one could set the background color option of the text to the same color as the background of the screen (usually black). This would overwrite the old screen contents with new data and work because the characters using the classic fonts are a uniform size. When using proportionally-spaced fonts, the background color option for the font is disabled by design.
This was presumably because of memory requirements and speed on slower AVR's. Regardless, when using proportionally-spaced fonts the background color feature won't work due to non-uniform sized characters overlapping the same regions as adjacent characters.
There are two work-arounds to this. Adafruit says in order to replace previously drawn text when using custom fonts you can either:
Use getTextBounds() to determine the smallest rectangle that encloses a
string and then erase that area using fillRect() prior to drawing
the new text. OR
Create an offscreen bitmap using GFXcanvas1 for a fixed size area,
draw the text in the GFXcanvas1 object and then copy to the screen
using drawBitmap().
Note that options 1 & 2 above are mutually exclusive. The second method requires more memory. The first method isn't perfect and produces some small amount of flicker, but is in general acceptable if coded carefully.
I hope that I have understood what the nature of your problem is and answered it in a satisfactory manner. If nothing else, at least now you know why custom font's will not work with the so called background color feature that works with the original 'classic' Adafruit fonts.
Nikki Cooper

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?

default MINMAXINFO values?

I am currently working on a piece of code to circumvent the modal loops for moving and resizing Windows by effectively re-implementing DefWindowProc for the process.
The first snag I've hit is with MINMAXINFO. It seems that Windows fills this in with default values before sending the message along to the WindowProc, so simply sending the message to a window that doesn't override the values wouldn't do any good. Figuring that this wouldn't be as simple as giving it the desktop window size for the max and zeroes for the min, I checked how ReactOS does it in their source and.... well, I don't understand why they do the things they do in calculating it.
In particular, they choose to negate the WS_BORDER style when calling AdjustWindowRectEx. Their use of variables named "xinc" and "yinc" also seems unusual to me.
Basically, I'm hoping someone who has worked with the code (or MINMAXINFO more generally) can explain what I'm missing.ReactOS: WinPosGetMinMaxInfo
The ptMaxSize values in the MINMAXINFO structure are not the maximum size you can drag size to, but what the size will be if the window is actually maximized. When a window is maximized, the thick border is removed (since you no longer want the user to grab the border and try to resize it).
Make sure you read all the details in the explanation of the values for MINMAXINFO.

wxDC printing a text on screen while typing

I am trying to show a string on the screen while the user still types it. Normally wxDC's DrawText function is used for a string where the contents of the string is already known.
void DrawText(const wxString& text, wxCoord x, wxCoord y)
As we know, this function takes a wxString and prints on the screen. However, how can I let the user type something on the screen (on a wxWindow, wxFrame ). All and all, I am working nowadays on a drawing program where users can draw certain shapes. Certain shapes are easy to draw, move etc... But having a textbox and letting user type something in it is bugging my mind so far. Of course, this should be editable such as when the user clicks again on the same "text box" I should be able to edit it.
One last point, I am trying to avoid using controls such as wxTextCtrl and in a sense trying to make my own textctrl. What would be the best starting point?
Any ideas would be appreciated.
Writing your own wxTextCtrl is difficult, I'd strongly recommend against doing this. But if you really want to (why?), then it's, of course, possible, after all wxRichTextCtrl which has significantly more features than the plain wxTextCtrl is written using only wxWidgets API.
And there is no particular magic here, you just need to update the window (ideally, use wxWindow::RefreshRect() instead of refreshing the entire window) whenever the text displayed in it changes and your wxEVT_PAINT handler must be capable of drawing the text correctly.
I don't think you need to do anything special here. As long as the user is in some kind of "edit" mode - i.e. you're expecting them to type text - then all you need to do is to redraw everything whenever the user enters more text.
Something like this:
User clicks inside a rect to edit text.
Program starts edit mode (some internal state initialises an empty string).
While user didn't click outside the rect
add the entered character to the text string
clear the drawing area inside the rect to background
call DrawText or more likely DrawLabel to draw the string in the rect
Then the text is redrawn as it changes and you have a string with the content for persistence if necessary.
Alternatively, you can just pop up a wxDialog with a wxTextCtrl to ask the user for the whole text string and then draw after the dialog is closed.
Makes sense?