Skip to main content

GridTrack

Struct GridTrack 

Source
pub struct GridTrack { /* private fields */ }
Available on crate feature bevy_ui only.
Expand description

A GridTrack is a Row or Column of a CSS Grid. This struct specifies what size the track should be. See below for the different “track sizing functions” you can specify.

Implementations§

Source§

impl GridTrack

Source

pub const DEFAULT: GridTrack

Source

pub fn px<T>(value: f32) -> T
where T: From<GridTrack>,

Create a grid track with a fixed pixel size

Examples found in repository?
examples/testbed/ui.rs (line 1147)
1135    pub fn setup(mut commands: Commands) {
1136        commands.spawn((Camera2d, DespawnOnExit(super::Scene::Grid)));
1137        // Top-level grid (app frame)
1138        commands.spawn((
1139            Node {
1140                display: Display::Grid,
1141                width: percent(100),
1142                height: percent(100),
1143                grid_template_columns: vec![GridTrack::min_content(), GridTrack::flex(1.0)],
1144                grid_template_rows: vec![
1145                    GridTrack::auto(),
1146                    GridTrack::flex(1.0),
1147                    GridTrack::px(40.),
1148                ],
1149                ..default()
1150            },
1151            BackgroundColor(Color::WHITE),
1152            DespawnOnExit(super::Scene::Grid),
1153            children![
1154                // Header
1155                (
1156                    Node {
1157                        display: Display::Grid,
1158                        grid_column: GridPlacement::span(2),
1159                        padding: UiRect::all(px(40)),
1160                        ..default()
1161                    },
1162                    BackgroundColor(RED.into()),
1163                ),
1164                // Main content grid (auto placed in row 2, column 1)
1165                (
1166                    Node {
1167                        height: percent(100),
1168                        aspect_ratio: Some(1.0),
1169                        display: Display::Grid,
1170                        grid_template_columns: RepeatedGridTrack::flex(3, 1.0),
1171                        grid_template_rows: RepeatedGridTrack::flex(2, 1.0),
1172                        row_gap: px(12),
1173                        column_gap: px(12),
1174                        ..default()
1175                    },
1176                    BackgroundColor(Color::srgb(0.25, 0.25, 0.25)),
1177                    children![
1178                        (Node::default(), BackgroundColor(ORANGE.into())),
1179                        (Node::default(), BackgroundColor(BISQUE.into())),
1180                        (Node::default(), BackgroundColor(BLUE.into())),
1181                        (Node::default(), BackgroundColor(CRIMSON.into())),
1182                        (Node::default(), BackgroundColor(AQUA.into())),
1183                    ]
1184                ),
1185                // Right side bar (auto placed in row 2, column 2)
1186                (Node::DEFAULT, BackgroundColor(BLACK.into())),
1187            ],
1188        ));
1189    }
1190}
1191
1192mod borders {
1193    use bevy::{color::palettes::css::*, prelude::*};
1194
1195    pub fn setup(mut commands: Commands) {
1196        commands.spawn((Camera2d, DespawnOnExit(super::Scene::Borders)));
1197        let root = commands
1198            .spawn((
1199                Node {
1200                    flex_wrap: FlexWrap::Wrap,
1201                    ..default()
1202                },
1203                DespawnOnExit(super::Scene::Borders),
1204            ))
1205            .id();
1206
1207        // all the different combinations of border edges
1208        let borders = [
1209            UiRect::default(),
1210            UiRect::all(px(20)),
1211            UiRect::left(px(20)),
1212            UiRect::vertical(px(20)),
1213            UiRect {
1214                left: px(40),
1215                top: px(20),
1216                ..Default::default()
1217            },
1218            UiRect {
1219                right: px(20),
1220                bottom: px(30),
1221                ..Default::default()
1222            },
1223            UiRect {
1224                right: px(20),
1225                top: px(40),
1226                bottom: px(20),
1227                ..Default::default()
1228            },
1229            UiRect {
1230                left: px(20),
1231                top: px(20),
1232                bottom: px(20),
1233                ..Default::default()
1234            },
1235            UiRect {
1236                left: px(20),
1237                right: px(20),
1238                bottom: px(40),
1239                ..Default::default()
1240            },
1241        ];
1242
1243        let non_zero = |x, y| x != px(0) && y != px(0);
1244        let border_size = |x, y| if non_zero(x, y) { f32::MAX } else { 0. };
1245
1246        for border in borders {
1247            for rounded in [true, false] {
1248                let border_node = commands
1249                    .spawn((
1250                        Node {
1251                            width: px(100),
1252                            height: px(100),
1253                            border,
1254                            margin: UiRect::all(px(30)),
1255                            align_items: AlignItems::Center,
1256                            justify_content: JustifyContent::Center,
1257                            border_radius: if rounded {
1258                                BorderRadius::px(
1259                                    border_size(border.left, border.top),
1260                                    border_size(border.right, border.top),
1261                                    border_size(border.right, border.bottom),
1262                                    border_size(border.left, border.bottom),
1263                                )
1264                            } else {
1265                                BorderRadius::ZERO
1266                            },
1267                            ..default()
1268                        },
1269                        BackgroundColor(MAROON.into()),
1270                        BorderColor::all(RED),
1271                        Outline {
1272                            width: px(10),
1273                            offset: px(10),
1274                            color: Color::WHITE,
1275                        },
1276                    ))
1277                    .id();
1278
1279                commands.entity(root).add_child(border_node);
1280            }
1281        }
1282    }
1283}
1284
1285mod elliptical_border_radius {
1286    use bevy::{color::palettes::css::*, prelude::*};
1287
1288    pub fn setup(mut commands: Commands, assets: Res<AssetServer>) {
1289        commands.spawn((
1290            Camera2d,
1291            DespawnOnExit(super::Scene::EllipticalBorderRadius),
1292        ));
1293        commands
1294            .spawn((
1295                Node {
1296                    width: percent(100),
1297                    height: percent(100),
1298                    flex_wrap: FlexWrap::Wrap,
1299                    column_gap: px(40),
1300                    row_gap: px(40),
1301                    margin: auto().all(),
1302                    padding: px(30).all(),
1303                    ..default()
1304                },
1305                BackgroundColor(DARK_GRAY.into()),
1306                DespawnOnExit(super::Scene::EllipticalBorderRadius),
1307            ))
1308            .with_children(|builder| {
1309                builder.spawn((
1310                    Node {
1311                        width: px(200),
1312                        height: px(100),
1313                        border: UiRect::all(px(8)),
1314                        border_radius: BorderRadius::new(
1315                            CornerRadius {
1316                                x: px(90),
1317                                y: px(24),
1318                            },
1319                            CornerRadius {
1320                                x: px(18),
1321                                y: px(70),
1322                            },
1323                            CornerRadius {
1324                                x: px(110),
1325                                y: px(32),
1326                            },
1327                            CornerRadius {
1328                                x: px(28),
1329                                y: px(58),
1330                            },
1331                        ),
1332                        ..default()
1333                    },
1334                    BackgroundColor(ORANGE.into()),
1335                    BackgroundGradient::from(LinearGradient {
1336                        stops: vec![
1337                            RED.into(),
1338                            Color::BLACK.into(),
1339                            BLUE.into(),
1340                            WHEAT.into(),
1341                            GREEN.into(),
1342                        ],
1343                        ..default()
1344                    }),
1345                    BorderColor::all(RED),
1346                    Outline {
1347                        width: px(4),
1348                        offset: px(8),
1349                        color: WHITE.into(),
1350                    },
1351                    BoxShadow::from(ShadowStyle {
1352                        blur_radius: px(5),
1353                        ..default()
1354                    }),
1355                ));
1356
1357                builder.spawn((
1358                    Node {
1359                        width: px(150),
1360                        height: px(150),
1361                        border: UiRect {
1362                            left: px(16),
1363                            right: px(4),
1364                            top: px(24),
1365                            bottom: px(8),
1366                        },
1367                        border_radius: BorderRadius::new(
1368                            CornerRadius {
1369                                x: percent(65),
1370                                y: percent(20),
1371                            },
1372                            CornerRadius {
1373                                x: percent(20),
1374                                y: percent(65),
1375                            },
1376                            CornerRadius {
1377                                x: percent(65),
1378                                y: percent(20),
1379                            },
1380                            CornerRadius {
1381                                x: percent(20),
1382                                y: percent(65),
1383                            },
1384                        ),
1385                        ..default()
1386                    },
1387                    BackgroundColor(MEDIUM_SEA_GREEN.into()),
1388                    BorderColor::all(DARK_GREEN),
1389                    Outline {
1390                        width: px(3),
1391                        offset: px(10),
1392                        color: LIME.into(),
1393                    },
1394                    BoxShadow::from(ShadowStyle {
1395                        blur_radius: px(5),
1396                        ..default()
1397                    }),
1398                ));
1399
1400                builder.spawn((
1401                    Node {
1402                        width: px(210),
1403                        height: px(75),
1404                        border: UiRect::axes(px(12), px(4)),
1405                        border_radius: BorderRadius::new(
1406                            CornerRadius {
1407                                x: px(140),
1408                                y: px(18),
1409                            },
1410                            CornerRadius {
1411                                x: px(140),
1412                                y: px(18),
1413                            },
1414                            CornerRadius {
1415                                x: px(42),
1416                                y: px(54),
1417                            },
1418                            CornerRadius {
1419                                x: px(42),
1420                                y: px(54),
1421                            },
1422                        ),
1423                        ..default()
1424                    },
1425                    BackgroundColor(DODGER_BLUE.into()),
1426                    BorderColor::all(NAVY),
1427                    Outline {
1428                        width: px(5),
1429                        offset: px(6),
1430                        color: SKY_BLUE.into(),
1431                    },
1432                    BoxShadow::from(ShadowStyle {
1433                        blur_radius: px(5),
1434                        ..default()
1435                    }),
1436                ));
1437                builder.spawn((
1438                    Node {
1439                        width: px(160),
1440                        height: px(120),
1441                        border: UiRect::axes(px(20), px(20)),
1442                        border_radius: BorderRadius::new(
1443                            CornerRadius {
1444                                x: px(50),
1445                                y: px(10),
1446                            },
1447                            CornerRadius {
1448                                x: px(50),
1449                                y: px(10),
1450                            },
1451                            CornerRadius {
1452                                x: px(50),
1453                                y: px(10),
1454                            },
1455                            CornerRadius {
1456                                x: px(50),
1457                                y: px(10),
1458                            },
1459                        ),
1460                        ..default()
1461                    },
1462                    BackgroundColor(RED.into()),
1463                    BorderColor::all(WHITE),
1464                    Outline {
1465                        width: px(3),
1466                        offset: px(5),
1467                        color: SKY_BLUE.into(),
1468                    },
1469                    BoxShadow::from(ShadowStyle {
1470                        blur_radius: px(5),
1471                        ..default()
1472                    }),
1473                ));
1474
1475                builder.spawn((
1476                    Node {
1477                        width: px(160),
1478                        height: px(120),
1479                        border: UiRect::axes(px(20), px(20)),
1480                        border_radius: BorderRadius::all(px(1000)),
1481                        ..default()
1482                    },
1483                    BackgroundColor(RED.into()),
1484                    BorderColor::all(WHITE),
1485                    Outline {
1486                        width: px(3),
1487                        offset: px(5),
1488                        color: SKY_BLUE.into(),
1489                    },
1490                    BoxShadow::from(ShadowStyle {
1491                        blur_radius: px(5),
1492                        ..default()
1493                    }),
1494                ));
1495
1496                builder.spawn((
1497                    Node {
1498                        width: px(160),
1499                        height: px(120),
1500                        border: UiRect::axes(px(20), px(20)),
1501                        border_radius: BorderRadius {
1502                            top_left: CornerRadius {
1503                                x: px(1000),
1504                                y: auto(),
1505                            },
1506                            top_right: CornerRadius {
1507                                x: auto(),
1508                                y: px(1000),
1509                            },
1510                            bottom_right: CornerRadius::circular(px(1000)),
1511                            bottom_left: CornerRadius::circular(px(1000)),
1512                        },
1513                        ..default()
1514                    },
1515                    BackgroundColor(RED.into()),
1516                    BorderColor::all(WHITE),
1517                    Outline {
1518                        width: px(3),
1519                        offset: px(5),
1520                        color: SKY_BLUE.into(),
1521                    },
1522                    BoxShadow::from(ShadowStyle {
1523                        blur_radius: px(5),
1524                        ..default()
1525                    }),
1526                ));
1527
1528                builder.spawn((
1529                    Node {
1530                        width: px(160),
1531                        height: px(120),
1532                        border: UiRect::axes(px(20), px(20)),
1533                        border_radius: BorderRadius::new(
1534                            CornerRadius {
1535                                x: px(25),
1536                                y: px(20),
1537                            },
1538                            CornerRadius {
1539                                x: px(20),
1540                                y: px(25),
1541                            },
1542                            CornerRadius {
1543                                x: px(20),
1544                                y: px(25),
1545                            },
1546                            CornerRadius {
1547                                x: px(20),
1548                                y: px(25),
1549                            },
1550                        ),
1551                        ..default()
1552                    },
1553                    BackgroundColor(RED.into()),
1554                    ImageNode::from(assets.load("branding/icon.png")),
1555                    BorderColor::all(WHITE),
1556                    Outline {
1557                        width: px(3),
1558                        offset: px(5),
1559                        color: SKY_BLUE.into(),
1560                    },
1561                    BoxShadow::from(ShadowStyle {
1562                        blur_radius: px(5),
1563                        ..default()
1564                    }),
1565                ));
1566
1567                builder.spawn((
1568                    Node {
1569                        width: px(160),
1570                        height: px(120),
1571                        border: UiRect::axes(px(10), px(10)),
1572                        border_radius: BorderRadius::new(
1573                            CornerRadius {
1574                                x: px(40),
1575                                y: px(30),
1576                            },
1577                            CornerRadius {
1578                                x: px(40),
1579                                y: px(30),
1580                            },
1581                            CornerRadius {
1582                                x: px(40),
1583                                y: px(30),
1584                            },
1585                            CornerRadius {
1586                                x: px(40),
1587                                y: px(30),
1588                            },
1589                        ),
1590                        ..default()
1591                    },
1592                    BackgroundColor(RED.into()),
1593                    BorderColor::all(WHITE),
1594                    Outline {
1595                        width: px(3),
1596                        offset: px(5),
1597                        color: SKY_BLUE.into(),
1598                    },
1599                    BoxShadow::from(ShadowStyle {
1600                        blur_radius: px(5),
1601                        ..default()
1602                    }),
1603                ));
1604
1605                builder.spawn((
1606                    Node {
1607                        width: px(160),
1608                        height: px(80),
1609                        border: UiRect::axes(px(10), px(10)),
1610                        border_radius: BorderRadius::new(
1611                            CornerRadius {
1612                                x: percent(50),
1613                                y: percent(50),
1614                            },
1615                            CornerRadius {
1616                                x: percent(50),
1617                                y: percent(50),
1618                            },
1619                            CornerRadius {
1620                                x: percent(50),
1621                                y: percent(50),
1622                            },
1623                            CornerRadius {
1624                                x: percent(50),
1625                                y: percent(50),
1626                            },
1627                        ),
1628                        ..default()
1629                    },
1630                    BackgroundColor(RED.into()),
1631                    BorderColor::all(WHITE),
1632                    ImageNode::from(assets.load("branding/icon.png")),
1633                    Outline {
1634                        width: px(3),
1635                        offset: px(5),
1636                        color: SKY_BLUE.into(),
1637                    },
1638                    BoxShadow::from(ShadowStyle {
1639                        blur_radius: px(5),
1640                        ..default()
1641                    }),
1642                ));
1643
1644                builder.spawn((
1645                    Node {
1646                        width: px(80),
1647                        height: px(160),
1648                        border: UiRect::axes(px(10), px(10)),
1649                        border_radius: BorderRadius::new(
1650                            CornerRadius {
1651                                x: percent(50),
1652                                y: percent(50),
1653                            },
1654                            CornerRadius {
1655                                x: percent(50),
1656                                y: percent(50),
1657                            },
1658                            CornerRadius {
1659                                x: percent(50),
1660                                y: percent(50),
1661                            },
1662                            CornerRadius {
1663                                x: percent(50),
1664                                y: percent(50),
1665                            },
1666                        ),
1667                        ..default()
1668                    },
1669                    BackgroundColor(RED.into()),
1670                    BorderColor::all(WHITE),
1671                    ImageNode::from(assets.load("branding/icon.png")),
1672                    Outline {
1673                        width: px(3),
1674                        offset: px(5),
1675                        color: SKY_BLUE.into(),
1676                    },
1677                    BoxShadow::from(ShadowStyle {
1678                        blur_radius: px(5),
1679                        ..default()
1680                    }),
1681                ));
1682
1683                builder.spawn((
1684                    Node {
1685                        width: px(160),
1686                        height: px(80),
1687                        border: UiRect::axes(px(20), px(10)),
1688                        border_radius: BorderRadius::new(
1689                            CornerRadius {
1690                                x: percent(50),
1691                                y: percent(50),
1692                            },
1693                            CornerRadius {
1694                                x: percent(50),
1695                                y: percent(50),
1696                            },
1697                            CornerRadius {
1698                                x: percent(50),
1699                                y: percent(50),
1700                            },
1701                            CornerRadius {
1702                                x: percent(50),
1703                                y: percent(50),
1704                            },
1705                        ),
1706                        ..default()
1707                    },
1708                    BackgroundColor(RED.into()),
1709                    BorderColor::all(WHITE),
1710                    ImageNode::from(assets.load("branding/icon.png")),
1711                    Outline {
1712                        width: px(3),
1713                        offset: px(5),
1714                        color: SKY_BLUE.into(),
1715                    },
1716                    BoxShadow::from(ShadowStyle {
1717                        blur_radius: px(5),
1718                        ..default()
1719                    }),
1720                ));
1721
1722                builder.spawn((
1723                    Node {
1724                        width: px(80),
1725                        height: px(160),
1726                        border: UiRect::all(px(10)).with_right(px(25)),
1727                        border_radius: BorderRadius::new(
1728                            CornerRadius {
1729                                x: percent(50),
1730                                y: percent(50),
1731                            },
1732                            CornerRadius {
1733                                x: percent(50),
1734                                y: percent(50),
1735                            },
1736                            CornerRadius {
1737                                x: percent(50),
1738                                y: percent(50),
1739                            },
1740                            CornerRadius {
1741                                x: percent(50),
1742                                y: percent(50),
1743                            },
1744                        ),
1745                        ..default()
1746                    },
1747                    BackgroundColor(RED.into()),
1748                    BorderColor::all(WHITE),
1749                    Outline {
1750                        width: px(3),
1751                        offset: px(5),
1752                        color: SKY_BLUE.into(),
1753                    },
1754                    BoxShadow::from(ShadowStyle {
1755                        blur_radius: px(5),
1756                        ..default()
1757                    }),
1758                ));
1759
1760                builder.spawn((
1761                    Node {
1762                        width: px(160),
1763                        height: px(80),
1764                        border: UiRect::all(px(5)),
1765                        border_radius: BorderRadius::new(
1766                            CornerRadius {
1767                                x: percent(50),
1768                                y: percent(50),
1769                            },
1770                            CornerRadius {
1771                                x: percent(50),
1772                                y: percent(50),
1773                            },
1774                            CornerRadius {
1775                                x: percent(50),
1776                                y: percent(50),
1777                            },
1778                            CornerRadius {
1779                                x: px(20),
1780                                y: px(20),
1781                            },
1782                        ),
1783                        ..default()
1784                    },
1785                    BackgroundColor(RED.into()),
1786                    BorderColor::all(WHITE),
1787                    ImageNode::from(assets.load("branding/icon.png")),
1788                    Outline {
1789                        width: px(3),
1790                        offset: px(5),
1791                        color: SKY_BLUE.into(),
1792                    },
1793                    BoxShadow::from(ShadowStyle {
1794                        blur_radius: px(5),
1795                        ..default()
1796                    }),
1797                ));
1798            });
1799    }
1800}
1801
1802mod box_shadow {
1803    use bevy::{color::palettes::css::*, prelude::*};
1804
1805    pub fn setup(mut commands: Commands) {
1806        commands.spawn((Camera2d, DespawnOnExit(super::Scene::BoxShadow)));
1807
1808        commands
1809            .spawn((
1810                Node {
1811                    width: percent(100),
1812                    height: percent(100),
1813                    padding: UiRect::all(px(30)),
1814                    column_gap: px(200),
1815                    flex_wrap: FlexWrap::Wrap,
1816                    ..default()
1817                },
1818                BackgroundColor(GREEN.into()),
1819                DespawnOnExit(super::Scene::BoxShadow),
1820            ))
1821            .with_children(|commands| {
1822                let example_nodes = [
1823                    (
1824                        Vec2::splat(100.),
1825                        Vec2::ZERO,
1826                        10.,
1827                        0.,
1828                        BorderRadius::bottom_right(px(10)),
1829                    ),
1830                    (Vec2::new(200., 50.), Vec2::ZERO, 10., 0., BorderRadius::MAX),
1831                    (
1832                        Vec2::new(100., 50.),
1833                        Vec2::ZERO,
1834                        10.,
1835                        10.,
1836                        BorderRadius::ZERO,
1837                    ),
1838                    (
1839                        Vec2::splat(100.),
1840                        Vec2::splat(20.),
1841                        10.,
1842                        10.,
1843                        BorderRadius::bottom_right(px(10)),
1844                    ),
1845                    (
1846                        Vec2::splat(100.),
1847                        Vec2::splat(50.),
1848                        0.,
1849                        10.,
1850                        BorderRadius::ZERO,
1851                    ),
1852                    (
1853                        Vec2::new(50., 100.),
1854                        Vec2::splat(10.),
1855                        0.,
1856                        10.,
1857                        BorderRadius::MAX,
1858                    ),
1859                ];
1860
1861                for (size, offset, spread, blur, border_radius) in example_nodes {
1862                    commands.spawn((
1863                        Node {
1864                            width: px(size.x),
1865                            height: px(size.y),
1866                            border: UiRect::all(px(2)),
1867                            border_radius,
1868                            ..default()
1869                        },
1870                        BorderColor::all(WHITE),
1871                        BackgroundColor(BLUE.into()),
1872                        BoxShadow::new(
1873                            Color::BLACK.with_alpha(0.9),
1874                            percent(offset.x),
1875                            percent(offset.y),
1876                            percent(spread),
1877                            px(blur),
1878                        ),
1879                    ));
1880                }
1881            });
1882    }
1883}
1884
1885mod text_wrap {
1886    use bevy::prelude::*;
1887
1888    pub fn setup(mut commands: Commands) {
1889        commands.spawn((Camera2d, DespawnOnExit(super::Scene::TextWrap)));
1890
1891        let root = commands
1892            .spawn((
1893                Node {
1894                    flex_direction: FlexDirection::Column,
1895                    width: px(200),
1896                    height: percent(100),
1897                    overflow: Overflow::clip_x(),
1898                    ..default()
1899                },
1900                BackgroundColor(Color::BLACK),
1901                DespawnOnExit(super::Scene::TextWrap),
1902            ))
1903            .id();
1904
1905        for linebreak in [
1906            LineBreak::AnyCharacter,
1907            LineBreak::WordBoundary,
1908            LineBreak::WordOrCharacter,
1909            LineBreak::NoWrap,
1910        ] {
1911            let messages = [
1912                "Lorem ipsum dolor sit amet, consectetur adipiscing elit.".to_string(),
1913                "pneumonoultramicroscopicsilicovolcanoconiosis".to_string(),
1914            ];
1915
1916            for (j, message) in messages.into_iter().enumerate() {
1917                commands.entity(root).with_child((
1918                    Text(message.clone()),
1919                    TextLayout::new(Justify::Left, linebreak),
1920                    BackgroundColor(Color::srgb(0.8 - j as f32 * 0.3, 0., 0.)),
1921                ));
1922            }
1923        }
1924    }
1925}
1926
1927mod overflow {
1928    use bevy::{color::palettes::css::*, prelude::*};
1929
1930    pub fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
1931        commands.spawn((Camera2d, DespawnOnExit(super::Scene::Overflow)));
1932        let image = asset_server.load("branding/icon.png");
1933
1934        commands
1935            .spawn((
1936                Node {
1937                    width: percent(100),
1938                    height: percent(100),
1939                    align_items: AlignItems::Center,
1940                    justify_content: JustifyContent::SpaceAround,
1941                    ..Default::default()
1942                },
1943                BackgroundColor(BLUE.into()),
1944                DespawnOnExit(super::Scene::Overflow),
1945            ))
1946            .with_children(|parent| {
1947                for overflow in [
1948                    Overflow::visible(),
1949                    Overflow::clip_x(),
1950                    Overflow::clip_y(),
1951                    Overflow::clip(),
1952                ] {
1953                    parent
1954                        .spawn((
1955                            Node {
1956                                width: px(100),
1957                                height: px(100),
1958                                padding: UiRect {
1959                                    left: px(25),
1960                                    top: px(25),
1961                                    ..Default::default()
1962                                },
1963                                border: UiRect::all(px(5)),
1964                                overflow,
1965                                ..default()
1966                            },
1967                            BorderColor::all(RED),
1968                            BackgroundColor(Color::WHITE),
1969                        ))
1970                        .with_children(|parent| {
1971                            parent.spawn((
1972                                ImageNode::new(image.clone()),
1973                                Node {
1974                                    min_width: px(100),
1975                                    min_height: px(100),
1976                                    ..default()
1977                                },
1978                                Outline {
1979                                    width: px(2),
1980                                    offset: px(2),
1981                                    color: Color::NONE,
1982                                },
1983                            ));
1984                        });
1985                }
1986            });
1987    }
1988}
1989
1990mod slice {
1991    use bevy::prelude::*;
1992
1993    pub fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
1994        commands.spawn((Camera2d, DespawnOnExit(super::Scene::Slice)));
1995        let image = asset_server.load("textures/fantasy_ui_borders/numbered_slices.png");
1996
1997        let slicer = TextureSlicer {
1998            border: BorderRect::all(16.0),
1999            center_scale_mode: SliceScaleMode::Tile { stretch_value: 1.0 },
2000            sides_scale_mode: SliceScaleMode::Tile { stretch_value: 1.0 },
2001            ..default()
2002        };
2003        commands
2004            .spawn((
2005                Node {
2006                    width: percent(100),
2007                    height: percent(100),
2008                    flex_direction: FlexDirection::Column,
2009                    justify_content: JustifyContent::SpaceAround,
2010                    align_content: AlignContent::Center,
2011                    ..default()
2012                },
2013                DespawnOnExit(super::Scene::Slice),
2014            ))
2015            .with_children(|parent| {
2016                for visual_box in [
2017                    VisualBox::BorderBox,
2018                    VisualBox::PaddingBox,
2019                    VisualBox::ContentBox,
2020                ] {
2021                    parent
2022                        .spawn(Node {
2023                            justify_content: JustifyContent::SpaceAround,
2024                            ..default()
2025                        })
2026                        .with_children(|parent| {
2027                            for [w, h] in [[200.0, 200.0], [300.0, 200.0], [150., 200.0]] {
2028                                parent.spawn((
2029                                    ImageNode {
2030                                        image: image.clone(),
2031                                        image_mode: NodeImageMode::Sliced(slicer.clone()),
2032                                        visual_box,
2033                                        ..default()
2034                                    },
2035                                    Node {
2036                                        width: px(w),
2037                                        height: px(h),
2038                                        border: px(20.).all(),
2039                                        padding: px(20.).all(),
2040                                        ..default()
2041                                    },
2042                                    Outline {
2043                                        width: px(2.),
2044                                        ..default()
2045                                    },
2046                                ));
2047                            }
2048
2049                            parent.spawn((
2050                                ImageNode {
2051                                    image: asset_server
2052                                        .load("textures/fantasy_ui_borders/panel-border-010.png"),
2053                                    image_mode: NodeImageMode::Sliced(TextureSlicer {
2054                                        border: BorderRect::all(22.0),
2055                                        center_scale_mode: SliceScaleMode::Stretch,
2056                                        sides_scale_mode: SliceScaleMode::Stretch,
2057                                        max_corner_scale: 1.0,
2058                                    }),
2059                                    visual_box,
2060                                    ..Default::default()
2061                                },
2062                                Node {
2063                                    width: px(200),
2064                                    height: px(200),
2065                                    border: px(20.).all(),
2066                                    padding: px(20.).all(),
2067                                    ..default()
2068                                },
2069                                Outline {
2070                                    color: bevy::color::palettes::css::DARK_CYAN.into(),
2071                                    width: px(2.),
2072                                    ..default()
2073                                },
2074                                BackgroundColor(bevy::color::palettes::css::NAVY.into()),
2075                            ));
2076                        });
2077                }
2078            });
2079    }
2080}
2081
2082mod layout_rounding {
2083    use bevy::{color::palettes::css::*, prelude::*};
2084
2085    pub fn setup(mut commands: Commands) {
2086        commands.spawn((Camera2d, DespawnOnExit(super::Scene::LayoutRounding)));
2087
2088        commands
2089            .spawn((
2090                Node {
2091                    display: Display::Grid,
2092                    width: percent(100),
2093                    height: percent(100),
2094                    grid_template_rows: vec![RepeatedGridTrack::fr(10, 1.)],
2095                    ..Default::default()
2096                },
2097                BackgroundColor(Color::WHITE),
2098                DespawnOnExit(super::Scene::LayoutRounding),
2099            ))
2100            .with_children(|commands| {
2101                for i in 2..12 {
2102                    commands
2103                        .spawn(Node {
2104                            display: Display::Grid,
2105                            grid_template_columns: vec![RepeatedGridTrack::fr(i, 1.)],
2106                            ..Default::default()
2107                        })
2108                        .with_children(|commands| {
2109                            for _ in 0..i {
2110                                commands.spawn((
2111                                    Node {
2112                                        border: UiRect::all(px(5)),
2113                                        ..Default::default()
2114                                    },
2115                                    BackgroundColor(MAROON.into()),
2116                                    BorderColor::all(DARK_BLUE),
2117                                ));
2118                            }
2119                        });
2120                }
2121            });
2122    }
2123}
2124
2125mod linear_gradient {
2126    use bevy::camera::Camera2d;
2127    use bevy::color::palettes::css::BLUE;
2128    use bevy::color::palettes::css::LIME;
2129    use bevy::color::palettes::css::RED;
2130    use bevy::color::palettes::css::YELLOW;
2131    use bevy::color::Color;
2132    use bevy::ecs::prelude::*;
2133    use bevy::state::state_scoped::DespawnOnExit;
2134    use bevy::text::TextFont;
2135    use bevy::ui::widget::Text;
2136    use bevy::ui::AlignItems;
2137    use bevy::ui::BackgroundGradient;
2138    use bevy::ui::ColorStop;
2139    use bevy::ui::GridPlacement;
2140    use bevy::ui::InterpolationColorSpace;
2141    use bevy::ui::JustifyContent;
2142    use bevy::ui::LinearGradient;
2143    use bevy::ui::Node;
2144    use bevy::ui::PositionType;
2145    use bevy::utils::default;
2146
2147    pub fn setup(mut commands: Commands) {
2148        commands.spawn((Camera2d, DespawnOnExit(super::Scene::LinearGradient)));
2149        commands
2150            .spawn((
2151                Node {
2152                    flex_direction: bevy::ui::FlexDirection::Column,
2153                    width: bevy::ui::percent(100),
2154                    height: bevy::ui::percent(100),
2155                    justify_content: JustifyContent::Center,
2156                    align_items: AlignItems::Center,
2157                    row_gap: bevy::ui::px(5),
2158                    ..default()
2159                },
2160                DespawnOnExit(super::Scene::LinearGradient),
2161            ))
2162            .with_children(|commands| {
2163                let mut i = 0;
2164                commands
2165                    .spawn(Node {
2166                        display: bevy::ui::Display::Grid,
2167                        row_gap: bevy::ui::px(4),
2168                        column_gap: bevy::ui::px(4),
2169                        ..Default::default()
2170                    })
2171                    .with_children(|commands| {
2172                        for stops in [
2173                            vec![ColorStop::auto(RED), ColorStop::auto(YELLOW)],
2174                            vec![
2175                                ColorStop::auto(Color::BLACK),
2176                                ColorStop::auto(RED),
2177                                ColorStop::auto(Color::WHITE),
2178                            ],
2179                            vec![
2180                                Color::hsl(180.71191, 0.0, 0.3137255).into(),
2181                                Color::hsl(180.71191, 0.5, 0.3137255).into(),
2182                                Color::hsl(180.71191, 1.0, 0.3137255).into(),
2183                            ],
2184                            vec![
2185                                Color::hsl(180.71191, 0.825, 0.0).into(),
2186                                Color::hsl(180.71191, 0.825, 0.5).into(),
2187                                Color::hsl(180.71191, 0.825, 1.0).into(),
2188                            ],
2189                            vec![
2190                                Color::hsl(0.0 + 0.0001, 1.0, 0.5).into(),
2191                                Color::hsl(180.0, 1.0, 0.5).into(),
2192                                Color::hsl(360.0 - 0.0001, 1.0, 0.5).into(),
2193                            ],
2194                            vec![
2195                                Color::WHITE.into(),
2196                                RED.into(),
2197                                LIME.into(),
2198                                BLUE.into(),
2199                                Color::BLACK.into(),
2200                            ],
2201                        ] {
2202                            for color_space in [
2203                                InterpolationColorSpace::LinearRgba,
2204                                InterpolationColorSpace::Srgba,
2205                                InterpolationColorSpace::Oklaba,
2206                                InterpolationColorSpace::Oklcha,
2207                                InterpolationColorSpace::OklchaLong,
2208                                InterpolationColorSpace::Hsla,
2209                                InterpolationColorSpace::HslaLong,
2210                                InterpolationColorSpace::Hsva,
2211                                InterpolationColorSpace::HsvaLong,
2212                            ] {
2213                                let row = i % 18 + 1;
2214                                let column = i / 18 + 1;
2215                                i += 1;
2216
2217                                commands.spawn((
2218                                    Node {
2219                                        grid_row: GridPlacement::start(row as i16 + 1),
2220                                        grid_column: GridPlacement::start(column as i16 + 1),
2221                                        justify_content: JustifyContent::SpaceEvenly,
2222                                        ..Default::default()
2223                                    },
2224                                    children![(
2225                                        Node {
2226                                            height: bevy::ui::px(30),
2227                                            width: bevy::ui::px(300),
2228                                            justify_content: JustifyContent::Center,
2229                                            ..Default::default()
2230                                        },
2231                                        BackgroundGradient::from(LinearGradient {
2232                                            color_space,
2233                                            angle: LinearGradient::TO_RIGHT,
2234                                            stops: stops.clone(),
2235                                        }),
2236                                        children![
2237                                            Node {
2238                                                position_type: PositionType::Absolute,
2239                                                ..default()
2240                                            },
2241                                            TextFont::from_font_size(10.),
2242                                            Text(format!("{color_space:?}")),
2243                                        ]
2244                                    )],
2245                                ));
2246                            }
2247                        }
2248                    });
2249            });
2250    }
2251}
2252
2253mod radial_gradient {
2254    use bevy::color::palettes::css::RED;
2255    use bevy::color::palettes::tailwind::GRAY_700;
2256    use bevy::prelude::*;
2257    use bevy::ui::ColorStop;
2258
2259    const CELL_SIZE: f32 = 80.;
2260    const GAP: f32 = 10.;
2261
2262    pub fn setup(mut commands: Commands) {
2263        let color_stops = vec![
2264            ColorStop::new(Color::BLACK, px(5)),
2265            ColorStop::new(Color::WHITE, px(5)),
2266            ColorStop::new(Color::WHITE, percent(100)),
2267            ColorStop::auto(RED),
2268        ];
2269
2270        commands.spawn((Camera2d, DespawnOnExit(super::Scene::RadialGradient)));
2271        commands
2272            .spawn((
2273                Node {
2274                    width: percent(100),
2275                    height: percent(100),
2276                    display: Display::Grid,
2277                    align_items: AlignItems::Start,
2278                    grid_template_columns: vec![RepeatedGridTrack::px(
2279                        GridTrackRepetition::AutoFill,
2280                        CELL_SIZE,
2281                    )],
2282                    grid_auto_flow: GridAutoFlow::Row,
2283                    row_gap: px(GAP),
2284                    column_gap: px(GAP),
2285                    padding: UiRect::all(px(GAP)),
2286                    ..default()
2287                },
2288                DespawnOnExit(super::Scene::RadialGradient),
2289            ))
2290            .with_children(|commands| {
2291                for (shape, shape_label) in [
2292                    (RadialGradientShape::ClosestSide, "ClosestSide"),
2293                    (RadialGradientShape::FarthestSide, "FarthestSide"),
2294                    (RadialGradientShape::Circle(percent(55)), "Circle(55%)"),
2295                    (RadialGradientShape::FarthestCorner, "FarthestCorner"),
2296                ] {
2297                    for (position, position_label) in [
2298                        (UiPosition::TOP_LEFT, "TOP_LEFT"),
2299                        (UiPosition::LEFT, "LEFT"),
2300                        (UiPosition::BOTTOM_LEFT, "BOTTOM_LEFT"),
2301                        (UiPosition::TOP, "TOP"),
2302                        (UiPosition::CENTER, "CENTER"),
2303                        (UiPosition::BOTTOM, "BOTTOM"),
2304                        (UiPosition::TOP_RIGHT, "TOP_RIGHT"),
2305                        (UiPosition::RIGHT, "RIGHT"),
2306                        (UiPosition::BOTTOM_RIGHT, "BOTTOM_RIGHT"),
2307                    ] {
2308                        for (w, h) in [(CELL_SIZE, CELL_SIZE), (CELL_SIZE, CELL_SIZE / 2.)] {
2309                            commands
2310                                .spawn((
2311                                    BackgroundColor(GRAY_700.into()),
2312                                    Node {
2313                                        display: Display::Grid,
2314                                        width: px(CELL_SIZE),
2315                                        ..Default::default()
2316                                    },
2317                                ))
2318                                .with_children(|commands| {
2319                                    commands.spawn((
2320                                        Node {
2321                                            margin: UiRect::all(px(2)),
2322                                            ..default()
2323                                        },
2324                                        Text(format!("{shape_label}\n{position_label}")),
2325                                        TextFont::from_font_size(9.),
2326                                    ));
2327                                    commands.spawn((
2328                                        Node {
2329                                            width: px(w),
2330                                            height: px(h),
2331                                            ..default()
2332                                        },
2333                                        BackgroundGradient::from(RadialGradient {
2334                                            stops: color_stops.clone(),
2335                                            position,
2336                                            shape,
2337                                            ..default()
2338                                        }),
2339                                    ));
2340                                });
2341                        }
2342                    }
2343                }
2344            });
2345    }
2346}
2347
2348mod transformations {
2349    use bevy::{color::palettes::css::*, prelude::*};
2350
2351    pub fn setup(mut commands: Commands) {
2352        commands.spawn((Camera2d, DespawnOnExit(super::Scene::Transformations)));
2353        commands
2354            .spawn((
2355                Node {
2356                    width: percent(100),
2357                    height: percent(100),
2358                    display: Display::Block,
2359                    ..default()
2360                },
2361                DespawnOnExit(super::Scene::Transformations),
2362            ))
2363            .with_children(|parent| {
2364                for (transformation, label, background) in [
2365                    (
2366                        UiTransform::from_rotation(Rot2::degrees(45.)),
2367                        "Rotate 45 degrees",
2368                        RED,
2369                    ),
2370                    (
2371                        UiTransform::from_scale(Vec2::new(2., 0.5)),
2372                        "Scale 2.x 0.5y",
2373                        GREEN,
2374                    ),
2375                    (
2376                        UiTransform::from_translation(Val2::px(-50., 50.)),
2377                        "Translate -50px x +50px y",
2378                        BLUE,
2379                    ),
2380                    (
2381                        UiTransform {
2382                            translation: Val2::px(50., 0.),
2383                            scale: Vec2::new(-1., 1.),
2384                            rotation: Rot2::degrees(30.),
2385                        },
2386                        "T 50px x\nS -1.x (refl)\nR 30deg",
2387                        DARK_CYAN,
2388                    ),
2389                ] {
2390                    parent
2391                        .spawn((Node {
2392                            width: percent(100),
2393                            margin: UiRect {
2394                                top: px(50),
2395                                bottom: px(50),
2396                                ..default()
2397                            },
2398                            align_items: AlignItems::Center,
2399                            justify_content: JustifyContent::SpaceAround,
2400                            ..default()
2401                        },))
2402                        .with_children(|row| {
2403                            row.spawn((
2404                                Text::new("Before Tf"),
2405                                Node {
2406                                    width: px(100),
2407                                    height: px(100),
2408                                    border_radius: BorderRadius::bottom_right(px(25.)),
2409                                    ..default()
2410                                },
2411                                BackgroundColor(background.into()),
2412                                TextFont::default(),
2413                            ));
2414                            row.spawn((
2415                                Text::new(label),
2416                                Node {
2417                                    width: px(100),
2418                                    height: px(100),
2419                                    border_radius: BorderRadius::bottom_right(px(25.)),
2420                                    ..default()
2421                                },
2422                                BackgroundColor(background.into()),
2423                                transformation,
2424                                TextFont::default(),
2425                            ));
2426                        });
2427                }
2428            });
2429    }
2430}
2431
2432#[cfg(feature = "bevy_ui_debug")]
2433mod debug_outlines {
2434    use bevy::{
2435        color::palettes::css::{BLUE, GRAY, RED},
2436        prelude::*,
2437        ui_render::UiDebugOptions,
2438    };
2439
2440    pub fn setup(mut commands: Commands, mut debug_options: ResMut<GlobalUiDebugOptions>) {
2441        debug_options.enabled = true;
2442        debug_options.line_width = 5.;
2443        debug_options.line_color_override = Some(LinearRgba::GREEN);
2444        debug_options.show_hidden = true;
2445        debug_options.show_clipped = true;
2446
2447        let debug_options: UiDebugOptions = (*debug_options.as_ref()).into();
2448
2449        commands.spawn((Camera2d, DespawnOnExit(super::Scene::DebugOutlines)));
2450        commands
2451            .spawn((
2452                Node {
2453                    width: percent(100),
2454                    height: percent(50),
2455                    align_items: AlignItems::Center,
2456                    justify_content: JustifyContent::SpaceAround,
2457                    ..default()
2458                },
2459                DespawnOnExit(super::Scene::DebugOutlines),
2460            ))
2461            .with_children(|parent| {
2462                parent.spawn((
2463                    Node {
2464                        width: px(100),
2465                        height: px(100),
2466                        ..default()
2467                    },
2468                    BackgroundColor(GRAY.into()),
2469                    UiTransform::from_rotation(Rot2::degrees(45.)),
2470                ));
2471
2472                parent.spawn((Text::new("Regular Text"), TextFont::default()));
2473
2474                parent.spawn((
2475                    Node {
2476                        width: px(100),
2477                        height: px(100),
2478                        ..default()
2479                    },
2480                    Text::new("Invisible"),
2481                    BackgroundColor(GRAY.into()),
2482                    TextFont::default(),
2483                    Visibility::Hidden,
2484                ));
2485
2486                parent
2487                    .spawn((
2488                        Node {
2489                            width: px(100),
2490                            height: px(100),
2491                            padding: UiRect {
2492                                left: px(25),
2493                                top: px(25),
2494                                ..Default::default()
2495                            },
2496                            overflow: Overflow::clip(),
2497                            ..default()
2498                        },
2499                        BackgroundColor(RED.into()),
2500                    ))
2501                    .with_children(|child| {
2502                        child.spawn((
2503                            Node {
2504                                min_width: px(100),
2505                                min_height: px(100),
2506                                ..default()
2507                            },
2508                            BackgroundColor(BLUE.into()),
2509                        ));
2510                    });
2511            });
2512
2513        commands
2514            .spawn((
2515                Node {
2516                    width: percent(100),
2517                    height: percent(50),
2518                    top: percent(50),
2519                    align_items: AlignItems::Center,
2520                    justify_content: JustifyContent::SpaceAround,
2521                    ..default()
2522                },
2523                DespawnOnExit(super::Scene::DebugOutlines),
2524            ))
2525            .with_children(|parent| {
2526                parent.spawn((
2527                    Node {
2528                        width: px(200),
2529                        height: px(200),
2530                        border: UiRect {
2531                            top: px(10),
2532                            bottom: px(20),
2533                            left: px(30),
2534                            right: px(40),
2535                        },
2536                        border_radius: BorderRadius::bottom_right(px(10)),
2537                        padding: UiRect {
2538                            top: px(40),
2539                            bottom: px(30),
2540                            left: px(20),
2541                            right: px(10),
2542                        },
2543                        ..default()
2544                    },
2545                    children![(
2546                        Text::new("border padding content outlines"),
2547                        TextFont::default(),
2548                        UiDebugOptions {
2549                            enabled: false,
2550                            ..default()
2551                        }
2552                    )],
2553                    UiDebugOptions {
2554                        outline_border_box: true,
2555                        outline_padding_box: true,
2556                        outline_content_box: true,
2557                        ignore_border_radius: false,
2558                        ..debug_options
2559                    },
2560                ));
2561
2562                // Vertical scrollbar (non-functional)
2563                parent.spawn((
2564                    Node {
2565                        flex_direction: FlexDirection::Column,
2566                        width: px(90),
2567                        height: px(230),
2568                        overflow: Overflow::scroll_y(),
2569                        scrollbar_width: 20.,
2570                        ..default()
2571                    },
2572                    ScrollPosition(Vec2::new(180., 180.)),
2573                    UiDebugOptions {
2574                        line_width: 3.,
2575                        outline_scrollbars: true,
2576                        show_hidden: false,
2577                        show_clipped: false,
2578                        ..debug_options
2579                    },
2580                    Children::spawn(SpawnIter((0..20).map(move |i| {
2581                        (
2582                            Node::default(),
2583                            children![(
2584                                Text(format!("Item {i}")),
2585                                UiDebugOptions {
2586                                    enabled: false,
2587                                    ..default()
2588                                }
2589                            )],
2590                            UiDebugOptions {
2591                                enabled: false,
2592                                ..default()
2593                            },
2594                        )
2595                    }))),
2596                ));
2597
2598                // Horizontal scrollbar (non-functional)
2599                parent.spawn((
2600                    Node {
2601                        flex_direction: FlexDirection::Row,
2602                        width: px(156),
2603                        height: px(70),
2604                        overflow: Overflow::scroll_x(),
2605                        scrollbar_width: 10.,
2606                        ..default()
2607                    },
2608                    UiDebugOptions {
2609                        line_width: 3.,
2610                        outline_scrollbars: true,
2611                        show_hidden: false,
2612                        show_clipped: false,
2613                        ..debug_options
2614                    },
2615                    Children::spawn(SpawnIter((0..20).map(move |i| {
2616                        (
2617                            Node::default(),
2618                            children![(
2619                                Text(format!("Item {i}")),
2620                                UiDebugOptions {
2621                                    enabled: false,
2622                                    ..default()
2623                                }
2624                            )],
2625                            UiDebugOptions {
2626                                enabled: false,
2627                                ..default()
2628                            },
2629                        )
2630                    }))),
2631                ));
2632
2633                // bi-directional scrollbar (non-functional)
2634                parent.spawn((
2635                    Node {
2636                        flex_direction: FlexDirection::Column,
2637                        width: px(230),
2638                        height: px(125),
2639                        overflow: Overflow::scroll(),
2640                        scrollbar_width: 20.,
2641                        ..default()
2642                    },
2643                    ScrollPosition(Vec2::new(300., 0.)),
2644                    UiDebugOptions {
2645                        line_width: 3.,
2646                        outline_scrollbars: true,
2647                        show_hidden: false,
2648                        show_clipped: false,
2649                        ..debug_options
2650                    },
2651                    Children::spawn(SpawnIter((0..6).map(move |i| {
2652                        (
2653                            Node {
2654                                flex_direction: FlexDirection::Row,
2655                                ..default()
2656                            },
2657                            Children::spawn(SpawnIter((0..6).map({
2658                                move |j| {
2659                                    (
2660                                        Text(format!("Item {}", (i * 5) + j)),
2661                                        UiDebugOptions {
2662                                            enabled: false,
2663                                            ..default()
2664                                        },
2665                                    )
2666                                }
2667                            }))),
2668                            UiDebugOptions {
2669                                enabled: false,
2670                                ..default()
2671                            },
2672                        )
2673                    }))),
2674                ));
2675            });
2676    }
2677
2678    pub fn teardown(mut debug_options: ResMut<GlobalUiDebugOptions>) {
2679        *debug_options = GlobalUiDebugOptions::default();
2680    }
2681}
2682
2683mod viewport_coords {
2684    use bevy::{color::palettes::css::*, prelude::*};
2685
2686    const PALETTE: [Srgba; 9] = [RED, WHITE, BEIGE, AQUA, CRIMSON, NAVY, AZURE, LIME, BLACK];
2687
2688    pub fn setup(mut commands: Commands) {
2689        commands.spawn((Camera2d, DespawnOnExit(super::Scene::ViewportCoords)));
2690        commands
2691            .spawn((
2692                Node {
2693                    width: vw(100),
2694                    height: vh(100),
2695                    border: UiRect::axes(vw(5), vh(5)),
2696                    flex_wrap: FlexWrap::Wrap,
2697                    ..default()
2698                },
2699                BorderColor::all(PALETTE[0]),
2700                DespawnOnExit(super::Scene::ViewportCoords),
2701            ))
2702            .with_children(|builder| {
2703                builder.spawn((
2704                    Node {
2705                        width: vw(30),
2706                        height: vh(30),
2707                        border: UiRect::all(vmin(5)),
2708                        ..default()
2709                    },
2710                    BackgroundColor(PALETTE[1].into()),
2711                    BorderColor::all(PALETTE[8]),
2712                ));
2713
2714                builder.spawn((
2715                    Node {
2716                        width: vw(60),
2717                        height: vh(30),
2718                        ..default()
2719                    },
2720                    BackgroundColor(PALETTE[2].into()),
2721                ));
2722
2723                builder.spawn((
2724                    Node {
2725                        width: vw(45),
2726                        height: vh(30),
2727                        border: UiRect::left(vmax(45. / 2.)),
2728                        ..default()
2729                    },
2730                    BackgroundColor(PALETTE[3].into()),
2731                    BorderColor::all(PALETTE[7]),
2732                ));
2733
2734                builder.spawn((
2735                    Node {
2736                        width: vw(45),
2737                        height: vh(30),
2738                        border: UiRect::right(vmax(45. / 2.)),
2739                        ..default()
2740                    },
2741                    BackgroundColor(PALETTE[4].into()),
2742                    BorderColor::all(PALETTE[7]),
2743                ));
2744
2745                builder.spawn((
2746                    Node {
2747                        width: vw(60),
2748                        height: vh(30),
2749                        ..default()
2750                    },
2751                    BackgroundColor(PALETTE[5].into()),
2752                ));
2753
2754                builder.spawn((
2755                    Node {
2756                        width: vw(30),
2757                        height: vh(30),
2758                        border: UiRect::all(vmin(5)),
2759                        ..default()
2760                    },
2761                    BackgroundColor(PALETTE[6].into()),
2762                    BorderColor::all(PALETTE[8]),
2763                ));
2764            });
2765    }
2766}
2767
2768mod viewport_node {
2769    use bevy::{
2770        camera::RenderTarget, prelude::*, render::render_resource::TextureFormat,
2771        ui::widget::ViewportNode,
2772    };
2773
2774    pub fn setup(
2775        mut commands: Commands,
2776        mut images: ResMut<Assets<Image>>,
2777        mut meshes: ResMut<Assets<Mesh>>,
2778        mut materials: ResMut<Assets<StandardMaterial>>,
2779    ) {
2780        commands.spawn((
2781            Camera3d::default(),
2782            DespawnOnExit(super::Scene::ViewportNode),
2783        ));
2784
2785        let image = Image::new_target_texture(0, 0, TextureFormat::Bgra8UnormSrgb, None);
2786        let image_handle = images.add(image);
2787
2788        let camera = commands
2789            .spawn((
2790                Camera3d::default(),
2791                Camera {
2792                    order: -1,
2793                    ..default()
2794                },
2795                RenderTarget::Image(image_handle.into()),
2796                DespawnOnExit(super::Scene::ViewportNode),
2797            ))
2798            .id();
2799
2800        commands.spawn((
2801            Mesh3d(meshes.add(Cuboid::new(5.0, 5.0, 5.0))),
2802            MeshMaterial3d(materials.add(Color::WHITE)),
2803            Transform {
2804                translation: Vec3::new(0.0, 0.0, -10.0),
2805                rotation: Quat::from_euler(EulerRot::XYZ, 0.4, 0.7, 0.1),
2806                ..default()
2807            },
2808            DespawnOnExit(super::Scene::ViewportNode),
2809        ));
2810
2811        commands.spawn((
2812            Node {
2813                position_type: PositionType::Absolute,
2814                top: px(50),
2815                left: px(50),
2816                width: px(200),
2817                height: px(200),
2818                border: UiRect::all(px(5)),
2819                ..default()
2820            },
2821            BorderColor::all(Color::WHITE),
2822            ViewportNode::new(camera),
2823            DespawnOnExit(super::Scene::ViewportNode),
2824        ));
2825    }
2826}
2827
2828mod outer_color {
2829    use bevy::prelude::*;
2830
2831    pub fn setup(mut commands: Commands) {
2832        let radius = CornerRadius::from(percent(33.));
2833        let width = px(10.);
2834
2835        commands.spawn((Camera2d, DespawnOnExit(super::Scene::OuterColor)));
2836        commands
2837            .spawn((
2838                Node {
2839                    display: Display::Grid,
2840                    grid_template_columns: RepeatedGridTrack::px(3, 200.),
2841                    grid_template_rows: RepeatedGridTrack::px(3, 200.),
2842                    margin: UiRect::AUTO,
2843                    ..default()
2844                },
2845                DespawnOnExit(super::Scene::OuterColor),
2846            ))
2847            .with_children(|builder| {
2848                for (border, border_radius, invert) in [
2849                    (UiRect::ZERO, BorderRadius::bottom_right(radius), true),
2850                    (UiRect::top(width), BorderRadius::top(radius), false),
2851                    (UiRect::ZERO, BorderRadius::bottom_left(radius), true),
2852                    (UiRect::left(width), BorderRadius::left(radius), false),
2853                    (UiRect::all(width), BorderRadius::all(radius.x), true),
2854                    (UiRect::right(width), BorderRadius::right(radius), false),
2855                    (UiRect::ZERO, BorderRadius::top_right(radius), true),
2856                    (UiRect::bottom(width), BorderRadius::bottom(radius), false),
2857                    (UiRect::ZERO, BorderRadius::top_left(radius), true),
2858                ] {
2859                    builder
2860                        .spawn((
2861                            Node {
2862                                width: px(200.),
2863                                height: px(200.),
2864                                border_radius,
2865                                border,
2866                                ..default()
2867                            },
2868                            BorderColor::all(bevy::color::palettes::css::RED),
2869                        ))
2870                        .insert_if(BackgroundColor(Color::WHITE), || !invert)
2871                        .insert_if(OuterColor(Color::WHITE), || invert);
2872                }
2873            });
2874    }
2875}
2876
2877mod boxed_content {
2878    use bevy::color::palettes::css::RED;
2879    use bevy::prelude::*;
2880
2881    pub fn setup(mut commands: Commands) {
2882        commands.spawn((Camera2d, DespawnOnExit(super::Scene::BoxedContent)));
2883        commands
2884            .spawn((
2885                Node {
2886                    margin: auto().all(),
2887                    column_gap: px(30),
2888                    ..default()
2889                },
2890                DespawnOnExit(super::Scene::BoxedContent),
2891            ))
2892            .with_children(|builder| {
2893                for (heading, text_justify) in [
2894                    ("Left", Justify::Left),
2895                    ("Center", Justify::Center),
2896                    ("Right", Justify::Right),
2897                ] {
2898                    builder
2899                        .spawn(Node {
2900                            flex_direction: FlexDirection::Column,
2901                            align_items: AlignItems::Center,
2902                            justify_content: JustifyContent::Start,
2903                            row_gap: px(20),
2904                            ..default()
2905                        })
2906                        .with_children(|builder| {
2907                            builder.spawn((
2908                                Node::default(),
2909                                Text::new(format!("{heading} justify")),
2910                                TextFont::from_font_size(FontSize::Px(14.)),
2911                                TextLayout::justify(Justify::Center),
2912                            ));
2913
2914                            builder.spawn((
2915                                Node::default(),
2916                                Text::new("This text has\nno border or padding."),
2917                                TextFont::from_font_size(FontSize::Px(10.)),
2918                                TextLayout::justify(text_justify),
2919                                Outline {
2920                                    width: px(2),
2921                                    color: Color::WHITE,
2922                                    ..Default::default()
2923                                },
2924                            ));
2925
2926                            builder.spawn((
2927                                Node {
2928                                    border: px(10).all(),
2929                                    ..default()
2930                                },
2931                                Text::new("This text has\na border but no padding."),
2932                                TextFont::from_font_size(FontSize::Px(10.)),
2933                                TextLayout::justify(text_justify),
2934                                BorderColor::all(RED),
2935                                Outline {
2936                                    width: px(2),
2937                                    color: Color::WHITE,
2938                                    ..Default::default()
2939                                },
2940                            ));
2941
2942                            builder.spawn((
2943                                Node {
2944                                    padding: px(20).all(),
2945                                    ..default()
2946                                },
2947                                Text::new("This text has\npadding but no border."),
2948                                TextFont::from_font_size(FontSize::Px(10.)),
2949                                TextLayout::justify(text_justify),
2950                                Outline {
2951                                    width: px(2),
2952                                    color: Color::WHITE,
2953                                    ..Default::default()
2954                                },
2955                            ));
2956
2957                            builder.spawn((
2958                                Node {
2959                                    border: px(10).all(),
2960                                    padding: px(20).all(),
2961                                    ..default()
2962                                },
2963                                Text::new("This text has\nborder and padding."),
2964                                TextFont::from_font_size(FontSize::Px(10.)),
2965                                TextLayout::justify(text_justify),
2966                                BorderColor::all(RED),
2967                                Outline {
2968                                    width: px(2),
2969                                    color: Color::WHITE,
2970                                    ..Default::default()
2971                                },
2972                            ));
2973
2974                            builder.spawn((
2975                                Node {
2976                                    border: px(10).left(),
2977                                    ..default()
2978                                },
2979                                Text::new("This text has\na left border and no padding."),
2980                                TextFont::from_font_size(FontSize::Px(10.)),
2981                                TextLayout::justify(text_justify),
2982                                BorderColor::all(RED),
2983                                Outline {
2984                                    width: px(2),
2985                                    color: Color::WHITE,
2986                                    ..Default::default()
2987                                },
2988                            ));
2989
2990                            builder.spawn((
2991                                Node {
2992                                    border: px(10).right(),
2993                                    ..default()
2994                                },
2995                                Text::new("This text has\na right border and no padding."),
2996                                TextFont::from_font_size(FontSize::Px(10.)),
2997                                TextLayout::justify(text_justify),
2998                                BorderColor::all(RED),
2999                                Outline {
3000                                    width: px(2),
3001                                    color: Color::WHITE,
3002                                    ..Default::default()
3003                                },
3004                            ));
3005
3006                            builder.spawn((
3007                                Node {
3008                                    padding: px(20).top().with_right(px(20)),
3009                                    ..default()
3010                                },
3011                                Text::new("This text has\npadding on its top and right."),
3012                                TextFont::from_font_size(FontSize::Px(10.)),
3013                                TextLayout::justify(text_justify),
3014                                BorderColor::all(RED),
3015                                Outline {
3016                                    width: px(2),
3017                                    color: Color::WHITE,
3018                                    ..Default::default()
3019                                },
3020                            ));
3021
3022                            builder.spawn((
3023                                Node {
3024                                    padding: px(20).bottom().with_left(px(20)),
3025                                    ..default()
3026                                },
3027                                Text::new("This text has\npadding on its bottom and left."),
3028                                TextFont::from_font_size(FontSize::Px(10.)),
3029                                TextLayout::justify(text_justify),
3030                                BorderColor::all(RED),
3031                                Outline {
3032                                    width: px(2),
3033                                    color: Color::WHITE,
3034                                    ..Default::default()
3035                                },
3036                            ));
3037
3038                            builder.spawn((
3039                                Node {
3040                                    padding: px(20).top().with_left(px(20)),
3041                                    border: px(10).bottom().with_right(px(10)),
3042                                    ..default()
3043                                },
3044                                Text::new(
3045                                    "This text has\npadding on its top and left\nand a border on its bottom and right.",
3046                                ),
3047                                TextFont::from_font_size(FontSize::Px(10.)),
3048                                TextLayout::justify(text_justify),
3049                                BorderColor::all(RED),
3050                                Outline {
3051                                    width: px(2),
3052                                    color: Color::WHITE,
3053                                    ..Default::default()
3054                                },
3055                            ));
3056                        });
3057                }
3058            });
3059    }
3060}
3061
3062mod editable_text {
3063    use bevy::color::palettes::css::YELLOW;
3064    use bevy::prelude::*;
3065    use bevy::text::EditableText;
3066    use bevy::text::TextCursorStyle;
3067    use bevy::text::TextEdit;
3068    use bevy::ui_widgets::TextInput;
3069
3070    const DUMMY_TEXT: &str = "one\ntwo\nthree\nfour\nfive\nsix\nseven\neight\nnine\nten";
3071    const LOREM_TEXT: &str = concat!(
3072        "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. ",
3073        "Aenean commodo ligula eget dolor. Aenean massa. ",
3074        "Cum sociis natoque penatibus et magnis dis parturient montes, nascetur reprehenderit mus. ",
3075        "Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. ",
3076        "Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. ",
3077        "In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. ",
3078        "Nullam dictum felis eu pede mollis pretium. Integer tincidunt. ",
3079        "Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. ",
3080        "Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. ",
3081        "Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus. ",
3082        "Phasellus viverra nulla ut metus officia laoreet. Quisque rutrum. ",
3083        "Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi.",
3084        " Qui eget dui. Etiam rhoncus. Maecenas tempus, tellus eget condimentum rhoncus, ",
3085        "sem quam semper libero, sit amet adipiscing sem neque sed ipsum. ",
3086        "Qui quam nunc, blandit vel, luctus pulvinar, hendrerit id, lorem. ",
3087        "Maecenas nec odio et ante tincidunt tempus. Donec vitae sapien ut libero venenatis faucibus. ",
3088        "Nullam quis ante. Etiam sit amet orci eget eros faucibus tincidunt. Duis leo. ",
3089        "Sed fringilla mauris sit amet nibh. Donec sodales sagittis magna. ",
3090        "Sed consequat, leo eget bibendum sodales, augue velit cursus nunc,"
3091    );
3092
3093    pub fn setup(mut commands: Commands) {
3094        commands.spawn((Camera2d, DespawnOnExit(super::Scene::EditableText)));
3095        commands.spawn((
3096            Node {
3097                flex_wrap: FlexWrap::Wrap,
3098                align_items: AlignItems::Start,
3099                margin: px(10.).all(),
3100                width: vw(100),
3101                height: vh(100),
3102                row_gap: px(10),
3103                column_gap: px(20),
3104                ..default()
3105            },
3106            DespawnOnExit(super::Scene::EditableText),
3107            children![
3108                (
3109                    Node {
3110                        flex_direction: FlexDirection::Column,
3111                        row_gap: px(10),
3112                        ..default()
3113                    },
3114                    children![
3115                        Text::new("Single line"),
3116                        (
3117                            TextInput,
3118                            EditableText {
3119                                pending_edits: vec![TextEdit::Insert(
3120                                    "Single line EditableText".into(),
3121                                )],
3122                                ..default()
3123                            },
3124                            TextLayout::no_wrap(),
3125                            TextFont {
3126                                font_size: FontSize::Px(10.),
3127                                ..default()
3128                            },
3129                            TextCursorStyle::default(),
3130                            Node {
3131                                width: px(200.),
3132                                border: px(2).all(),
3133                                ..default()
3134                            },
3135                            BorderColor::all(YELLOW),
3136                        ),
3137                        Text::new("Initial end"),
3138                        (
3139                            EditableText::new(LOREM_TEXT),
3140                            TextLayout::no_wrap(),
3141                            TextFont {
3142                                font_size: FontSize::Px(10.),
3143                                ..default()
3144                            },
3145                            TextCursorStyle::default(),
3146                            Node {
3147                                width: px(200.),
3148                                border: px(2).all(),
3149                                ..default()
3150                            },
3151                            BorderColor::all(YELLOW),
3152                        ),
3153                        Text::new("Insert end"),
3154                        (
3155                            TextInput,
3156                            EditableText {
3157                                pending_edits: vec![TextEdit::Insert(LOREM_TEXT.into())],
3158                                ..default()
3159                            },
3160                            TextLayout::no_wrap(),
3161                            TextFont {
3162                                font_size: FontSize::Px(10.),
3163                                ..default()
3164                            },
3165                            TextCursorStyle::default(),
3166                            Node {
3167                                width: px(200.),
3168                                border: px(2).all(),
3169                                ..default()
3170                            },
3171                            BorderColor::all(YELLOW),
3172                        ),
3173                        Text::new("Select line start"),
3174                        (
3175                            TextInput,
3176                            EditableText {
3177                                pending_edits: vec![
3178                                    TextEdit::Insert(LOREM_TEXT.into()),
3179                                    TextEdit::LineStart(true),
3180                                ],
3181                                ..default()
3182                            },
3183                            TextLayout::no_wrap(),
3184                            TextFont {
3185                                font_size: FontSize::Px(10.),
3186                                ..default()
3187                            },
3188                            TextCursorStyle::default(),
3189                            Node {
3190                                width: px(200.),
3191                                border: px(2).all(),
3192                                ..default()
3193                            },
3194                            BorderColor::all(YELLOW),
3195                        ),
3196                    ],
3197                ),
3198                (
3199                    Node {
3200                        flex_direction: FlexDirection::Column,
3201                        row_gap: px(10),
3202                        ..default()
3203                    },
3204                    children![
3205                        Text::new("Wrapped start"),
3206                        (
3207                            TextInput,
3208                            EditableText {
3209                                pending_edits: vec![
3210                                    TextEdit::Insert(LOREM_TEXT.into()),
3211                                    TextEdit::TextStart(false),
3212                                ],
3213                                visible_lines: Some(8.),
3214                                ..default()
3215                            },
3216                            Node {
3217                                width: px(200.),
3218                                border: px(2).all(),
3219                                ..default()
3220                            },
3221                            TextCursorStyle::default(),
3222                            TextFont {
3223                                font_size: FontSize::Px(10.),
3224                                ..default()
3225                            },
3226                            BorderColor::all(YELLOW),
3227                        ),
3228                    ],
3229                ),
3230                (
3231                    Node {
3232                        flex_direction: FlexDirection::Column,
3233                        row_gap: px(10),
3234                        ..default()
3235                    },
3236                    children![
3237                        Text::new("Wrapped selection"),
3238                        (
3239                            TextInput,
3240                            EditableText {
3241                                pending_edits: vec![
3242                                    TextEdit::Insert(LOREM_TEXT.into()),
3243                                    TextEdit::TextStart(false),
3244                                    TextEdit::Down(false),
3245                                    TextEdit::TextEnd(true),
3246                                ],
3247                                visible_lines: Some(8.),
3248                                ..default()
3249                            },
3250                            TextCursorStyle::default(),
3251                            Node {
3252                                width: px(200.),
3253                                border: px(2).all(),
3254                                ..default()
3255                            },
3256                            TextFont {
3257                                font_size: FontSize::Px(10.),
3258                                ..default()
3259                            },
3260                            BorderColor::all(YELLOW),
3261                        ),
3262                    ],
3263                ),
3264                (
3265                    Node {
3266                        flex_direction: FlexDirection::Column,
3267                        row_gap: px(10),
3268                        ..default()
3269                    },
3270                    children![
3271                        Text::new("Clamp top"),
3272                        (
3273                            TextInput,
3274                            EditableText {
3275                                pending_edits: vec![
3276                                    TextEdit::Insert(DUMMY_TEXT.into()),
3277                                    TextEdit::ScrollByLines(-10.0),
3278                                ],
3279                                visible_lines: Some(5.5),
3280                                ..default()
3281                            },
3282                            TextCursorStyle::default(),
3283                            TextFont {
3284                                font_size: FontSize::Px(10.),
3285                                ..default()
3286                            },
3287                            Node {
3288                                width: px(100.),
3289                                border: px(2).all(),
3290                                ..default()
3291                            },
3292                            BorderColor::all(YELLOW),
3293                        ),
3294                    ],
3295                ),
3296                (
3297                    Node {
3298                        flex_direction: FlexDirection::Column,
3299                        row_gap: px(10),
3300                        ..default()
3301                    },
3302                    children![
3303                        Text::new("Home, Scroll 1"),
3304                        (
3305                            TextInput,
3306                            EditableText {
3307                                pending_edits: vec![
3308                                    TextEdit::Insert(DUMMY_TEXT.into()),
3309                                    TextEdit::ScrollTo(Vec2::ZERO),
3310                                    TextEdit::ScrollByLines(1.0),
3311                                ],
3312                                visible_lines: Some(5.5),
3313                                ..default()
3314                            },
3315                            TextCursorStyle::default(),
3316                            TextFont {
3317                                font_size: FontSize::Px(10.),
3318                                ..default()
3319                            },
3320                            Node {
3321                                width: px(100.),
3322                                border: px(2).all(),
3323                                ..default()
3324                            },
3325                            BorderColor::all(YELLOW),
3326                        ),
3327                    ],
3328                ),
3329                (
3330                    Node {
3331                        flex_direction: FlexDirection::Column,
3332                        row_gap: px(10),
3333                        ..default()
3334                    },
3335                    children![
3336                        Text::new("Home, Scroll 2"),
3337                        (
3338                            TextInput,
3339                            EditableText {
3340                                pending_edits: vec![
3341                                    TextEdit::Insert(DUMMY_TEXT.into()),
3342                                    TextEdit::ScrollTo(Vec2::ZERO),
3343                                    TextEdit::ScrollByLines(2.0),
3344                                ],
3345                                visible_lines: Some(5.5),
3346                                ..default()
3347                            },
3348                            TextFont {
3349                                font_size: FontSize::Px(10.),
3350                                ..default()
3351                            },
3352                            TextCursorStyle::default(),
3353                            Node {
3354                                width: px(100.),
3355                                border: px(2).all(),
3356                                ..default()
3357                            },
3358                            BorderColor::all(YELLOW),
3359                        ),
3360                    ],
3361                ),
3362                (
3363                    Node {
3364                        flex_direction: FlexDirection::Column,
3365                        row_gap: px(10),
3366                        ..default()
3367                    },
3368                    children![
3369                        Text::new("Clamp bottom"),
3370                        (
3371                            TextInput,
3372                            EditableText {
3373                                pending_edits: vec![
3374                                    TextEdit::Insert(DUMMY_TEXT.into()),
3375                                    TextEdit::ScrollByLines(-1000.0),
3376                                    TextEdit::ScrollByLines(1000.0),
3377                                ],
3378                                visible_lines: Some(5.5),
3379                                ..default()
3380                            },
3381                            TextCursorStyle::default(),
3382                            TextFont {
3383                                font_size: FontSize::Px(10.),
3384                                ..default()
3385                            },
3386                            Node {
3387                                width: px(100.),
3388                                border: px(2).all(),
3389                                ..default()
3390                            },
3391                            BorderColor::all(YELLOW),
3392                        ),
3393                    ],
3394                ),
3395                (
3396                    Node {
3397                        flex_direction: FlexDirection::Column,
3398                        row_gap: px(10),
3399                        ..default()
3400                    },
3401                    children![
3402                        Text::new("Bottom -1"),
3403                        (
3404                            TextInput,
3405                            EditableText {
3406                                pending_edits: vec![
3407                                    TextEdit::Insert(DUMMY_TEXT.into()),
3408                                    TextEdit::ScrollByLines(-1000.0),
3409                                    TextEdit::ScrollByLines(1000.0),
3410                                    TextEdit::ScrollByLines(-1.0),
3411                                ],
3412                                visible_lines: Some(5.5),
3413                                ..default()
3414                            },
3415                            TextCursorStyle::default(),
3416                            TextFont {
3417                                font_size: FontSize::Px(10.),
3418                                ..default()
3419                            },
3420                            Node {
3421                                width: px(100.),
3422                                border: px(2).all(),
3423                                ..default()
3424                            },
3425                            BorderColor::all(YELLOW),
3426                        ),
3427                    ],
3428                ),
3429                (
3430                    Node {
3431                        flex_direction: FlexDirection::Column,
3432                        row_gap: px(10),
3433                        ..default()
3434                    },
3435                    children![
3436                        Text::new("Top +3"),
3437                        (
3438                            TextInput,
3439                            EditableText {
3440                                pending_edits: vec![
3441                                    TextEdit::Insert(DUMMY_TEXT.into()),
3442                                    TextEdit::ScrollByLines(-1000.0),
3443                                    TextEdit::ScrollByLines(3.0),
3444                                ],
3445                                visible_lines: Some(5.5),
3446                                ..default()
3447                            },
3448                            TextCursorStyle::default(),
3449                            TextFont {
3450                                font_size: FontSize::Px(10.),
3451                                ..default()
3452                            },
3453                            Node {
3454                                width: px(100.),
3455                                border: px(2).all(),
3456                                ..default()
3457                            },
3458                            BorderColor::all(YELLOW),
3459                        ),
3460                    ],
3461                ),
3462                (
3463                    Node {
3464                        flex_direction: FlexDirection::Column,
3465                        row_gap: px(10),
3466                        ..default()
3467                    },
3468                    children![
3469                        Text::new("Select down 3"),
3470                        (
3471                            TextInput,
3472                            EditableText {
3473                                pending_edits: vec![
3474                                    TextEdit::Insert(DUMMY_TEXT.into()),
3475                                    TextEdit::TextStart(false),
3476                                    TextEdit::Down(false),
3477                                    TextEdit::Down(true),
3478                                    TextEdit::Down(true),
3479                                    TextEdit::Down(true),
3480                                ],
3481                                visible_lines: Some(5.5),
3482                                ..default()
3483                            },
3484                            TextCursorStyle::default(),
3485                            TextFont {
3486                                font_size: FontSize::Px(10.),
3487                                ..default()
3488                            },
3489                            Node {
3490                                width: px(100.),
3491                                border: px(2).all(),
3492                                ..default()
3493                            },
3494                            BorderColor::all(YELLOW),
3495                        ),
3496                    ],
3497                ),
3498                (
3499                    Node {
3500                        flex_direction: FlexDirection::Column,
3501                        row_gap: px(10),
3502                        ..default()
3503                    },
3504                    children![
3505                        Text::new("End, Scroll 1"),
3506                        (
3507                            TextInput,
3508                            EditableText {
3509                                pending_edits: vec![
3510                                    TextEdit::Insert(DUMMY_TEXT.into()),
3511                                    TextEdit::ScrollByLines(1.0),
3512                                ],
3513                                visible_lines: Some(5.5),
3514                                ..default()
3515                            },
3516                            TextCursorStyle::default(),
3517                            TextFont {
3518                                font_size: FontSize::Px(10.),
3519                                ..default()
3520                            },
3521                            Node {
3522                                width: px(100.),
3523                                border: px(2).all(),
3524                                ..default()
3525                            },
3526                            BorderColor::all(YELLOW),
3527                        ),
3528                    ],
3529                ),
3530                (
3531                    Node {
3532                        flex_direction: FlexDirection::Column,
3533                        row_gap: px(10),
3534                        ..default()
3535                    },
3536                    children![
3537                        Text::new("End, Scroll -0.5"),
3538                        (
3539                            TextInput,
3540                            EditableText {
3541                                pending_edits: vec![
3542                                    TextEdit::Insert(DUMMY_TEXT.into()),
3543                                    TextEdit::ScrollByLines(-0.5),
3544                                ],
3545                                visible_lines: Some(5.5),
3546                                ..default()
3547                            },
3548                            TextCursorStyle::default(),
3549                            TextFont {
3550                                font_size: FontSize::Px(10.),
3551                                ..default()
3552                            },
3553                            Node {
3554                                width: px(100.),
3555                                border: px(2).all(),
3556                                ..default()
3557                            },
3558                            BorderColor::all(YELLOW),
3559                        ),
3560                    ],
3561                )
3562            ],
3563        ));
3564    }
3565}
3566
3567mod node_material {
3568    use bevy::{
3569        color::palettes::tailwind::{CYAN_100, RED_500, YELLOW_100},
3570        prelude::*,
3571        render::render_resource::AsBindGroup,
3572        shader::ShaderRef,
3573    };
3574    const SHADER_ASSET_PATH: &str = "shaders/custom_ui_material.wesl";
3575
3576    #[derive(AsBindGroup, Asset, TypePath, Debug, Clone)]
3577    pub(super) struct DefaultUiMaterial {}
3578
3579    impl UiMaterial for DefaultUiMaterial {}
3580
3581    #[derive(AsBindGroup, Asset, TypePath, Debug, Clone)]
3582    pub(super) struct CustomUiMaterial {
3583        /// Color multiplied with the image
3584        #[uniform(0)]
3585        color: Vec4,
3586        /// Represents how much of the image is visible
3587        /// Goes from 0 to 1
3588        /// A `Vec4` is used here because Bevy with webgl2 requires that uniforms are 16-byte aligned but only the first component is read.
3589        #[uniform(1)]
3590        slider: Vec4,
3591        /// Image used to represent the slider
3592        #[texture(2)]
3593        #[sampler(3)]
3594        color_texture: Handle<Image>,
3595        /// Color of the image's border
3596        #[uniform(4)]
3597        border_color: Vec4,
3598    }
3599
3600    impl UiMaterial for CustomUiMaterial {
3601        fn fragment_shader() -> ShaderRef {
3602            SHADER_ASSET_PATH.into()
3603        }
3604    }
3605
3606    pub fn setup(
3607        mut commands: Commands,
3608        mut default_ui_materials: ResMut<Assets<DefaultUiMaterial>>,
3609        mut ui_materials: ResMut<Assets<CustomUiMaterial>>,
3610        asset_server: Res<AssetServer>,
3611    ) {
3612        let default_material = default_ui_materials.add(DefaultUiMaterial {});
3613        let custom_material = |slider| CustomUiMaterial {
3614            color: LinearRgba::from(CYAN_100).to_vec4(),
3615            slider: Vec4::splat(slider),
3616            color_texture: asset_server.load("branding/banner.png"),
3617            border_color: LinearRgba::from(YELLOW_100).to_vec4(),
3618        };
3619        let full_material = ui_materials.add(custom_material(1.));
3620        let material_node = Node {
3621            width: px(200),
3622            height: px(80),
3623            border: px(10).all(),
3624            border_radius: BorderRadius::all(px(20)),
3625            ..default()
3626        };
3627        let material_label = |text: &str| (Text::new(text), TextFont::from_font_size(px(10.)));
3628
3629        commands.spawn((Camera2d, DespawnOnExit(super::Scene::NodeMaterial)));
3630        commands.spawn((
3631            Node {
3632                display: Display::Grid,
3633                // two column grid, labels then materials, first row is spanned by title.
3634                width: percent(100),
3635                height: percent(100),
3636                grid_template_columns: vec![GridTrack::auto(), GridTrack::px(200.)],
3637                align_items: AlignItems::Center,
3638                align_content: AlignContent::Center,
3639                justify_content: JustifyContent::Center,
3640                row_gap: px(10.),
3641                column_gap: px(20.),
3642                ..default()
3643            },
3644            DespawnOnExit(super::Scene::NodeMaterial),
3645            children![
3646                (
3647                    Text::new("MaterialNode"),
3648                    TextFont::from_font_size(px(30.)),
3649                    TextLayout::justify(Justify::Center),
3650                    Node {
3651                        grid_column: GridPlacement::span(2),
3652                        margin: px(10.).bottom(),
3653                        ..default()
3654                    },
3655                ),
3656                // Default UI material (just white with the default ui_material.wgsl shader for the bevy_ui crate)
3657                material_label("'ui_material.wgsl' default material"),
3658                (material_node.clone(), MaterialNode(default_material),),
3659                // Custom UI material, 1./3 full.
3660                material_label("'custom_ui_material.wgsl' 1/3"),
3661                (
3662                    material_node.clone(),
3663                    MaterialNode(ui_materials.add(custom_material(1. / 3.))),
3664                ),
3665                // Custom UI material, 2./3 full.
3666                material_label("'custom_ui_material.wgsl' 2/3"),
3667                (
3668                    material_node.clone(),
3669                    MaterialNode(ui_materials.add(custom_material(2. / 3.)))
3670                ),
3671                // Custom UI material, full.
3672                material_label("'custom_ui_material.wgsl' Full"),
3673                (material_node.clone(), MaterialNode(full_material.clone()),),
3674                // Custom UI material, full. Clipped using overflow so bottom 50% missing
3675                material_label("'custom_ui_material.wgsl' clipped vertically"),
3676                (
3677                    Node {
3678                        width: material_node.width,
3679                        height: material_node.height,
3680                        ..default()
3681                    },
3682                    Outline {
3683                        width: px(1),
3684                        color: RED_500.into(),
3685                        ..default()
3686                    },
3687                    children![(
3688                        Node {
3689                            width: percent(100),
3690                            height: percent(50),
3691                            overflow: Overflow::clip(),
3692                            ..default()
3693                        },
3694                        children![(material_node.clone(), MaterialNode(full_material.clone()))],
3695                    )],
3696                ),
3697                // Custom UI material clipped on both axis so bottom 25% and right 25% not visible.
3698                material_label("'custom_ui_material.wgsl' end clipped on both axis"),
3699                (
3700                    Node {
3701                        width: material_node.width,
3702                        height: material_node.height,
3703                        ..default()
3704                    },
3705                    Outline {
3706                        width: px(1),
3707                        color: RED_500.into(),
3708                        ..default()
3709                    },
3710                    children![(
3711                        Node {
3712                            width: percent(75),
3713                            height: percent(75),
3714                            overflow: Overflow::clip(),
3715                            ..default()
3716                        },
3717                        children![(
3718                            Node {
3719                                position_type: PositionType::Absolute,
3720                                width: px(200),
3721                                height: px(80),
3722                                border: px(10).all(),
3723                                border_radius: BorderRadius::all(px(20)),
3724                                ..default()
3725                            },
3726                            MaterialNode(full_material.clone()),
3727                        )],
3728                    )],
3729                ),
3730                // Custom UI material clipped on both axis so top 25% and left 25% not visible.
3731                material_label("'custom_ui_material.wgsl' start clipped on both axis"),
3732                (
3733                    Node {
3734                        width: material_node.width,
3735                        height: material_node.height,
3736                        align_items: AlignItems::End,
3737                        justify_content: JustifyContent::End,
3738                        ..default()
3739                    },
3740                    Outline {
3741                        width: px(1),
3742                        color: RED_500.into(),
3743                        ..default()
3744                    },
3745                    children![(
3746                        Node {
3747                            width: percent(75),
3748                            height: percent(75),
3749                            overflow: Overflow::clip(),
3750                            ..default()
3751                        },
3752                        children![(
3753                            Node {
3754                                position_type: PositionType::Absolute,
3755                                width: px(200),
3756                                height: px(80),
3757                                right: px(0),
3758                                bottom: px(0),
3759                                border: px(10).all(),
3760                                border_radius: BorderRadius::all(px(20)),
3761                                ..default()
3762                            },
3763                            MaterialNode(full_material),
3764                        )],
3765                    )],
3766                ),
3767            ],
3768        ));
3769    }
More examples
Hide additional examples
examples/ui/layout/grid.rs (line 42)
18fn spawn_layout(mut commands: Commands, asset_server: Res<AssetServer>) {
19    let font = asset_server.load("fonts/FiraSans-Bold.ttf");
20    commands.spawn(Camera2d);
21
22    // Top-level grid (app frame)
23    commands
24        .spawn((
25            Node {
26                // Use the CSS Grid algorithm for laying out this node
27                display: Display::Grid,
28                // Make node fill the entirety of its parent (in this case the window)
29                width: percent(100),
30                height: percent(100),
31                // Set the grid to have 2 columns with sizes [min-content, minmax(0, 1fr)]
32                //   - The first column will size to the size of its contents
33                //   - The second column will take up the remaining available space
34                grid_template_columns: vec![GridTrack::min_content(), GridTrack::flex(1.0)],
35                // Set the grid to have 3 rows with sizes [auto, minmax(0, 1fr), 20px]
36                //  - The first row will size to the size of its contents
37                //  - The second row take up remaining available space (after rows 1 and 3 have both been sized)
38                //  - The third row will be exactly 20px high
39                grid_template_rows: vec![
40                    GridTrack::auto(),
41                    GridTrack::flex(1.0),
42                    GridTrack::px(20.),
43                ],
44                ..default()
45            },
46            BackgroundColor(Color::WHITE),
47        ))
48        .with_children(|builder| {
49            // Header
50            builder
51                .spawn(
52                    Node {
53                        display: Display::Grid,
54                        // Make this node span two grid columns so that it takes up the entire top tow
55                        grid_column: GridPlacement::span(2),
56                        padding: UiRect::all(px(6)),
57                        ..default()
58                    },
59                )
60                .with_children(|builder| {
61                    spawn_nested_text_bundle(builder, font.clone(), "Bevy CSS Grid Layout Example");
62                });
63
64            // Main content grid (auto placed in row 2, column 1)
65            builder
66                .spawn((
67                    Node {
68                        // Make the height of the node fill its parent
69                        height: percent(100),
70                        // Make the grid have a 1:1 aspect ratio meaning it will scale as an exact square
71                        // As the height is set explicitly, this means the width will adjust to match the height
72                        aspect_ratio: Some(1.0),
73                        // Use grid layout for this node
74                        display: Display::Grid,
75                        // Add 24px of padding around the grid
76                        padding: UiRect::all(px(24)),
77                        // Set the grid to have 4 columns all with sizes minmax(0, 1fr)
78                        // This creates 4 exactly evenly sized columns
79                        grid_template_columns: RepeatedGridTrack::flex(4, 1.0),
80                        // Set the grid to have 4 rows all with sizes minmax(0, 1fr)
81                        // This creates 4 exactly evenly sized rows
82                        grid_template_rows: RepeatedGridTrack::flex(4, 1.0),
83                        // Set a 12px gap/gutter between rows and columns
84                        row_gap: px(12),
85                        column_gap: px(12),
86                        ..default()
87                    },
88                    BackgroundColor(Color::srgb(0.25, 0.25, 0.25)),
89                ))
90                .with_children(|builder| {
91                    // Note there is no need to specify the position for each grid item. Grid items that are
92                    // not given an explicit position will be automatically positioned into the next available
93                    // grid cell. The order in which this is performed can be controlled using the grid_auto_flow
94                    // style property.
95
96                    item_rect(builder, ORANGE);
97                    item_rect(builder, BISQUE);
98                    item_rect(builder, BLUE);
99                    item_rect(builder, CRIMSON);
100                    item_rect(builder, AQUA);
101                    item_rect(builder, ORANGE_RED);
102                    item_rect(builder, DARK_GREEN);
103                    item_rect(builder, FUCHSIA);
104                    item_rect(builder, TEAL);
105                    item_rect(builder, ALICE_BLUE);
106                    item_rect(builder, CRIMSON);
107                    item_rect(builder, ANTIQUE_WHITE);
108                    item_rect(builder, YELLOW);
109                    item_rect(builder, DEEP_PINK);
110                    item_rect(builder, YELLOW_GREEN);
111                    item_rect(builder, SALMON);
112                });
113
114            // Right side bar (auto placed in row 2, column 2)
115            builder
116                .spawn((
117                    Node {
118                        display: Display::Grid,
119                        // Align content towards the start (top) in the vertical axis
120                        align_items: AlignItems::Start,
121                        // Align content towards the center in the horizontal axis
122                        justify_items: JustifyItems::Center,
123                        // Add 10px padding
124                        padding: UiRect::all(px(10)),
125                        // Add an fr track to take up all the available space at the bottom of the column so that the text nodes
126                        // can be top-aligned. Normally you'd use flexbox for this, but this is the CSS Grid example so we're using grid.
127                        grid_template_rows: vec![GridTrack::auto(), GridTrack::auto(), GridTrack::fr(1.0)],
128                        // Add a 10px gap between rows
129                        row_gap: px(10),
130                        ..default()
131                    },
132                    BackgroundColor(BLACK.into()),
133                ))
134                .with_children(|builder| {
135                    builder.spawn((Text::new("Sidebar"),
136                        TextFont::from(font.clone()),
137                    ));
138                    builder.spawn((Text::new("A paragraph of text which ought to wrap nicely. A paragraph of text which ought to wrap nicely. A paragraph of text which ought to wrap nicely. A paragraph of text which ought to wrap nicely. A paragraph of text which ought to wrap nicely. A paragraph of text which ought to wrap nicely. A paragraph of text which ought to wrap nicely."),
139                        TextFont {
140                            font: font.clone().into(),
141                            font_size: FontSize::Px(13.0),
142                            ..default()
143                        },
144                    ));
145                    builder.spawn(Node::default());
146                });
147
148            // Footer / status bar
149            builder.spawn((
150                Node {
151                    // Make this node span two grid column so that it takes up the entire bottom row
152                    grid_column: GridPlacement::span(2),
153                    ..default()
154                },
155                BackgroundColor(WHITE.into()),
156            ));
157
158            // Modal (absolutely positioned on top of content - currently hidden: to view it, change its visibility)
159            builder.spawn((
160                Node {
161                    position_type: PositionType::Absolute,
162                    margin: UiRect {
163                        top: px(100),
164                        bottom: auto(),
165                        left: auto(),
166                        right: auto(),
167                    },
168                    width: percent(60),
169                    height: px(300),
170                    max_width: px(600),
171                    ..default()
172                },
173                Visibility::Hidden,
174                BackgroundColor(Color::WHITE.with_alpha(0.8)),
175            ));
176        });
177}
examples/ui/text/multiple_text_inputs.rs (line 56)
39fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
40    commands.spawn(Camera2d);
41
42    let font = TextFont {
43        font: asset_server.load("fonts/FiraMono-Medium.ttf").into(),
44        font_size: FontSize::Px(24.),
45        ..default()
46    };
47
48    commands
49        .spawn((
50            Node {
51                width: percent(100.),
52                height: percent(100.),
53                display: Display::Grid,
54                justify_content: JustifyContent::Center,
55                align_content: AlignContent::Center,
56                grid_template_columns: vec![GridTrack::px(160.), RepeatedGridTrack::px(3, 320.)],
57                row_gap: px(8.),
58                column_gap: px(8.),
59                ..default()
60            },
61            TabGroup::default(),
62        ))
63        .with_children(|parent| {
64            parent.spawn((
65                Text::new("Multiple Text Inputs Example"),
66                Node {
67                    grid_column: GridPlacement::span(4),
68                    justify_self: JustifySelf::Center,
69                    margin: px(16).bottom(),
70                    ..default()
71                },
72                TextColor::WHITE,
73                font.clone(),
74            ));
75
76            let label_font = font.clone().with_font_size(14.);
77            for label in ["Justify", "EditableText", "value", "submission"] {
78                parent.spawn((
79                    Text::new(label),
80                    label_font.clone(),
81                    Node {
82                        justify_self: JustifySelf::Center,
83                        margin: px(-4).bottom(),
84                        ..default()
85                    },
86                ));
87            }
88
89            for (row, justify) in [
90                Justify::Left,
91                Justify::Center,
92                Justify::Right,
93                Justify::Justified,
94                Justify::Start,
95                Justify::End,
96            ]
97            .into_iter()
98            .enumerate()
99            {
100                parent.spawn((
101                    Node {
102                        border: px(4).all(),
103                        justify_content: JustifyContent::Center,
104                        align_items: AlignItems::Center,
105                        ..default()
106                    },
107                    BorderColor::all(Color::WHITE),
108                    children![(Text::new(format!("{justify:?}")), font.clone(),)],
109                ));
110
111                let mut input = parent.spawn((
112                    Node {
113                        border: px(4.).all(),
114                        padding: px(4.).all(),
115                        ..default()
116                    },
117                    TextInput,
118                    EditableText::new(format!("Initial text {row}")),
119                    TextCursorStyle::default(),
120                    font.clone(),
121                    BackgroundColor(bevy::color::palettes::css::DARK_GREY.into()),
122                    TextInputRow(row),
123                    TextLayout::no_wrap().with_justify(justify),
124                    TabIndex(row as i32),
125                    BorderColor::all(SLATE_300),
126                ));
127                if row == 0 {
128                    input.insert(AutoFocus);
129                }
130
131                parent.spawn((
132                    Node {
133                        border: px(4.).all(),
134                        padding: px(4.).all(),
135                        overflow: Overflow::clip_x(),
136                        overflow_clip_margin: OverflowClipMargin {
137                            visual_box: VisualBox::ContentBox,
138                            ..default()
139                        },
140                        ..default()
141                    },
142                    BackgroundColor(bevy::color::palettes::css::DARK_SLATE_BLUE.into()),
143                    BorderColor::all(Color::WHITE),
144                    children![(
145                        Text::default(),
146                        TextLayout::no_wrap(),
147                        font.clone(),
148                        BackgroundColor(bevy::color::palettes::css::DARK_SLATE_GRAY.into()),
149                        BorderColor::all(Color::WHITE),
150                        TextInputRow(row),
151                        TextOutput,
152                    )],
153                ));
154
155                parent.spawn((
156                    Node {
157                        border: px(4.).all(),
158                        padding: px(4.).all(),
159                        overflow: Overflow::clip_x(),
160                        overflow_clip_margin: OverflowClipMargin {
161                            visual_box: VisualBox::ContentBox,
162                            ..default()
163                        },
164
165                        ..default()
166                    },
167                    BackgroundColor(bevy::color::palettes::css::DARK_SLATE_BLUE.into()),
168                    BorderColor::all(Color::WHITE),
169                    children![(
170                        Text::default(),
171                        TextLayout::no_wrap(),
172                        font.clone(),
173                        TextInputRow(row),
174                        SubmitOutput,
175                    )],
176                ));
177            }
178
179            let label_font = font.clone().with_font_size(14.);
180            for label in ["ReadWrite", "EditableText", "value", "submission"] {
181                parent.spawn((
182                    Text::new(label),
183                    label_font.clone(),
184                    Node {
185                        justify_self: JustifySelf::Center,
186                        margin: px(-4).bottom(),
187                        ..default()
188                    },
189                ));
190            }
191
192            for (row, rwmode) in [
193                TextReadWriteMode::Editable,
194                TextReadWriteMode::ReadOnly,
195                TextReadWriteMode::Static,
196            ]
197            .into_iter()
198            .enumerate()
199            {
200                parent.spawn((
201                    Node {
202                        border: px(4).all(),
203                        justify_content: JustifyContent::Center,
204                        align_items: AlignItems::Center,
205                        ..default()
206                    },
207                    BorderColor::all(Color::WHITE),
208                    children![(Text::new(format!("{rwmode:?}")), font.clone(),)],
209                ));
210
211                let mut input = parent.spawn((
212                    Node {
213                        border: px(4.).all(),
214                        padding: px(4.).all(),
215                        ..default()
216                    },
217                    TextInput,
218                    EditableText::new(format!("Initial text {row}")),
219                    TextCursorStyle::default(),
220                    font.clone(),
221                    BackgroundColor(bevy::color::palettes::css::DARK_GREY.into()),
222                    TextInputRow(row + 100),
223                    rwmode,
224                    TabIndex(row as i32 + 100),
225                    BorderColor::all(SLATE_300),
226                ));
227                if row == 0 {
228                    input.insert(AutoFocus);
229                }
230
231                parent.spawn((
232                    Node {
233                        border: px(4.).all(),
234                        padding: px(4.).all(),
235                        overflow: Overflow::clip_x(),
236                        overflow_clip_margin: OverflowClipMargin {
237                            visual_box: VisualBox::ContentBox,
238                            ..default()
239                        },
240                        ..default()
241                    },
242                    BackgroundColor(bevy::color::palettes::css::DARK_SLATE_BLUE.into()),
243                    BorderColor::all(Color::WHITE),
244                    children![(
245                        Text::default(),
246                        TextLayout::no_wrap(),
247                        font.clone(),
248                        BackgroundColor(bevy::color::palettes::css::DARK_SLATE_GRAY.into()),
249                        BorderColor::all(Color::WHITE),
250                        TextInputRow(row + 100),
251                        TextOutput,
252                    )],
253                ));
254
255                parent.spawn((
256                    Node {
257                        border: px(4.).all(),
258                        padding: px(4.).all(),
259                        overflow: Overflow::clip_x(),
260                        overflow_clip_margin: OverflowClipMargin {
261                            visual_box: VisualBox::ContentBox,
262                            ..default()
263                        },
264
265                        ..default()
266                    },
267                    BackgroundColor(bevy::color::palettes::css::DARK_SLATE_BLUE.into()),
268                    BorderColor::all(Color::WHITE),
269                    children![(
270                        Text::default(),
271                        TextLayout::no_wrap(),
272                        font.clone(),
273                        TextInputRow(row + 100),
274                        SubmitOutput,
275                    )],
276                ));
277            }
278
279            parent.spawn((
280                Text::new("Press Enter to submit"),
281                Node {
282                    grid_column: GridPlacement::span(4),
283                    justify_self: JustifySelf::Center,
284                    margin: px(16).top(),
285                    ..default()
286                },
287                font.clone(),
288            ));
289        });
290}
Source

pub fn percent<T>(value: f32) -> T
where T: From<GridTrack>,

Create a grid track with a percentage size

Source

pub fn em<T>(value: f32) -> T
where T: From<GridTrack>,

Create a grid track with size as a multiple of the grid container’s font size.

Examples found in repository?
examples/testbed/ui.rs (line 3871)
3794    fn text_font_row(font_size: f32) -> impl Bundle {
3795        (
3796            Node {
3797                flex_direction: FlexDirection::Row,
3798                align_items: AlignItems::Center,
3799                column_gap: rem(1),
3800                ..default()
3801            },
3802            children![
3803                (
3804                    Node {
3805                        width: rem(4),
3806                        ..default()
3807                    },
3808                    Text::new(format!("{font_size}px")),
3809                    TextFont::from_font_size(font_size),
3810                    TextColor(LAVENDER.into()),
3811                ),
3812                // `em` padding: scales with this node's own font size.
3813                (
3814                    Node {
3815                        width: rem(20),
3816                        justify_content: JustifyContent::Center,
3817                        ..default()
3818                    },
3819                    children![(
3820                        Node {
3821                            padding: UiRect::all(em(1)),
3822                            flex_basis: Val::Auto,
3823                            border_radius: em(1).into(),
3824                            border: em(0.5).into(),
3825                            ..default()
3826                        },
3827                        EmSize(font_size),
3828                        BackgroundColor(DARK_SLATE_BLUE.into()),
3829                        BorderColor::all(LAVENDER),
3830                        children![(
3831                            Text::new("em sizing"),
3832                            TextFont::from_font_size(font_size),
3833                            BackgroundColor(PEACHPUFF.into()),
3834                            TextColor(DARK_SLATE_GRAY.into())
3835                        )],
3836                    )],
3837                ),
3838                // Always 10rem across
3839                (
3840                    Node {
3841                        flex_direction: FlexDirection::Row,
3842                        align_items: AlignItems::Center,
3843                        ..default()
3844                    },
3845                    EmSize(font_size),
3846                    children![(
3847                        Node {
3848                            width: rem(10),
3849                            ..default()
3850                        },
3851                        Text::new("< rem >"),
3852                        TextLayout {
3853                            justify: Justify::Center,
3854                            ..default()
3855                        },
3856                        TextFont::from_font_size(font_size),
3857                        BackgroundColor(PALE_TURQUOISE.into()),
3858                        TextColor(DARK_SLATE_GRAY.into())
3859                    )],
3860                ),
3861                // Grid tracks: left is 5em sized, right is 10rem, padding is 0.5rem
3862                (
3863                    Node {
3864                        width: rem(24),
3865                        justify_content: JustifyContent::End,
3866                        ..default()
3867                    },
3868                    children![(
3869                        Node {
3870                            display: Display::Grid,
3871                            grid_template_columns: vec![GridTrack::em(5.), GridTrack::rem(10.)],
3872                            padding: px(10).into(),
3873                            border_radius: px(10).into(),
3874                            border: px(1).into(),
3875                            ..default()
3876                        },
3877                        EmSize(font_size),
3878                        BackgroundColor(DARK_SLATE_BLUE.into()),
3879                        BorderColor::all(LAVENDER),
3880                        children![
3881                            (
3882                                Node {
3883                                    display: Display::Grid,
3884                                    grid_column: GridPlacement::span(2),
3885                                    ..default()
3886                                },
3887                                Text::new("px sizing"),
3888                                TextFont::from_font_size(px(16)),
3889                                TextColor(LAVENDER.into()),
3890                            ),
3891                            (
3892                                Text::new("< em >"),
3893                                TextLayout {
3894                                    justify: Justify::Center,
3895                                    ..default()
3896                                },
3897                                TextFont::from_font_size(font_size),
3898                                BackgroundColor(PEACHPUFF.into()),
3899                                TextColor(DARK_SLATE_GRAY.into())
3900                            ),
3901                            (
3902                                Text::new("< rem >"),
3903                                TextLayout {
3904                                    justify: Justify::Center,
3905                                    ..default()
3906                                },
3907                                TextFont::from_font_size(font_size),
3908                                BackgroundColor(PALE_TURQUOISE.into()),
3909                                TextColor(DARK_SLATE_GRAY.into())
3910                            ),
3911                        ]
3912                    )]
3913                ),
3914            ],
3915        )
3916    }
Source

