dispatch repaint events and lay yet more groundwork
This commit is contained in:
parent
b4cfe309f3
commit
529c286b8f
13 changed files with 234 additions and 25 deletions
18
src/Box.cpp
18
src/Box.cpp
|
@ -6,9 +6,21 @@ 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;
|
||||
}
|
||||
|
||||
bool Box::contains_box(const Box &other) {
|
||||
// FIXME
|
||||
return false;
|
||||
bool Box::contains_box(Box &other) const {
|
||||
double ax1 = m_x;
|
||||
double ax2 = m_x + m_width;
|
||||
double ay1 = m_y;
|
||||
double ay2 = m_y + m_height;
|
||||
|
||||
double bx1 = other.get_x();
|
||||
double bx2 = other.get_x() + other.get_width();
|
||||
double by1 = other.get_y();
|
||||
double by2 = other.get_y() + other.get_height();
|
||||
|
||||
// https://stackoverflow.com/a/306332
|
||||
bool boxes_overlap = (ax1 < bx2 && ax2 > bx1 && ay1 < by2 && ay2 > by1);
|
||||
|
||||
return boxes_overlap;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ public:
|
|||
void set_height(double height) { m_height = height; }
|
||||
|
||||
bool contains_point(double x, double y);
|
||||
bool contains_box(const Box &other);
|
||||
bool contains_box(Box &other) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
13
src/Button.cpp
Normal file
13
src/Button.cpp
Normal file
|
@ -0,0 +1,13 @@
|
|||
#include "Button.hpp"
|
||||
#include "Window.hpp"
|
||||
|
||||
namespace Raven {
|
||||
|
||||
void Button::on_paint() {
|
||||
auto painter = get_window()->get_painter();
|
||||
auto ctx = painter.get_cairo();
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
22
src/Button.hpp
Normal file
22
src/Button.hpp
Normal file
|
@ -0,0 +1,22 @@
|
|||
#include <string>
|
||||
#include "Widget.hpp"
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Raven {
|
||||
|
||||
class Button : public Widget {
|
||||
private:
|
||||
std::string m_text;
|
||||
public:
|
||||
Button(std::string text)
|
||||
: Widget()
|
||||
, m_text(text) {}
|
||||
|
||||
void set_text(std::string text) { m_text = text; wants_repaint(); }
|
||||
std::string &get_text() { return m_text; }
|
||||
|
||||
void on_paint();
|
||||
};
|
||||
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include "Point.hpp"
|
||||
#include "Box.hpp"
|
||||
|
||||
namespace Raven {
|
||||
|
||||
|
@ -57,11 +58,16 @@ public:
|
|||
};
|
||||
|
||||
class WidgetRepaintRequestedEvent : public Event {
|
||||
private:
|
||||
Box m_repaint_area;
|
||||
public:
|
||||
WidgetRepaintRequestedEvent() {}
|
||||
WidgetRepaintRequestedEvent(Box repaint_area)
|
||||
: m_repaint_area(repaint_area) {}
|
||||
|
||||
EventType get_type() { return EventType::WidgetRepaintRequested; }
|
||||
const char *get_name() { return "WidgetRepaintRequested"; }
|
||||
|
||||
Box &get_repaint_area() { return m_repaint_area; }
|
||||
};
|
||||
|
||||
}
|
||||
|
|
11
src/Forward.hpp
Normal file
11
src/Forward.hpp
Normal file
|
@ -0,0 +1,11 @@
|
|||
namespace Raven {
|
||||
class Box;
|
||||
class Button;
|
||||
class Events;
|
||||
class Painter;
|
||||
class Point;
|
||||
class Widget;
|
||||
class Window;
|
||||
|
||||
enum class EventType;
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
#include "Painter.hpp"
|
||||
|
||||
namespace Raven {
|
||||
|
||||
void Painter::rounded_rectangle(Box &geometry, double border_radius) {
|
||||
double aspect = 1.0;
|
||||
double radius = border_radius / aspect;
|
||||
double degrees = M_PI / 180.0;
|
||||
double x = geometry.get_x();
|
||||
double y = geometry.get_y();
|
||||
double w = geometry.get_width();
|
||||
double h = geometry.get_height();
|
||||
|
||||
m_cairo->begin_new_sub_path();
|
||||
m_cairo->arc(x + w - radius, y + radius, radius, -90 * degrees, 0 * degrees);
|
||||
m_cairo->arc(x + w - radius, y + h - radius, radius, 0 * degrees, 90 * degrees);
|
||||
m_cairo->arc(x + radius, y + h - radius, radius, 90 * degrees, 180 * degrees);
|
||||
m_cairo->arc(x + radius, y + radius, radius, 180 * degrees, 270 * degrees);
|
||||
m_cairo->close_path();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "Box.hpp"
|
||||
#include <cairomm/cairomm.h>
|
||||
|
||||
namespace Raven {
|
||||
|
@ -12,6 +13,8 @@ public:
|
|||
|
||||
Cairo::RefPtr<Cairo::Context> get_cairo() { return m_cairo; }
|
||||
void set_cairo(Cairo::RefPtr<Cairo::Context> cairo) { m_cairo = cairo; }
|
||||
|
||||
void rounded_rectangle(Box &geometry, double border_radius);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1,9 +1,78 @@
|
|||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include "Widget.hpp"
|
||||
#include "Events.hpp"
|
||||
#include "Window.hpp"
|
||||
|
||||
namespace Raven {
|
||||
|
||||
void Widget::wants_repaint() {
|
||||
if (!m_window)
|
||||
return;
|
||||
|
||||
m_window->dispatch_repaint_on_box(m_current_geometry);
|
||||
}
|
||||
|
||||
bool Widget::add_child(Widget *child) {
|
||||
if (child->get_parent()) {
|
||||
return false;
|
||||
}
|
||||
m_children.push_back(child);
|
||||
child->set_parent(this);
|
||||
// children inherit the window from the parent
|
||||
// TODO?: what happens when the parent changes its window?
|
||||
child->set_window(m_window);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Widget::remove_child(Widget *child) {
|
||||
m_children.erase(std::remove(m_children.begin(), m_children.end(), child), m_children.end());
|
||||
}
|
||||
|
||||
void Widget::handle_repaint_requested(WidgetRepaintRequestedEvent &event) {
|
||||
std::cout << "-------\n";
|
||||
|
||||
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
|
||||
// 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
|
||||
if (!event.get_repaint_area().contains_box(m_current_geometry)) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::cout << "--- PASSED\n";
|
||||
|
||||
on_paint(); // we're going to call this widget's paint function
|
||||
|
||||
// tell all children about this event
|
||||
// the repaint area matching the geometry is checked at the start of
|
||||
// this function, which means they'll repaint as well if it is needed
|
||||
for (auto& child : m_children) {
|
||||
child->dispatch_event(event);
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::dispatch_event(Event &event) {
|
||||
process_event(event);
|
||||
}
|
||||
|
@ -19,7 +88,7 @@ void Widget::process_event(Event &event) {
|
|||
break;
|
||||
}
|
||||
case EventType::WidgetRepaintRequested: {
|
||||
on_paint();
|
||||
handle_repaint_requested(reinterpret_cast<WidgetRepaintRequestedEvent&>(event));
|
||||
break;
|
||||
}
|
||||
case EventType::NoneEvent: {
|
||||
|
|
|
@ -1,29 +1,47 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "Box.hpp"
|
||||
#include "Events.hpp"
|
||||
#include "Forward.hpp"
|
||||
|
||||
namespace Raven {
|
||||
|
||||
class Widget {
|
||||
private:
|
||||
Box m_current_geometry {};
|
||||
std::vector<Widget*> m_children;
|
||||
Widget *m_parent { nullptr };
|
||||
Window *m_window { nullptr };
|
||||
public:
|
||||
Widget() {
|
||||
Widget() {}
|
||||
|
||||
}
|
||||
Box &get_current_geometry() { return m_current_geometry; }
|
||||
void set_current_geometry(Box current_geometry) { m_current_geometry = current_geometry; wants_repaint(); }
|
||||
|
||||
std::vector<Widget*> &get_children() { return m_children; }
|
||||
bool add_child(Widget *child);
|
||||
void remove_child(Widget *child);
|
||||
|
||||
Widget *get_parent() { return m_parent; }
|
||||
void set_parent(Widget *parent) { m_parent = parent; }
|
||||
|
||||
Window *get_window() { return m_window; }
|
||||
void set_window(Window *window) { m_window = window; }
|
||||
|
||||
const Box &get_current_geometry() const { return m_current_geometry; }
|
||||
|
||||
void dispatch_event(Event &event);
|
||||
void wants_repaint();
|
||||
Widget *walk_until_top_level();
|
||||
|
||||
virtual void on_mouse_button(MouseButtonEvent &event) = 0;
|
||||
virtual void on_mouse_move(MouseMoveEvent &event) = 0;
|
||||
virtual void on_paint() = 0;
|
||||
virtual void on_mouse_button(MouseButtonEvent &event) {};
|
||||
virtual void on_mouse_move(MouseMoveEvent &event) {};
|
||||
virtual void on_paint() {};
|
||||
|
||||
virtual ~Widget() = default;
|
||||
private:
|
||||
void process_event(Event &event);
|
||||
void handle_repaint_requested(WidgetRepaintRequestedEvent &event);
|
||||
};
|
||||
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
#include <X11/X.h>
|
||||
#include <iostream>
|
||||
#include "Window.hpp"
|
||||
#include <X11/X.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <cairomm/cairomm.h>
|
||||
|
@ -8,8 +7,16 @@
|
|||
#include <cairomm/surface.h>
|
||||
#include <cairomm/xlib_surface.h>
|
||||
|
||||
#include "Window.hpp"
|
||||
#include "Events.hpp"
|
||||
|
||||
namespace Raven {
|
||||
|
||||
void Window::set_main_widget(Widget *main_widget) {
|
||||
m_main_widget = main_widget;
|
||||
m_main_widget->set_window(this);
|
||||
}
|
||||
|
||||
bool Window::spawn_window() {
|
||||
Display *dsp = XOpenDisplay(NULL);
|
||||
if (dsp == NULL) {
|
||||
|
@ -38,6 +45,19 @@ bool Window::spawn_window() {
|
|||
return true;
|
||||
}
|
||||
|
||||
void Window::dispatch_repaint_on_box(Box box) {
|
||||
if (!m_main_widget)
|
||||
return;
|
||||
|
||||
auto event = WidgetRepaintRequestedEvent(std::move(box));
|
||||
|
||||
m_main_widget->dispatch_event(event);
|
||||
}
|
||||
|
||||
void Window::dispatch_full_repaint() {
|
||||
dispatch_repaint_on_box(m_current_geometry);
|
||||
}
|
||||
|
||||
void Window::run(bool block) {
|
||||
XEvent e;
|
||||
|
||||
|
@ -48,14 +68,13 @@ void Window::run(bool block) {
|
|||
break;
|
||||
|
||||
switch (e.type) {
|
||||
case MapNotify: {
|
||||
std::cout << "MapNotify\n";
|
||||
case MapNotify:
|
||||
case Expose:
|
||||
std::cout << "gotta repaint!\n";
|
||||
dispatch_full_repaint();
|
||||
break;
|
||||
}
|
||||
case Expose: {
|
||||
std::cout << "we'd probably repaint the window right now\n";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,8 @@ namespace Raven {
|
|||
|
||||
class Window {
|
||||
private:
|
||||
Widget *m_active_widget { nullptr };
|
||||
Widget *m_hovered_widget { nullptr };
|
||||
Widget *m_main_widget { nullptr };
|
||||
Box m_current_geometry { 0, 0, 800, 600 };
|
||||
Painter m_painter {};
|
||||
|
||||
|
@ -18,8 +19,15 @@ public:
|
|||
|
||||
Painter &get_painter() { return m_painter; }
|
||||
|
||||
Widget *get_active_widget() { return m_active_widget; }
|
||||
void set_active_widget(Widget *active_widget) { m_active_widget = active_widget; }
|
||||
Widget *get_hovered_widget() { return m_hovered_widget; }
|
||||
void set_hovered_widget(Widget *hovered_widget) { m_hovered_widget = hovered_widget; }
|
||||
|
||||
Widget *get_main_widget() { return m_main_widget; }
|
||||
void set_main_widget(Widget *main_widget);
|
||||
|
||||
|
||||
void dispatch_repaint_on_box(Box box);
|
||||
void dispatch_full_repaint();
|
||||
|
||||
Box &get_current_geometry() { return m_current_geometry; }
|
||||
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
#include <iostream>
|
||||
#include "Window.hpp"
|
||||
#include "Widget.hpp"
|
||||
#include "Box.hpp"
|
||||
|
||||
int main() {
|
||||
Raven::Window window {};
|
||||
Raven::Widget main_widget {};
|
||||
|
||||
window.spawn_window();
|
||||
window.run(true);
|
||||
|
||||
main_widget.set_current_geometry(Raven::Box(10, 10, 100, 30));
|
||||
window.set_main_widget(&main_widget);
|
||||
|
||||
window.run(true);
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue