novelWriter icon indicating copy to clipboard operation
novelWriter copied to clipboard

Editor Line Height

Open vkbo opened this issue 4 years ago • 23 comments

Is it possible to change the line spacing between lines? I haven't found any settings for that yet, maybe I'm overlooking something.

If not, it would be a great addition. When I first started trying to write, I used a line spacing of 1 too, as mostly used by text editors, but I met a professional writer, who asked why I don't write, and even print the manuscript in a line spacing of 1.5! She was surprised I did not!

Apparently, most manuscripts are printed with a line spacing of 1.5 when printed on regular size A4 pages (that's here in Belgium the case) because it reads much easier, which is important for the person evaluating your work, and then the amount of pages corresponds more or less to what it would be when published. She recommended me to do the writing with such line spacing too, which I did in other software, and to be honest, it is much better! It is much easier for the eyes.

grtz, Bart

Originally posted by @bartart3d in https://github.com/vkbo/novelWriter/discussions/653

vkbo avatar Feb 07 '21 10:02 vkbo

It's not straight forward in the editor, but need to test: https://stackoverflow.com/questions/10250533/set-line-spacing-in-qtextedit

vkbo avatar Feb 07 '21 10:02 vkbo

The following code will do the trick, but it is far too slow as it has to be applied after the document is loaded since the .setPlainText method resets formatting. For a novel-size reference document (1.2 Mb) the load time goes from ~340 ms to ~30 seconds on my fast i7 desktop PC.

if self.mainConf.lineHeight > 100:
    blockFmt = QTextBlockFormat()
    blockFmt.setLineHeight(self.mainConf.lineHeight, QTextBlockFormat.ProportionalHeight)

    theCursor = self.textCursor()
    theCursor.clearSelection()
    theCursor.select(QTextCursor.Document)
    theCursor.mergeBlockFormat(blockFmt)

vkbo avatar Feb 07 '21 17:02 vkbo

I too use this 1.5 line spacing for review copies, but that is part of the magical incantations I perform manually in my cave with my LibreOffice cauldron ... might it be an option for the .odt output ? Jan

jyhelle avatar Feb 09 '21 23:02 jyhelle

Absolutely. With the ODT converter I wrote last week I have full control of the output as opposed to the current exporter. It will be included in the 1.2 release. I'll make a beta release of it very soon.

vkbo avatar Feb 10 '21 08:02 vkbo

Since this will only be available for exports, and that has now been merged to dev for 1.2, I'm closing this.

vkbo avatar Feb 10 '21 19:02 vkbo

Has there maybe been an update since Feb 2021 that would make the load time for a custom line height in the editor more feasible? For certain fonts and font sizes it can feel rather cramped when writing.

HeyMyian avatar Dec 29 '22 03:12 HeyMyian

No, there are no changes. Qt5, which novelWriter is based on, is no longer being updated with new features. I'm not sure whether this is different in Qt6, but novelWriter is not moving to Qt6 yet.

vkbo avatar Dec 29 '22 15:12 vkbo

The following code will do the trick, but it is far too slow as it has to be applied after the document is loaded sine the .setPlainText method resets formatting. For a novel-size reference document (1.2 Mb) the load time goes from ~340 ms to ~30 seconds on my fast i7 desktop PC.

if self.mainConf.lineHeight > 100:
    blockFmt = QTextBlockFormat()
    blockFmt.setLineHeight(self.mainConf.lineHeight, QTextBlockFormat.ProportionalHeight)

    theCursor = self.textCursor()
    theCursor.clearSelection()
    theCursor.select(QTextCursor.Document)
    theCursor.mergeBlockFormat(blockFmt)

In which file would I set this, if I want to try it out?

berndschmidl avatar Apr 02 '23 10:04 berndschmidl

I can't remember, but somewhere after the setPlainText call in the loadText function of the doceditor.py file.

vkbo avatar Apr 02 '23 11:04 vkbo

@berndschmidl Did you find where exactly to put the mentioned code, and if you did what were your results?

HeyMyian avatar May 02 '23 17:05 HeyMyian

@HeyMyian Sorry, for the late answer. Unfortunately not but I also just tried for 20 minutes or so. Please let me know if you could figure it out.

berndschmidl avatar May 17 '23 11:05 berndschmidl

Nope, I couldn't figure it out either. If my memory serves, there were some errors about self.mainConf.lineHeight not defined, which looks like it would make sense, but then I also gave up because I don't Python.

HeyMyian avatar May 17 '23 11:05 HeyMyian

Yeah, that's just the config value I added for the line height in my test implementation. All you need to do is replace that with the line height value you want.

vkbo avatar May 17 '23 15:05 vkbo

I just injected this into the code after the .setPlainText() function I mentioned earlier (the lines with the green bar) and it worked right away.

image

You also need to import QTextBlockFormat at the top (my editor adds this automatically).

image

vkbo avatar May 17 '23 15:05 vkbo

@vkbo Thank you! I'm a step further. I think I did exactly what you said in your previous post. But now when I open novelwriter I get this error:

Environment: novelWriter Version: 2.0.7 Host OS: linux (6.2.6-76060206-generic) Python: 3.10.6 (0x30a06f0) Qt: 5.15.3, PyQt: 5.15.6 lxml: 4.8.0 enchant: 3.2.0

AttributeError: 'Config' object has no attribute 'lineHeight'

Traceback: File "/usr/bin/novelwriter", line 33, in sys.exit(load_entry_point('novelWriter==2.0.7', 'gui_scripts', 'novelwriter')())

File "/usr/lib/python3/dist-packages/novelwriter/init.py", line 258, in main nwGUI.postLaunchTasks(cmdOpen)

File "/usr/lib/python3/dist-packages/novelwriter/guimain.py", line 354, in postLaunchTasks self.showProjectLoadDialog()

File "/usr/lib/python3/dist-packages/novelwriter/guimain.py", line 893, in showProjectLoadDialog self.openProject(dlgProj.openPath)

File "/usr/lib/python3/dist-packages/novelwriter/guimain.py", line 547, in openProject self.openDocument(lastEdited, doScroll=True)

File "/usr/lib/python3/dist-packages/novelwriter/guimain.py", line 625, in openDocument if self.docEditor.loadText(tHandle, tLine):

File "/usr/lib/python3/dist-packages/novelwriter/gui/doceditor.py", line 396, in loadText blockFmt.setLineHeight(self.mainConf.lineHeight, QTextBlockFormat.ProportionalHeight)

skofield05 avatar May 18 '23 11:05 skofield05

Yes, because you keep adding the self.mainConf.lineHeight value. As I already mentioned three posts up, the config doesn't have a lineHeight setting, so just add the line height you want manually like in my screenshots.

vkbo avatar May 18 '23 13:05 vkbo

Thanks a lot. I missed that. Works fine now!

skofield05 avatar May 19 '23 07:05 skofield05

I found a workaround to increase the line height. It uses https://github.com/source-foundry/font-line to change the line height in the font file itself. For simultaneous installations of the same font with different line heights, one will also need https://github.com/chrissimpkins/fontname.py or similar tools to rename the font family.

HeyMyian avatar Jun 26 '23 13:06 HeyMyian

Ooh, interesting. If it's not a too technical solution, maybe it's a candidate for the FAQ.

vkbo avatar Jun 26 '23 14:06 vkbo

The font-line script itself is a one-line installation with pip. The font family name change is a python file that I somehow had to download and put into the same folder as the font file I was changing -- I have little idea about Python magic but I got this to work very easily.

After that, I didn't bother with any of the reports that font-line can generate and I went straight for the change. It's two lines in the terminal:

font-line percent 30 Hack-Regular.ttf to change the line height (30 % works fine for me for the font Hack).

python3 fontname.py "Hack LG 30" Hack-Regular-linegap30.ttf to change the name of the font family (originally "Hack") to something custom ("Hack LG 30").

This has to be repeated for each font file in the family, like regular, italic, and bold.

It works well with the novelWriter editor itself, but the document header clips the lower parts of the letters, especially with more extreme changes to the line height. I would absolutely prefer a native solution within novelWriter, I kind of see it as a basic setting for any text editor. But if it's not happening, then this seems to be a valid workaround.

Do FAQ already exist for novelWriter? Do you want me to type something up or can you use the above info?

HeyMyian avatar Jun 26 '23 14:06 HeyMyian

It works well with the novelWriter editor itself, but the document header clips the lower parts of the letters, especially with more extreme changes to the line height. I would absolutely prefer a native solution within novelWriter, I kind of see it as a basic setting for any text editor. But if it's not happening, then this seems to be a valid workaround.

Perhaps it is basic, but Qt doesn't seem to consider it a basic enough setting to provide a default option for it. It's easy enough to set the initial text format, so for a new document, it is trivial to achieve. However, when you load a document into the editor, this is reset, and I haven't yet found a way to load the document with a specific text format. The only option I've found is to iteratively apply it after loading, which is the solution mentioned above. This is painfully slow from Python.

I guess the main reason Qt doesn't care is that in C++ this is trivial. From C++ you can just build the document line by line very quickly, and apply whatever formatting you like.

I can experiment some more with it, but any solution that iteratively builds a document from Python seems to be incredibly slow, and I still haven't found out why. I've even discussed it with one of their developers at a conference.

Do FAQ already exist for novelWriter? Do you want me to type something up or can you use the above info?

There is a FAQ in the docs, but I plan to move it out from there and into the website itself. I can let you know when I've done that.

vkbo avatar Jun 26 '23 17:06 vkbo

I have made good progress on this issue. Mostly by accident.

The editor in novelWriter is actually a rich text editor forced to run as a plain text editor. There are a few benefits to this, in particular, it's much smoother because the content is laid out with real pixel values, so you can have pixel-by-pixel scrolling.

I recently tested switching to Qt's plain text editor, which allows for no formatting at all, and therefore uses a significantly simpler text layout engine under the hood. The rest of the editor behaves the same. I found this editor setup to be significantly faster without the large text scaling issues of the rich text editor when accessed from Python.

I'm testing this out now in the branch that will eventually be release 2.2 (so not the upcoming release). I have been able to not only successfully apply line height settings other than the default, but also allow full spell checking for very large documents. I've removed the large document limit setting the user can define, and the hard cap of 5 MB of text per document.

The only downside is the lack of smooth scrolling (it scrolls line-by-line), which also affects the "typewriter scrolling" mode. I think it is worth it.

Anyway, I'm therefore re-opening this issue, and scheduling it for the 2.2 Beta release,

vkbo avatar Sep 10 '23 15:09 vkbo

Well, that attempt was short lived. The layout engine for plain text ignores the line height setting completely, see QTBUG-51891. So, until the issue is fixed, we're back to square one here.

I'll leave the issue open though for future reference, and in case it is resolved. If a fix is implemented into a Qt 5.15 LTS release, I'll add the feature.

vkbo avatar Sep 10 '23 17:09 vkbo