Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Text area / Code editor #200

Closed
TuomLarsen opened this issue Apr 17, 2015 · 38 comments
Closed

Text area / Code editor #200

TuomLarsen opened this issue Apr 17, 2015 · 38 comments

Comments

@TuomLarsen
Copy link

Hello!
I apologize in advance, as this is not an issue but I could not find any user forums.
Do you have any plans for adding multi-line editing widget, aka text area? I was just wondering, as there are now a single line edit and the ability to display lots of "immutable" lines of text.
If so, would it be possible to use it as a simple syntax-highlighting code editor? (just colored tokens and perhaps regular/bold/italic styles)
In any case, thank you for the hard work you are putting into the project!

@ocornut
Copy link
Owner

ocornut commented Apr 17, 2015

Features requests are totally fine here.

Yes we should probably add multi-line text edition. Shouldn't be too hard seeing the underlying stb_textedit already supports it. It may be biased toward "short" text (a few hundred lines). Can't really tell when. But you could look into it if you need it soon.

Syntax highlighting would be a separate thing. I don't have any immediate plan/idea to implement this. The approach that https://github.com/emoon/ProDBG is using is to use Scintilla which is a full featured source code edition component, and wire it to render within ImGui. #108 I think it's working now you you may be able to borrow code from there. Probably requires a bit of setup but then I assume you'd get a high quality multi-language component.

@paultech
Copy link

I +1 this request for multiline editing via stb_textedit. Code/Syntax highlight is too application specific so I simple request for multiline editor.

If bounties are accepted, I'd offer $35 for this request to be completed.

Thank you for this great project!

@ocornut
Copy link
Owner

ocornut commented May 18, 2015

Hi Paul,

It's on my list, I'll try to work on it when I'm done with the menus stuff, but I have so many things lined up at the moment it is a little overwhelming to handle every request. But I will try! You can probably bribe me with a Patreon subscription ($35 every month? :)

@paultech
Copy link

Hello Omar,

Understandable, have been watching the menu branch and see you are a busy guy!
Bribe submitted at $15/month.
Thanks again for ImGUI!

@ocornut
Copy link
Owner

ocornut commented May 18, 2015

Thank you very much! :)

What sort of text size are you aiming to edit? A few kilobytes and under a hundred lines? Or something larger?

The current API takes a buffer size, so to handle large amount of text you would either need a big enough buffer or allocate a capacity enough to fit current text size + extra inputs every frame which needs to take account of the worse case, aka clipboard size. Otherwise it would make more sense if I added extra feature in the API or via callback to resize your buffer, but the first version will probably require you sizing the buffer. Again it depends how scalable you need the thing to be for big text.

Above a few lines, it would also probably need to preserve scrolling and cursor position more persistently (currently we only preserve them for 1 text field), so that you don't lose scrolling when another field is edited.

Do you need TAB ? Proper tabs requires a change in the text renderer and text size calculation which I have removed prior to v1.0 because it was making the rendering code more complicated and less performant. Text size calculation is among the bottleneck for very large UI so it needs to be kept optimal even if it takes having multiple code path with features enabled/disabled as needed.

We're also lacking an horizontal scrollbar, shouldn't be a big problem.

@paultech
Copy link

Very welcome!
That would be right on par. It's editing of assembly so between 10-200 lines would be in expected range.

Sized buffer would be fine for first revision but a dynamic method would be desirable

Tab would be a a desirable attribute as the formatting is a important aspect for assembly code.

Thank you!

@paultech
Copy link

Hope pings are not considered rude as I know your busy. Any ETA on this? Planning internally around this feature so a rough estimate would be appreciated

@ocornut
Copy link
Owner

ocornut commented Jun 14, 2015

Sorry! I'll give it an attempt in the upcoming days and see how it does (it might just be easy)

On another note bgfx has a basic integration of scintilla using imgui that I could fix/cleanup and then provide as a standalone thing for using scintilla.

@paultech
Copy link

Fantastic! No reason for sorry, Did not mean to rush.

I did look at scintilla but the interface looked rather complex. I'd be over the moon for a clean standalone scintilla interface for ImGUI!

@emoon
Copy link
Contributor

