vkbo / novelWriter

novelWriter is an open source plain text editor designed for writing novels. It supports a minimal markdown-like syntax for formatting text. It is written with Python 3 (3.9+) and Qt 5 (5.15) for cross-platform support.
https://novelwriter.io
GNU General Public License v3.0
2.01k stars 102 forks source link

A visual representation of chronologies with grouping support #854

Open attilaoroszdev opened 3 years ago

attilaoroszdev commented 3 years ago

Hi,

I've only just discovered noverWriter, and loving it. I'm tech-firs minded, so really-enjoying the markdown-esque syntax and the simplicity.

My suggestion is a visual timeline-like representation of everything, but I purposely did not use that word, since I noticed it is used in another context already.

This might be loosely related to #76, so if you find it too similar, I'm happy to close this and add everything as a suggestion there.

The idea

When things get complicated, i.e. multiple POVs, many locations, multiple plot lines, etc it can be difficult to keep track of how everything progresses within these boundaries. Windows only software like Plottr and Aeon timeline cater for these needs, but neither are integrated right into a writing app. Since we have a lot of info and meta info available, making a visual group-able representation could probably be doable.

The point would be to represent each chapter and scene on mutiple visual chronological timelines, where the swim-lanes would mean the metadata or tag based groups. User could group by. e.g. POV character, plot line, location, timeline, etc (yes, a timeline-based timeline :smile: )

Something like this:

| Chapter | Chapter 1                                  | Chapter 2                                   | Chapter 3        ... |
|         |                                            |                                             |                      |
| Group 1 |---[Scene 1.1]---[Scene 1.2]----------------|-------------------------------[Scene 2.3]---|----------------  ... | 
|         |                                            |                                             |                      |
| Group 2 |-------------------------------[Scene 1.3]--|---[Scene 2.1]-------------------------------|---[Scene 3.1]--- ... |
|         |                                            |                                             |                      |
| Group 3 |--------------------------------------------|-----------------[Scene 2.2]-----------------|----------------- ... |

Here, of course, the groups could be dynamically changed, to whatever the user wants to group by, which would only make the difference of showing the individual scenes in a different swimlane.

Where multiple attributes might apply to a scene, they could be shown in both swimlanes.