pub fn rem<T>(value: f32) -> T
where T: From<GridTrack>,

Create a grid track with size as a multiple of the root font size.

Examples found in repository?
examples/testbed/ui.rs (line 3871)
3794    fn text_font_row(font_size: f32) -> impl Bundle {
3795        (
3796            Node {
3797                flex_direction: FlexDirection::Row,
3798                align_items: AlignItems::Center,
3799                column_gap: rem(1),
3800                ..default()
3801            },
3802            children![
3803                (
3804                    Node {
3805                        width: rem(4),
3806                        ..default()
3807                    },
3808                    Text::new(format!("{font_size}px")),
3809                    TextFont::from_font_size(font_size),
3810                    TextColor(LAVENDER.into()),
3811                ),
3812                // `em` padding: scales with this node's own font size.
3813                (
3814                    Node {
3815                        width: rem(20),
3816                        justify_content: JustifyContent::Center,
3817                        ..default()
3818                    },
3819                    children![(
3820                        Node {
3821                            padding: UiRect::all(em(1)),
3822                            flex_basis: Val::Auto,
3823                            border_radius: em(1).into(),
3824                            border: em(0.5).into(),
3825                            ..default()
3826                        },
3827                        EmSize(font_size),
3828                        BackgroundColor(DARK_SLATE_BLUE.into()),
3829                        BorderColor::all(LAVENDER),
3830                        children![(
3831                            Text::new("em sizing"),
3832                            TextFont::from_font_size(font_size),
3833                            BackgroundColor(PEACHPUFF.into()),
3834                            TextColor(DARK_SLATE_GRAY.into())
3835                        )],
3836                    )],
3837                ),
3838                // Always 10rem across
3839                (
3840                    Node {
3841                        flex_direction: FlexDirection::Row,
3842                        align_items: AlignItems::Center,
3843                        ..default()
3844                    },
3845                    EmSize(font_size),
3846                    children![(
3847                        Node {
3848                            width: rem(10),
3849                            ..default()
3850                        },
3851                        Text::new("< rem >"),
3852                        TextLayout {
3853                            justify: Justify::Center,
3854                            ..default()
3855                        },
3856                        TextFont::from_font_size(font_size),
3857                        BackgroundColor(PALE_TURQUOISE.into()),
3858                        TextColor(DARK_SLATE_GRAY.into())
3859                    )],
3860                ),
3861                // Grid tracks: left is 5em sized, right is 10rem, padding is 0.5rem
3862                (
3863                    Node {
3864                        width: rem(24),
3865                        justify_content: JustifyContent::End,
3866                        ..default()
3867                    },
3868                    children![(
3869                        Node {
3870                            display: Display::Grid,
3871                            grid_template_columns: vec![GridTrack::em(5.), GridTrack::rem(10.)],
3872                            padding: px(10).into(),
3873                            border_radius: px(10).into(),
3874                            border: px(1).into(),
3875                            ..default()
3876                        },
3877                        EmSize(font_size),
3878                        BackgroundColor(DARK_SLATE_BLUE.into()),
3879                        BorderColor::all(LAVENDER),
3880                        children![
3881                            (
3882                                Node {
3883                                    display: Display::Grid,
3884                                    grid_column: GridPlacement::span(2),
3885                                    ..default()
3886                                },
3887                                Text::new("px sizing"),
3888                                TextFont::from_font_size(px(16)),
3889                                TextColor(LAVENDER.into()),
3890                            ),
3891                            (
3892                                Text::new("< em >"),
3893                                TextLayout {
3894                                    justify: Justify::Center,
3895                                    ..default()
3896                                },
3897                                TextFont::from_font_size(font_size),
3898                                BackgroundColor(PEACHPUFF.into()),
3899                                TextColor(DARK_SLATE_GRAY.into())
3900                            ),
3901                            (
3902                                Text::new("< rem >"),
3903                                TextLayout {
3904                                    justify: Justify::Center,
3905                                    ..default()
3906                                },
3907                                TextFont::from_font_size(font_size),
3908                                BackgroundColor(PALE_TURQUOISE.into()),
3909                                TextColor(DARK_SLATE_GRAY.into())
3910                            ),
3911                        ]
3912                    )]
3913                ),
3914            ],
3915        )
3916    }
Source

pub fn fr<T>(value: f32) -> T
where T: From<GridTrack>,

Create a grid track with an fr size. Note that this will give the track a content-based minimum size. Usually you are best off using GridTrack::flex instead which uses a zero minimum size.

Examples found in repository?
examples/ui/layout/grid.rs (line 127)
18fn spawn_layout(mut commands: Commands, asset_server: Res<AssetServer>) {
19    let font = asset_server.load("fonts/FiraSans-Bold.ttf");
20    commands.spawn(Camera2d);
21
22    // Top-level grid (app frame)
23    commands
24        .spawn((
25            Node {
26                // Use the CSS Grid algorithm for laying out this node
27                display: Display::Grid,
28                // Make node fill the entirety of its parent (in this case the window)
29                width: percent(100),
30                height: percent(100),
31                // Set the grid to have 2 columns with sizes [min-content, minmax(0, 1fr)]
32                //   - The first column will size to the size of its contents
33                //   - The second column will take up the remaining available space
34                grid_template_columns: vec![GridTrack::min_content(), GridTrack::flex(1.0)],
35                // Set the grid to have 3 rows with sizes [auto, minmax(0, 1fr), 20px]
36                //  - The first row will size to the size of its contents
37                //  - The second row take up remaining available space (after rows 1 and 3 have both been sized)
38                //  - The third row will be exactly 20px high
39                grid_template_rows: vec![
40                    GridTrack::auto(),
41                    GridTrack::flex(1.0),
42                    GridTrack::px(20.),
43                ],
44                ..default()
45            },
46            BackgroundColor(Color::WHITE),
47        ))
48        .with_children(|builder| {
49            // Header
50            builder
51                .spawn(
52                    Node {
53                        display: Display::Grid,
54                        // Make this node span two grid columns so that it takes up the entire top tow
55                        grid_column: GridPlacement::span(2),
56                        padding: UiRect::all(px(6)),
57                        ..default()
58                    },
59                )
60                .with_children(|builder| {
61                    spawn_nested_text_bundle(builder, font.clone(), "Bevy CSS Grid Layout Example");
62                });
63
64            // Main content grid (auto placed in row 2, column 1)
65            builder
66                .spawn((
67                    Node {
68                        // Make the height of the node fill its parent
69                        height: percent(100),
70                        // Make the grid have a 1:1 aspect ratio meaning it will scale as an exact square
71                        // As the height is set explicitly, this means the width will adjust to match the height
72                        aspect_ratio: Some(1.0),
73                        // Use grid layout for this node
74                        display: Display::Grid,
75                        // Add 24px of padding around the grid
76                        padding: UiRect::all(px(24)),
77                        // Set the grid to have 4 columns all with sizes minmax(0, 1fr)
78                        // This creates 4 exactly evenly sized columns
79                        grid_template_columns: RepeatedGridTrack::flex(4, 1.0),
80                        // Set the grid to have 4 rows all with sizes minmax(0, 1fr)
81                        // This creates 4 exactly evenly sized rows
82                        grid_template_rows: RepeatedGridTrack::flex(4, 1.0),
83                        // Set a 12px gap/gutter between rows and columns
84                        row_gap: px(12),
85                        column_gap: px(12),
86                        ..default()
87                    },
88                    BackgroundColor(Color::srgb(0.25, 0.25, 0.25)),
89                ))
90                .with_children(|builder| {
91                    // Note there is no need to specify the position for each grid item. Grid items that are
92                    // not given an explicit position will be automatically positioned into the next available
93                    // grid cell. The order in which this is performed can be controlled using the grid_auto_flow
94                    // style property.
95
96                    item_rect(builder, ORANGE);
97                    item_rect(builder, BISQUE);
98                    item_rect(builder, BLUE);
99                    item_rect(builder, CRIMSON);
100                    item_rect(builder, AQUA);
101                    item_rect(builder, ORANGE_RED);
102                    item_rect(builder, DARK_GREEN);
103                    item_rect(builder, FUCHSIA);
104                    item_rect(builder, TEAL);
105                    item_rect(builder, ALICE_BLUE);
106                    item_rect(builder, CRIMSON);
107                    item_rect(builder, ANTIQUE_WHITE);
108                    item_rect(builder, YELLOW);
109                    item_rect(builder, DEEP_PINK);
110                    item_rect(builder, YELLOW_GREEN);
111                    item_rect(builder, SALMON);
112                });
113
114            // Right side bar (auto placed in row 2, column 2)
115            builder
116                .spawn((
117                    Node {
118                        display: Display::Grid,
119                        // Align content towards the start (top) in the vertical axis
120                        align_items: AlignItems::Start,
121                        // Align content towards the center in the horizontal axis
122                        justify_items: JustifyItems::Center,
123                        // Add 10px padding
124                        padding: UiRect::all(px(10)),
125                        // Add an fr track to take up all the available space at the bottom of the column so that the text nodes
126                        // can be top-aligned. Normally you'd use flexbox for this, but this is the CSS Grid example so we're using grid.
127                        grid_template_rows: vec![GridTrack::auto(), GridTrack::auto(), GridTrack::fr(1.0)],
128                        // Add a 10px gap between rows
129                        row_gap: px(10),
130                        ..default()
131                    },
132                    BackgroundColor(BLACK.into()),
133                ))
134                .with_children(|builder| {
135                    builder.spawn((Text::new("Sidebar"),
136                        TextFont::from(font.clone()),
137                    ));
138                    builder.spawn((Text::new("A paragraph of text which ought to wrap nicely. A paragraph of text which ought to wrap nicely. A paragraph of text which ought to wrap nicely. A paragraph of text which ought to wrap nicely. A paragraph of text which ought to wrap nicely. A paragraph of text which ought to wrap nicely. A paragraph of text which ought to wrap nicely."),
139                        TextFont {
140                            font: font.clone().into(),
141                            font_size: FontSize::Px(13.0),
142                            ..default()
143                        },
144                    ));
145                    builder.spawn(Node::default());
146                });
147
148            // Footer / status bar
149            builder.spawn((
150                Node {
151                    // Make this node span two grid column so that it takes up the entire bottom row
152                    grid_column: GridPlacement::span(2),
153                    ..default()
154                },
155                BackgroundColor(WHITE.into()),
156            ));
157
158            // Modal (absolutely positioned on top of content - currently hidden: to view it, change its visibility)
159            builder.spawn((
160                Node {
161                    position_type: PositionType::Absolute,
162                    margin: UiRect {
163                        top: px(100),
164                        bottom: auto(),
165                        left: auto(),
166                        right: auto(),
167                    },
168                    width: percent(60),
169                    height: px(300),
170                    max_width: px(600),
171                    ..default()
172                },
173                Visibility::Hidden,
174                BackgroundColor(Color::WHITE.with_alpha(0.8)),
175            ));
176        });
177}
Source

pub fn flex<T>(value: f32) -> T
where T: From<GridTrack>,

Create a grid track with a minmax(0, Nfr) size.

Examples found in repository?
examples/ui/text/system_fonts.rs (line 62)
16fn setup(mut commands: Commands, mut font_system: ResMut<FontCx>) {
17    let mut families: Vec<String> = font_system
18        .context
19        .collection
20        .family_names()
21        .map(ToOwned::to_owned)
22        .collect();
23    families.sort_unstable();
24    families.dedup();
25    let family_count = families.len();
26
27    commands.spawn(Camera2d);
28
29    commands
30        .spawn((
31            Node {
32                flex_direction: FlexDirection::Column,
33                width: percent(100),
34                height: percent(100),
35                align_items: AlignItems::Center,
36                row_gap: px(10.),
37                ..default()
38            },
39            BackgroundColor(Color::srgb(0.1, 0.1, 0.1)),
40        ))
41        .with_children(move |builder| {
42            builder.spawn(Text::new(format!(
43                "Total available fonts: {}",
44                family_count,
45            )));
46
47            builder
48                .spawn(Node {
49                    flex_direction: FlexDirection::Column,
50                    row_gap: px(6),
51                    overflow: Overflow::scroll_y(),
52                    align_items: AlignItems::Stretch,
53                    ..default()
54                })
55                .with_children(|builder| {
56                    for family in families {
57                        let font = FontSource::Family(family.clone().into());
58                        builder.spawn((
59                            Node {
60                                display: Display::Grid,
61                                grid_template_columns: vec![
62                                    GridTrack::flex(1.),
63                                    GridTrack::flex(1.),
64                                ],
65                                padding: px(6).all(),
66                                column_gap: px(50.),
67                                ..default()
68                            },
69                            BackgroundColor(Color::srgb(0.2, 0.2, 0.25)),
70                            children![
71                                (
72                                    Text::new(&family),
73                                    TextFont { font, ..default() },
74                                    TextLayout::no_wrap()
75                                ),
76                                (Text::new(family), TextLayout::no_wrap()),
77                            ],
78                        ));
79                    }
80                })
81                .observe(
82                    |on_scroll: On<PointerScroll>,
83                     mut query: Query<(&mut ScrollPosition, &ComputedNode)>| {
84                        if let Ok((mut scroll_position, node)) = query.get_mut(on_scroll.entity) {
85                            let dy = match on_scroll.unit {
86                                MouseScrollUnit::Line => on_scroll.y * 20.,
87                                MouseScrollUnit::Pixel => on_scroll.y,
88                            };
89                            let range = (node.content_size.y - node.size.y).max(0.)
90                                * node.inverse_scale_factor;
91                            scroll_position.y = (scroll_position.y - dy).clamp(0., range);
92                        }
93                    },
94                );
95        });
96}
More examples
Hide additional examples
examples/ui/images/image_node_resizing.rs (line 77)
62fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
63    let image_handle = asset_server.load("branding/icon.png");
64    let full_text = format!(
65        "{}height : {}%, width : {}%",
66        TEXT_PREFIX, IMAGE_GROUP_BOX_INIT_HEIGHT, IMAGE_GROUP_BOX_INIT_WIDTH,
67    );
68
69    commands.spawn(Camera2d);
70
71    let container = commands
72        .spawn((
73            Node {
74                display: Display::Grid,
75                width: percent(100),
76                height: percent(100),
77                grid_template_rows: vec![GridTrack::min_content(), GridTrack::flex(1.0)],
78                ..default()
79            },
80            BackgroundColor(Color::WHITE),
81        ))
82        .id();
83
84    // Keyboard Text
85    commands
86        .spawn((
87            TextData {
88                height: IMAGE_GROUP_BOX_INIT_HEIGHT,
89                width: IMAGE_GROUP_BOX_INIT_WIDTH,
90            },
91            Text::new(full_text),
92            TextColor::BLACK,
93            Node {
94                grid_row: GridPlacement::span(1),
95                padding: px(6).all(),
96                ..default()
97            },
98            UiDebugOptions {
99                enabled: false,
100                ..default()
101            },
102            ChildOf(container),
103        ))
104        .observe(update_text);
105
106    commands
107        .spawn((
108            Node {
109                display: Display::Flex,
110                grid_row: GridPlacement::span(1),
111                flex_direction: FlexDirection::Column,
112                justify_content: JustifyContent::SpaceAround,
113                padding: px(10.).all(),
114                ..default()
115            },
116            BackgroundColor(Color::BLACK),
117            ChildOf(container),
118        ))
119        .with_children(|builder| {
120            // `NodeImageMode::Auto` will resize the image automatically by taking the size of the source image and applying any layout constraints.
121            builder
122                .spawn((
123                    ImageGroup,
124                    Node {
125                        display: Display::Flex,
126                        justify_content: JustifyContent::Start,
127                        width: percent(IMAGE_GROUP_BOX_INIT_WIDTH),
128                        height: percent(IMAGE_GROUP_BOX_INIT_HEIGHT),
129                        ..default()
130                    },
131                    BackgroundColor(Color::from(tailwind::BLUE_100)),
132                ))
133                .with_children(|parent| {
134                    for _ in 0..4 {
135                        // child node will apply Flex layout
136                        parent.spawn((
137                            Node::default(),
138                            ImageNode {
139                                image: image_handle.clone(),
140                                image_mode: NodeImageMode::Auto,
141                                ..default()
142                            },
143                        ));
144                    }
145                });
146            // `NodeImageMode::Stretch` will resize the image to match the size of the `Node` component
147            builder
148                .spawn((
149                    ImageGroup,
150                    Node {
151                        display: Display::Flex,
152                        justify_content: JustifyContent::Start,
153                        width: percent(IMAGE_GROUP_BOX_INIT_WIDTH),
154                        height: percent(IMAGE_GROUP_BOX_INIT_HEIGHT),
155                        ..default()
156                    },
157                    BackgroundColor(Color::from(tailwind::BLUE_100)),
158                ))
159                .with_children(|parent| {
160                    for width in [10., 20., 30., 40.] {
161                        parent.spawn((
162                            Node {
163                                height: percent(100),
164                                width: percent(width),
165                                ..default()
166                            },
167                            ImageNode {
168                                image: image_handle.clone(),
169                                image_mode: NodeImageMode::Stretch,
170                                ..default()
171                            },
172                        ));
173                    }
174                });
175        });
176}
examples/ui/layout/grid.rs (line 34)
18fn spawn_layout(mut commands: Commands, asset_server: Res<AssetServer>) {
19    let font = asset_server.load("fonts/FiraSans-Bold.ttf");
20    commands.spawn(Camera2d);
21
22    // Top-level grid (app frame)
23    commands
24        .spawn((
25            Node {
26                // Use the CSS Grid algorithm for laying out this node
27                display: Display::Grid,
28                // Make node fill the entirety of its parent (in this case the window)
29                width: percent(100),
30                height: percent(100),
31                // Set the grid to have 2 columns with sizes [min-content, minmax(0, 1fr)]
32                //   - The first column will size to the size of its contents
33                //   - The second column will take up the remaining available space
34                grid_template_columns: vec![GridTrack::min_content(), GridTrack::flex(1.0)],
35                // Set the grid to have 3 rows with sizes [auto, minmax(0, 1fr), 20px]
36                //  - The first row will size to the size of its contents
37                //  - The second row take up remaining available space (after rows 1 and 3 have both been sized)
38                //  - The third row will be exactly 20px high
39                grid_template_rows: vec![
40                    GridTrack::auto(),
41                    GridTrack::flex(1.0),
42                    GridTrack::px(20.),
43                ],
44                ..default()
45            },
46            BackgroundColor(Color::WHITE),
47        ))
48        .with_children(|builder| {
49            // Header
50            builder
51                .spawn(
52                    Node {
53                        display: Display::Grid,
54                        // Make this node span two grid columns so that it takes up the entire top tow
55                        grid_column: GridPlacement::span(2),
56                        padding: UiRect::all(px(6)),
57                        ..default()
58                    },
59                )
60                .with_children(|builder| {
61                    spawn_nested_text_bundle(builder, font.clone(), "Bevy CSS Grid Layout Example");
62                });
63
64            // Main content grid (auto placed in row 2, column 1)
65            builder
66                .spawn((
67                    Node {
68                        // Make the height of the node fill its parent
69                        height: percent(100),
70                        // Make the grid have a 1:1 aspect ratio meaning it will scale as an exact square
71                        // As the height is set explicitly, this means the width will adjust to match the height
72                        aspect_ratio: Some(1.0),
73                        // Use grid layout for this node
74                        display: Display::Grid,
75                        // Add 24px of padding around the grid
76                        padding: UiRect::all(px(24)),
77                        // Set the grid to have 4 columns all with sizes minmax(0, 1fr)
78                        // This creates 4 exactly evenly sized columns
79                        grid_template_columns: RepeatedGridTrack::flex(4, 1.0),
80                        // Set the grid to have 4 rows all with sizes minmax(0, 1fr)
81                        // This creates 4 exactly evenly sized rows
82                        grid_template_rows: RepeatedGridTrack::flex(4, 1.0),
83                        // Set a 12px gap/gutter between rows and columns
84                        row_gap: px(12),
85                        column_gap: px(12),
86                        ..default()
87                    },
88                    BackgroundColor(Color::srgb(0.25, 0.25, 0.25)),
89                ))
90                .with_children(|builder| {
91                    // Note there is no need to specify the position for each grid item. Grid items that are
92                    // not given an explicit position will be automatically positioned into the next available
93                    // grid cell. The order in which this is performed can be controlled using the grid_auto_flow
94                    // style property.
95
96                    item_rect(builder, ORANGE);
97                    item_rect(builder, BISQUE);
98                    item_rect(builder, BLUE);
99                    item_rect(builder, CRIMSON);
100                    item_rect(builder, AQUA);
101                    item_rect(builder, ORANGE_RED);
102                    item_rect(builder, DARK_GREEN);
103                    item_rect(builder, FUCHSIA);
104                    item_rect(builder, TEAL);
105                    item_rect(builder, ALICE_BLUE);
106                    item_rect(builder, CRIMSON);
107                    item_rect(builder, ANTIQUE_WHITE);
108                    item_rect(builder, YELLOW);
109                    item_rect(builder, DEEP_PINK);
110                    item_rect(builder, YELLOW_GREEN);
111                    item_rect(builder, SALMON);
112                });
113
114            // Right side bar (auto placed in row 2, column 2)
115            builder
116                .spawn((
117                    Node {
118                        display: Display::Grid,
119                        // Align content towards the start (top) in the vertical axis
120                        align_items: AlignItems::Start,
121                        // Align content towards the center in the horizontal axis
122                        justify_items: JustifyItems::Center,
123                        // Add 10px padding
124                        padding: UiRect::all(px(10)),
125                        // Add an fr track to take up all the available space at the bottom of the column so that the text nodes
126                        // can be top-aligned. Normally you'd use flexbox for this, but this is the CSS Grid example so we're using grid.
127                        grid_template_rows: vec![GridTrack::auto(), GridTrack::auto(), GridTrack::fr(1.0)],
128                        // Add a 10px gap between rows
129                        row_gap: px(10),
130                        ..default()
131                    },
132                    BackgroundColor(BLACK.into()),
133                ))
134                .with_children(|builder| {
135                    builder.spawn((Text::new("Sidebar"),
136                        TextFont::from(font.clone()),
137                    ));
138                    builder.spawn((Text::new("A paragraph of text which ought to wrap nicely. A paragraph of text which ought to wrap nicely. A paragraph of text which ought to wrap nicely. A paragraph of text which ought to wrap nicely. A paragraph of text which ought to wrap nicely. A paragraph of text which ought to wrap nicely. A paragraph of text which ought to wrap nicely."),
139                        TextFont {
140                            font: font.clone().into(),
141                            font_size: FontSize::Px(13.0),
142                            ..default()
143                        },
144                    ));
145                    builder.spawn(Node::default());
146                });
147
148            // Footer / status bar
149            builder.spawn((
150                Node {
151                    // Make this node span two grid column so that it takes up the entire bottom row
152                    grid_column: GridPlacement::span(2),
153                    ..default()
154                },
155                BackgroundColor(WHITE.into()),
156            ));
157
158            // Modal (absolutely positioned on top of content - currently hidden: to view it, change its visibility)
159            builder.spawn((
160                Node {
161                    position_type: PositionType::Absolute,
162                    margin: UiRect {
163                        top: px(100),
164                        bottom: auto(),
165                        left: auto(),
166                        right: auto(),
167                    },
168                    width: percent(60),
169                    height: px(300),
170                    max_width: px(600),
171                    ..default()
172                },
173                Visibility::Hidden,
174                BackgroundColor(Color::WHITE.with_alpha(0.8)),
175            ));
176        });
177}
examples/testbed/ui.rs (line 405)
382    pub fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
383        commands.spawn((Camera2d, DespawnOnExit(super::Scene::Text)));
384
385        let mut container = commands.spawn((
386            Node {
387                flex_direction: FlexDirection::Column,
388                ..default()
389            },
390            DespawnOnExit(super::Scene::Text),
391        ));
392
393        container.with_child((
394            Text::new("Hello World."),
395            TextFont {
396                font: asset_server.load("fonts/FiraSans-Bold.ttf").into(),
397                font_size: FontSize::Px(100.),
398                ..default()
399            },
400        ));
401
402        container.with_children(|builder| {
403            let mut grid = builder.spawn(Node {
404                display: Display::Grid,
405                grid_template_columns: vec![GridTrack::flex(1.0), GridTrack::flex(1.0)],
406                padding: UiRect::horizontal(px(5.)),
407                ..default()
408            });
409
410            grid.with_children(|grid| {
411                for hinting in [FontHinting::Enabled, FontHinting::Disabled] {
412                    let mut content = grid.spawn(Node {
413                        flex_direction: FlexDirection::Column,
414                        row_gap: px(5.),
415                        ..default()
416                    });
417
418                    content.with_child((
419                        Text::new(format!("FontHinting::{:?}", hinting)),
420                        TextFont {
421                            font: asset_server.load("fonts/FiraSans-Bold.ttf").into(),
422                            ..default()
423                        },
424                        hinting,
425                    ));
426
427                    content.with_child((
428                        Text::new("Font from css font list"),
429                        TextFont {
430                            font: FontSource::families(
431                                "'Comic Sans', Arial, 'Noto Sans', sans-serif",
432                            ),
433                            ..Default::default()
434                        },
435                    ));
436
437                    content.with_child((
438                        Text::new("white "),
439                        TextFont {
440                            font: asset_server.load("fonts/FiraSans-Bold.ttf").into(),
441                            ..default()
442                        },
443                        hinting,
444                        children![
445                            (TextSpan::new("red "), TextColor(RED.into()),),
446                            (TextSpan::new("green "), TextColor(GREEN.into()),),
447                            (TextSpan::new("blue "), TextColor(BLUE.into()),),
448                            (
449                                TextSpan::new("black"),
450                                TextColor(Color::BLACK),
451                                TextFont {
452                                    font: asset_server.load("fonts/FiraSans-Bold.ttf").into(),
453                                    ..default()
454                                },
455                                TextBackgroundColor(Color::WHITE)
456                            ),
457                        ],
458                    ));
459
460                    content.with_child((
461                        Text::new(""),
462                        TextFont {
463                            font: asset_server.load("fonts/FiraSans-Bold.ttf").into(),
464                            ..default()
465                        },
466                        hinting,
467                        children![
468                            (
469                                TextSpan::new("white "),
470                                TextFont {
471                                    font: asset_server.load("fonts/FiraSans-Bold.ttf").into(),
472                                    ..default()
473                                }
474                            ),
475                            (TextSpan::new("red "), TextColor(RED.into()),),
476                            (TextSpan::new("green "), TextColor(GREEN.into()),),
477                            (TextSpan::new("blue "), TextColor(BLUE.into()),),
478                            (
479                                TextSpan::new("black"),
480                                TextColor(Color::BLACK),
481                                TextFont {
482                                    font: asset_server.load("fonts/FiraSans-Bold.ttf").into(),
483                                    ..default()
484                                },
485                                TextBackgroundColor(Color::WHITE)
486                            ),
487                        ],
488                    ));
489
490                    content.with_child((
491                        Text::new(""),
492                        TextFont {
493                            font: asset_server.load("fonts/FiraSans-Bold.ttf").into(),
494                            ..default()
495                        },
496                        hinting,
497                        children![
498                            (TextSpan::new(""), TextColor(YELLOW.into()),),
499                            TextSpan::new(""),
500                            (
501                                TextSpan::new("white "),
502                                TextFont {
503                                    font: asset_server.load("fonts/FiraSans-Bold.ttf").into(),
504                                    ..default()
505                                }
506                            ),
507                            TextSpan::new(""),
508                            (TextSpan::new("red "), TextColor(RED.into()),),
509                            TextSpan::new(""),
510                            TextSpan::new(""),
511                            (TextSpan::new("green "), TextColor(GREEN.into()),),
512                            (TextSpan::new(""), TextColor(YELLOW.into()),),
513                            (TextSpan::new("blue "), TextColor(BLUE.into()),),
514                            TextSpan::new(""),
515                            (TextSpan::new(""), TextColor(YELLOW.into()),),
516                            (
517                                TextSpan::new("black"),
518                                TextColor(Color::BLACK),
519                                TextFont {
520                                    font: asset_server.load("fonts/FiraSans-Bold.ttf").into(),
521                                    ..default()
522                                },
523                                TextBackgroundColor(Color::WHITE)
524                            ),
525                            TextSpan::new(""),
526                        ],
527                    ));
528
529                    content.with_child((
530                        hinting,
531                        Text::new("FiraSans_"),
532                        TextFont {
533                            font: asset_server.load("fonts/FiraSans-Bold.ttf").into(),
534                            font_size: FontSize::Px(25.),
535                            ..default()
536                        },
537                        children![
538                            (
539                                TextSpan::new("MonaSans_"),
540                                TextFont {
541                                    font: asset_server
542                                        .load("fonts/MonaSans-VariableFont.ttf")
543                                        .into(),
544                                    font_size: FontSize::Px(25.),
545                                    ..default()
546                                }
547                            ),
548                            (
549                                TextSpan::new("EBGaramond_"),
550                                TextFont {
551                                    font: asset_server
552                                        .load("fonts/EBGaramond12-Regular.otf")
553                                        .into(),
554                                    font_size: FontSize::Px(25.),
555                                    ..default()
556                                },
557                            ),
558                            (
559                                TextSpan::new("FiraMono"),
560                                TextFont {
561                                    font: asset_server.load("fonts/FiraMono-Medium.ttf").into(),
562                                    font_size: FontSize::Px(25.),
563                                    ..default()
564                                },
565                            ),
566                        ],
567                    ));
568
569                    content.with_child((
570                        hinting,
571                        Text::new("FiraSans "),
572                        TextFont {
573                            font: asset_server.load("fonts/FiraSans-Bold.ttf").into(),
574                            font_size: FontSize::Px(25.),
575                            ..default()
576                        },
577                        children![
578                            (
579                                TextSpan::new("MonaSans "),
580                                TextFont {
581                                    font: asset_server
582                                        .load("fonts/MonaSans-VariableFont.ttf")
583                                        .into(),
584                                    font_size: FontSize::Px(25.),
585                                    ..default()
586                                }
587                            ),
588                            (
589                                TextSpan::new("EBGaramond "),
590                                TextFont {
591                                    font: asset_server
592                                        .load("fonts/EBGaramond12-Regular.otf")
593                                        .into(),
594                                    font_size: FontSize::Px(25.),
595                                    ..default()
596                                },
597                            ),
598                            (
599                                TextSpan::new("FiraMono"),
600                                TextFont {
601                                    font: asset_server.load("fonts/FiraMono-Medium.ttf").into(),
602                                    font_size: FontSize::Px(25.),
603                                    ..default()
604                                },
605                            ),
606                        ],
607                    ));
608
609                    content.with_child((
610                        hinting,
611                        Text::new("FiraSans "),
612                        TextFont {
613                            font: asset_server.load("fonts/FiraSans-Bold.ttf").into(),
614                            font_size: FontSize::Px(25.),
615                            ..default()
616                        },
617                        children![
618                            (
619                                TextSpan::new("MonaSans_"),
620                                TextFont {
621                                    font: asset_server
622                                        .load("fonts/MonaSans-VariableFont.ttf")
623                                        .into(),
624                                    font_size: FontSize::Px(25.),
625                                    ..default()
626                                }
627                            ),
628                            (
629                                TextSpan::new("EBGaramond "),
630                                TextFont {
631                                    font: asset_server
632                                        .load("fonts/EBGaramond12-Regular.otf")
633                                        .into(),
634                                    font_size: FontSize::Px(25.),
635                                    ..default()
636                                },
637                            ),
638                            (
639                                TextSpan::new("FiraMono"),
640                                TextFont {
641                                    font: asset_server.load("fonts/FiraMono-Medium.ttf").into(),
642                                    font_size: FontSize::Px(25.),
643                                    ..default()
644                                },
645                            ),
646                        ],
647                    ));
648
649                    content.with_child((
650                        hinting,
651                        Text::new("FiraSans"),
652                        TextFont {
653                            font: asset_server.load("fonts/FiraSans-Bold.ttf").into(),
654                            font_size: FontSize::Px(25.),
655                            ..default()
656                        },
657                        children![
658                            TextSpan::new(" "),
659                            (
660                                TextSpan::new("MonaSans"),
661                                TextFont {
662                                    font: asset_server
663                                        .load("fonts/MonaSans-VariableFont.ttf")
664                                        .into(),
665                                    font_size: FontSize::Px(25.),
666                                    ..default()
667                                }
668                            ),
669                            TextSpan::new(" "),
670                            (
671                                TextSpan::new("EBGaramond"),
672                                TextFont {
673                                    font: asset_server
674                                        .load("fonts/EBGaramond12-Regular.otf")
675                                        .into(),
676                                    font_size: FontSize::Px(25.),
677                                    ..default()
678                                },
679                            ),
680                            TextSpan::new(" "),
681                            (
682                                TextSpan::new("FiraMono"),
683                                TextFont {
684                                    font: asset_server.load("fonts/FiraMono-Medium.ttf").into(),
685                                    font_size: FontSize::Px(25.),
686                                    ..default()
687                                },
688                            ),
689                        ],
690                    ));
691
692                    content.with_child((
693                        hinting,
694                        Text::new("Fira Sans_"),
695                        TextFont {
696                            font: asset_server.load("fonts/FiraSans-Bold.ttf").into(),
697                            font_size: FontSize::Px(25.),
698                            ..default()
699                        },
700                        children![
701                            (
702                                TextSpan::new("Mona Sans_"),
703                                TextFont {
704                                    font: asset_server
705                                        .load("fonts/MonaSans-VariableFont.ttf")
706                                        .into(),
707                                    font_size: FontSize::Px(25.),
708                                    ..default()
709                                }
710                            ),
711                            (
712                                TextSpan::new("EB Garamond_"),
713                                TextFont {
714                                    font: asset_server
715                                        .load("fonts/EBGaramond12-Regular.otf")
716                                        .into(),
717                                    font_size: FontSize::Px(25.),
718                                    ..default()
719                                },
720                            ),
721                            (
722                                TextSpan::new("Fira Mono"),
723                                TextFont {
724                                    font: asset_server.load("fonts/FiraMono-Medium.ttf").into(),
725                                    font_size: FontSize::Px(25.),
726                                    ..default()
727                                },
728                            ),
729                        ],
730                    ));
731
732                    content.with_child((
733                        hinting,
734                        Text::new("FontWeight(100)_"),
735                        TextFont {
736                            font: "Mona Sans".into(),
737                            font_size: FontSize::Px(25.),
738                            weight: FontWeight(100),
739                            ..default()
740                        },
741                        children![
742                            (
743                                TextSpan::new("FontWeight(500)_"),
744                                TextFont {
745                                    font: "Mona Sans".into(),
746                                    font_size: FontSize::Px(25.),
747                                    weight: FontWeight(500),
748                                    ..default()
749                                }
750                            ),
751                            (
752                                TextSpan::new("FontWeight(900)"),
753                                TextFont {
754                                    font: "Mona Sans".into(),
755                                    font_size: FontSize::Px(25.),
756                                    weight: FontWeight(900),
757                                    ..default()
758                                },
759                            ),
760                        ],
761                    ));
762
763                    content.with_child((
764                        hinting,
765                        Text::new("FiraSans_"),
766                        TextFont {
767                            font: asset_server.load("fonts/FiraSans-Bold.ttf").into(),
768                            font_size: FontSize::Px(25.),
769                            weight: FontWeight(900),
770                            ..default()
771                        },
772                        children![
773                            (
774                                TextSpan::new("MonaSans_"),
775                                TextFont {
776                                    font: asset_server
777                                        .load("fonts/MonaSans-VariableFont.ttf")
778                                        .into(),
779                                    font_size: FontSize::Px(25.),
780                                    weight: FontWeight(700),
781                                    ..default()
782                                }
783                            ),
784                            (
785                                TextSpan::new("EBGaramond_"),
786                                TextFont {
787                                    font: asset_server
788                                        .load("fonts/EBGaramond12-Regular.otf")
789                                        .into(),
790                                    font_size: FontSize::Px(25.),
791                                    weight: FontWeight(500),
792                                    ..default()
793                                },
794                            ),
795                            (
796                                TextSpan::new("FiraMono"),
797                                TextFont {
798                                    font: asset_server.load("fonts/FiraMono-Medium.ttf").into(),
799                                    font_size: FontSize::Px(25.),
800                                    weight: FontWeight(300),
801                                    ..default()
802                                },
803                            ),
804                        ],
805                    ));
806
807                    content.with_child((
808                        hinting,
809                        Text::new("FiraSans\t"),
810                        TextFont {
811                            font: asset_server.load("fonts/FiraSans-Bold.ttf").into(),
812                            font_size: FontSize::Px(25.),
813                            ..default()
814                        },
815                        children![
816                            (
817                                TextSpan::new("MonaSans\t"),
818                                TextFont {
819                                    font: asset_server
820                                        .load("fonts/MonaSans-VariableFont.ttf")
821                                        .into(),
822                                    font_size: FontSize::Px(25.),
823                                    ..default()
824                                }
825                            ),
826                            (
827                                TextSpan::new("EBGaramond\t"),
828                                TextFont {
829                                    font: asset_server
830                                        .load("fonts/EBGaramond12-Regular.otf")
831                                        .into(),
832                                    font_size: FontSize::Px(25.),
833                                    ..default()
834                                },
835                            ),
836                            (
837                                TextSpan::new("FiraMono"),
838                                TextFont {
839                                    font: asset_server.load("fonts/FiraMono-Medium.ttf").into(),
840                                    font_size: FontSize::Px(25.),
841                                    ..default()
842                                },
843                            ),
844                        ],
845                    ));
846
847                    for font_smoothing in [FontSmoothing::AntiAliased, FontSmoothing::None] {
848                        content.with_child((
849                            Text::new(format!("FontSmoothing::{:?}", font_smoothing)),
850                            TextFont {
851                                font: asset_server.load("fonts/MonaSans-VariableFont.ttf").into(),
852                                font_size: FontSize::Px(25.),
853                                font_smoothing,
854                                ..default()
855                            },
856                        ));
857                    }
858                }
859            });
860        });
861    }
862}
863
864mod font_lists {
865    use bevy::prelude::*;
866
867    const FONT_ASSETS: &[&str] = &[
868        "fonts/FiraSans-Bold.ttf",
869        "fonts/FiraMono-Medium.ttf",
870        "fonts/MonaSans-VariableFont.ttf",
871        "fonts/EBGaramond12-Regular.otf",
872    ];
873
874    const FONT_NAMES: &[&str] = &[
875        "Gabriola",
876        "Fira Sans",
877        "Fira Mono",
878        "Mona Sans",
879        "EB Garamond",
880    ];
881
882    #[derive(Resource)]
883    struct LoadedFontAssets {
884        _handles: Vec<Handle<Font>>,
885    }
886
887    pub fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
888        commands.spawn((Camera2d, DespawnOnExit(super::Scene::FontLists)));
889        commands.insert_resource(LoadedFontAssets {
890            _handles: FONT_ASSETS
891                .iter()
892                .map(|font_asset| asset_server.load(*font_asset))
893                .collect(),
894        });
895        commands.spawn((
896            Node {
897                flex_direction: FlexDirection::Column,
898                align_self: AlignSelf::Center,
899                justify_self: JustifySelf::Center,
900                row_gap: px(25),
901                ..default()
902            },
903            DespawnOnExit(super::Scene::FontLists),
904            children![
905                (
906                    Text::new("Font Lists"),
907                    TextFont::from_font_size(FontSize::Px(32.)),
908                    Underline,
909                ),
910                (
911                    Node {
912                        flex_direction: FlexDirection::Column,
913                        row_gap: px(6),
914                        ..default()
915                    },
916                    children![
917                        Text::new("FontSource::Families"),
918                        (
919                            Node {
920                                flex_direction: FlexDirection::Row,
921                                flex_wrap: FlexWrap::Wrap,
922                                padding: px(16).left(),
923                                column_gap: px(30),
924                                row_gap: px(30),
925                                ..default()
926                            },
927                            Children::spawn(SpawnIter(
928                                (0..FONT_NAMES.len())
929                                    .map(|start| {
930                                        FONT_NAMES
931                                            .iter()
932                                            .copied()
933                                            .cycle()
934                                            .skip(start)
935                                            .take(FONT_NAMES.len())
936                                            .collect::<Vec<_>>()
937                                            .join(", ")
938                                    })
939                                    .map(|list| {
940                                        (
941                                            Text::new(list.replace(", ", "\n")),
942                                            TextFont {
943                                                font: FontSource::families(list),
944                                                font_size: FontSize::Px(16.),
945                                                ..default()
946                                            },
947                                            Node {
948                                                padding: px(4.).all(),
949                                                ..default()
950                                            },
951                                            TextLayout::no_wrap(),
952                                            Outline::default(),
953                                        )
954                                    }),
955                            )),
956                        )
957                    ]
958                ),
959                (
960                    Node {
961                        flex_direction: FlexDirection::Column,
962                        row_gap: px(6),
963                        ..default()
964                    },
965                    children![
966                        Text::new("FontSource::List"),
967                        (
968                            Node {
969                                flex_direction: FlexDirection::Row,
970                                flex_wrap: FlexWrap::Wrap,
971                                padding: px(16).left(),
972                                column_gap: px(30),
973                                row_gap: px(30),
974                                ..default()
975                            },
976                            Children::spawn(SpawnIter(
977                                (0..FONT_NAMES.len())
978                                    .map(|start| {
979                                        FONT_NAMES
980                                            .iter()
981                                            .copied()
982                                            .cycle()
983                                            .skip(start)
984                                            .take(FONT_NAMES.len())
985                                            .collect::<Vec<_>>()
986                                    })
987                                    .map(|list| {
988                                        (
989                                            Text::new(list.join("\n")),
990                                            TextFont {
991                                                font: FontSource::list(list.iter().copied()),
992                                                font_size: FontSize::Px(16.),
993                                                ..default()
994                                            },
995                                            Node {
996                                                padding: px(4.).all(),
997                                                ..default()
998                                            },
999                                            TextLayout::no_wrap(),
1000                                            Outline::default(),
1001                                        )
1002                                    }),
1003                            )),
1004                        )
1005                    ]
1006                ),
1007            ],
1008        ));
1009    }
1010}
1011mod text_measurement {
1012    use bevy::prelude::*;
1013
1014    pub fn setup(mut commands: Commands) {
1015        commands.spawn((Camera2d, DespawnOnExit(super::Scene::TextMeasurement)));
1016
1017        commands
1018            .spawn((
1019                Node {
1020                    width: percent(100),
1021                    height: percent(100),
1022                    flex_direction: FlexDirection::Row,
1023                    column_gap: px(8),
1024                    padding: px(8).horizontal(),
1025                    ..default()
1026                },
1027                DespawnOnExit(super::Scene::TextMeasurement),
1028            ))
1029            .with_children(|parent| {
1030                let width = px(102);
1031                for (flex_direction, boxed) in [
1032                    (FlexDirection::Row, true),
1033                    (FlexDirection::Row, false),
1034                    (FlexDirection::Column, true),
1035                    (FlexDirection::Column, false),
1036                ] {
1037                    parent
1038                        .spawn(Node {
1039                            flex_direction: FlexDirection::Column,
1040                            ..default()
1041                        })
1042                        .with_children(|parent| {
1043                            for align_items in [
1044                                AlignItems::Baseline,
1045                                AlignItems::Center,
1046                                AlignItems::Stretch,
1047                                AlignItems::FlexStart,
1048                                AlignItems::FlexEnd,
1049                            ] {
1050                                parent.spawn((
1051                                    Node {
1052                                        margin: px(8).top(),
1053                                        ..default()
1054                                    },
1055                                    Text::new(format!("AlignItems::{align_items:?}")),
1056                                    TextFont::from_font_size(10.),
1057                                ));
1058                                if boxed {
1059                                    parent.spawn((
1060                                        Node {
1061                                            align_items,
1062                                            border: px(2).all(),
1063                                            padding: px(2).all(),
1064                                            flex_direction,
1065                                            ..default()
1066                                        },
1067                                        BorderColor::all(Color::WHITE),
1068                                        children![
1069                                            (
1070                                                Node {
1071                                                    width: px(32),
1072                                                    height: px(32),
1073                                                    ..default()
1074                                                },
1075                                                BackgroundColor(Color::WHITE),
1076                                            ),
1077                                            (
1078                                                Node { width, ..default() },
1079                                                children![(
1080                                                    Text::new("+300 Some Long Item Title"),
1081                                                    TextFont {
1082                                                        font_size: FontSize::Px(10.),
1083                                                        ..default()
1084                                                    },
1085                                                    BackgroundColor(Color::srgba(
1086                                                        0.95, 0.85, 0.2, 0.35
1087                                                    )),
1088                                                )]
1089                                            )
1090                                        ],
1091                                    ));
1092                                } else {
1093                                    parent.spawn((
1094                                        Node {
1095                                            align_items,
1096                                            border: px(2).all(),
1097                                            padding: px(2).all(),
1098                                            flex_direction,
1099                                            ..default()
1100                                        },
1101                                        BorderColor::all(Color::WHITE),
1102                                        children![
1103                                            (
1104                                                Node {
1105                                                    width: px(32),
1106                                                    height: px(32),
1107                                                    ..default()
1108                                                },
1109                                                BackgroundColor(Color::WHITE),
1110                                            ),
1111                                            (
1112                                                Node { width, ..default() },
1113                                                Text::new("+300 Some Long Item Title"),
1114                                                TextFont {
1115                                                    font_size: FontSize::Px(10.),
1116                                                    ..default()
1117                                                },
1118                                                BackgroundColor(Color::srgba(
1119                                                    0.95, 0.85, 0.2, 0.35
1120                                                )),
1121                                            )
1122                                        ],
1123                                    ));
1124                                }
1125                            }
1126                        });
1127                }
1128            });
1129    }
1130}
1131
1132mod grid {
1133    use bevy::{color::palettes::css::*, prelude::*};
1134
1135    pub fn setup(mut commands: Commands) {
1136        commands.spawn((Camera2d, DespawnOnExit(super::Scene::Grid)));
1137        // Top-level grid (app frame)
1138        commands.spawn((
1139            Node {
1140                display: Display::Grid,
1141                width: percent(100),
1142                height: percent(100),
1143                grid_template_columns: vec![GridTrack::min_content(), GridTrack::flex(1.0)],
1144                grid_template_rows: vec![
1145                    GridTrack::auto(),
1146                    GridTrack::flex(1.0),
1147                    GridTrack::px(40.),
1148                ],
1149                ..default()
1150            },
1151            BackgroundColor(Color::WHITE),
1152            DespawnOnExit(super::Scene::Grid),
1153            children![
1154                // Header
1155                (
1156                    Node {
1157                        display: Display::Grid,
1158                        grid_column: GridPlacement::span(2),
1159                        padding: UiRect::all(px(40)),
1160                        ..default()
1161                    },
1162                    BackgroundColor(RED.into()),
1163                ),
1164                // Main content grid (auto placed in row 2, column 1)
1165                (
1166                    Node {
1167                        height: percent(100),
1168                        aspect_ratio: Some(1.0),
1169                        display: Display::Grid,
1170                        grid_template_columns: RepeatedGridTrack::flex(3, 1.0),
1171                        grid_template_rows: RepeatedGridTrack::flex(2, 1.0),
1172                        row_gap: px(12),
1173                        column_gap: px(12),
1174                        ..default()
1175                    },
1176                    BackgroundColor(Color::srgb(0.25, 0.25, 0.25)),
1177                    children![
1178                        (Node::default(), BackgroundColor(ORANGE.into())),
1179                        (Node::default(), BackgroundColor(BISQUE.into())),
1180                        (Node::default(), BackgroundColor(BLUE.into())),
1181                        (Node::default(), BackgroundColor(CRIMSON.into())),
1182                        (Node::default(), BackgroundColor(AQUA.into())),
1183                    ]
1184                ),
1185                // Right side bar (auto placed in row 2, column 2)
1186                (Node::DEFAULT, BackgroundColor(BLACK.into())),
1187            ],
1188        ));
1189    }
Source

pub fn auto<T>() -> T
where T: From<GridTrack>,

Create a grid track which is automatically sized to fit its contents.

Examples found in repository?
examples/testbed/ui.rs (line 1145)
1135    pub fn setup(mut commands: Commands) {
1136        commands.spawn((Camera2d, DespawnOnExit(super::Scene::Grid)));
1137        // Top-level grid (app frame)
1138        commands.spawn((
1139            Node {
1140                display: Display::Grid,
1141                width: percent(100),
1142                height: percent(100),
1143                grid_template_columns: vec![GridTrack::min_content(), GridTrack::flex(1.0)],
1144                grid_template_rows: vec![
1145                    GridTrack::auto(),
1146                    GridTrack::flex(1.0),
1147                    GridTrack::px(40.),
1148                ],
1149                ..default()
1150            },
1151            BackgroundColor(Color::WHITE),
1152            DespawnOnExit(super::Scene::Grid),
1153            children![
1154                // Header
1155                (
1156                    Node {
1157                        display: Display::Grid,
1158                        grid_column: GridPlacement::span(2),
1159                        padding: UiRect::all(px(40)),
1160                        ..default()
1161                    },
1162                    BackgroundColor(RED.into()),
1163                ),
1164                // Main content grid (auto placed in row 2, column 1)
1165                (
1166                    Node {
1167                        height: percent(100),
1168                        aspect_ratio: Some(1.0),
1169                        display: Display::Grid,
1170                        grid_template_columns: RepeatedGridTrack::flex(3, 1.0),
1171                        grid_template_rows: RepeatedGridTrack::flex(2, 1.0),
1172                        row_gap: px(12),
1173                        column_gap: px(12),
1174                        ..default()
1175                    },
1176                    BackgroundColor(Color::srgb(0.25, 0.25, 0.25)),
1177                    children![
1178                        (Node::default(), BackgroundColor(ORANGE.into())),
1179                        (Node::default(), BackgroundColor(BISQUE.into())),
1180                        (Node::default(), BackgroundColor(BLUE.into())),
1181                        (Node::default(), BackgroundColor(CRIMSON.into())),
1182                        (Node::default(), BackgroundColor(AQUA.into())),
1183                    ]
1184                ),
1185                // Right side bar (auto placed in row 2, column 2)
1186                (Node::DEFAULT, BackgroundColor(BLACK.into())),
1187            ],
1188        ));
1189    }
1190}
1191
1192mod borders {
1193    use bevy::{color::palettes::css::*, prelude::*};
1194
1195    pub fn setup(mut commands: Commands) {
1196        commands.spawn((Camera2d, DespawnOnExit(super::Scene::Borders)));
1197        let root = commands
1198            .spawn((
1199                Node {
1200                    flex_wrap: FlexWrap::Wrap,
1201                    ..default()
1202                },
1203                DespawnOnExit(super::Scene::Borders),
1204            ))
1205            .id();
1206
1207        // all the different combinations of border edges
1208        let borders = [
1209            UiRect::default(),
1210            UiRect::all(px(20)),
1211            UiRect::left(px(20)),
1212            UiRect::vertical(px(20)),
1213            UiRect {
1214                left: px(40),
1215                top: px(20),
1216                ..Default::default()
1217            },
1218            UiRect {
1219                right: px(20),
1220                bottom: px(30),
1221                ..Default::default()
1222            },
1223            UiRect {
1224                right: px(20),
1225                top: px(40),
1226                bottom: px(20),
1227                ..Default::default()
1228            },
1229            UiRect {
1230                left: px(20),
1231                top: px(20),
1232                bottom: px(20),
1233                ..Default::default()
1234            },
1235            UiRect {
1236                left: px(20),
1237                right: px(20),
1238                bottom: px(40),
1239                ..Default::default()
1240            },
1241        ];
1242
1243        let non_zero = |x, y| x != px(0) && y != px(0);
1244        let border_size = |x, y| if non_zero(x, y) { f32::MAX } else { 0. };
1245
1246        for border in borders {
1247            for rounded in [true, false] {
1248                let border_node = commands
1249                    .spawn((
1250                        Node {
1251                            width: px(100),
1252                            height: px(100),
1253                            border,
1254                            margin: UiRect::all(px(30)),
1255                            align_items: AlignItems::Center,
1256                            justify_content: JustifyContent::Center,
1257                            border_radius: if rounded {
1258                                BorderRadius::px(
1259                                    border_size(border.left, border.top),
1260                                    border_size(border.right, border.top),
1261                                    border_size(border.right, border.bottom),
1262                                    border_size(border.left, border.bottom),
1263                                )
1264                            } else {
1265                                BorderRadius::ZERO
1266                            },
1267                            ..default()
1268                        },
1269                        BackgroundColor(MAROON.into()),
1270                        BorderColor::all(RED),
1271                        Outline {
1272                            width: px(10),
1273                            offset: px(10),
1274                            color: Color::WHITE,
1275                        },
1276                    ))
1277                    .id();
1278
1279                commands.entity(root).add_child(border_node);
1280            }
1281        }
1282    }
1283}
1284
1285mod elliptical_border_radius {
1286    use bevy::{color::palettes::css::*, prelude::*};
1287
1288    pub fn setup(mut commands: Commands, assets: Res<AssetServer>) {
1289        commands.spawn((
1290            Camera2d,
1291            DespawnOnExit(super::Scene::EllipticalBorderRadius),
1292        ));
1293        commands
1294            .spawn((
1295                Node {
1296                    width: percent(100),
1297                    height: percent(100),
1298                    flex_wrap: FlexWrap::Wrap,
1299                    column_gap: px(40),
1300                    row_gap: px(40),
1301                    margin: auto().all(),
1302                    padding: px(30).all(),
1303                    ..default()
1304                },
1305                BackgroundColor(DARK_GRAY.into()),
1306                DespawnOnExit(super::Scene::EllipticalBorderRadius),
1307            ))
1308            .with_children(|builder| {
1309                builder.spawn((
1310                    Node {
1311                        width: px(200),
1312                        height: px(100),
1313                        border: UiRect::all(px(8)),
1314                        border_radius: BorderRadius::new(
1315                            CornerRadius {
1316                                x: px(90),
1317                                y: px(24),
1318                            },
1319                            CornerRadius {
1320                                x: px(18),
1321                                y: px(70),
1322                            },
1323                            CornerRadius {
1324                                x: px(110),
1325                                y: px(32),
1326                            },
1327                            CornerRadius {
1328                                x: px(28),
1329                                y: px(58),
1330                            },
1331                        ),
1332                        ..default()
1333                    },
1334                    BackgroundColor(ORANGE.into()),
1335                    BackgroundGradient::from(LinearGradient {
1336                        stops: vec![
1337                            RED.into(),
1338                            Color::BLACK.into(),
1339                            BLUE.into(),
1340                            WHEAT.into(),
1341                            GREEN.into(),
1342                        ],
1343                        ..default()
1344                    }),
1345                    BorderColor::all(RED),
1346                    Outline {
1347                        width: px(4),
1348                        offset: px(8),
1349                        color: WHITE.into(),
1350                    },
1351                    BoxShadow::from(ShadowStyle {
1352                        blur_radius: px(5),
1353                        ..default()
1354                    }),
1355                ));
1356
1357                builder.spawn((
1358                    Node {
1359                        width: px(150),
1360                        height: px(150),
1361                        border: UiRect {
1362                            left: px(16),
1363                            right: px(4),
1364                            top: px(24),
1365                            bottom: px(8),
1366                        },
1367                        border_radius: BorderRadius::new(
1368                            CornerRadius {
1369                                x: percent(65),
1370                                y: percent(20),
1371                            },
1372                            CornerRadius {
1373                                x: percent(20),
1374                                y: percent(65),
1375                            },
1376                            CornerRadius {
1377                                x: percent(65),
1378                                y: percent(20),
1379                            },
1380                            CornerRadius {
1381                                x: percent(20),
1382                                y: percent(65),
1383                            },
1384                        ),
1385                        ..default()
1386                    },
1387                    BackgroundColor(MEDIUM_SEA_GREEN.into()),
1388                    BorderColor::all(DARK_GREEN),
1389                    Outline {
1390                        width: px(3),
1391                        offset: px(10),
1392                        color: LIME.into(),
1393                    },
1394                    BoxShadow::from(ShadowStyle {
1395                        blur_radius: px(5),
1396                        ..default()
1397                    }),
1398                ));
1399
1400                builder.spawn((
1401                    Node {
1402                        width: px(210),
1403                        height: px(75),
1404                        border: UiRect::axes(px(12), px(4)),
1405                        border_radius: BorderRadius::new(
1406                            CornerRadius {
1407                                x: px(140),
1408                                y: px(18),
1409                            },
1410                            CornerRadius {
1411                                x: px(140),
1412                                y: px(18),
1413                            },
1414                            CornerRadius {
1415                                x: px(42),
1416                                y: px(54),
1417                            },
1418                            CornerRadius {
1419                                x: px(42),
1420                                y: px(54),
1421                            },
1422                        ),
1423                        ..default()
1424                    },
1425                    BackgroundColor(DODGER_BLUE.into()),
1426                    BorderColor::all(NAVY),
1427                    Outline {
1428                        width: px(5),
1429                        offset: px(6),
1430                        color: SKY_BLUE.into(),
1431                    },
1432                    BoxShadow::from(ShadowStyle {
1433                        blur_radius: px(5),
1434                        ..default()
1435                    }),
1436                ));
1437                builder.spawn((
1438                    Node {
1439                        width: px(160),
1440                        height: px(120),
1441                        border: UiRect::axes(px(20), px(20)),
1442                        border_radius: BorderRadius::new(
1443                            CornerRadius {
1444                                x: px(50),
1445                                y: px(10),
1446                            },
1447                            CornerRadius {
1448                                x: px(50),
1449                                y: px(10),
1450                            },
1451                            CornerRadius {
1452                                x: px(50),
1453                                y: px(10),
1454                            },
1455                            CornerRadius {
1456                                x: px(50),
1457                                y: px(10),
1458                            },
1459                        ),
1460                        ..default()
1461                    },
1462                    BackgroundColor(RED.into()),
1463                    BorderColor::all(WHITE),
1464                    Outline {
1465                        width: px(3),
1466                        offset: px(5),
1467                        color: SKY_BLUE.into(),
1468                    },
1469                    BoxShadow::from(ShadowStyle {
1470                        blur_radius: px(5),
1471                        ..default()
1472                    }),
1473                ));
1474
1475                builder.spawn((
1476                    Node {
1477                        width: px(160),
1478                        height: px(120),
1479                        border: UiRect::axes(px(20), px(20)),
1480                        border_radius: BorderRadius::all(px(1000)),
1481                        ..default()
1482                    },
1483                    BackgroundColor(RED.into()),
1484                    BorderColor::all(WHITE),
1485                    Outline {
1486                        width: px(3),
1487                        offset: px(5),
1488                        color: SKY_BLUE.into(),
1489                    },
1490                    BoxShadow::from(ShadowStyle {
1491                        blur_radius: px(5),
1492                        ..default()
1493                    }),
1494                ));
1495
1496                builder.spawn((
1497                    Node {
1498                        width: px(160),
1499                        height: px(120),
1500                        border: UiRect::axes(px(20), px(20)),
1501                        border_radius: BorderRadius {
1502                            top_left: CornerRadius {
1503                                x: px(1000),
1504                                y: auto(),
1505                            },
1506                            top_right: CornerRadius {
1507                                x: auto(),
1508                                y: px(1000),
1509                            },
1510                            bottom_right: CornerRadius::circular(px(1000)),
1511                            bottom_left: CornerRadius::circular(px(1000)),
1512                        },
1513                        ..default()
1514                    },
1515                    BackgroundColor(RED.into()),
1516                    BorderColor::all(WHITE),
1517                    Outline {
1518                        width: px(3),
1519                        offset: px(5),
1520                        color: SKY_BLUE.into(),
1521                    },
1522                    BoxShadow::from(ShadowStyle {
1523                        blur_radius: px(5),
1524                        ..default()
1525                    }),
1526                ));
1527
1528                builder.spawn((
1529                    Node {
1530                        width: px(160),
1531                        height: px(120),
1532                        border: UiRect::axes(px(20), px(20)),
1533                        border_radius: BorderRadius::new(
1534                            CornerRadius {
1535                                x: px(25),
1536                                y: px(20),
1537                            },
1538                            CornerRadius {
1539                                x: px(20),
1540                                y: px(25),
1541                            },
1542                            CornerRadius {
1543                                x: px(20),
1544                                y: px(25),
1545                            },
1546                            CornerRadius {
1547                                x: px(20),
1548                                y: px(25),
1549                            },
1550                        ),
1551                        ..default()
1552                    },
1553                    BackgroundColor(RED.into()),
1554                    ImageNode::from(assets.load("branding/icon.png")),
1555                    BorderColor::all(WHITE),
1556                    Outline {
1557                        width: px(3),
1558                        offset: px(5),
1559                        color: SKY_BLUE.into(),
1560                    },
1561                    BoxShadow::from(ShadowStyle {
1562                        blur_radius: px(5),
1563                        ..default()
1564                    }),
1565                ));
1566
1567                builder.spawn((
1568                    Node {
1569                        width: px(160),
1570                        height: px(120),
1571                        border: UiRect::axes(px(10), px(10)),
1572                        border_radius: BorderRadius::new(
1573                            CornerRadius {
1574                                x: px(40),
1575                                y: px(30),
1576                            },
1577                            CornerRadius {
1578                                x: px(40),
1579                                y: px(30),
1580                            },
1581                            CornerRadius {
1582                                x: px(40),
1583                                y: px(30),
1584                            },
1585                            CornerRadius {
1586                                x: px(40),
1587                                y: px(30),
1588                            },
1589                        ),
1590                        ..default()
1591                    },
1592                    BackgroundColor(RED.into()),
1593                    BorderColor::all(WHITE),
1594                    Outline {
1595                        width: px(3),
1596                        offset: px(5),
1597                        color: SKY_BLUE.into(),
1598                    },
1599                    BoxShadow::from(ShadowStyle {
1600                        blur_radius: px(5),
1601                        ..default()
1602                    }),
1603                ));
1604
1605                builder.spawn((
1606                    Node {
1607                        width: px(160),
1608                        height: px(80),
1609                        border: UiRect::axes(px(10), px(10)),
1610                        border_radius: BorderRadius::new(
1611                            CornerRadius {
1612                                x: percent(50),
1613                                y: percent(50),
1614                            },
1615                            CornerRadius {
1616                                x: percent(50),
1617                                y: percent(50),
1618                            },
1619                            CornerRadius {
1620                                x: percent(50),
1621                                y: percent(50),
1622                            },
1623                            CornerRadius {
1624                                x: percent(50),
1625                                y: percent(50),
1626                            },
1627                        ),
1628                        ..default()
1629                    },
1630                    BackgroundColor(RED.into()),
1631                    BorderColor::all(WHITE),
1632                    ImageNode::from(assets.load("branding/icon.png")),
1633                    Outline {
1634                        width: px(3),
1635                        offset: px(5),
1636                        color: SKY_BLUE.into(),
1637                    },
1638                    BoxShadow::from(ShadowStyle {
1639                        blur_radius: px(5),
1640                        ..default()
1641                    }),
1642                ));
1643
1644                builder.spawn((
1645                    Node {
1646                        width: px(80),
1647                        height: px(160),
1648                        border: UiRect::axes(px(10), px(10)),
1649                        border_radius: BorderRadius::new(
1650                            CornerRadius {
1651                                x: percent(50),
1652                                y: percent(50),
1653                            },
1654                            CornerRadius {
1655                                x: percent(50),
1656                                y: percent(50),
1657                            },
1658                            CornerRadius {
1659                                x: percent(50),
1660                                y: percent(50),
1661                            },
1662                            CornerRadius {
1663                                x: percent(50),
1664                                y: percent(50),
1665                            },
1666                        ),
1667                        ..default()
1668                    },
1669                    BackgroundColor(RED.into()),
1670                    BorderColor::all(WHITE),
1671                    ImageNode::from(assets.load("branding/icon.png")),
1672                    Outline {
1673                        width: px(3),
1674                        offset: px(5),
1675                        color: SKY_BLUE.into(),
1676                    },
1677                    BoxShadow::from(ShadowStyle {
1678                        blur_radius: px(5),
1679                        ..default()
1680                    }),
1681                ));
1682
1683                builder.spawn((
1684                    Node {
1685                        width: px(160),
1686                        height: px(80),
1687                        border: UiRect::axes(px(20), px(10)),
1688                        border_radius: BorderRadius::new(
1689                            CornerRadius {
1690                                x: percent(50),
1691                                y: percent(50),
1692                            },
1693                            CornerRadius {
1694                                x: percent(50),
1695                                y: percent(50),
1696                            },
1697                            CornerRadius {
1698                                x: percent(50),
1699                                y: percent(50),
1700                            },
1701                            CornerRadius {
1702                                x: percent(50),
1703                                y: percent(50),
1704                            },
1705                        ),
1706                        ..default()
1707                    },
1708                    BackgroundColor(RED.into()),
1709                    BorderColor::all(WHITE),
1710                    ImageNode::from(assets.load("branding/icon.png")),
1711                    Outline {
1712                        width: px(3),
1713                        offset: px(5),
1714                        color: SKY_BLUE.into(),
1715                    },
1716                    BoxShadow::from(ShadowStyle {
1717                        blur_radius: px(5),
1718                        ..default()
1719                    }),
1720                ));
1721
1722                builder.spawn((
1723                    Node {
1724                        width: px(80),
1725                        height: px(160),
1726                        border: UiRect::all(px(10)).with_right(px(25)),
1727                        border_radius: BorderRadius::new(
1728                            CornerRadius {
1729                                x: percent(50),
1730                                y: percent(50),
1731                            },
1732                            CornerRadius {
1733                                x: percent(50),
1734                                y: percent(50),
1735                            },
1736                            CornerRadius {
1737                                x: percent(50),
1738                                y: percent(50),
1739                            },
1740                            CornerRadius {
1741                                x: percent(50),
1742                                y: percent(50),
1743                            },
1744                        ),
1745                        ..default()
1746                    },
1747                    BackgroundColor(RED.into()),
1748                    BorderColor::all(WHITE),
1749                    Outline {
1750                        width: px(3),
1751                        offset: px(5),
1752                        color: SKY_BLUE.into(),
1753                    },
1754                    BoxShadow::from(ShadowStyle {
1755                        blur_radius: px(5),
1756                        ..default()
1757                    }),
1758                ));
1759
1760                builder.spawn((
1761                    Node {
1762                        width: px(160),
1763                        height: px(80),
1764                        border: UiRect::all(px(5)),
1765                        border_radius: BorderRadius::new(
1766                            CornerRadius {
1767                                x: percent(50),
1768                                y: percent(50),
1769                            },
1770                            CornerRadius {
1771                                x: percent(50),
1772                                y: percent(50),
1773                            },
1774                            CornerRadius {
1775                                x: percent(50),
1776                                y: percent(50),
1777                            },
1778                            CornerRadius {
1779                                x: px(20),
1780                                y: px(20),
1781                            },
1782                        ),
1783                        ..default()
1784                    },
1785                    BackgroundColor(RED.into()),
1786                    BorderColor::all(WHITE),
1787                    ImageNode::from(assets.load("branding/icon.png")),
1788                    Outline {
1789                        width: px(3),
1790                        offset: px(5),
1791                        color: SKY_BLUE.into(),
1792                    },
1793                    BoxShadow::from(ShadowStyle {
1794                        blur_radius: px(5),
1795                        ..default()
1796                    }),
1797                ));
1798            });
1799    }
1800}
1801
1802mod box_shadow {
1803    use bevy::{color::palettes::css::*, prelude::*};
1804
1805    pub fn setup(mut commands: Commands) {
1806        commands.spawn((Camera2d, DespawnOnExit(super::Scene::BoxShadow)));
1807
1808        commands
1809            .spawn((
1810                Node {
1811                    width: percent(100),
1812                    height: percent(100),
1813                    padding: UiRect::all(px(30)),
1814                    column_gap: px(200),
1815                    flex_wrap: FlexWrap::Wrap,
1816                    ..default()
1817                },
1818                BackgroundColor(GREEN.into()),
1819                DespawnOnExit(super::Scene::BoxShadow),
1820            ))
1821            .with_children(|commands| {
1822                let example_nodes = [
1823                    (
1824                        Vec2::splat(100.),
1825                        Vec2::ZERO,
1826                        10.,
1827                        0.,
1828                        BorderRadius::bottom_right(px(10)),
1829                    ),
1830                    (Vec2::new(200., 50.), Vec2::ZERO, 10., 0., BorderRadius::MAX),
1831                    (
1832                        Vec2::new(100., 50.),
1833                        Vec2::ZERO,
1834                        10.,
1835                        10.,
1836                        BorderRadius::ZERO,
1837                    ),
1838                    (
1839                        Vec2::splat(100.),
1840                        Vec2::splat(20.),
1841                        10.,
1842                        10.,
1843                        BorderRadius::bottom_right(px(10)),
1844                    ),
1845                    (
1846                        Vec2::splat(100.),
1847                        Vec2::splat(50.),
1848                        0.,
1849                        10.,
1850                        BorderRadius::ZERO,
1851                    ),
1852                    (
1853                        Vec2::new(50., 100.),
1854                        Vec2::splat(10.),
1855                        0.,
1856                        10.,
1857                        BorderRadius::MAX,
1858                    ),
1859                ];
1860
1861                for (size, offset, spread, blur, border_radius) in example_nodes {
1862                    commands.spawn((
1863                        Node {
1864                            width: px(size.x),
1865                            height: px(size.y),
1866                            border: UiRect::all(px(2)),
1867                            border_radius,
1868                            ..default()
1869                        },
1870                        BorderColor::all(WHITE),
1871                        BackgroundColor(BLUE.into()),
1872                        BoxShadow::new(
1873                            Color::BLACK.with_alpha(0.9),
1874                            percent(offset.x),
1875                            percent(offset.y),
1876                            percent(spread),
1877                            px(blur),
1878                        ),
1879                    ));
1880                }
1881            });
1882    }
1883}
1884
1885mod text_wrap {
1886    use bevy::prelude::*;
1887
1888    pub fn setup(mut commands: Commands) {
1889        commands.spawn((Camera2d, DespawnOnExit(super::Scene::TextWrap)));
1890
1891        let root = commands
1892            .spawn((
1893                Node {
1894                    flex_direction: FlexDirection::Column,
1895                    width: px(200),
1896                    height: percent(100),
1897                    overflow: Overflow::clip_x(),
1898                    ..default()
1899                },
1900                BackgroundColor(Color::BLACK),
1901                DespawnOnExit(super::Scene::TextWrap),
1902            ))
1903            .id();
1904
1905        for linebreak in [
1906            LineBreak::AnyCharacter,
1907            LineBreak::WordBoundary,
1908            LineBreak::WordOrCharacter,
1909            LineBreak::NoWrap,
1910        ] {
1911            let messages = [
1912                "Lorem ipsum dolor sit amet, consectetur adipiscing elit.".to_string(),
1913                "pneumonoultramicroscopicsilicovolcanoconiosis".to_string(),
1914            ];
1915
1916            for (j, message) in messages.into_iter().enumerate() {
1917                commands.entity(root).with_child((
1918                    Text(message.clone()),
1919                    TextLayout::new(Justify::Left, linebreak),
1920                    BackgroundColor(Color::srgb(0.8 - j as f32 * 0.3, 0., 0.)),
1921                ));
1922            }
1923        }
1924    }
1925}
1926
1927mod overflow {
1928    use bevy::{color::palettes::css::*, prelude::*};
1929
1930    pub fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
1931        commands.spawn((Camera2d, DespawnOnExit(super::Scene::Overflow)));
1932        let image = asset_server.load("branding/icon.png");
1933
1934        commands
1935            .spawn((
1936                Node {
1937                    width: percent(100),
1938                    height: percent(100),
1939                    align_items: AlignItems::Center,
1940                    justify_content: JustifyContent::SpaceAround,
1941                    ..Default::default()
1942                },
1943                BackgroundColor(BLUE.into()),
1944                DespawnOnExit(super::Scene::Overflow),
1945            ))
1946            .with_children(|parent| {
1947                for overflow in [
1948                    Overflow::visible(),
1949                    Overflow::clip_x(),
1950                    Overflow::clip_y(),
1951                    Overflow::clip(),
1952                ] {
1953                    parent
1954                        .spawn((
1955                            Node {
1956                                width: px(100),
1957                                height: px(100),
1958                                padding: UiRect {
1959                                    left: px(25),
1960                                    top: px(25),
1961                                    ..Default::default()
1962                                },
1963                                border: UiRect::all(px(5)),
1964                                overflow,
1965                                ..default()
1966                            },
1967                            BorderColor::all(RED),
1968                            BackgroundColor(Color::WHITE),
1969                        ))
1970                        .with_children(|parent| {
1971                            parent.spawn((
1972                                ImageNode::new(image.clone()),
1973                                Node {
1974                                    min_width: px(100),
1975                                    min_height: px(100),
1976                                    ..default()
1977                                },
1978                                Outline {
1979                                    width: px(2),
1980                                    offset: px(2),
1981                                    color: Color::NONE,
1982                                },
1983                            ));
1984                        });
1985                }
1986            });
1987    }
1988}
1989
1990mod slice {
1991    use bevy::prelude::*;
1992
1993    pub fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
1994        commands.spawn((Camera2d, DespawnOnExit(super::Scene::Slice)));
1995        let image = asset_server.load("textures/fantasy_ui_borders/numbered_slices.png");
1996
1997        let slicer = TextureSlicer {
1998            border: BorderRect::all(16.0),
1999            center_scale_mode: SliceScaleMode::Tile { stretch_value: 1.0 },
2000            sides_scale_mode: SliceScaleMode::Tile { stretch_value: 1.0 },
2001            ..default()
2002        };
2003        commands
2004            .spawn((
2005                Node {
2006                    width: percent(100),
2007                    height: percent(100),
2008                    flex_direction: FlexDirection::Column,
2009                    justify_content: JustifyContent::SpaceAround,
2010                    align_content: AlignContent::Center,
2011                    ..default()
2012                },
2013                DespawnOnExit(super::Scene::Slice),
2014            ))
2015            .with_children(|parent| {
2016                for visual_box in [
2017                    VisualBox::BorderBox,
2018                    VisualBox::PaddingBox,
2019                    VisualBox::ContentBox,
2020                ] {
2021                    parent
2022                        .spawn(Node {
2023                            justify_content: JustifyContent::SpaceAround,
2024                            ..default()
2025                        })
2026                        .with_children(|parent| {
2027                            for [w, h] in [[200.0, 200.0], [300.0, 200.0], [150., 200.0]] {
2028                                parent.spawn((
2029                                    ImageNode {
2030                                        image: image.clone(),
2031                                        image_mode: NodeImageMode::Sliced(slicer.clone()),
2032                                        visual_box,
2033                                        ..default()
2034                                    },
2035                                    Node {
2036                                        width: px(w),
2037                                        height: px(h),
2038                                        border: px(20.).all(),
2039                                        padding: px(20.).all(),
2040                                        ..default()
2041                                    },
2042                                    Outline {
2043                                        width: px(2.),
2044                                        ..default()
2045                                    },
2046                                ));
2047                            }
2048
2049                            parent.spawn((
2050                                ImageNode {
2051                                    image: asset_server
2052                                        .load("textures/fantasy_ui_borders/panel-border-010.png"),
2053                                    image_mode: NodeImageMode::Sliced(TextureSlicer {
2054                                        border: BorderRect::all(22.0),
2055                                        center_scale_mode: SliceScaleMode::Stretch,
2056                                        sides_scale_mode: SliceScaleMode::Stretch,
2057                                        max_corner_scale: 1.0,
2058                                    }),
2059                                    visual_box,
2060                                    ..Default::default()
2061                                },
2062                                Node {
2063                                    width: px(200),
2064                                    height: px(200),
2065                                    border: px(20.).all(),
2066                                    padding: px(20.).all(),
2067                                    ..default()
2068                                },
2069                                Outline {
2070                                    color: bevy::color::palettes::css::DARK_CYAN.into(),
2071                                    width: px(2.),
2072                                    ..default()
2073                                },
2074                                BackgroundColor(bevy::color::palettes::css::NAVY.into()),
2075                            ));
2076                        });
2077                }
2078            });
2079    }
2080}
2081
2082mod layout_rounding {
2083    use bevy::{color::palettes::css::*, prelude::*};
2084
2085    pub fn setup(mut commands: Commands) {
2086        commands.spawn((Camera2d, DespawnOnExit(super::Scene::LayoutRounding)));
2087
2088        commands
2089            .spawn((
2090                Node {
2091                    display: Display::Grid,
2092                    width: percent(100),
2093                    height: percent(100),
2094                    grid_template_rows: vec![RepeatedGridTrack::fr(10, 1.)],
2095                    ..Default::default()
2096                },
2097                BackgroundColor(Color::WHITE),
2098                DespawnOnExit(super::Scene::LayoutRounding),
2099            ))
2100            .with_children(|commands| {
2101                for i in 2..12 {
2102                    commands
2103                        .spawn(Node {
2104                            display: Display::Grid,
2105                            grid_template_columns: vec![RepeatedGridTrack::fr(i, 1.)],
2106                            ..Default::default()
2107                        })
2108                        .with_children(|commands| {
2109                            for _ in 0..i {
2110                                commands.spawn((
2111                                    Node {
2112                                        border: UiRect::all(px(5)),
2113                                        ..Default::default()
2114                                    },
2115                                    BackgroundColor(MAROON.into()),
2116                                    BorderColor::all(DARK_BLUE),
2117                                ));
2118                            }
2119                        });
2120                }
2121            });
2122    }
2123}
2124
2125mod linear_gradient {
2126    use bevy::camera::Camera2d;
2127    use bevy::color::palettes::css::BLUE;
2128    use bevy::color::palettes::css::LIME;
2129    use bevy::color::palettes::css::RED;
2130    use bevy::color::palettes::css::YELLOW;
2131    use bevy::color::Color;
2132    use bevy::ecs::prelude::*;
2133    use bevy::state::state_scoped::DespawnOnExit;
2134    use bevy::text::TextFont;
2135    use bevy::ui::widget::Text;
2136    use bevy::ui::AlignItems;
2137    use bevy::ui::BackgroundGradient;
2138    use bevy::ui::ColorStop;
2139    use bevy::ui::GridPlacement;
2140    use bevy::ui::InterpolationColorSpace;
2141    use bevy::ui::JustifyContent;
2142    use bevy::ui::LinearGradient;
2143    use bevy::ui::Node;
2144    use bevy::ui::PositionType;
2145    use bevy::utils::default;
2146
2147    pub fn setup(mut commands: Commands) {
2148        commands.spawn((Camera2d, DespawnOnExit(super::Scene::LinearGradient)));
2149        commands
2150            .spawn((
2151                Node {
2152                    flex_direction: bevy::ui::FlexDirection::Column,
2153                    width: bevy::ui::percent(100),
2154                    height: bevy::ui::percent(100),
2155                    justify_content: JustifyContent::Center,
2156                    align_items: AlignItems::Center,
2157                    row_gap: bevy::ui::px(5),
2158                    ..default()
2159                },
2160                DespawnOnExit(super::Scene::LinearGradient),
2161            ))
2162            .with_children(|commands| {
2163                let mut i = 0;
2164                commands
2165                    .spawn(Node {
2166                        display: bevy::ui::Display::Grid,
2167                        row_gap: bevy::ui::px(4),
2168                        column_gap: bevy::ui::px(4),
2169                        ..Default::default()
2170                    })
2171                    .with_children(|commands| {
2172                        for stops in [
2173                            vec![ColorStop::auto(RED), ColorStop::auto(YELLOW)],
2174                            vec![
2175                                ColorStop::auto(Color::BLACK),
2176                                ColorStop::auto(RED),
2177                                ColorStop::auto(Color::WHITE),
2178                            ],
2179                            vec![
2180                                Color::hsl(180.71191, 0.0, 0.3137255).into(),
2181                                Color::hsl(180.71191, 0.5, 0.3137255).into(),
2182                                Color::hsl(180.71191, 1.0, 0.3137255).into(),
2183                            ],
2184                            vec![
2185                                Color::hsl(180.71191, 0.825, 0.0).into(),
2186                                Color::hsl(180.71191, 0.825, 0.5).into(),
2187                                Color::hsl(180.71191, 0.825, 1.0).into(),
2188                            ],
2189                            vec![
2190                                Color::hsl(0.0 + 0.0001, 1.0, 0.5).into(),
2191                                Color::hsl(180.0, 1.0, 0.5).into(),
2192                                Color::hsl(360.0 - 0.0001, 1.0, 0.5).into(),
2193                            ],
2194                            vec![
2195                                Color::WHITE.into(),
2196                                RED.into(),
2197                                LIME.into(),
2198                                BLUE.into(),
2199                                Color::BLACK.into(),
2200                            ],
2201                        ] {
2202                            for color_space in [
2203                                InterpolationColorSpace::LinearRgba,
2204                                InterpolationColorSpace::Srgba,
2205                                InterpolationColorSpace::Oklaba,
2206                                InterpolationColorSpace::Oklcha,
2207                                InterpolationColorSpace::OklchaLong,
2208                                InterpolationColorSpace::Hsla,
2209                                InterpolationColorSpace::HslaLong,
2210                                InterpolationColorSpace::Hsva,
2211                                InterpolationColorSpace::HsvaLong,
2212                            ] {
2213                                let row = i % 18 + 1;
2214                                let column = i / 18 + 1;
2215                                i += 1;
2216
2217                                commands.spawn((
2218                                    Node {
2219                                        grid_row: GridPlacement::start(row as i16 + 1),
2220                                        grid_column: GridPlacement::start(column as i16 + 1),
2221                                        justify_content: JustifyContent::SpaceEvenly,
2222                                        ..Default::default()
2223                                    },
2224                                    children![(
2225                                        Node {
2226                                            height: bevy::ui::px(30),
2227                                            width: bevy::ui::px(300),
2228                                            justify_content: JustifyContent::Center,
2229                                            ..Default::default()
2230                                        },
2231                                        BackgroundGradient::from(LinearGradient {
2232                                            color_space,
2233                                            angle: LinearGradient::TO_RIGHT,
2234                                            stops: stops.clone(),
2235                                        }),
2236                                        children![
2237                                            Node {
2238                                                position_type: PositionType::Absolute,
2239                                                ..default()
2240                                            },
2241                                            TextFont::from_font_size(10.),
2242                                            Text(format!("{color_space:?}")),
2243                                        ]
2244                                    )],
2245                                ));
2246                            }
2247                        }
2248                    });
2249            });
2250    }
2251}
2252
2253mod radial_gradient {
2254    use bevy::color::palettes::css::RED;
2255    use bevy::color::palettes::tailwind::GRAY_700;
2256    use bevy::prelude::*;
2257    use bevy::ui::ColorStop;
2258
2259    const CELL_SIZE: f32 = 80.;
2260    const GAP: f32 = 10.;
2261
2262    pub fn setup(mut commands: Commands) {
2263        let color_stops = vec![
2264            ColorStop::new(Color::BLACK, px(5)),
2265            ColorStop::new(Color::WHITE, px(5)),
2266            ColorStop::new(Color::WHITE, percent(100)),
2267            ColorStop::auto(RED),
2268        ];
2269
2270        commands.spawn((Camera2d, DespawnOnExit(super::Scene::RadialGradient)));
2271        commands
2272            .spawn((
2273                Node {
2274                    width: percent(100),
2275                    height: percent(100),
2276                    display: Display::Grid,
2277                    align_items: AlignItems::Start,
2278                    grid_template_columns: vec![RepeatedGridTrack::px(
2279                        GridTrackRepetition::AutoFill,
2280                        CELL_SIZE,
2281                    )],
2282                    grid_auto_flow: GridAutoFlow::Row,
2283                    row_gap: px(GAP),
2284                    column_gap: px(GAP),
2285                    padding: UiRect::all(px(GAP)),
2286                    ..default()
2287                },
2288                DespawnOnExit(super::Scene::RadialGradient),
2289            ))
2290            .with_children(|commands| {
2291                for (shape, shape_label) in [
2292                    (RadialGradientShape::ClosestSide, "ClosestSide"),
2293                    (RadialGradientShape::FarthestSide, "FarthestSide"),
2294                    (RadialGradientShape::Circle(percent(55)), "Circle(55%)"),
2295                    (RadialGradientShape::FarthestCorner, "FarthestCorner"),
2296                ] {
2297                    for (position, position_label) in [
2298                        (UiPosition::TOP_LEFT, "TOP_LEFT"),
2299                        (UiPosition::LEFT, "LEFT"),
2300                        (UiPosition::BOTTOM_LEFT, "BOTTOM_LEFT"),
2301                        (UiPosition::TOP, "TOP"),
2302                        (UiPosition::CENTER, "CENTER"),
2303                        (UiPosition::BOTTOM, "BOTTOM"),
2304                        (UiPosition::TOP_RIGHT, "TOP_RIGHT"),
2305                        (UiPosition::RIGHT, "RIGHT"),
2306                        (UiPosition::BOTTOM_RIGHT, "BOTTOM_RIGHT"),
2307                    ] {
2308                        for (w, h) in [(CELL_SIZE, CELL_SIZE), (CELL_SIZE, CELL_SIZE / 2.)] {
2309                            commands
2310                                .spawn((
2311                                    BackgroundColor(GRAY_700.into()),
2312                                    Node {
2313                                        display: Display::Grid,
2314                                        width: px(CELL_SIZE),
2315                                        ..Default::default()
2316                                    },
2317                                ))
2318                                .with_children(|commands| {
2319                                    commands.spawn((
2320                                        Node {
2321                                            margin: UiRect::all(px(2)),
2322                                            ..default()
2323                                        },
2324                                        Text(format!("{shape_label}\n{position_label}")),
2325                                        TextFont::from_font_size(9.),
2326                                    ));
2327                                    commands.spawn((
2328                                        Node {
2329                                            width: px(w),
2330                                            height: px(h),
2331                                            ..default()
2332                                        },
2333                                        BackgroundGradient::from(RadialGradient {
2334                                            stops: color_stops.clone(),
2335                                            position,
2336                                            shape,
2337                                            ..default()
2338                                        }),
2339                                    ));
2340                                });
2341                        }
2342                    }
2343                }
2344            });
2345    }
2346}
2347
2348mod transformations {
2349    use bevy::{color::palettes::css::*, prelude::*};
2350
2351    pub fn setup(mut commands: Commands) {
2352        commands.spawn((Camera2d, DespawnOnExit(super::Scene::Transformations)));
2353        commands
2354            .spawn((
2355                Node {
2356                    width: percent(100),
2357                    height: percent(100),
2358                    display: Display::Block,
2359                    ..default()
2360                },
2361                DespawnOnExit(super::Scene::Transformations),
2362            ))
2363            .with_children(|parent| {
2364                for (transformation, label, background) in [
2365                    (
2366                        UiTransform::from_rotation(Rot2::degrees(45.)),
2367                        "Rotate 45 degrees",
2368                        RED,
2369                    ),
2370                    (
2371                        UiTransform::from_scale(Vec2::new(2., 0.5)),
2372                        "Scale 2.x 0.5y",
2373                        GREEN,
2374                    ),
2375                    (
2376                        UiTransform::from_translation(Val2::px(-50., 50.)),
2377                        "Translate -50px x +50px y",
2378                        BLUE,
2379                    ),
2380                    (
2381                        UiTransform {
2382                            translation: Val2::px(50., 0.),
2383                            scale: Vec2::new(-1., 1.),
2384                            rotation: Rot2::degrees(30.),
2385                        },
2386                        "T 50px x\nS -1.x (refl)\nR 30deg",
2387                        DARK_CYAN,
2388                    ),
2389                ] {
2390                    parent
2391                        .spawn((Node {
2392                            width: percent(100),
2393                            margin: UiRect {
2394                                top: px(50),
2395                                bottom: px(50),
2396                                ..default()
2397                            },
2398                            align_items: AlignItems::Center,
2399                            justify_content: JustifyContent::SpaceAround,
2400                            ..default()
2401                        },))
2402                        .with_children(|row| {
2403                            row.spawn((
2404                                Text::new("Before Tf"),
2405                                Node {
2406                                    width: px(100),
2407                                    height: px(100),
2408                                    border_radius: BorderRadius::bottom_right(px(25.)),
2409                                    ..default()
2410                                },
2411                                BackgroundColor(background.into()),
2412                                TextFont::default(),
2413                            ));
2414                            row.spawn((
2415                                Text::new(label),
2416                                Node {
2417                                    width: px(100),
2418                                    height: px(100),
2419                                    border_radius: BorderRadius::bottom_right(px(25.)),
2420                                    ..default()
2421                                },
2422                                BackgroundColor(background.into()),
2423                                transformation,
2424                                TextFont::default(),
2425                            ));
2426                        });
2427                }
2428            });
2429    }
2430}
2431
2432#[cfg(feature = "bevy_ui_debug")]
2433mod debug_outlines {
2434    use bevy::{
2435        color::palettes::css::{BLUE, GRAY, RED},
2436        prelude::*,
2437        ui_render::UiDebugOptions,
2438    };
2439
2440    pub fn setup(mut commands: Commands, mut debug_options: ResMut<GlobalUiDebugOptions>) {
2441        debug_options.enabled = true;
2442        debug_options.line_width = 5.;
2443        debug_options.line_color_override = Some(LinearRgba::GREEN);
2444        debug_options.show_hidden = true;
2445        debug_options.show_clipped = true;
2446
2447        let debug_options: UiDebugOptions = (*debug_options.as_ref()).into();
2448
2449        commands.spawn((Camera2d, DespawnOnExit(super::Scene::DebugOutlines)));
2450        commands
2451            .spawn((
2452                Node {
2453                    width: percent(100),
2454                    height: percent(50),
2455                    align_items: AlignItems::Center,
2456                    justify_content: JustifyContent::SpaceAround,
2457                    ..default()
2458                },
2459                DespawnOnExit(super::Scene::DebugOutlines),
2460            ))
2461            .with_children(|parent| {
2462                parent.spawn((
2463                    Node {
2464                        width: px(100),
2465                        height: px(100),
2466                        ..default()
2467                    },
2468                    BackgroundColor(GRAY.into()),
2469                    UiTransform::from_rotation(Rot2::degrees(45.)),
2470                ));
2471
2472                parent.spawn((Text::new("Regular Text"), TextFont::default()));
2473
2474                parent.spawn((
2475                    Node {
2476                        width: px(100),
2477                        height: px(100),
2478                        ..default()
2479                    },
2480                    Text::new("Invisible"),
2481                    BackgroundColor(GRAY.into()),
2482                    TextFont::default(),
2483                    Visibility::Hidden,
2484                ));
2485
2486                parent
2487                    .spawn((
2488                        Node {
2489                            width: px(100),
2490                            height: px(100),
2491                            padding: UiRect {
2492                                left: px(25),
2493                                top: px(25),
2494                                ..Default::default()
2495                            },
2496                            overflow: Overflow::clip(),
2497                            ..default()
2498                        },
2499                        BackgroundColor(RED.into()),
2500                    ))
2501                    .with_children(|child| {
2502                        child.spawn((
2503                            Node {
2504                                min_width: px(100),
2505                                min_height: px(100),
2506                                ..default()
2507                            },
2508                            BackgroundColor(BLUE.into()),
2509                        ));
2510                    });
2511            });
2512
2513        commands
2514            .spawn((
2515                Node {
2516                    width: percent(100),
2517                    height: percent(50),
2518                    top: percent(50),
2519                    align_items: AlignItems::Center,
2520                    justify_content: JustifyContent::SpaceAround,
2521                    ..default()
2522                },
2523                DespawnOnExit(super::Scene::DebugOutlines),
2524            ))
2525            .with_children(|parent| {
2526                parent.spawn((
2527                    Node {
2528                        width: px(200),
2529                        height: px(200),
2530                        border: UiRect {
2531                            top: px(10),
2532                            bottom: px(20),
2533                            left: px(30),
2534                            right: px(40),
2535                        },
2536                        border_radius: BorderRadius::bottom_right(px(10)),
2537                        padding: UiRect {
2538                            top: px(40),
2539                            bottom: px(30),
2540                            left: px(20),
2541                            right: px(10),
2542                        },
2543                        ..default()
2544                    },
2545                    children![(
2546                        Text::new("border padding content outlines"),
2547                        TextFont::default(),
2548                        UiDebugOptions {
2549                            enabled: false,
2550                            ..default()
2551                        }
2552                    )],
2553                    UiDebugOptions {
2554                        outline_border_box: true,
2555                        outline_padding_box: true,
2556                        outline_content_box: true,
2557                        ignore_border_radius: false,
2558                        ..debug_options
2559                    },
2560                ));
2561
2562                // Vertical scrollbar (non-functional)
2563                parent.spawn((
2564                    Node {
2565                        flex_direction: FlexDirection::Column,
2566                        width: px(90),
2567                        height: px(230),
2568                        overflow: Overflow::scroll_y(),
2569                        scrollbar_width: 20.,
2570                        ..default()
2571                    },
2572                    ScrollPosition(Vec2::new(180., 180.)),
2573                    UiDebugOptions {
2574                        line_width: 3.,
2575                        outline_scrollbars: true,
2576                        show_hidden: false,
2577                        show_clipped: false,
2578                        ..debug_options
2579                    },
2580                    Children::spawn(SpawnIter((0..20).map(move |i| {
2581                        (
2582                            Node::default(),
2583                            children![(
2584                                Text(format!("Item {i}")),
2585                                UiDebugOptions {
2586                                    enabled: false,
2587                                    ..default()
2588                                }
2589                            )],
2590                            UiDebugOptions {
2591                                enabled: false,
2592                                ..default()
2593                            },
2594                        )
2595                    }))),
2596                ));
2597
2598                // Horizontal scrollbar (non-functional)
2599                parent.spawn((
2600                    Node {
2601                        flex_direction: FlexDirection::Row,
2602                        width: px(156),
2603                        height: px(70),
2604                        overflow: Overflow::scroll_x(),
2605                        scrollbar_width: 10.,
2606                        ..default()
2607                    },
2608                    UiDebugOptions {
2609                        line_width: 3.,
2610                        outline_scrollbars: true,
2611                        show_hidden: false,
2612                        show_clipped: false,
2613                        ..debug_options
2614                    },
2615                    Children::spawn(SpawnIter((0..20).map(move |i| {
2616                        (
2617                            Node::default(),
2618                            children![(
2619                                Text(format!("Item {i}")),
2620                                UiDebugOptions {
2621                                    enabled: false,
2622                                    ..default()
2623                                }
2624                            )],
2625                            UiDebugOptions {
2626                                enabled: false,
2627                                ..default()
2628                            },
2629                        )
2630                    }))),
2631                ));
2632
2633                // bi-directional scrollbar (non-functional)
2634                parent.spawn((
2635                    Node {
2636                        flex_direction: FlexDirection::Column,
2637                        width: px(230),
2638                        height: px(125),
2639                        overflow: Overflow::scroll(),
2640                        scrollbar_width: 20.,
2641                        ..default()
2642                    },
2643                    ScrollPosition(Vec2::new(300., 0.)),
2644                    UiDebugOptions {
2645                        line_width: 3.,
2646                        outline_scrollbars: true,
2647                        show_hidden: false,
2648                        show_clipped: false,
2649                        ..debug_options
2650                    },
2651                    Children::spawn(SpawnIter((0..6).map(move |i| {
2652                        (
2653                            Node {
2654                                flex_direction: FlexDirection::Row,
2655                                ..default()
2656                            },
2657                            Children::spawn(SpawnIter((0..6).map({
2658                                move |j| {
2659                                    (
2660                                        Text(format!("Item {}", (i * 5) + j)),
2661                                        UiDebugOptions {
2662                                            enabled: false,
2663                                            ..default()
2664                                        },
2665                                    )
2666                                }
2667                            }))),
2668                            UiDebugOptions {
2669                                enabled: false,
2670                                ..default()
2671                            },
2672                        )
2673                    }))),
2674                ));
2675            });
2676    }
2677
2678    pub fn teardown(mut debug_options: ResMut<GlobalUiDebugOptions>) {
2679        *debug_options = GlobalUiDebugOptions::default();
2680    }
2681}
2682
2683mod viewport_coords {
2684    use bevy::{color::palettes::css::*, prelude::*};
2685
2686    const PALETTE: [Srgba; 9] = [RED, WHITE, BEIGE, AQUA, CRIMSON, NAVY, AZURE, LIME, BLACK];
2687
2688    pub fn setup(mut commands: Commands) {
2689        commands.spawn((Camera2d, DespawnOnExit(super::Scene::ViewportCoords)));
2690        commands
2691            .spawn((
2692                Node {
2693                    width: vw(100),
2694                    height: vh(100),
2695                    border: UiRect::axes(vw(5), vh(5)),
2696                    flex_wrap: FlexWrap::Wrap,
2697                    ..default()
2698                },
2699                BorderColor::all(PALETTE[0]),
2700                DespawnOnExit(super::Scene::ViewportCoords),
2701            ))
2702            .with_children(|builder| {
2703                builder.spawn((
2704                    Node {
2705                        width: vw(30),
2706                        height: vh(30),
2707                        border: UiRect::all(vmin(5)),
2708                        ..default()
2709                    },
2710                    BackgroundColor(PALETTE[1].into()),
2711                    BorderColor::all(PALETTE[8]),
2712                ));
2713
2714                builder.spawn((
2715                    Node {
2716                        width: vw(60),
2717                        height: vh(30),
2718                        ..default()
2719                    },
2720                    BackgroundColor(PALETTE[2].into()),
2721                ));
2722
2723                builder.spawn((
2724                    Node {
2725                        width: vw(45),
2726                        height: vh(30),
2727                        border: UiRect::left(vmax(45. / 2.)),
2728                        ..default()
2729                    },
2730                    BackgroundColor(PALETTE[3].into()),
2731                    BorderColor::all(PALETTE[7]),
2732                ));
2733
2734                builder.spawn((
2735                    Node {
2736                        width: vw(45),
2737                        height: vh(30),
2738                        border: UiRect::right(vmax(45. / 2.)),
2739                        ..default()
2740                    },
2741                    BackgroundColor(PALETTE[4].into()),
2742                    BorderColor::all(PALETTE[7]),
2743                ));
2744
2745                builder.spawn((
2746                    Node {
2747                        width: vw(60),
2748                        height: vh(30),
2749                        ..default()
2750                    },
2751                    BackgroundColor(PALETTE[5].into()),
2752                ));
2753
2754                builder.spawn((
2755                    Node {
2756                        width: vw(30),
2757                        height: vh(30),
2758                        border: UiRect::all(vmin(5)),
2759                        ..default()
2760                    },
2761                    BackgroundColor(PALETTE[6].into()),
2762                    BorderColor::all(PALETTE[8]),
2763                ));
2764            });
2765    }
2766}
2767
2768mod viewport_node {
2769    use bevy::{
2770        camera::RenderTarget, prelude::*, render::render_resource::TextureFormat,
2771        ui::widget::ViewportNode,
2772    };
2773
2774    pub fn setup(
2775        mut commands: Commands,
2776        mut images: ResMut<Assets<Image>>,
2777        mut meshes: ResMut<Assets<Mesh>>,
2778        mut materials: ResMut<Assets<StandardMaterial>>,
2779    ) {
2780        commands.spawn((
2781            Camera3d::default(),
2782            DespawnOnExit(super::Scene::ViewportNode),
2783        ));
2784
2785        let image = Image::new_target_texture(0, 0, TextureFormat::Bgra8UnormSrgb, None);
2786        let image_handle = images.add(image);
2787
2788        let camera = commands
2789            .spawn((
2790                Camera3d::default(),
2791                Camera {
2792                    order: -1,
2793                    ..default()
2794                },
2795                RenderTarget::Image(image_handle.into()),
2796                DespawnOnExit(super::Scene::ViewportNode),
2797            ))
2798            .id();
2799
2800        commands.spawn((
2801            Mesh3d(meshes.add(Cuboid::new(5.0, 5.0, 5.0))),
2802            MeshMaterial3d(materials.add(Color::WHITE)),
2803            Transform {
2804                translation: Vec3::new(0.0, 0.0, -10.0),
2805                rotation: Quat::from_euler(EulerRot::XYZ, 0.4, 0.7, 0.1),
2806                ..default()
2807            },
2808            DespawnOnExit(super::Scene::ViewportNode),
2809        ));
2810
2811        commands.spawn((
2812            Node {
2813                position_type: PositionType::Absolute,
2814                top: px(50),
2815                left: px(50),
2816                width: px(200),
2817                height: px(200),
2818                border: UiRect::all(px(5)),
2819                ..default()
2820            },
2821            BorderColor::all(Color::WHITE),
2822            ViewportNode::new(camera),
2823            DespawnOnExit(super::Scene::ViewportNode),
2824        ));
2825    }
2826}
2827
2828mod outer_color {
2829    use bevy::prelude::*;
2830
2831    pub fn setup(mut commands: Commands) {
2832        let radius = CornerRadius::from(percent(33.));
2833        let width = px(10.);
2834
2835        commands.spawn((Camera2d, DespawnOnExit(super::Scene::OuterColor)));
2836        commands
2837            .spawn((
2838                Node {
2839                    display: Display::Grid,
2840                    grid_template_columns: RepeatedGridTrack::px(3, 200.),
2841                    grid_template_rows: RepeatedGridTrack::px(3, 200.),
2842                    margin: UiRect::AUTO,
2843                    ..default()
2844                },
2845                DespawnOnExit(super::Scene::OuterColor),
2846            ))
2847            .with_children(|builder| {
2848                for (border, border_radius, invert) in [
2849                    (UiRect::ZERO, BorderRadius::bottom_right(radius), true),
2850                    (UiRect::top(width), BorderRadius::top(radius), false),
2851                    (UiRect::ZERO, BorderRadius::bottom_left(radius), true),
2852                    (UiRect::left(width), BorderRadius::left(radius), false),
2853                    (UiRect::all(width), BorderRadius::all(radius.x), true),
2854                    (UiRect::right(width), BorderRadius::right(radius), false),
2855                    (UiRect::ZERO, BorderRadius::top_right(radius), true),
2856                    (UiRect::bottom(width), BorderRadius::bottom(radius), false),
2857                    (UiRect::ZERO, BorderRadius::top_left(radius), true),
2858                ] {
2859                    builder
2860                        .spawn((
2861                            Node {
2862                                width: px(200.),
2863                                height: px(200.),
2864                                border_radius,
2865                                border,
2866                                ..default()
2867                            },
2868                            BorderColor::all(bevy::color::palettes::css::RED),
2869                        ))
2870                        .insert_if(BackgroundColor(Color::WHITE), || !invert)
2871                        .insert_if(OuterColor(Color::WHITE), || invert);
2872                }
2873            });
2874    }
2875}
2876
2877mod boxed_content {
2878    use bevy::color::palettes::css::RED;
2879    use bevy::prelude::*;
2880
2881    pub fn setup(mut commands: Commands) {
2882        commands.spawn((Camera2d, DespawnOnExit(super::Scene::BoxedContent)));
2883        commands
2884            .spawn((
2885                Node {
2886                    margin: auto().all(),
2887                    column_gap: px(30),
2888                    ..default()
2889                },
2890                DespawnOnExit(super::Scene::BoxedContent),
2891            ))
2892            .with_children(|builder| {
2893                for (heading, text_justify) in [
2894                    ("Left", Justify::Left),
2895                    ("Center", Justify::Center),
2896                    ("Right", Justify::Right),
2897                ] {
2898                    builder
2899                        .spawn(Node {
2900                            flex_direction: FlexDirection::Column,
2901                            align_items: AlignItems::Center,
2902                            justify_content: JustifyContent::Start,
2903                            row_gap: px(20),
2904                            ..default()
2905                        })
2906                        .with_children(|builder| {
2907                            builder.spawn((
2908                                Node::default(),
2909                                Text::new(format!("{heading} justify")),
2910                                TextFont::from_font_size(FontSize::Px(14.)),
2911                                TextLayout::justify(Justify::Center),
2912                            ));
2913
2914                            builder.spawn((
2915                                Node::default(),
2916                                Text::new("This text has\nno border or padding."),
2917                                TextFont::from_font_size(FontSize::Px(10.)),
2918                                TextLayout::justify(text_justify),
2919                                Outline {
2920                                    width: px(2),
2921                                    color: Color::WHITE,
2922                                    ..Default::default()
2923                                },
2924                            ));
2925
2926                            builder.spawn((
2927                                Node {
2928                                    border: px(10).all(),
2929                                    ..default()
2930                                },
2931                                Text::new("This text has\na border but no padding."),
2932                                TextFont::from_font_size(FontSize::Px(10.)),
2933                                TextLayout::justify(text_justify),
2934                                BorderColor::all(RED),
2935                                Outline {
2936                                    width: px(2),
2937                                    color: Color::WHITE,
2938                                    ..Default::default()
2939                                },
2940                            ));
2941
2942                            builder.spawn((
2943                                Node {
2944                                    padding: px(20).all(),
2945                                    ..default()
2946                                },
2947                                Text::new("This text has\npadding but no border."),
2948                                TextFont::from_font_size(FontSize::Px(10.)),
2949                                TextLayout::justify(text_justify),
2950                                Outline {
2951                                    width: px(2),
2952                                    color: Color::WHITE,
2953                                    ..Default::default()
2954                                },
2955                            ));
2956
2957                            builder.spawn((
2958                                Node {
2959                                    border: px(10).all(),
2960                                    padding: px(20).all(),
2961                                    ..default()
2962                                },
2963                                Text::new("This text has\nborder and padding."),
2964                                TextFont::from_font_size(FontSize::Px(10.)),
2965                                TextLayout::justify(text_justify),
2966                                BorderColor::all(RED),
2967                                Outline {
2968                                    width: px(2),
2969                                    color: Color::WHITE,
2970                                    ..Default::default()
2971                                },
2972                            ));
2973
2974                            builder.spawn((
2975                                Node {
2976                                    border: px(10).left(),
2977                                    ..default()
2978                                },
2979                                Text::new("This text has\na left border and no padding."),
2980                                TextFont::from_font_size(FontSize::Px(10.)),
2981                                TextLayout::justify(text_justify),
2982                                BorderColor::all(RED),
2983                                Outline {
2984                                    width: px(2),
2985                                    color: Color::WHITE,
2986                                    ..Default::default()
2987                                },
2988                            ));
2989
2990                            builder.spawn((
2991                                Node {
2992                                    border: px(10).right(),
2993                                    ..default()
2994                                },
2995                                Text::new("This text has\na right border and no padding."),
2996                                TextFont::from_font_size(FontSize::Px(10.)),
2997                                TextLayout::justify(text_justify),
2998                                BorderColor::all(RED),
2999                                Outline {
3000                                    width: px(2),
3001                                    color: Color::WHITE,
3002                                    ..Default::default()
3003                                },
3004                            ));
3005
3006                            builder.spawn((
3007                                Node {
3008                                    padding: px(20).top().with_right(px(20)),
3009                                    ..default()
3010                                },
3011                                Text::new("This text has\npadding on its top and right."),
3012                                TextFont::from_font_size(FontSize::Px(10.)),
3013                                TextLayout::justify(text_justify),
3014                                BorderColor::all(RED),
3015                                Outline {
3016                                    width: px(2),
3017                                    color: Color::WHITE,
3018                                    ..Default::default()
3019                                },
3020                            ));
3021
3022                            builder.spawn((
3023                                Node {
3024                                    padding: px(20).bottom().with_left(px(20)),
3025                                    ..default()
3026                                },
3027                                Text::new("This text has\npadding on its bottom and left."),
3028                                TextFont::from_font_size(FontSize::Px(10.)),
3029                                TextLayout::justify(text_justify),
3030                                BorderColor::all(RED),
3031                                Outline {
3032                                    width: px(2),
3033                                    color: Color::WHITE,
3034                                    ..Default::default()
3035                                },
3036                            ));
3037
3038                            builder.spawn((
3039                                Node {
3040                                    padding: px(20).top().with_left(px(20)),
3041                                    border: px(10).bottom().with_right(px(10)),
3042                                    ..default()
3043                                },
3044                                Text::new(
3045                                    "This text has\npadding on its top and left\nand a border on its bottom and right.",
3046                                ),
3047                                TextFont::from_font_size(FontSize::Px(10.)),
3048                                TextLayout::justify(text_justify),
3049                                BorderColor::all(RED),
3050                                Outline {
3051                                    width: px(2),
3052                                    color: Color::WHITE,
3053                                    ..Default::default()
3054                                },
3055                            ));
3056                        });
3057                }
3058            });
3059    }
3060}
3061
3062mod editable_text {
3063    use bevy::color::palettes::css::YELLOW;
3064    use bevy::prelude::*;
3065    use bevy::text::EditableText;
3066    use bevy::text::TextCursorStyle;
3067    use bevy::text::TextEdit;
3068    use bevy::ui_widgets::TextInput;
3069
3070    const DUMMY_TEXT: &str = "one\ntwo\nthree\nfour\nfive\nsix\nseven\neight\nnine\nten";
3071    const LOREM_TEXT: &str = concat!(
3072        "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. ",
3073        "Aenean commodo ligula eget dolor. Aenean massa. ",
3074        "Cum sociis natoque penatibus et magnis dis parturient montes, nascetur reprehenderit mus. ",
3075        "Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. ",
3076        "Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. ",
3077        "In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. ",
3078        "Nullam dictum felis eu pede mollis pretium. Integer tincidunt. ",
3079        "Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. ",
3080        "Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. ",
3081        "Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus. ",
3082        "Phasellus viverra nulla ut metus officia laoreet. Quisque rutrum. ",
3083        "Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi.",
3084        " Qui eget dui. Etiam rhoncus. Maecenas tempus, tellus eget condimentum rhoncus, ",
3085        "sem quam semper libero, sit amet adipiscing sem neque sed ipsum. ",
3086        "Qui quam nunc, blandit vel, luctus pulvinar, hendrerit id, lorem. ",
3087        "Maecenas nec odio et ante tincidunt tempus. Donec vitae sapien ut libero venenatis faucibus. ",
3088        "Nullam quis ante. Etiam sit amet orci eget eros faucibus tincidunt. Duis leo. ",
3089        "Sed fringilla mauris sit amet nibh. Donec sodales sagittis magna. ",
3090        "Sed consequat, leo eget bibendum sodales, augue velit cursus nunc,"
3091    );
3092
3093    pub fn setup(mut commands: Commands) {
3094        commands.spawn((Camera2d, DespawnOnExit(super::Scene::EditableText)));
3095        commands.spawn((
3096            Node {
3097                flex_wrap: FlexWrap::Wrap,
3098                align_items: AlignItems::Start,
3099                margin: px(10.).all(),
3100                width: vw(100),
3101                height: vh(100),
3102                row_gap: px(10),
3103                column_gap: px(20),
3104                ..default()
3105            },
3106            DespawnOnExit(super::Scene::EditableText),
3107            children![
3108                (
3109                    Node {
3110                        flex_direction: FlexDirection::Column,
3111                        row_gap: px(10),
3112                        ..default()
3113                    },
3114                    children![
3115                        Text::new("Single line"),
3116                        (
3117                            TextInput,
3118                            EditableText {
3119                                pending_edits: vec![TextEdit::Insert(
3120                                    "Single line EditableText".into(),
3121                                )],
3122                                ..default()
3123                            },
3124                            TextLayout::no_wrap(),
3125                            TextFont {
3126                                font_size: FontSize::Px(10.),
3127                                ..default()
3128                            },
3129                            TextCursorStyle::default(),
3130                            Node {
3131                                width: px(200.),
3132                                border: px(2).all(),
3133                                ..default()
3134                            },
3135                            BorderColor::all(YELLOW),
3136                        ),
3137                        Text::new("Initial end"),
3138                        (
3139                            EditableText::new(LOREM_TEXT),
3140                            TextLayout::no_wrap(),
3141                            TextFont {
3142                                font_size: FontSize::Px(10.),
3143                                ..default()
3144                            },
3145                            TextCursorStyle::default(),
3146                            Node {
3147                                width: px(200.),
3148                                border: px(2).all(),
3149                                ..default()
3150                            },
3151                            BorderColor::all(YELLOW),
3152                        ),
3153                        Text::new("Insert end"),
3154                        (
3155                            TextInput,
3156                            EditableText {
3157                                pending_edits: vec![TextEdit::Insert(LOREM_TEXT.into())],
3158                                ..default()
3159                            },
3160                            TextLayout::no_wrap(),
3161                            TextFont {
3162                                font_size: FontSize::Px(10.),
3163                                ..default()
3164                            },
3165                            TextCursorStyle::default(),
3166                            Node {
3167                                width: px(200.),
3168                                border: px(2).all(),
3169                                ..default()
3170                            },
3171                            BorderColor::all(YELLOW),
3172                        ),
3173                        Text::new("Select line start"),
3174                        (
3175                            TextInput,
3176                            EditableText {
3177                                pending_edits: vec![
3178                                    TextEdit::Insert(LOREM_TEXT.into()),
3179                                    TextEdit::LineStart(true),
3180                                ],
3181                                ..default()
3182                            },
3183                            TextLayout::no_wrap(),
3184                            TextFont {
3185                                font_size: FontSize::Px(10.),
3186                                ..default()
3187                            },
3188                            TextCursorStyle::default(),
3189                            Node {
3190                                width: px(200.),
3191                                border: px(2).all(),
3192                                ..default()
3193                            },
3194                            BorderColor::all(YELLOW),
3195                        ),
3196                    ],
3197                ),
3198                (
3199                    Node {
3200                        flex_direction: FlexDirection::Column,
3201                        row_gap: px(10),
3202                        ..default()
3203                    },
3204                    children![
3205                        Text::new("Wrapped start"),
3206                        (
3207                            TextInput,
3208                            EditableText {
3209                                pending_edits: vec![
3210                                    TextEdit::Insert(LOREM_TEXT.into()),
3211                                    TextEdit::TextStart(false),
3212                                ],
3213                                visible_lines: Some(8.),
3214                                ..default()
3215                            },
3216                            Node {
3217                                width: px(200.),
3218                                border: px(2).all(),
3219                                ..default()
3220                            },
3221                            TextCursorStyle::default(),
3222                            TextFont {
3223                                font_size: FontSize::Px(10.),
3224                                ..default()
3225                            },
3226                            BorderColor::all(YELLOW),
3227                        ),
3228                    ],
3229                ),
3230                (
3231                    Node {
3232                        flex_direction: FlexDirection::Column,
3233                        row_gap: px(10),
3234                        ..default()
3235                    },
3236                    children![
3237                        Text::new("Wrapped selection"),
3238                        (
3239                            TextInput,
3240                            EditableText {
3241                                pending_edits: vec![
3242                                    TextEdit::Insert(LOREM_TEXT.into()),
3243                                    TextEdit::TextStart(false),
3244                                    TextEdit::Down(false),
3245                                    TextEdit::TextEnd(true),
3246                                ],
3247                                visible_lines: Some(8.),
3248                                ..default()
3249                            },
3250                            TextCursorStyle::default(),
3251                            Node {
3252                                width: px(200.),
3253                                border: px(2).all(),
3254                                ..default()
3255                            },
3256                            TextFont {
3257                                font_size: FontSize::Px(10.),
3258                                ..default()
3259                            },
3260                            BorderColor::all(YELLOW),
3261                        ),
3262                    ],
3263                ),
3264                (
3265                    Node {
3266                        flex_direction: FlexDirection::Column,
3267                        row_gap: px(10),
3268                        ..default()
3269                    },
3270                    children![
3271                        Text::new("Clamp top"),
3272                        (
3273                            TextInput,
3274                            EditableText {
3275                                pending_edits: vec![
3276                                    TextEdit::Insert(DUMMY_TEXT.into()),
3277                                    TextEdit::ScrollByLines(-10.0),
3278                                ],
3279                                visible_lines: Some(5.5),
3280                                ..default()
3281                            },
3282                            TextCursorStyle::default(),
3283                            TextFont {
3284                                font_size: FontSize::Px(10.),
3285                                ..default()
3286                            },
3287                            Node {
3288                                width: px(100.),
3289                                border: px(2).all(),
3290                                ..default()
3291                            },
3292                            BorderColor::all(YELLOW),
3293                        ),
3294                    ],
3295                ),
3296                (
3297                    Node {
3298                        flex_direction: FlexDirection::Column,
3299                        row_gap: px(10),
3300                        ..default()
3301                    },
3302                    children![
3303                        Text::new("Home, Scroll 1"),
3304                        (
3305                            TextInput,
3306                            EditableText {
3307                                pending_edits: vec![
3308                                    TextEdit::Insert(DUMMY_TEXT.into()),
3309                                    TextEdit::ScrollTo(Vec2::ZERO),
3310                                    TextEdit::ScrollByLines(1.0),
3311                                ],
3312                                visible_lines: Some(5.5),
3313                                ..default()
3314                            },
3315                            TextCursorStyle::default(),
3316                            TextFont {
3317                                font_size: FontSize::Px(10.),
3318                                ..default()
3319                            },
3320                            Node {
3321                                width: px(100.),
3322                                border: px(2).all(),
3323                                ..default()
3324                            },
3325                            BorderColor::all(YELLOW),
3326                        ),
3327                    ],
3328                ),
3329                (
3330                    Node {
3331                        flex_direction: FlexDirection::Column,
3332                        row_gap: px(10),
3333                        ..default()
3334                    },
3335                    children![
3336                        Text::new("Home, Scroll 2"),
3337                        (
3338                            TextInput,
3339                            EditableText {
3340                                pending_edits: vec![
3341                                    TextEdit::Insert(DUMMY_TEXT.into()),
3342                                    TextEdit::ScrollTo(Vec2::ZERO),
3343                                    TextEdit::ScrollByLines(2.0),
3344                                ],
3345                                visible_lines: Some(5.5),
3346                                ..default()
3347                            },
3348                            TextFont {
3349                                font_size: FontSize::Px(10.),
3350                                ..default()
3351                            },
3352                            TextCursorStyle::default(),
3353                            Node {
3354                                width: px(100.),
3355                                border: px(2).all(),
3356                                ..default()
3357                            },
3358                            BorderColor::all(YELLOW),
3359                        ),
3360                    ],
3361                ),
3362                (
3363                    Node {
3364                        flex_direction: FlexDirection::Column,
3365                        row_gap: px(10),
3366                        ..default()
3367                    },
3368                    children![
3369                        Text::new("Clamp bottom"),
3370                        (
3371                            TextInput,
3372                            EditableText {
3373                                pending_edits: vec![
3374                                    TextEdit::Insert(DUMMY_TEXT.into()),
3375                                    TextEdit::ScrollByLines(-1000.0),
3376                                    TextEdit::ScrollByLines(1000.0),
3377                                ],
3378                                visible_lines: Some(5.5),
3379                                ..default()
3380                            },
3381                            TextCursorStyle::default(),
3382                            TextFont {
3383                                font_size: FontSize::Px(10.),
3384                                ..default()
3385                            },
3386                            Node {
3387                                width: px(100.),
3388                                border: px(2).all(),
3389                                ..default()
3390                            },
3391                            BorderColor::all(YELLOW),
3392                        ),
3393                    ],
3394                ),
3395                (
3396                    Node {
3397                        flex_direction: FlexDirection::Column,
3398                        row_gap: px(10),
3399                        ..default()
3400                    },
3401                    children![
3402                        Text::new("Bottom -1"),
3403                        (
3404                            TextInput,
3405                            EditableText {
3406                                pending_edits: vec![
3407                                    TextEdit::Insert(DUMMY_TEXT.into()),
3408                                    TextEdit::ScrollByLines(-1000.0),
3409                                    TextEdit::ScrollByLines(1000.0),
3410                                    TextEdit::ScrollByLines(-1.0),
3411                                ],
3412                                visible_lines: Some(5.5),
3413                                ..default()
3414                            },
3415                            TextCursorStyle::default(),
3416                            TextFont {
3417                                font_size: FontSize::Px(10.),
3418                                ..default()
3419                            },
3420                            Node {
3421                                width: px(100.),
3422                                border: px(2).all(),
3423                                ..default()
3424                            },
3425                            BorderColor::all(YELLOW),
3426                        ),
3427                    ],
3428                ),
3429                (
3430                    Node {
3431                        flex_direction: FlexDirection::Column,
3432                        row_gap: px(10),
3433                        ..default()
3434                    },
3435                    children![
3436                        Text::new("Top +3"),
3437                        (
3438                            TextInput,
3439                            EditableText {
3440                                pending_edits: vec![
3441                                    TextEdit::Insert(DUMMY_TEXT.into()),
3442                                    TextEdit::ScrollByLines(-1000.0),
3443                                    TextEdit::ScrollByLines(3.0),
3444                                ],
3445                                visible_lines: Some(5.5),
3446                                ..default()
3447                            },
3448                            TextCursorStyle::default(),
3449                            TextFont {
3450                                font_size: FontSize::Px(10.),
3451                                ..default()
3452                            },
3453                            Node {
3454                                width: px(100.),
3455                                border: px(2).all(),
3456                                ..default()
3457                            },
3458                            BorderColor::all(YELLOW),
3459                        ),
3460                    ],
3461                ),
3462                (
3463                    Node {
3464                        flex_direction: FlexDirection::Column,
3465                        row_gap: px(10),
3466                        ..default()
3467                    },
3468                    children![
3469                        Text::new("Select down 3"),
3470                        (
3471                            TextInput,
3472                            EditableText {
3473                                pending_edits: vec![
3474                                    TextEdit::Insert(DUMMY_TEXT.into()),
3475                                    TextEdit::TextStart(false),
3476                                    TextEdit::Down(false),
3477                                    TextEdit::Down(true),
3478                                    TextEdit::Down(true),
3479                                    TextEdit::Down(true),
3480                                ],
3481                                visible_lines: Some(5.5),
3482                                ..default()
3483                            },
3484                            TextCursorStyle::default(),
3485                            TextFont {
3486                                font_size: FontSize::Px(10.),
3487                                ..default()
3488                            },
3489                            Node {
3490                                width: px(100.),
3491                                border: px(2).all(),
3492                                ..default()
3493                            },
3494                            BorderColor::all(YELLOW),
3495                        ),
3496                    ],
3497                ),
3498                (
3499                    Node {
3500                        flex_direction: FlexDirection::Column,
3501                        row_gap: px(10),
3502                        ..default()
3503                    },
3504                    children![
3505                        Text::new("End, Scroll 1"),
3506                        (
3507                            TextInput,
3508                            EditableText {
3509                                pending_edits: vec![
3510                                    TextEdit::Insert(DUMMY_TEXT.into()),
3511                                    TextEdit::ScrollByLines(1.0),
3512                                ],
3513                                visible_lines: Some(5.5),
3514                                ..default()
3515                            },
3516                            TextCursorStyle::default(),
3517                            TextFont {
3518                                font_size: FontSize::Px(10.),
3519                                ..default()
3520                            },
3521                            Node {
3522                                width: px(100.),
3523                                border: px(2).all(),
3524                                ..default()
3525                            },
3526                            BorderColor::all(YELLOW),
3527                        ),
3528                    ],
3529                ),
3530                (
3531                    Node {
3532                        flex_direction: FlexDirection::Column,
3533                        row_gap: px(10),
3534                        ..default()
3535                    },
3536                    children![
3537                        Text::new("End, Scroll -0.5"),
3538                        (
3539                            TextInput,
3540                            EditableText {
3541                                pending_edits: vec![
3542                                    TextEdit::Insert(DUMMY_TEXT.into()),
3543                                    TextEdit::ScrollByLines(-0.5),
3544                                ],
3545                                visible_lines: Some(5.5),
3546                                ..default()
3547                            },
3548                            TextCursorStyle::default(),
3549                            TextFont {
3550                                font_size: FontSize::Px(10.),
3551                                ..default()
3552                            },
3553                            Node {
3554                                width: px(100.),
3555                                border: px(2).all(),
3556                                ..default()
3557                            },
3558                            BorderColor::all(YELLOW),
3559                        ),
3560                    ],
3561                )
3562            ],
3563        ));
3564    }
3565}
3566
3567mod node_material {
3568    use bevy::{
3569        color::palettes::tailwind::{CYAN_100, RED_500, YELLOW_100},
3570        prelude::*,
3571        render::render_resource::AsBindGroup,
3572        shader::ShaderRef,
3573    };
3574    const SHADER_ASSET_PATH: &str = "shaders/custom_ui_material.wesl";
3575
3576    #[derive(AsBindGroup, Asset, TypePath, Debug, Clone)]
3577    pub(super) struct DefaultUiMaterial {}
3578
3579    impl UiMaterial for DefaultUiMaterial {}
3580
3581    #[derive(AsBindGroup, Asset, TypePath, Debug, Clone)]
3582    pub(super) struct CustomUiMaterial {
3583        /// Color multiplied with the image
3584        #[uniform(0)]
3585        color: Vec4,
3586        /// Represents how much of the image is visible
3587        /// Goes from 0 to 1
3588        /// A `Vec4` is used here because Bevy with webgl2 requires that uniforms are 16-byte aligned but only the first component is read.
3589        #[uniform(1)]
3590        slider: Vec4,
3591        /// Image used to represent the slider
3592        #[texture(2)]
3593        #[sampler(3)]
3594        color_texture: Handle<Image>,
3595        /// Color of the image's border
3596        #[uniform(4)]
3597        border_color: Vec4,
3598    }
3599
3600    impl UiMaterial for CustomUiMaterial {
3601        fn fragment_shader() -> ShaderRef {
3602            SHADER_ASSET_PATH.into()
3603        }
3604    }
3605
3606    pub fn setup(
3607        mut commands: Commands,
3608        mut default_ui_materials: ResMut<Assets<DefaultUiMaterial>>,
3609        mut ui_materials: ResMut<Assets<CustomUiMaterial>>,
3610        asset_server: Res<AssetServer>,
3611    ) {
3612        let default_material = default_ui_materials.add(DefaultUiMaterial {});
3613        let custom_material = |slider| CustomUiMaterial {
3614            color: LinearRgba::from(CYAN_100).to_vec4(),
3615            slider: Vec4::splat(slider),
3616            color_texture: asset_server.load("branding/banner.png"),
3617            border_color: LinearRgba::from(YELLOW_100).to_vec4(),
3618        };
3619        let full_material = ui_materials.add(custom_material(1.));
3620        let material_node = Node {
3621            width: px(200),
3622            height: px(80),
3623            border: px(10).all(),
3624            border_radius: BorderRadius::all(px(20)),
3625            ..default()
3626        };
3627        let material_label = |text: &str| (Text::new(text), TextFont::from_font_size(px(10.)));
3628
3629        commands.spawn((Camera2d, DespawnOnExit(super::Scene::NodeMaterial)));
3630        commands.spawn((
3631            Node {
3632                display: Display::Grid,
3633                // two column grid, labels then materials, first row is spanned by title.
3634                width: percent(100),
3635                height: percent(100),
3636                grid_template_columns: vec![GridTrack::auto(), GridTrack::px(200.)],
3637                align_items: AlignItems::Center,
3638                align_content: AlignContent::Center,
3639                justify_content: JustifyContent::Center,
3640                row_gap: px(10.),
3641                column_gap: px(20.),
3642                ..default()
3643            },
3644            DespawnOnExit(super::Scene::NodeMaterial),
3645            children![
3646                (
3647                    Text::new("MaterialNode"),
3648                    TextFont::from_font_size(px(30.)),
3649                    TextLayout::justify(Justify::Center),
3650                    Node {
3651                        grid_column: GridPlacement::span(2),
3652                        margin: px(10.).bottom(),
3653                        ..default()
3654                    },
3655                ),
3656                // Default UI material (just white with the default ui_material.wgsl shader for the bevy_ui crate)
3657                material_label("'ui_material.wgsl' default material"),
3658                (material_node.clone(), MaterialNode(default_material),),
3659                // Custom UI material, 1./3 full.
3660                material_label("'custom_ui_material.wgsl' 1/3"),
3661                (
3662                    material_node.clone(),
3663                    MaterialNode(ui_materials.add(custom_material(1. / 3.))),
3664                ),
3665                // Custom UI material, 2./3 full.
3666                material_label("'custom_ui_material.wgsl' 2/3"),
3667                (
3668                    material_node.clone(),
3669                    MaterialNode(ui_materials.add(custom_material(2. / 3.)))
3670                ),
3671                // Custom UI material, full.
3672                material_label("'custom_ui_material.wgsl' Full"),
3673                (material_node.clone(), MaterialNode(full_material.clone()),),
3674                // Custom UI material, full. Clipped using overflow so bottom 50% missing
3675                material_label("'custom_ui_material.wgsl' clipped vertically"),
3676                (
3677                    Node {
3678                        width: material_node.width,
3679                        height: material_node.height,
3680                        ..default()
3681                    },
3682                    Outline {
3683                        width: px(1),
3684                        color: RED_500.into(),
3685                        ..default()
3686                    },
3687                    children![(
3688                        Node {
3689                            width: percent(100),
3690                            height: percent(50),
3691                            overflow: Overflow::clip(),
3692                            ..default()
3693                        },
3694                        children![(material_node.clone(), MaterialNode(full_material.clone()))],
3695                    )],
3696                ),
3697                // Custom UI material clipped on both axis so bottom 25% and right 25% not visible.
3698                material_label("'custom_ui_material.wgsl' end clipped on both axis"),
3699                (
3700                    Node {
3701                        width: material_node.width,
3702                        height: material_node.height,
3703                        ..default()
3704                    },
3705                    Outline {
3706                        width: px(1),
3707                        color: RED_500.into(),
3708                        ..default()
3709                    },
3710                    children![(
3711                        Node {
3712                            width: percent(75),
3713                            height: percent(75),
3714                            overflow: Overflow::clip(),
3715                            ..default()
3716                        },
3717                        children![(
3718                            Node {
3719                                position_type: PositionType::Absolute,
3720                                width: px(200),
3721                                height: px(80),
3722                                border: px(10).all(),
3723                                border_radius: BorderRadius::all(px(20)),
3724                                ..default()
3725                            },
3726                            MaterialNode(full_material.clone()),
3727                        )],
3728                    )],
3729                ),
3730                // Custom UI material clipped on both axis so top 25% and left 25% not visible.
3731                material_label("'custom_ui_material.wgsl' start clipped on both axis"),
3732                (
3733                    Node {
3734                        width: material_node.width,
3735                        height: material_node.height,
3736                        align_items: AlignItems::End,
3737                        justify_content: JustifyContent::End,
3738                        ..default()
3739                    },
3740                    Outline {
3741                        width: px(1),
3742                        color: RED_500.into(),
3743                        ..default()
3744                    },
3745                    children![(
3746                        Node {
3747                            width: percent(75),
3748                            height: percent(75),
3749                            overflow: Overflow::clip(),
3750                            ..default()
3751                        },
3752                        children![(
3753                            Node {
3754                                position_type: PositionType::Absolute,
3755                                width: px(200),
3756                                height: px(80),
3757                                right: px(0),
3758                                bottom: px(0),
3759                                border: px(10).all(),
3760                                border_radius: BorderRadius::all(px(20)),
3761                                ..default()
3762                            },
3763                            MaterialNode(full_material),
3764                        )],
3765                    )],
3766                ),
3767            ],
3768        ));
3769    }
More examples
Hide additional examples
examples/ui/layout/grid.rs (line 40)
18fn spawn_layout(mut commands: Commands, asset_server: Res<AssetServer>) {
19    let font = asset_server.load("fonts/FiraSans-Bold.ttf");
20    commands.spawn(Camera2d);
21
22    // Top-level grid (app frame)
23    commands
24        .spawn((
25            Node {
26                // Use the CSS Grid algorithm for laying out this node
27                display: Display::Grid,
28                // Make node fill the entirety of its parent (in this case the window)
29                width: percent(100),
30                height: percent(100),
31                // Set the grid to have 2 columns with sizes [min-content, minmax(0, 1fr)]
32                //   - The first column will size to the size of its contents
33                //   - The second column will take up the remaining available space
34                grid_template_columns: vec![GridTrack::min_content(), GridTrack::flex(1.0)],
35                // Set the grid to have 3 rows with sizes [auto, minmax(0, 1fr), 20px]
36                //  - The first row will size to the size of its contents
37                //  - The second row take up remaining available space (after rows 1 and 3 have both been sized)
38                //  - The third row will be exactly 20px high
39                grid_template_rows: vec![
40                    GridTrack::auto(),
41                    GridTrack::flex(1.0),
42                    GridTrack::px(20.),
43                ],
44                ..default()
45            },
46            BackgroundColor(Color::WHITE),
47        ))
48        .with_children(|builder| {
49            // Header
50            builder
51                .spawn(
52                    Node {
53                        display: Display::Grid,
54                        // Make this node span two grid columns so that it takes up the entire top tow
55                        grid_column: GridPlacement::span(2),
56                        padding: UiRect::all(px(6)),
57                        ..default()
58                    },
59                )
60                .with_children(|builder| {
61                    spawn_nested_text_bundle(builder, font.clone(), "Bevy CSS Grid Layout Example");
62                });
63
64            // Main content grid (auto placed in row 2, column 1)
65            builder
66                .spawn((
67                    Node {
68                        // Make the height of the node fill its parent
69                        height: percent(100),
70                        // Make the grid have a 1:1 aspect ratio meaning it will scale as an exact square
71                        // As the height is set explicitly, this means the width will adjust to match the height
72                        aspect_ratio: Some(1.0),
73                        // Use grid layout for this node
74                        display: Display::Grid,
75                        // Add 24px of padding around the grid
76                        padding: UiRect::all(px(24)),
77                        // Set the grid to have 4 columns all with sizes minmax(0, 1fr)
78                        // This creates 4 exactly evenly sized columns
79                        grid_template_columns: RepeatedGridTrack::flex(4, 1.0),
80                        // Set the grid to have 4 rows all with sizes minmax(0, 1fr)
81                        // This creates 4 exactly evenly sized rows
82                        grid_template_rows: RepeatedGridTrack::flex(4, 1.0),
83                        // Set a 12px gap/gutter between rows and columns
84                        row_gap: px(12),
85                        column_gap: px(12),
86                        ..default()
87                    },
88                    BackgroundColor(Color::srgb(0.25, 0.25, 0.25)),
89                ))
90                .with_children(|builder| {
91                    // Note there is no need to specify the position for each grid item. Grid items that are
92                    // not given an explicit position will be automatically positioned into the next available
93                    // grid cell. The order in which this is performed can be controlled using the grid_auto_flow
94                    // style property.
95
96                    item_rect(builder, ORANGE);
97                    item_rect(builder, BISQUE);
98                    item_rect(builder, BLUE);
99                    item_rect(builder, CRIMSON);
100                    item_rect(builder, AQUA);
101                    item_rect(builder, ORANGE_RED);
102                    item_rect(builder, DARK_GREEN);
103                    item_rect(builder, FUCHSIA);
104                    item_rect(builder, TEAL);
105                    item_rect(builder, ALICE_BLUE);
106                    item_rect(builder, CRIMSON);
107                    item_rect(builder, ANTIQUE_WHITE);
108                    item_rect(builder, YELLOW);
109                    item_rect(builder, DEEP_PINK);
110                    item_rect(builder, YELLOW_GREEN);
111                    item_rect(builder, SALMON);
112                });
113
114            // Right side bar (auto placed in row 2, column 2)
115            builder
116                .spawn((
117                    Node {
118                        display: Display::Grid,
119                        // Align content towards the start (top) in the vertical axis
120                        align_items: AlignItems::Start,
121                        // Align content towards the center in the horizontal axis
122                        justify_items: JustifyItems::Center,
123                        // Add 10px padding
124                        padding: UiRect::all(px(10)),
125                        // Add an fr track to take up all the available space at the bottom of the column so that the text nodes
126                        // can be top-aligned. Normally you'd use flexbox for this, but this is the CSS Grid example so we're using grid.
127                        grid_template_rows: vec![GridTrack::auto(), GridTrack::auto(), GridTrack::fr(1.0)],
128                        // Add a 10px gap between rows
129                        row_gap: px(10),
130                        ..default()
131                    },
132                    BackgroundColor(BLACK.into()),
133                ))
134                .with_children(|builder| {
135                    builder.spawn((Text::new("Sidebar"),
136                        TextFont::from(font.clone()),
137                    ));
138                    builder.spawn((Text::new("A paragraph of text which ought to wrap nicely. A paragraph of text which ought to wrap nicely. A paragraph of text which ought to wrap nicely. A paragraph of text which ought to wrap nicely. A paragraph of text which ought to wrap nicely. A paragraph of text which ought to wrap nicely. A paragraph of text which ought to wrap nicely."),
139                        TextFont {
140                            font: font.clone().into(),
141                            font_size: FontSize::Px(13.0),
142                            ..default()
143                        },
144                    ));
145                    builder.spawn(Node::default());
146                });
147
148            // Footer / status bar
149            builder.spawn((
150                Node {
151                    // Make this node span two grid column so that it takes up the entire bottom row
152                    grid_column: GridPlacement::span(2),
153                    ..default()
154                },
155                BackgroundColor(WHITE.into()),
156            ));
157
158            // Modal (absolutely positioned on top of content - currently hidden: to view it, change its visibility)
159            builder.spawn((
160                Node {
161                    position_type: PositionType::Absolute,
162                    margin: UiRect {
163                        top: px(100),
164                        bottom: auto(),
165                        left: auto(),
166                        right: auto(),
167                    },
168                    width: percent(60),
169                    height: px(300),
170                    max_width: px(600),
171                    ..default()
172                },
173                Visibility::Hidden,
174                BackgroundColor(Color::WHITE.with_alpha(0.8)),
175            ));
176        });
177}
Source

pub fn min_content<T>() -> T
where T: From<GridTrack>,

Create a grid track which is automatically sized to fit its contents when sized at their “min-content” sizes

Examples found in repository?
examples/testbed/ui.rs (line 1143)
1135    pub fn setup(mut commands: Commands) {
1136        commands.spawn((Camera2d, DespawnOnExit(super::Scene::Grid)));
1137        // Top-level grid (app frame)
1138        commands.spawn((
1139            Node {
1140                display: Display::Grid,
1141                width: percent(100),
1142                height: percent(100),
1143                grid_template_columns: vec![GridTrack::min_content(), GridTrack::flex(1.0)],
1144                grid_template_rows: vec![
1145                    GridTrack::auto(),
1146                    GridTrack::flex(1.0),
1147                    GridTrack::px(40.),
1148                ],
1149                ..default()
1150            },
1151            BackgroundColor(Color::WHITE),
1152            DespawnOnExit(super::Scene::Grid),
1153            children![
1154                // Header
1155                (
1156                    Node {
1157                        display: Display::Grid,
1158                        grid_column: GridPlacement::span(2),
1159                        padding: UiRect::all(px(40)),
1160                        ..default()
1161                    },
1162                    BackgroundColor(RED.into()),
1163                ),
1164                // Main content grid (auto placed in row 2, column 1)
1165                (
1166                    Node {
1167                        height: percent(100),
1168                        aspect_ratio: Some(1.0),
1169                        display: Display::Grid,
1170                        grid_template_columns: RepeatedGridTrack::flex(3, 1.0),
1171                        grid_template_rows: RepeatedGridTrack::flex(2, 1.0),
1172                        row_gap: px(12),
1173                        column_gap: px(12),
1174                        ..default()
1175                    },
1176                    BackgroundColor(Color::srgb(0.25, 0.25, 0.25)),
1177                    children![
1178                        (Node::default(), BackgroundColor(ORANGE.into())),
1179                        (Node::default(), BackgroundColor(BISQUE.into())),
1180                        (Node::default(), BackgroundColor(BLUE.into())),
1181                        (Node::default(), BackgroundColor(CRIMSON.into())),
1182                        (Node::default(), BackgroundColor(AQUA.into())),
1183                    ]
1184                ),
1185                // Right side bar (auto placed in row 2, column 2)
1186                (Node::DEFAULT, BackgroundColor(BLACK.into())),
1187            ],
1188        ));
1189    }
More examples
Hide additional examples
examples/ui/images/image_node_resizing.rs (line 77)
62fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
63    let image_handle = asset_server.load("branding/icon.png");
64    let full_text = format!(
65        "{}height : {}%, width : {}%",
66        TEXT_PREFIX, IMAGE_GROUP_BOX_INIT_HEIGHT, IMAGE_GROUP_BOX_INIT_WIDTH,
67    );
68
69    commands.spawn(Camera2d);
70
71    let container = commands
72        .spawn((
73            Node {
74                display: Display::Grid,
75                width: percent(100),
76                height: percent(100),
77                grid_template_rows: vec![GridTrack::min_content(), GridTrack::flex(1.0)],
78                ..default()
79            },
80            BackgroundColor(Color::WHITE),
81        ))
82        .id();
83
84    // Keyboard Text
85    commands
86        .spawn((
87            TextData {
88                height: IMAGE_GROUP_BOX_INIT_HEIGHT,
89                width: IMAGE_GROUP_BOX_INIT_WIDTH,
90            },
91            Text::new(full_text),
92            TextColor::BLACK,
93            Node {
94                grid_row: GridPlacement::span(1),
95                padding: px(6).all(),
96                ..default()
97            },
98            UiDebugOptions {
99                enabled: false,
100                ..default()
101            },
102            ChildOf(container),
103        ))
104        .observe(update_text);
105
106    commands
107        .spawn((
108            Node {
109                display: Display::Flex,
110                grid_row: GridPlacement::span(1),
111                flex_direction: FlexDirection::Column,
112                justify_content: JustifyContent::SpaceAround,
113                padding: px(10.).all(),
114                ..default()
115            },
116            BackgroundColor(Color::BLACK),
117            ChildOf(container),
118        ))
119        .with_children(|builder| {
120            // `NodeImageMode::Auto` will resize the image automatically by taking the size of the source image and applying any layout constraints.
121            builder
122                .spawn((
123                    ImageGroup,
124                    Node {
125                        display: Display::Flex,
126                        justify_content: JustifyContent::Start,
127                        width: percent(IMAGE_GROUP_BOX_INIT_WIDTH),
128                        height: percent(IMAGE_GROUP_BOX_INIT_HEIGHT),
129                        ..default()
130                    },
131                    BackgroundColor(Color::from(tailwind::BLUE_100)),
132                ))
133                .with_children(|parent| {
134                    for _ in 0..4 {
135                        // child node will apply Flex layout
136                        parent.spawn((
137                            Node::default(),
138                            ImageNode {
139                                image: image_handle.clone(),
140                                image_mode: NodeImageMode::Auto,
141                                ..default()
142                            },
143                        ));
144                    }
145                });
146            // `NodeImageMode::Stretch` will resize the image to match the size of the `Node` component
147            builder
148                .spawn((
149                    ImageGroup,
150                    Node {
151                        display: Display::Flex,
152                        justify_content: JustifyContent::Start,
153                        width: percent(IMAGE_GROUP_BOX_INIT_WIDTH),
154                        height: percent(IMAGE_GROUP_BOX_INIT_HEIGHT),
155                        ..default()
156                    },
157                    BackgroundColor(Color::from(tailwind::BLUE_100)),
158                ))
159                .with_children(|parent| {
160                    for width in [10., 20., 30., 40.] {
161                        parent.spawn((
162                            Node {
163                                height: percent(100),
164                                width: percent(width),
165                                ..default()
166                            },
167                            ImageNode {
168                                image: image_handle.clone(),
169                                image_mode: NodeImageMode::Stretch,
170                                ..default()
171                            },
172                        ));
173                    }
174                });
175        });
176}
examples/ui/layout/grid.rs (line 34)
18fn spawn_layout(mut commands: Commands, asset_server: Res<AssetServer>) {
19    let font = asset_server.load("fonts/FiraSans-Bold.ttf");
20    commands.spawn(Camera2d);
21
22    // Top-level grid (app frame)
23    commands
24        .spawn((
25            Node {
26                // Use the CSS Grid algorithm for laying out this node
27                display: Display::Grid,
28                // Make node fill the entirety of its parent (in this case the window)
29                width: percent(100),
30                height: percent(100),
31                // Set the grid to have 2 columns with sizes [min-content, minmax(0, 1fr)]
32                //   - The first column will size to the size of its contents
33                //   - The second column will take up the remaining available space
34                grid_template_columns: vec![GridTrack::min_content(), GridTrack::flex(1.0)],
35                // Set the grid to have 3 rows with sizes [auto, minmax(0, 1fr), 20px]
36                //  - The first row will size to the size of its contents
37                //  - The second row take up remaining available space (after rows 1 and 3 have both been sized)
38                //  - The third row will be exactly 20px high
39                grid_template_rows: vec![
40                    GridTrack::auto(),
41                    GridTrack::flex(1.0),
42                    GridTrack::px(20.),
43                ],
44                ..default()
45            },
46            BackgroundColor(Color::WHITE),
47        ))
48        .with_children(|builder| {
49            // Header
50            builder
51                .spawn(
52                    Node {
53                        display: Display::Grid,
54                        // Make this node span two grid columns so that it takes up the entire top tow
55                        grid_column: GridPlacement::span(2),
56                        padding: UiRect::all(px(6)),
57                        ..default()
58                    },
59                )
60                .with_children(|builder| {
61                    spawn_nested_text_bundle(builder, font.clone(), "Bevy CSS Grid Layout Example");
62                });
63
64            // Main content grid (auto placed in row 2, column 1)
65            builder
66                .spawn((
67                    Node {
68                        // Make the height of the node fill its parent
69                        height: percent(100),
70                        // Make the grid have a 1:1 aspect ratio meaning it will scale as an exact square
71                        // As the height is set explicitly, this means the width will adjust to match the height
72                        aspect_ratio: Some(1.0),
73                        // Use grid layout for this node
74                        display: Display::Grid,
75                        // Add 24px of padding around the grid
76                        padding: UiRect::all(px(24)),
77                        // Set the grid to have 4 columns all with sizes minmax(0, 1fr)
78                        // This creates 4 exactly evenly sized columns
79                        grid_template_columns: RepeatedGridTrack::flex(4, 1.0),
80                        // Set the grid to have 4 rows all with sizes minmax(0, 1fr)
81                        // This creates 4 exactly evenly sized rows
82                        grid_template_rows: RepeatedGridTrack::flex(4, 1.0),
83                        // Set a 12px gap/gutter between rows and columns
84                        row_gap: px(12),
85                        column_gap: px(12),
86                        ..default()
87                    },
88                    BackgroundColor(Color::srgb(0.25, 0.25, 0.25)),
89                ))
90                .with_children(|builder| {
91                    // Note there is no need to specify the position for each grid item. Grid items that are
92                    // not given an explicit position will be automatically positioned into the next available
93                    // grid cell. The order in which this is performed can be controlled using the grid_auto_flow
94                    // style property.
95
96                    item_rect(builder, ORANGE);
97                    item_rect(builder, BISQUE);
98                    item_rect(builder, BLUE);
99                    item_rect(builder, CRIMSON);
100                    item_rect(builder, AQUA);
101                    item_rect(builder, ORANGE_RED);
102                    item_rect(builder, DARK_GREEN);
103                    item_rect(builder, FUCHSIA);
104                    item_rect(builder, TEAL);
105                    item_rect(builder, ALICE_BLUE);
106                    item_rect(builder, CRIMSON);
107                    item_rect(builder, ANTIQUE_WHITE);
108                    item_rect(builder, YELLOW);
109                    item_rect(builder, DEEP_PINK);
110                    item_rect(builder, YELLOW_GREEN);
111                    item_rect(builder, SALMON);
112                });
113
114            // Right side bar (auto placed in row 2, column 2)
115            builder
116                .spawn((
117                    Node {
118                        display: Display::Grid,
119                        // Align content towards the start (top) in the vertical axis
120                        align_items: AlignItems::Start,
121                        // Align content towards the center in the horizontal axis
122                        justify_items: JustifyItems::Center,
123                        // Add 10px padding
124                        padding: UiRect::all(px(10)),
125                        // Add an fr track to take up all the available space at the bottom of the column so that the text nodes
126                        // can be top-aligned. Normally you'd use flexbox for this, but this is the CSS Grid example so we're using grid.
127                        grid_template_rows: vec![GridTrack::auto(), GridTrack::auto(), GridTrack::fr(1.0)],
128                        // Add a 10px gap between rows
129                        row_gap: px(10),
130                        ..default()
131                    },
132                    BackgroundColor(BLACK.into()),
133                ))
134                .with_children(|builder| {
135                    builder.spawn((Text::new("Sidebar"),
136                        TextFont::from(font.clone()),
137                    ));
138                    builder.spawn((Text::new("A paragraph of text which ought to wrap nicely. A paragraph of text which ought to wrap nicely. A paragraph of text which ought to wrap nicely. A paragraph of text which ought to wrap nicely. A paragraph of text which ought to wrap nicely. A paragraph of text which ought to wrap nicely. A paragraph of text which ought to wrap nicely."),
139                        TextFont {
140                            font: font.clone().into(),
141                            font_size: FontSize::Px(13.0),
142                            ..default()
143                        },
144                    ));
145                    builder.spawn(Node::default());
146                });
147
148            // Footer / status bar
149            builder.spawn((
150                Node {
151                    // Make this node span two grid column so that it takes up the entire bottom row
152                    grid_column: GridPlacement::span(2),
153                    ..default()
154                },
155                BackgroundColor(WHITE.into()),
156            ));
157
158            // Modal (absolutely positioned on top of content - currently hidden: to view it, change its visibility)
159            builder.spawn((
160                Node {
161                    position_type: PositionType::Absolute,
162                    margin: UiRect {
163                        top: px(100),
164                        bottom: auto(),
165                        left: auto(),
166                        right: auto(),
167                    },
168                    width: percent(60),
169                    height: px(300),
170                    max_width: px(600),
171                    ..default()
172                },
173                Visibility::Hidden,
174                BackgroundColor(Color::WHITE.with_alpha(0.8)),
175            ));
176        });
177}
Source

