tl;dr: This adds `.block_mouse_except_scroll()` which should typically
be used instead of `.occlude()` for cases when the mouse shouldn't
interact with elements drawn below an element. The rationale for
treating scroll events differently:
* Mouse move / click / styles / tooltips are for elements the user is
interacting with directly.
* Mouse scroll events are about finding the current outer scroll
container.
Most use of `occlude` should probably be switched to this, but I figured
I'd derisk this change by minimizing behavior changes to just the 3 uses
of `block_mouse_except_scroll`.
GPUI changes:
* Added `InteractiveElement::block_mouse_except_scroll()`, and removes
`stop_mouse_events_except_scroll()`
* Added `Hitbox::should_handle_scroll()` to be used when handling scroll
wheel events.
* `Window::insert_hitbox` now takes `HitboxBehavior` instead of
`occlude: bool`.
- `false` for that bool is now `HitboxBehavior::Normal`.
- `true` for that bool is now `HitboxBehavior::BlockMouse`.
- The new mode is `HitboxBehavior::BlockMouseExceptScroll`.
* Removes `Default` impl for `HitboxId` since applications should not
manually create `HitboxId(0)`.
Release Notes:
- N/A
Open inspector with `dev: toggle inspector` from command palette or
`cmd-alt-i` on mac or `ctrl-alt-i` on linux.
https://github.com/user-attachments/assets/54c43034-d40b-414e-ba9b-190bed2e6d2f
* Picking of elements via the mouse, with scroll wheel to inspect
occluded elements.
* Temporary manipulation of the selected element.
* Layout info and JSON-based style manipulation for `Div`.
* Navigation to code that constructed the element.
Big thanks to @as-cii and @maxdeviant for sorting out how to implement
the core of an inspector.
Release Notes:
- N/A
---------
Co-authored-by: Antonio Scandurra <me@as-cii.com>
Co-authored-by: Marshall Bowers <git@maxdeviant.com>
Co-authored-by: Federico Dionisi <code@fdionisi.me>
Felt like this was relevant particularly as we're living with both
`trigger` and `trigger_with_tooltip`. At some point, I believe there
should be only one (`trigger_with_tooltip`) and that should be then
renamed to just `trigger` back again! We're supporting both for now just
for ease of migration/avoiding big changes.
Release Notes:
- N/A
There's still a bit more work to do on this, but this PR is compiling
(with warnings) after eliminating the key types. When the tasks below
are complete, this will be the new narrative for GPUI:
- `Entity<T>` - This replaces `View<T>`/`Model<T>`. It represents a unit
of state, and if `T` implements `Render`, then `Entity<T>` implements
`Element`.
- `&mut App` This replaces `AppContext` and represents the app.
- `&mut Context<T>` This replaces `ModelContext` and derefs to `App`. It
is provided by the framework when updating an entity.
- `&mut Window` Broken out of `&mut WindowContext` which no longer
exists. Every method that once took `&mut WindowContext` now takes `&mut
Window, &mut App` and every method that took `&mut ViewContext<T>` now
takes `&mut Window, &mut Context<T>`
Not pictured here are the two other failed attempts. It's been quite a
month!
Tasks:
- [x] Remove `View`, `ViewContext`, `WindowContext` and thread through
`Window`
- [x] [@cole-miller @mikayla-maki] Redraw window when entities change
- [x] [@cole-miller @mikayla-maki] Get examples and Zed running
- [x] [@cole-miller @mikayla-maki] Fix Zed rendering
- [x] [@mikayla-maki] Fix todo! macros and comments
- [x] Fix a bug where the editor would not be redrawn because of view
caching
- [x] remove publicness window.notify() and replace with
`AppContext::notify`
- [x] remove `observe_new_window_models`, replace with
`observe_new_models` with an optional window
- [x] Fix a bug where the project panel would not be redrawn because of
the wrong refresh() call being used
- [x] Fix the tests
- [x] Fix warnings by eliminating `Window` params or using `_`
- [x] Fix conflicts
- [x] Simplify generic code where possible
- [x] Rename types
- [ ] Update docs
### issues post merge
- [x] Issues switching between normal and insert mode
- [x] Assistant re-rendering failure
- [x] Vim test failures
- [x] Mac build issue
Release Notes:
- N/A
---------
Co-authored-by: Antonio Scandurra <me@as-cii.com>
Co-authored-by: Cole Miller <cole@zed.dev>
Co-authored-by: Mikayla <mikayla@zed.dev>
Co-authored-by: Joseph <joseph@zed.dev>
Co-authored-by: max <max@zed.dev>
Co-authored-by: Michael Sloan <michael@zed.dev>
Co-authored-by: Mikayla Maki <mikaylamaki@Mikaylas-MacBook-Pro.local>
Co-authored-by: Mikayla <mikayla.c.maki@gmail.com>
Co-authored-by: joão <joao@zed.dev>
Before, the conversation popover menu covered up what you were typing
because it wasn't offset properly.
Now it's offset properly, using the UI font size so the amount of offset
scales with the font size:
<img width="435" alt="Screenshot 2025-01-07 at 4 34 27 PM"
src="https://github.com/user-attachments/assets/55e40910-8cd4-4548-b4fb-521eb2845775"
/>
<img width="454" alt="Screenshot 2025-01-07 at 4 33 58 PM"
src="https://github.com/user-attachments/assets/30350489-09f1-4cb8-9f95-ed4ee87bc110"
/>
<img width="488" alt="Screenshot 2025-01-07 at 4 34 18 PM"
src="https://github.com/user-attachments/assets/de60d990-2bd9-418d-a616-56beb3e4aa8a"
/>
Release Notes:
- N/A *or* Added/Fixed/Improved ...

