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

GodSVG requirements #687

Open
MewPurPur opened this issue Apr 27, 2024 · 1 comment
Open

GodSVG requirements #687

MewPurPur opened this issue Apr 27, 2024 · 1 comment

Comments

@MewPurPur
Copy link
Owner

MewPurPur commented Apr 27, 2024

The core infrastructure refers to the native handling of the SVG text, the TagSVG representation of it, and the ways these implementations hook into the different places in the editor.

Needed for #663 and #434. The latter is the most important feature missing from GodSVG at the moment, and a direct blocker for the beta.

Put simply, when I implemented tag hierarchies in GodSVG, there are a few things I kicked down into the future, because I didn't have enough knowledge to be able to tackle them. The biggest one is the inheritance of default values for attributes. and tags can override the default values of some attributes (but not all) for all ancestor tags.

Currently, even though is implemented, it doesn't support the functionality natively. If you override fill="red" in the root tag, all its ancestors will still have a default of fill="black", and they won't even let you change to a black color, since they still believe it's the default. This behavior is erroneous, and needs to be fixed.

A lot of limitations hamper the possibility to implement this though, for example the fact that attribute changes only propagate up to the root, but they need to also be able to propagate down, as when you change a or tag, all ancestor tags should be notified about the change.

Requirements

Below I've listed the things that GodSVG needs to be able to do, which would help me define a specification.

SVG Parser

Only SVG text can be used for generating a graphic, but you can't get specific information out of it before parsing it. The SVG Parser must have two important functions:

  1. A function that converts text into a TagSVG representation. This one can potentially error out, for example if it doesn't describe an SVG.
  2. A function that converts TagSVG into text, which must always produce a valid result and respect the XML autoformatting settings.

Undo and Redo

The UndoRedo that handles the SVG should handle versions of the SVG text. It should only take specific snapshots of it, that is, actions should be able to opt out of UndoRedo (e.g., no UndoRedo while you're dragging a gizmo, only when you finish the operation). Also, no operation if the SVG text didn't change.

Editing the SVG text without the SVG Code Editor

  1. Importing an SVG should update the underlying SVG text and clear the undo history. Except, if the file is the same as the current one, don't clear the history. Moreover, if the text would also be unchanged, throw a dialog like "Note: The imported SVG is identical to the currently edited one." and don't create any UndoRedo actions.
  2. Resetting an SVG should only be available if it would change the underlying SVG text. Register it as a single action and don't clear any history.
  3. Optimizing an SVG should only be available if it would change the underlying SVG text. Register it as a single action.
  4. Clearing an SVG should set its text to a default, empty, 16x16 SVG, and be registered as a single action without clearing any history.

If importing or resetting makes it so the new text gives parser errors, don't parse it.

SVG Code Editor

When not focused, the SVG Code Editor should always reflect the underlying SVG text. Any changes to the text while it's not focused clear its undo history.

When focused, the text should only change how the user edits it. It would no longer reflect the underlying SVG text. Every time the user edits the text, it would be passed to the SVG Parser. If there's an error, don't change the underlying SVG text, keep the old one. If there's no error, feed the TagSVG representation back into the SVG Parser and use the returned text as an underlying SVG text.

When you click away, the SVG Code Editor should go back to reflecting the underlying SVG text. If this change resulted in any difference, that should count as a single UndoRedo action, and should be the only kind of external change that doesn't clear the SVG Code Editor's undo history

Indications

Certain elements should be able to be marked as selected or hovered. They should reflect simultaneously inside the SVG Inspector and the SVG Viewport, if relevant there. Those things are:

  • XML nodes such as tags
  • Path commands
  • Segments of a polyline or a polygon (Neither are implemented right now, this is just food for thought right now)

You should be able to select multiple of all of these, but you shouldn't be able to select things from different categories, or path commands or segments of a polyline or polygon from different tags.

Moreover, there should be a mechanism to allow some of the attributes in a tag to be focused, specifically in the inspector. When you drag handles that can change this attribute, it should be highlighted specially in the inspector.

SVG Inspector

The SVG Inspector should always represent the root TagSVG's hierarchy. A tag would be represented as a frame which has attribute editors, some extra things that may allow certain operations or other actions, and the child XML nodes at the bottom.

XML nodes - Comments, Text, and CDATA - should have simpler editors, where the main part is a TextEdit. When text is edited inside them, it immediately affects the SVG itself, unless the new text is illegal (i.e. -- inside a comment, or < inside text). Their undo history management should be similar to that of the SVG Code Editor.

The basic XML nodes don't need any context about the SVG hierarchy.

Tags should have more complex editors that allow you to focus attribute editors, tied to specific attributes of the tag, and edit those attributes. All attribute editors are shaping up to have LineEdits, which should enact their change on the TagSVG, and thereby the underlying SVG text, when they are unfocused. How undo history is done doesn't matter much for them (Godot doesn't make it very controllable anyway).

