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;
|
return x >= m_x && m_x + m_width >= x && y >= m_y && m_y + m_height >= y;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Box::contains_box(const Box &other) {
|
bool Box::contains_box(Box &other) const {
|
||||||
// FIXME
|
double ax1 = m_x;
|
||||||
return false;
|
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; }
|
void set_height(double height) { m_height = height; }
|
||||||
|
|
||||||
bool contains_point(double x, double y);
|
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 <stdint.h>
|
||||||
#include "Point.hpp"
|
#include "Point.hpp"
|
||||||
|
#include "Box.hpp"
|
||||||
|
|
||||||
namespace Raven {
|
namespace Raven {
|
||||||
|
|
||||||
|
@ -57,11 +58,16 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
class WidgetRepaintRequestedEvent : public Event {
|
class WidgetRepaintRequestedEvent : public Event {
|
||||||
|
private:
|
||||||
|
Box m_repaint_area;
|
||||||
public:
|
public:
|
||||||
WidgetRepaintRequestedEvent() {}
|
WidgetRepaintRequestedEvent(Box repaint_area)
|
||||||
|
: m_repaint_area(repaint_area) {}
|
||||||
|
|
||||||
EventType get_type() { return EventType::WidgetRepaintRequested; }
|
EventType get_type() { return EventType::WidgetRepaintRequested; }
|
||||||
const char *get_name() { return "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
|
#pragma once
|
||||||
|
|
||||||
|
#include "Box.hpp"
|
||||||
#include <cairomm/cairomm.h>
|
#include <cairomm/cairomm.h>
|
||||||
|
|
||||||
namespace Raven {
|
namespace Raven {
|
||||||
|
@ -12,6 +13,8 @@ public:
|
||||||
|
|
||||||
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 rounded_rectangle(Box &geometry, double border_radius);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,78 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <algorithm>
|
||||||
#include "Widget.hpp"
|
#include "Widget.hpp"
|
||||||
#include "Events.hpp"
|
#include "Events.hpp"
|
||||||
|
#include "Window.hpp"
|
||||||
|
|
||||||
namespace Raven {
|
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) {
|
void Widget::dispatch_event(Event &event) {
|
||||||
process_event(event);
|
process_event(event);
|
||||||
}
|
}
|
||||||
|
@ -19,7 +88,7 @@ void Widget::process_event(Event &event) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case EventType::WidgetRepaintRequested: {
|
case EventType::WidgetRepaintRequested: {
|
||||||
on_paint();
|
handle_repaint_requested(reinterpret_cast<WidgetRepaintRequestedEvent&>(event));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case EventType::NoneEvent: {
|
case EventType::NoneEvent: {
|
||||||
|
|
|
@ -1,29 +1,47 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
#include "Box.hpp"
|
#include "Box.hpp"
|
||||||
#include "Events.hpp"
|
#include "Events.hpp"
|
||||||
|
#include "Forward.hpp"
|
||||||
|
|
||||||
namespace Raven {
|
namespace Raven {
|
||||||
|
|
||||||
class Widget {
|
class Widget {
|
||||||
private:
|
private:
|
||||||
Box m_current_geometry {};
|
Box m_current_geometry {};
|
||||||
|
std::vector<Widget*> m_children;
|
||||||
|
Widget *m_parent { nullptr };
|
||||||
|
Window *m_window { nullptr };
|
||||||
public:
|
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 dispatch_event(Event &event);
|
||||||
|
void wants_repaint();
|
||||||
|
Widget *walk_until_top_level();
|
||||||
|
|
||||||
virtual void on_mouse_button(MouseButtonEvent &event) = 0;
|
virtual void on_mouse_button(MouseButtonEvent &event) {};
|
||||||
virtual void on_mouse_move(MouseMoveEvent &event) = 0;
|
virtual void on_mouse_move(MouseMoveEvent &event) {};
|
||||||
virtual void on_paint() = 0;
|
virtual void on_paint() {};
|
||||||
|
|
||||||
virtual ~Widget() = default;
|
virtual ~Widget() = default;
|
||||||
private:
|
private:
|
||||||
void process_event(Event &event);
|
void process_event(Event &event);
|
||||||
|
void handle_repaint_requested(WidgetRepaintRequestedEvent &event);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,6 +1,5 @@
|
||||||
#include <X11/X.h>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "Window.hpp"
|
#include <X11/X.h>
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#include <X11/Xutil.h>
|
#include <X11/Xutil.h>
|
||||||
#include <cairomm/cairomm.h>
|
#include <cairomm/cairomm.h>
|
||||||
|
@ -8,8 +7,16 @@
|
||||||
#include <cairomm/surface.h>
|
#include <cairomm/surface.h>
|
||||||
#include <cairomm/xlib_surface.h>
|
#include <cairomm/xlib_surface.h>
|
||||||
|
|
||||||
|
#include "Window.hpp"
|
||||||
|
#include "Events.hpp"
|
||||||
|
|
||||||
namespace Raven {
|
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() {
|
bool Window::spawn_window() {
|
||||||
Display *dsp = XOpenDisplay(NULL);
|
Display *dsp = XOpenDisplay(NULL);
|
||||||
if (dsp == NULL) {
|
if (dsp == NULL) {
|
||||||
|
@ -38,6 +45,19 @@ bool Window::spawn_window() {
|
||||||
return true;
|
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) {
|
void Window::run(bool block) {
|
||||||
XEvent e;
|
XEvent e;
|
||||||
|
|
||||||
|
@ -48,14 +68,13 @@ void Window::run(bool block) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
switch (e.type) {
|
switch (e.type) {
|
||||||
case MapNotify: {
|
case MapNotify:
|
||||||
std::cout << "MapNotify\n";
|
case Expose:
|
||||||
|
std::cout << "gotta repaint!\n";
|
||||||
|
dispatch_full_repaint();
|
||||||
break;
|
break;
|
||||||
}
|
default:
|
||||||
case Expose: {
|
|
||||||
std::cout << "we'd probably repaint the window right now\n";
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,8 @@ namespace Raven {
|
||||||
|
|
||||||
class Window {
|
class Window {
|
||||||
private:
|
private:
|
||||||
Widget *m_active_widget { nullptr };
|
Widget *m_hovered_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 {};
|
||||||
|
|
||||||
|
@ -18,8 +19,15 @@ public:
|
||||||
|
|
||||||
Painter &get_painter() { return m_painter; }
|
Painter &get_painter() { return m_painter; }
|
||||||
|
|
||||||
Widget *get_active_widget() { return m_active_widget; }
|
Widget *get_hovered_widget() { return m_hovered_widget; }
|
||||||
void set_active_widget(Widget *active_widget) { m_active_widget = active_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; }
|
Box &get_current_geometry() { return m_current_geometry; }
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,17 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "Window.hpp"
|
#include "Window.hpp"
|
||||||
|
#include "Widget.hpp"
|
||||||
|
#include "Box.hpp"
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
Raven::Window window {};
|
Raven::Window window {};
|
||||||
|
Raven::Widget main_widget {};
|
||||||
|
|
||||||
window.spawn_window();
|
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;
|
return 0;
|
||||||
}
|
}
|
Loading…
Reference in a new issue