switch to different painting method and add label widget

This commit is contained in:
hippoz 2022-03-26 02:57:41 +02:00
parent 24c139b917
commit 596b0e530f
Signed by: hippoz
GPG key ID: 7C52899193467641
12 changed files with 125 additions and 49 deletions

View file

@ -7,10 +7,11 @@ xlib_dep = dependency('x11')
executable(
'ravenapp',
'./src/Box.cpp',
'./src/Widget.cpp',
'./src/Button.cpp',
'./src/Painter.cpp',
'./src/Window.cpp',
'./src/Widget.cpp',
'./src/Button.cpp',
'./src/Label.cpp',
'./src/main.cpp',
dependencies : [cairomm_dep, xlib_dep, pangocairo_dep]
)

View file

@ -66,15 +66,16 @@ public:
class WidgetRepaintRequestedEvent : public Event {
private:
Box m_repaint_area;
bool m_should_do_group { false };
public:
WidgetRepaintRequestedEvent(Box repaint_area)
: m_repaint_area(repaint_area) {}
WidgetRepaintRequestedEvent(bool should_do_group)
: m_should_do_group(should_do_group) {}
EventType get_type() { return EventType::WidgetRepaintRequested; }
const char *get_name() { return "WidgetRepaintRequested"; }
Box &get_repaint_area() { return m_repaint_area; }
bool should_do_group() { return m_should_do_group; }
void set_should_do_group(bool should_do_group) { m_should_do_group = should_do_group; }
};
class FocusUpdateEvent : public Event {

25
src/Label.cpp Normal file
View file

@ -0,0 +1,25 @@
#include "Label.hpp"
#include "Window.hpp"
namespace Raven {
void Label::on_init() {
// the label will inherit the background color properties from the parent
if (Widget *parent = get_parent()) {
set_do_background_fill(parent->get_do_background_fill());
set_background_fill_color(parent->get_background_fill_color());
}
set_did_init(true);
}
void Label::on_paint() {
auto painter = get_window()->get_painter();
auto text_color = get_styles()->get_label_text_color();
painter.source_rgb(text_color);
painter.set_pango_font_description(get_styles()->get_controls_font_description());
painter.text(get_current_geometry(), m_text, PaintTextAlign::Center);
painter.fill();
}
}

23
src/Label.hpp Normal file
View file

@ -0,0 +1,23 @@
#pragma once
#include "Widget.hpp"
#include "PropMacros.hpp"
namespace Raven {
class Label : public Widget {
DEF_WIDGET_STYLE_PROP(text, std::string, "")
private:
public:
Label(std::string text)
: Widget()
, m_text(text) {}
~Label() {}
protected:
void on_paint();
void on_init();
};
}

View file

@ -76,4 +76,13 @@ void Painter::fill() {
m_cairo->fill();
}
void Painter::begin_paint_group() {
m_cairo->push_group();
}
void Painter::end_paint_group() {
m_cairo->pop_group_to_source();
m_cairo->paint();
}
}

View file

@ -3,6 +3,7 @@
#include "Box.hpp"
#include "Point.hpp"
#include "RGB.hpp"
#include "cairomm/xlib_surface.h"
#include <cairomm/cairomm.h>
#include <pango/pangocairo.h>
@ -15,8 +16,8 @@ enum class PaintTextAlign {
class Painter {
private:
Cairo::RefPtr<Cairo::Context> m_cairo;
PangoFontDescription *m_pango_font_description;
Cairo::RefPtr<Cairo::Context> m_cairo { nullptr };
PangoFontDescription *m_pango_font_description { nullptr };
public:
Painter() {}
@ -32,6 +33,9 @@ public:
void source_rgb(RGB &source_rgb);
void fill();
void begin_paint_group();
void end_paint_group();
};
}

View file

@ -25,6 +25,8 @@ DEF_WIDGET_STYLE_PROP(button_focused_color, RGB, m_accent_color_darker)
DEF_WIDGET_STYLE_PROP(button_active_color, RGB, m_accent_color_darkest)
DEF_WIDGET_STYLE_PROP(button_border_radius, double, 8.0)
DEF_WIDGET_STYLE_PROP(label_text_color, RGB, m_text_color)
private:
Window *m_window;
public:

View file

@ -13,13 +13,6 @@ void Widget::set_window(Window *window) {
on_init();
}
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;
@ -51,34 +44,42 @@ void Widget::do_generic_paint() {
}
}
void Widget::handle_repaint_requested(WidgetRepaintRequestedEvent &event) {
void Widget::wants_repaint() {
// TODOO: not necessary
m_window->widget_repaint(this);
}
void Widget::handle_repaint(WidgetRepaintRequestedEvent &event) {
// immediately accept the event - we will do our own propagation logic
event.accept();
if (!m_did_init)
return;
// 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)) {
event.accept(); // consume this event so that it won't bubble down to the other children
return;
}
// before calling this widget's paint function, we
// will perform generic widget painting behavior (background color, etc)
do_generic_paint();
// 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();
auto event_should_do_group = event.should_do_group();
if (event_should_do_group) {
painter.begin_paint_group();
}
do_generic_paint();
cr->save();
on_paint();
cr->restore();
// we are not going to call accept() on this event as we want it to bubble down
// to all the other relevant children
// we will propagate this event to all of our children, except it will have
// should_do_group set to false
event.set_should_do_group(false);
for (auto& child : m_children) {
child->dispatch_event(event);
}
if (event_should_do_group) {
painter.end_paint_group();
}
}
void Widget::handle_mouse_move_event(MouseMoveEvent &event) {
@ -137,7 +138,7 @@ void Widget::dispatch_event(Event &event) {
break;
}
case EventType::WidgetRepaintRequested: {
handle_repaint_requested(reinterpret_cast<WidgetRepaintRequestedEvent&>(event));
handle_repaint(reinterpret_cast<WidgetRepaintRequestedEvent&>(event));
break;
}
/* these events aren't handled here, as they won't be dispatched to us from other places */

View file

@ -62,17 +62,17 @@ public:
void dispatch_event(Event &event);
void wants_repaint();
virtual ~Widget() {};
protected:
virtual void on_init() { set_did_init(true); }
virtual void on_mouse_button(MouseButtonEvent &event) {}
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() {};
private:
void handle_repaint_requested(WidgetRepaintRequestedEvent &event);
void handle_repaint(WidgetRepaintRequestedEvent& event);
void do_generic_paint();
void handle_mouse_move_event(MouseMoveEvent &event);
void handle_mouse_button_event(MouseButtonEvent &event);

View file

@ -60,6 +60,11 @@ bool Window::spawn_window() {
return true;
}
void Window::widget_repaint(Widget *target) {
auto event = WidgetRepaintRequestedEvent(true);
target->dispatch_event(event);
}
bool Window::dispatch_to_main_widget(Event &event) {
if (!m_main_widget)
return false;
@ -68,13 +73,9 @@ bool Window::dispatch_to_main_widget(Event &event) {
return true;
}
bool Window::dispatch_repaint_on_box(Box box) {
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);
auto event = WidgetRepaintRequestedEvent(true);
return dispatch_to_main_widget(event);
}
void Window::run(bool block) {
@ -107,8 +108,9 @@ void Window::run(bool block) {
}
case Expose: {
if (e.xexpose.count == 0) {
auto box = Box(e.xexpose.x, e.xexpose.y, e.xexpose.width, e.xexpose.height);
dispatch_repaint_on_box(std::move(box));
// TODO: hack
// might run into issues with other X implementations... :(
dispatch_full_repaint();
}
break;
}

View file

@ -1,6 +1,7 @@
#pragma once
#include <memory>
#include <stack>
#include "Widget.hpp"
#include "Painter.hpp"
#include <X11/Xlib.h>
@ -33,7 +34,8 @@ public:
Widget *get_main_widget() { return m_main_widget; }
void set_main_widget(Widget *main_widget);
// TODO: add setter for top_level_styles
void widget_repaint(Widget *target);
std::shared_ptr<TopLevelStyles> get_top_level_styles() { return m_top_level_styles; }

View file

@ -1,25 +1,31 @@
#include "Label.hpp"
#include "Window.hpp"
#include "Widget.hpp"
#include "Button.hpp"
#include "Box.hpp"
#include "Label.hpp"
int main() {
Raven::Window window {};
Raven::Widget main_widget {};
Raven::Button button {"click me!"};
Raven::Label label {"you have not yet clicked the button..."};
window.spawn_window();
button.set_current_geometry(Raven::Box(10, 10, 100, 30));
label.set_current_geometry(Raven::Box(10, 45, 100, 20));
main_widget.set_background_fill_color(window.get_top_level_styles()->get_background_color());
main_widget.set_do_background_fill(true);
window.set_main_widget(&main_widget);
button.on_click = [&button]() {
button.set_text("clicked!");
button.on_click = [&label]() {
label.set_text("you clicked it!!!!!");
};
main_widget.add_child(&button);
main_widget.add_child(&label);
window.run(true);
return 0;