If/when/as the meta/tags get extended with anything like start/end times, duration, etc, the individual rectangles, representing scenes could graphically represent length as well, but for the simplest implementation this might be overkill. (Plus it would depend on something lie that #76 discuses.)

A nice feature would be to be able to "turn" this, so as to make it either horizontal or vertical (Plottr has this feature, it's quite useful, as e.g. one of my screens is in portrait mode).

I was thinking, this could be done with a simple grid layout, basically.

So what do you all think?

vkbo commented 3 years ago

Thanks for writing such a detailed feature proposal. This is indeed where #76 is headed based on the previous discussions there. I like the "swim lane" proposal as well. That's a neat feature.

There is a way to render such visual representations in Qt with a QGraphicsView, which would also allow for some interaction with the content. I think this would fit best in a visualisation tool in a separate window that can be open when needed, and closed when not.

attilaoroszdev commented 3 years ago

Cool! Why not a tab, though? Just under "Outline", I think? It could be used as an alternative to that, or that's how I would use it, anyway. :) I might look into QGraphicsView if I find the time, and cobble something together, but can't say when.

If interaction, and particularly moving items is possible (from having a cursory glance at the docs, it seems to be), it would also make it super-easy (from a user/UX perspective) to reorder items, and that would be even better.

vkbo commented 3 years ago

I could put it in a third tab. I'm mainly concerned with performance issues as this view may be heavy to generate for a complex project. However, I can make the canvas blank and require that the user presses a button to build it, in which case it would be more static. It would also be possible to just generate the whole thing as an SVG image, which can be cached between sessions. However, that would make it less interactive,

I've never used the QGraphicsView feature, so I have no idea how well it works, but I know Scrite uses it for a similar purpose.

As for the drag and drop, this is more tricky. The way the user splits content into documents is entirely up to the user. This means that scenes may not be in individual files, so reordering them would imply manipulating the content of the files. The way novelWriter is written, at no time does the application touch the content of your files with automated processes. Only when typing is the content ever changed. The split tool doesn't touch your file either. It generates new ones only.

I've been very strict about this to make the application resistant to data loss. It is so easy to introduce a small bug that drops the last line of a file, or something similar, due to indexing offsets. I've made that mistake several times in code that analyses content (which is non-destructive).

attilaoroszdev commented 3 years ago

OK, I see the problem, I suppose making it possible to only move the contents of individual files around as a unit would break the flow of d-n-d reorganisation in general; although if one wants to be able to reorder stuff properly, one might as well make a sensible structure first. :)

Structural reordeing could also be an optional feature, either form settings or something like a checkbox, with an explanation that you'd only be able to move units that are in the same file together, and that it might not make a lot of sense in some cases.

Might be worth marking file boundaries, somehow? So that user knows what can be moved?

Performance-wise, I'm not sure how Qt renders into the viewport, but AFAIU it will only paint the relevant bits, so might not be very heavy. Anyway, I think you could do the empty canvas thing, and use the tab switch as a trigger so no extra button clicking would be necessary.

vkbo commented 3 years ago

Yeah, the Outline panel auto-updates when the tab is clicked, but only if any of the novel files have been changed since last time. This may be enough for the other tab too. It should be tested for performance anyway.

Since novelWriter is written in Python, there is a bottleneck between the Python and Qt C++ libraries that occurs when there is a lot of communication back and forth. This limits how much you can customise the Qt widgets through for instance subclassing and paint events for drawing custom graphics. It is also why there is a bottleneck for the spell checker for large files as it triggers a back-and-forth on every line of the document. This somewhat limits how much fancy things you can do that is otherwise possible in Qt.

One way to generate a map of the project is, as I mentioned, by generating an SVG file. Since it is just XML, it can be generated entirely in Python and just loaded in a single pass to a Qt widget for displaying. This is also a bit appealing because you can pretty much draw anything on an SVG canvas.

In the original idea between me and @Number042 we were talking about having a split view at the bottom of the main tab, under the editor and viewer, that could show something similar to what you're proposing above. That too would be easy to generate as an SVG.

attilaoroszdev commented 3 years ago

Didn't know pyQt had those limitations. True, then, performance-wise the SVG would be the best, and since this is more a representation than anything, it might be best over-all. Also, thus the whole idea of everything being text based is better adhered to. Fancy GUIs are for noobs and Mac users, anyway. 🤣

So clicking to render at first click or when contents changed sounds like the most economic solution. Or when the user changes grouping type, I'd suggest, since the power of swim-lane groups is that one can decide what to display as groups.

I'd say separate tab might still be more useable, though, than a tiny timeline underneath that you can see in e.g. Manuskript (if that's what you meant). This way scenes could show all sorts of interesting infos, like title, filename, non-grouping tags (characters, location, etc), colour, whatever you like, plus with many item in the grouping type (e.g. 6 diatinct POVs) there might be a need for sufficient space to display.

Ellipsine commented 2 years ago

What if we use a separate kind of documents to create timeline (and not our scenes) ? The "Chronologie" racine folder object can be use to make a separate timeline which can be use as tag "time" in the novel itself. We could use manual tagging to add information like places, characters and so on. We would not manipulate the novel structure by itself and we may manipulate the "chronologie" object files instead of parts of the novel. I am not programmer myself so I don't know if it would work this way.

attilaoroszdev commented 2 years ago

What if we use a separate kind of documents to create timeline (and not our scenes) ? The "Chronologie" racine folder object can be use to make a separate timeline which can be use as tag "time" in the novel itself. We could use manual tagging to add information like places, characters and so on. We would not manipulate the novel structure by itself and we may manipulate the "chronologie" object files instead of parts of the novel. I am not programmer myself so I don't know if it would work this way.

Yes, I think that's the whole idea, keeping the structure and the content separated, and build timelines from meta, really.

I've been OOO and will be for a while (travelling), so I cannot really look into the structures, but it sounds doable.

peter88213 commented 1 year ago

I guess that such a view can be implemented relatively easily with a grid containing differently formatted text labels. I have implemented something similar with tkinter:

grid

Via callback methods the whole thing is also interactive, i.e. the intersection points have a binary status that can be changed by clicking on them. As easy as this is to program, the table builds up slowly with tkinter.

Maybe I'll try a swimlane representation as suggested by the original poster; the transfer effort from the table should be manageable.