MoviePass Button

A cinema ticket button that tears along its perforation on click, hinging open or snapping apart.

Preview

Loading GPUI

Install

cargo add evilbuttons

Usage

use evilbuttons::{MoviePassButton, MoviePassVariant};
use gpui::{div, prelude::*, Context, IntoElement, Render, Window};

struct ButtonDemo;

impl Render for ButtonDemo {
    fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
        div().child(
            MoviePassButton::new("admit", "Admit One")
                .variant(MoviePassVariant::Snap)
                .on_tear(|_, _| println!("Ripped!")),
        )
    }
}

Variants

Tilt

Both halves pivot on their shared bottom corners, opening a V along the tear.

Loading GPUI
MoviePassButton::new("book", "Book Seat").variant(MoviePassVariant::Tilt)

Snap

The stub breaks off in a straight line and leaves a small gap.

Loading GPUI
MoviePassButton::new("book", "Book Seat").variant(MoviePassVariant::Snap)

Keep it torn

Pass reset_delay(None) to leave the ticket torn until it is clicked again, and swap the stub text with stub.

Loading GPUI
MoviePassButton::new("backstage", "Backstage")
    .variant(MoviePassVariant::Tilt)
    .reset_delay(None)
    .stub("VIP")

Props

MoviePassButton is a GPUI RenderOnce builder; its torn state is keyed by id.

MethodTypeDefaultDescription
new(id, label)impl Into<ElementId>, impl Into<SharedString>-Unique id and the label printed on the main part of the ticket.
variant(v)MoviePassVariant::{Tilt, Snap}TiltHow the ticket tears on click.
stub(s)impl Into<SharedString>NO. 01Text on the tear-off stub.
reset_delay(d)Option<Duration>Some(1800ms)How long before the ticket mends. None keeps it torn until the next click.
stub_font(name)impl Into<SharedString>inheritedStub font, e.g. your monospace font.
on_tear(f)Fn(&mut Window, &mut App)-Fired each time the ticket tears.
on_click(f)Fn(&ClickEvent, &mut Window, &mut App)-Fired on every click (and Space/Enter), before the ticket tears or mends.
disabled(bool)boolfalseDims the ticket and ignores input.

Good to know

  • The notched halves are painted as paths, so it works on any background, and the drop shadows follow the notches.
  • GPUI can't rotate text, so when the halves tilt each glyph rides the rotated baseline but stays upright; at 6° and 10° it reads the same.
  • There is no preventDefault in GPUI: on_click can't cancel the tear.

Search docs

Jump to a button documentation page