text, hover, styles and buttons!
This commit is contained in:
parent
9fe7659a0f
commit
ef85745f58
18 changed files with 404 additions and 64 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1 +1,3 @@
|
||||||
builddir/
|
builddir/
|
||||||
|
.cache/
|
||||||
|
compile_commands.json
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "Box.hpp"
|
#include "Box.hpp"
|
||||||
|
#include "Point.hpp"
|
||||||
|
|
||||||
namespace Raven {
|
namespace Raven {
|
||||||
|
|
||||||
|
@ -6,6 +7,10 @@ bool Box::contains_point(double x, double y) {
|
||||||
return x >= m_x && m_x + m_width >= x && y >= m_y && m_y + m_height >= y;
|
return x >= m_x && m_x + m_width >= x && y >= m_y && m_y + m_height >= y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Box::contains_point(Point &point) {
|
||||||
|
return point.get_x() >= m_x && m_x + m_width >= point.get_x() && point.get_y() >= m_y && m_y + m_height >= point.get_y();
|
||||||
|
}
|
||||||
|
|
||||||
bool Box::contains_box(Box &other) const {
|
bool Box::contains_box(Box &other) const {
|
||||||
double ax1 = m_x;
|
double ax1 = m_x;
|
||||||
double ax2 = m_x + m_width;
|
double ax2 = m_x + m_width;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "Point.hpp"
|
||||||
|
|
||||||
namespace Raven {
|
namespace Raven {
|
||||||
|
|
||||||
class Box {
|
class Box {
|
||||||
|
@ -30,6 +32,7 @@ public:
|
||||||
void set_height(double height) { m_height = height; }
|
void set_height(double height) { m_height = height; }
|
||||||
|
|
||||||
bool contains_point(double x, double y);
|
bool contains_point(double x, double y);
|
||||||
|
bool contains_point(Point &point);
|
||||||
bool contains_box(Box &other) const;
|
bool contains_box(Box &other) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,35 @@
|
||||||
|
#include <iostream>
|
||||||
#include "Button.hpp"
|
#include "Button.hpp"
|
||||||
#include "Box.hpp"
|
#include "Box.hpp"
|
||||||
#include "Window.hpp"
|
#include "Window.hpp"
|
||||||
|
#include "src/Painter.hpp"
|
||||||
|
#include <pango/pangocairo.h>
|
||||||
|
|
||||||
namespace Raven {
|
namespace Raven {
|
||||||
|
|
||||||
|
void Button::on_init() {
|
||||||
|
set_style_do_background_fill(true);
|
||||||
|
set_style_background_fill_color(m_style_normal_background_fill_color);
|
||||||
|
set_style_font_description(get_top_level_styles()->get_style_controls_font_description());
|
||||||
|
|
||||||
|
set_did_init(true);
|
||||||
|
}
|
||||||
|
|
||||||
void Button::on_paint() {
|
void Button::on_paint() {
|
||||||
auto painter = get_window()->get_painter();
|
auto painter = get_window()->get_painter();
|
||||||
auto cr = painter.get_cairo();
|
|
||||||
|
|
||||||
cr->set_source_rgb(0.866, 0.713, 0.949);
|
painter.source_rgb(m_style_text_fill_color);
|
||||||
painter.rounded_rectangle(get_current_geometry(), 8);
|
painter.set_pango_font_description(m_style_font_description);
|
||||||
cr->fill();
|
painter.text(get_current_geometry(), m_text, PaintTextAlign::Center);
|
||||||
|
painter.fill();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Button::on_focus_update(FocusUpdateEvent &event) {
|
||||||
|
if (is_focused()) {
|
||||||
|
set_style_background_fill_color(m_style_focused_background_fill_color);
|
||||||
|
} else {
|
||||||
|
set_style_background_fill_color(m_style_normal_background_fill_color);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +1,35 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "Widget.hpp"
|
#include "Widget.hpp"
|
||||||
|
#include "RGB.hpp"
|
||||||
|
#include "pango/pango-font.h"
|
||||||
|
#include "Window.hpp"
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
namespace Raven {
|
namespace Raven {
|
||||||
|
|
||||||
class Button : public Widget {
|
class Button : public Widget {
|
||||||
|
DEF_STYLE(text_fill_color, RGB, 0.0, 0.0, 0.0)
|
||||||
|
|
||||||
|
DEF_STYLE(normal_background_fill_color, RGB, 0.6941, 0.3843, 0.5254)
|
||||||
|
DEF_STYLE(focused_background_fill_color, RGB, 0.5607, 0.2470, 0.4431)
|
||||||
|
DEF_STYLE(active_background_fill_color, RGB, 0.896, 0.743, 0.979)
|
||||||
|
|
||||||
|
DEF_STYLE(font_description, PangoFontDescription*, nullptr)
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string m_text;
|
std::string m_text;
|
||||||
public:
|
public:
|
||||||
Button(std::string text)
|
Button(std::string text)
|
||||||
: m_text(text)
|
: Widget()
|
||||||
, Widget() {}
|
, m_text(text) {}
|
||||||
|
|
||||||
void set_text(std::string text) { m_text = text; wants_repaint(); }
|
void set_text(std::string text) { m_text = text; wants_repaint(); }
|
||||||
std::string &get_text() { return m_text; }
|
std::string &get_text() { return m_text; }
|
||||||
|
|
||||||
void on_paint();
|
void on_paint();
|
||||||
|
void on_init();
|
||||||
|
void on_focus_update(FocusUpdateEvent &event);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,9 @@ enum class EventType {
|
||||||
|
|
||||||
MouseButton,
|
MouseButton,
|
||||||
MouseMove,
|
MouseMove,
|
||||||
WidgetRepaintRequested
|
WidgetRepaintRequested,
|
||||||
|
FocusUpdate,
|
||||||
|
ActivationUpdate
|
||||||
};
|
};
|
||||||
|
|
||||||
class Event {
|
class Event {
|
||||||
|
@ -20,11 +22,12 @@ private:
|
||||||
public:
|
public:
|
||||||
Event() {}
|
Event() {}
|
||||||
|
|
||||||
void accept() { m_accepted = true; }
|
|
||||||
bool is_accepted() { return m_accepted; }
|
|
||||||
virtual EventType get_type() { return EventType::NoneEvent; }
|
virtual EventType get_type() { return EventType::NoneEvent; }
|
||||||
virtual const char *get_name() { return "NoneEvent"; }
|
virtual const char *get_name() { return "NoneEvent"; }
|
||||||
|
|
||||||
|
void accept() { m_accepted = true; }
|
||||||
|
bool get_accepted() { return m_accepted; }
|
||||||
|
|
||||||
virtual ~Event() = default;
|
virtual ~Event() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -70,4 +73,30 @@ public:
|
||||||
Box &get_repaint_area() { return m_repaint_area; }
|
Box &get_repaint_area() { return m_repaint_area; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class FocusUpdateEvent : public Event {
|
||||||
|
private:
|
||||||
|
bool m_focus_status;
|
||||||
|
public:
|
||||||
|
FocusUpdateEvent(bool focus_status)
|
||||||
|
: m_focus_status(focus_status) {}
|
||||||
|
|
||||||
|
EventType get_type() { return EventType::FocusUpdate; }
|
||||||
|
const char *get_name() { return "FocusUpdate"; }
|
||||||
|
|
||||||
|
bool get_focus_status() { return m_focus_status; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class ActivationUpdateEvent : public Event {
|
||||||
|
private:
|
||||||
|
bool m_activation_status;
|
||||||
|
public:
|
||||||
|
ActivationUpdateEvent(bool activation_status)
|
||||||
|
: m_activation_status(activation_status) {}
|
||||||
|
|
||||||
|
EventType get_type() { return EventType::ActivationUpdate; }
|
||||||
|
const char *get_name() { return "ActivationUpdate"; }
|
||||||
|
|
||||||
|
bool get_activation_status() { return m_activation_status; }
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ namespace Raven {
|
||||||
class Events;
|
class Events;
|
||||||
class Painter;
|
class Painter;
|
||||||
class Point;
|
class Point;
|
||||||
|
class TopLevelStyles;
|
||||||
class Widget;
|
class Widget;
|
||||||
class Window;
|
class Window;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "Painter.hpp"
|
#include "Painter.hpp"
|
||||||
|
#include "src/RGB.hpp"
|
||||||
|
|
||||||
namespace Raven {
|
namespace Raven {
|
||||||
|
|
||||||
|
@ -19,4 +20,60 @@ void Painter::rounded_rectangle(Box &geometry, double border_radius) {
|
||||||
m_cairo->close_path();
|
m_cairo->close_path();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Painter::text(Point &where, std::string &text) {
|
||||||
|
if (m_pango_font_description == nullptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
PangoLayout *layout = pango_cairo_create_layout(m_cairo->cobj());
|
||||||
|
|
||||||
|
pango_layout_set_font_description(layout, m_pango_font_description);
|
||||||
|
pango_layout_set_text(layout, text.c_str(), -1);
|
||||||
|
|
||||||
|
m_cairo->move_to(where.get_x(), where.get_y());
|
||||||
|
pango_cairo_show_layout(m_cairo->cobj(), layout);
|
||||||
|
|
||||||
|
g_object_unref(layout);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Painter::text(Box &geometry, std::string &text, PaintTextAlign align) {
|
||||||
|
if (m_pango_font_description == nullptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
PangoLayout *layout = pango_cairo_create_layout(m_cairo->cobj());
|
||||||
|
|
||||||
|
int font_width;
|
||||||
|
int font_height;
|
||||||
|
|
||||||
|
pango_layout_set_font_description(layout, m_pango_font_description);
|
||||||
|
pango_layout_set_text(layout, text.c_str(), -1);
|
||||||
|
|
||||||
|
pango_layout_get_pixel_size(layout, &font_width, &font_height);
|
||||||
|
|
||||||
|
double x = -1;
|
||||||
|
double y = geometry.get_y() + ((geometry.get_height() - font_height) / 2);
|
||||||
|
|
||||||
|
if (align == PaintTextAlign::Center) {
|
||||||
|
x = geometry.get_x() + ((geometry.get_width() - font_width) / 2);
|
||||||
|
} else {
|
||||||
|
x = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_cairo->move_to(x, y);
|
||||||
|
pango_cairo_show_layout(m_cairo->cobj(), layout);
|
||||||
|
|
||||||
|
g_object_unref(layout);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Painter::source_rgb(RGB &source_rgb) {
|
||||||
|
m_cairo->set_source_rgb(source_rgb.get_r(), source_rgb.get_g(), source_rgb.get_b());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Painter::fill() {
|
||||||
|
m_cairo->fill();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,37 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Box.hpp"
|
#include "Box.hpp"
|
||||||
|
#include "Point.hpp"
|
||||||
|
#include "src/RGB.hpp"
|
||||||
#include <cairomm/cairomm.h>
|
#include <cairomm/cairomm.h>
|
||||||
|
#include <pango/pangocairo.h>
|
||||||
|
|
||||||
namespace Raven {
|
namespace Raven {
|
||||||
|
|
||||||
|
enum class PaintTextAlign {
|
||||||
|
Center = 0,
|
||||||
|
Left
|
||||||
|
};
|
||||||
|
|
||||||
class Painter {
|
class Painter {
|
||||||
private:
|
private:
|
||||||
Cairo::RefPtr<Cairo::Context> m_cairo;
|
Cairo::RefPtr<Cairo::Context> m_cairo;
|
||||||
|
PangoFontDescription *m_pango_font_description;
|
||||||
public:
|
public:
|
||||||
Painter() {}
|
Painter() {}
|
||||||
|
|
||||||
Cairo::RefPtr<Cairo::Context> get_cairo() { return m_cairo; }
|
Cairo::RefPtr<Cairo::Context> get_cairo() { return m_cairo; }
|
||||||
void set_cairo(Cairo::RefPtr<Cairo::Context> cairo) { m_cairo = cairo; }
|
void set_cairo(Cairo::RefPtr<Cairo::Context> cairo) { m_cairo = cairo; }
|
||||||
|
|
||||||
|
void set_pango_font_description(PangoFontDescription *pango_font_description) { m_pango_font_description = pango_font_description; }
|
||||||
|
PangoFontDescription *get_pango_font_description() { return m_pango_font_description; }
|
||||||
|
|
||||||
void rounded_rectangle(Box &geometry, double border_radius);
|
void rounded_rectangle(Box &geometry, double border_radius);
|
||||||
|
bool text(Point &where, std::string &text);
|
||||||
|
bool text(Box &geometry, std::string &text, PaintTextAlign align);
|
||||||
|
|
||||||
|
void source_rgb(RGB &source_rgb);
|
||||||
|
void fill();
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
26
src/RGB.hpp
Normal file
26
src/RGB.hpp
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Raven {
|
||||||
|
|
||||||
|
class RGB {
|
||||||
|
private:
|
||||||
|
double m_r {0.0};
|
||||||
|
double m_g {0.0};
|
||||||
|
double m_b {0.0};
|
||||||
|
public:
|
||||||
|
RGB() {}
|
||||||
|
RGB(double r, double g, double b)
|
||||||
|
: m_r(r)
|
||||||
|
, m_g(g)
|
||||||
|
, m_b(b) {}
|
||||||
|
|
||||||
|
void set_r(double r) { m_r = r; }
|
||||||
|
void set_g(double g) { m_g = g; }
|
||||||
|
void set_b(double b) { m_b = b; }
|
||||||
|
|
||||||
|
double get_r() { return m_r; }
|
||||||
|
double get_g() { return m_g; }
|
||||||
|
double get_b() { return m_b; }
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
9
src/StyleMacros.hpp
Normal file
9
src/StyleMacros.hpp
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define DEF_STYLE(name, type, ...) \
|
||||||
|
private: \
|
||||||
|
type m_style_##name {__VA_ARGS__}; \
|
||||||
|
public: \
|
||||||
|
void set_style_##name(type new_style_value) { m_style_##name = new_style_value; wants_repaint(); } \
|
||||||
|
type get_style_##name() { return m_style_##name; } \
|
||||||
|
private:
|
12
src/TopLevelStyles.cpp
Normal file
12
src/TopLevelStyles.cpp
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#include "TopLevelStyles.hpp"
|
||||||
|
#include "Window.hpp"
|
||||||
|
|
||||||
|
namespace Raven {
|
||||||
|
|
||||||
|
void TopLevelStyles::wants_repaint() {
|
||||||
|
// when one of the styles here changes, we will dispatch
|
||||||
|
// a full repaint to the entire window :^)
|
||||||
|
m_window->dispatch_full_repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
40
src/TopLevelStyles.hpp
Normal file
40
src/TopLevelStyles.hpp
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include "Forward.hpp"
|
||||||
|
#include "pango/pango-font.h"
|
||||||
|
#include "StyleMacros.hpp"
|
||||||
|
|
||||||
|
namespace Raven {
|
||||||
|
|
||||||
|
class TopLevelStyles {
|
||||||
|
DEF_STYLE(controls_font_description, PangoFontDescription*, nullptr)
|
||||||
|
|
||||||
|
private:
|
||||||
|
Window *m_window;
|
||||||
|
public:
|
||||||
|
TopLevelStyles(Window *window)
|
||||||
|
: m_window(window)
|
||||||
|
{
|
||||||
|
PangoFontDescription *font_description = pango_font_description_new();
|
||||||
|
|
||||||
|
pango_font_description_set_family(font_description, "sans-serif");
|
||||||
|
pango_font_description_set_weight(font_description, PANGO_WEIGHT_NORMAL);
|
||||||
|
pango_font_description_set_absolute_size(font_description, 16 * PANGO_SCALE);
|
||||||
|
|
||||||
|
m_style_controls_font_description = font_description;
|
||||||
|
}
|
||||||
|
|
||||||
|
~TopLevelStyles() {
|
||||||
|
if (m_style_controls_font_description) {
|
||||||
|
pango_font_description_free(m_style_controls_font_description);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Window *get_window() { return m_window; }
|
||||||
|
void set_window(Window *window) { m_window = window; }
|
||||||
|
|
||||||
|
void wants_repaint();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
118
src/Widget.cpp
118
src/Widget.cpp
|
@ -6,6 +6,13 @@
|
||||||
|
|
||||||
namespace Raven {
|
namespace Raven {
|
||||||
|
|
||||||
|
void Widget::set_window(Window *window) {
|
||||||
|
m_window = window;
|
||||||
|
m_top_level_styles = m_window->get_top_level_styles();
|
||||||
|
|
||||||
|
on_init();
|
||||||
|
}
|
||||||
|
|
||||||
void Widget::wants_repaint() {
|
void Widget::wants_repaint() {
|
||||||
if (!m_window)
|
if (!m_window)
|
||||||
return;
|
return;
|
||||||
|
@ -29,72 +36,111 @@ void Widget::remove_child(Widget *child) {
|
||||||
m_children.erase(std::remove(m_children.begin(), m_children.end(), child), m_children.end());
|
m_children.erase(std::remove(m_children.begin(), m_children.end(), child), m_children.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Widget::do_generic_paint() {
|
||||||
|
if (m_style_do_background_fill) {
|
||||||
|
auto painter = m_window->get_painter();
|
||||||
|
auto cr = painter.get_cairo();
|
||||||
|
|
||||||
|
cr->save();
|
||||||
|
|
||||||
|
painter.source_rgb(m_style_background_fill_color);
|
||||||
|
painter.rounded_rectangle(m_current_geometry, m_style_background_border_radius);
|
||||||
|
painter.fill();
|
||||||
|
|
||||||
|
cr->restore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Widget::handle_repaint_requested(WidgetRepaintRequestedEvent &event) {
|
void Widget::handle_repaint_requested(WidgetRepaintRequestedEvent &event) {
|
||||||
std::cout << "-------\n";
|
if (!m_did_init)
|
||||||
|
return;
|
||||||
std::cout << "-- repaint_area: "
|
|
||||||
<< event.get_repaint_area().get_x()
|
|
||||||
<< ", "
|
|
||||||
<< event.get_repaint_area().get_y()
|
|
||||||
<< ", "
|
|
||||||
<< event.get_repaint_area().get_width()
|
|
||||||
<< ", "
|
|
||||||
<< event.get_repaint_area().get_height()
|
|
||||||
<< " --\n";
|
|
||||||
|
|
||||||
std::cout << "-- m_current_geometry: "
|
|
||||||
<< m_current_geometry.get_x()
|
|
||||||
<< ", "
|
|
||||||
<< m_current_geometry.get_y()
|
|
||||||
<< ", "
|
|
||||||
<< m_current_geometry.get_width()
|
|
||||||
<< ", "
|
|
||||||
<< m_current_geometry.get_height()
|
|
||||||
<< " --\n";
|
|
||||||
|
|
||||||
std::cout << "-------\n";
|
|
||||||
|
|
||||||
// widgets contain all of thier children inside their geometry
|
// widgets contain all of thier children inside their geometry
|
||||||
// we will check if the event's repaint area (the area that needs to be repainted :))
|
// we will check if the event's repaint area (the area that needs to be repainted :))
|
||||||
// overlaps with our geometry. If it does, we will proceed with the repaint process
|
// overlaps with our geometry. If it does, we will proceed with the repaint process
|
||||||
if (!event.get_repaint_area().contains_box(m_current_geometry)) {
|
if (!event.get_repaint_area().contains_box(m_current_geometry)) {
|
||||||
|
event.accept(); // consume this event so that it won't bubble down to the other children
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "--- PASSED\n";
|
// before calling this widget's paint function, we
|
||||||
|
// will perform generic widget painting behavior (background color, etc)
|
||||||
|
do_generic_paint();
|
||||||
|
|
||||||
on_paint(); // we're going to call this widget's paint function
|
// we're going to call this widget's paint handler function
|
||||||
|
// we will also save and then restore the cairo context
|
||||||
|
// to prevent the state (e.g. source rgb) for leaking onto other widgets
|
||||||
|
auto painter = m_window->get_painter();
|
||||||
|
auto cr = painter.get_cairo();
|
||||||
|
|
||||||
// tell all children about this event
|
cr->save();
|
||||||
// the repaint area matching the geometry is checked at the start of
|
on_paint();
|
||||||
// this function, which means they'll repaint as well if it is needed
|
cr->restore();
|
||||||
for (auto& child : m_children) {
|
|
||||||
child->dispatch_event(event);
|
// we are not going to call accept() on this event as we want it to bubble down
|
||||||
|
// to all the other relevant children
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::handle_mouse_move_event(MouseMoveEvent &event) {
|
||||||
|
bool update_focus_to = true;
|
||||||
|
|
||||||
|
if (!m_current_geometry.contains_point(event.get_point())) {
|
||||||
|
// we just became unfocused
|
||||||
|
if (m_is_focused) {
|
||||||
|
update_focus_to = false;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_is_focused = update_focus_to;
|
||||||
|
auto focus_update_event = FocusUpdateEvent(update_focus_to);
|
||||||
|
on_mouse_move(event);
|
||||||
|
on_focus_update(focus_update_event);
|
||||||
|
|
||||||
|
if (m_consumes_hits)
|
||||||
|
event.accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::handle_mouse_button_event(MouseButtonEvent &event) {
|
||||||
|
// the mouse has updated its click state in our bounds
|
||||||
|
m_is_active = event.get_was_left_button_pressed();
|
||||||
|
|
||||||
|
auto activation_update_event = ActivationUpdateEvent(m_is_active);
|
||||||
|
on_mouse_button(event);
|
||||||
|
on_activation_update(activation_update_event);
|
||||||
|
|
||||||
|
if (m_consumes_hits)
|
||||||
|
event.accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::dispatch_event(Event &event) {
|
void Widget::dispatch_event(Event &event) {
|
||||||
process_event(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Widget::process_event(Event &event) {
|
|
||||||
switch (event.get_type()) {
|
switch (event.get_type()) {
|
||||||
case EventType::MouseMove: {
|
case EventType::MouseMove: {
|
||||||
on_mouse_move(reinterpret_cast<MouseMoveEvent&>(event));
|
handle_mouse_move_event(reinterpret_cast<MouseMoveEvent&>(event));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case EventType::MouseButton: {
|
case EventType::MouseButton: {
|
||||||
on_mouse_button(reinterpret_cast<MouseButtonEvent&>(event));
|
handle_mouse_button_event(reinterpret_cast<MouseButtonEvent&>(event));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case EventType::WidgetRepaintRequested: {
|
case EventType::WidgetRepaintRequested: {
|
||||||
handle_repaint_requested(reinterpret_cast<WidgetRepaintRequestedEvent&>(event));
|
handle_repaint_requested(reinterpret_cast<WidgetRepaintRequestedEvent&>(event));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
/* these events aren't handled here, as they won't be dispatched to us from other places */
|
||||||
|
case EventType::FocusUpdate:
|
||||||
|
case EventType::ActivationUpdate:
|
||||||
case EventType::NoneEvent: {
|
case EventType::NoneEvent: {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!event.get_accepted()) {
|
||||||
|
for (auto& child : m_children) {
|
||||||
|
child->dispatch_event(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,18 +1,34 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
#include "Box.hpp"
|
#include "Box.hpp"
|
||||||
#include "Events.hpp"
|
#include "Events.hpp"
|
||||||
#include "Forward.hpp"
|
#include "Forward.hpp"
|
||||||
|
#include "RGB.hpp"
|
||||||
|
#include "TopLevelStyles.hpp"
|
||||||
|
#include "StyleMacros.hpp"
|
||||||
|
|
||||||
namespace Raven {
|
namespace Raven {
|
||||||
|
|
||||||
class Widget {
|
class Widget {
|
||||||
|
|
||||||
|
DEF_STYLE(do_background_fill, bool, false)
|
||||||
|
DEF_STYLE(background_fill_color, RGB, 0, 0, 0)
|
||||||
|
DEF_STYLE(background_border_radius, double, 0.0)
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Box m_current_geometry {};
|
Box m_current_geometry {};
|
||||||
std::vector<Widget*> m_children;
|
std::vector<Widget*> m_children;
|
||||||
Widget *m_parent { nullptr };
|
Widget *m_parent { nullptr };
|
||||||
Window *m_window { nullptr };
|
Window *m_window { nullptr };
|
||||||
|
std::shared_ptr<TopLevelStyles> m_top_level_styles = nullptr;
|
||||||
|
bool m_did_init { false };
|
||||||
|
bool m_is_focused { false };
|
||||||
|
bool m_is_active { false };
|
||||||
|
bool m_consumes_hits { false };
|
||||||
public:
|
public:
|
||||||
Widget() {}
|
Widget() {}
|
||||||
|
|
||||||
|
@ -27,21 +43,39 @@ public:
|
||||||
void set_parent(Widget *parent) { m_parent = parent; }
|
void set_parent(Widget *parent) { m_parent = parent; }
|
||||||
|
|
||||||
Window *get_window() { return m_window; }
|
Window *get_window() { return m_window; }
|
||||||
void set_window(Window *window) { m_window = window; }
|
void set_window(Window *window);
|
||||||
|
|
||||||
|
std::shared_ptr<TopLevelStyles> get_top_level_styles() { return m_top_level_styles; }
|
||||||
|
void set_top_level_styles(std::shared_ptr<TopLevelStyles> top_level_styles) { m_top_level_styles = top_level_styles; }
|
||||||
|
|
||||||
|
void set_did_init(bool did_init) { m_did_init = did_init; }
|
||||||
|
bool get_did_init() { return m_did_init; }
|
||||||
|
|
||||||
|
bool is_focused() { return m_is_focused; }
|
||||||
|
|
||||||
|
bool is_active() { return m_is_active; }
|
||||||
|
|
||||||
|
bool get_consumes_hits() { return m_consumes_hits; }
|
||||||
|
void set_consumes_hits(bool consumes_hits) { m_consumes_hits = consumes_hits; }
|
||||||
|
|
||||||
|
|
||||||
void dispatch_event(Event &event);
|
void dispatch_event(Event &event);
|
||||||
void wants_repaint();
|
void wants_repaint();
|
||||||
Widget *walk_until_top_level();
|
|
||||||
|
|
||||||
virtual void on_mouse_button(MouseButtonEvent &event) {};
|
virtual void on_init() { set_did_init(true); }
|
||||||
virtual void on_mouse_move(MouseMoveEvent &event) {};
|
virtual void on_mouse_button(MouseButtonEvent &event) {}
|
||||||
virtual void on_paint() {};
|
virtual void on_mouse_move(MouseMoveEvent &event) {}
|
||||||
|
virtual void on_focus_update(FocusUpdateEvent &event) {}
|
||||||
|
virtual void on_activation_update(ActivationUpdateEvent &event) {}
|
||||||
|
virtual void on_paint() {}
|
||||||
|
|
||||||
|
|
||||||
virtual ~Widget() {};
|
virtual ~Widget() {};
|
||||||
private:
|
private:
|
||||||
void process_event(Event &event);
|
|
||||||
void handle_repaint_requested(WidgetRepaintRequestedEvent &event);
|
void handle_repaint_requested(WidgetRepaintRequestedEvent &event);
|
||||||
|
void do_generic_paint();
|
||||||
|
void handle_mouse_move_event(MouseMoveEvent &event);
|
||||||
|
void handle_mouse_button_event(MouseButtonEvent &event);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include "Window.hpp"
|
#include "Window.hpp"
|
||||||
#include "Events.hpp"
|
#include "Events.hpp"
|
||||||
|
#include "src/Point.hpp"
|
||||||
|
|
||||||
namespace Raven {
|
namespace Raven {
|
||||||
|
|
||||||
|
@ -45,17 +46,21 @@ bool Window::spawn_window() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::dispatch_repaint_on_box(Box box) {
|
bool Window::dispatch_to_main_widget(Event &event) {
|
||||||
if (!m_main_widget)
|
if (!m_main_widget)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
auto event = WidgetRepaintRequestedEvent(std::move(box));
|
|
||||||
|
|
||||||
m_main_widget->dispatch_event(event);
|
m_main_widget->dispatch_event(event);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::dispatch_full_repaint() {
|
bool Window::dispatch_repaint_on_box(Box box) {
|
||||||
dispatch_repaint_on_box(m_current_geometry);
|
auto event = WidgetRepaintRequestedEvent(std::move(box));
|
||||||
|
return dispatch_to_main_widget(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Window::dispatch_full_repaint() {
|
||||||
|
return dispatch_repaint_on_box(m_current_geometry);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::run(bool block) {
|
void Window::run(bool block) {
|
||||||
|
@ -68,13 +73,23 @@ void Window::run(bool block) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
switch (e.type) {
|
switch (e.type) {
|
||||||
case MapNotify:
|
case MapNotify: {
|
||||||
case Expose:
|
|
||||||
std::cout << "gotta repaint!\n";
|
|
||||||
dispatch_full_repaint();
|
dispatch_full_repaint();
|
||||||
break;
|
break;
|
||||||
default:
|
}
|
||||||
|
case Expose: {
|
||||||
|
auto box = Box(e.xexpose.x, e.xexpose.y, e.xexpose.width, e.xexpose.height);
|
||||||
|
dispatch_repaint_on_box(std::move(box));
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
case MotionNotify: {
|
||||||
|
auto point = Point(e.xmotion.x, e.xmotion.y);
|
||||||
|
auto event = MouseMoveEvent(std::move(point));
|
||||||
|
dispatch_to_main_widget(event);
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include "Widget.hpp"
|
#include "Widget.hpp"
|
||||||
#include "Painter.hpp"
|
#include "Painter.hpp"
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
|
@ -12,6 +13,7 @@ private:
|
||||||
Widget *m_main_widget { nullptr };
|
Widget *m_main_widget { nullptr };
|
||||||
Box m_current_geometry { 0, 0, 800, 600 };
|
Box m_current_geometry { 0, 0, 800, 600 };
|
||||||
Painter m_painter {};
|
Painter m_painter {};
|
||||||
|
std::shared_ptr<TopLevelStyles> m_top_level_styles = std::make_shared<TopLevelStyles>(this);
|
||||||
|
|
||||||
Display *m_x_display { nullptr };
|
Display *m_x_display { nullptr };
|
||||||
public:
|
public:
|
||||||
|
@ -25,9 +27,13 @@ public:
|
||||||
Widget *get_main_widget() { return m_main_widget; }
|
Widget *get_main_widget() { return m_main_widget; }
|
||||||
void set_main_widget(Widget *main_widget);
|
void set_main_widget(Widget *main_widget);
|
||||||
|
|
||||||
|
// TODO: add setter for top_level_styles
|
||||||
|
std::shared_ptr<TopLevelStyles> get_top_level_styles() { return m_top_level_styles; }
|
||||||
|
|
||||||
void dispatch_repaint_on_box(Box box);
|
|
||||||
void dispatch_full_repaint();
|
bool dispatch_repaint_on_box(Box box);
|
||||||
|
bool dispatch_full_repaint();
|
||||||
|
bool dispatch_to_main_widget(Event &event);
|
||||||
|
|
||||||
Box &get_current_geometry() { return m_current_geometry; }
|
Box &get_current_geometry() { return m_current_geometry; }
|
||||||
|
|
||||||
|
|
|
@ -6,12 +6,18 @@
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
Raven::Window window {};
|
Raven::Window window {};
|
||||||
|
Raven::Widget main_widget {};
|
||||||
Raven::Button button {"click me!"};
|
Raven::Button button {"click me!"};
|
||||||
|
|
||||||
window.spawn_window();
|
window.spawn_window();
|
||||||
|
|
||||||
button.set_current_geometry(Raven::Box(10, 10, 100, 30));
|
button.set_current_geometry(Raven::Box(10, 10, 100, 30));
|
||||||
window.set_main_widget(&button);
|
main_widget.set_current_geometry(window.get_current_geometry());
|
||||||
|
main_widget.set_style_background_fill_color(Raven::RGB(0.9764, 0.9607, 0.8431));
|
||||||
|
main_widget.set_style_do_background_fill(true);
|
||||||
|
window.set_main_widget(&main_widget);
|
||||||
|
|
||||||
|
main_widget.add_child(&button);
|
||||||
|
|
||||||
window.run(true);
|
window.run(true);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in a new issue