summaryrefslogtreecommitdiff
path: root/Userland/Applications
diff options
context:
space:
mode:
authorKyle Lanmon <kyle.lanmon@gmail.com>2023-03-20 22:56:55 -0500
committerAndreas Kling <kling@serenityos.org>2023-03-22 10:32:02 +0100
commitfcda397136eaf31ccf60a9c5fba85f62a359ffdd (patch)
tree99f83b697e06cf6ae4e45beec027ae4d61dee55b /Userland/Applications
parent7c312980b08e436e4183e297a33dd515fe818a03 (diff)
downloadserenity-fcda397136eaf31ccf60a9c5fba85f62a359ffdd.zip
Presenter: Support multiple frames per slide
Diffstat (limited to 'Userland/Applications')
-rw-r--r--Userland/Applications/Presenter/Presentation.cpp48
-rw-r--r--Userland/Applications/Presenter/Presentation.h4
-rw-r--r--Userland/Applications/Presenter/PresenterWidget.cpp4
-rw-r--r--Userland/Applications/Presenter/Slide.cpp13
-rw-r--r--Userland/Applications/Presenter/Slide.h8
-rw-r--r--Userland/Applications/Presenter/SlideObject.cpp9
-rw-r--r--Userland/Applications/Presenter/SlideObject.h29
7 files changed, 78 insertions, 37 deletions
diff --git a/Userland/Applications/Presenter/Presentation.cpp b/Userland/Applications/Presenter/Presentation.cpp
index f8873a7515..7b53b02571 100644
--- a/Userland/Applications/Presenter/Presentation.cpp
+++ b/Userland/Applications/Presenter/Presentation.cpp
@@ -41,14 +41,20 @@ StringView Presentation::author() const
return "Unknown Author"sv;
}
-bool Presentation::has_a_next_frame() const
+bool Presentation::has_next_frame() const
{
- return m_current_slide < u32(m_slides.size() > 1 ? m_slides.size() - 1 : 0);
+ if (m_slides.is_empty())
+ return false;
+ if (m_current_slide.value() < m_slides.size() - 1)
+ return true;
+ return m_current_frame_in_slide < m_slides[m_current_slide.value()].frame_count() - 1;
}
-bool Presentation::has_a_previous_frame() const
+bool Presentation::has_previous_frame() const
{
- return m_current_slide > 0u;
+ if (m_current_slide > 0u)
+ return true;
+ return m_current_frame_in_slide > 0u;
}
void Presentation::next_frame()
@@ -65,7 +71,7 @@ void Presentation::previous_frame()
m_current_frame_in_slide.sub(1);
if (m_current_frame_in_slide.has_overflow()) {
m_current_slide.saturating_sub(1);
- m_current_frame_in_slide = m_current_slide == 0u ? 0 : current_slide().frame_count() - 1;
+ m_current_frame_in_slide = current_slide().frame_count() - 1;
}
}
@@ -108,13 +114,15 @@ ErrorOr<NonnullOwnPtr<Presentation>> Presentation::load_from_file(StringView fil
auto presentation = Presentation::construct(size, metadata);
auto const& slides = maybe_slides.value();
+ unsigned i = 0;
for (auto const& maybe_slide : slides.values()) {
if (!maybe_slide.is_object())
return Error::from_string_view("Slides must be objects"sv);
auto const& slide_object = maybe_slide.as_object();
- auto slide = TRY(Slide::parse_slide(slide_object));
+ auto slide = TRY(Slide::parse_slide(slide_object, i));
presentation->append_slide(move(slide));
+ i++;
}
return presentation;
@@ -163,9 +171,8 @@ ErrorOr<DeprecatedString> Presentation::render()
for (size_t i = 0; i < m_slides.size(); ++i) {
HTMLElement slide_div;
slide_div.tag_name = "div"sv;
- TRY(slide_div.style.try_set("display"sv, "none"sv));
TRY(slide_div.attributes.try_set("id"sv, DeprecatedString::formatted("slide{}", i)));
- TRY(slide_div.attributes.try_set("class"sv, "slide"));
+ TRY(slide_div.attributes.try_set("class"sv, "slide hidden"sv));
auto& slide = m_slides[i];
TRY(slide_div.children.try_append(TRY(slide.render(*this))));
main_element.children.append(move(slide_div));
@@ -181,18 +188,29 @@ ErrorOr<DeprecatedString> Presentation::render()
width: 100%;
height: 100%;
}
+ .hidden {
+ display: none;
+ }
</style><script>
function goto(slideIndex, frameIndex) {
- // FIXME: Honor the frameIndex.
- let slide;
- for (slide of document.getElementsByClassName("slide")) {
- slide.style.display = "none";
+ for (const slide of document.getElementsByClassName("slide")) {
+ slide.classList.add("hidden");
+ }
+ for (const frame of document.getElementsByClassName("frame")) {
+ frame.classList.add("hidden");
+ }
+
+ const slide = document.getElementById(`slide${slideIndex}`);
+ if (slide) slide.classList.remove("hidden");
+
+ for (let i = 0; i <= frameIndex; i++) {
+ for (const frame of document.getElementsByClassName(`slide${slideIndex}-frame${i}`)) {
+ if (frame) frame.classList.remove("hidden");
+ }
}
- if (slide = document.getElementById(`slide${slideIndex}`))
- slide.style.display = "block";
}
window.onload = function() { goto(0, 0) }
-</script><body>
+</script></head><body>
)"sv));
TRY(main_element.serialize(builder));
TRY(builder.try_append("</body></html>"sv));
diff --git a/Userland/Applications/Presenter/Presentation.h b/Userland/Applications/Presenter/Presentation.h
index 210c9fefd1..47cb07441b 100644
--- a/Userland/Applications/Presenter/Presentation.h
+++ b/Userland/Applications/Presenter/Presentation.h
@@ -32,8 +32,8 @@ public:
unsigned current_slide_number() const { return m_current_slide.value(); }
unsigned current_frame_in_slide_number() const { return m_current_frame_in_slide.value(); }
- bool has_a_next_frame() const;
- bool has_a_previous_frame() const;
+ bool has_next_frame() const;
+ bool has_previous_frame() const;
void next_frame();
void previous_frame();
void go_to_first_slide();
diff --git a/Userland/Applications/Presenter/PresenterWidget.cpp b/Userland/Applications/Presenter/PresenterWidget.cpp
index 52d3bf7719..2620c7d835 100644
--- a/Userland/Applications/Presenter/PresenterWidget.cpp
+++ b/Userland/Applications/Presenter/PresenterWidget.cpp
@@ -128,8 +128,8 @@ void PresenterWidget::update_web_view()
void PresenterWidget::update_slides_actions()
{
if (m_current_presentation) {
- m_next_slide_action->set_enabled(m_current_presentation->has_a_next_frame());
- m_previous_slide_action->set_enabled(m_current_presentation->has_a_previous_frame());
+ m_next_slide_action->set_enabled(m_current_presentation->has_next_frame());
+ m_previous_slide_action->set_enabled(m_current_presentation->has_previous_frame());
m_full_screen_action->set_enabled(true);
m_present_from_first_slide_action->set_enabled(true);
} else {
diff --git a/Userland/Applications/Presenter/Slide.cpp b/Userland/Applications/Presenter/Slide.cpp
index 8e07961a19..b9b8e09213 100644
--- a/Userland/Applications/Presenter/Slide.cpp
+++ b/Userland/Applications/Presenter/Slide.cpp
@@ -9,17 +9,18 @@
#include "Presentation.h"
#include <AK/JsonObject.h>
-Slide::Slide(Vector<NonnullRefPtr<SlideObject>> slide_objects, DeprecatedString title)
- : m_slide_objects(move(slide_objects))
+Slide::Slide(unsigned frame_count, Vector<NonnullRefPtr<SlideObject>> slide_objects, DeprecatedString title)
+ : m_frame_count(move(frame_count))
+ , m_slide_objects(move(slide_objects))
, m_title(move(title))
{
}
-ErrorOr<Slide> Slide::parse_slide(JsonObject const& slide_json)
+ErrorOr<Slide> Slide::parse_slide(JsonObject const& slide_json, unsigned slide_index)
{
// FIXME: Use the text with the "title" role for a title, if there is no title given.
auto title = slide_json.get_deprecated_string("title"sv).value_or("Untitled slide");
-
+ auto frame_count = slide_json.get_u32("frame_count"sv).value_or(1);
auto maybe_slide_objects = slide_json.get_array("objects"sv);
if (!maybe_slide_objects.has_value())
return Error::from_string_view("Slide objects must be an array"sv);
@@ -31,11 +32,11 @@ ErrorOr<Slide> Slide::parse_slide(JsonObject const& slide_json)
return Error::from_string_view("Slides must be objects"sv);
auto const& slide_object_json = maybe_slide_object_json.as_object();
- auto slide_object = TRY(SlideObject::parse_slide_object(slide_object_json));
+ auto slide_object = TRY(SlideObject::parse_slide_object(slide_object_json, slide_index));
slide_objects.append(move(slide_object));
}
- return Slide { move(slide_objects), title };
+ return Slide { frame_count, move(slide_objects), title };
}
ErrorOr<HTMLElement> Slide::render(Presentation const& presentation) const
diff --git a/Userland/Applications/Presenter/Slide.h b/Userland/Applications/Presenter/Slide.h
index f33026c7ef..864cd4e4ec 100644
--- a/Userland/Applications/Presenter/Slide.h
+++ b/Userland/Applications/Presenter/Slide.h
@@ -14,17 +14,17 @@
// A single slide of a presentation.
class Slide final {
public:
- static ErrorOr<Slide> parse_slide(JsonObject const& slide_json);
+ static ErrorOr<Slide> parse_slide(JsonObject const& slide_json, unsigned slide_index);
- // FIXME: shouldn't be hard-coded to 1.
- unsigned frame_count() const { return 1; }
+ unsigned frame_count() const { return m_frame_count; }
StringView title() const { return m_title; }
ErrorOr<HTMLElement> render(Presentation const&) const;
private:
- Slide(Vector<NonnullRefPtr<SlideObject>> slide_objects, DeprecatedString title);
+ Slide(unsigned frame_count, Vector<NonnullRefPtr<SlideObject>> slide_objects, DeprecatedString title);
+ unsigned m_frame_count;
Vector<NonnullRefPtr<SlideObject>> m_slide_objects;
DeprecatedString m_title;
};
diff --git a/Userland/Applications/Presenter/SlideObject.cpp b/Userland/Applications/Presenter/SlideObject.cpp
index eee1ef8ee8..25d12bf1b6 100644
--- a/Userland/Applications/Presenter/SlideObject.cpp
+++ b/Userland/Applications/Presenter/SlideObject.cpp
@@ -17,8 +17,9 @@ static DeprecatedString to_css_length(float design_value, Presentation const& pr
return DeprecatedString::formatted("{}vw", length_in_vw);
}
-ErrorOr<NonnullRefPtr<SlideObject>> SlideObject::parse_slide_object(JsonObject const& slide_object_json)
+ErrorOr<NonnullRefPtr<SlideObject>> SlideObject::parse_slide_object(JsonObject const& slide_object_json, unsigned slide_index)
{
+ auto frame = slide_object_json.get_u32("frame"sv).value_or(0);
auto maybe_type = slide_object_json.get_deprecated_string("type"sv);
if (!maybe_type.has_value())
return Error::from_string_view("Slide object must have a type"sv);
@@ -26,9 +27,9 @@ ErrorOr<NonnullRefPtr<SlideObject>> SlideObject::parse_slide_object(JsonObject c
auto type = maybe_type.value();
RefPtr<SlideObject> object;
if (type == "text"sv)
- object = TRY(try_make_ref_counted<Text>());
+ object = TRY(try_make_ref_counted<Text>(Index { slide_index, frame }));
else if (type == "image"sv)
- object = TRY(try_make_ref_counted<Image>());
+ object = TRY(try_make_ref_counted<Image>(Index { slide_index, frame }));
else
return Error::from_string_view("Unsupported slide object type"sv);
@@ -97,6 +98,7 @@ ErrorOr<HTMLElement> Text::render(Presentation const& presentation) const
{
HTMLElement div;
div.tag_name = "div"sv;
+ TRY(div.attributes.try_set("class"sv, DeprecatedString::formatted("frame slide{}-frame{}", m_slide_index, m_frame_index)));
div.style.set("color"sv, m_color.to_deprecated_string());
div.style.set("font-family"sv, DeprecatedString::formatted("'{}'", m_font_family));
div.style.set("font-size"sv, to_css_length(m_font_size_in_pt * 1.33333333f, presentation));
@@ -125,6 +127,7 @@ ErrorOr<HTMLElement> Image::render(Presentation const& presentation) const
HTMLElement image_wrapper;
image_wrapper.tag_name = "div"sv;
+ TRY(image_wrapper.attributes.try_set("class"sv, DeprecatedString::formatted("frame slide{}-frame{}", m_slide_index, m_frame_index)));
image_wrapper.children.append(move(img));
image_wrapper.style.set("position"sv, "absolute"sv);
image_wrapper.style.set("left"sv, to_css_length(m_rect.left(), presentation));
diff --git a/Userland/Applications/Presenter/SlideObject.h b/Userland/Applications/Presenter/SlideObject.h
index 0ace94b7d3..1936f84d46 100644
--- a/Userland/Applications/Presenter/SlideObject.h
+++ b/Userland/Applications/Presenter/SlideObject.h
@@ -21,19 +21,29 @@ struct HTMLElement {
ErrorOr<void> serialize(StringBuilder&) const;
};
+struct Index {
+ unsigned slide;
+ unsigned frame;
+};
// Anything that can be on a slide.
class SlideObject : public RefCounted<SlideObject> {
public:
virtual ~SlideObject() = default;
- static ErrorOr<NonnullRefPtr<SlideObject>> parse_slide_object(JsonObject const& slide_object_json);
+ static ErrorOr<NonnullRefPtr<SlideObject>> parse_slide_object(JsonObject const& slide_object_json, unsigned slide_index);
virtual ErrorOr<HTMLElement> render(Presentation const&) const = 0;
protected:
- SlideObject() = default;
+ SlideObject(Index index)
+ : m_frame_index(index.frame)
+ , m_slide_index(index.slide)
+ {
+ }
virtual void set_property(StringView name, JsonValue);
+ unsigned m_frame_index;
+ unsigned m_slide_index;
HashMap<DeprecatedString, JsonValue> m_properties;
Gfx::IntRect m_rect;
};
@@ -44,7 +54,10 @@ public:
virtual ~GraphicsObject() = default;
protected:
- GraphicsObject() = default;
+ GraphicsObject(Index index)
+ : SlideObject(index)
+ {
+ }
virtual void set_property(StringView name, JsonValue) override;
// FIXME: Change the default color based on the color scheme
@@ -53,7 +66,10 @@ protected:
class Text final : public GraphicsObject {
public:
- Text() = default;
+ Text(Index index)
+ : GraphicsObject(index)
+ {
+ }
virtual ~Text() = default;
private:
@@ -69,7 +85,10 @@ private:
class Image final : public SlideObject {
public:
- Image() = default;
+ Image(Index index)
+ : SlideObject(index)
+ {
+ }
virtual ~Image() = default;
private: