From: Daniel Karbach Date: Wed, 2 Oct 2024 12:04:10 +0000 (+0200) Subject: show multiple messages X-Git-Url: https://git.localhorst.tv/?a=commitdiff_plain;h=70f95d5df3fedec646327e44c7a6d3318812b73e;p=ffmpeg-test.git show multiple messages --- diff --git a/src/app/Message.h b/src/app/Message.h new file mode 100644 index 0000000..30fbc81 --- /dev/null +++ b/src/app/Message.h @@ -0,0 +1,106 @@ +#ifndef TEST_APP_MESSAGE_H_ +#define TEST_APP_MESSAGE_H_ + +#include + +#include "../cairo/Context.h" +#include "../gfx/ColorRGB.h" +#include "../gfx/Position.h" +#include "../gfx/Size.h" +#include "../gfx/Spacing.h" +#include "../pango/Layout.h" + +namespace app { + +class Message { + +public: + Message(cairo::Context &ctx) + : ctx(ctx) + , text_layout(ctx.CreateLayout()) + , channel_layout(ctx.CreateLayout()) + , bg_color{0.1, 0.1, 0.1} + , text_color{1, 1, 1} + , channel_color{0.392, 0.255, 0.647} + , padding(10) { + } + ~Message() { + } + + Message(const Message &) = delete; + Message &operator =(const Message &) = delete; + +public: + void SetTextFont(pango::Font &font) { + text_layout.SetFont(font); + } + + void SetChannelFont(pango::Font &font) { + channel_layout.SetFont(font); + } + + void SetWidth(double width) { + size.w = width; + int inner_width = width - padding.left - padding.right; + text_layout.SetWidth(inner_width); + channel_layout.SetWidth(inner_width); + } + + void SetText(const std::string &t) { + text_layout.SetText(t); + } + + void SetChannel(const std::string &c) { + channel_layout.SetText(c); + } + + void SetPosition(const gfx::Position &p) { + pos = p; + } + + double GetHeight() const { + return size.h; + } + + void Update() { + text_layout.Update(); + channel_layout.Update(); + text_offset = padding.Offset(); + channel_offset = text_offset; + channel_offset.y += text_layout.GetLogicalRect().height + 10.0; + size.h = channel_offset.y + channel_layout.GetLogicalRect().height + padding.bottom; + } + + void Render() { + ctx.SetSourceColor(bg_color); + ctx.Rectangle(pos, size); + ctx.Fill(); + + ctx.MoveTo(pos + text_offset); + ctx.SetSourceColor(text_color); + text_layout.Render(); + + ctx.MoveTo(pos + channel_offset); + ctx.SetSourceColor(channel_color); + channel_layout.Render(); + } + +private: + cairo::Context ctx; + pango::Layout text_layout; + pango::Layout channel_layout; + gfx::ColorRGB bg_color; + gfx::ColorRGB text_color; + gfx::ColorRGB channel_color; + + gfx::Position pos; + gfx::Size size; + gfx::Spacing padding; + gfx::Position text_offset; + gfx::Position channel_offset; + +}; + +} + +#endif diff --git a/src/app/Renderer.h b/src/app/Renderer.h index b31c73c..a74c7c8 100644 --- a/src/app/Renderer.h +++ b/src/app/Renderer.h @@ -2,14 +2,15 @@ #define TEST_APP_RENDERER_H_ #include -#include +#include + extern "C" { #include "cairo.h" } +#include "Message.h" #include "../cairo/Context.h" #include "../cairo/Surface.h" -#include "../pango/Layout.h" namespace app { @@ -22,17 +23,8 @@ public: , surface(plane, linesize, CAIRO_FORMAT_ARGB32, width, height) , ctx(surface.CreateContext()) , width(width) - , height(height) - , text() - , text_layout(ctx.CreateLayout()) - , channel() - , channel_layout(ctx.CreateLayout()) { - text_layout.SetFont(text_font); - text_layout.SetWidth(width / 2); - channel_layout.SetFont(channel_font); - channel_layout.SetWidth(width / 2); - SetText("Hello, I am a long text that should wrap eventually when it gets long enough to cross the halfway point of the total width available (not including the offset which is added afterwards)."); - SetChannel(""); + , height(height) { + PushMessage("Hello, I am a long text that should wrap eventually when it gets long enough to cross the halfway point of the total width available (not including the offset which is added afterwards).", "The Dummy Channel"); } ~Renderer() { } @@ -45,30 +37,32 @@ public: ctx.SetSourceRGB(0, 0, 0); ctx.Paint(); - ctx.MoveTo(50, 50); - ctx.SetSourceRGB(1, 1, 1); - text_layout.Render(); - - ctx.MoveTo(50, 50 + text_layout.GetLogicalRect().height + 10); - ctx.SetSourceRGB(0.392, 0.255, 0.647); - channel_layout.Render(); + for (Message &msg : msgs) { + msg.Render(); + } surface.Flush(); } - void SetText(const std::string &t) { - text = t; - text_layout.SetText(text); - text_layout.Update(); + void PushMessage(const std::string &text, const std::string &channel) { + msgs.emplace_front(ctx); + Message &msg = msgs.front(); + msg.SetTextFont(text_font); + msg.SetChannelFont(channel_font); + msg.SetWidth(width / 2.0); + msg.SetText(text); + msg.SetChannel(channel); + msg.Update(); + if (msgs.size() > 3) { + msgs.pop_back(); + } + gfx::Position pos({ 50, 50 }); + for (Message &msg : msgs) { + msg.SetPosition(pos); + pos.y += msg.GetHeight() + 10.0; + } } - void SetChannel(const std::string &c) { - channel = c; - channel_layout.SetText(channel); - channel_layout.Update(); - } - - private: pango::Font text_font; pango::Font channel_font; @@ -78,10 +72,7 @@ private: int width; int height; - std::string text; - pango::Layout text_layout; - std::string channel; - pango::Layout channel_layout; + std::list msgs; }; diff --git a/src/cairo/Context.h b/src/cairo/Context.h index 6824820..e34548e 100644 --- a/src/cairo/Context.h +++ b/src/cairo/Context.h @@ -4,9 +4,14 @@ #include #include #include +#include #include "Error.h" #include "Face.h" +#include "../gfx/ColorRGB.h" +#include "../gfx/Position.h" +#include "../gfx/Rectangle.h" +#include "../gfx/Size.h" #include "../pango/Layout.h" namespace cairo { @@ -27,9 +32,16 @@ public: } Context(Context &&other): ctx(cairo_reference(other.ctx)) { } - - Context(const Context &) = delete; - Context &operator =(const Context &) = delete; + Context(const Context &other): ctx(cairo_reference(other.ctx)) { + } + Context &operator =(const Context &other) { + Context temp(other); + Swap(temp); + return *this; + } + void Swap(Context &other) { + std::swap(ctx, other.ctx); + } public: pango::Layout CreateLayout() { @@ -49,10 +61,18 @@ public: cairo_text_extents(ctx, text, &extends); } + void MoveTo(const gfx::Position &pos) { + MoveTo(pos.x, pos.y); + } + void MoveTo(double x, double y) { cairo_move_to(ctx, x, y); } + void LineTo(const gfx::Position &pos) { + LineTo(pos.x, pos.y); + } + void LineTo(double x, double y) { cairo_line_to(ctx, x, y); } @@ -65,6 +85,14 @@ public: cairo_paint_with_alpha(ctx, alpha); } + void Rectangle(const gfx::Rectangle &r) { + Rectangle(r.x, r.y, r.w, r.h); + } + + void Rectangle(const gfx::Position &pos, const gfx::Size &size) { + Rectangle(pos.x, pos.y, size.w, size.h); + } + void Rectangle(double x, double y, double w, double h) { cairo_rectangle(ctx, x, y, w, h); } @@ -85,6 +113,10 @@ public: cairo_set_line_width(ctx, width); } + void SetSourceColor(const gfx::ColorRGB &color) { + SetSourceRGB(color.r, color.g, color.b); + } + void SetSourceRGB(double r, double g, double b) { cairo_set_source_rgb(ctx, r, g, b); } @@ -108,4 +140,13 @@ private: } +namespace std { + +template<> +inline void swap(cairo::Context &a, cairo::Context &b) { + a.Swap(b); +} + +} + #endif diff --git a/src/gfx/ColorRGB.h b/src/gfx/ColorRGB.h new file mode 100644 index 0000000..2d30fbf --- /dev/null +++ b/src/gfx/ColorRGB.h @@ -0,0 +1,16 @@ +#ifndef TEST_GFX_COLORRGB_H_ +#define TEST_GFX_COLORRGB_H_ + +namespace gfx { + +struct ColorRGB { + + double r = 0.0; + double g = 0.0; + double b = 0.0; + +}; + +} + +#endif diff --git a/src/gfx/Position.h b/src/gfx/Position.h new file mode 100644 index 0000000..380e67b --- /dev/null +++ b/src/gfx/Position.h @@ -0,0 +1,25 @@ +#ifndef TEST_GFX_POSITION_H_ +#define TEST_GFX_POSITION_H_ + +#include + +namespace gfx { + +struct Position { + + double x = 0.0; + double y = 0.0; + +}; + +} + +inline gfx::Position operator +(const gfx::Position &a, const gfx::Position &b) { + return gfx::Position{a.x + b.x, a.y + b.y}; +} + +inline std::ostream &operator <<(std::ostream &out, const gfx::Position &pos) { + return out << '(' << pos.x << ", " << pos.y << ')'; +} + +#endif diff --git a/src/gfx/Rectangle.h b/src/gfx/Rectangle.h new file mode 100644 index 0000000..bd14cb5 --- /dev/null +++ b/src/gfx/Rectangle.h @@ -0,0 +1,23 @@ +#ifndef TEST_GFX_RECTANGLE_H_ +#define TEST_GFX_RECTANGLE_H_ + +#include "Position.h" + +namespace gfx { + +struct Rectangle { + + double x = 0.0; + double y = 0.0; + double w = 0.0; + double h = 0.0; + + Position Position() const { + return gfx::Position{x, y}; + } + +}; + +} + +#endif diff --git a/src/gfx/Size.h b/src/gfx/Size.h new file mode 100644 index 0000000..3ab08e2 --- /dev/null +++ b/src/gfx/Size.h @@ -0,0 +1,21 @@ +#ifndef TEST_GFX_SIZE_H_ +#define TEST_GFX_SIZE_H_ + +#include + +namespace gfx { + +struct Size { + + double w = 0.0; + double h = 0.0; + +}; + +} + +inline std::ostream &operator <<(std::ostream &out, const gfx::Size &size) { + return out << size.w << 'x' << size.h; +} + +#endif diff --git a/src/gfx/Spacing.h b/src/gfx/Spacing.h new file mode 100644 index 0000000..d6f0bf8 --- /dev/null +++ b/src/gfx/Spacing.h @@ -0,0 +1,30 @@ +#ifndef TEST_GFX_SPACING_H_ +#define TEST_GFX_SPACING_H_ + +#include "Position.h" + +namespace gfx { + +struct Spacing { + + double left = 0.0; + double top = 0.0; + double bottom = 0.0; + double right = 0.0; + + explicit Spacing(double all) + : left(all), top(all), bottom(all), right(all) { + } + Spacing(double horiz, double vert) + : left(horiz), top(vert), bottom(horiz), right(vert) { + } + + Position Offset() const { + return Position{left, top}; + } + +}; + +} + +#endif diff --git a/src/main.cpp b/src/main.cpp index 31cfa98..8626285 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -41,8 +41,7 @@ void ws_handler(void *user, const Json::Value &json) { const std::string text = data["model"]["text"].asString(); const std::string channel = data["model"]["channel"]["title"].asString(); if (text.length() > 0) { - renderer->SetText(text); - renderer->SetChannel(channel); + renderer->PushMessage(text, channel); } } diff --git a/src/ws/Connection.cpp b/src/ws/Connection.cpp index 6debd28..a111318 100644 --- a/src/ws/Connection.cpp +++ b/src/ws/Connection.cpp @@ -63,6 +63,7 @@ int Connection::ProtoCallback(lws_callback_reasons reason, void *in, size_t len) Ping(); lws_set_timer_usecs(wsi, 30000000); break; + case LWS_CALLBACK_CLIENT_RECEIVE_PONG: case LWS_CALLBACK_CLIENT_HTTP_BIND_PROTOCOL: case LWS_CALLBACK_CLIENT_HTTP_DROP_PROTOCOL: case LWS_CALLBACK_WS_CLIENT_BIND_PROTOCOL: