gBar/src/Widget.h

320 lines
6.4 KiB
C
Raw Normal View History

2023-01-13 15:13:56 +00:00
#pragma once
#include <gtk/gtk.h>
#include <vector>
#include <memory>
#include <string>
#include <functional>
enum class Alignment
{
Fill,
Center,
Left,
Right,
};
struct Transform
{
int size = -1;
bool expand = true;
Alignment alignment = Alignment::Fill;
};
enum class Orientation
{
Vertical,
Horizontal
};
struct Spacing
{
uint32_t free = 0;
bool evenly = false;
};
enum class TransitionType
{
Fade,
SlideLeft,
SlideRight,
SlideUp,
SlideDown
};
struct Transition
2023-01-13 15:13:56 +00:00
{
TransitionType type;
uint32_t durationMS;
};
struct Quad
{
double x, y, size;
};
2023-01-13 15:13:56 +00:00
struct SensorStyle
{
double start = -90; // 0 = leftmost; -90 = topmost
double strokeWidth = 4;
};
struct Range
2023-01-13 15:13:56 +00:00
{
double min, max;
};
struct SliderRange : Range
{
double step;
2023-01-13 15:13:56 +00:00
};
enum class TimerDispatchBehaviour
{
ImmediateDispatch, // Call immediately after adding the timeout, then every x ms
LateDispatch // Call for the first time after x ms.
};
2023-01-13 15:13:56 +00:00
enum class TimerResult
{
Ok,
Delete
};
template<typename TWidget>
using Callback = std::function<void(TWidget&)>;
template<typename TWidget>
using TimerCallback = std::function<TimerResult(TWidget&)>;
class Widget
{
public:
Widget() = default;
virtual ~Widget();
template<typename TWidget>
static std::unique_ptr<TWidget> Create()
{
return std::make_unique<TWidget>();
}
static void CreateAndAddWidget(Widget* widget, GtkWidget* parentWidget);
2023-01-13 15:13:56 +00:00
void SetClass(const std::string& cssClass);
void AddClass(const std::string& cssClass);
void RemoveClass(const std::string& cssClass);
2023-01-13 15:13:56 +00:00
void SetVerticalTransform(const Transform& transform);
void SetHorizontalTransform(const Transform& transform);
2023-01-14 13:47:30 +00:00
void SetTooltip(const std::string& tooltip);
2023-01-13 15:13:56 +00:00
virtual void Create() = 0;
void AddChild(std::unique_ptr<Widget>&& widget);
void RemoveChild(size_t idx);
std::vector<std::unique_ptr<Widget>>& GetWidgets() { return m_Childs; }
2023-01-13 15:13:56 +00:00
template<typename TWidget>
void AddTimer(TimerCallback<TWidget>&& callback, uint32_t timeoutMS, TimerDispatchBehaviour dispatch = TimerDispatchBehaviour::ImmediateDispatch)
2023-01-13 15:13:56 +00:00
{
struct TimerPayload
{
TimerCallback<TWidget> timeoutFn;
Widget* thisWidget;
};
TimerPayload* payload = new TimerPayload();
payload->thisWidget = this;
payload->timeoutFn = std::move(callback);
auto fn = [](void* data) -> int
{
TimerPayload* payload = (TimerPayload*)data;
TimerResult result = payload->timeoutFn(*(TWidget*)payload->thisWidget);
if (result == TimerResult::Delete)
{
delete payload;
return false;
}
return true;
};
if (dispatch == TimerDispatchBehaviour::ImmediateDispatch)
{
if (fn(payload) == false)
{
return;
}
}
2023-01-13 15:13:56 +00:00
g_timeout_add(timeoutMS, +fn, payload);
}
GtkWidget* Get() { return m_Widget; };
const std::vector<std::unique_ptr<Widget>>& GetChilds() const { return m_Childs; };
void SetVisible(bool visible);
protected:
void PropagateToParent(GdkEvent* event);
2023-01-13 15:13:56 +00:00
void ApplyPropertiesToWidget();
GtkWidget* m_Widget = nullptr;
std::vector<std::unique_ptr<Widget>> m_Childs;
std::string m_CssClass;
2023-01-14 13:47:30 +00:00
std::string m_Tooltip;
2023-01-13 15:13:56 +00:00
Transform m_HorizontalTransform; // X
Transform m_VerticalTransform; // Y
};
class Box : public Widget
{
public:
Box() = default;
virtual ~Box() = default;
void SetOrientation(Orientation orientation);
void SetSpacing(Spacing spacing);
virtual void Create() override;
private:
Orientation m_Orientation = Orientation::Horizontal;
Spacing m_Spacing;
};
class CenterBox : public Widget
{
public:
void SetOrientation(Orientation orientation);
virtual void Create() override;
private:
Orientation m_Orientation = Orientation::Horizontal;
};
class EventBox : public Widget
{
public:
void SetEventFn(std::function<void(EventBox&, bool)>&& fn);
virtual void Create() override;
private:
std::function<void(EventBox&, bool)> m_EventFn;
};
class CairoArea : public Widget
2023-01-13 15:13:56 +00:00
{
public:
virtual void Create() override;
protected:
virtual void Draw(cairo_t* cr) = 0;
Quad GetQuad();
};
class Sensor : public CairoArea
{
public:
2023-01-13 15:13:56 +00:00
// Goes from 0-1
void SetValue(double val);
void SetStyle(SensorStyle style);
private:
void Draw(cairo_t* cr) override;
2023-01-13 15:13:56 +00:00
double m_Val;
SensorStyle m_Style{};
};
class NetworkSensor : public CairoArea
{
public:
virtual void Create() override;
void SetLimitUp(Range limit) { limitUp = limit; };
void SetLimitDown(Range limit) { limitDown = limit; };
void SetUp(double val);
void SetDown(double val);
private:
void Draw(cairo_t* cr) override;
// These are in percent
double up, down;
Range limitUp;
Range limitDown;
// What I do here is a little bit gross, but I need a working style context
// Just manually creating a style context doesn't work for me.
std::unique_ptr<Box> contextUp;
std::unique_ptr<Box> contextDown;
};
2023-01-13 15:13:56 +00:00
class Revealer : public Widget
{
public:
void SetTransition(Transition transition);
2023-01-13 15:13:56 +00:00
void SetRevealed(bool revealed);
virtual void Create() override;
private:
Transition m_Transition;
};
class Text : public Widget
{
public:
Text() = default;
virtual ~Text() = default;
void SetText(const std::string& text);
virtual void Create() override;
private:
std::string m_Text;
};
class Button : public Widget
{
public:
Button() = default;
virtual ~Button() = default;
void SetText(const std::string& text);
virtual void Create() override;
void OnClick(Callback<Button>&& callback);
private:
std::string m_Text;
Callback<Button> m_OnClick;
};
class Slider : public Widget
{
public:
Slider() = default;
virtual ~Slider() = default;
void SetValue(double value);
void SetOrientation(Orientation orientation);
void SetInverted(bool flipped);
void SetRange(SliderRange range);
void OnValueChange(std::function<void(Slider&, double)>&& callback);
virtual void Create() override;
private:
Orientation m_Orientation = Orientation::Horizontal;
SliderRange m_Range;
bool m_Inverted = false;
std::function<void(Slider&, double)> m_OnValueChange;
};