emoon commented Jun 14, 2015

One issue with Scintilla is that it's a bit "statefull" which goes against ImGui style a bit. If you want you can take a peak at how I solved it for ProDBG (uiFuncs here is a C wrapper for ImGui)

PDSCInterface* sourceFuncs = uiFuncs->scInputText("test", 800, 700, 0, 0);

Here I return an API to for the input that I later on can use to send command to Scintilla like this

PDUI_SCSendCommand(sourceFuncs, SCI_GOTOLINE, (uintptr_t)line, 0);

This code above is just a macro that looks like this

#define PDUI_SCSendCommand(funcs, msg, p0, p1) funcs->sendCommand(funcs->privateData, msg, p0, p1)

The code is used here https://github.com/emoon/ProDBG/blob/master/src/plugins/sourcecode/sourcecode_plugin.cpp#L85

Internally in https://github.com/emoon/ProDBG/blob/master/src/prodbg/ui/bgfx/imgui_extra.inl#L81 I will do caching of the Scintilla editor because it's heavy to create each frame. Hopefully my implementation can be used somewhat as a ref.

@ocornut
Copy link
Owner

ocornut commented Jun 14, 2015

That's the bgfx example running after I made it use C++ lexer and passed it some keywords (that I grabbed from some forum)

scintilla

Looks like bit of a setup to take advantage of it. I'll first try to get the "simple" no-dependencies multiline edit in place.

@paultech
Copy link

Thank you emoon. Reviewing that information now.
Building scintilla seems to have some heavy dependencies that I ideally do not need (Cairo, GTK2+, GLIB to name a few). This seems rather heavy for my usage case.

A simple multiline may be a better fit for my usage.

@emoon
Copy link
Contributor

emoon commented Jun 14, 2015

@paultech The Scintilla version I use (for ProDBG) doesn't have any such requirements. Me and @gwihlidal implemented a backend that uses ImGui rendering functions directly.

The base implementation is here https://github.com/emoon/ProDBG/blob/master/src/prodbg/ui/bgfx/sc_platform_bgfx.cpp

Which still needs improvments but is somewhat working.

@ocornut
Copy link
Owner

ocornut commented Jun 14, 2015

For reference that's the bgfx commit (not viewable on github web)
bkaradzic/bgfx@a510b8f
Which possibly has been based on the prodbg one.

But yes there will be a simple multiple :)

@paultech
Copy link

@emoon I was building on OSX using ./gtk/ This seems to be where my dependencies came from. Building under ./cocoa/ provides a much cleaner build. My mistake!

Thank you @ocornut!

@emoon
Copy link
Contributor

emoon commented Jun 14, 2015

That is not needed for ImGui integration: I cleaned away quite a bit of code with the version I'm using. Look at this tree here https://github.com/emoon/ProDBG/tree/master/src/external/scintilla/src

@ocornut
Copy link
Owner

ocornut commented Jun 16, 2015

Been working on this now. Not sure when it'll be done, there's literally a hundred things to redo in the code but I'm on it.
multiline
0df7b47

