-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdrawable.h
189 lines (152 loc) · 4.18 KB
/
drawable.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
#pragma once
#include <gtkmm/drawingarea.h>
#include <sigc++/sigc++.h>
#include <vector>
//class to represent a hierarchy of objects drawable to a cairo canvas
//child drawables can be added and are automatically drawn
class Drawable : public sigc::trackable{
protected:
std::vector<std::shared_ptr<Drawable>> children;
bool drawChildren(const Cairo::RefPtr<Cairo::Context>& cr) {
bool out = false;
for(auto& d: children){
out = out || d->draw(cr);
}
return out;
}
public:
Drawable() = default;
virtual bool draw(const Cairo::RefPtr<Cairo::Context>& cr) = 0;
//add drawable to area
void connect(Gtk::DrawingArea& area){
area.signal_draw().connect(sigc::mem_fun(*this, &Drawable::draw));
}
// references can't be null
void addChild(std::shared_ptr<Drawable>&& d) {
children.push_back(d);
}
void removeChild(int i) {
children.erase(children.begin() + i);
}
const std::vector<std::shared_ptr<Drawable>>& getChildren(){
return children;
}
};
class ChildDrawer: public Drawable{
public:
ChildDrawer() = default;
bool draw(const Cairo::RefPtr<Cairo::Context>& cr) override{
return drawChildren(cr);
}
};
// An abstract drawable that draws some primitive cairo path with a given fill, stroke
// scale, orientation, and position
class Shape : public Drawable{
private:
bool between(double x,double min, double max){
return x>min && x<max;
}
public:
double x=0,y=0; // coordinates of center
double angle=0;
double fr = 0, fg = 0, fb = 0, fa = 1;
double sr = 0, sg = 0, sb = 0, sa = 1;
double sx=1,sy=1; //size of bounding box
Shape() = default;
Shape(double x, double y, double sx, double sy): x(x), y(y), sx(sx), sy(sy){}
void set_position(double x, double y){
this->x = x;
this->y = y;
}
void set_fill_color(double r,double g, double b, double a){
this->fr = r;
this->fg = g;
this->fb = b;
this->fa = a;
}
void set_stroke_color(double r, double g, double b, double a) {
this->sr = r;
this->sg = g;
this->sb = b;
this->sa = a;
}
void set_dimensions(double sx, double sy){
this->sx =sx; this->sy = sy;
}
virtual bool draw_shape(const Cairo::RefPtr<Cairo::Context> &cr) = 0;
virtual bool draw(const Cairo::RefPtr<Cairo::Context> &cr) override{
cr->save();
cr->translate(x, y);
cr->scale(sx, sy);
cr->rotate(angle);
cr->set_source_rgb(fr, fg, fb);
bool out = draw_shape(cr);
cr->restore();
return out;
}
double top(){
return y - sy/2;
}
double bottom(){
return y + sy / 2;
}
double left(){
return x - sx /2;
}
double right(){
return y + sx/2;
}
bool point_in_box(double x, double y) {
return between(x, this->x - sx, this->x + sx) &&
between(y, this->y - sy, this->y + sy);
}
//by default tests the unoriented bounding box
virtual bool point_inside(double x, double y){
return point_in_box(x,y);
}
};
class Square : public Shape{
public:
Square() = default;
Square(double x, double y, double sx, double sy) : Shape(x, y, sx, sy) { }
virtual bool draw_shape(const Cairo::RefPtr<Cairo::Context> &cr) override{
cr->rectangle(-0.5, -0.5, 1, 1);
cr->close_path();
cr->fill();
cr->set_source_rgb(sr, sg, sb);
//cr->stroke();
return false;
}
};
class Hexagon : public Shape {
public:
Hexagon() = default;
Hexagon(double x, double y, double sx, double sy) : Shape(x, y, sx, sy) {}
virtual bool draw_shape(const Cairo::RefPtr<Cairo::Context> &cr) override {
cr->translate(-0.5, -0.5);
cr->move_to(0.5 , 0);
cr->line_to(1,1/(2*sqrt(3)));
cr->line_to(1,1 - 1 / (2 * sqrt(3)));
cr->line_to(0.5, 1);
cr->line_to(0,1 - 1 / (2 * sqrt(3)));
cr->line_to(0, 1 / (2 * sqrt(3)));
cr->close_path();
cr->fill();
cr->set_source_rgb(sr, sg, sb);
cr->stroke();
return false;
}
};
// a wrapper for a drawing area that add a convienience function
// for triggering a draw
class AreaController{
protected:
Gtk::DrawingArea* area;
public:
AreaController(Gtk::DrawingArea *area): area{area} {}
void invalidate_rect() {
auto win = area->get_window();
if(win)
win->invalidate_rect(area->get_allocation(), true);
}
};