Tags need context about the SVG hierarchy, as there are multiple "illegal" configurations (they aren't errors, but they are still for the most part illegal), and they also have attributes which would require information about things like IDs, ancestor groups, etc.

Attribute editors may popup widgets. Changes in those should change the underlying SVG text immediately. The popup widgets should probably not have their own undo history management, but instead apply to the SVG itself in a reasonable way.

XML node operations

  • Add: Creates a new XML node with its default configuration, selecting it as well. Should be possible at any location.

  • Delete: Deletes all selected XML nodes, and the selection is removed.

  • Duplicate: Each selected XML node creates a new identical XML node under it, and the selection is changed to all the new XML nodes.

  • Convert To: Turns the selected XML node into some kind of equivalent one of a different type, keeping its selection.

  • Move Up/Down: If all selected XML nodes, after filtering descendants, are at the same depth, move them up or down, whilst keeping them selected.

Move To: Happens via drag-and-drop, and maybe other methods in the future. After filtering descendants, all XML nodes are moved to a set location, retaining their order from top to bottom. Locations can be below an XML node, above an XML node, or inside a tag (should not be a one of the selected ones or an ancestor of it)

SVG Viewport

In this section, a "sizeless" SVG is one without width and height, as well as without a viewBox.

The SVG viewport should have:

  • Zooming controls: Should generally be freeform, but any time the SVG's size changes, the zoom should reset and the graphic should be centered (as if you've pressed Ctrl+0). The grid should also be redrawn. If the SVG is sizeless, zoom reset should take you to 100% size, and center you on (0, 0).
  • Checkerboard background: See above. It should always go from (0, 0) to (width, height). If the SVG is sizeless, have the checkerboard background stretch infinitely.
  • Graphic: Should be based off of the underlying SVG text and fit the same space as the checkerboard pattern. If the SVG is sizeless, the graphic should go on forever. When it comes to actual rendering, in both scenarios, only the visible rectangle should be rendered (this is crucial for performance).
  • Resizing dragger: To change how much space the viewport takes vs the inspector. When the viewport gets resized, an equal amount of space should be added on both sides.
  • Handles and contours: Contours roughly outline the mathematical shape of the SVG and can't be interacted with. Handles are objects that display little textures on the canvas that can be hovered, selected, and dragged. Selecting a handle is similar to selecting a tag in the inspector, but more limited - dragging it gives you access to at most two attributes, path command parameters, or other selectable things.

Handles

Handles should be able to be hovered and selected, which would use the same interface as the inspector's hovering and selecting of tag editors.

The SVG viewport can also have options that context popups, with some actions occasionally. Right-clicking a place in the viewport should enable you to add a tag at that position, overriding the position defaults immediately upon the creation of the tag, with this being registered as a single action in the UndoRedo.

Moreover, certain actions that would normally create a handle, when done in the viewport, should force you to move that handle. For example, adding a new path command would also make you drag along the new handle, as well as any handles that should be relative to it in some way. Only when you click will an UndoRedo action be generated, and if you make any destructive operations in the meantime, the handle is just deleted without any UndoRedo action.

Attribute editing

The default of an attribute is defined, as per the SVG specification, by its usual default value, or its nearest or tag ancestor that has a value for it.

If an attribute is edited to a value that's the same as its current default, it should be "turned off", its value dimmed.

When an attribute inside a tag is changed, the tag itself and all the ancestor tags need to somehow learn about this, so that they can update their default, in case this tag was somehow inherited. Moreover, a similar mechanic should somehow be implemented for IDs and URLs, i.e. changing a stop inside a gradient would change a gradient, which would need to propagate to everything that references this ID.

Formatting

The XML will have an autoformatter that will always be active.

Attribute formatters would have some more quirks. For all of them, you would have a number of settings to specify how formatting works, which will be used in scenarios where you don't input a value manually (such as "2 + 3" in a number field, using the color picker in a color field, or changing path commands in a path field). When you, the user, input things (i.e. the direct value through a LineEdit, like "5" in a number field, or "M4 2 h8" in a path field) they won't be formatted, unless you've turned on autoformatting for the particular type of attribute.


This list should elaborately define all the systems that need to interact with the core architecture of GodSVG. Knowing the requirements is essential to be able to come up with a good core architecture that can fulfill all of them. This can also serve as a baseline if/when further changes to the core infrastructure are needed.

@MewPurPur
Copy link
Owner Author

MewPurPur commented Apr 27, 2024

Monologue about something I didn't specify in here

Bummer, but I don't think GodSVG can have any functionality around deciding whether an attribute change in a tag will affect a child or not.

Normally, if you have something like

<g fill="red">
  <circle fill="red">
  <circle fill="red">
  <circle fill="red">
</g>

when you change the fill of the tag, the circles would remain the same. But GodSVG automatically would remove the circles' fill attributes, because they are the default value

Hmm... Maybe if an attribute is taking its default value from a specific tag, you can have both cases?

If you have the attribute in the SVG or if you edit the attribute through the editor, the value won't default even if it's the same as the default. The attribute would be added to the SVG. But you can reset it to default by deleting all text, or maybe I'd even add an option in the context menu for resetting to the default.

I think that'd be the best of both worlds.

Edit: No, it wouldn't be, now you can't hardcode the circles to black.

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

1 participant