ocornut added a commit that referenced this issue Jun 17, 2015
…tUnformatted() level for large chunks but this is also useful) (#200)
ocornut added a commit that referenced this issue Jun 17, 2015
Not horizontally scrolling on char boundaries anymore
@ocornut
Copy link
Owner

ocornut commented Jun 17, 2015

@paultech : If you checkout the multiline branch you can try a version 1

ImGui::InputTextMultiline()

// new flags
ImGuiInputTextFlags_AllowTabInput       = 1 << 10,  // Pressing TAB input a '\t' character into the text field
ImGuiInputTextFlags_CtrlEnterForNewLine = 1 << 11,  // In multi-line mode, allow exiting edition by pressing Enter. Ctrl+Enter to add new line (by default adds new lines with Enter).
  • currently fixed size buffer provided by user (so you must provide big enough)
  • no up-down scrolling yet
  • api may change as i figure out how to enable fixed size buffer
  • i might have broke something with regular text input during the change? hopefully not.
  • there's currently a 1 KB text limit due to some buffers in the code (working on it now)

@ocornut
Copy link
Owner

ocornut commented Jun 17, 2015

I tested it on big text (100k+) and it seems to works but it is really slow at the moment. Lots of assumption in both stb_textedit and imgui side don't scale well with big text. Even a few hundred lines can have noticeable 1ms+ impact. I'll work on some optimisation. imgui side still does a lot of stupid things (~5 calc text size calculation per-frame when cursor is in a scrolled position due to various dependencies).

@paultech
Copy link

Hi @ocornut - This is looking great on my end and all my InputText seem to work just fine.
2015-06-16_000_tc_g3d_r5839

Thanks!

@ocornut
Copy link
Owner

ocornut commented Jun 19, 2015

Went beyond the call of duty and spent some time optimising the code. Basically went to tried to minimize the number of passes touching each character by merging lots of stuff.

My test case was pasting and text editing imgui.cpp (12600 lines, 540 KB) in a non-optimised build. The CPU cost grows with character count, line count, position of the cursor within the field (very top is cheaper than very bottom), amount and position selection.

TL;DR; it is now optimised enough that the cost should be negligible for files of a few hundred lines.
There's some remaining optimisation (unnecessary utf-8 <> wchar conversions).
And of course I could go the full way of storing state like a normal text editor would do (building an index and managing state) but I have tried to avoid that for now.

Some measurement on my laptop

Debug Build, editing 'main.cpp' (92 lines, ~4 KB)
- inactive ~ near 0 ms
- active at top of buffer ~ near 0 ms
- active at top of buffer, all-selected: near 0 ms
- active at bottom of buffer: near 0 ms
- active at bottom of buffer, all-selected: near 0 ms

Debug Build, editing 'imgui.cpp' (12600 lines, ~540 KB)
- widget inactive ~0.8 ms
- active at top of buffer ~3 ms
- active at top of buffer, all-selected: ~3.1 ms
- active at bottom of buffer: near ~4.5 ms
- active at bottom of buffer, all-selected: ~6.1 ms

Optimised Build, editing 'imgui.cpp' (12600 lines, ~540 KB)
- inactive ~ near 0 ms
- active at top of buffer ~0.7 ms
- active at top of buffer, all-selected: ~0.7 ms
- active at bottom of buffer: near ~0.8 ms
- active at bottom of buffer, all-selected: ~1.8 ms

Obviously editing a 12000+ lines file is not something that I'd expect anyone to do with ImGui, it's more of a extreme case. Rather than add more state to the widget for this sort of thing I'd expect people to use something like Scintilla.

Feedback welcome! I hope to merge that in master soon

@TuomLarsen
Copy link
Author

Thank you very, very much! It looks awesome!

It really is quite speedy, and I don't think thousands of lines would be that uncommon as even simple scripts could reach so many lines easily.

I ran into some issues however: in the provided example, when a line is too long I cannot see a horizontal scrollbar. But I guess I just have to provide it myself, as it is the case with vertical scrollbar. Another issue is, I have a mouse which has a "free-running" scroll-wheel - I can spin the wheel quickly and it keeps on scrolling for a while by inertia. When the text input is at the very bottom and I keep scrolling down, the screen starts to flicker as it redraws the very last lines and probably the last frame before them.

What Scintilla goes, I don't know about the one provided in bgfx, but I cannot use its original version as it scrolls the text line-by-line, i.e. not "smoothly" pixel-by-pixel, which I find very distracting, especially when using e.g. web browser next to it.

Also, I know you said you have no immediate plan to implement it but maybe you can give us a hint on how to go about adding the syntax highlighting?

In any case, thanks a lot once more, I believe this is a great addition to ImGui.

Edit: I now see that the scroll-wheel thing affect any scrolling widget but maybe it's I'm trying this under Ubuntu in VirtualBox.

@ocornut
Copy link
Owner

ocornut commented Jun 19, 2015

Horizontal scrollbar
There is horizontal scrolling when you move the cursor with the keyboard but not horizontal scrollbar.
The problem with visualizing the horizontal scrollbar is that measuring the width of the entire text would be much more costly. So while I could add it I am concerned that what may appears as a "free" feature isn't. Also just raised in #246 which I haven't answered to in details yet, but learnings from making the multi-line edition box gives me a better understanding at this.

So one possibility is to have it available but not by default and clearly comment that it has non-negligible cost. Another possibility is to come up with a "click and drag" scrollbar with no visualization of the limits but that would be inconsistent with the vertical scroll-bar.

Another possibility would be to start carrying more state across frame for this sort of case. The problem is to handle CPU spikes. I could easily cache width for a given text blob, or in fact once edition is active ImGui is in control of the text box content so I could maintain it as edition happens. But I still need to do it without major spikes (would be bad to have a 5 ms spike then typing a character, which may not be easy to do without preprocessing/indexing of lines) and need to handle it for non-active edit box which is essentially taking the text data from the user so it could change every frame. We could hide the horizontal scrollbar prior to activating the widget and that would simplify the problem a little.

Of course this all stem from the fact that little state is kept across frame and it could be reworked, but I don't see myself heading into writing a proper text editor which is a task in itself.

Mouse wheel/scrolling
My mouse wheel has been dying in the past week and I couldn't find a new mouse where I am presently, I'll look into your bug by simulating mouse with keyboard entries.

Syntax highlighting
Code call text rendering ImFont->AddFont() so assuming syntax highlighting doesn't change the size/position of any glyph but only affect colors, we could come up with a system to hook highlighting into text rendering.
A dumb "color keywords" would be trivial but that wouldn't take account of things like strings and comments. I currently rely on skipping lines prior to reaching the visible portion and this would be a problem if you want to run a lexer (it is possible to reliably backtrack with a typical lexer for say, Lua or c++? tricky because of \ inhibitor?) So if you need to tokenize the text you may have to give up on skipping lines above the visible porition.

todo

  • mouse wheel scrolling bug
  • bug handling \r

@ocornut
Copy link
Owner

ocornut commented Jun 20, 2015

Mouse wheel issue is solved. I had noticed this bug recently but as my mouse wheel my failing I attributed it to crazy mouse. When mapping the wheel to keyboard it became super clear there was a bug :)

