[Solved] Text editor minimap (like Sublime Text/Emacs/Eclipse)
I'm trying to create a text editor minimap like the one in Sublime Text
!http://upload.wikimedia.org/wikipedia/commons/a/af/Sublime_text3.png(Sublime Text - you can see the minimap at the right)!
At first I thought it would be very easy and straight forward, I just needed to create two QPlainTextEdit with a shared QTextDocument and set the font point size of the second one to a very small value. After that I would just have to write some simple code to connect them both.
But it turns out that it doesn't work like that. As I soon discovered, if two QPlainTextEdit share the same QTextDocument object they also share the same font.
Now I'm back at square one with egg on my face.
I've been thinking about creating a QGraphicsView, adding the second QPlainTextEdit to it and scaling the view down but it seems overly complicated and the preliminary results show a very ugly text in the scaled editor.
Any ideas about how I can create that minimap control?
Thanks in advance.
An easy approach is to "clone":http://qt-project.org/doc/qt-5/qtextdocument.html#clone the QTextDocument on every change to another QPlainTextEdit and change the font size there. You might think that it would have terrible performance, but it actually works pretty well. The disadvantage of this is that the minimum font size is 1 so you're limiting number of lines in the editor to the scrollbar height. If you add more you'll get a scrollbar in the minimap, which somewhat defeats the purpose.
Another approach would be to render the contents of the editor to a pixmap, scale it down and display it eg. on a label. There's a "grab":http://qt-project.org/doc/qt-5/qwidget.html#grab method that does that, but it has the limitation of only rendering the visible portion. Maybe there's a workaround for it. You might want to investigate that approach more.
Yet another idea is to make a custom widget, implement paintEvent, grab the text from QPlainTextEdit and draw it yourself (either to a pixmap and scale it down or directly with a small font, whichever gives better results).
thank you for the suggestions.
I decided not to use a shared QTextDocument object but instead of cloning the text document at every change I used the contentsChange() signal to keep the two text documents in sinc (it is a lot cheaper, specially if the minimap document uses a syntax highlighter).
bq. The disadvantage of this is that the minimum font size is 1 so you’re limiting number of lines in the editor to the scrollbar height. If you add more you’ll get a scrollbar in the minimap, which somewhat defeats the purpose.
Perhaps I missed the point entirely, but can't I just hide the scrollbar?.
Thanks again mate.
You could of course hide it but if your text is, say, 1000 lines long and the minimap is only 500px high because of the window size then with font of size 1 you'll only show half of the document in the minimap. Now what do you do to get to the other half if you hide the scrollbar? And if you don't hide it it's no longer a minimap. It's just another scrollable view of the document with smaller font.
With scaled pixmap approach it would work because the lines would merge eg. in the case above one line in minimap would represent two lines of the document.
Thanks for the clarification. I kind of figured out what you mean after I posted.
From my experience with Sublime Text I think it is not that important to have the whole document displayed in the minimap.
If the document is too big to fit in the minimap, ST shows only a sensible neighborhood of the region visible in the editor and adjust that neighborhood smartly and smoothly whenever that region changes. It works quite well.