mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-09-20 01:37:39 +03:00
LibWeb: Draw a speaker on media elements to toggle muting audio
This commit is contained in:
parent
1107cb58c0
commit
a4cb3b5d4d
Notes:
sideshowbarker
2024-07-17 10:31:19 +09:00
Author: https://github.com/trflynn89 Commit: https://github.com/SerenityOS/serenity/commit/a4cb3b5d4d Pull-request: https://github.com/SerenityOS/serenity/pull/19409
@ -389,6 +389,9 @@ void HTMLMediaElement::volume_or_muted_attribute_changed()
|
||||
|
||||
// FIXME: Then, if the media element is not allowed to play, the user agent must run the internal pause steps for the media element.
|
||||
|
||||
if (auto* layout_node = this->layout_node())
|
||||
layout_node->set_needs_display();
|
||||
|
||||
on_volume_change();
|
||||
}
|
||||
|
||||
|
@ -103,6 +103,7 @@ public:
|
||||
Optional<CSSPixelRect> control_box_rect;
|
||||
Optional<CSSPixelRect> playback_button_rect;
|
||||
Optional<CSSPixelRect> timeline_rect;
|
||||
Optional<CSSPixelRect> speaker_button_rect;
|
||||
};
|
||||
CachedLayoutBoxes& cached_layout_boxes(Badge<Painting::MediaPaintable>) const { return m_layout_boxes; }
|
||||
|
||||
|
@ -61,6 +61,7 @@ void MediaPaintable::paint_media_controls(PaintContext& context, HTML::HTMLMedia
|
||||
paint_control_bar_playback_button(context, media_element, components, mouse_position);
|
||||
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);
|
||||
}
|
||||
|
||||
MediaPaintable::Components MediaPaintable::compute_control_bar_components(PaintContext& context, HTML::HTMLMediaElement const& media_element, DevicePixelRect media_rect) const
|
||||
@ -82,6 +83,13 @@ MediaPaintable::Components MediaPaintable::compute_control_bar_components(PaintC
|
||||
components.playback_button_rect.set_width(playback_button_rect_width);
|
||||
remaining_rect.take_from_left(playback_button_rect_width);
|
||||
|
||||
components.speaker_button_size = context.rounded_device_pixels(30);
|
||||
if (components.speaker_button_size <= remaining_rect.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);
|
||||
}
|
||||
|
||||
auto current_time = human_readable_digital_time(round(media_element.current_time()));
|
||||
auto duration = human_readable_digital_time(isnan(media_element.duration()) ? 0 : round(media_element.duration()));
|
||||
components.timestamp = String::formatted("{} / {}", current_time, duration).release_value_but_fixme_should_propagate_errors();
|
||||
@ -105,6 +113,7 @@ MediaPaintable::Components MediaPaintable::compute_control_bar_components(PaintC
|
||||
media_element.cached_layout_boxes({}).control_box_rect = context.scale_to_css_rect(components.control_box_rect);
|
||||
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);
|
||||
|
||||
return components;
|
||||
}
|
||||
@ -182,6 +191,52 @@ void MediaPaintable::paint_control_bar_timestamp(PaintContext& context, Componen
|
||||
context.painter().draw_text(components.timestamp_rect.to_type<int>(), components.timestamp, *components.timestamp_font, Gfx::TextAlignment::CenterLeft, Color::White);
|
||||
}
|
||||
|
||||
void MediaPaintable::paint_control_bar_speaker(PaintContext& context, HTML::HTMLMediaElement const& media_element, Components const& components, Optional<DevicePixelPoint> const& mouse_position)
|
||||
{
|
||||
if (components.speaker_button_rect.is_empty())
|
||||
return;
|
||||
|
||||
auto speaker_button_width = context.rounded_device_pixels(20);
|
||||
auto speaker_button_height = context.rounded_device_pixels(15);
|
||||
|
||||
auto speaker_button_offset_x = (components.speaker_button_rect.width() - speaker_button_width) / 2;
|
||||
auto speaker_button_offset_y = (components.speaker_button_rect.height() - speaker_button_height) / 2;
|
||||
auto speaker_button_location = components.speaker_button_rect.top_left().translated(speaker_button_offset_x, speaker_button_offset_y);
|
||||
|
||||
auto device_point = [&](double x, double y) {
|
||||
auto position = context.rounded_device_point({ x, y }) + speaker_button_location;
|
||||
return position.to_type<DevicePixels::Type>().to_type<float>();
|
||||
};
|
||||
|
||||
auto speaker_button_is_hovered = mouse_position.has_value() && components.speaker_button_rect.contains(*mouse_position);
|
||||
auto speaker_button_color = control_button_color(speaker_button_is_hovered);
|
||||
|
||||
Gfx::AntiAliasingPainter painter { context.painter() };
|
||||
Gfx::Path path;
|
||||
|
||||
path.move_to(device_point(0, 4));
|
||||
path.line_to(device_point(5, 4));
|
||||
path.line_to(device_point(11, 0));
|
||||
path.line_to(device_point(11, 15));
|
||||
path.line_to(device_point(5, 11));
|
||||
path.line_to(device_point(0, 11));
|
||||
path.line_to(device_point(0, 4));
|
||||
path.close();
|
||||
painter.fill_path(path, speaker_button_color, Gfx::Painter::WindingRule::EvenOdd);
|
||||
|
||||
path.clear();
|
||||
path.move_to(device_point(13, 3));
|
||||
path.quadratic_bezier_curve_to(device_point(16, 7.5), device_point(13, 12));
|
||||
path.move_to(device_point(14, 0));
|
||||
path.quadratic_bezier_curve_to(device_point(20, 7.5), device_point(14, 15));
|
||||
painter.stroke_path(path, speaker_button_color, 1);
|
||||
|
||||
if (media_element.muted()) {
|
||||
painter.draw_line(device_point(0, 0), device_point(20, 15), Color::Red, 2);
|
||||
painter.draw_line(device_point(0, 15), device_point(20, 0), Color::Red, 2);
|
||||
}
|
||||
}
|
||||
|
||||
MediaPaintable::DispatchEventOfSameName MediaPaintable::handle_mouseup(Badge<EventHandler>, CSSPixelPoint position, unsigned button, unsigned)
|
||||
{
|
||||
if (button != GUI::MouseButton::Primary)
|
||||
@ -221,6 +276,11 @@ MediaPaintable::DispatchEventOfSameName MediaPaintable::handle_mouseup(Badge<Eve
|
||||
return DispatchEventOfSameName::Yes;
|
||||
}
|
||||
|
||||
if (cached_layout_boxes.speaker_button_rect.has_value() && cached_layout_boxes.speaker_button_rect->contains(position)) {
|
||||
media_element.set_muted(!media_element.muted());
|
||||
return DispatchEventOfSameName::Yes;
|
||||
}
|
||||
|
||||
return DispatchEventOfSameName::No;
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,9 @@ private:
|
||||
String timestamp;
|
||||
RefPtr<Gfx::Font> timestamp_font;
|
||||
DevicePixelRect timestamp_rect;
|
||||
|
||||
DevicePixelRect speaker_button_rect;
|
||||
DevicePixels speaker_button_size;
|
||||
};
|
||||
|
||||
virtual bool wants_mouse_events() const override { return true; }
|
||||
@ -44,6 +47,7 @@ private:
|
||||
static void paint_control_bar_playback_button(PaintContext&, HTML::HTMLMediaElement const&, Components const&, Optional<DevicePixelPoint> const& mouse_position);
|
||||
static void paint_control_bar_timeline(PaintContext&, HTML::HTMLMediaElement const&, Components const&, Optional<DevicePixelPoint> 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<DevicePixelPoint> const& mouse_position);
|
||||
};
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user