I have now merged everything back in master.

@TuomLarsen
Copy link
Author

The mouse wheel issues is indeed gone. Thank you!

@ocornut
Copy link
Owner

ocornut commented Jun 27, 2015

Closing this. Other things like horizontal scrollbar, making it easier to grow the buffer without allocating for worse case etc. will be handled later. I added notes in the todo list.

@ocornut ocornut closed this as completed Jun 27, 2015
@Hevedy
Copy link

Hevedy commented Oct 27, 2015

So then no news about this ?
If you can include things like the ones in this c# project repo https://github.com/PavelTorgashov/FastColoredTextBox it would be very useful for all.

@aiekick
Copy link
Contributor

aiekick commented May 13, 2016

hello,

@ocornut, can you show us the code you use scintilla from bgfx ? i have many porblem with my Eu keyboard and the use of brace. left brace is alt gr and 4, and right brace is alt gr and +.

after done the right brace, the control not receive any others input, and there is some delay to have the left or right brace to show in the editor. its weird

thanks in advance :)

@ocornut
Copy link
Owner

ocornut commented May 13, 2016

I don't use scintilla or bgfx. @emoon might know.

@aiekick
Copy link
Contributor

aiekick commented May 13, 2016

OK but you have post an example from bgfx on top (Jun 2015). I speak about that

@emoon
Copy link
Contributor

emoon commented May 13, 2016

You can link to post by pressing the date. So I assume you mean this? #200 (comment)

@aiekick
Copy link
Contributor

aiekick commented May 13, 2016

yep :)

@egordorichev
Copy link

Could I ask you quickly, how did you get those line numbers? :3

@ocornut
Copy link
Owner

ocornut commented Jan 7, 2018

@egordorichev If you are interested in a fully featured text editor, try https://github.com/BalazsJako/ImGuiColorTextEdit

@egordorichev
Copy link

Haha, thanks 👍

@data-man
Copy link

data-man commented Jan 8, 2018

And even better with Scintilla

ocornut added a commit that referenced this issue Aug 22, 2018
…gle from counting in the worst case vertices reservation. (fix code added in #200!)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants