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(
|
executable(
|
||||||
'ravenapp',
|
'ravenapp',
|
||||||
'./src/Box.cpp',
|
'./src/Box.cpp',
|
||||||
'./src/Widget.cpp',
|
|
||||||
'./src/Button.cpp',
|
|
||||||
'./src/Painter.cpp',
|
'./src/Painter.cpp',
|
||||||
'./src/Window.cpp',
|
'./src/Window.cpp',
|
||||||
|
'./src/Widget.cpp',
|
||||||
|
'./src/Button.cpp',
|
||||||
|
'./src/Label.cpp',
|
||||||
'./src/main.cpp',
|
'./src/main.cpp',
|
||||||
dependencies : [cairomm_dep, xlib_dep, pangocairo_dep]
|
dependencies : [cairomm_dep, xlib_dep, pangocairo_dep]
|
||||||
)
|
)
|
||||||
|
|
|
@ -66,15 +66,16 @@ public:
|
||||||
|
|
||||||
class WidgetRepaintRequestedEvent : public Event {
|
class WidgetRepaintRequestedEvent : public Event {
|
||||||
private:
|
private:
|
||||||
Box m_repaint_area;
|
bool m_should_do_group { false };
|
||||||
public:
|
public:
|
||||||
WidgetRepaintRequestedEvent(Box repaint_area)
|
WidgetRepaintRequestedEvent(bool should_do_group)
|
||||||
: m_repaint_area(repaint_area) {}
|
: m_should_do_group(should_do_group) {}
|
||||||
|
|
||||||
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; }
|
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 {
|
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();
|
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 "Box.hpp"
|
||||||
#include "Point.hpp"
|
#include "Point.hpp"
|
||||||
#include "RGB.hpp"
|
#include "RGB.hpp"
|
||||||
|
#include "cairomm/xlib_surface.h"
|
||||||
#include <cairomm/cairomm.h>
|
#include <cairomm/cairomm.h>
|
||||||
#include <pango/pangocairo.h>
|
#include <pango/pangocairo.h>
|
||||||
|
|
||||||
|
@ -15,8 +16,8 @@ enum class PaintTextAlign {
|
||||||
|
|
||||||
class Painter {
|
class Painter {
|
||||||
private:
|
private:
|
||||||
Cairo::RefPtr<Cairo::Context> m_cairo;
|
Cairo::RefPtr<Cairo::Context> m_cairo { nullptr };
|
||||||
PangoFontDescription *m_pango_font_description;
|
PangoFontDescription *m_pango_font_description { nullptr };
|
||||||
public:
|
public:
|
||||||
Painter() {}
|
Painter() {}
|
||||||
|
|
||||||
|
@ -32,6 +33,9 @@ public:
|
||||||
|
|
||||||
void source_rgb(RGB &source_rgb);
|
void source_rgb(RGB &source_rgb);
|
||||||
void fill();
|
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_active_color, RGB, m_accent_color_darkest)
|
||||||
DEF_WIDGET_STYLE_PROP(button_border_radius, double, 8.0)
|
DEF_WIDGET_STYLE_PROP(button_border_radius, double, 8.0)
|
||||||
|
|
||||||
|
DEF_WIDGET_STYLE_PROP(label_text_color, RGB, m_text_color)
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Window *m_window;
|
Window *m_window;
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -13,13 +13,6 @@ void Widget::set_window(Window *window) {
|
||||||
on_init();
|
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) {
|
bool Widget::add_child(Widget *child) {
|
||||||
if (child->get_parent()) {
|
if (child->get_parent()) {
|
||||||
return false;
|
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)
|
if (!m_did_init)
|
||||||
return;
|
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 painter = m_window->get_painter();
|
||||||
auto cr = painter.get_cairo();
|
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();
|
cr->save();
|
||||||
on_paint();
|
on_paint();
|
||||||
cr->restore();
|
cr->restore();
|
||||||
|
|
||||||
// we are not going to call accept() on this event as we want it to bubble down
|
// we will propagate this event to all of our children, except it will have
|
||||||
// to all the other relevant children
|
// 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) {
|
void Widget::handle_mouse_move_event(MouseMoveEvent &event) {
|
||||||
|
@ -137,7 +138,7 @@ void Widget::dispatch_event(Event &event) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case EventType::WidgetRepaintRequested: {
|
case EventType::WidgetRepaintRequested: {
|
||||||
handle_repaint_requested(reinterpret_cast<WidgetRepaintRequestedEvent&>(event));
|
handle_repaint(reinterpret_cast<WidgetRepaintRequestedEvent&>(event));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* these events aren't handled here, as they won't be dispatched to us from other places */
|
/* 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 dispatch_event(Event &event);
|
||||||
void wants_repaint();
|
void wants_repaint();
|
||||||
|
|
||||||
|
|
||||||
|
virtual ~Widget() {};
|
||||||
|
protected:
|
||||||
virtual void on_init() { set_did_init(true); }
|
virtual void on_init() { set_did_init(true); }
|
||||||
virtual void on_mouse_button(MouseButtonEvent &event) {}
|
virtual void on_mouse_button(MouseButtonEvent &event) {}
|
||||||
virtual void on_mouse_move(MouseMoveEvent &event) {}
|
virtual void on_mouse_move(MouseMoveEvent &event) {}
|
||||||
virtual void on_focus_update(FocusUpdateEvent &event) {}
|
virtual void on_focus_update(FocusUpdateEvent &event) {}
|
||||||
virtual void on_activation_update(ActivationUpdateEvent &event) {}
|
virtual void on_activation_update(ActivationUpdateEvent &event) {}
|
||||||
virtual void on_paint() {}
|
virtual void on_paint() {}
|
||||||
|
|
||||||
|
|
||||||
virtual ~Widget() {};
|
|
||||||
private:
|
private:
|
||||||
void handle_repaint_requested(WidgetRepaintRequestedEvent &event);
|
void handle_repaint(WidgetRepaintRequestedEvent& event);
|
||||||
void do_generic_paint();
|
void do_generic_paint();
|
||||||
void handle_mouse_move_event(MouseMoveEvent &event);
|
void handle_mouse_move_event(MouseMoveEvent &event);
|
||||||
void handle_mouse_button_event(MouseButtonEvent &event);
|
void handle_mouse_button_event(MouseButtonEvent &event);
|
||||||
|
|
|
@ -60,6 +60,11 @@ bool Window::spawn_window() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Window::widget_repaint(Widget *target) {
|
||||||
|
auto event = WidgetRepaintRequestedEvent(true);
|
||||||
|
target->dispatch_event(event);
|
||||||
|
}
|
||||||
|
|
||||||
bool Window::dispatch_to_main_widget(Event &event) {
|
bool Window::dispatch_to_main_widget(Event &event) {
|
||||||
if (!m_main_widget)
|
if (!m_main_widget)
|
||||||
return false;
|
return false;
|
||||||
|
@ -68,13 +73,9 @@ bool Window::dispatch_to_main_widget(Event &event) {
|
||||||
return true;
|
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() {
|
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) {
|
void Window::run(bool block) {
|
||||||
|
@ -107,8 +108,9 @@ void Window::run(bool block) {
|
||||||
}
|
}
|
||||||
case Expose: {
|
case Expose: {
|
||||||
if (e.xexpose.count == 0) {
|
if (e.xexpose.count == 0) {
|
||||||
auto box = Box(e.xexpose.x, e.xexpose.y, e.xexpose.width, e.xexpose.height);
|
// TODO: hack
|
||||||
dispatch_repaint_on_box(std::move(box));
|
// might run into issues with other X implementations... :(
|
||||||
|
dispatch_full_repaint();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <stack>
|
||||||
#include "Widget.hpp"
|
#include "Widget.hpp"
|
||||||
#include "Painter.hpp"
|
#include "Painter.hpp"
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
|
@ -33,7 +34,8 @@ 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
|
void widget_repaint(Widget *target);
|
||||||
|
|
||||||
std::shared_ptr<TopLevelStyles> get_top_level_styles() { return m_top_level_styles; }
|
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 "Window.hpp"
|
||||||
#include "Widget.hpp"
|
#include "Widget.hpp"
|
||||||
#include "Button.hpp"
|
#include "Button.hpp"
|
||||||
#include "Box.hpp"
|
#include "Box.hpp"
|
||||||
|
#include "Label.hpp"
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
Raven::Window window {};
|
Raven::Window window {};
|
||||||
Raven::Widget main_widget {};
|
Raven::Widget main_widget {};
|
||||||
Raven::Button button {"click me!"};
|
Raven::Button button {"click me!"};
|
||||||
|
Raven::Label label {"you have not yet clicked the button..."};
|
||||||
|
|
||||||
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));
|
||||||
|
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_background_fill_color(window.get_top_level_styles()->get_background_color());
|
||||||
main_widget.set_do_background_fill(true);
|
main_widget.set_do_background_fill(true);
|
||||||
window.set_main_widget(&main_widget);
|
window.set_main_widget(&main_widget);
|
||||||
|
|
||||||
button.on_click = [&button]() {
|
button.on_click = [&label]() {
|
||||||
button.set_text("clicked!");
|
label.set_text("you clicked it!!!!!");
|
||||||
};
|
};
|
||||||
|
|
||||||
main_widget.add_child(&button);
|
main_widget.add_child(&button);
|
||||||
|
main_widget.add_child(&label);
|
||||||
|
|
||||||
window.run(true);
|
window.run(true);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in a new issue