diff --git a/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.h b/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.h index c0c4b2d7b5..e038a855e3 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.h @@ -104,6 +104,7 @@ public: Optional playback_button_rect; Optional timeline_rect; Optional speaker_button_rect; + Optional volume_rect; }; CachedLayoutBoxes& cached_layout_boxes(Badge) const { return m_layout_boxes; } diff --git a/Userland/Libraries/LibWeb/Painting/MediaPaintable.cpp b/Userland/Libraries/LibWeb/Painting/MediaPaintable.cpp index 9996d4153e..1831edb349 100644 --- a/Userland/Libraries/LibWeb/Painting/MediaPaintable.cpp +++ b/Userland/Libraries/LibWeb/Painting/MediaPaintable.cpp @@ -62,6 +62,7 @@ void MediaPaintable::paint_media_controls(PaintContext& context, HTML::HTMLMedia paint_control_bar_timeline(context, media_element, components, mouse_position); paint_control_bar_timestamp(context, components); paint_control_bar_speaker(context, media_element, components, mouse_position); + paint_control_bar_volume(context, media_element, components, mouse_position); } MediaPaintable::Components MediaPaintable::compute_control_bar_components(PaintContext& context, HTML::HTMLMediaElement const& media_element, DevicePixelRect media_rect) const @@ -85,6 +86,16 @@ MediaPaintable::Components MediaPaintable::compute_control_bar_components(PaintC components.speaker_button_size = context.rounded_device_pixels(30); if (components.speaker_button_size <= remaining_rect.width()) { + components.volume_button_size = context.rounded_device_pixels(16); + + if ((components.speaker_button_size + components.volume_button_size * 3) <= remaining_rect.width()) { + auto volume_width = min(context.rounded_device_pixels(60), remaining_rect.width() - components.speaker_button_size); + + components.volume_rect = remaining_rect; + components.volume_rect.take_from_left(remaining_rect.width() - volume_width); + remaining_rect.take_from_right(volume_width); + } + components.speaker_button_rect = remaining_rect; components.speaker_button_rect.take_from_left(remaining_rect.width() - components.speaker_button_size); remaining_rect.take_from_right(components.speaker_button_size + component_padding); @@ -114,6 +125,7 @@ MediaPaintable::Components MediaPaintable::compute_control_bar_components(PaintC media_element.cached_layout_boxes({}).playback_button_rect = context.scale_to_css_rect(components.playback_button_rect); media_element.cached_layout_boxes({}).timeline_rect = context.scale_to_css_rect(components.timeline_rect); media_element.cached_layout_boxes({}).speaker_button_rect = context.scale_to_css_rect(components.speaker_button_rect); + media_element.cached_layout_boxes({}).volume_rect = context.scale_to_css_rect(components.volume_rect); return components; } @@ -237,6 +249,36 @@ void MediaPaintable::paint_control_bar_speaker(PaintContext& context, HTML::HTML } } +void MediaPaintable::paint_control_bar_volume(PaintContext& context, HTML::HTMLMediaElement const& media_element, Components const& components, Optional const& mouse_position) +{ + if (components.volume_rect.is_empty()) + return; + + auto volume_scrub_rect = components.volume_rect; + volume_scrub_rect.shrink(components.volume_button_size, volume_scrub_rect.height() - components.volume_button_size / 2); + + auto volume_position = static_cast(static_cast(volume_scrub_rect.width())) * media_element.volume(); + auto volume_button_offset_x = static_cast(round(volume_position)); + + Gfx::AntiAliasingPainter painter { context.painter() }; + + auto volume_lower_rect = volume_scrub_rect; + volume_lower_rect.set_width(volume_button_offset_x); + painter.fill_rect_with_rounded_corners(volume_lower_rect.to_type(), control_highlight_color.lightened(), 4); + + auto volume_higher_rect = volume_scrub_rect; + volume_higher_rect.take_from_left(volume_button_offset_x); + painter.fill_rect_with_rounded_corners(volume_higher_rect.to_type(), Color::Black, 4); + + auto volume_button_rect = volume_scrub_rect; + volume_button_rect.shrink(volume_scrub_rect.width() - components.volume_button_size, volume_scrub_rect.height() - components.volume_button_size); + volume_button_rect.set_x(volume_scrub_rect.x() + volume_button_offset_x - components.volume_button_size / 2); + + auto volume_is_hovered = mouse_position.has_value() && components.volume_rect.contains(*mouse_position); + auto volume_color = control_button_color(volume_is_hovered); + painter.fill_ellipse(volume_button_rect.to_type(), volume_color); +} + MediaPaintable::DispatchEventOfSameName MediaPaintable::handle_mouseup(Badge, CSSPixelPoint position, unsigned button, unsigned) { if (button != GUI::MouseButton::Primary) @@ -281,6 +323,15 @@ MediaPaintable::DispatchEventOfSameName MediaPaintable::handle_mouseup(Badgecontains(position)) { + auto x_offset = position.x() - cached_layout_boxes.volume_rect->x(); + auto volume = static_cast(x_offset) / static_cast(cached_layout_boxes.volume_rect->width()); + + media_element.set_volume(volume).release_value_but_fixme_should_propagate_errors(); + + return DispatchEventOfSameName::Yes; + } + return DispatchEventOfSameName::No; } diff --git a/Userland/Libraries/LibWeb/Painting/MediaPaintable.h b/Userland/Libraries/LibWeb/Painting/MediaPaintable.h index 73d75a0e7b..e6c0cf4ee3 100644 --- a/Userland/Libraries/LibWeb/Painting/MediaPaintable.h +++ b/Userland/Libraries/LibWeb/Painting/MediaPaintable.h @@ -37,6 +37,9 @@ private: DevicePixelRect speaker_button_rect; DevicePixels speaker_button_size; + + DevicePixelRect volume_rect; + DevicePixels volume_button_size; }; virtual bool wants_mouse_events() const override { return true; } @@ -48,6 +51,7 @@ private: static void paint_control_bar_timeline(PaintContext&, HTML::HTMLMediaElement const&, Components const&, Optional const& mouse_position); static void paint_control_bar_timestamp(PaintContext&, Components const&); static void paint_control_bar_speaker(PaintContext&, HTML::HTMLMediaElement const&, Components const& components, Optional const& mouse_position); + static void paint_control_bar_volume(PaintContext&, HTML::HTMLMediaElement const&, Components const&, Optional const& mouse_position); }; }