- Adds the Switch component
- Updates `Selected`, `Selectable` -> `ToggleState`, `Toggleable`
- Adds `checkbox` and `switch` functions to align better with other
elements in our layout system.
We decided not to merge Switch and Checkbox. However, in a followup I'll
introduce a Toggle or AnyToggle enum so we can update
`CheckboxWithLabel` -> `ToggleWithLabel` as this component will work
exactly the same with either a Checkbox or a Switch.
Release Notes:
- N/A
Similar to https://github.com/zed-industries/zed/pull/18690 &
https://github.com/zed-industries/zed/pull/18695, this PR enables
required docs for `ui` and does some cleanup.
Changes:
- Enables the `deny(missing_docs)` crate-wide.
- Adds `allow(missing_docs)` on many modules until folks pick them up to
document them
- Documents some modules (all in `ui/src/styles`)
- Crate root-level organization: Traits move to `traits`, other misc
organization
- Cleaned out a bunch of unused code.
Note: I'd like to remove `utils/format_distance` but the assistant panel
uses it. To move it over to use the `time_format` crate we may need to
update it to use `time` instead of `chrono`. Needs more investigation.
Release Notes:
- N/A
This PR replaces the `popover_menu` function for constructing
`PopoverMenu`s with a `PopoverMenu::new` associated function.
This brings `PopoverMenu` in line with our other UI components.
Release Notes:
- N/A
A minor thing I've spotted and decided to fix on the spot.
It was being cloned twice within the body of that function (one of which
was redundant even without this PR); now in most cases we go down from 2
clones to 0.
Release Notes:
- N/A
We're planning to associate "selection sources" with global element ids
to allow arbitrary UI text to be selected in GPUI. Previously, global
ids were not exposed outside the framework and we entangled management
of the element id stack with element state access. This was more
acceptable when element state was the only place we used global element
ids, but now that we're planning to use them more places, it makes sense
to deal with element identity as a first-class part of the element
system. We now ensure that the stack of element ids which forms the
current global element id is correctly managed in every phase of element
layout and paint and make the global id available to each element
method. In a subsequent PR, we'll use the global element id as part of
implementing arbitrary selection for UI text.
Release Notes:
- N/A
---------
Co-authored-by: Antonio Scandurra <me@as-cii.com>
The new `ElementContext` was originally introduced to ensure the element
APIs could only be used inside of elements. Unfortunately, there were
many places where some of those APIs needed to be used, so
`WindowContext::with_element_context` was introduced, which defeated the
original safety purposes of having a specific context for elements.
This pull request merges `ElementContext` into `WindowContext` and adds
(debug) runtime checks to APIs that can only be used during certain
phases of element drawing.
Release Notes:
- N/A
---------
Co-authored-by: Nathan Sobo <nathan@zed.dev>
This pull request introduces the new
`ElementContext::request_autoscroll(bounds)` and
`ElementContext::take_autoscroll()` methods in GPUI. These new APIs
enable container elements such as `List` to change their scroll position
if one of their children requested an autoscroll. We plan to use this in
the revamped assistant.
As a drive-by, we also:
- Renamed `Element::before_layout` to `Element::request_layout`
- Renamed `Element::after_layout` to `Element::prepaint`
- Introduced a new `List::splice_focusable` method to splice focusable
elements into the list, which enables rendering offscreen elements that
are focused.
Release Notes:
- N/A
---------
Co-authored-by: Nathan <nathan@zed.dev>
Closes#10017. While reworking the `overlay` element in #9911, I did not
realize that all overlay elements called `defer_draw` with a priority of
`1`.
/cc @as-cii
Not including release notes, since it was only present in nightly.
Release Notes:
- N/A
There was a problem using deferred draws with `overlay` and tooltips at
the same time.
The `overlay` element was removed and was split up into two separate
elements
- `deferred`
- `anchored` - Mimics the `overlay` behavior but does not render its
children as deferred
`tooltip_container` does not defer its drawing anymore and only uses
`anchored`.
/cc @as-cii
Release Notes:
- Fixed tooltip for the recent projects popover not showing anymore
---------
Co-authored-by: Antonio <antonio@zed.dev>
This PR adds a new `rems_from_px` helper function that can be used to
compute rem values based on a pixel value.
This is something we do fairly commonly, where we want to express a size
that is a given pixel size at the base rem size (e.g., "14px when the
rem size is 16px").
`rems_from_px` helps make the intent more explicit, as well as prevent
the base rem size from being duplicated everywhere.
Note: Ideally we would want `rems_from_px` to be `const`, but that
depends on https://github.com/rust-lang/rust/issues/57241.
Release Notes:
- N/A
Previously, we were considering the mouse to be "out" of a div when its
hitbox wasn't hovered. However, if a parent listened for
"mouse_down_out" and a child occluded the parent, the parent would
always think the mouse was out even when the user clicked the child.
This commit changes the definition of "mouse out" to simply mean "does
not contain the point", without accounting for occlusion.
Release Notes:
- N/A
Co-authored-by: Julia <julia@zed.dev>
See https://zed.dev/channel/gpui-536
Fixes https://github.com/zed-industries/zed/issues/9010
Fixes https://github.com/zed-industries/zed/issues/8883
Fixes https://github.com/zed-industries/zed/issues/8640
Fixes https://github.com/zed-industries/zed/issues/8598
Fixes https://github.com/zed-industries/zed/issues/8579
Fixes https://github.com/zed-industries/zed/issues/8363
Fixes https://github.com/zed-industries/zed/issues/8207
### Problem
After transitioning Zed to GPUI 2, we started noticing that interacting
with the mouse on many UI elements would lead to a pretty annoying
flicker. The main issue with the old approach was that hover state was
calculated based on the previous frame. That is, when computing whether
a given element was hovered in the current frame, we would use
information about the same element in the previous frame.
However, inspecting the previous frame tells us very little about what
should be hovered in the current frame, as elements in the current frame
may have changed significantly.
### Solution
This pull request's main contribution is the introduction of a new
`after_layout` phase when redrawing the window. The key idea is that
we'll give every element a chance to register a hitbox (see
`ElementContext::insert_hitbox`) before painting anything. Then, during
the `paint` phase, elements can determine whether they're the topmost
and draw their hover state accordingly.
We are also removing the ability to give an arbitrary z-index to
elements. Instead, we will follow the much simpler painter's algorithm.
That is, an element that gets painted after will be drawn on top of an
element that got painted earlier. Elements can still escape their
current "stacking context" by using the new `ElementContext::defer_draw`
method (see `Overlay` for an example). Elements drawn using this method
will still be logically considered as being children of their original
parent (for keybinding, focus and cache invalidation purposes) but their
layout and paint passes will be deferred until the currently-drawn
element is done.
With these changes we also reworked geometry batching within the
`Scene`. The new approach uses an AABB tree to determine geometry
occlusion, which allows the GPU to render non-overlapping geometry in
parallel.
### Performance
Performance is slightly better than on `main` even though this new
approach is more correct and we're maintaining an extra data structure
(the AABB tree).

Release Notes:
- Fixed a bug that was causing popovers to flicker.
---------
Co-authored-by: Nathan Sobo <nathan@zed.dev>
Co-authored-by: Thorsten <thorsten@zed.dev>
This PR cleans up a number of references in doc comments in the `ui` and
`theme` crates so that `rustdoc` will link and display them correctly.
Release Notes:
- N/A