pub fn max_content<T>() -> T
where T: From<GridTrack>,

Create a grid track which is automatically sized to fit its contents when sized at their “max-content” sizes

Source

pub fn fit_content_px<T>(limit: f32) -> T
where T: From<GridTrack>,

Create a fit-content() grid track with fixed pixel limit.

https://developer.mozilla.org/en-US/docs/Web/CSS/fit-content_function

Source

pub fn fit_content_percent<T>(limit: f32) -> T
where T: From<GridTrack>,

Create a fit-content() grid track with percentage limit.

https://developer.mozilla.org/en-US/docs/Web/CSS/fit-content_function

Source

pub fn minmax<T>(min: MinTrackSizingFunction, max: MaxTrackSizingFunction) -> T
where T: From<GridTrack>,

Source

pub fn vmin<T>(value: f32) -> T
where T: From<GridTrack>,

Create a grid track with a percentage of the viewport’s smaller dimension

Source

pub fn vmax<T>(value: f32) -> T
where T: From<GridTrack>,

Create a grid track with a percentage of the viewport’s larger dimension

Source

pub fn vh<T>(value: f32) -> T
where T: From<GridTrack>,

Create a grid track with a percentage of the viewport’s height dimension

Source

pub fn vw<T>(value: f32) -> T
where T: From<GridTrack>,

