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

Layer API #153

Open
sunjay opened this issue Nov 27, 2019 · 0 comments
Open

Layer API #153

sunjay opened this issue Nov 27, 2019 · 0 comments

Comments

@sunjay
Copy link
Owner

sunjay commented Nov 27, 2019

NB: This is a far future idea at the time of writing, but who knows, maybe we'll get it done sooner than we think! 😄

It would be very cool if we added support for allowing turtles to divide up the drawing into layers. The layer stack would behave exactly like layers behave in graphics programs like Photoshop. The base Drawing would act as a permanent bottom layer (cannot be reordered).

Here's the API I'm imagining for this:

pub struct Layer {
    // ...
}

impl Layer {
    /// Adds a layer to above this layer and returns it. Any drawings created
    /// on this new layer will appear above this layer, and any other layers
    /// below it in the layer stack. Drawings on this new layer will also
    /// appear above the original `Drawing` itself. Other layers and the
    /// `Drawing` can still be used as normal as you use this layer.
    pub fn add_layer_above(&mut self) -> Layer {
        // ...
    }

    /// Creates a new turtle and assigns it to this layer.
    pub fn add_turtle(&mut self) -> Turtle {
        // ...
    }

    /// Merges the drawings of this layer into the layer below it (or
    /// into the `Drawing` if this is the first layer). This layer may not
    /// be used anymore after this point. Any `Turtle`s that have been
    /// assigned to this layer will be reassigned to the layer this was
    /// merged with.
    ///
    /// # Panics
    ///
    /// Panics if there is no lower layer to merge into.
    pub fn merge_down(self) {
        // ...
    }

    /// Moves this layer underneath the given layer in the layer stack.
    /// The drawings of this layer will now be drawn underneath that layer.
    /// Any `Turtle`s assigned to this layer will continue drawing on it
    /// unaffected.
    ///
    /// # Panics
    ///
    /// The base layer (from `Drawing`) cannot be moved. Attempting to do
    /// so will result in a panic.
    pub fn move_under(&mut self, other: &Layer) {
        // ...
    }
    pub fn move_over(&mut self, other: &Layer) { /* ... */ }

    /// Clears all the drawings from this layer. All other layers,
    /// as well as the original `Drawing`, are completely unaffected.
    pub fn clear(&mut self) {
        // ...
    }

    /// Removes this layer from the layer stack, deleting all drawings
    /// on this layer in the process. Any turtles assigned to this layer
    /// are reassigned to the original `Drawing`.
    ///
    /// # Panics
    ///
    /// Trying to remove the base layer (from `Drawing`) will result in
    /// a panic.
    pub fn remove(self) {
        // ...
    }

    /// Duplicates this layer and all of its drawings, leaving any
    /// assigned turtles still assigned to the previous layer.
    /// The new layer is placed above this layer.
    pub fn duplicate(&self) {
        // ...
    }

    /// Sets the clipping rectangle in which this layer will be drawn
    ///
    /// No drawings outside of the given rectangle will show. This can be
    /// useful to accomplish a "picture in picture" effect or even a
    /// "split screen" effect.
    pub fn set_clipping(&mut self, top_left: Point, size: Size) {
        // top_left and size are in turtle world coordinates
        // ...
    }

    /// Clears the clipping rectangle for this layer and allows it to be
    /// drawn across the entire window.
    pub fn clear_clipping(&mut self) {
        // ...
    }

    //TODO: set_background_color
}
impl Drawing {
    /// Creates a new turtle that can draw on this drawing
    pub fn add_turtle(&mut self) -> Turtle {
        // ...
    }

    /// Adds a layer to this drawing and returns it. Any drawings created
    /// on this new layer will appear above any previously created layers
    /// as well as the original `Drawing` itself. Other layers and the
    /// `Drawing` can still be used as normal as you use this layer.
    pub fn add_layer_above(&mut self) -> Layer {
        // ...
    }

    // Clears the drawing and all layers in the layer stack
    pub fn clear_all(&mut self) {
        // ....
    }
}
impl Turtle {
    /// Assigns this turtle to draw on the given layer. You may also
    /// pass the original `Drawing` to this method to assign the turtle
    /// back to the base layer of the layer stack.
    pub fn draw_on<L: AsLayer>(&mut self, layer: L) {
        // ...
    }
}

The add_turtle methods are specifically a part of the multiple turtles API (#16). Every other part of this can be implemented independent of that.

The set_clipping method can become a future extension and a separate GitHub issue if it is too much work to implement it as part of this.

Missing from this API is any way to traverse the layer stack. I have no idea if that is a useful feature or not or how the API should look. The functions above should be sufficient as a starting point.

There should also be more getters in the final API.

Mentoring Instructions

This is a big issue and it will require a lot of thought and design before the actual implementation work can begin.

Having said that, here are some assorted notes about the implementation:

  • The public API will be implemented like everything else in turtle: as a set of requests/responses
  • The main interesting part of the implementation is the edits to the display list
  • The display list will become a stack of layers instead of just the flat list that is right now
  • The methods on the display list will have a layer ID parameter added to them
  • The iteration methods on the display list will need to go through the layers in order, and continue to work regardless of which layers have drawing primitives added to them
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