1032 lines · 33.0 KB · Rust
RawDownload
use std::{    hash::{Hash, Hasher},    iter, mem,    ops::Range,}; use crate::{    black, phi, point, quad, rems, size, AbsoluteLength, Background, BackgroundTag, Bounds,    ContentMask, Corners, CornersRefinement, CursorStyle, DefiniteLength, DevicePixels, Edges,    EdgesRefinement, Font, FontFallbacks, FontFeatures, FontStyle, FontWeight, Hsla, Length,    Pixels, Point, PointRefinement, Rgba, SharedString, Size, SizeRefinement, Styled, TextRun,    WindowContext,};use collections::HashSet;use refineable::Refineable;use smallvec::SmallVec;pub use taffy::style::{    AlignContent, AlignItems, AlignSelf, Display, FlexDirection, FlexWrap, JustifyContent,    Overflow, Position,}; /// Use this struct for interfacing with the 'debug_below' styling from your own elements./// If a parent element has this style set on it, then this struct will be set as a global in/// GPUI.#[cfg(debug_assertions)]pub struct DebugBelow; #[cfg(debug_assertions)]impl crate::Global for DebugBelow {} /// How to fit the image into the bounds of the element.pub enum ObjectFit {    /// The image will be stretched to fill the bounds of the element.    Fill,    /// The image will be scaled to fit within the bounds of the element.    Contain,    /// The image will be scaled to cover the bounds of the element.    Cover,    /// The image will be scaled down to fit within the bounds of the element.    ScaleDown,    /// The image will maintain its original size.    None,} impl ObjectFit {    /// Get the bounds of the image within the given bounds.    pub fn get_bounds(        &self,        bounds: Bounds<Pixels>,        image_size: Size<DevicePixels>,    ) -> Bounds<Pixels> {        let image_size = image_size.map(|dimension| Pixels::from(u32::from(dimension)));        let image_ratio = image_size.width / image_size.height;        let bounds_ratio = bounds.size.width / bounds.size.height;         match self {            ObjectFit::Fill => bounds,            ObjectFit::Contain => {                let new_size = if bounds_ratio > image_ratio {                    size(                        image_size.width * (bounds.size.height / image_size.height),                        bounds.size.height,                    )                } else {                    size(                        bounds.size.width,                        image_size.height * (bounds.size.width / image_size.width),                    )                };                 Bounds {                    origin: point(                        bounds.origin.x + (bounds.size.width - new_size.width) / 2.0,                        bounds.origin.y + (bounds.size.height - new_size.height) / 2.0,                    ),                    size: new_size,                }            }            ObjectFit::ScaleDown => {                // Check if the image is larger than the bounds in either dimension.                if image_size.width > bounds.size.width || image_size.height > bounds.size.height {                    // If the image is larger, use the same logic as Contain to scale it down.                    let new_size = if bounds_ratio > image_ratio {                        size(                            image_size.width * (bounds.size.height / image_size.height),                            bounds.size.height,                        )                    } else {                        size(                            bounds.size.width,                            image_size.height * (bounds.size.width / image_size.width),                        )                    };                     Bounds {                        origin: point(                            bounds.origin.x + (bounds.size.width - new_size.width) / 2.0,                            bounds.origin.y + (bounds.size.height - new_size.height) / 2.0,                        ),                        size: new_size,                    }                } else {                    // If the image is smaller than or equal to the container, display it at its original size,                    // centered within the container.                    let original_size = size(image_size.width, image_size.height);                    Bounds {                        origin: point(                            bounds.origin.x + (bounds.size.width - original_size.width) / 2.0,                            bounds.origin.y + (bounds.size.height - original_size.height) / 2.0,                        ),                        size: original_size,                    }                }            }            ObjectFit::Cover => {                let new_size = if bounds_ratio > image_ratio {                    size(                        bounds.size.width,                        image_size.height * (bounds.size.width / image_size.width),                    )                } else {                    size(                        image_size.width * (bounds.size.height / image_size.height),                        bounds.size.height,                    )                };                 Bounds {                    origin: point(                        bounds.origin.x + (bounds.size.width - new_size.width) / 2.0,                        bounds.origin.y + (bounds.size.height - new_size.height) / 2.0,                    ),                    size: new_size,                }            }            ObjectFit::None => Bounds {                origin: bounds.origin,                size: image_size,            },        }    }} /// The CSS styling that can be applied to an element via the `Styled` trait#[derive(Clone, Refineable, Debug)]#[refineable(Debug)]pub struct Style {    /// What layout strategy should be used?    pub display: Display,     /// Should the element be painted on screen?    pub visibility: Visibility,     // Overflow properties    /// How children overflowing their container should affect layout    #[refineable]    pub overflow: Point<Overflow>,    /// How much space (in points) should be reserved for the scrollbars of `Overflow::Scroll` and `Overflow::Auto` nodes.    pub scrollbar_width: f32,    /// Whether both x and y axis should be scrollable at the same time.    pub allow_concurrent_scroll: bool,     // Position properties    /// What should the `position` value of this struct use as a base offset?    pub position: Position,    /// How should the position of this element be tweaked relative to the layout defined?    #[refineable]    pub inset: Edges<Length>,     // Size properties    /// Sets the initial size of the item    #[refineable]    pub size: Size<Length>,    /// Controls the minimum size of the item    #[refineable]    pub min_size: Size<Length>,    /// Controls the maximum size of the item    #[refineable]    pub max_size: Size<Length>,    /// Sets the preferred aspect ratio for the item. The ratio is calculated as width divided by height.    pub aspect_ratio: Option<f32>,     // Spacing Properties    /// How large should the margin be on each side?    #[refineable]    pub margin: Edges<Length>,    /// How large should the padding be on each side?    #[refineable]    pub padding: Edges<DefiniteLength>,    /// How large should the border be on each side?    #[refineable]    pub border_widths: Edges<AbsoluteLength>,     // Alignment properties    /// How this node's children aligned in the cross/block axis?    pub align_items: Option<AlignItems>,    /// How this node should be aligned in the cross/block axis. Falls back to the parents [`AlignItems`] if not set    pub align_self: Option<AlignSelf>,    /// How should content contained within this item be aligned in the cross/block axis    pub align_content: Option<AlignContent>,    /// How should contained within this item be aligned in the main/inline axis    pub justify_content: Option<JustifyContent>,    /// How large should the gaps between items in a flex container be?    #[refineable]    pub gap: Size<DefiniteLength>,     // Flexbox properties    /// Which direction does the main axis flow in?    pub flex_direction: FlexDirection,    /// Should elements wrap, or stay in a single line?    pub flex_wrap: FlexWrap,    /// Sets the initial main axis size of the item    pub flex_basis: Length,    /// The relative rate at which this item grows when it is expanding to fill space, 0.0 is the default value, and this value must be positive.    pub flex_grow: f32,    /// The relative rate at which this item shrinks when it is contracting to fit into space, 1.0 is the default value, and this value must be positive.    pub flex_shrink: f32,     /// The fill color of this element    pub background: Option<Fill>,     /// The border color of this element    pub border_color: Option<Hsla>,     /// The radius of the corners of this element    #[refineable]    pub corner_radii: Corners<AbsoluteLength>,     /// Box Shadow of the element    pub box_shadow: SmallVec<[BoxShadow; 2]>,     /// The text style of this element    pub text: TextStyleRefinement,     /// The mouse cursor style shown when the mouse pointer is over an element.    pub mouse_cursor: Option<CursorStyle>,     /// The opacity of this element    pub opacity: Option<f32>,     /// Whether to draw a red debugging outline around this element    #[cfg(debug_assertions)]    pub debug: bool,     /// Whether to draw a red debugging outline around this element and all of its conforming children    #[cfg(debug_assertions)]    pub debug_below: bool,} impl Styled for StyleRefinement {    fn style(&mut self) -> &mut StyleRefinement {        self    }} /// The value of the visibility property, similar to the CSS property `visibility`#[derive(Default, Clone, Copy, Debug, Eq, PartialEq)]pub enum Visibility {    /// The element should be drawn as normal.    #[default]    Visible,    /// The element should not be drawn, but should still take up space in the layout.    Hidden,} /// The possible values of the box-shadow property#[derive(Clone, Debug)]pub struct BoxShadow {    /// What color should the shadow have?    pub color: Hsla,    /// How should it be offset from its element?    pub offset: Point<Pixels>,    /// How much should the shadow be blurred?    pub blur_radius: Pixels,    /// How much should the shadow spread?    pub spread_radius: Pixels,} /// How to handle whitespace in text#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]pub enum WhiteSpace {    /// Normal line wrapping when text overflows the width of the element    #[default]    Normal,    /// No line wrapping, text will overflow the width of the element    Nowrap,} /// How to truncate text that overflows the width of the element#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]pub enum Truncate {    /// Truncate the text without an ellipsis    #[default]    Truncate,    /// Truncate the text with an ellipsis    Ellipsis,} /// The properties that can be used to style text in GPUI#[derive(Refineable, Clone, Debug, PartialEq)]#[refineable(Debug)]pub struct TextStyle {    /// The color of the text    pub color: Hsla,     /// The font family to use    pub font_family: SharedString,     /// The font features to use    pub font_features: FontFeatures,     /// The fallback fonts to use    pub font_fallbacks: Option<FontFallbacks>,     /// The font size to use, in pixels or rems.    pub font_size: AbsoluteLength,     /// The line height to use, in pixels or fractions    pub line_height: DefiniteLength,     /// The font weight, e.g. bold    pub font_weight: FontWeight,     /// The font style, e.g. italic    pub font_style: FontStyle,     /// The background color of the text    pub background_color: Option<Hsla>,     /// The underline style of the text    pub underline: Option<UnderlineStyle>,     /// The strikethrough style of the text    pub strikethrough: Option<StrikethroughStyle>,     /// How to handle whitespace in the text    pub white_space: WhiteSpace,     /// The text should be truncated if it overflows the width of the element    pub truncate: Option<Truncate>,} impl Default for TextStyle {    fn default() -> Self {        TextStyle {            color: black(),            // todo(linux) make this configurable or choose better default            font_family: if cfg!(any(target_os = "linux", target_os = "freebsd")) {                "FreeMono".into()            } else if cfg!(target_os = "windows") {                "Segoe UI".into()            } else {                "Helvetica".into()            },            font_features: FontFeatures::default(),            font_fallbacks: None,            font_size: rems(1.).into(),            line_height: phi(),            font_weight: FontWeight::default(),            font_style: FontStyle::default(),            background_color: None,            underline: None,            strikethrough: None,            white_space: WhiteSpace::Normal,            truncate: None,        }    }} impl TextStyle {    /// Create a new text style with the given highlighting applied.    pub fn highlight(mut self, style: impl Into<HighlightStyle>) -> Self {        let style = style.into();        if let Some(weight) = style.font_weight {            self.font_weight = weight;        }        if let Some(style) = style.font_style {            self.font_style = style;        }         if let Some(color) = style.color {            self.color = self.color.blend(color);        }         if let Some(factor) = style.fade_out {            self.color.fade_out(factor);        }         if let Some(background_color) = style.background_color {            self.background_color = Some(background_color);        }         if let Some(underline) = style.underline {            self.underline = Some(underline);        }         if let Some(strikethrough) = style.strikethrough {            self.strikethrough = Some(strikethrough);        }         self    }     /// Get the font configured for this text style.    pub fn font(&self) -> Font {        Font {            family: self.font_family.clone(),            features: self.font_features.clone(),            fallbacks: self.font_fallbacks.clone(),            weight: self.font_weight,            style: self.font_style,        }    }     /// Returns the rounded line height in pixels.    pub fn line_height_in_pixels(&self, rem_size: Pixels) -> Pixels {        self.line_height.to_pixels(self.font_size, rem_size).round()    }     /// Convert this text style into a [`TextRun`], for the given length of the text.    pub fn to_run(&self, len: usize) -> TextRun {        TextRun {            len,            font: Font {                family: self.font_family.clone(),                features: Default::default(),                fallbacks: self.font_fallbacks.clone(),                weight: self.font_weight,                style: self.font_style,            },            color: self.color,            background_color: self.background_color,            underline: self.underline,            strikethrough: self.strikethrough,        }    }} /// A highlight style to apply, similar to a `TextStyle` except/// for a single font, uniformly sized and spaced text.#[derive(Copy, Clone, Debug, Default, PartialEq)]pub struct HighlightStyle {    /// The color of the text    pub color: Option<Hsla>,     /// The font weight, e.g. bold    pub font_weight: Option<FontWeight>,     /// The font style, e.g. italic    pub font_style: Option<FontStyle>,     /// The background color of the text    pub background_color: Option<Hsla>,     /// The underline style of the text    pub underline: Option<UnderlineStyle>,     /// The underline style of the text    pub strikethrough: Option<StrikethroughStyle>,     /// Similar to the CSS `opacity` property, this will cause the text to be less vibrant.    pub fade_out: Option<f32>,} impl Eq for HighlightStyle {} impl Hash for HighlightStyle {    fn hash<H: Hasher>(&self, state: &mut H) {        self.color.hash(state);        self.font_weight.hash(state);        self.font_style.hash(state);        self.background_color.hash(state);        self.underline.hash(state);        self.strikethrough.hash(state);        state.write_u32(u32::from_be_bytes(            self.fade_out.map(|f| f.to_be_bytes()).unwrap_or_default(),        ));    }} impl Style {    /// Returns true if the style is visible and the background is opaque.    pub fn has_opaque_background(&self) -> bool {        self.background            .as_ref()            .is_some_and(|fill| fill.color().is_some_and(|color| !color.is_transparent()))    }     /// Get the text style in this element style.    pub fn text_style(&self) -> Option<&TextStyleRefinement> {        if self.text.is_some() {            Some(&self.text)        } else {            None        }    }     /// Get the content mask for this element style, based on the given bounds.    /// If the element does not hide its overflow, this will return `None`.    pub fn overflow_mask(

Lines 1–500 of 1032.