Create a grid track with a percentage of the viewport’s width dimension

Trait Implementations§

Source§

impl Clone for GridTrack

Source§

fn clone(&self) -> GridTrack

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Copy for GridTrack

Source§

impl Debug for GridTrack

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Default for GridTrack

Source§

fn default() -> GridTrack

Returns the “default value” for a type. Read more
Source§

impl<'de> Deserialize<'de> for GridTrack

Source§

fn deserialize<__D>( __deserializer: __D, ) -> Result<GridTrack, <__D as Deserializer<'de>>::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl From<GridTrack> for RepeatedGridTrack

Source§

fn from(track: GridTrack) -> RepeatedGridTrack

Converts to this type from the input type.
Source§

impl From<GridTrack> for Vec<GridTrack>

Source§

fn from(track: GridTrack) -> Vec<GridTrack>

Converts to this type from the input type.
Source§

impl From<GridTrack> for Vec<RepeatedGridTrack>

Source§

fn from(track: GridTrack) -> Vec<RepeatedGridTrack>

Converts to this type from the input type.
Source§

impl FromArg for GridTrack

Source§

type This<'from_arg> = GridTrack

The type to convert into. Read more
Source§

fn from_arg(arg: Arg<'_>) -> Result<<GridTrack as FromArg>::This<'_>, ArgError>

Creates an item from an argument. Read more
Source§

impl FromReflect for GridTrack

Source§

fn from_reflect(reflect: &(dyn PartialReflect + 'static)) -> Option<GridTrack>

Constructs a concrete instance of Self from a reflected value.
Source§

fn take_from_reflect( reflect: Box<dyn PartialReflect>, ) -> Result<Self, Box<dyn PartialReflect>>

Attempts to downcast the given value to Self using, constructing the value using from_reflect if that fails. Read more
Source§

impl GetOwnership for GridTrack

Source§

fn ownership() -> Ownership

Returns the ownership of Self.
Source§

impl GetTypeRegistration for GridTrack

Source§

fn get_type_registration() -> TypeRegistration

Returns the default TypeRegistration for this type.
Source§

fn register_type_dependencies(registry: &mut TypeRegistry)

Registers other types needed by this type. Read more
Source§

impl IntoReturn for GridTrack

Source§

fn into_return<'into_return>(self) -> Return<'into_return>
where GridTrack: 'into_return,

Converts Self into a Return value.
Source§

impl PartialEq for GridTrack

Source§

fn eq(&self, other: &GridTrack) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl PartialReflect for GridTrack

Source§

fn get_represented_type_info(&self) -> Option<&'static TypeInfo>

Returns the TypeInfo of the type represented by this value. Read more
Source§

fn try_apply( &mut self, value: &(dyn PartialReflect + 'static), ) -> Result<(), ApplyError>

Tries to apply a reflected value to this value. Read more
Source§

fn reflect_kind(&self) -> ReflectKind

Returns a zero-sized enumeration of “kinds” of type. Read more
Source§

fn reflect_ref(&self) -> ReflectRef<'_>

Returns an immutable enumeration of “kinds” of type. Read more
Source§

fn reflect_mut(&mut self) -> ReflectMut<'_>

Returns a mutable enumeration of “kinds” of type. Read more
Source§

fn reflect_owned(self: Box<GridTrack>) -> ReflectOwned

Returns an owned enumeration of “kinds” of type. Read more
Source§

fn try_into_reflect( self: Box<GridTrack>, ) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>>

Attempts to cast this type to a boxed, fully-reflected value.
Source§

fn try_as_reflect(&self) -> Option<&(dyn Reflect + 'static)>

Attempts to cast this type to a fully-reflected value.
Source§

fn try_as_reflect_mut(&mut self) -> Option<&mut (dyn Reflect + 'static)>

Attempts to cast this type to a mutable, fully-reflected value.
Source§

fn into_partial_reflect(self: Box<GridTrack>) -> Box<dyn PartialReflect>

Casts this type to a boxed, reflected value. Read more
Source§

fn as_partial_reflect(&self) -> &(dyn PartialReflect + 'static)

Casts this type to a reflected value. Read more
Source§

fn as_partial_reflect_mut(&mut self) -> &mut (dyn PartialReflect + 'static)

Casts this type to a mutable, reflected value. Read more
Source§

fn reflect_partial_eq( &self, value: &(dyn PartialReflect + 'static), ) -> Option<bool>

Returns a “partial equality” comparison result. Read more
Source§

fn reflect_partial_cmp( &self, value: &(dyn PartialReflect + 'static), ) -> Option<Ordering>

Returns a “partial comparison” result. Read more
Source§

fn reflect_clone(&self) -> Result<Box<dyn Reflect>, ReflectCloneError>

Attempts to clone Self using reflection. Read more
Source§

fn apply(&mut self, value: &(dyn PartialReflect + 'static))

Applies a reflected value to this value. Read more
Source§

fn to_dynamic(&self) -> Result<Box<dyn PartialReflect>, ReflectCloneError>

Converts this reflected value into its dynamic representation based on its kind. Read more
Source§

fn reflect_clone_and_take<T>(&self) -> Result<T, ReflectCloneError>
where T: 'static, Self: Sized + TypePath,

For a type implementing PartialReflect, combines reflect_clone and take in a useful fashion, automatically constructing an appropriate ReflectCloneError if the downcast fails.
Source§

fn reflect_hash(&self) -> Option<u64>

Returns a hash of the value (which includes the type). Read more
Source§

fn debug(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Debug formatter for the value. Read more
Source§

fn is_dynamic(&self) -> bool

Indicates whether or not this type is a dynamic type. Read more
Source§

impl Reflect for GridTrack

Source§

fn into_any(self: Box<GridTrack>) -> Box<dyn Any>

Returns the value as a Box<dyn Any>. Read more
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Returns the value as a &dyn Any. Read more
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Returns the value as a &mut dyn Any. Read more
Source§

fn into_reflect(self: Box<GridTrack>) -> Box<dyn Reflect>

Casts this type to a boxed, fully-reflected value.
Source§

fn as_reflect(&self) -> &(dyn Reflect + 'static)

Casts this type to a fully-reflected value.
Source§

fn as_reflect_mut(&mut self) -> &mut (dyn Reflect + 'static)

Casts this type to a mutable, fully-reflected value.
Source§

fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>>

Performs a type-checked assignment of a reflected value to this value. Read more
Source§

impl Serialize for GridTrack

Source§

fn serialize<__S>( &self, __serializer: __S, ) -> Result<<__S as Serializer>::Ok, <__S as Serializer>::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl Struct for GridTrack

Source§

fn field(&self, name: &str) -> Option<&(dyn PartialReflect + 'static)>

Gets a reference to the value of the field named name as a &dyn PartialReflect.
Source§

fn field_mut( &mut self, name: &str, ) -> Option<&mut (dyn PartialReflect + 'static)>

Gets a mutable reference to the value of the field named name as a &mut dyn PartialReflect.
Source§

fn field_at(&self, index: usize) -> Option<&(dyn PartialReflect + 'static)>

Gets a reference to the value of the field with index index as a &dyn PartialReflect.
Source§

fn field_at_mut( &mut self, index: usize, ) -> Option<&mut (dyn PartialReflect + 'static)>

Gets a mutable reference to the value of the field with index index as a &mut dyn PartialReflect.
Source§

fn name_at(&self, index: usize) -> Option<&str>

Gets the name of the field with index index.
Source§

fn index_of_name(&self, name: &str) -> Option<usize>

Gets the index of the field with the given name.
Source§

fn field_len(&self) -> usize

Returns the number of fields in the struct.
Source§

fn iter_fields(&self) -> FieldIter<'_> ⓘ

Returns an iterator over the values of the reflectable fields for this struct.
Source§

fn to_dynamic_struct(&self) -> Result<DynamicStruct, ReflectCloneError>

Creates a new DynamicStruct from this struct. Read more
Source§

fn get_represented_struct_info(&self) -> Option<&'static StructInfo>

Will return None if TypeInfo is not available.
Source§

impl StructuralPartialEq for GridTrack

Source§

impl TypePath for GridTrack

Source§

fn type_path() -> &'static str

Returns the fully qualified path of the underlying type. Read more
Source§

fn short_type_path() -> &'static str

Returns a short, pretty-print enabled path to the type. Read more
Source§

fn type_ident() -> Option<&'static str>

Returns the name of the type, or None if it is anonymous. Read more
Source§

fn crate_name() -> Option<&'static str>

Returns the name of the crate the type is in, or None if it is anonymous. Read more
Source§

fn module_path() -> Option<&'static str>

Returns the path to the module the type is in, or None if it is anonymous. Read more
Source§

impl Typed for GridTrack

Source§

fn type_info() -> &'static TypeInfo

Returns the compile-time info for the underlying type.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T, U> AsBindGroupShaderType<U> for T
where U: ShaderType, &'a T: for<'a> Into<U>,

Source§

fn as_bind_group_shader_type(&self, _images: &RenderAssets<GpuImage>) -> U

Return the T ShaderType for self. When used in AsBindGroup derives, it is safe to assume that all images in self exist.
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> Brush for T
where T: Clone + PartialEq + Default + Debug,

Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> ConditionalSend for T
where T: Send,

Source§

impl<T> Conv for T

Source§

fn conv<T>(self) -> T
where Self: Into<T>,

Converts self into T using Into<T>. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Converts Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Converts Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Converts &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Converts &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> DowncastSend for T
where T: Any + Send,

Source§

fn into_any_send(self: Box<T>) -> Box<dyn Any + Send>

Converts Box<Trait> (where Trait: DowncastSend) to Box<dyn Any + Send>, which can then be downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Send + Sync> ⓘ

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<S, T> Duplex<S> for T
where T: FromSample<S> + ToSample<S>,

Source§

impl<T> DynamicTypePath for T
where T: TypePath,

Source§

impl<T> DynamicTyped for T
where T: Typed,

Source§

impl<T> ErasedDestructor for T
where T: 'static,

Source§

impl<T> FmtForward for T

Source§

fn fmt_binary(self) -> FmtBinary<Self>
where Self: Binary,

Causes self to use its Binary implementation when Debug-formatted.
Source§

fn fmt_display(self) -> FmtDisplay<Self>
where Self: Display,

Causes self to use its Display implementation when Debug-formatted.
Source§

fn fmt_lower_exp(self) -> FmtLowerExp<Self>
where Self: LowerExp,

Causes self to use its LowerExp implementation when Debug-formatted.
Source§

fn fmt_lower_hex(self) -> FmtLowerHex<Self>
where Self: LowerHex,

Causes self to use its LowerHex implementation when Debug-formatted.
Source§

fn fmt_octal(self) -> FmtOctal<Self>
where Self: Octal,

Causes self to use its Octal implementation when Debug-formatted.
Source§

fn fmt_pointer(self) -> FmtPointer<Self>
where Self: Pointer,

Causes self to use its Pointer implementation when Debug-formatted.
Source§

fn fmt_upper_exp(self) -> FmtUpperExp<Self>
where Self: UpperExp,

Causes self to use its UpperExp implementation when Debug-formatted.
Source§

fn fmt_upper_hex(self) -> FmtUpperHex<Self>
where Self: UpperHex,

Causes self to use its UpperHex implementation when Debug-formatted.
Source§

fn fmt_list(self) -> FmtList<Self>
where &'a Self: for<'a> IntoIterator,

Formats each item in a sequence. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<S> FromSample<S> for S

Source§

fn from_sample_(s: S) -> S

Source§

impl<T> FromTemplate for T
where T: Clone + Default + Unpin,

Source§

type Template = T

The Template for this type.
Source§

impl<T> FromWorld for T
where T: Default,

Source§

fn from_world(_world: &mut World) -> T

Creates Self using default().

Source§

impl<S> GetField for S
where S: Struct,

Source§

fn get_field<T>(&self, name: &str) -> Option<&T>
where T: Reflect,

Gets a reference to the value of the field named name, downcast to T.
Source§

fn get_field_mut<T>(&mut self, name: &str) -> Option<&mut T>
where T: Reflect,

Gets a mutable reference to the value of the field named name, downcast to T.
Source§

impl<T> GetPath for T
where T: Reflect + ?Sized,

Source§

fn reflect_path<'p>( &self, path: impl ReflectPath<'p>, ) -> Result<&(dyn PartialReflect + 'static), ReflectPathError<'p>>

Returns a reference to the value specified by path. Read more
Source§

fn reflect_path_mut<'p>( &mut self, path: impl ReflectPath<'p>, ) -> Result<&mut (dyn PartialReflect + 'static), ReflectPathError<'p>>

Returns a mutable reference to the value specified by path. Read more
Source§

fn path<'p, T>( &self, path: impl ReflectPath<'p>, ) -> Result<&T, ReflectPathError<'p>>
where T: Reflect,

Returns a statically typed reference to the value specified by path. Read more
Source§

fn path_mut<'p, T>( &mut self, path: impl ReflectPath<'p>, ) -> Result<&mut T, ReflectPathError<'p>>
where T: Reflect,

Returns a statically typed mutable reference to the value specified by path. Read more
Source§

impl<T, W> HasTypeWitness<W> for T
where W: MakeTypeWitness<Arg = T>, T: ?Sized,

Source§

const WITNESS: W = W::MAKE

A constant of the type witness
Source§

impl<T> HitDataExtra for T
where T: Send + Sync + Debug + Any + 'static,

Source§

impl<T> Identity for T
where T: ?Sized,

Source§

const TYPE_EQ: TypeEq<T, <T as Identity>::Type> = TypeEq::NEW

Proof that Self is the same type as Self::Type, provides methods for casting between Self and Self::Type.
Source§

type Type = T

The same type as Self, used to emulate type equality bounds (T == U) with associated type equality constraints (T: Identity<Type = U>).
Source§

impl<T> InitializeFromFunction<T> for T

Source§

fn initialize_from_function(f: fn() -> T) -> T

Create an instance of this type from an initialization function
Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> IntoResult<T> for T

Source§

fn into_result(self) -> Result<T, RunSystemError>

Converts this type into the system output type.
Source§

impl<F, T> IntoSample<T> for F
where T: FromSample<F>,

Source§

fn into_sample(self) -> T

Source§

impl<A> Is for A
where A: Any,

Source§

fn is<T>() -> bool
where T: Any,

Checks if the current type “is” another type, using a TypeId equality comparison. This is most useful in the context of generic logic. Read more
Source§

impl<T> NoneValue for T
where T: Default,

Source§

type NoneType = T

Source§

fn null_value() -> T

The none-equivalent value.
Source§

impl<G> PatchFromTemplate for G
where G: FromTemplate,

Source§

type Template = <G as FromTemplate>::Template

The Template that will be patched.
Source§

fn patch<F>(func: F) -> TemplatePatch<F, <G as PatchFromTemplate>::Template>
where F: FnOnce(&mut <G as PatchFromTemplate>::Template, &mut ResolveContext<'_>),

Takes a “patch function” func, and turns it into a TemplatePatch.
Source§

impl<T> PatchTemplate for T
where T: Template,

Source§

fn patch_template<F>(func: F) -> TemplatePatch<F, T>
where F: FnOnce(&mut T, &mut ResolveContext<'_>),

Takes a “patch function” func that patches this Template, and turns it into a TemplatePatch.
Source§

impl<T> Pipe for T
where T: ?Sized,

Source§

fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> R
where Self: Sized,

Pipes by value. This is generally the method you want to use. Read more
Source§

fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> R
where R: 'a,

Borrows self and passes that borrow into the pipe function. Read more
Source§

fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> R
where R: 'a,

Mutably borrows self and passes that borrow into the pipe function. Read more
Source§

fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
where Self: Borrow<B>, B: 'a + ?Sized, R: 'a,

Borrows self, then passes self.borrow() into the pipe function. Read more
Source§

fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
where Self: BorrowMut<B>, B: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.borrow_mut() into the pipe function. Read more
Source§

fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
where Self: AsRef<U>, U: 'a + ?Sized, R: 'a,

Borrows self, then passes self.as_ref() into the pipe function.
Source§

fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
where Self: AsMut<U>, U: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.as_mut() into the pipe function.
Source§

fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
where Self: Deref<Target = T>, T: 'a + ?Sized, R: 'a,

Borrows self, then passes self.deref() into the pipe function.
Source§

fn pipe_deref_mut<'a, T, R>( &'a mut self, func: impl FnOnce(&'a mut T) -> R, ) -> R
where Self: DerefMut<Target = T> + Deref, T: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.deref_mut() into the pipe function.
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<R, P> ReadPrimitive<R> for P
where R: Read + ReadEndian<P>, P: Default,

Source§

fn read_from_little_endian(read: &mut R) -> Result<Self, Error>

Read this value from the supplied reader. Same as ReadEndian::read_from_little_endian().
Source§

fn read_from_big_endian(read: &mut R) -> Result<Self, Error>

Read this value from the supplied reader. Same as ReadEndian::read_from_big_endian().
Source§

fn read_from_native_endian(read: &mut R) -> Result<Self, Error>

Read this value from the supplied reader. Same as ReadEndian::read_from_native_endian().
Source§

impl<T> Reflectable for T

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> Serialize for T
where T: Serialize + ?Sized,

Source§

fn erased_serialize(&self, serializer: &mut dyn Serializer) -> Result<(), Error>

Source§

fn do_erased_serialize( &self, serializer: &mut dyn Serializer, ) -> Result<(), ErrorImpl>

Source§

impl<T> Settings for T
where T: 'static + Send + Sync,

Source§

impl<Ret> SpawnIfAsync<(), Ret> for Ret

Source§

fn spawn(self) -> Ret

Spawn the value into the dioxus runtime if it is an async block
Source§

impl<T, O> SuperFrom<T> for O
where O: From<T>,

Source§

fn super_from(input: T) -> O

Convert from a type to another type.
Source§

impl<T, O, M> SuperInto<O, M> for T
where O: SuperFrom<T, M>,

Source§

fn super_into(self) -> O

Convert from a type to another type.
Source§

impl<T> Tap for T

Source§

fn tap(self, func: impl FnOnce(&Self)) -> Self

Immutable access to a value. Read more
Source§

fn tap_mut(self, func: impl FnOnce(&mut Self)) -> Self

Mutable access to a value. Read more
Source§

fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Immutable access to the Borrow<B> of a value. Read more
Source§

fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
where Self: BorrowMut<B>, B: ?Sized,

Mutable access to the BorrowMut<B> of a value. Read more
Source§

fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Immutable access to the AsRef<R> view of a value. Read more
Source§

fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
where Self: AsMut<R>, R: ?Sized,

Mutable access to the AsMut<R> view of a value. Read more
Source§

fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Immutable access to the Deref::Target of a value. Read more
Source§

fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Mutable access to the Deref::Target of a value. Read more
Source§

fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self

Calls .tap() only in debug builds, and is erased in release builds.
Source§

fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self

Calls .tap_mut() only in debug builds, and is erased in release builds.
Source§

fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Calls .tap_borrow() only in debug builds, and is erased in release builds.
Source§

fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
where Self: BorrowMut<B>, B: ?Sized,

Calls .tap_borrow_mut() only in debug builds, and is erased in release builds.
Source§

fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Calls .tap_ref() only in debug builds, and is erased in release builds.
Source§

fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
where Self: AsMut<R>, R: ?Sized,

Calls .tap_ref_mut() only in debug builds, and is erased in release builds.
Source§

fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Calls .tap_deref() only in debug builds, and is erased in release builds.
Source§

fn tap_deref_mut_dbg<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Calls .tap_deref_mut() only in debug builds, and is erased in release builds.
Source§

impl<T> Template for T
where T: Clone + Unpin,

Source§

type Output = T

The type of value produced by this Template.
Source§

fn build_template( &self, _context: &mut TemplateContext<'_, '_>, ) -> Result<<T as Template>::Output, BevyError>

Uses this template and the given entity context to produce a Template::Output.
Source§

fn clone_template(&self) -> T

Clones this template. See Clone.
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> ToSample<U> for T
where U: FromSample<T>,

Source§

fn to_sample_(self) -> U

Source§

impl<T> TryConv for T

Source§

fn try_conv<T>(self) -> Result<T, Self::Error>
where Self: TryInto<T>,

Attempts to convert self into T using TryInto<T>. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> TypeData for T
where T: 'static + Send + Sync + Clone,

Source§

fn clone_type_data(&self) -> Box<dyn TypeData>

Creates a type-erased clone of self.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WasmNotSend for T
where T: Send,

Source§

impl<T> WasmNotSendSync for T

Source§

impl<T> WasmNotSync for T
where T: Sync,

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more