switch to different painting method and add label widget
This commit is contained in:
parent
24c139b917
commit
596b0e530f
12 changed files with 125 additions and 49 deletions
|
@ -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]
|
||||
)
|
||||
|
|
|
@ -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
25
src/Label.cpp
Normal 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
23
src/Label.hpp
Normal 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();
|
||||
};
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
||||
|
|
10
src/main.cpp
10
src/main.cpp
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue