├── CairoTut.png ├── 1-empty-cairo-program ├── canvas.cpp ├── canvas.h └── main.cpp ├── m-mass-animation ├── ytballet.png ├── main.cpp ├── canvas.cpp └── canvas.h ├── 0-empty-program └── main.cpp ├── g-app-draw ├── atom.cpp ├── main.cpp └── atom.h ├── compile.sh ├── debug.sh ├── 2-a-red-line ├── canvas.cpp ├── canvas.h └── main.cpp ├── 4-picture-png ├── canvas.h ├── main.cpp └── canvas.cpp ├── 5-picture-svg ├── canvas.h ├── main.cpp └── canvas.cpp ├── 3-a-total-line ├── canvas.h ├── main.cpp └── canvas.cpp ├── .gitignore ├── 9-shift ├── main.cpp ├── canvas.h └── canvas.cpp ├── d-text ├── main.cpp ├── canvas.cpp └── canvas.h ├── 8-collision ├── main.cpp ├── canvas.h └── canvas.cpp ├── a-shift+move ├── main.cpp ├── canvas.h └── canvas.cpp ├── c-animation ├── main.cpp ├── canvas.cpp └── canvas.h ├── 6-mouse-position ├── main.cpp ├── canvas.h └── canvas.cpp ├── 7-mouse-complete ├── main.cpp ├── canvas.cpp └── canvas.h ├── b-shift+zoom+move ├── main.cpp ├── canvas.h └── canvas.cpp ├── e-ui-button-bar ├── main.cpp ├── canvas.h └── canvas.cpp ├── f-drawing-helpers ├── main.cpp └── canvas.cpp ├── k-like-cad ├── main.cpp └── typesNmath.h ├── o-breakout ├── main.cpp ├── typesNmath.h └── canvas.cpp ├── h-3-lagen-synthese ├── main.cpp ├── 3lagen.h ├── typesNmath.h └── canvas.cpp ├── i-4-bar-analytics ├── main.cpp ├── 4bar.h ├── typesNmath.h ├── canvas.h └── canvas.cpp ├── README.md └── CairoTut.svg /CairoTut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/morgner/Cairo-Tutorial/HEAD/CairoTut.png -------------------------------------------------------------------------------- /1-empty-cairo-program/canvas.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /m-mass-animation/ytballet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/morgner/Cairo-Tutorial/HEAD/m-mass-animation/ytballet.png -------------------------------------------------------------------------------- /0-empty-program/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | std::cout << "I say: 'Cairo' !\n"; 6 | } 7 | -------------------------------------------------------------------------------- /g-app-draw/atom.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file atom.cpp 3 | * 4 | * @author Manfred Morgner 5 | * @date 10.10.2018 6 | */ 7 | 8 | #include "atom.h" 9 | 10 | -------------------------------------------------------------------------------- /1-empty-cairo-program/canvas.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class CCanvas : public Gtk::DrawingArea 5 | { 6 | public: 7 | CCanvas() 8 | { 9 | 10 | } 11 | 12 | virtual ~CCanvas() { }; 13 | 14 | }; // CCanvas 15 | -------------------------------------------------------------------------------- /compile.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | SD=`pwd` 4 | SD=${SD##/*/} 5 | EN="CairoTut-$SD" 6 | 7 | clang `pkg-config --libs --cflags gtkmm-3.0 cairomm-1.0` -O3 -std=c++2a -lstdc++ -lm *.cpp -o "$EN" 8 | 9 | if [[ $? -eq 0 ]] 10 | then 11 | ./$EN 12 | fi 13 | 14 | echo "Executable Name: $EN" 15 | -------------------------------------------------------------------------------- /debug.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | SD=`pwd` 4 | SD=${SD##/*/} 5 | EN="CairoTut-$SD" 6 | 7 | clang `pkg-config --libs --cflags gtkmm-3.0 cairomm-1.0` -g -std=c++2a -lstdc++ -lm *.cpp -o "$EN" 8 | 9 | if [[ $? -eq 0 ]] 10 | then 11 | nemiver ./$EN 12 | fi 13 | 14 | echo "Executable Name: $EN" 15 | -------------------------------------------------------------------------------- /2-a-red-line/canvas.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | 3 | 4 | 5 | 6 | 7 | 8 | bool CCanvas::on_draw(Cairo::RefPtr const & cr) 9 | { 10 | cr->set_source_rgb(1.,.5,.0); 11 | cr->set_line_width(3); 12 | 13 | cr->move_to( 11, 11); 14 | cr->line_to(111,111); 15 | cr->stroke(); 16 | 17 | return true; 18 | } 19 | -------------------------------------------------------------------------------- /2-a-red-line/canvas.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class CCanvas : public Gtk::DrawingArea 5 | { 6 | public: 7 | CCanvas() 8 | { 9 | 10 | } 11 | 12 | virtual ~CCanvas() { }; 13 | 14 | protected: 15 | // Override default signal handler: 16 | bool on_draw(const Cairo::RefPtr& cr) override; 17 | 18 | }; // CCanvas 19 | -------------------------------------------------------------------------------- /4-picture-png/canvas.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class CCanvas : public Gtk::DrawingArea 5 | { 6 | public: 7 | CCanvas() 8 | { 9 | 10 | } 11 | 12 | virtual ~CCanvas() { }; 13 | 14 | protected: 15 | // Override default signal handler: 16 | bool on_draw(const Cairo::RefPtr& cr) override; 17 | 18 | }; // CCanvas 19 | -------------------------------------------------------------------------------- /5-picture-svg/canvas.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class CCanvas : public Gtk::DrawingArea 5 | { 6 | public: 7 | CCanvas() 8 | { 9 | 10 | } 11 | 12 | virtual ~CCanvas() { }; 13 | 14 | protected: 15 | // Override default signal handler: 16 | bool on_draw(const Cairo::RefPtr& cr) override; 17 | 18 | }; // CCanvas 19 | -------------------------------------------------------------------------------- /3-a-total-line/canvas.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class CCanvas : public Gtk::DrawingArea 5 | { 6 | public: 7 | CCanvas() 8 | { 9 | 10 | } 11 | 12 | virtual ~CCanvas() { }; 13 | 14 | protected: 15 | // Override default signal handler: 16 | bool on_draw(const Cairo::RefPtr& cr) override; 17 | 18 | }; // CCanvas 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # The binaries 2 | CairoTut-?-* 3 | 4 | # Prerequisites 5 | *.d 6 | 7 | # Compiled Object files 8 | *.slo 9 | *.lo 10 | *.o 11 | *.obj 12 | 13 | # Precompiled Headers 14 | *.gch 15 | *.pch 16 | 17 | # Compiled Dynamic libraries 18 | *.so 19 | *.dylib 20 | *.dll 21 | 22 | # Fortran module files 23 | *.mod 24 | *.smod 25 | 26 | # Compiled Static libraries 27 | *.lai 28 | *.la 29 | *.a 30 | *.lib 31 | 32 | # Executables 33 | *.exe 34 | *.out 35 | *.app 36 | -------------------------------------------------------------------------------- /9-shift/main.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | #include 3 | #include 4 | 5 | 6 | int main(int argc, char** argv) 7 | { 8 | auto app = Gtk::Application::create(argc, argv, "org.gtkmm.cairo.tut"); 9 | 10 | Gtk::Window window; 11 | window.resize(800,600); 12 | window.set_title("Cairo tutorial C++"); 13 | 14 | CCanvas area; 15 | window.add(area); 16 | area.show(); 17 | 18 | return app->run(window); 19 | } 20 | 21 | -------------------------------------------------------------------------------- /d-text/main.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | #include 3 | #include 4 | 5 | 6 | int main(int argc, char** argv) 7 | { 8 | auto app = Gtk::Application::create(argc, argv, "org.gtkmm.cairo.tut"); 9 | 10 | Gtk::Window window; 11 | window.resize(800,600); 12 | window.set_title("Cairo tutorial C++"); 13 | 14 | CCanvas area; 15 | window.add(area); 16 | area.show(); 17 | 18 | return app->run(window); 19 | } 20 | 21 | -------------------------------------------------------------------------------- /2-a-red-line/main.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | #include 3 | #include 4 | 5 | 6 | int main(int argc, char** argv) 7 | { 8 | auto app = Gtk::Application::create(argc, argv, "org.gtkmm.cairo.tut"); 9 | 10 | Gtk::Window window; 11 | window.resize(800,600); 12 | window.set_title("Cairo tutorial C++"); 13 | 14 | CCanvas area; 15 | window.add(area); 16 | area.show(); 17 | 18 | return app->run(window); 19 | } 20 | 21 | -------------------------------------------------------------------------------- /4-picture-png/main.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | #include 3 | #include 4 | 5 | 6 | int main(int argc, char** argv) 7 | { 8 | auto app = Gtk::Application::create(argc, argv, "org.gtkmm.cairo.tut"); 9 | 10 | Gtk::Window window; 11 | window.resize(800,600); 12 | window.set_title("Cairo tutorial C++"); 13 | 14 | CCanvas area; 15 | window.add(area); 16 | area.show(); 17 | 18 | return app->run(window); 19 | } 20 | 21 | -------------------------------------------------------------------------------- /5-picture-svg/main.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | #include 3 | #include 4 | 5 | 6 | int main(int argc, char** argv) 7 | { 8 | auto app = Gtk::Application::create(argc, argv, "org.gtkmm.cairo.tut"); 9 | 10 | Gtk::Window window; 11 | window.resize(800,600); 12 | window.set_title("Cairo tutorial C++"); 13 | 14 | CCanvas area; 15 | window.add(area); 16 | area.show(); 17 | 18 | return app->run(window); 19 | } 20 | 21 | -------------------------------------------------------------------------------- /8-collision/main.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | #include 3 | #include 4 | 5 | 6 | int main(int argc, char** argv) 7 | { 8 | auto app = Gtk::Application::create(argc, argv, "org.gtkmm.cairo.tut"); 9 | 10 | Gtk::Window window; 11 | window.resize(800,600); 12 | window.set_title("Cairo tutorial C++"); 13 | 14 | CCanvas area; 15 | window.add(area); 16 | area.show(); 17 | 18 | return app->run(window); 19 | } 20 | 21 | -------------------------------------------------------------------------------- /a-shift+move/main.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | #include 3 | #include 4 | 5 | 6 | int main(int argc, char** argv) 7 | { 8 | auto app = Gtk::Application::create(argc, argv, "org.gtkmm.cairo.tut"); 9 | 10 | Gtk::Window window; 11 | window.resize(800,600); 12 | window.set_title("Cairo tutorial C++"); 13 | 14 | CCanvas area; 15 | window.add(area); 16 | area.show(); 17 | 18 | return app->run(window); 19 | } 20 | 21 | -------------------------------------------------------------------------------- /c-animation/main.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | #include 3 | #include 4 | 5 | 6 | int main(int argc, char** argv) 7 | { 8 | auto app = Gtk::Application::create(argc, argv, "org.gtkmm.cairo.tut"); 9 | 10 | Gtk::Window window; 11 | window.resize(800,600); 12 | window.set_title("Cairo tutorial C++"); 13 | 14 | CCanvas area; 15 | window.add(area); 16 | area.show(); 17 | 18 | return app->run(window); 19 | } 20 | 21 | -------------------------------------------------------------------------------- /g-app-draw/main.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | #include 3 | #include 4 | 5 | 6 | int main(int argc, char** argv) 7 | { 8 | auto app = Gtk::Application::create(argc, argv, "org.gtkmm.cairo.tut"); 9 | 10 | Gtk::Window window; 11 | window.resize(800,600); 12 | window.set_title("Cairo tutorial C++"); 13 | 14 | CCanvas area; 15 | window.add(area); 16 | area.show(); 17 | 18 | return app->run(window); 19 | } 20 | 21 | -------------------------------------------------------------------------------- /3-a-total-line/main.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | #include 3 | #include 4 | 5 | 6 | int main(int argc, char** argv) 7 | { 8 | auto app = Gtk::Application::create(argc, argv, "org.gtkmm.cairo.tut"); 9 | 10 | Gtk::Window window; 11 | window.resize(800,600); 12 | window.set_title("Cairo tutorial C++"); 13 | 14 | CCanvas area; 15 | window.add(area); 16 | area.show(); 17 | 18 | return app->run(window); 19 | } 20 | 21 | -------------------------------------------------------------------------------- /6-mouse-position/main.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | #include 3 | #include 4 | 5 | 6 | int main(int argc, char** argv) 7 | { 8 | auto app = Gtk::Application::create(argc, argv, "org.gtkmm.cairo.tut"); 9 | 10 | Gtk::Window window; 11 | window.resize(800,600); 12 | window.set_title("Cairo tutorial C++"); 13 | 14 | CCanvas area; 15 | window.add(area); 16 | area.show(); 17 | 18 | return app->run(window); 19 | } 20 | 21 | -------------------------------------------------------------------------------- /7-mouse-complete/main.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | #include 3 | #include 4 | 5 | 6 | int main(int argc, char** argv) 7 | { 8 | auto app = Gtk::Application::create(argc, argv, "org.gtkmm.cairo.tut"); 9 | 10 | Gtk::Window window; 11 | window.resize(800,600); 12 | window.set_title("Cairo tutorial C++"); 13 | 14 | CCanvas area; 15 | window.add(area); 16 | area.show(); 17 | 18 | return app->run(window); 19 | } 20 | 21 | -------------------------------------------------------------------------------- /b-shift+zoom+move/main.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | #include 3 | #include 4 | 5 | 6 | int main(int argc, char** argv) 7 | { 8 | auto app = Gtk::Application::create(argc, argv, "org.gtkmm.cairo.tut"); 9 | 10 | Gtk::Window window; 11 | window.resize(800,600); 12 | window.set_title("Cairo tutorial C++"); 13 | 14 | CCanvas area; 15 | window.add(area); 16 | area.show(); 17 | 18 | return app->run(window); 19 | } 20 | 21 | -------------------------------------------------------------------------------- /e-ui-button-bar/main.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | #include 3 | #include 4 | 5 | 6 | int main(int argc, char** argv) 7 | { 8 | auto app = Gtk::Application::create(argc, argv, "org.gtkmm.cairo.tut"); 9 | 10 | Gtk::Window window; 11 | window.resize(800,600); 12 | window.set_title("Cairo tutorial C++"); 13 | 14 | CCanvas area; 15 | window.add(area); 16 | area.show(); 17 | 18 | return app->run(window); 19 | } 20 | 21 | -------------------------------------------------------------------------------- /f-drawing-helpers/main.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | #include 3 | #include 4 | 5 | 6 | int main(int argc, char** argv) 7 | { 8 | auto app = Gtk::Application::create(argc, argv, "org.gtkmm.cairo.tut"); 9 | 10 | Gtk::Window window; 11 | window.resize(800,600); 12 | window.set_title("Cairo tutorial C++"); 13 | 14 | CCanvas area; 15 | window.add(area); 16 | area.show(); 17 | 18 | return app->run(window); 19 | } 20 | 21 | -------------------------------------------------------------------------------- /1-empty-cairo-program/main.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | #include 3 | #include 4 | 5 | 6 | int main(int argc, char** argv) 7 | { 8 | auto app = Gtk::Application::create(argc, argv, "org.gtkmm.cairo.tut"); 9 | 10 | Gtk::Window window; 11 | window.resize(800,600); 12 | window.set_title("Cairo tutorial C++"); 13 | 14 | CCanvas area; 15 | window.add(area); 16 | area.show(); 17 | 18 | return app->run(window); 19 | } 20 | 21 | -------------------------------------------------------------------------------- /k-like-cad/main.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | #include 3 | #include 4 | 5 | 6 | int main(int argc, char** argv) 7 | { 8 | auto app = Gtk::Application::create(argc, argv, "org.gtkmm.cairo.tut"); 9 | 10 | Gtk::Window window; 11 | window.resize(800,600); 12 | // window.fullscreen(); 13 | window.set_title("Cairo tutorial C++"); 14 | 15 | CCanvas area; 16 | window.add(area); 17 | area.show(); 18 | 19 | return app->run(window); 20 | } 21 | 22 | -------------------------------------------------------------------------------- /o-breakout/main.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | #include 3 | #include 4 | 5 | 6 | int main(int argc, char** argv) 7 | { 8 | auto app = Gtk::Application::create(argc, argv, "org.gtkmm.cairo.tut"); 9 | 10 | Gtk::Window window; 11 | // window.resize(800,600); 12 | window.fullscreen(); 13 | window.set_title("Cairo tutorial C++"); 14 | 15 | CCanvas area; 16 | window.add(area); 17 | area.show(); 18 | 19 | return app->run(window); 20 | } 21 | 22 | -------------------------------------------------------------------------------- /h-3-lagen-synthese/main.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | #include 3 | #include 4 | 5 | 6 | int main(int argc, char** argv) 7 | { 8 | auto app = Gtk::Application::create(argc, argv, "org.gtkmm.cairo.tut"); 9 | 10 | Gtk::Window window; 11 | window.resize(800,600); 12 | // window.fullscreen(); 13 | window.set_title("Cairo tutorial C++"); 14 | 15 | CCanvas area; 16 | window.add(area); 17 | area.show(); 18 | 19 | return app->run(window); 20 | } 21 | 22 | -------------------------------------------------------------------------------- /i-4-bar-analytics/main.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | #include 3 | #include 4 | 5 | 6 | int main(int argc, char** argv) 7 | { 8 | auto app = Gtk::Application::create(argc, argv, "org.gtkmm.cairo.tut"); 9 | 10 | Gtk::Window window; 11 | window.resize(800,600); 12 | // window.fullscreen(); 13 | window.set_title("Cairo tutorial C++"); 14 | 15 | CCanvas area; 16 | window.add(area); 17 | area.show(); 18 | 19 | return app->run(window); 20 | } 21 | 22 | -------------------------------------------------------------------------------- /m-mass-animation/main.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | #include 3 | #include 4 | 5 | 6 | int main(int argc, char** argv) 7 | { 8 | auto app = Gtk::Application::create(argc, argv, "org.gtkmm.cairo.tut"); 9 | 10 | Gtk::Window window; 11 | // window.resize(800,600); 12 | window.fullscreen(); 13 | window.set_title("Cairo tutorial C++"); 14 | 15 | CCanvas area; 16 | window.add(area); 17 | area.show(); 18 | 19 | return app->run(window); 20 | } 21 | 22 | -------------------------------------------------------------------------------- /3-a-total-line/canvas.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | 3 | 4 | 5 | 6 | 7 | 8 | bool CCanvas::on_draw(Cairo::RefPtr const & cr) 9 | { 10 | Gtk::Allocation allocation{ get_allocation() }; 11 | auto const width { (double)allocation.get_width() }; 12 | auto const height{ (double)allocation.get_height() }; 13 | 14 | cr->set_source_rgb(1.,.5,.0); 15 | cr->set_line_width(3); 16 | 17 | // line crossing the whole window 18 | cr->move_to( 0, 0); 19 | cr->line_to(width, height); 20 | cr->stroke(); 21 | 22 | // circle gray 23 | cr->set_source_rgb(.7,.7,.7); 24 | cr->arc(width/2, height/2, 100, 0, 2*M_PI); 25 | cr->fill(); 26 | 27 | return true; 28 | } 29 | -------------------------------------------------------------------------------- /6-mouse-position/canvas.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct SPoint 5 | { 6 | SPoint() = default; 7 | SPoint(double const & x, double const & y) : x(x), y(y) {} 8 | template 9 | SPoint(T const & t) : x(t.x), y(t.y) {} 10 | double x{0}, y{0}; 11 | }; 12 | 13 | class CCanvas : public Gtk::DrawingArea 14 | { 15 | public: 16 | CCanvas() 17 | { 18 | add_events(Gdk::BUTTON1_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK); 19 | } 20 | 21 | virtual ~CCanvas() { }; 22 | 23 | protected: 24 | // Override default signal handler: 25 | bool on_draw(const Cairo::RefPtr& cr) override; 26 | bool on_motion_notify_event(GdkEventMotion *event) override; 27 | 28 | SPoint m_tMousePos; 29 | 30 | 31 | }; // CCanvas 32 | -------------------------------------------------------------------------------- /4-picture-png/canvas.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | 3 | 4 | 5 | 6 | 7 | 8 | bool CCanvas::on_draw(Cairo::RefPtr const & cr) 9 | { 10 | Gtk::Allocation allocation{ get_allocation() }; 11 | auto const width { (double)allocation.get_width() }; 12 | auto const height{ (double)allocation.get_height() }; 13 | 14 | cr->set_source_rgb(1.,.5,.0); 15 | cr->set_line_width(3); 16 | 17 | // line crossing the whole window 18 | cr->move_to( 0, 0); 19 | cr->line_to(width, height); 20 | cr->stroke(); 21 | 22 | // circle gray 23 | cr->set_source_rgb(.7,.7,.7); 24 | cr->arc(width/2, height/2, 100, 0, 2*M_PI); 25 | cr->fill(); 26 | 27 | // picture png quadratic 28 | // - load picture 29 | static Glib::RefPtr const image = Gdk::Pixbuf::create_from_file("../CairoTut.png"); 30 | // - scale picture to destination size 31 | static Glib::RefPtr imageS = image->scale_simple( 180, 180, Gdk::INTERP_BILINEAR); 32 | // - place scaled pictures to specified position in render context 33 | Gdk::Cairo::set_source_pixbuf(cr, imageS, width/2-90, height/2-90 ); 34 | // - open a hole for the pixels 35 | cr->rectangle( width/2-90, height/2-90, 180, 180 ); 36 | // - show the hole 37 | cr->fill(); 38 | 39 | return true; 40 | } 41 | -------------------------------------------------------------------------------- /5-picture-svg/canvas.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | 3 | 4 | 5 | 6 | 7 | 8 | bool CCanvas::on_draw(Cairo::RefPtr const & cr) 9 | { 10 | Gtk::Allocation allocation{ get_allocation() }; 11 | auto const width { (double)allocation.get_width() }; 12 | auto const height{ (double)allocation.get_height() }; 13 | 14 | cr->set_source_rgb(1.,.5,.0); 15 | cr->set_line_width(3); 16 | 17 | // line crossing the whole window 18 | cr->move_to( 0, 0); 19 | cr->line_to(width, height); 20 | cr->stroke(); 21 | 22 | // circle gray 23 | cr->set_source_rgb(.7,.7,.7); 24 | cr->arc(width/2, height/2, 100, 0, 2*M_PI); 25 | cr->fill(); 26 | 27 | // picture svg quadratic 28 | // - load picture 29 | static Glib::RefPtr const image = Gdk::Pixbuf::create_from_file("../CairoTut.svg"); 30 | // - scale picture to destination size 31 | static Glib::RefPtr imageS = image->scale_simple( 180, 180, Gdk::INTERP_BILINEAR); 32 | // - place scaled pictures to specified position in render context 33 | Gdk::Cairo::set_source_pixbuf(cr, imageS, width/2-90, height/2-90 ); 34 | // - open a hole for the pixels 35 | cr->rectangle( width/2-90, height/2-90, 180, 180 ); 36 | // - show the hole 37 | cr->fill(); 38 | 39 | return true; 40 | } 41 | -------------------------------------------------------------------------------- /7-mouse-complete/canvas.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | 3 | 4 | 5 | 6 | 7 | 8 | bool CCanvas::on_button_press_event(GdkEventButton *event) 9 | { 10 | m_tMouseColor = { .0,.0,.9 }; 11 | 12 | queue_draw(); 13 | return true; 14 | } 15 | 16 | bool CCanvas::on_motion_notify_event(GdkEventMotion *event) 17 | { 18 | m_tMousePos = SPoint{*event}; 19 | 20 | queue_draw(); 21 | return true; 22 | } 23 | 24 | bool CCanvas::on_button_release_event(GdkEventButton* event) 25 | { 26 | m_tMouseColor = { .5,.5,.5 }; 27 | m_vMouseTrail.emplace_back( SPoint{ *event } ); 28 | 29 | queue_draw(); 30 | return true; 31 | } 32 | 33 | bool CCanvas::on_scroll_event(GdkEventScroll *event) 34 | { 35 | if ( event->delta_y>0 ) 36 | m_tMouseColor = { .9,.0,.0 }; 37 | else 38 | m_tMouseColor = { .0,.9,.0 }; 39 | 40 | queue_draw(); 41 | return true; 42 | } 43 | 44 | bool CCanvas::on_draw(Cairo::RefPtr const & cr) 45 | { 46 | cr->set_source_rgb( .0,.0,.0 ); 47 | cr->set_line_width(3); 48 | if ( m_vMouseTrail.size() ) 49 | { 50 | cr->move_to(m_vMouseTrail[0].x,m_vMouseTrail[0].y); 51 | for (auto const & a:m_vMouseTrail) 52 | { 53 | cr->line_to( a.x, a.y); 54 | } 55 | cr->stroke(); 56 | } 57 | 58 | cr->set_source_rgb( m_tMouseColor.r, m_tMouseColor.b, m_tMouseColor.b ); 59 | cr->arc(m_tMousePos.x, m_tMousePos.y, 11, 0, 2*M_PI); 60 | cr->fill(); 61 | 62 | return true; 63 | } 64 | -------------------------------------------------------------------------------- /7-mouse-complete/canvas.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | 7 | struct SPoint 8 | { 9 | SPoint() = default; 10 | SPoint(double const & x, double const & y) : x(x), y(y) {} 11 | template 12 | SPoint(T const & t) : x(t.x), y(t.y) {} 13 | double x{0}, y{0}; 14 | }; 15 | 16 | struct SColor 17 | { 18 | double r{0},g{0},b{0}; 19 | }; 20 | 21 | using VPoints = std::vector; 22 | 23 | class CCanvas : public Gtk::DrawingArea 24 | { 25 | public: 26 | CCanvas() 27 | { 28 | add_events(Gdk::BUTTON_PRESS_MASK | Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK); 29 | add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK); 30 | add_events(Gdk::BUTTON1_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK); 31 | add_events(Gdk::KEY_PRESS_MASK | Gdk::KEY_RELEASE_MASK); 32 | } 33 | 34 | virtual ~CCanvas() { }; 35 | 36 | protected: 37 | // Override default signal handler: 38 | bool on_draw(const Cairo::RefPtr& cr) override; 39 | bool on_scroll_event(GdkEventScroll *event) override; 40 | bool on_button_press_event(GdkEventButton * event) override; 41 | bool on_motion_notify_event(GdkEventMotion *event) override; 42 | bool on_button_release_event(GdkEventButton* release_event) override; 43 | 44 | SPoint m_tMousePos; 45 | SColor m_tMouseColor{ .5,.5,.5 }; 46 | VPoints m_vMouseTrail; 47 | 48 | 49 | }; // CCanvas 50 | -------------------------------------------------------------------------------- /6-mouse-position/canvas.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | 3 | 4 | 5 | 6 | 7 | 8 | bool CCanvas::on_motion_notify_event(GdkEventMotion *event) 9 | { 10 | m_tMousePos = SPoint{*event}; 11 | queue_draw(); 12 | return true; 13 | } 14 | 15 | bool CCanvas::on_draw(Cairo::RefPtr const & cr) 16 | { 17 | Gtk::Allocation allocation{ get_allocation() }; 18 | auto const width { (double)allocation.get_width() }; 19 | auto const height{ (double)allocation.get_height() }; 20 | 21 | cr->set_source_rgb(1.,.5,.0); 22 | cr->set_line_width(3); 23 | 24 | // line crossing the whole window 25 | cr->move_to( 0, 0); 26 | cr->line_to(width, height); 27 | cr->stroke(); 28 | 29 | // circle gray 30 | cr->set_source_rgb(.7,.7,.0); 31 | cr->arc(width/2, height/2, 100, 0, 2*M_PI); 32 | cr->fill(); 33 | 34 | // picture png quadratic 35 | // - load picture 36 | static Glib::RefPtr const image = Gdk::Pixbuf::create_from_file("../CairoTut.svg"); 37 | // - scale picture to destination size 38 | static Glib::RefPtr imageS = image->scale_simple( 180, 180, Gdk::INTERP_BILINEAR); 39 | // - place scaled pictures to specified position in render context 40 | Gdk::Cairo::set_source_pixbuf(cr, imageS, width/2-90, height/2-90 ); 41 | // - open a hole for the pixels 42 | cr->rectangle( width/2-90, height/2-90, 180, 180 ); 43 | // - show the hole 44 | cr->fill(); 45 | 46 | // draw a blue circle at last mouse position 47 | cr->set_source_rgb(.0,.0,.9); 48 | cr->arc(m_tMousePos.x, m_tMousePos.y, 3, 0, 2*M_PI); 49 | cr->fill(); 50 | 51 | return true; 52 | } 53 | -------------------------------------------------------------------------------- /8-collision/canvas.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | 7 | struct SPoint 8 | { 9 | SPoint() = default; 10 | SPoint(double const & x, double const & y) : x(x), y(y) {} 11 | template 12 | SPoint(T const & t) : x(t.x), y(t.y) {} 13 | double x{0}, y{0}; 14 | }; 15 | 16 | struct SFleck 17 | { 18 | double x{0}, y{0}, r{0}; 19 | }; 20 | 21 | struct SColor 22 | { 23 | double r{0},g{0},b{0}; 24 | }; 25 | 26 | using VPoints = std::vector; 27 | using VFlecken = std::vector; 28 | 29 | // the first argument can be anything having the members x and y 30 | // a Gtk event, a SFleck or whatever 31 | template 32 | double Distance( P const & a, SPoint const & b ) 33 | { 34 | return sqrt( pow((a.x-b.x),2) + pow((a.y-b.y),2) ); 35 | } 36 | 37 | 38 | class CCanvas : public Gtk::DrawingArea 39 | { 40 | public: 41 | CCanvas() 42 | { 43 | add_events(Gdk::BUTTON_PRESS_MASK | Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK); 44 | add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK); 45 | add_events(Gdk::BUTTON1_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK); 46 | add_events(Gdk::KEY_PRESS_MASK | Gdk::KEY_RELEASE_MASK); 47 | } 48 | 49 | virtual ~CCanvas() { }; 50 | 51 | protected: 52 | // Override default signal handler: 53 | bool on_draw(const Cairo::RefPtr& cr) override; 54 | bool on_scroll_event(GdkEventScroll *event) override; 55 | bool on_button_press_event(GdkEventButton * event) override; 56 | bool on_motion_notify_event(GdkEventMotion *event) override; 57 | bool on_button_release_event(GdkEventButton* release_event) override; 58 | 59 | int Collision(SPoint const & tPoint); 60 | 61 | SPoint m_tMousePos; 62 | SColor m_tMouseColor{ .5,.5,.5 }; 63 | VPoints m_vMouseTrail; 64 | VFlecken m_vFlecken { {30,30,20}, {300,300,50}, {500,200,40} }; 65 | 66 | }; // CCanvas 67 | -------------------------------------------------------------------------------- /i-4-bar-analytics/4bar.h: -------------------------------------------------------------------------------- 1 | #ifndef A4BAR_H 2 | #define A4BAR_H 3 | 4 | #include 5 | 6 | #include 7 | 8 | #include "canvas.h" 9 | 10 | 11 | 12 | 13 | 14 | int constexpr D_OK {0}; 15 | int constexpr D2LONG {1}; 16 | int constexpr D2SHORT {2}; 17 | struct SPointT 18 | { 19 | double x{.0}, y{.0}; 20 | int nSplit{D_OK}; 21 | }; 22 | using VSpur = std::vector; 23 | 24 | 25 | struct C4Bar 26 | { 27 | int m_nSplit{D_OK}; 28 | 29 | bool m_bWithTraces { false }; 30 | bool m_bDurchschlagen{ true }; 31 | bool m_bShowText { true }; 32 | bool m_bShowHints { true }; 33 | bool m_bShowBlink { true }; 34 | bool m_bShowMouse { true }; 35 | 36 | bool m_bCalculate { true }; 37 | 38 | 39 | double m_tAnimStep { 0.0 }; 40 | 41 | void TraceReset() { m_vSpurE1.clear(); m_vSpurE2.clear(); m_tAnimStep = 0; } 42 | void TraceInvrt() { m_bWithTraces = !m_bWithTraces; TraceReset(); } 43 | void Durchschlagen() { m_bDurchschlagen = !m_bDurchschlagen; TraceReset(); } 44 | void Rotate() { } 45 | void WithText() { m_bShowText = !m_bShowText; } 46 | void WithHints() { m_bShowHints = !m_bShowHints; } 47 | void WithBlink() { m_bShowBlink = !m_bShowBlink; } 48 | void WithMouse() { m_bShowMouse = !m_bShowMouse; } 49 | 50 | 51 | bool m_bAnimReverse{false}; 52 | SPoint A0{-100, 0},A1{-100,-100}, A1m{A1}, 53 | B0{ 100, 0},B1{ 100,-150}, B1m{B1}; 54 | VSpur m_vSpurE1; 55 | VSpur m_vSpurE2; 56 | 57 | void Show(CairoCtx cr, double const & dScale); 58 | 59 | CCanvas::SCollision Collision(SPoint const & tPoint); 60 | bool MoveObject(CCanvas::SCollision const & tCollision, SPoint const & pos); 61 | void CalcGetriebe(CairoCtx cr, double const & ani, double const & dAni); 62 | 63 | 64 | void DrawGehausePunkt (CairoCtx cr, SPoint const & G0, 65 | std::string const & t); 66 | void DrawGetriebe(CairoCtx cr, double const & ani, double const & dAni); 67 | 68 | }; // struct C4Bar 69 | 70 | // A4BAR_H 71 | #endif 72 | -------------------------------------------------------------------------------- /8-collision/canvas.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | 3 | 4 | 5 | 6 | 7 | 8 | int CCanvas::Collision(SPoint const & tPoint) 9 | { 10 | int i{0}; 11 | for ( auto & a:m_vFlecken ) 12 | { 13 | if ( Distance(a, tPoint) < a.r ) 14 | { 15 | return std::move(i); 16 | } 17 | ++i; 18 | } 19 | return -1; 20 | } 21 | 22 | 23 | bool CCanvas::on_button_press_event(GdkEventButton *event) 24 | { 25 | m_tMouseColor = { .0,.0,.9 }; 26 | 27 | queue_draw(); 28 | return true; 29 | } 30 | 31 | bool CCanvas::on_motion_notify_event(GdkEventMotion *event) 32 | { 33 | m_tMousePos = SPoint{*event}; 34 | 35 | queue_draw(); 36 | return true; 37 | } 38 | 39 | bool CCanvas::on_button_release_event(GdkEventButton* event) 40 | { 41 | m_tMouseColor = { .5,.5,.5 }; 42 | m_vMouseTrail.emplace_back( SPoint{ *event } ); 43 | 44 | queue_draw(); 45 | return true; 46 | } 47 | 48 | bool CCanvas::on_scroll_event(GdkEventScroll *event) 49 | { 50 | if ( event->delta_y>0 ) 51 | m_tMouseColor = { .9,.0,.0 }; 52 | else 53 | m_tMouseColor = { .0,.9,.0 }; 54 | 55 | queue_draw(); 56 | return true; 57 | } 58 | 59 | bool CCanvas::on_draw(Cairo::RefPtr const & cr) 60 | { 61 | cr->set_source_rgb( .0,.0,.0 ); 62 | cr->set_line_width(3); 63 | if ( m_vMouseTrail.size() ) 64 | { 65 | cr->move_to(m_vMouseTrail[0].x,m_vMouseTrail[0].y); 66 | for (auto const & a:m_vMouseTrail) 67 | { 68 | cr->line_to( a.x, a.y); 69 | } 70 | cr->stroke(); 71 | } 72 | 73 | auto const ic{Collision(m_tMousePos)}; 74 | int i{0}; 75 | for ( auto const & a:m_vFlecken ) 76 | { 77 | if ( ic == i++ ) 78 | cr->set_source_rgb( .9, .0, .0 ); 79 | else 80 | cr->set_source_rgb( .0, .9, .0 ); 81 | cr->arc(a.x, a.y, a.r, 0, 2*M_PI); 82 | cr->fill(); 83 | } 84 | 85 | 86 | cr->set_source_rgb( m_tMouseColor.r, m_tMouseColor.b, m_tMouseColor.b ); 87 | cr->arc(m_tMousePos.x, m_tMousePos.y, 11, 0, 2*M_PI); 88 | cr->fill(); 89 | 90 | return true; 91 | } 92 | -------------------------------------------------------------------------------- /9-shift/canvas.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | 7 | struct SPoint 8 | { 9 | SPoint() = default; 10 | SPoint(double const & x, double const & y) : x(x), y(y) {} 11 | template 12 | SPoint(T const & t) : x(t.x), y(t.y) {} 13 | double x{0}, y{0}; 14 | SPoint operator -= (SPoint const & p) 15 | { 16 | x -= p.x; 17 | y -= p.y; 18 | return *this; 19 | } 20 | SPoint operator += (SPoint const & p) 21 | { 22 | x += p.x; 23 | y += p.y; 24 | return *this; 25 | } 26 | }; 27 | 28 | inline bool operator == (SPoint const & p1, SPoint const & p2) 29 | { 30 | return (p1.x==p2.x) && (p1.y==p2.y); 31 | } 32 | 33 | inline bool operator != (SPoint const & p1, SPoint const & p2) 34 | { 35 | return !(p1==p2); 36 | } 37 | 38 | inline SPoint operator - (SPoint const & p1, SPoint const & p2) 39 | { 40 | return {p1.x-p2.x, p1.y-p2.y}; 41 | } 42 | 43 | inline SPoint operator + (SPoint const & p1, SPoint const & p2) 44 | { 45 | return {p2.x+p1.x, p2.y+p1.y}; 46 | } 47 | 48 | inline SPoint operator / (SPoint const & p, double const & d) 49 | { 50 | return {p.x/d, p.y/d}; 51 | } 52 | 53 | inline SPoint operator * (SPoint const & p, double const & d) 54 | { 55 | return {p.x*d, p.y*d}; 56 | } 57 | 58 | 59 | struct SFleck 60 | { 61 | double x{0}, y{0}, r{0}; 62 | }; 63 | 64 | struct SColor 65 | { 66 | double r{0},g{0},b{0}; 67 | }; 68 | 69 | using VPoints = std::vector; 70 | using VFlecken = std::vector; 71 | 72 | // the first argument can be anything having the members x and y 73 | // a Gtk event, a SFleck or whatever 74 | template 75 | double Distance( P const & a, SPoint const & b ) 76 | { 77 | return sqrt( pow((a.x-b.x),2) + pow((a.y-b.y),2) ); 78 | } 79 | 80 | 81 | class CCanvas : public Gtk::DrawingArea 82 | { 83 | public: 84 | CCanvas() 85 | { 86 | add_events(Gdk::BUTTON_PRESS_MASK | Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK); 87 | add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK); 88 | add_events(Gdk::BUTTON1_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK); 89 | add_events(Gdk::KEY_PRESS_MASK | Gdk::KEY_RELEASE_MASK); 90 | } 91 | 92 | virtual ~CCanvas() { }; 93 | 94 | protected: 95 | // Override default signal handler: 96 | bool on_draw(const Cairo::RefPtr& cr) override; 97 | bool on_scroll_event(GdkEventScroll *event) override; 98 | bool on_button_press_event(GdkEventButton * event) override; 99 | bool on_motion_notify_event(GdkEventMotion *event) override; 100 | bool on_button_release_event(GdkEventButton* release_event) override; 101 | 102 | int Collision(SPoint const & tPoint); 103 | 104 | bool m_bShiftInit { true }; 105 | SPoint m_tShift { .0,.0 }; 106 | SPoint m_tEventPress { .0,.0 }; 107 | 108 | SPoint m_tShiftStart { .0,.0 }; 109 | 110 | 111 | SPoint m_tMousePos; 112 | SColor m_tMouseColor{ .5,.5,.5 }; 113 | VPoints m_vMouseTrail; 114 | VFlecken m_vFlecken { {30,30,20}, {300,300,50}, {500,200,40} }; 115 | 116 | }; // CCanvas 117 | -------------------------------------------------------------------------------- /9-shift/canvas.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | 3 | 4 | 5 | 6 | 7 | 8 | int CCanvas::Collision(SPoint const & tPoint) 9 | { 10 | int i{0}; 11 | for ( auto & a:m_vFlecken ) 12 | { 13 | if ( Distance(a, tPoint) < a.r ) 14 | { 15 | return std::move(i); 16 | } 17 | ++i; 18 | } 19 | return -1; 20 | } 21 | 22 | 23 | bool CCanvas::on_button_press_event(GdkEventButton *event) 24 | { 25 | m_tMouseColor = { .0,.0,.9 }; 26 | if (event->type == GDK_BUTTON_PRESS ) 27 | { 28 | m_tEventPress = *event; 29 | m_tShiftStart = m_tShift; 30 | } 31 | 32 | queue_draw(); 33 | return true; 34 | } 35 | 36 | bool CCanvas::on_motion_notify_event(GdkEventMotion *event) 37 | { 38 | m_tMousePos = *event - m_tShift; 39 | 40 | if ( event->type & GDK_MOTION_NOTIFY ) 41 | if ( event->state & GDK_BUTTON3_MASK ) 42 | { 43 | m_tShift = m_tShiftStart - (m_tEventPress - *event); 44 | } 45 | 46 | queue_draw(); 47 | return true; 48 | } 49 | 50 | bool CCanvas::on_button_release_event(GdkEventButton* event) 51 | { 52 | if ( event->type & GDK_MOTION_NOTIFY ) 53 | if ( event->state & GDK_BUTTON1_MASK ) 54 | { 55 | m_tMouseColor = { .5,.5,.5 }; 56 | m_vMouseTrail.emplace_back( SPoint{ *event - m_tShift } ); 57 | } 58 | if ( event->state & GDK_BUTTON3_MASK ) 59 | { 60 | } 61 | 62 | queue_draw(); 63 | return true; 64 | } 65 | 66 | bool CCanvas::on_scroll_event(GdkEventScroll *event) 67 | { 68 | if ( event->delta_y>0 ) 69 | m_tMouseColor = { .9,.0,.0 }; 70 | else 71 | m_tMouseColor = { .0,.9,.0 }; 72 | 73 | queue_draw(); 74 | return true; 75 | } 76 | 77 | bool CCanvas::on_draw(Cairo::RefPtr const & cr) 78 | { 79 | auto const all { get_allocation() }; 80 | auto const m_tCtxSize { SPoint { (double)all.get_width(), 81 | (double)all.get_height() } }; 82 | 83 | static auto tHome{ SPoint { m_tCtxSize }/2 }; 84 | 85 | if ( m_bShiftInit ) 86 | { 87 | tHome = m_tShift = m_tCtxSize/2; 88 | m_bShiftInit = false; 89 | } 90 | auto const tSizeHalf{m_tCtxSize/2}; 91 | if ( tHome != tSizeHalf ) 92 | { 93 | m_tShift -= tHome - tSizeHalf; tHome = tSizeHalf; 94 | } 95 | 96 | Cairo::Matrix matrix(1.0, 0.0, 0.0, 1.0, 0.0, 0.0); 97 | matrix.translate(m_tShift.x, m_tShift.y); 98 | 99 | cr->transform(matrix); 100 | 101 | 102 | 103 | cr->set_source_rgb( .0,.0,.0 ); 104 | cr->set_line_width(3); 105 | if ( m_vMouseTrail.size() ) 106 | { 107 | cr->move_to(m_vMouseTrail[0].x,m_vMouseTrail[0].y); 108 | for (auto const & a:m_vMouseTrail) 109 | { 110 | cr->line_to( a.x, a.y); 111 | } 112 | cr->stroke(); 113 | } 114 | 115 | auto const ic{Collision(m_tMousePos)}; 116 | int i{0}; 117 | for ( auto const & a:m_vFlecken ) 118 | { 119 | if ( ic == i++ ) 120 | cr->set_source_rgb( .9, .0, .0 ); 121 | else 122 | cr->set_source_rgb( .0, .9, .0 ); 123 | cr->arc(a.x, a.y, a.r, 0, 2*M_PI); 124 | cr->fill(); 125 | } 126 | 127 | 128 | cr->set_source_rgb( m_tMouseColor.r, m_tMouseColor.b, m_tMouseColor.b ); 129 | cr->arc(m_tMousePos.x, m_tMousePos.y, 11, 0, 2*M_PI); 130 | cr->fill(); 131 | 132 | return true; 133 | } 134 | -------------------------------------------------------------------------------- /h-3-lagen-synthese/3lagen.h: -------------------------------------------------------------------------------- 1 | #ifndef L3LAGEN_H 2 | #define L3LAGEN_H 3 | 4 | #include 5 | 6 | #include 7 | 8 | #include "canvas.h" 9 | 10 | 11 | using SGrundPunkt = SPoint; 12 | using SGehausePunkt = SPoint; 13 | using SGelenkPunkt = SPoint; 14 | using SPolPunkt = SPoint; 15 | 16 | using VGrundPunkte = std::vector; 17 | using VGelenkPunkte = std::vector; 18 | using VPolDreieck = std::vector; 19 | using VEbenen = std::vector; 20 | 21 | 22 | int constexpr D_OK {0}; 23 | int constexpr D2LONG {1}; 24 | int constexpr D2SHORT {2}; 25 | struct SPointT 26 | { 27 | double x{.0}, y{.0}; 28 | int nSplit{D_OK}; 29 | }; 30 | using VSpur = std::vector; 31 | 32 | 33 | struct C3Lagen 34 | { 35 | protected: 36 | 37 | int m_nSplit{D_OK}; 38 | 39 | public: 40 | 41 | bool m_bWithTraces { false }; 42 | bool m_bDurchschlagen{ false }; 43 | bool m_bRotate { false }; 44 | bool m_bShowText { true }; 45 | bool m_bShowHints { true }; 46 | bool m_bShowBlink { true }; 47 | bool m_bShowMouse { true }; 48 | 49 | double m_tAnimStep { 0.0 }; 50 | bool m_bAnimReverse{ false }; 51 | 52 | void TraceReset() { m_vSpurE1.clear(); m_vSpurE2.clear(); m_tAnimStep = 0; } 53 | void TraceInvrt() { m_bWithTraces = !m_bWithTraces; TraceReset(); } 54 | void Durchschlagen() { m_bDurchschlagen = !m_bDurchschlagen; TraceReset(); } 55 | void Rotate() { m_bRotate = !m_bRotate; } 56 | void WithText() { m_bShowText = !m_bShowText; } 57 | void WithHints() { m_bShowHints = !m_bShowHints; } 58 | void WithBlink() { m_bShowBlink = !m_bShowBlink; } 59 | void WithMouse() { m_bShowMouse = !m_bShowMouse; } 60 | 61 | 62 | VGrundPunkte m_vGrundPunkte; 63 | VGelenkPunkte m_vGelenkPunkte[2]; 64 | VPolDreieck m_vPolDreieck; 65 | VEbenen m_vEbenen; 66 | VSpur m_vSpurE1; 67 | VSpur m_vSpurE2; 68 | 69 | void Show(CairoCtx cr, double const & dScale); 70 | 71 | CCanvas::SCollision Collision(SPoint const & tPoint); 72 | bool MoveObject(CCanvas::SCollision const & tCollision, SPoint const & pos); 73 | 74 | 75 | void Update(SEbene const & e, size_t const & i); 76 | void Update(SGrundPunkt const & e, size_t const & i); 77 | // void Update(SGelenkPunkt const & e, size_t const & i); 78 | 79 | bool CalcGrundPunktDerivates(CairoCtx cr, SPoint const & gp, 80 | VPolDreieck const & pd ); 81 | 82 | void DrawEbene(CairoCtx cr, SEbene const & e, size_t const & i); 83 | 84 | void DrawPoldreieck(CairoCtx cr, SPoint const & pa, 85 | SPoint const & pb, 86 | SPoint const & pc, 87 | SColor const & fc, 88 | SColor const & bc, 89 | double const & s=1.0); 90 | 91 | void DrawGrundPunkt(CairoCtx cr, SPoint const & m, size_t const & i); 92 | void DrawGelenkViereck(CairoCtx cr, size_t const & i); 93 | void DrawGehausePunkt (CairoCtx cr, SGehausePunkt const & G0, 94 | std::string const & t); 95 | void DrawGetriebe(CairoCtx cr, double const & ani, double const & dAni); 96 | 97 | }; // struct C3Lagen 98 | 99 | // L3LAGEN_H 100 | #endif 101 | -------------------------------------------------------------------------------- /a-shift+move/canvas.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | 7 | struct SPoint 8 | { 9 | SPoint() = default; 10 | SPoint(SPoint const & src) = default; 11 | template 12 | SPoint(T const & x, T const & y) : x(x), y(y) {} 13 | template 14 | SPoint(T const & t) : x(t.x), y(t.y) {} 15 | double x{0}, y{0}; 16 | template 17 | SPoint operator = (P const & p) 18 | { 19 | x = p.x; 20 | y = p.y; 21 | return *this; 22 | } 23 | template 24 | SPoint operator -= (P const & p) 25 | { 26 | x -= p.x; 27 | y -= p.y; 28 | return *this; 29 | } 30 | template 31 | SPoint operator += (P const & p) 32 | { 33 | x += p.x; 34 | y += p.y; 35 | return *this; 36 | } 37 | }; 38 | 39 | inline bool operator == (SPoint const & p1, SPoint const & p2) 40 | { 41 | return (p1.x==p2.x) && (p1.y==p2.y); 42 | } 43 | 44 | inline bool operator != (SPoint const & p1, SPoint const & p2) 45 | { 46 | return !(p1==p2); 47 | } 48 | 49 | inline SPoint operator - (SPoint const & p1, SPoint const & p2) 50 | { 51 | return {p1.x-p2.x, p1.y-p2.y}; 52 | } 53 | 54 | inline SPoint operator + (SPoint const & p1, SPoint const & p2) 55 | { 56 | return {p2.x+p1.x, p2.y+p1.y}; 57 | } 58 | 59 | inline SPoint operator / (SPoint const & p, double const & d) 60 | { 61 | return {p.x/d, p.y/d}; 62 | } 63 | 64 | inline SPoint operator * (SPoint const & p, double const & d) 65 | { 66 | return {p.x*d, p.y*d}; 67 | } 68 | 69 | 70 | struct SFleck 71 | { 72 | double x{0}, y{0}, r{0}; 73 | template 74 | SFleck operator -= (P const & p) 75 | { 76 | x -= p.x; 77 | y -= p.y; 78 | return *this; 79 | } 80 | template 81 | SFleck operator += (P const & p) 82 | { 83 | x += p.x; 84 | y += p.y; 85 | return *this; 86 | } 87 | template 88 | SFleck operator = (P const & p) 89 | { 90 | x = p.x; 91 | y = p.y; 92 | return *this; 93 | } 94 | }; 95 | 96 | struct SColor 97 | { 98 | double r{0},g{0},b{0}; 99 | }; 100 | 101 | using VPoints = std::vector; 102 | using VFlecken = std::vector; 103 | 104 | // the first argument can be anything having the members x and y 105 | // a Gtk event, a SFleck or whatever 106 | template 107 | double Distance( P const & a, T const & b ) 108 | { 109 | return sqrt( pow((a.x-b.x),2) + pow((a.y-b.y),2) ); 110 | } 111 | 112 | 113 | class CCanvas : public Gtk::DrawingArea 114 | { 115 | public: 116 | CCanvas() 117 | { 118 | add_events(Gdk::BUTTON_PRESS_MASK | Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK); 119 | add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK); 120 | add_events(Gdk::BUTTON1_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK); 121 | add_events(Gdk::KEY_PRESS_MASK | Gdk::KEY_RELEASE_MASK); 122 | } 123 | 124 | virtual ~CCanvas() { }; 125 | 126 | protected: 127 | // Override default signal handler: 128 | bool on_draw(const Cairo::RefPtr& cr) override; 129 | bool on_scroll_event(GdkEventScroll *event) override; 130 | bool on_button_press_event(GdkEventButton * event) override; 131 | bool on_motion_notify_event(GdkEventMotion *event) override; 132 | bool on_button_release_event(GdkEventButton* release_event) override; 133 | 134 | bool Collision(SPoint const & tPoint); 135 | 136 | bool m_bShiftInit { true }; 137 | SPoint m_tShift { .0,.0 }; 138 | SPoint m_tEventPress { .0,.0 }; 139 | SPoint m_tEventRelease{ .0,.0 }; 140 | SPoint m_tShiftStart { .0,.0 }; 141 | 142 | 143 | SPoint m_tMousePos; 144 | SColor m_tMouseColor{ .5,.5,.5 }; 145 | VPoints m_vMouseTrail; 146 | VFlecken m_vFlecken { {30,30,20}, {300,300,50}, {500,200,40}, 147 | {40,50,25}, {240,320,30}, {580,270,45} }; 148 | 149 | struct SCollision 150 | { 151 | SPoint tWhere { .0,.0 }; 152 | SPoint tOffset{ .0,.0 }; 153 | enum class EWhat 154 | { 155 | none, // there was no collision 156 | Fleck, // move a Fleck 157 | Line, // move a Line 158 | }eWhat {EWhat::none}; 159 | int nIndex {0}; // O: L1, L2, L3 160 | int nSubIx {0}; // L: P1, PM, P2 161 | } m_tCollision; 162 | 163 | }; // CCanvas 164 | -------------------------------------------------------------------------------- /b-shift+zoom+move/canvas.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | 7 | struct SPoint 8 | { 9 | SPoint() = default; 10 | SPoint(SPoint const & src) = default; 11 | template 12 | SPoint(T const & x, T const & y) : x(x), y(y) {} 13 | template 14 | SPoint(T const & t) : x(t.x), y(t.y) {} 15 | double x{0}, y{0}; 16 | template 17 | SPoint operator = (P const & p) 18 | { 19 | x = p.x; 20 | y = p.y; 21 | return *this; 22 | } 23 | template 24 | SPoint operator -= (P const & p) 25 | { 26 | x -= p.x; 27 | y -= p.y; 28 | return *this; 29 | } 30 | template 31 | SPoint operator += (P const & p) 32 | { 33 | x += p.x; 34 | y += p.y; 35 | return *this; 36 | } 37 | }; 38 | 39 | inline bool operator == (SPoint const & p1, SPoint const & p2) 40 | { 41 | return (p1.x==p2.x) && (p1.y==p2.y); 42 | } 43 | 44 | inline bool operator != (SPoint const & p1, SPoint const & p2) 45 | { 46 | return !(p1==p2); 47 | } 48 | 49 | inline SPoint operator - (SPoint const & p1, SPoint const & p2) 50 | { 51 | return {p1.x-p2.x, p1.y-p2.y}; 52 | } 53 | 54 | inline SPoint operator + (SPoint const & p1, SPoint const & p2) 55 | { 56 | return {p2.x+p1.x, p2.y+p1.y}; 57 | } 58 | 59 | inline SPoint operator / (SPoint const & p, double const & d) 60 | { 61 | return {p.x/d, p.y/d}; 62 | } 63 | 64 | inline SPoint operator * (SPoint const & p, double const & d) 65 | { 66 | return {p.x*d, p.y*d}; 67 | } 68 | 69 | 70 | struct SFleck 71 | { 72 | double x{0}, y{0}, r{0}; 73 | template 74 | SFleck operator -= (P const & p) 75 | { 76 | x -= p.x; 77 | y -= p.y; 78 | return *this; 79 | } 80 | template 81 | SFleck operator += (P const & p) 82 | { 83 | x += p.x; 84 | y += p.y; 85 | return *this; 86 | } 87 | template 88 | SFleck operator = (P const & p) 89 | { 90 | x = p.x; 91 | y = p.y; 92 | return *this; 93 | } 94 | }; 95 | 96 | struct SColor 97 | { 98 | double r{0},g{0},b{0}; 99 | }; 100 | 101 | using VPoints = std::vector; 102 | using VFlecken = std::vector; 103 | 104 | // the first argument can be anything having the members x and y 105 | // a Gtk event, a SFleck or whatever 106 | template 107 | double Distance( P const & a, T const & b ) 108 | { 109 | return sqrt( pow((a.x-b.x),2) + pow((a.y-b.y),2) ); 110 | } 111 | 112 | 113 | class CCanvas : public Gtk::DrawingArea 114 | { 115 | public: 116 | CCanvas() 117 | { 118 | add_events(Gdk::BUTTON_PRESS_MASK | Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK); 119 | add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK); 120 | add_events(Gdk::BUTTON1_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK); 121 | add_events(Gdk::KEY_PRESS_MASK | Gdk::KEY_RELEASE_MASK); 122 | } 123 | 124 | virtual ~CCanvas() { }; 125 | 126 | protected: 127 | // Override default signal handler: 128 | bool on_draw(const Cairo::RefPtr& cr) override; 129 | bool on_scroll_event(GdkEventScroll *event) override; 130 | bool on_button_press_event(GdkEventButton * event) override; 131 | bool on_motion_notify_event(GdkEventMotion *event) override; 132 | bool on_button_release_event(GdkEventButton* release_event) override; 133 | 134 | bool Collision(SPoint const & tPoint); 135 | 136 | SPoint m_tCtxSize { .0,.0 }; 137 | double m_dScale { 1.0 }; 138 | bool m_bShiftInit { true }; 139 | SPoint m_tShift { .0,.0 }; 140 | SPoint m_tEventPress { .0,.0 }; 141 | SPoint m_tEventRelease{ .0,.0 }; 142 | SPoint m_tShiftStart { .0,.0 }; 143 | 144 | 145 | SPoint m_tMousePos; 146 | SColor m_tMouseColor{ .5,.5,.5 }; 147 | VPoints m_vMouseTrail; 148 | VFlecken m_vFlecken { {30,30,20}, {300,300,50}, {500,200,40}, 149 | {40,50,25}, {240,320,30}, {580,270,45} }; 150 | 151 | struct SCollision 152 | { 153 | SPoint tWhere { .0,.0 }; 154 | SPoint tOffset{ .0,.0 }; 155 | enum class EWhat 156 | { 157 | none, // there was no collision 158 | Fleck, // move a Fleck 159 | Line, // move a Line 160 | }eWhat {EWhat::none}; 161 | int nIndex {0}; // O: L1, L2, L3 162 | int nSubIx {0}; // L: P1, PM, P2 163 | } m_tCollision; 164 | 165 | }; // CCanvas 166 | -------------------------------------------------------------------------------- /a-shift+move/canvas.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | 3 | 4 | 5 | 6 | 7 | 8 | bool CCanvas::Collision(SPoint const & tPoint) 9 | { 10 | m_tCollision.eWhat = SCollision::EWhat::none; 11 | 12 | int i{0}; 13 | for ( auto & a:m_vFlecken ) 14 | { 15 | if ( Distance(a, tPoint) < a.r ) 16 | { 17 | m_tCollision.tWhere = tPoint; 18 | m_tCollision.tOffset= tPoint - a; 19 | m_tCollision.eWhat = SCollision::EWhat::Fleck; 20 | m_tCollision.nIndex = i; 21 | return std::move(true); 22 | } 23 | ++i; 24 | } 25 | return false; 26 | } 27 | 28 | 29 | bool CCanvas::on_button_press_event(GdkEventButton *event) 30 | { 31 | m_tMouseColor = { .0,.0,.9 }; 32 | if (event->type == GDK_BUTTON_PRESS ) 33 | { 34 | m_tEventPress = *event; 35 | m_tShiftStart = m_tShift; 36 | } 37 | else 38 | { 39 | auto const bCol { Collision(m_tMousePos) }; 40 | } 41 | 42 | if ( event->button == 3 ) 43 | { 44 | switch ( m_tCollision.eWhat ) 45 | { 46 | case SCollision::EWhat::Fleck: 47 | break; 48 | case SCollision::EWhat::Line: 49 | break; 50 | case SCollision::EWhat::none: 51 | break; 52 | } 53 | } 54 | 55 | queue_draw(); 56 | return true; 57 | } 58 | 59 | bool CCanvas::on_motion_notify_event(GdkEventMotion *event) 60 | { 61 | m_tMousePos = *event - m_tShift; 62 | 63 | if ( event->type & GDK_MOTION_NOTIFY ) 64 | if ( event->state & GDK_BUTTON3_MASK ) 65 | { 66 | switch ( m_tCollision.eWhat ) 67 | { 68 | case SCollision::EWhat::Fleck: 69 | m_vFlecken[m_tCollision.nIndex] = m_tMousePos 70 | - m_tCollision.tOffset; 71 | break; 72 | case SCollision::EWhat::Line: 73 | break; 74 | case SCollision::EWhat::none: 75 | m_tShift = m_tShiftStart - (m_tEventPress - *event); 76 | break; 77 | } 78 | } 79 | else 80 | { 81 | auto const bCol { Collision(m_tMousePos) }; 82 | } 83 | 84 | queue_draw(); 85 | return true; 86 | } 87 | 88 | bool CCanvas::on_button_release_event(GdkEventButton* event) 89 | { 90 | if ( event->type & GDK_MOTION_NOTIFY ) 91 | if ( event->state & GDK_BUTTON1_MASK ) 92 | { 93 | m_tMouseColor = { .5,.5,.5 }; 94 | m_vMouseTrail.emplace_back( SPoint{ *event - m_tShift } ); 95 | } 96 | if ( event->state & GDK_BUTTON3_MASK ) 97 | { 98 | } 99 | 100 | queue_draw(); 101 | return true; 102 | } 103 | 104 | bool CCanvas::on_scroll_event(GdkEventScroll *event) 105 | { 106 | if ( event->delta_y>0 ) 107 | m_tMouseColor = { .9,.0,.0 }; 108 | else 109 | m_tMouseColor = { .0,.9,.0 }; 110 | 111 | queue_draw(); 112 | return true; 113 | } 114 | 115 | bool CCanvas::on_draw(Cairo::RefPtr const & cr) 116 | { 117 | auto const all { get_allocation() }; 118 | auto const m_tCtxSize { SPoint { (double)all.get_width(), 119 | (double)all.get_height() } }; 120 | 121 | static auto tHome{ SPoint { m_tCtxSize }/2 }; 122 | 123 | if ( m_bShiftInit ) 124 | { 125 | tHome = m_tShift = m_tCtxSize/2; 126 | m_bShiftInit = false; 127 | } 128 | auto const tSizeHalf{m_tCtxSize/2}; 129 | if ( tHome != tSizeHalf ) 130 | { 131 | m_tShift -= tHome - tSizeHalf; tHome = tSizeHalf; 132 | } 133 | 134 | Cairo::Matrix matrix(1.0, 0.0, 0.0, 1.0, 0.0, 0.0); 135 | matrix.translate(m_tShift.x, m_tShift.y); 136 | 137 | cr->transform(matrix); 138 | 139 | 140 | 141 | if ( auto const i{m_vMouseTrail.size()} ) 142 | { 143 | cr->set_source_rgb( .0,.0,.0 ); 144 | cr->set_line_width(3); 145 | cr->move_to(m_vMouseTrail[0].x,m_vMouseTrail[0].y); 146 | for (auto const & a:m_vMouseTrail) 147 | { 148 | cr->line_to( a.x, a.y); 149 | } 150 | cr->stroke(); 151 | 152 | cr->set_source_rgb( .6,.6,.6 ); 153 | cr->set_line_width(1); 154 | cr->move_to(m_vMouseTrail[i-1].x,m_vMouseTrail[i-1].y); 155 | cr->line_to( m_tMousePos.x, m_tMousePos.y ); 156 | cr->stroke(); 157 | } 158 | 159 | int i{0}; 160 | for ( auto const & a:m_vFlecken ) 161 | { 162 | if ( ( m_tCollision.nIndex == i++ ) && 163 | ( m_tCollision.eWhat == SCollision::EWhat::Fleck ) ) 164 | cr->set_source_rgb( .9, .0, .0 ); 165 | else 166 | cr->set_source_rgb( .0, .9, .0 ); 167 | cr->arc(a.x, a.y, a.r, 0, 2*M_PI); 168 | cr->fill(); 169 | } 170 | 171 | 172 | cr->set_source_rgb( m_tMouseColor.r, m_tMouseColor.b, m_tMouseColor.b ); 173 | cr->arc(m_tMousePos.x, m_tMousePos.y, 11, 0, 2*M_PI); 174 | cr->fill(); 175 | 176 | return true; 177 | } 178 | -------------------------------------------------------------------------------- /g-app-draw/atom.h: -------------------------------------------------------------------------------- 1 | #ifndef CATOM_H 2 | #define CATOM_H 3 | 4 | /** 5 | * @file atom.h 6 | * 7 | * @author Manfred Morgner 8 | * @date 10.10.2018 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include "canvas.h" 16 | 17 | 18 | 19 | using namespace std::string_literals; 20 | 21 | 22 | 23 | 24 | inline bool MoveAtom(SRect & r, SPoint const & p) 25 | { 26 | r.p = p; 27 | return true; 28 | } 29 | 30 | inline bool MoveAtom(SFrame & r, SPoint const & p) 31 | { 32 | r.p = p; 33 | return true; 34 | } 35 | 36 | inline bool MoveAtom(SFleck & f, SPoint const & p) 37 | { 38 | f.x = p.x; 39 | f.y = p.y; 40 | return true; 41 | } 42 | 43 | template 44 | bool MoveAtom(T & t, SPoint const & p) 45 | { 46 | return false; 47 | } 48 | 49 | 50 | inline SHit CollAtom(SPoint const & p, SFrame const & r) 51 | { 52 | if ( p.x > r.p.x && p.x < r.p.x+r.s.x && p.y < r.p.y && p.y > r.p.y+r.s.y ) 53 | { 54 | return {true, p-r.p}; 55 | } 56 | return {false, {.0,.0}}; 57 | } 58 | 59 | inline SHit CollAtom(SPoint const & p, SRect const & r) 60 | { 61 | if ( p.x > r.p.x && p.x < r.p.x+r.s.x && p.y < r.p.y && p.y > r.p.y+r.s.y ) 62 | { 63 | return {true, p-r.p}; 64 | } 65 | return {false, {.0,.0}}; 66 | } 67 | 68 | inline SHit CollAtom(SPoint const & p, SFleck const & f) 69 | { 70 | if ( Distance(f, p) < f.r ) 71 | { 72 | return {true, p-SPoint{f.x,f.y}}; 73 | } 74 | return {false, {.0,.0}}; 75 | } 76 | 77 | template 78 | SHit CollAtom(SPoint const & p, T const & t) 79 | { 80 | return {false, {.0,.0}}; 81 | } 82 | 83 | 84 | 85 | inline void DrawAtom(Cairo::RefPtr const & cr, SLineWidth const & w) 86 | { 87 | LineWidth( cr, w ); 88 | } 89 | 90 | inline void DrawAtom(Cairo::RefPtr const & cr, SColor const & c) 91 | { 92 | Color( cr, c ); 93 | } 94 | 95 | inline void DrawAtom(Cairo::RefPtr const & cr, SRect const & t) 96 | { 97 | Rectangle( cr, t.p, t.s ); 98 | } 99 | 100 | inline void DrawAtom(Cairo::RefPtr const & cr, SFrame const & t) 101 | { 102 | Frame( cr, t.p, t.s ); 103 | } 104 | 105 | inline void DrawAtom(Cairo::RefPtr const & cr, SFleck const & t) 106 | { 107 | cr->save(); 108 | Color( cr, {.0,.0,.0} ); 109 | Ring ( cr, SPoint{t.x,t.y}, t.r ); 110 | cr->restore(); 111 | Circle( cr, SPoint{t.x,t.y}, t.r ); 112 | } 113 | 114 | template 115 | void DrawAtom(Cairo::RefPtr const & cr, T const & t) 116 | { 117 | Line( cr, t ); 118 | } 119 | 120 | 121 | 122 | class CAtom 123 | { 124 | public: 125 | 126 | template 127 | CAtom(T tAtomData) 128 | : m_pAtomData(new SAtomData(std::move(tAtomData))) 129 | { 130 | } 131 | 132 | /// Destruction as usual (=default) 133 | virtual ~CAtom() noexcept = default; 134 | 135 | 136 | SPoint operator = (SPoint const & p) 137 | { 138 | m_pAtomData->move_element(p); 139 | return p; 140 | } 141 | 142 | bool ShiftAtom(SPoint const & p) 143 | { 144 | return m_pAtomData->move_element(p); 145 | } 146 | 147 | void ShowAtom(Cairo::RefPtr const & cr) const 148 | { 149 | m_pAtomData->draw_element(cr); 150 | } 151 | 152 | SHit HitAtom(SPoint const & p) const 153 | { 154 | return m_pAtomData->hit_element(p); 155 | } 156 | 157 | 158 | /// start of data implementation 159 | struct SAtomDataConcept 160 | { 161 | virtual ~SAtomDataConcept() = default; 162 | /// Will send the data of the atom to the given output 163 | virtual void draw_element(Cairo::RefPtr const &) const = 0; 164 | /// Will check for collision with given point 165 | virtual SHit hit_element(SPoint const &) const = 0; 166 | /// Will move geometric position 167 | virtual bool move_element(SPoint const &) = 0; 168 | }; // struct SAtomDataConcept 169 | 170 | /// The templated data structure to hold an arbitrary data element 171 | template 172 | struct SAtomData : SAtomDataConcept 173 | { 174 | SAtomData(T tData) : m_tData(std::move(tData)) {} 175 | 176 | void draw_element(Cairo::RefPtr const & cr) const 177 | { 178 | DrawAtom(cr, m_tData); 179 | } 180 | 181 | SHit hit_element(SPoint const & p) const 182 | { 183 | return CollAtom(p, m_tData); 184 | } 185 | 186 | bool move_element(SPoint const & p) 187 | { 188 | return MoveAtom(m_tData, p); 189 | } 190 | 191 | /// @brief The decalartion of the data element of type T 192 | T m_tData; 193 | }; // struct SAtomData 194 | 195 | /// @brief The pointer and holder of the data element of type T 196 | std::unique_ptr m_pAtomData; 197 | }; // class CAtom 198 | 199 | 200 | // CATOM_H 201 | #endif 202 | -------------------------------------------------------------------------------- /b-shift+zoom+move/canvas.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | 3 | 4 | 5 | 6 | 7 | 8 | bool CCanvas::Collision(SPoint const & tPoint) 9 | { 10 | m_tCollision.eWhat = SCollision::EWhat::none; 11 | 12 | int i{0}; 13 | for ( auto & a:m_vFlecken ) 14 | { 15 | if ( Distance(a, tPoint) < a.r ) 16 | { 17 | m_tCollision.tWhere = tPoint; 18 | m_tCollision.tOffset= tPoint - a; 19 | m_tCollision.eWhat = SCollision::EWhat::Fleck; 20 | m_tCollision.nIndex = i; 21 | return std::move(true); 22 | } 23 | ++i; 24 | } 25 | return false; 26 | } 27 | 28 | 29 | bool CCanvas::on_button_press_event(GdkEventButton *event) 30 | { 31 | m_tMouseColor = { .0,.0,.9 }; 32 | if (event->type == GDK_BUTTON_PRESS ) 33 | { 34 | m_tEventPress = *event; 35 | m_tShiftStart = m_tShift; 36 | } 37 | else 38 | { 39 | auto const bCol { Collision(m_tMousePos) }; 40 | } 41 | 42 | if ( event->button == 3 ) 43 | { 44 | switch ( m_tCollision.eWhat ) 45 | { 46 | case SCollision::EWhat::Fleck: 47 | break; 48 | case SCollision::EWhat::Line: 49 | break; 50 | case SCollision::EWhat::none: 51 | break; 52 | } 53 | } 54 | 55 | queue_draw(); 56 | return true; 57 | } 58 | 59 | bool CCanvas::on_motion_notify_event(GdkEventMotion *event) 60 | { 61 | m_tMousePos = (*event - m_tShift)/m_dScale; 62 | 63 | if ( event->type & GDK_MOTION_NOTIFY ) 64 | if ( event->state & GDK_BUTTON3_MASK ) 65 | { 66 | switch ( m_tCollision.eWhat ) 67 | { 68 | case SCollision::EWhat::Fleck: 69 | m_vFlecken[m_tCollision.nIndex] = m_tMousePos 70 | - m_tCollision.tOffset; 71 | break; 72 | case SCollision::EWhat::Line: 73 | break; 74 | case SCollision::EWhat::none: 75 | m_tShift = m_tShiftStart - (m_tEventPress - *event); 76 | break; 77 | } 78 | } 79 | else 80 | { 81 | auto const bCol { Collision(m_tMousePos) }; 82 | } 83 | 84 | queue_draw(); 85 | return true; 86 | } 87 | 88 | bool CCanvas::on_button_release_event(GdkEventButton* event) 89 | { 90 | if ( event->type & GDK_MOTION_NOTIFY ) 91 | if ( event->state & GDK_BUTTON1_MASK ) 92 | { 93 | m_tMouseColor = { .5,.5,.5 }; 94 | m_vMouseTrail.emplace_back( (*event - m_tShift)/m_dScale ); 95 | } 96 | if ( event->state & GDK_BUTTON3_MASK ) 97 | { 98 | } 99 | 100 | queue_draw(); 101 | return true; 102 | } 103 | 104 | bool CCanvas::on_scroll_event(GdkEventScroll *event) 105 | { 106 | if ( event->delta_y>0 ) 107 | m_tMouseColor = { .9,.0,.0 }; 108 | else 109 | m_tMouseColor = { .0,.9,.0 }; 110 | 111 | SPoint const p0{ (*event - m_tShift)/m_dScale }; 112 | m_dScale *= (event->delta_y>0)?.9:1.1; if (m_dScale<.01) m_dScale=.01; 113 | SPoint const p1{ (*event - m_tShift)/m_dScale }; 114 | m_tShift -= (p0-p1)*m_dScale; 115 | 116 | queue_draw(); 117 | return true; 118 | } 119 | 120 | bool CCanvas::on_draw(Cairo::RefPtr const & cr) 121 | { 122 | auto const all { get_allocation() }; 123 | auto const m_tCtxSize { SPoint { (double)all.get_width(), 124 | (double)all.get_height() } }; 125 | 126 | static auto tHome{ SPoint { m_tCtxSize }/2 }; 127 | 128 | if ( m_bShiftInit ) 129 | { 130 | tHome = m_tShift = m_tCtxSize/2; 131 | m_bShiftInit = false; 132 | } 133 | auto const tSizeHalf{m_tCtxSize/2}; 134 | if ( tHome != tSizeHalf ) 135 | { 136 | m_tShift -= tHome - tSizeHalf; tHome = tSizeHalf; 137 | } 138 | 139 | Cairo::Matrix matrix(1.0, 0.0, 0.0, 1.0, 0.0, 0.0); 140 | matrix.scale(m_dScale,m_dScale); 141 | matrix.translate(m_tShift.x/m_dScale, m_tShift.y/m_dScale); 142 | 143 | cr->transform(matrix); 144 | 145 | 146 | 147 | if ( auto const i{m_vMouseTrail.size()} ) 148 | { 149 | cr->set_source_rgb( .0,.0,.0 ); 150 | cr->set_line_width(3); 151 | cr->move_to(m_vMouseTrail[0].x,m_vMouseTrail[0].y); 152 | for (auto const & a:m_vMouseTrail) 153 | { 154 | cr->line_to( a.x, a.y); 155 | } 156 | cr->stroke(); 157 | 158 | cr->set_source_rgb( .6,.6,.6 ); 159 | cr->set_line_width(1); 160 | cr->move_to(m_vMouseTrail[i-1].x,m_vMouseTrail[i-1].y); 161 | cr->line_to( m_tMousePos.x, m_tMousePos.y ); 162 | cr->stroke(); 163 | } 164 | 165 | int i{0}; 166 | for ( auto const & a:m_vFlecken ) 167 | { 168 | if ( ( m_tCollision.nIndex == i++ ) && 169 | ( m_tCollision.eWhat == SCollision::EWhat::Fleck ) ) 170 | cr->set_source_rgb( .9, .0, .0 ); 171 | else 172 | cr->set_source_rgb( .0, .9, .0 ); 173 | cr->arc(a.x, a.y, a.r, 0, 2*M_PI); 174 | cr->fill(); 175 | } 176 | 177 | 178 | cr->set_source_rgb( m_tMouseColor.r, m_tMouseColor.b, m_tMouseColor.b ); 179 | cr->arc(m_tMousePos.x, m_tMousePos.y, 11, 0, 2*M_PI); 180 | cr->fill(); 181 | 182 | return true; 183 | } 184 | -------------------------------------------------------------------------------- /c-animation/canvas.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | 3 | 4 | 5 | 6 | 7 | 8 | bool CCanvas::Collision(SPoint const & tPoint) 9 | { 10 | m_tCollision.eWhat = SCollision::EWhat::none; 11 | 12 | int i{0}; 13 | for ( auto & a:m_vFlecken ) 14 | { 15 | if ( Distance(a, tPoint) < a.r ) 16 | { 17 | m_tCollision.tWhere = tPoint; 18 | m_tCollision.tOffset = tPoint - a; 19 | m_tCollision.eWhat = SCollision::EWhat::Fleck; 20 | m_tCollision.nIndex = i; 21 | return std::move(true); 22 | } 23 | ++i; 24 | } 25 | return false; 26 | } 27 | 28 | 29 | bool CCanvas::on_button_press_event(GdkEventButton *event) 30 | { 31 | m_tMouseColor = { .0,.0,.9 }; 32 | if (event->type == GDK_BUTTON_PRESS ) 33 | { 34 | m_tEventPress = *event; 35 | m_tShiftStart = m_tShift; 36 | } 37 | else 38 | { 39 | auto const bCol { Collision(m_tMousePos) }; 40 | } 41 | 42 | if ( event->button == 3 ) 43 | { 44 | switch ( m_tCollision.eWhat ) 45 | { 46 | case SCollision::EWhat::Fleck: 47 | break; 48 | case SCollision::EWhat::Line: 49 | break; 50 | case SCollision::EWhat::none: 51 | break; 52 | } 53 | } 54 | 55 | queue_draw(); 56 | return true; 57 | } 58 | 59 | bool CCanvas::on_motion_notify_event(GdkEventMotion *event) 60 | { 61 | m_tMousePos = (*event - m_tShift)/m_dScale; 62 | 63 | if ( event->type & GDK_MOTION_NOTIFY ) 64 | if ( event->state & GDK_BUTTON3_MASK ) 65 | { 66 | switch ( m_tCollision.eWhat ) 67 | { 68 | case SCollision::EWhat::Fleck: 69 | m_vFlecken[m_tCollision.nIndex] = m_tMousePos 70 | - m_tCollision.tOffset; 71 | break; 72 | case SCollision::EWhat::Line: 73 | break; 74 | case SCollision::EWhat::none: 75 | m_tShift = m_tShiftStart - (m_tEventPress - *event); 76 | break; 77 | } 78 | } 79 | else 80 | { 81 | auto const bCol { Collision(m_tMousePos) }; 82 | } 83 | 84 | queue_draw(); 85 | return true; 86 | } 87 | 88 | bool CCanvas::on_button_release_event(GdkEventButton* event) 89 | { 90 | if ( event->type & GDK_MOTION_NOTIFY ) 91 | if ( event->state & GDK_BUTTON1_MASK ) 92 | { 93 | m_tMouseColor = { .5,.5,.5 }; 94 | m_vMouseTrail.emplace_back( (*event - m_tShift)/m_dScale ); 95 | } 96 | if ( event->state & GDK_BUTTON3_MASK ) 97 | { 98 | } 99 | 100 | queue_draw(); 101 | return true; 102 | } 103 | 104 | bool CCanvas::on_scroll_event(GdkEventScroll *event) 105 | { 106 | if ( event->delta_y>0 ) 107 | m_tMouseColor = { .9,.0,.0 }; 108 | else 109 | m_tMouseColor = { .0,.9,.0 }; 110 | 111 | SPoint const p0{ (*event - m_tShift)/m_dScale }; 112 | m_dScale *= (event->delta_y>0)?.9:1.1; if (m_dScale<.01) m_dScale=.01; 113 | SPoint const p1{ (*event - m_tShift)/m_dScale }; 114 | m_tShift -= (p0-p1)*m_dScale; 115 | 116 | queue_draw(); 117 | return true; 118 | } 119 | 120 | bool CCanvas::on_draw(Cairo::RefPtr const & cr) 121 | { 122 | auto const all { get_allocation() }; 123 | auto const m_tCtxSize { SPoint { (double)all.get_width(), 124 | (double)all.get_height() } }; 125 | 126 | static auto tHome{ SPoint { m_tCtxSize }/2 }; 127 | 128 | if ( m_bShiftInit ) 129 | { 130 | tHome = m_tShift = m_tCtxSize/2; 131 | m_bShiftInit = false; 132 | } 133 | auto const tSizeHalf{m_tCtxSize/2}; 134 | if ( tHome != tSizeHalf ) 135 | { 136 | m_tShift -= tHome - tSizeHalf; tHome = tSizeHalf; 137 | } 138 | 139 | Cairo::Matrix matrix(1.0, 0.0, 0.0, 1.0, 0.0, 0.0); 140 | matrix.scale(m_dScale,m_dScale); 141 | matrix.translate(m_tShift.x/m_dScale, m_tShift.y/m_dScale); 142 | 143 | cr->transform(matrix); 144 | 145 | 146 | 147 | if ( auto const i{m_vMouseTrail.size()} ) 148 | { 149 | cr->set_source_rgb( .0,.0,.0 ); 150 | cr->set_line_width(3); 151 | cr->move_to(m_vMouseTrail[0].x,m_vMouseTrail[0].y); 152 | for (auto const & a:m_vMouseTrail) 153 | { 154 | cr->line_to( a.x, a.y); 155 | } 156 | cr->stroke(); 157 | 158 | cr->set_source_rgb( .6,.6,.6 ); 159 | cr->set_line_width(1); 160 | cr->move_to(m_vMouseTrail[i-1].x,m_vMouseTrail[i-1].y); 161 | cr->line_to( m_tMousePos.x, m_tMousePos.y ); 162 | cr->stroke(); 163 | } 164 | 165 | int i{0}; 166 | for ( auto const & a:m_vFlecken ) 167 | { 168 | if ( ( m_tCollision.nIndex == i++ ) && 169 | ( m_tCollision.eWhat == SCollision::EWhat::Fleck ) ) 170 | cr->set_source_rgb( .9, .0, .0 ); 171 | else 172 | cr->set_source_rgb( .0, .9, .0 ); 173 | if ( i == 1 ) 174 | cr->arc(a.x + 250*m_dAnimatorBi, a.y, a.r, 0, 2*M_PI); 175 | else if ( i == 2 ) 176 | cr->arc(a.x, a.y - sin(2*M_PI*m_dAnimatorRot)*125, a.r, 0, 2*M_PI); 177 | else 178 | cr->arc(a.x, a.y, a.r, 0, 2*M_PI); 179 | cr->fill(); 180 | 181 | cr->set_source_rgb( .0, .2, .0 ); 182 | cr->set_line_width(1); 183 | cr->arc(a.x, a.y, a.r, 0, 2*M_PI); 184 | cr->stroke(); 185 | } 186 | 187 | 188 | cr->set_source_rgb( m_tMouseColor.r, m_tMouseColor.b, m_tMouseColor.b ); 189 | cr->arc(m_tMousePos.x, m_tMousePos.y, 11, 0, 2*M_PI); 190 | cr->fill(); 191 | 192 | return true; 193 | } 194 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cairo-Tutorial 2 | Simple C++ code samples to get a feeling for Cairo and how to animate your graohics 3 | 4 | ## How to compile 5 | 6 | * enter a sample directory, e.g. 8-collision 7 | * call: ../compile.sh 8 | 9 | ## what's in there? 10 | 11 | ### 0-empty-program 12 | an empty C++ program 13 | 14 | ### 1-empty-cairo-program 15 | an empty Cairo program 16 | 17 | let us open a GDK window filled with Cairo filled with nothing 18 | 19 | ### 2-a-red-line 20 | a Cairo program showing a line 21 | 22 | we need to override default signal handler 23 | ```c++ 24 | bool on_draw(const Cairo::RefPtr& cr) override; 25 | ``` 26 | this is, what we do override it for 27 | ```c++ 28 | bool on_draw(Cairo::RefPtr const & cr) 29 | { 30 | cr->set_source_rgb(1.,.5,.0); 31 | cr->set_line_width(3); 32 | 33 | cr->move_to( 11, 11); 34 | cr->line_to(111,111); 35 | cr->stroke(); 36 | 37 | return true; 38 | } 39 | ``` 40 | * inform the context about the next colour 41 | * inform it about the next line width 42 | * move the pencil to 11,11 43 | * propose a line to the context, to 111,111 44 | * request the context to draw this line using all accumulated information 45 | 46 | ### 3-a-total-line 47 | showing a line trough the complete window. 48 | 49 | To enable this, we need to know 50 | the visible coordinates range of the cairo render context: 51 | ```c++ 52 | Gtk::Allocation allocation{ get_allocation() }; 53 | auto const width { (double)allocation.get_width() }; 54 | auto const height{ (double)allocation.get_height() }; 55 | ``` 56 | now the total line: 57 | ```c++ 58 | cr->move_to( 0, 0); 59 | cr->line_to(width, height); 60 | cr->stroke(); 61 | ``` 62 | and a funny gray circle in the middle: 63 | ```c++ 64 | cr->set_source_rgb(.7,.7,.7); 65 | cr->arc(width/2, height/2, 100, 0, 2*M_PI); 66 | cr->fill(); 67 | ``` 68 | 69 | ### 4-picture-png 70 | a Cairo program showing a png picture 71 | 72 | ```c++ 73 | static Glib::RefPtr const image = Gdk::Pixbuf::create_from_file("CairoTut.png"); 74 | static Glib::RefPtr imageS = image->scale_simple( 180, 180, Gdk::INTERP_BILINEAR); 75 | Gdk::Cairo::set_source_pixbuf(cr, imageS, width/2-90, height/2-90 ); 76 | cr->rectangle( width/2-90, height/2-90, 180, 180 ); 77 | cr->fill(); 78 | ``` 79 | * load picture 80 | static Glib::RefPtr const image = Gdk::Pixbuf::create_from_file("CairoTut.png"); 81 | * scale picture to destination size 82 | static Glib::RefPtr imageS = image->scale_simple( 180, 180, Gdk::INTERP_BILINEAR); 83 | * place scaled pictures to specified position in render context 84 | Gdk::Cairo::set_source_pixbuf(cr, imageS, width/2-90, height/2-90 ); 85 | * open a hole for the pixels 86 | cr->rectangle( width/2-90, height/2-90, 180, 180 ); 87 | * show the hole 88 | 89 | ### 5-picture-svg 90 | a Cairo program showing a svg drawing 91 | 92 | ### 6-mouse-position 93 | a Cairo program tracking the mouse pointer 94 | 95 | intoducing the first GDK callback into the Cairo application 96 | 97 | ```C++ 98 | bool on_motion_notify_event(GdkEventMotion *event) 99 | { 100 | tMousePos = SPoint{*event}; 101 | queue_draw(); 102 | return true; 103 | } 104 | ``` 105 | 106 | * saving the current mouse position to draw a point there later 107 | * from Cairo request a call to `bool on_draw(...)` 108 | * return true because we have consumed the event 109 | 110 | show the result utilizing `on_draw(...)` 111 | 112 | ```c++ 113 | cr->set_source_rgb(.0,.0,.9); 114 | cr->arc(tMousePos.x, tMousePos.y, 3, 0, 2*M_PI); 115 | cr->fill(); 116 | ``` 117 | * set the colour to blue 118 | * declare a circle at saved mouse position 119 | * fill the declared circle with the set colour 120 | 121 | ### 7-mouse-complete 122 | a Cairo program tracking the mouse pointer and intractively drawing a line 123 | 124 | ```c++ 125 | bool CCanvas::on_button_press_event(GdkEventButton *event) 126 | { 127 | m_tMouseColor = { .0,.0,.9 }; 128 | queue_draw(); 129 | return true; 130 | } 131 | ``` 132 | * if a mouse button is pressed, the mouse color becomes blue 133 | * to show thw change, a redraw is queued 134 | ```c++ 135 | bool CCanvas::on_button_release_event(GdkEventButton* event) 136 | { 137 | m_tMouseColor = { .5,.5,.5 }; 138 | m_vMouseTrail.emplace_back( SPoint{ *event } ); 139 | queue_draw(); 140 | return true; 141 | } 142 | ``` 143 | * if a mouse button is released, the position becomes queued 144 | ```c++ 145 | bool CCanvas::on_draw(Cairo::RefPtr const & cr) 146 | { 147 | cr->set_source_rgb( .0,.0,.0 ); 148 | cr->set_line_width(3); 149 | if ( m_vMouseTrail.size() ) 150 | { 151 | cr->move_to(m_vMouseTrail[0].x,m_vMouseTrail[0].y); 152 | for (auto const & a:m_vMouseTrail) 153 | { 154 | cr->line_to( a.x, a.y); 155 | } 156 | cr->stroke(); 157 | } 158 | ``` 159 | * draw lines connecting all trigger points 160 | 161 | ### 8-collision 162 | a Cairo program demonstraing the collision between the mouse pointer and graphucal objects 163 | 164 | ### 9-shift 165 | a Cairo program showing how to move the canvas whilst keeping the mouse collider functional 166 | 167 | ### a-shift+move 168 | a Cairo program adding moving of objects by mouse 169 | 170 | ### b-shift+zoom+move 171 | a Cairo program adding zooming of tha canvas whilst keeping the canvas shifter and the mouse collider functional 172 | 173 | ### c-animation 174 | a Cairo program adding two different animation clocks to the mix, demonstrating multi animation 175 | 176 | ### d-text 177 | a Cairo program adding text to all other functions 178 | 179 | ### e-ui-button-bar 180 | adding a button bar 181 | ### f-drawing-helpers 182 | adding an elastic line 183 | 184 | ### g-app-draw 185 | a simple drawing application 186 | 187 | ### h-3-lagen-synthese 188 | a mechanism sythese application 189 | 190 | ### i-4-bar-analytics 191 | a mechanism analyse application 192 | 193 | ### k-like-cad 194 | an experimental CAD application 195 | 196 | ### o-gaming 197 | an experimental game with potential 198 | -------------------------------------------------------------------------------- /m-mass-animation/canvas.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | #include 3 | 4 | 5 | 6 | 7 | 8 | 9 | bool CCanvas::Collision(SPoint const & tPoint) 10 | { 11 | /* 12 | m_tCollision.eWhat = SCollision::EWhat::none; 13 | 14 | int i{0}; 15 | for ( auto & a:m_vFlecken ) 16 | { 17 | if ( Distance(a, tPoint) < a.r ) 18 | { 19 | m_tCollision.tWhere = tPoint; 20 | m_tCollision.tOffset = tPoint - a; 21 | m_tCollision.eWhat = SCollision::EWhat::Fleck; 22 | m_tCollision.nIndex = i; 23 | return std::move(true); 24 | } 25 | ++i; 26 | } 27 | */ 28 | return false; 29 | } 30 | 31 | 32 | bool CCanvas::on_button_press_event(GdkEventButton *event) 33 | { 34 | m_tMouseColor = { .0,.0,.9 }; 35 | if (event->type == GDK_BUTTON_PRESS ) 36 | { 37 | m_tEventPress = *event; 38 | m_tShiftStart = m_tShift; 39 | } 40 | else 41 | { 42 | auto const bCol { Collision(m_tMousePos) }; 43 | } 44 | 45 | if ( event->button == 3 ) 46 | { 47 | switch ( m_tCollision.eWhat ) 48 | { 49 | case SCollision::EWhat::Fleck: 50 | break; 51 | case SCollision::EWhat::Line: 52 | break; 53 | case SCollision::EWhat::none: 54 | break; 55 | } 56 | } 57 | 58 | queue_draw(); 59 | return true; 60 | } 61 | 62 | bool CCanvas::on_motion_notify_event(GdkEventMotion *event) 63 | { 64 | m_tMousePos = (*event - m_tShift)/m_dScale; 65 | 66 | if ( event->type & GDK_MOTION_NOTIFY ) 67 | { 68 | if ( event->state & GDK_BUTTON3_MASK ) 69 | { 70 | switch ( m_tCollision.eWhat ) 71 | { 72 | case SCollision::EWhat::Fleck: 73 | m_vFlecken[m_tCollision.nIndex] = m_tMousePos 74 | - m_tCollision.tOffset; 75 | break; 76 | case SCollision::EWhat::Line: 77 | break; 78 | case SCollision::EWhat::none: 79 | m_tShift = m_tShiftStart - (m_tEventPress - *event); 80 | break; 81 | } 82 | } 83 | else 84 | { 85 | auto const bCol { Collision(m_tMousePos) }; 86 | } 87 | } 88 | queue_draw(); 89 | return true; 90 | } 91 | 92 | bool CCanvas::on_button_release_event(GdkEventButton* event) 93 | { 94 | if ( event->type & GDK_MOTION_NOTIFY ) 95 | if ( event->state & GDK_BUTTON1_MASK ) 96 | { 97 | m_tMouseColor = { .5,.5,.5 }; 98 | m_vMouseTrail.emplace_back( (*event - m_tShift)/m_dScale ); 99 | } 100 | if ( event->state & GDK_BUTTON3_MASK ) 101 | { 102 | } 103 | 104 | queue_draw(); 105 | return true; 106 | } 107 | 108 | bool CCanvas::on_scroll_event(GdkEventScroll *event) 109 | { 110 | if ( event->delta_y>0 ) 111 | m_tMouseColor = { .9,.0,.0 }; 112 | else 113 | m_tMouseColor = { .0,.9,.0 }; 114 | 115 | SPoint const p0{ (*event - m_tShift)/m_dScale }; 116 | m_dScale *= (event->delta_y>0)?.9:1.1; if (m_dScale<.01) m_dScale=.01; 117 | SPoint const p1{ (*event - m_tShift)/m_dScale }; 118 | m_tShift -= (p0-p1)*m_dScale; 119 | 120 | queue_draw(); 121 | return true; 122 | } 123 | 124 | bool CCanvas::on_draw(Cairo::RefPtr const & cr) 125 | { 126 | auto const all { get_allocation() }; 127 | auto const m_tCtxSize { SPoint { (double)all.get_width(), 128 | (double)all.get_height() } }; 129 | 130 | static auto tHome{ SPoint { m_tCtxSize }/2 }; 131 | 132 | if ( m_bShiftInit ) 133 | { 134 | tHome = m_tShift = m_tCtxSize/2; 135 | m_bShiftInit = false; 136 | } 137 | auto const tSizeHalf{m_tCtxSize/2}; 138 | if ( tHome != tSizeHalf ) 139 | { 140 | m_tShift -= tHome - tSizeHalf; tHome = tSizeHalf; 141 | } 142 | 143 | Cairo::Matrix matrix(1.0, 0.0, 0.0, 1.0, 0.0, 0.0); 144 | matrix.scale(m_dScale,m_dScale); 145 | matrix.translate(m_tShift.x/m_dScale, m_tShift.y/m_dScale); 146 | 147 | cr->transform(matrix); 148 | 149 | 150 | /* 151 | if ( auto const i{m_vMouseTrail.size()} ) 152 | { 153 | cr->set_source_rgb( .0,.0,.0 ); 154 | cr->set_line_width(3); 155 | cr->move_to(m_vMouseTrail[0].x,m_vMouseTrail[0].y); 156 | for (auto const & a:m_vMouseTrail) 157 | { 158 | cr->line_to( a.x, a.y); 159 | } 160 | cr->stroke(); 161 | 162 | cr->set_source_rgb( .6,.6,.6 ); 163 | cr->set_line_width(1); 164 | cr->move_to(m_vMouseTrail[i-1].x,m_vMouseTrail[i-1].y); 165 | cr->line_to( m_tMousePos.x, m_tMousePos.y ); 166 | cr->stroke(); 167 | } 168 | */ 169 | int i{0}; 170 | cr->set_source_rgb( .0, .2, .9 ); 171 | cr->set_line_width(1); 172 | for ( auto const & a:m_vFlecken ) 173 | { 174 | /* 175 | if ( ( m_tCollision.nIndex == i++ ) && 176 | ( m_tCollision.eWhat == SCollision::EWhat::Fleck ) ) 177 | cr->set_source_rgb( .9, .0, .0 ); 178 | else 179 | */ 180 | cr->set_source_rgb((a.x+570)/1140,(a.y+570)/1140,abs(a.x+a.y)/2280); 181 | // if ( i == 1 ) 182 | // cr->arc(a.x + sin(2*M_PI*m_dAnimatorRot)*125, a.y + cos(2*M_PI*m_dAnimatorRot)*125, a.r, 0, 2*M_PI); 183 | double l=sqrt(pow(a.x,2)+pow(a.y,2)); 184 | auto const x{a.x + sin(2*M_PI*m_dAnimatorRot)*(l*sin(a.x/570*M_PI))}; 185 | auto const y{a.y + cos(2*M_PI*m_dAnimatorRot)*(l*cos(a.y/570*M_PI))}; 186 | cr->arc(x, y, a.r, 0, 2*M_PI); 187 | /* 188 | else if ( i == 2 ) 189 | cr->arc(a.x, a.y - sin(2*M_PI*m_dAnimatorRot)*125, a.r, 0, 2*M_PI); 190 | else 191 | cr->arc(a.x, a.y, a.r, 0, 2*M_PI); 192 | */ 193 | cr->fill(); 194 | 195 | // cr->arc(x, y, a.r, 0, 2*M_PI); 196 | // cr->stroke(); 197 | cr->arc(a.x, a.y, a.r, 0, 2*M_PI); 198 | cr->stroke(); 199 | } 200 | 201 | return true; 202 | } 203 | -------------------------------------------------------------------------------- /CairoTut.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 28 | 29 | 47 | 49 | 50 | 52 | image/svg+xml 53 | 55 | 56 | 57 | 58 | 59 | 64 | 71 | 78 | 85 | 92 | 99 | 106 | 113 | 120 | 121 | 128 | 135 | SVG Demo 146 | 147 | 148 | -------------------------------------------------------------------------------- /d-text/canvas.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | #include 3 | 4 | 5 | 6 | 7 | 8 | SPoint draw_text(Cairo::RefPtr const & cr, 9 | double posx, double posy, 10 | std::string const & crsText, double const & dScale = 1.0) 11 | { 12 | cr->save(); 13 | 14 | Pango::FontDescription font; 15 | 16 | font.set_family("Monospace"); 17 | font.set_absolute_size(12.0 * PANGO_SCALE*dScale); 18 | 19 | CCanvas w; 20 | auto layout = w.create_pango_layout(crsText); 21 | 22 | layout->set_font_description(font); 23 | int iWidth {0}; 24 | int iHeight{0}; 25 | SPoint tSize{.0,.0}; 26 | 27 | layout->get_pixel_size(iWidth, iHeight); 28 | tSize = SPoint{iWidth, iHeight}; 29 | cr->move_to(posx-tSize.x/2, posy-tSize.y/2); 30 | layout->show_in_cairo_context(cr); 31 | cr->restore(); 32 | 33 | return std::move(tSize); 34 | } 35 | 36 | bool CCanvas::Collision(SPoint const & tPoint) 37 | { 38 | m_tCollision.eWhat = SCollision::EWhat::none; 39 | 40 | int i{0}; 41 | for ( auto & a:m_vFlecken ) 42 | { 43 | if ( Distance(a, tPoint) < a.r ) 44 | { 45 | m_tCollision.tWhere = tPoint; 46 | m_tCollision.tOffset = tPoint - a; 47 | m_tCollision.eWhat = SCollision::EWhat::Fleck; 48 | m_tCollision.nIndex = i; 49 | return std::move(true); 50 | } 51 | ++i; 52 | } 53 | return false; 54 | } 55 | 56 | 57 | bool CCanvas::on_button_press_event(GdkEventButton *event) 58 | { 59 | m_tMouseColor = { .0,.0,.9 }; 60 | if (event->type == GDK_BUTTON_PRESS ) 61 | { 62 | m_tEventPress = *event; 63 | m_tShiftStart = m_tShift; 64 | } 65 | else 66 | { 67 | auto const bCol { Collision(m_tMousePos) }; 68 | } 69 | 70 | if ( event->button == 3 ) 71 | { 72 | switch ( m_tCollision.eWhat ) 73 | { 74 | case SCollision::EWhat::Fleck: 75 | break; 76 | case SCollision::EWhat::Line: 77 | break; 78 | case SCollision::EWhat::none: 79 | break; 80 | } 81 | } 82 | 83 | queue_draw(); 84 | return true; 85 | } 86 | 87 | bool CCanvas::on_motion_notify_event(GdkEventMotion *event) 88 | { 89 | m_tMousePos = (*event - m_tShift)/m_dScale; 90 | 91 | if ( event->type & GDK_MOTION_NOTIFY ) 92 | if ( event->state & GDK_BUTTON3_MASK ) 93 | { 94 | switch ( m_tCollision.eWhat ) 95 | { 96 | case SCollision::EWhat::Fleck: 97 | m_vFlecken[m_tCollision.nIndex] = m_tMousePos 98 | - m_tCollision.tOffset; 99 | break; 100 | case SCollision::EWhat::Line: 101 | break; 102 | case SCollision::EWhat::none: 103 | m_tShift = m_tShiftStart - (m_tEventPress - *event); 104 | break; 105 | } 106 | } 107 | else 108 | { 109 | auto const bCol { Collision(m_tMousePos) }; 110 | } 111 | 112 | queue_draw(); 113 | return true; 114 | } 115 | 116 | bool CCanvas::on_button_release_event(GdkEventButton* event) 117 | { 118 | if ( event->type & GDK_MOTION_NOTIFY ) 119 | if ( event->state & GDK_BUTTON1_MASK ) 120 | { 121 | m_tMouseColor = { .5,.5,.5 }; 122 | m_vMouseTrail.emplace_back( (*event - m_tShift)/m_dScale ); 123 | } 124 | if ( event->state & GDK_BUTTON3_MASK ) 125 | { 126 | } 127 | 128 | queue_draw(); 129 | return true; 130 | } 131 | 132 | bool CCanvas::on_scroll_event(GdkEventScroll *event) 133 | { 134 | if ( event->delta_y>0 ) 135 | m_tMouseColor = { .9,.0,.0 }; 136 | else 137 | m_tMouseColor = { .0,.9,.0 }; 138 | 139 | SPoint const p0{ (*event - m_tShift)/m_dScale }; 140 | m_dScale *= (event->delta_y>0)?.9:1.1; if (m_dScale<.01) m_dScale=.01; 141 | SPoint const p1{ (*event - m_tShift)/m_dScale }; 142 | m_tShift -= (p0-p1)*m_dScale; 143 | 144 | queue_draw(); 145 | return true; 146 | } 147 | 148 | bool CCanvas::on_draw(Cairo::RefPtr const & cr) 149 | { 150 | auto const all { get_allocation() }; 151 | auto const m_tCtxSize { SPoint { (double)all.get_width(), 152 | (double)all.get_height() } }; 153 | 154 | static auto tHome{ SPoint { m_tCtxSize }/2 }; 155 | 156 | if ( m_bShiftInit ) 157 | { 158 | tHome = m_tShift = m_tCtxSize/2; 159 | m_bShiftInit = false; 160 | } 161 | auto const tSizeHalf{m_tCtxSize/2}; 162 | if ( tHome != tSizeHalf ) 163 | { 164 | m_tShift -= tHome - tSizeHalf; tHome = tSizeHalf; 165 | } 166 | 167 | Cairo::Matrix matrix(1.0, 0.0, 0.0, 1.0, 0.0, 0.0); 168 | matrix.scale(m_dScale,m_dScale); 169 | matrix.translate(m_tShift.x/m_dScale, m_tShift.y/m_dScale); 170 | 171 | cr->transform(matrix); 172 | 173 | 174 | 175 | if ( auto const i{m_vMouseTrail.size()} ) 176 | { 177 | cr->set_source_rgb( .0,.0,.0 ); 178 | cr->set_line_width(3); 179 | cr->move_to(m_vMouseTrail[0].x,m_vMouseTrail[0].y); 180 | for (auto const & a:m_vMouseTrail) 181 | { 182 | cr->line_to( a.x, a.y); 183 | } 184 | cr->stroke(); 185 | 186 | cr->set_source_rgb( .6,.6,.6 ); 187 | cr->set_line_width(1); 188 | cr->move_to(m_vMouseTrail[i-1].x,m_vMouseTrail[i-1].y); 189 | cr->line_to( m_tMousePos.x, m_tMousePos.y ); 190 | cr->stroke(); 191 | } 192 | 193 | int i{0}; 194 | for ( auto const & a:m_vFlecken ) 195 | { 196 | if ( ( m_tCollision.nIndex == i++ ) && 197 | ( m_tCollision.eWhat == SCollision::EWhat::Fleck ) ) 198 | cr->set_source_rgb( .9, .0, .0 ); 199 | else 200 | cr->set_source_rgb( .0, .9, .0 ); 201 | if ( i == 1 ) 202 | cr->arc(a.x + 250*m_dAnimatorBi, a.y, a.r, 0, 2*M_PI); 203 | else if ( i == 2 ) 204 | cr->arc(a.x, a.y - sin(2*M_PI*m_dAnimatorRot)*125, a.r, 0, 2*M_PI); 205 | else 206 | cr->arc(a.x, a.y, a.r, 0, 2*M_PI); 207 | cr->fill(); 208 | 209 | cr->set_source_rgb( .0, .2, .0 ); 210 | cr->set_line_width(1); 211 | cr->arc(a.x, a.y, a.r, 0, 2*M_PI); 212 | cr->stroke(); 213 | } 214 | 215 | 216 | cr->set_source_rgb( m_tMouseColor.r, m_tMouseColor.b, m_tMouseColor.b ); 217 | cr->arc(m_tMousePos.x, m_tMousePos.y, 11, 0, 2*M_PI); 218 | cr->fill(); 219 | 220 | cr->set_source_rgb( .5, .5, .5 ); 221 | draw_text(cr, sin(2*M_PI*m_dAnimatorRot)*75, -60, "Informational text submission", 4); 222 | 223 | return true; 224 | } 225 | -------------------------------------------------------------------------------- /c-animation/canvas.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | 7 | struct SPoint 8 | { 9 | SPoint() = default; 10 | SPoint(SPoint const & src) = default; 11 | template 12 | SPoint(T const & x, T const & y) : x(x), y(y) {} 13 | template 14 | SPoint(T const & t) : x(t.x), y(t.y) {} 15 | double x{0}, y{0}; 16 | template 17 | SPoint operator = (P const & p) 18 | { 19 | x = p.x; 20 | y = p.y; 21 | return *this; 22 | } 23 | template 24 | SPoint operator -= (P const & p) 25 | { 26 | x -= p.x; 27 | y -= p.y; 28 | return *this; 29 | } 30 | template 31 | SPoint operator += (P const & p) 32 | { 33 | x += p.x; 34 | y += p.y; 35 | return *this; 36 | } 37 | }; 38 | 39 | inline bool operator == (SPoint const & p1, SPoint const & p2) 40 | { 41 | return (p1.x==p2.x) && (p1.y==p2.y); 42 | } 43 | 44 | inline bool operator != (SPoint const & p1, SPoint const & p2) 45 | { 46 | return !(p1==p2); 47 | } 48 | 49 | inline SPoint operator - (SPoint const & p1, SPoint const & p2) 50 | { 51 | return {p1.x-p2.x, p1.y-p2.y}; 52 | } 53 | 54 | inline SPoint operator + (SPoint const & p1, SPoint const & p2) 55 | { 56 | return {p2.x+p1.x, p2.y+p1.y}; 57 | } 58 | 59 | inline SPoint operator / (SPoint const & p, double const & d) 60 | { 61 | return {p.x/d, p.y/d}; 62 | } 63 | 64 | inline SPoint operator * (SPoint const & p, double const & d) 65 | { 66 | return {p.x*d, p.y*d}; 67 | } 68 | 69 | 70 | struct SFleck 71 | { 72 | double x{0}, y{0}, r{0}; 73 | template 74 | SFleck operator -= (P const & p) 75 | { 76 | x -= p.x; 77 | y -= p.y; 78 | return *this; 79 | } 80 | template 81 | SFleck operator += (P const & p) 82 | { 83 | x += p.x; 84 | y += p.y; 85 | return *this; 86 | } 87 | template 88 | SFleck operator = (P const & p) 89 | { 90 | x = p.x; 91 | y = p.y; 92 | return *this; 93 | } 94 | }; 95 | 96 | struct SColor 97 | { 98 | double r{0},g{0},b{0}; 99 | }; 100 | 101 | using VPoints = std::vector; 102 | using VFlecken = std::vector; 103 | 104 | // the first argument can be anything having the members x and y 105 | // a Gtk event, a SFleck or whatever 106 | template 107 | double Distance( P const & a, T const & b ) 108 | { 109 | return sqrt( pow((a.x-b.x),2) + pow((a.y-b.y),2) ); 110 | } 111 | 112 | 113 | class CCanvas : public Gtk::DrawingArea 114 | { 115 | public: 116 | CCanvas() 117 | { 118 | add_events(Gdk::BUTTON_PRESS_MASK | Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK); 119 | add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK); 120 | add_events(Gdk::BUTTON1_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK); 121 | add_events(Gdk::KEY_PRESS_MASK | Gdk::KEY_RELEASE_MASK); 122 | 123 | m_fSlot[0] = sigc::bind(sigc::mem_fun(*this, &CCanvas::AnimateBi), 0); 124 | m_fSlot[1] = sigc::bind(sigc::mem_fun(*this, &CCanvas::AnimateRot), 0); 125 | m_afConnections[0] = Glib::signal_timeout().connect(m_fSlot[0], 40); 126 | m_afConnections[1] = Glib::signal_timeout().connect(m_fSlot[1], 40); 127 | } 128 | 129 | virtual ~CCanvas() 130 | { 131 | m_afConnections[0].disconnect(); 132 | m_afConnections[1].disconnect(); 133 | }; 134 | 135 | protected: 136 | // Override default signal handler: 137 | bool on_draw(const Cairo::RefPtr& cr) override; 138 | bool on_scroll_event(GdkEventScroll *event) override; 139 | bool on_button_press_event(GdkEventButton * event) override; 140 | bool on_motion_notify_event(GdkEventMotion *event) override; 141 | bool on_button_release_event(GdkEventButton* release_event) override; 142 | 143 | bool Collision(SPoint const & tPoint); 144 | 145 | SPoint m_tCtxSize { .0,.0 }; 146 | double m_dScale { 1.0 }; 147 | 148 | bool m_bShiftInit { true }; 149 | SPoint m_tShift { .0,.0 }; 150 | SPoint m_tEventPress { .0,.0 }; 151 | SPoint m_tEventRelease{ .0,.0 }; 152 | SPoint m_tShiftStart { .0,.0 }; 153 | 154 | 155 | SPoint m_tMousePos; 156 | SColor m_tMouseColor{ .5,.5,.5 }; 157 | VPoints m_vMouseTrail; 158 | VFlecken m_vFlecken { {30,30,20}, {300,300,50}, {500,200,40}, 159 | {40,50,25}, {240,320,30}, {580,270,45} }; 160 | 161 | struct SCollision 162 | { 163 | SPoint tWhere { .0,.0 }; 164 | SPoint tOffset { .0,.0 }; 165 | enum class EWhat 166 | { 167 | none, // there was no collision 168 | Fleck, // move a Fleck 169 | Line, // move a Line 170 | }eWhat {EWhat::none}; 171 | int nIndex {0}; // O: L1, L2, L3 172 | int nSubIx {0}; // L: P1, PM, P2 173 | } m_tCollision; 174 | 175 | // animation 176 | bool m_bAnimate{true}; 177 | bool m_bAnimateLeftBi{true}; 178 | bool m_bAnimateLeftRot{true}; 179 | 180 | // animation clock 181 | double m_dAnimatorBi{0}; // $m_tAnimator animation parameter 182 | double m_dAnimatorRot{0}; // $m_tAnimator animation parameter 183 | double m_dAnimStep{0}; // intermediate animation parameter 184 | sigc::slot m_fSlot[2]; 185 | sigc::connection m_afConnections[2]; 186 | 187 | double m_dAnimate {0.0125}; // animation steps width 188 | double const m_dAnimateMax{0.0250}; // maximal animation step width 189 | double const m_dAnimateMin{0.0025}; // minimal animation step width 190 | 191 | bool AnimateRot(int c) // rotation 192 | { 193 | if (!m_bAnimate) return true; 194 | if (m_bAnimateLeftRot) 195 | m_dAnimatorRot = (m_dAnimatorRot <= m_dAnimate) ? 1 : m_dAnimatorRot-m_dAnimate; 196 | else 197 | m_dAnimatorRot = (m_dAnimatorRot >=1-m_dAnimate) ? 0 : m_dAnimatorRot+m_dAnimate; 198 | queue_draw(); 199 | return true; 200 | } 201 | 202 | bool AnimateBi(int c) // bidirectional 203 | { 204 | if (!m_bAnimate) return true; 205 | if (m_bAnimateLeftBi) 206 | m_dAnimatorBi -= m_dAnimate; 207 | else 208 | m_dAnimatorBi += m_dAnimate; 209 | if (m_dAnimatorBi <= 0) m_bAnimateLeftBi = false; 210 | if (m_dAnimatorBi >= 1) m_bAnimateLeftBi = true; 211 | queue_draw(); 212 | return true; 213 | } 214 | }; // CCanvas 215 | -------------------------------------------------------------------------------- /d-text/canvas.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | 7 | struct SPoint 8 | { 9 | SPoint() = default; 10 | SPoint(SPoint const & src) = default; 11 | template 12 | SPoint(T const & x, T const & y) : x(x), y(y) {} 13 | template 14 | SPoint(T const & t) : x(t.x), y(t.y) {} 15 | double x{0}, y{0}; 16 | template 17 | SPoint operator = (P const & p) 18 | { 19 | x = p.x; 20 | y = p.y; 21 | return *this; 22 | } 23 | template 24 | SPoint operator -= (P const & p) 25 | { 26 | x -= p.x; 27 | y -= p.y; 28 | return *this; 29 | } 30 | template 31 | SPoint operator += (P const & p) 32 | { 33 | x += p.x; 34 | y += p.y; 35 | return *this; 36 | } 37 | }; 38 | 39 | inline bool operator == (SPoint const & p1, SPoint const & p2) 40 | { 41 | return (p1.x==p2.x) && (p1.y==p2.y); 42 | } 43 | 44 | inline bool operator != (SPoint const & p1, SPoint const & p2) 45 | { 46 | return !(p1==p2); 47 | } 48 | 49 | inline SPoint operator - (SPoint const & p1, SPoint const & p2) 50 | { 51 | return {p1.x-p2.x, p1.y-p2.y}; 52 | } 53 | 54 | inline SPoint operator + (SPoint const & p1, SPoint const & p2) 55 | { 56 | return {p2.x+p1.x, p2.y+p1.y}; 57 | } 58 | 59 | inline SPoint operator / (SPoint const & p, double const & d) 60 | { 61 | return {p.x/d, p.y/d}; 62 | } 63 | 64 | inline SPoint operator * (SPoint const & p, double const & d) 65 | { 66 | return {p.x*d, p.y*d}; 67 | } 68 | 69 | 70 | struct SFleck 71 | { 72 | double x{0}, y{0}, r{0}; 73 | template 74 | SFleck operator -= (P const & p) 75 | { 76 | x -= p.x; 77 | y -= p.y; 78 | return *this; 79 | } 80 | template 81 | SFleck operator += (P const & p) 82 | { 83 | x += p.x; 84 | y += p.y; 85 | return *this; 86 | } 87 | template 88 | SFleck operator = (P const & p) 89 | { 90 | x = p.x; 91 | y = p.y; 92 | return *this; 93 | } 94 | }; 95 | 96 | struct SColor 97 | { 98 | double r{0},g{0},b{0}; 99 | }; 100 | 101 | using VPoints = std::vector; 102 | using VFlecken = std::vector; 103 | 104 | // the first argument can be anything having the members x and y 105 | // a Gtk event, a SFleck or whatever 106 | template 107 | double Distance( P const & a, T const & b ) 108 | { 109 | return sqrt( pow((a.x-b.x),2) + pow((a.y-b.y),2) ); 110 | } 111 | 112 | 113 | class CCanvas : public Gtk::DrawingArea 114 | { 115 | public: 116 | CCanvas() 117 | { 118 | add_events(Gdk::BUTTON_PRESS_MASK | Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK); 119 | add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK); 120 | add_events(Gdk::BUTTON1_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK); 121 | add_events(Gdk::KEY_PRESS_MASK | Gdk::KEY_RELEASE_MASK); 122 | 123 | m_fSlot[0] = sigc::bind(sigc::mem_fun(*this, &CCanvas::AnimateBi), 0); 124 | m_fSlot[1] = sigc::bind(sigc::mem_fun(*this, &CCanvas::AnimateRot), 0); 125 | m_afConnections[0] = Glib::signal_timeout().connect(m_fSlot[0], 40); 126 | m_afConnections[1] = Glib::signal_timeout().connect(m_fSlot[1], 40); 127 | } 128 | 129 | virtual ~CCanvas() 130 | { 131 | m_afConnections[0].disconnect(); 132 | m_afConnections[1].disconnect(); 133 | }; 134 | 135 | protected: 136 | // Override default signal handler: 137 | bool on_draw(const Cairo::RefPtr& cr) override; 138 | bool on_scroll_event(GdkEventScroll *event) override; 139 | bool on_button_press_event(GdkEventButton * event) override; 140 | bool on_motion_notify_event(GdkEventMotion *event) override; 141 | bool on_button_release_event(GdkEventButton* release_event) override; 142 | 143 | bool Collision(SPoint const & tPoint); 144 | 145 | SPoint m_tCtxSize { .0,.0 }; 146 | double m_dScale { 1.0 }; 147 | 148 | bool m_bShiftInit { true }; 149 | SPoint m_tShift { .0,.0 }; 150 | SPoint m_tEventPress { .0,.0 }; 151 | SPoint m_tEventRelease{ .0,.0 }; 152 | SPoint m_tShiftStart { .0,.0 }; 153 | 154 | 155 | SPoint m_tMousePos; 156 | SColor m_tMouseColor{ .5,.5,.5 }; 157 | VPoints m_vMouseTrail; 158 | VFlecken m_vFlecken { {30,30,20}, {300,300,50}, {500,200,40}, 159 | {40,50,25}, {240,320,30}, {580,270,45} }; 160 | 161 | struct SCollision 162 | { 163 | SPoint tWhere { .0,.0 }; 164 | SPoint tOffset { .0,.0 }; 165 | enum class EWhat 166 | { 167 | none, // there was no collision 168 | Fleck, // move a Fleck 169 | Line, // move a Line 170 | }eWhat {EWhat::none}; 171 | int nIndex {0}; // O: L1, L2, L3 172 | int nSubIx {0}; // L: P1, PM, P2 173 | } m_tCollision; 174 | 175 | // animation 176 | bool m_bAnimate{true}; 177 | bool m_bAnimateLeftBi{true}; 178 | bool m_bAnimateLeftRot{true}; 179 | 180 | // animation clock 181 | double m_dAnimatorBi{0}; // $m_tAnimator animation parameter 182 | double m_dAnimatorRot{0}; // $m_tAnimator animation parameter 183 | double m_dAnimStep{0}; // intermediate animation parameter 184 | sigc::slot m_fSlot[2]; 185 | sigc::connection m_afConnections[2]; 186 | 187 | double m_dAnimate {0.0125}; // animation steps width 188 | double const m_dAnimateMax{0.0250}; // maximal animation step width 189 | double const m_dAnimateMin{0.0025}; // minimal animation step width 190 | 191 | bool AnimateRot(int c) // rotation 192 | { 193 | if (!m_bAnimate) return true; 194 | if (m_bAnimateLeftRot) 195 | m_dAnimatorRot = (m_dAnimatorRot <= m_dAnimate) ? 1 : m_dAnimatorRot-m_dAnimate; 196 | else 197 | m_dAnimatorRot = (m_dAnimatorRot >=1-m_dAnimate) ? 0 : m_dAnimatorRot+m_dAnimate; 198 | queue_draw(); 199 | return true; 200 | } 201 | 202 | bool AnimateBi(int c) // bidirectional 203 | { 204 | if (!m_bAnimate) return true; 205 | if (m_bAnimateLeftBi) 206 | m_dAnimatorBi -= m_dAnimate; 207 | else 208 | m_dAnimatorBi += m_dAnimate; 209 | if (m_dAnimatorBi <= 0) m_bAnimateLeftBi = false; 210 | if (m_dAnimatorBi >= 1) m_bAnimateLeftBi = true; 211 | queue_draw(); 212 | return true; 213 | } 214 | 215 | }; // CCanvas 216 | -------------------------------------------------------------------------------- /m-mass-animation/canvas.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | 7 | struct SPoint 8 | { 9 | SPoint() = default; 10 | SPoint(SPoint const & src) = default; 11 | template 12 | SPoint(T const & x, T const & y) : x(x), y(y) {} 13 | template 14 | SPoint(T const & t) : x(t.x), y(t.y) {} 15 | double x{0}, y{0}; 16 | template 17 | SPoint operator = (P const & p) 18 | { 19 | x = p.x; 20 | y = p.y; 21 | return *this; 22 | } 23 | template 24 | SPoint operator -= (P const & p) 25 | { 26 | x -= p.x; 27 | y -= p.y; 28 | return *this; 29 | } 30 | template 31 | SPoint operator += (P const & p) 32 | { 33 | x += p.x; 34 | y += p.y; 35 | return *this; 36 | } 37 | }; 38 | 39 | inline bool operator == (SPoint const & p1, SPoint const & p2) 40 | { 41 | return (p1.x==p2.x) && (p1.y==p2.y); 42 | } 43 | 44 | inline bool operator != (SPoint const & p1, SPoint const & p2) 45 | { 46 | return !(p1==p2); 47 | } 48 | 49 | inline SPoint operator - (SPoint const & p1, SPoint const & p2) 50 | { 51 | return {p1.x-p2.x, p1.y-p2.y}; 52 | } 53 | 54 | inline SPoint operator + (SPoint const & p1, SPoint const & p2) 55 | { 56 | return {p2.x+p1.x, p2.y+p1.y}; 57 | } 58 | 59 | inline SPoint operator / (SPoint const & p, double const & d) 60 | { 61 | return {p.x/d, p.y/d}; 62 | } 63 | 64 | inline SPoint operator * (SPoint const & p, double const & d) 65 | { 66 | return {p.x*d, p.y*d}; 67 | } 68 | 69 | 70 | struct SFleck 71 | { 72 | double x{0}, y{0}, r{0}; 73 | template 74 | SFleck operator -= (P const & p) 75 | { 76 | x -= p.x; 77 | y -= p.y; 78 | return *this; 79 | } 80 | template 81 | SFleck operator += (P const & p) 82 | { 83 | x += p.x; 84 | y += p.y; 85 | return *this; 86 | } 87 | template 88 | SFleck operator = (P const & p) 89 | { 90 | x = p.x; 91 | y = p.y; 92 | return *this; 93 | } 94 | }; 95 | 96 | struct SColor 97 | { 98 | double r{0},g{0},b{0}; 99 | }; 100 | 101 | using VPoints = std::vector; 102 | using VFlecken = std::vector; 103 | 104 | // the first argument can be anything having the members x and y 105 | // a Gtk event, a SFleck or whatever 106 | template 107 | double Distance( P const & a, T const & b ) 108 | { 109 | return sqrt( pow((a.x-b.x),2) + pow((a.y-b.y),2) ); 110 | } 111 | 112 | 113 | class CCanvas : public Gtk::DrawingArea 114 | { 115 | public: 116 | CCanvas() 117 | { 118 | add_events(Gdk::BUTTON_PRESS_MASK | Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK); 119 | add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK); 120 | add_events(Gdk::BUTTON1_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK); 121 | add_events(Gdk::KEY_PRESS_MASK | Gdk::KEY_RELEASE_MASK); 122 | 123 | m_fSlot[0] = sigc::bind(sigc::mem_fun(*this, &CCanvas::AnimateBi), 0); 124 | m_fSlot[1] = sigc::bind(sigc::mem_fun(*this, &CCanvas::AnimateRot), 0); 125 | m_afConnections[0] = Glib::signal_timeout().connect(m_fSlot[0], 5); 126 | m_afConnections[1] = Glib::signal_timeout().connect(m_fSlot[1], 5); 127 | for (double x{-570}; x < 570; x+=40) 128 | for (double y{-570}; y < 570; y+=40) 129 | m_vFlecken.emplace_back( SFleck{x,y,20} ); 130 | } 131 | 132 | virtual ~CCanvas() 133 | { 134 | m_afConnections[0].disconnect(); 135 | m_afConnections[1].disconnect(); 136 | }; 137 | 138 | protected: 139 | // Override default signal handler: 140 | bool on_draw(const Cairo::RefPtr& cr) override; 141 | bool on_scroll_event(GdkEventScroll *event) override; 142 | bool on_button_press_event(GdkEventButton * event) override; 143 | bool on_motion_notify_event(GdkEventMotion *event) override; 144 | bool on_button_release_event(GdkEventButton* release_event) override; 145 | 146 | bool Collision(SPoint const & tPoint); 147 | 148 | SPoint m_tCtxSize { .0,.0 }; 149 | double m_dScale { 1.0 }; 150 | 151 | bool m_bShiftInit { true }; 152 | SPoint m_tShift { .0,.0 }; 153 | SPoint m_tEventPress { .0,.0 }; 154 | SPoint m_tEventRelease{ .0,.0 }; 155 | SPoint m_tShiftStart { .0,.0 }; 156 | 157 | 158 | SPoint m_tMousePos; 159 | SColor m_tMouseColor{ .5,.5,.5 }; 160 | VPoints m_vMouseTrail; 161 | VFlecken m_vFlecken { }; 162 | 163 | struct SCollision 164 | { 165 | SPoint tWhere { .0,.0 }; 166 | SPoint tOffset { .0,.0 }; 167 | enum class EWhat 168 | { 169 | none, // there was no collision 170 | Fleck, // move a Fleck 171 | Line, // move a Line 172 | }eWhat {EWhat::none}; 173 | int nIndex {0}; // O: L1, L2, L3 174 | int nSubIx {0}; // L: P1, PM, P2 175 | } m_tCollision; 176 | 177 | // animation 178 | bool m_bAnimate{true}; 179 | bool m_bAnimateLeftBi{true}; 180 | bool m_bAnimateLeftRot{true}; 181 | 182 | // animation clock 183 | double m_dAnimatorBi{0}; // $m_tAnimator animation parameter 184 | double m_dAnimatorRot{0}; // $m_tAnimator animation parameter 185 | double m_dAnimStep{0}; // intermediate animation parameter 186 | sigc::slot m_fSlot[2]; 187 | sigc::connection m_afConnections[2]; 188 | 189 | double m_dAnimate {0.0025}; // animation steps width 190 | double const m_dAnimateMax{0.0250}; // maximal animation step width 191 | double const m_dAnimateMin{0.0025}; // minimal animation step width 192 | 193 | bool AnimateRot(int c) // rotation 194 | { 195 | if (!m_bAnimate) return true; 196 | if (m_bAnimateLeftRot) 197 | m_dAnimatorRot = (m_dAnimatorRot <= m_dAnimate) ? 1 : m_dAnimatorRot-m_dAnimate; 198 | else 199 | m_dAnimatorRot = (m_dAnimatorRot >=1-m_dAnimate) ? 0 : m_dAnimatorRot+m_dAnimate; 200 | queue_draw(); 201 | return true; 202 | } 203 | 204 | bool AnimateBi(int c) // bidirectional 205 | { 206 | if (!m_bAnimate) return true; 207 | if (m_bAnimateLeftBi) 208 | m_dAnimatorBi -= m_dAnimate; 209 | else 210 | m_dAnimatorBi += m_dAnimate; 211 | if (m_dAnimatorBi <= 0) m_bAnimateLeftBi = false; 212 | if (m_dAnimatorBi >= 1) m_bAnimateLeftBi = true; 213 | queue_draw(); 214 | return true; 215 | } 216 | }; // CCanvas 217 | -------------------------------------------------------------------------------- /i-4-bar-analytics/typesNmath.h: -------------------------------------------------------------------------------- 1 | #ifndef TYPES_AND_MATH_H 2 | #define TYPES_AND_MATH_H 3 | 4 | 5 | 6 | struct SPoint 7 | { 8 | SPoint() = default; 9 | SPoint(SPoint const & src) = default; 10 | template 11 | SPoint(T const & x, T const & y) : x(x), y(y) {} 12 | template 13 | SPoint(T const & t) : x(t.x), y(t.y) {} 14 | double x{0}, y{0}; 15 | template 16 | SPoint operator = (P const & p) 17 | { 18 | x = p.x; 19 | y = p.y; 20 | return *this; 21 | } 22 | template 23 | SPoint operator -= (P const & p) 24 | { 25 | x -= p.x; 26 | y -= p.y; 27 | return *this; 28 | } 29 | template 30 | SPoint operator += (P const & p) 31 | { 32 | x += p.x; 33 | y += p.y; 34 | return *this; 35 | } 36 | }; // struct SPoint 37 | 38 | inline bool operator == (SPoint const & p1, SPoint const & p2) 39 | { 40 | return (p1.x==p2.x) && (p1.y==p2.y); 41 | } 42 | 43 | inline bool operator != (SPoint const & p1, SPoint const & p2) 44 | { 45 | return !(p1==p2); 46 | } 47 | 48 | inline SPoint operator - (SPoint const & p1, SPoint const & p2) 49 | { 50 | return {p1.x-p2.x, p1.y-p2.y}; 51 | } 52 | 53 | inline SPoint operator + (SPoint const & p1, SPoint const & p2) 54 | { 55 | return {p2.x+p1.x, p2.y+p1.y}; 56 | } 57 | 58 | inline SPoint operator / (SPoint const & p, double const & d) 59 | { 60 | return {p.x/d, p.y/d}; 61 | } 62 | 63 | inline SPoint operator * (SPoint const & p, double const & d) 64 | { 65 | return {p.x*d, p.y*d}; 66 | } 67 | 68 | struct SLine 69 | { 70 | SPoint a{0,0}; 71 | SPoint b{0,0}; 72 | }; 73 | 74 | using SEbene = SLine; 75 | 76 | struct SRect 77 | { 78 | SPoint p{0,0}; 79 | SPoint s{0,0}; 80 | }; 81 | 82 | struct SFrame 83 | { 84 | SPoint p{0,0}; 85 | SPoint s{0,0}; 86 | }; 87 | 88 | struct SUmkreis 89 | { 90 | double r{0}; 91 | SPoint p{.0,.0}; 92 | }; 93 | 94 | struct SLineWidth 95 | { 96 | double w{1}; 97 | }; 98 | 99 | struct SColor 100 | { 101 | double r{0},g{0},b{0}; 102 | }; 103 | 104 | struct SHit 105 | { 106 | bool bHit{false}; 107 | SPoint tOffset{.0,.0}; 108 | }; 109 | 110 | struct SButton 111 | { 112 | double x{0},y{0},w{0},h{0}; 113 | std::string const sTitle; 114 | std::string const sFunct; 115 | 116 | SButton (double const & x, double const & y, 117 | double const & w, double const & h, 118 | std::string const t, 119 | std::string const f) 120 | : x(x), y(y), w(w), h(h), sTitle(t), sFunct(f) {} 121 | 122 | bool Collision(SPoint const & p) const 123 | { 124 | return ( p.x > x && p.x < x+w && p.y > y && p.y < y+h ); 125 | } 126 | }; 127 | 128 | using VButtons = std::vector; 129 | using VPoints = std::vector; 130 | 131 | 132 | SColor constexpr BLACK {.0,.0,.0}; 133 | SColor constexpr DARKRED {.6,.0,.0}; 134 | SColor constexpr DARKGREEN {.0,.6,.0}; 135 | SColor constexpr DARKBLUE {.0,.0,.6}; 136 | SColor constexpr DARKCYAN {.0,.6,.6}; 137 | SColor constexpr DARKMAGENTA{.6,.0,.6}; 138 | SColor constexpr DARKYELLOW {.6,.6,.0}; 139 | SColor constexpr GRAY {.6,.6,.6}; 140 | SColor constexpr RED {1,0,0}; 141 | SColor constexpr GREEN {0,1,0}; 142 | SColor constexpr BLUE {0,0,1}; 143 | SColor constexpr CYAN {0,1,1}; 144 | SColor constexpr MAGENTA {1,0,1}; 145 | SColor constexpr YELLOW {1,1,0}; 146 | SColor constexpr WHITE {1,1,1}; 147 | 148 | 149 | // calculation helpers 150 | 151 | // angel at triangle point a of triangle a-b-c 152 | inline double Alpha(double const & a, double const & b, double const & c) 153 | { 154 | auto cosinus = (pow(b,2)+pow(c,2)-pow(a,2)) / (2*b*c); 155 | if ((cosinus<-1)||(cosinus>1)) 156 | { 157 | return 0.0; 158 | } 159 | return acos( cosinus ); 160 | } 161 | 162 | inline double VectorSlope(SPoint const & a, SPoint const & b) 163 | { 164 | auto const dba = SPoint{ b.x-a.x, b.y-a.y }; 165 | double dbax{dba.x}; 166 | if ( dba.x < 0 && dba.x > -.00001) dbax = -.00001; 167 | if ( dba.x > 0 && dba.x < .00001) dbax = .00001; 168 | auto sba = atan(dba.y / dbax); 169 | 170 | if ( (dba.x>0) && (dba.y<0) ) 171 | sba = -sba; 172 | else if ( (dba.x<0) && (dba.y<0) ) 173 | sba = M_PI - sba; 174 | else if ( (dba.x<0) && (dba.y>0) ) 175 | sba = M_PI - sba; 176 | else if ( (dba.x>0) && (dba.y>0) ) 177 | sba = 2*M_PI - sba; 178 | 179 | return sba; 180 | } 181 | 182 | inline double VectorDiff(SPoint const & a, SPoint const & b, SPoint const & c) 183 | { 184 | auto slb = VectorSlope(a,b); 185 | auto slc = VectorSlope(a,c); 186 | return slc - slb; 187 | } 188 | 189 | template 190 | double Distance( P const & a, T const & b ) 191 | { 192 | return sqrt( pow((a.x-b.x),2) + pow((a.y-b.y),2) ); 193 | } 194 | 195 | 196 | 197 | inline SEbene FixedLenLine(SLine & roL, double const & crnLen, bool const & crbFirst) 198 | { 199 | auto const dx { roL.a.x - roL.b.x }; 200 | auto const dy { roL.a.y - roL.b.y }; 201 | auto const nLen { sqrt(dx*dx + dy*dy) }; 202 | auto const q { (double)crnLen / ((nLen!=0)?nLen:1) }; 203 | if (crbFirst) 204 | { 205 | roL.b.x = roL.a.x - dx*q; 206 | roL.b.y = roL.a.y - dy*q; 207 | } 208 | else 209 | { 210 | roL.a.x = roL.b.x + dx*q; 211 | roL.a.y = roL.b.y + dy*q; 212 | } 213 | return roL; 214 | } // void FixedLenLine(... 215 | 216 | 217 | 218 | inline SPoint Intersection(SLine const & E1, SLine const & E2) 219 | { 220 | auto const dx1 { E1.b.x - E1.a.x }; 221 | auto const dx2 { E2.b.x - E2.a.x }; 222 | 223 | auto const m1 { (E1.b.y - E1.a.y) / ((dx1==0)?1e-9:dx1) }; // Steigungen ermitteln 224 | auto const m2 { (E2.b.y - E2.a.y) / ((dx2==0)?1e-9:dx2) }; 225 | 226 | // if (ROUND(m1,MAX_ACCURACY)==ROUND(m2,MAX_ACCURACY)) return false; // Geraden sind parallel 227 | 228 | auto const n1 { E1.a.y - (m1*E1.a.x) }; // Abstände von X-Achse ermitteln 229 | auto const n2 { E2.a.y - (m2*E2.a.x) }; 230 | 231 | auto const x { (n2-n1)/(m1-m2) }; // Schnittpunktkoordinate berechnen 232 | auto const y { m1*x+n1 }; 233 | 234 | return { x, y }; 235 | } // Intersection 236 | 237 | 238 | inline SLine Perpendicle(SLine const & l) 239 | { 240 | auto const dx = (l.b.x - l.a.x)/2.0; 241 | auto const dy = (l.b.y - l.a.y)/2.0; 242 | 243 | SLine I{ {l.b.x - dy - dx, 244 | l.b.y + dx - dy}, 245 | {l.b.x + dy - dx, 246 | l.b.y - dx - dy} }; 247 | 248 | return std::move(I); 249 | } 250 | 251 | inline SPoint PointMirror(SPoint const & p, SLine const & m) 252 | { 253 | auto const dx = (m.b.x - m.a.x)/2.0; 254 | auto const dy = (m.b.y - m.a.y)/2.0; 255 | 256 | SLine I{ {p.x - dy, 257 | p.y + dx}, 258 | {p.x + dy, 259 | p.y - dx} }; 260 | 261 | auto const S { Intersection(m, I) }; 262 | auto const mx { (m.b.x + m.a.x)/2.0 }; 263 | auto const my { (m.b.y + m.a.y)/2.0 }; 264 | 265 | return { S.x + (S.x - p.x), S.y + (S.y - p.y) }; 266 | } 267 | 268 | inline SPoint Polpunkt(SEbene const & E1, SEbene const & E2) 269 | { 270 | SEbene const L1{ E1.a, E2.a }; 271 | auto const La{ Perpendicle(L1) }; 272 | 273 | SEbene const L2{ E1.b, E2.b }; 274 | auto const Lb{ Perpendicle(L2) }; 275 | 276 | return std::move(Intersection(La, Lb)); 277 | } 278 | 279 | inline SUmkreis Umkreis( SPoint const & P1, SPoint const & P2, SPoint const & P3 ) 280 | { 281 | SLine const L1{{P1.x, P1.y},{P2.x, P2.y}}; 282 | auto const La{ Perpendicle(L1) }; 283 | 284 | SLine const L2{{P1.x, P1.y},{P3.x, P3.y}}; 285 | auto const Lb{ Perpendicle(L2) }; 286 | 287 | auto const M{Intersection(La, Lb)}; 288 | auto const R{sqrt( (double)(M.x - L1.a.x)*(M.x - L1.a.x) + (M.y - L1.a.y)*(M.y - L1.a.y) )}; 289 | 290 | return { R, M }; 291 | } 292 | 293 | 294 | // TYPES_AND_MATH_H 295 | #endif 296 | -------------------------------------------------------------------------------- /h-3-lagen-synthese/typesNmath.h: -------------------------------------------------------------------------------- 1 | #ifndef TYPES_AND_MATH_H 2 | #define TYPES_AND_MATH_H 3 | 4 | 5 | 6 | struct SPoint 7 | { 8 | SPoint() = default; 9 | SPoint(SPoint const & src) = default; 10 | template 11 | SPoint(T const & x, T const & y) : x(x), y(y) {} 12 | template 13 | SPoint(T const & t) : x(t.x), y(t.y) {} 14 | double x{0}, y{0}; 15 | template 16 | SPoint operator = (P const & p) 17 | { 18 | x = p.x; 19 | y = p.y; 20 | return *this; 21 | } 22 | template 23 | SPoint operator -= (P const & p) 24 | { 25 | x -= p.x; 26 | y -= p.y; 27 | return *this; 28 | } 29 | template 30 | SPoint operator += (P const & p) 31 | { 32 | x += p.x; 33 | y += p.y; 34 | return *this; 35 | } 36 | }; // struct SPoint 37 | 38 | inline bool operator == (SPoint const & p1, SPoint const & p2) 39 | { 40 | return (p1.x==p2.x) && (p1.y==p2.y); 41 | } 42 | 43 | inline bool operator != (SPoint const & p1, SPoint const & p2) 44 | { 45 | return !(p1==p2); 46 | } 47 | 48 | inline SPoint operator - (SPoint const & p1, SPoint const & p2) 49 | { 50 | return {p1.x-p2.x, p1.y-p2.y}; 51 | } 52 | 53 | inline SPoint operator + (SPoint const & p1, SPoint const & p2) 54 | { 55 | return {p2.x+p1.x, p2.y+p1.y}; 56 | } 57 | 58 | inline SPoint operator / (SPoint const & p, double const & d) 59 | { 60 | return {p.x/d, p.y/d}; 61 | } 62 | 63 | inline SPoint operator * (SPoint const & p, double const & d) 64 | { 65 | return {p.x*d, p.y*d}; 66 | } 67 | 68 | struct SLine 69 | { 70 | SPoint a{0,0}; 71 | SPoint b{0,0}; 72 | }; 73 | 74 | using SEbene = SLine; 75 | 76 | struct SRect 77 | { 78 | SPoint p{0,0}; 79 | SPoint s{0,0}; 80 | }; 81 | 82 | struct SFrame 83 | { 84 | SPoint p{0,0}; 85 | SPoint s{0,0}; 86 | }; 87 | 88 | struct SUmkreis 89 | { 90 | double r{0}; 91 | SPoint p{.0,.0}; 92 | }; 93 | 94 | struct SLineWidth 95 | { 96 | double w{1}; 97 | }; 98 | 99 | struct SColor 100 | { 101 | double r{0},g{0},b{0}; 102 | }; 103 | 104 | struct SHit 105 | { 106 | bool bHit{false}; 107 | SPoint tOffset{.0,.0}; 108 | }; 109 | 110 | struct SButton 111 | { 112 | double x{0},y{0},w{0},h{0}; 113 | std::string const sTitle; 114 | std::string const sFunct; 115 | 116 | SButton (double const & x, double const & y, 117 | double const & w, double const & h, 118 | std::string const t, 119 | std::string const f) 120 | : x(x), y(y), w(w), h(h), sTitle(t), sFunct(f) {} 121 | 122 | bool Collision(SPoint const & p) const 123 | { 124 | return ( p.x > x && p.x < x+w && p.y > y && p.y < y+h ); 125 | } 126 | }; 127 | 128 | using VButtons = std::vector; 129 | using VPoints = std::vector; 130 | 131 | 132 | SColor constexpr BLACK {.0,.0,.0}; 133 | SColor constexpr DARKRED {.6,.0,.0}; 134 | SColor constexpr DARKGREEN {.0,.6,.0}; 135 | SColor constexpr DARKBLUE {.0,.0,.6}; 136 | SColor constexpr DARKCYAN {.0,.6,.6}; 137 | SColor constexpr DARKMAGENTA{.6,.0,.6}; 138 | SColor constexpr DARKYELLOW {.6,.6,.0}; 139 | SColor constexpr GRAY {.6,.6,.6}; 140 | SColor constexpr RED {1,0,0}; 141 | SColor constexpr GREEN {0,1,0}; 142 | SColor constexpr BLUE {0,0,1}; 143 | SColor constexpr CYAN {0,1,1}; 144 | SColor constexpr MAGENTA {1,0,1}; 145 | SColor constexpr YELLOW {1,1,0}; 146 | SColor constexpr WHITE {1,1,1}; 147 | 148 | 149 | // calculation helpers 150 | 151 | // angel at triangle point a of triangle a-b-c 152 | inline double Alpha(double const & a, double const & b, double const & c) 153 | { 154 | auto cosinus = (pow(b,2)+pow(c,2)-pow(a,2)) / (2*b*c); 155 | if ((cosinus<-1)||(cosinus>1)) 156 | { 157 | return 0.0; 158 | } 159 | return acos( cosinus ); 160 | } 161 | 162 | inline double VectorSlope(SPoint const & a, SPoint const & b) 163 | { 164 | auto const dba = SPoint{ b.x-a.x, b.y-a.y }; 165 | double dbax{dba.x}; 166 | if ( dba.x < 0 && dba.x > -.00001) dbax = -.00001; 167 | if ( dba.x > 0 && dba.x < .00001) dbax = .00001; 168 | auto sba = atan(dba.y / dbax); 169 | 170 | if ( (dba.x>0) && (dba.y<0) ) 171 | sba = -sba; 172 | else if ( (dba.x<0) && (dba.y<0) ) 173 | sba = M_PI - sba; 174 | else if ( (dba.x<0) && (dba.y>0) ) 175 | sba = M_PI - sba; 176 | else if ( (dba.x>0) && (dba.y>0) ) 177 | sba = 2*M_PI - sba; 178 | 179 | return sba; 180 | } 181 | 182 | inline double VectorDiff(SPoint const & a, SPoint const & b, SPoint const & c) 183 | { 184 | auto slb = VectorSlope(a,b); 185 | auto slc = VectorSlope(a,c); 186 | return slc - slb; 187 | } 188 | 189 | template 190 | double Distance( P const & a, T const & b ) 191 | { 192 | return sqrt( pow((a.x-b.x),2) + pow((a.y-b.y),2) ); 193 | } 194 | 195 | 196 | 197 | inline SEbene FixedLenLine(SLine & roL, double const & crnLen, bool const & crbFirst) 198 | { 199 | auto const dx { roL.a.x - roL.b.x }; 200 | auto const dy { roL.a.y - roL.b.y }; 201 | auto const nLen { sqrt(dx*dx + dy*dy) }; 202 | auto const q { (double)crnLen / ((nLen!=0)?nLen:1) }; 203 | if (crbFirst) 204 | { 205 | roL.b.x = roL.a.x - dx*q; 206 | roL.b.y = roL.a.y - dy*q; 207 | } 208 | else 209 | { 210 | roL.a.x = roL.b.x + dx*q; 211 | roL.a.y = roL.b.y + dy*q; 212 | } 213 | return roL; 214 | } // void FixedLenLine(... 215 | 216 | 217 | 218 | inline SPoint Intersection(SLine const & E1, SLine const & E2) 219 | { 220 | auto const dx1 { E1.b.x - E1.a.x }; 221 | auto const dx2 { E2.b.x - E2.a.x }; 222 | 223 | auto const m1 { (E1.b.y - E1.a.y) / ((dx1==0)?1e-9:dx1) }; // Steigungen ermitteln 224 | auto const m2 { (E2.b.y - E2.a.y) / ((dx2==0)?1e-9:dx2) }; 225 | 226 | // if (ROUND(m1,MAX_ACCURACY)==ROUND(m2,MAX_ACCURACY)) return false; // Geraden sind parallel 227 | 228 | auto const n1 { E1.a.y - (m1*E1.a.x) }; // Abstände von X-Achse ermitteln 229 | auto const n2 { E2.a.y - (m2*E2.a.x) }; 230 | 231 | auto const x { (n2-n1)/(m1-m2) }; // Schnittpunktkoordinate berechnen 232 | auto const y { m1*x+n1 }; 233 | 234 | return { x, y }; 235 | } // Intersection 236 | 237 | 238 | inline SLine Perpendicle(SLine const & l) 239 | { 240 | auto const dx = (l.b.x - l.a.x)/2.0; 241 | auto const dy = (l.b.y - l.a.y)/2.0; 242 | 243 | SLine I{ {l.b.x - dy - dx, 244 | l.b.y + dx - dy}, 245 | {l.b.x + dy - dx, 246 | l.b.y - dx - dy} }; 247 | 248 | return std::move(I); 249 | } 250 | 251 | inline SPoint PointMirror(SPoint const & p, SLine const & m) 252 | { 253 | auto const dx = (m.b.x - m.a.x)/2.0; 254 | auto const dy = (m.b.y - m.a.y)/2.0; 255 | 256 | SLine I{ {p.x - dy, 257 | p.y + dx}, 258 | {p.x + dy, 259 | p.y - dx} }; 260 | 261 | auto const S { Intersection(m, I) }; 262 | auto const mx { (m.b.x + m.a.x)/2.0 }; 263 | auto const my { (m.b.y + m.a.y)/2.0 }; 264 | 265 | return { S.x + (S.x - p.x), S.y + (S.y - p.y) }; 266 | } 267 | 268 | inline SPoint Polpunkt(SEbene const & E1, SEbene const & E2) 269 | { 270 | SEbene const L1{ E1.a, E2.a }; 271 | auto const La{ Perpendicle(L1) }; 272 | 273 | SEbene const L2{ E1.b, E2.b }; 274 | auto const Lb{ Perpendicle(L2) }; 275 | 276 | return std::move(Intersection(La, Lb)); 277 | } 278 | 279 | inline SUmkreis Umkreis( SPoint const & P1, SPoint const & P2, SPoint const & P3 ) 280 | { 281 | SLine const L1{{P1.x, P1.y},{P2.x, P2.y}}; 282 | auto const La{ Perpendicle(L1) }; 283 | 284 | SLine const L2{{P1.x, P1.y},{P3.x, P3.y}}; 285 | auto const Lb{ Perpendicle(L2) }; 286 | 287 | auto const M{Intersection(La, Lb)}; 288 | auto const R{sqrt( (double)(M.x - L1.a.x)*(M.x - L1.a.x) + (M.y - L1.a.y)*(M.y - L1.a.y) )}; 289 | 290 | return { R, M }; 291 | } 292 | 293 | 294 | // TYPES_AND_MATH_H 295 | #endif 296 | -------------------------------------------------------------------------------- /i-4-bar-analytics/canvas.h: -------------------------------------------------------------------------------- 1 | #ifndef CCANVAS_H 2 | #define CCANVAS_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include "typesNmath.h" 9 | 10 | 11 | 12 | 13 | using CairoCtx = Cairo::RefPtr const &; 14 | 15 | 16 | // drawing primitives 17 | inline void LineWidth( CairoCtx cr, SLineWidth const & w, double const & s=1 ) 18 | { 19 | cr->set_line_width(w.w / ((s==0)?1:s)); 20 | } 21 | 22 | inline void Color( CairoCtx cr, SColor const & c ) 23 | { 24 | cr->set_source_rgb( c.r, c.g, c.b ); 25 | } 26 | 27 | inline void Color( CairoCtx cr, SColor const & c, double const & a ) 28 | { 29 | cr->set_source_rgba( c.r, c.g, c.b, a ); 30 | } 31 | 32 | inline void Color( CairoCtx cr, double const & r, double const & g, double const & b ) 33 | { 34 | cr->set_source_rgb( r, g, b ); 35 | } 36 | 37 | inline void Color( CairoCtx cr, double const & r, double const & g, double const & b, double const & a ) 38 | { 39 | cr->set_source_rgba( r, g, b, a ); 40 | } 41 | 42 | template 43 | void MoveTo(CairoCtx cr, P const & tPoint) 44 | { 45 | cr->move_to(tPoint.x, tPoint.y); 46 | } 47 | 48 | template 49 | void LineTo(CairoCtx cr, P const & tPoint) 50 | { 51 | cr->line_to(tPoint.x, tPoint.y); 52 | } 53 | 54 | template 55 | void Line(CairoCtx cr, S const & tPoint1, P const &... tPoints ) 56 | { 57 | MoveTo(cr, tPoint1); 58 | (LineTo(cr, tPoints), ...); 59 | cr->stroke(); 60 | } 61 | 62 | inline void Line(CairoCtx cr, SLine const & tLine ) 63 | { 64 | MoveTo(cr, tLine.a); 65 | LineTo(cr, tLine.b); 66 | cr->stroke(); 67 | } 68 | 69 | template 70 | void LineStrip(CairoCtx cr, C const & tPoints ) 71 | { 72 | bool b{true}; 73 | for ( auto const & a:tPoints ) 74 | { 75 | if (b) 76 | { 77 | MoveTo(cr, a); 78 | b = false; 79 | } 80 | else 81 | { 82 | LineTo(cr, a); 83 | } 84 | } 85 | cr->stroke(); 86 | } 87 | 88 | template 89 | void Polygon(CairoCtx cr, S const & tPoint1, P const &... tPoints ) 90 | { 91 | MoveTo(cr, tPoint1); 92 | (LineTo(cr, tPoints), ...); 93 | LineTo(cr, tPoint1); 94 | cr->fill(); 95 | } 96 | 97 | template 98 | void Polygon(CairoCtx cr, C const & tPoints ) 99 | { 100 | bool b{true}; 101 | for ( auto const & a:tPoints ) 102 | { 103 | if (b) MoveTo(cr, a); else LineTo(cr, a); 104 | } 105 | cr->fill(); 106 | } 107 | 108 | template 109 | void Circle(CairoCtx cr, P const & tPoint, double const & dRadius ) 110 | { 111 | cr->arc(tPoint.x, tPoint.y, dRadius, 0, 2*M_PI); 112 | cr->fill(); 113 | } 114 | 115 | template 116 | void Ring(CairoCtx cr, P const & tPoint, double const & dRadius ) 117 | { 118 | cr->arc(tPoint.x, tPoint.y, dRadius, 0, 2*M_PI); 119 | cr->stroke(); 120 | } 121 | 122 | template 123 | void Rectangle(CairoCtx cr, P const & tPoint, S const & tSize ) 124 | { 125 | cr->rectangle(tPoint.x, tPoint.y, tSize.x, tSize.y); 126 | cr->fill(); 127 | } 128 | 129 | template 130 | void Frame(CairoCtx cr, P const & tPoint, S const & tSize ) 131 | { 132 | cr->rectangle(tPoint.x, tPoint.y, tSize.x, tSize.y); 133 | cr->stroke(); 134 | } 135 | 136 | SPoint draw_text(CairoCtx cr, 137 | SPoint const & pos, 138 | std::string const & crsText, 139 | double const & dScale = 1.0, 140 | bool const & label = false); 141 | 142 | 143 | 144 | class CCanvas : public Gtk::DrawingArea 145 | { 146 | public: 147 | 148 | bool m_bButtonDown{ false }; 149 | 150 | void AnimateHlt() { m_bAnimate = !m_bAnimate; } 151 | void AnimateAdd() { m_dAnimate *= 1.1; m_dAnimate = (m_dAnimate>m_dAnimateMax)?m_dAnimateMax:m_dAnimate; } 152 | void AnimateSub() { m_dAnimate *= 0.9; m_dAnimate = (m_dAnimate& cr) override; 186 | bool on_scroll_event(GdkEventScroll *event) override; 187 | bool on_button_press_event(GdkEventButton * event) override; 188 | bool on_motion_notify_event(GdkEventMotion *event) override; 189 | bool on_button_release_event(GdkEventButton* release_event) override; 190 | 191 | bool Collision(SPoint const & tPoint); 192 | 193 | SPoint m_tCtxSize { .0,.0 }; 194 | double m_dScale { 1.0 }; 195 | 196 | bool m_bShiftInit { true }; 197 | SPoint m_tShift { .0,.0 }; 198 | SPoint m_tEventPress { .0,.0 }; 199 | SPoint m_tEventRelease{ .0,.0 }; 200 | SPoint m_tShiftStart { .0,.0 }; 201 | 202 | 203 | SPoint m_tMousePos; 204 | 205 | public: 206 | 207 | struct SCollision 208 | { 209 | SPoint tWhere { .0,.0 }; 210 | SPoint tOffset { .0,.0 }; 211 | double dRadius { 20.0 }; 212 | enum class EWhat 213 | { 214 | none, 215 | A0, A1, B0, B1, 216 | a, b, c, g 217 | }eWhat {EWhat::none}; 218 | } m_tCollision; 219 | 220 | protected: 221 | 222 | void AdjustAnimationToMechanism(); 223 | 224 | // animation 225 | bool m_bAnimate{true}; 226 | bool m_bAnimateLeft{true}; 227 | 228 | // animation clock 229 | double m_dAnimator{0}; // $m_tAnimator animation parameter 230 | double m_dAnimStep{0}; // intermediate animation parameter 231 | sigc::slot m_fSlot; 232 | sigc::connection m_afConnections; 233 | 234 | double m_dAnimate {0.0025}; // animation steps width 235 | double const m_dAnimateMax{0.0250}; // maximal animation step width 236 | double const m_dAnimateMin{0.0025}; // minimal animation step width 237 | 238 | 239 | bool Animate(int c) // rotation 240 | { 241 | if (!m_bAnimate) return true; 242 | if (m_bAnimateLeft) 243 | m_dAnimator = (m_dAnimator <= m_dAnimate) ? 1 : m_dAnimator-m_dAnimate; 244 | else 245 | m_dAnimator = (m_dAnimator >=1-m_dAnimate) ? 0 : m_dAnimator+m_dAnimate; 246 | queue_draw(); 247 | return true; 248 | } 249 | 250 | VButtons m_voButtons; // button bar 251 | std::string m_oButtonPressed{""}; // last pressed button 252 | 253 | char m_cNextDrop{' '}; 254 | 255 | }; // CCanvas 256 | 257 | // CCANVAS_H 258 | #endif 259 | -------------------------------------------------------------------------------- /e-ui-button-bar/canvas.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | 7 | struct SPoint 8 | { 9 | SPoint() = default; 10 | SPoint(SPoint const & src) = default; 11 | template 12 | SPoint(T const & x, T const & y) : x(x), y(y) {} 13 | template 14 | SPoint(T const & t) : x(t.x), y(t.y) {} 15 | double x{0}, y{0}; 16 | template 17 | SPoint operator = (P const & p) 18 | { 19 | x = p.x; 20 | y = p.y; 21 | return *this; 22 | } 23 | template 24 | SPoint operator -= (P const & p) 25 | { 26 | x -= p.x; 27 | y -= p.y; 28 | return *this; 29 | } 30 | template 31 | SPoint operator += (P const & p) 32 | { 33 | x += p.x; 34 | y += p.y; 35 | return *this; 36 | } 37 | }; 38 | 39 | inline bool operator == (SPoint const & p1, SPoint const & p2) 40 | { 41 | return (p1.x==p2.x) && (p1.y==p2.y); 42 | } 43 | 44 | inline bool operator != (SPoint const & p1, SPoint const & p2) 45 | { 46 | return !(p1==p2); 47 | } 48 | 49 | inline SPoint operator - (SPoint const & p1, SPoint const & p2) 50 | { 51 | return {p1.x-p2.x, p1.y-p2.y}; 52 | } 53 | 54 | inline SPoint operator + (SPoint const & p1, SPoint const & p2) 55 | { 56 | return {p2.x+p1.x, p2.y+p1.y}; 57 | } 58 | 59 | inline SPoint operator / (SPoint const & p, double const & d) 60 | { 61 | return {p.x/d, p.y/d}; 62 | } 63 | 64 | inline SPoint operator * (SPoint const & p, double const & d) 65 | { 66 | return {p.x*d, p.y*d}; 67 | } 68 | 69 | 70 | struct SFleck 71 | { 72 | double x{0}, y{0}, r{0}; 73 | template 74 | SFleck operator -= (P const & p) 75 | { 76 | x -= p.x; 77 | y -= p.y; 78 | return *this; 79 | } 80 | template 81 | SFleck operator += (P const & p) 82 | { 83 | x += p.x; 84 | y += p.y; 85 | return *this; 86 | } 87 | template 88 | SFleck operator = (P const & p) 89 | { 90 | x = p.x; 91 | y = p.y; 92 | return *this; 93 | } 94 | }; 95 | 96 | struct SColor 97 | { 98 | double r{0},g{0},b{0}; 99 | }; 100 | 101 | struct SButton 102 | { 103 | double x{0},y{0},w{0},h{0}; 104 | std::string const sTitle; 105 | std::string const sFunct; 106 | 107 | SButton (double const & x, double const & y, 108 | double const & w, double const & h, 109 | std::string const t, 110 | std::string const f) 111 | : x(x), y(y), w(w), h(h), sTitle(t), sFunct(f) {} 112 | 113 | bool Collision(SPoint const & p) const 114 | { 115 | return ( p.x > x && p.x < x+w && p.y > y && p.y < y+h ); 116 | } 117 | }; 118 | 119 | using VButtons = std::vector; 120 | 121 | using VPoints = std::vector; 122 | using VFlecken = std::vector; 123 | 124 | // the first argument can be anything having the members x and y 125 | // a Gtk event, a SFleck or whatever 126 | template 127 | double Distance( P const & a, T const & b ) 128 | { 129 | return sqrt( pow((a.x-b.x),2) + pow((a.y-b.y),2) ); 130 | } 131 | 132 | 133 | class CCanvas : public Gtk::DrawingArea 134 | { 135 | public: 136 | CCanvas() 137 | { 138 | add_events(Gdk::BUTTON_PRESS_MASK | Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK); 139 | add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK); 140 | add_events(Gdk::BUTTON1_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK); 141 | add_events(Gdk::KEY_PRESS_MASK | Gdk::KEY_RELEASE_MASK); 142 | 143 | m_fSlot[0] = sigc::bind(sigc::mem_fun(*this, &CCanvas::AnimateBi), 0); 144 | m_fSlot[1] = sigc::bind(sigc::mem_fun(*this, &CCanvas::AnimateRot), 0); 145 | m_afConnections[0] = Glib::signal_timeout().connect(m_fSlot[0], 40); 146 | m_afConnections[1] = Glib::signal_timeout().connect(m_fSlot[1], 40); 147 | 148 | for ( int i{0}; i<7; ++i) 149 | { 150 | auto constexpr bs {38.0}; // button size 151 | auto constexpr uix{20.0},uiy{20.0},uiw{bs},uih{bs}; 152 | auto constexpr bsp{ 8.0}; // button spacing 153 | auto constexpr bbo{16.0}; // button bar offset 154 | m_voButtons.emplace_back( bbo+i*(uiw+bsp), bbo+uiy, uiw, uih, 155 | std::to_string(i), 156 | std::to_string(i) ); 157 | } 158 | } 159 | 160 | virtual ~CCanvas() 161 | { 162 | m_afConnections[0].disconnect(); 163 | m_afConnections[1].disconnect(); 164 | }; 165 | 166 | protected: 167 | // Override default signal handler: 168 | bool on_draw(const Cairo::RefPtr& cr) override; 169 | bool on_scroll_event(GdkEventScroll *event) override; 170 | bool on_button_press_event(GdkEventButton * event) override; 171 | bool on_motion_notify_event(GdkEventMotion *event) override; 172 | bool on_button_release_event(GdkEventButton* release_event) override; 173 | 174 | bool Collision(SPoint const & tPoint); 175 | 176 | SPoint m_tCtxSize { .0,.0 }; 177 | double m_dScale { 1.0 }; 178 | 179 | bool m_bShiftInit { true }; 180 | SPoint m_tShift { .0,.0 }; 181 | SPoint m_tEventPress { .0,.0 }; 182 | SPoint m_tEventRelease{ .0,.0 }; 183 | SPoint m_tShiftStart { .0,.0 }; 184 | 185 | 186 | SPoint m_tMousePos; 187 | SColor m_tMouseColor{ .5,.5,.5 }; 188 | VPoints m_vMouseTrail; 189 | VFlecken m_vFlecken { {30,30,20}, {300,300,50}, {500,200,40}, 190 | {40,50,25}, {240,320,30}, {580,270,45} }; 191 | 192 | struct SCollision 193 | { 194 | SPoint tWhere { .0,.0 }; 195 | SPoint tOffset { .0,.0 }; 196 | enum class EWhat 197 | { 198 | none, // there was no collision 199 | Fleck, // move a Fleck 200 | Line, // move a Line 201 | }eWhat {EWhat::none}; 202 | int nIndex {0}; // O: L1, L2, L3 203 | int nSubIx {0}; // L: P1, PM, P2 204 | } m_tCollision; 205 | 206 | // animation 207 | bool m_bAnimate{true}; 208 | bool m_bAnimateLeftBi{true}; 209 | bool m_bAnimateLeftRot{true}; 210 | 211 | // animation clock 212 | double m_dAnimatorBi{0}; // $m_tAnimator animation parameter 213 | double m_dAnimatorRot{0}; // $m_tAnimator animation parameter 214 | double m_dAnimStep{0}; // intermediate animation parameter 215 | sigc::slot m_fSlot[2]; 216 | sigc::connection m_afConnections[2]; 217 | 218 | double m_dAnimate {0.0125}; // animation steps width 219 | double const m_dAnimateMax{0.0250}; // maximal animation step width 220 | double const m_dAnimateMin{0.0025}; // minimal animation step width 221 | 222 | bool AnimateRot(int c) // rotation 223 | { 224 | if (!m_bAnimate) return true; 225 | if (m_bAnimateLeftRot) 226 | m_dAnimatorRot = (m_dAnimatorRot <= m_dAnimate) ? 1 : m_dAnimatorRot-m_dAnimate; 227 | else 228 | m_dAnimatorRot = (m_dAnimatorRot >=1-m_dAnimate) ? 0 : m_dAnimatorRot+m_dAnimate; 229 | queue_draw(); 230 | return true; 231 | } 232 | 233 | bool AnimateBi(int c) // bidirectional 234 | { 235 | if (!m_bAnimate) return true; 236 | if (m_bAnimateLeftBi) 237 | m_dAnimatorBi -= m_dAnimate; 238 | else 239 | m_dAnimatorBi += m_dAnimate; 240 | if (m_dAnimatorBi <= 0) m_bAnimateLeftBi = false; 241 | if (m_dAnimatorBi >= 1) m_bAnimateLeftBi = true; 242 | queue_draw(); 243 | return true; 244 | } 245 | 246 | VButtons m_voButtons; // button bar 247 | std::string m_oButtonPressed{""}; // last pressed button 248 | 249 | }; // CCanvas 250 | -------------------------------------------------------------------------------- /i-4-bar-analytics/canvas.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | 3 | #include "4bar.h" 4 | #include "typesNmath.h" 5 | 6 | #include 7 | #include 8 | 9 | 10 | C4Bar g_o3LS; 11 | 12 | 13 | void CCanvas::AdjustAnimationToMechanism() 14 | { 15 | g_o3LS.A1 = g_o3LS.A1m; g_o3LS.B1 = g_o3LS.B1m; 16 | auto const w{ VectorSlope(g_o3LS.A0, g_o3LS.A1) }; 17 | m_dAnimator = w/(2*M_PI)+.75; 18 | if ( m_dAnimator >= 1 ) m_dAnimator -= 1; 19 | } 20 | 21 | 22 | SPoint draw_text(CairoCtx cr, 23 | SPoint const & pos, 24 | std::string const & crsText, 25 | double const & dScale, 26 | bool const & label) 27 | { 28 | cr->save(); 29 | 30 | Pango::FontDescription font; 31 | 32 | font.set_family("Sans"); 33 | font.set_absolute_size(12.0 * PANGO_SCALE*dScale); 34 | 35 | CCanvas w; 36 | auto layout = w.create_pango_layout(crsText); 37 | 38 | layout->set_font_description(font); 39 | int iWidth {0}; 40 | int iHeight{0}; 41 | SPoint tSize{.0,.0}; 42 | 43 | layout->get_pixel_size(iWidth, iHeight); 44 | tSize = SPoint{iWidth, iHeight}; 45 | 46 | if (label) 47 | { 48 | cr->save(); 49 | Color(cr, WHITE, .75); 50 | LineWidth(cr, {.0+iHeight}); 51 | Line(cr, {{pos.x-tSize.x/2+tSize.y/4, pos.y}, 52 | {pos.x+tSize.x/2-tSize.y/4, pos.y}}); 53 | cr->restore(); 54 | } 55 | 56 | cr->move_to(pos.x-tSize.x/2, pos.y-tSize.y/2); 57 | layout->show_in_cairo_context(cr); 58 | cr->restore(); 59 | 60 | return std::move(tSize); 61 | } 62 | 63 | bool CCanvas::Collision(SPoint const & tPoint) 64 | { 65 | m_tCollision = g_o3LS.Collision(tPoint); 66 | 67 | /* 68 | m_tCollision.eWhat = SCollision::EWhat::none; 69 | 70 | int i{0}; 71 | for ( auto const & a:m_vFlecken ) 72 | { 73 | if ( Distance(a, tPoint) < a.r ) 74 | { 75 | m_tCollision.tWhere = tPoint; 76 | m_tCollision.tOffset = tPoint - a; 77 | m_tCollision.eWhat = SCollision::EWhat::Fleck; 78 | m_tCollision.nIndex = i; 79 | return std::move(true); 80 | } 81 | ++i; 82 | } 83 | */ 84 | return m_tCollision.eWhat != SCollision::EWhat::none; 85 | } 86 | 87 | 88 | bool CCanvas::on_button_press_event(GdkEventButton *event) 89 | { 90 | for ( auto const & a:m_voButtons ) 91 | { 92 | if ( a.Collision(*event) ) 93 | { 94 | m_oButtonPressed = a.sFunct; 95 | return true; 96 | } 97 | } 98 | 99 | if (event->type == GDK_BUTTON_PRESS ) 100 | { 101 | m_tEventPress = *event; 102 | m_tShiftStart = m_tShift; 103 | } 104 | else 105 | { 106 | auto const bCol { Collision(m_tMousePos) }; 107 | } 108 | 109 | m_bButtonDown = true; 110 | 111 | queue_draw(); 112 | return true; 113 | } 114 | 115 | bool CCanvas::on_motion_notify_event(GdkEventMotion *event) 116 | { 117 | m_tMousePos = (*event - m_tShift)/m_dScale; 118 | 119 | if ( m_oButtonPressed > "") return true; 120 | 121 | if ( event->type & GDK_MOTION_NOTIFY ) 122 | { 123 | if ( event->state & GDK_BUTTON3_MASK ) 124 | { 125 | if ( m_tCollision.eWhat == SCollision::EWhat::none ) 126 | m_tShift = m_tShiftStart - (m_tEventPress - *event); 127 | } 128 | else if ( event->state & GDK_BUTTON1_MASK ) 129 | { 130 | if ( m_tCollision.eWhat != SCollision::EWhat::none ) 131 | g_o3LS.MoveObject(m_tCollision, m_tMousePos); 132 | } 133 | else 134 | { 135 | auto const bCol { Collision(m_tMousePos) }; 136 | } 137 | } 138 | 139 | queue_draw(); 140 | return true; 141 | } 142 | 143 | std::string s{"X"}; 144 | bool CCanvas::on_button_release_event(GdkEventButton* event) 145 | { 146 | if ( m_oButtonPressed.size() > 0 ) 147 | { 148 | if ( event->state & GDK_BUTTON1_MASK ) 149 | { 150 | m_oButtonPressed = ""; 151 | for ( auto const & a:m_voButtons ) 152 | if ( a.Collision(*event) ) 153 | { 154 | m_oButtonPressed = a.sFunct; 155 | break; 156 | } 157 | if ( m_oButtonPressed == "0" ) { AnimateHlt(); g_o3LS.m_bCalculate = m_bAnimate;} 158 | if ( m_oButtonPressed == "1" ) AnimateAdd(); 159 | if ( m_oButtonPressed == "2" ) AnimateSub(); 160 | if ( m_oButtonPressed == "3" ) { AnimateRev(); g_o3LS.m_bAnimReverse = m_bAnimateLeft; } 161 | if ( m_oButtonPressed == "4" ) g_o3LS.TraceReset(); 162 | if ( m_oButtonPressed == "5" ) g_o3LS.TraceInvrt(); 163 | if ( m_oButtonPressed == "6" ) g_o3LS.Durchschlagen(); 164 | if ( m_oButtonPressed == "7" ) g_o3LS.Rotate(); 165 | if ( m_oButtonPressed == "8" ) g_o3LS.WithText(); 166 | if ( m_oButtonPressed == "9" ) g_o3LS.WithHints(); 167 | if ( m_oButtonPressed =="11" ) g_o3LS.WithBlink(); 168 | if ( m_oButtonPressed =="12" ) g_o3LS.WithMouse(); 169 | } 170 | m_oButtonPressed=""; 171 | queue_draw(); 172 | return true; 173 | } 174 | 175 | if ( event->type & GDK_MOTION_NOTIFY ) 176 | if ( event->state & GDK_BUTTON1_MASK ) 177 | { 178 | } 179 | if ( event->state & GDK_BUTTON3_MASK ) 180 | { 181 | } 182 | 183 | m_bButtonDown = false; 184 | AdjustAnimationToMechanism(); 185 | 186 | queue_draw(); 187 | return true; 188 | } 189 | 190 | bool CCanvas::on_scroll_event(GdkEventScroll *event) 191 | { 192 | SPoint const p0{ (*event - m_tShift)/m_dScale }; 193 | m_dScale *= (event->delta_y>0)?.9:1.1; if (m_dScale<.01) m_dScale=.01; 194 | SPoint const p1{ (*event - m_tShift)/m_dScale }; 195 | m_tShift -= (p0-p1)*m_dScale; 196 | 197 | queue_draw(); 198 | return true; 199 | } 200 | 201 | 202 | 203 | bool CCanvas::on_draw(CairoCtx cr) 204 | { 205 | auto const all { get_allocation() }; 206 | auto const m_tCtxSize { SPoint { (double)all.get_width(), 207 | (double)all.get_height() } }; 208 | 209 | static auto tHome{ SPoint { m_tCtxSize }/2 }; 210 | 211 | if ( m_bShiftInit ) 212 | { 213 | tHome = m_tShift = m_tCtxSize/2; 214 | m_bShiftInit = false; 215 | } 216 | auto const tSizeHalf{m_tCtxSize/2}; 217 | if ( tHome != tSizeHalf ) 218 | { 219 | m_tShift -= tHome - tSizeHalf; tHome = tSizeHalf; 220 | } 221 | 222 | // adj the output context 223 | Cairo::Matrix matrix(1.0, 0.0, 0.0, 1.0, 0.0, 0.0); 224 | matrix.scale(m_dScale,m_dScale); 225 | matrix.translate(m_tShift.x/m_dScale, m_tShift.y/m_dScale); 226 | cr->transform(matrix); 227 | 228 | cr->set_line_cap(Cairo::LINE_CAP_ROUND); 229 | 230 | // main content 231 | 232 | if (m_tCollision.eWhat != SCollision::EWhat::none) 233 | { 234 | Color(cr, RED, .5); 235 | Circle(cr, m_tMousePos - m_tCollision.tOffset, 17); 236 | } 237 | 238 | g_o3LS.Show(cr, m_dScale); 239 | if ( m_bButtonDown ) 240 | { 241 | g_o3LS.DrawGetriebe(cr, m_dAnimator, m_dAnimate); 242 | } 243 | else 244 | { 245 | g_o3LS.CalcGetriebe(cr, m_dAnimator, m_dAnimate); 246 | } 247 | 248 | // text output 249 | Color(cr, GRAY); 250 | // draw_text(cr, {sin(2*M_PI*m_dAnimatorRot)*75, -60.0}, "Informational text submission", 4); 251 | 252 | 253 | // Buttons 254 | 255 | int i=0; 256 | SPoint const tMousePos{m_tMousePos*m_dScale+m_tShift}; 257 | for ( auto const & a:m_voButtons ) 258 | { 259 | ++i; 260 | cr->set_line_width(1/m_dScale); 261 | 262 | if ( a.Collision(tMousePos) ) 263 | { 264 | cr->set_source_rgba(0,1,0,.8); 265 | } 266 | else 267 | { 268 | cr->set_source_rgba(.7,.7,.7,.8); 269 | } 270 | 271 | Rectangle( cr, (a-m_tShift)/m_dScale, SPoint{a.w/m_dScale, a.h/m_dScale} ); 272 | cr->set_source_rgb(.2,.2,.2); 273 | Frame( cr, (a-m_tShift)/m_dScale, SPoint{a.w/m_dScale, a.h/m_dScale} ); 274 | 275 | cr->set_source_rgb(0,0,0); 276 | draw_text(cr, {(a.x+a.w/2-m_tShift.x)/m_dScale, 277 | (a.y+a.h/2-m_tShift.y)/m_dScale}, a.sTitle, 1/m_dScale); 278 | } 279 | 280 | return true; 281 | } 282 | -------------------------------------------------------------------------------- /k-like-cad/typesNmath.h: -------------------------------------------------------------------------------- 1 | #ifndef TYPES_AND_MATH_H 2 | #define TYPES_AND_MATH_H 3 | 4 | 5 | 6 | struct SPoint 7 | { 8 | SPoint() = default; 9 | SPoint(SPoint const & src) = default; 10 | template 11 | SPoint(T const & x, T const & y) : x(x), y(y) {} 12 | template 13 | SPoint(T const & t) : x(t.x), y(t.y) {} 14 | double x{0}, y{0}; 15 | template 16 | SPoint operator = (P const & p) 17 | { 18 | x = p.x; 19 | y = p.y; 20 | return *this; 21 | } 22 | template 23 | SPoint operator -= (P const & p) 24 | { 25 | x -= p.x; 26 | y -= p.y; 27 | return *this; 28 | } 29 | template 30 | SPoint operator += (P const & p) 31 | { 32 | x += p.x; 33 | y += p.y; 34 | return *this; 35 | } 36 | }; // struct SPoint 37 | 38 | inline bool operator == (SPoint const & p1, SPoint const & p2) 39 | { 40 | return (p1.x==p2.x) && (p1.y==p2.y); 41 | } 42 | 43 | inline bool operator != (SPoint const & p1, SPoint const & p2) 44 | { 45 | return !(p1==p2); 46 | } 47 | 48 | inline SPoint operator - (SPoint const & p1, SPoint const & p2) 49 | { 50 | return {p1.x-p2.x, p1.y-p2.y}; 51 | } 52 | 53 | inline SPoint operator + (SPoint const & p1, SPoint const & p2) 54 | { 55 | return {p2.x+p1.x, p2.y+p1.y}; 56 | } 57 | 58 | inline SPoint operator / (SPoint const & p, double const & d) 59 | { 60 | return {p.x/d, p.y/d}; 61 | } 62 | 63 | inline SPoint operator * (SPoint const & p, double const & d) 64 | { 65 | return {p.x*d, p.y*d}; 66 | } 67 | 68 | struct SLine 69 | { 70 | SPoint a{0,0}; 71 | SPoint b{0,0}; 72 | }; 73 | 74 | using SEbene = SLine; 75 | 76 | struct SRect 77 | { 78 | SPoint p{0,0}; 79 | SPoint s{0,0}; 80 | }; 81 | 82 | struct SFrame 83 | { 84 | SPoint p{0,0}; 85 | SPoint s{0,0}; 86 | }; 87 | 88 | struct SUmkreis 89 | { 90 | double r{0}; 91 | SPoint p{.0,.0}; 92 | }; 93 | 94 | struct SLineWidth 95 | { 96 | double w{1}; 97 | }; 98 | 99 | struct SColor 100 | { 101 | double r{0},g{0},b{0}; 102 | }; 103 | 104 | struct SHit 105 | { 106 | bool bHit{false}; 107 | SPoint tOffset{.0,.0}; 108 | }; 109 | 110 | struct SButton 111 | { 112 | double x{0},y{0},w{0},h{0}; 113 | std::string const sTitle; 114 | std::string const sFunct; 115 | 116 | SButton (double const & x, double const & y, 117 | double const & w, double const & h, 118 | std::string const t, 119 | std::string const f) 120 | : x(x), y(y), w(w), h(h), sTitle(t), sFunct(f) {} 121 | 122 | bool Collision(SPoint const & p) const 123 | { 124 | return ( p.x > x && p.x < x+w && p.y > y && p.y < y+h ); 125 | } 126 | }; 127 | 128 | using VButtons = std::vector; 129 | using VPoints = std::vector; 130 | 131 | 132 | SColor constexpr BLACK {.0,.0,.0}; 133 | SColor constexpr DARKRED {.6,.0,.0}; 134 | SColor constexpr DARKGREEN {.0,.6,.0}; 135 | SColor constexpr DARKBLUE {.0,.0,.6}; 136 | SColor constexpr DARKCYAN {.0,.6,.6}; 137 | SColor constexpr DARKMAGENTA{.6,.0,.6}; 138 | SColor constexpr DARKYELLOW {.6,.6,.0}; 139 | SColor constexpr GRAY {.6,.6,.6}; 140 | SColor constexpr RED {1,0,0}; 141 | SColor constexpr GREEN {0,1,0}; 142 | SColor constexpr BLUE {0,0,1}; 143 | SColor constexpr CYAN {0,1,1}; 144 | SColor constexpr MAGENTA {1,0,1}; 145 | SColor constexpr YELLOW {1,1,0}; 146 | SColor constexpr WHITE {1,1,1}; 147 | 148 | int constexpr TEXT_LEFT {0}; 149 | int constexpr TEXT_MIDDLE {1}; 150 | int constexpr TEXT_RIGHT {2}; 151 | 152 | 153 | // calculation helpers 154 | 155 | // angel at triangle point a of triangle a-b-c 156 | inline double Alpha(double const & a, double const & b, double const & c) 157 | { 158 | auto cosinus = (pow(b,2)+pow(c,2)-pow(a,2)) / (2*b*c); 159 | if ((cosinus<-1)||(cosinus>1)) 160 | { 161 | return 0.0; 162 | } 163 | return acos( cosinus ); 164 | } 165 | 166 | inline double VectorSlope(SPoint const & a, SPoint const & b) 167 | { 168 | auto const dba = SPoint{ b.x-a.x, b.y-a.y }; 169 | double dbax{dba.x}; 170 | if ( dba.x < 0 && dba.x > -.00001) dbax = -.00001; 171 | if ( dba.x > 0 && dba.x < .00001) dbax = .00001; 172 | auto sba = atan(dba.y / dbax); 173 | 174 | if ( (dba.x>0) && (dba.y<0) ) 175 | sba = -sba; 176 | else if ( (dba.x<0) && (dba.y<0) ) 177 | sba = M_PI - sba; 178 | else if ( (dba.x<0) && (dba.y>0) ) 179 | sba = M_PI - sba; 180 | else if ( (dba.x>0) && (dba.y>0) ) 181 | sba = 2*M_PI - sba; 182 | 183 | return sba; 184 | } 185 | 186 | template 187 | double VectorAngleDiff(P const & a, T const & b) 188 | { 189 | auto sla = VectorSlope(a.a,a.b); 190 | auto slb = VectorSlope(b.a,b.b); 191 | return sla - slb; 192 | } 193 | 194 | inline double VectorDiff(SPoint const & a, SPoint const & b, SPoint const & c) 195 | { 196 | auto slb = VectorSlope(a,b); 197 | auto slc = VectorSlope(a,c); 198 | return slc - slb; 199 | } 200 | 201 | template 202 | double Distance( P const & a, T const & b ) 203 | { 204 | return sqrt( pow((a.x-b.x),2) + pow((a.y-b.y),2) ); 205 | } 206 | 207 | 208 | 209 | inline SEbene FixedLenLine(SLine & roL, double const & crnLen, bool const & crbFirst) 210 | { 211 | auto const dx { roL.a.x - roL.b.x }; 212 | auto const dy { roL.a.y - roL.b.y }; 213 | auto const nLen { sqrt(dx*dx + dy*dy) }; 214 | auto const q { (double)crnLen / ((nLen!=0)?nLen:1) }; 215 | if (crbFirst) 216 | { 217 | roL.b.x = roL.a.x - dx*q; 218 | roL.b.y = roL.a.y - dy*q; 219 | } 220 | else 221 | { 222 | roL.a.x = roL.b.x + dx*q; 223 | roL.a.y = roL.b.y + dy*q; 224 | } 225 | return roL; 226 | } // void FixedLenLine(... 227 | 228 | 229 | 230 | template 231 | SPoint Intersection(P const & E1, T const & E2) 232 | { 233 | auto const dx1 { E1.b.x - E1.a.x }; 234 | auto const dx2 { E2.b.x - E2.a.x }; 235 | 236 | auto const m1 { (E1.b.y - E1.a.y) / ((dx1==0)?1e-9:dx1) }; // Steigungen ermitteln 237 | auto const m2 { (E2.b.y - E2.a.y) / ((dx2==0)?1e-9:dx2) }; 238 | 239 | // if (ROUND(m1,MAX_ACCURACY)==ROUND(m2,MAX_ACCURACY)) return false; // Geraden sind parallel 240 | 241 | auto const n1 { E1.a.y - (m1*E1.a.x) }; // Abstände von X-Achse ermitteln 242 | auto const n2 { E2.a.y - (m2*E2.a.x) }; 243 | 244 | auto const x { (n2-n1)/(m1-m2) }; // Schnittpunktkoordinate berechnen 245 | auto const y { m1*x+n1 }; 246 | 247 | return { x, y }; 248 | } // Intersection 249 | 250 | 251 | inline SLine Perpendicle(SLine const & l) 252 | { 253 | auto const dx = (l.b.x - l.a.x)/2.0; 254 | auto const dy = (l.b.y - l.a.y)/2.0; 255 | 256 | SLine I{ {l.b.x - dy - dx, 257 | l.b.y + dx - dy}, 258 | {l.b.x + dy - dx, 259 | l.b.y - dx - dy} }; 260 | 261 | return std::move(I); 262 | } 263 | 264 | inline SPoint PointMirror(SPoint const & p, SLine const & m) 265 | { 266 | auto const dx = (m.b.x - m.a.x)/2.0; 267 | auto const dy = (m.b.y - m.a.y)/2.0; 268 | 269 | SLine I{ {p.x - dy, 270 | p.y + dx}, 271 | {p.x + dy, 272 | p.y - dx} }; 273 | 274 | auto const S { Intersection(m, I) }; 275 | auto const mx { (m.b.x + m.a.x)/2.0 }; 276 | auto const my { (m.b.y + m.a.y)/2.0 }; 277 | 278 | return { S.x + (S.x - p.x), S.y + (S.y - p.y) }; 279 | } 280 | 281 | inline SPoint Polpunkt(SEbene const & E1, SEbene const & E2) 282 | { 283 | SEbene const L1{ E1.a, E2.a }; 284 | auto const La{ Perpendicle(L1) }; 285 | 286 | SEbene const L2{ E1.b, E2.b }; 287 | auto const Lb{ Perpendicle(L2) }; 288 | 289 | return std::move(Intersection(La, Lb)); 290 | } 291 | 292 | inline SUmkreis Umkreis( SPoint const & P1, SPoint const & P2, SPoint const & P3 ) 293 | { 294 | SLine const L1{{P1.x, P1.y},{P2.x, P2.y}}; 295 | auto const La{ Perpendicle(L1) }; 296 | 297 | SLine const L2{{P1.x, P1.y},{P3.x, P3.y}}; 298 | auto const Lb{ Perpendicle(L2) }; 299 | 300 | auto const M{Intersection(La, Lb)}; 301 | auto const R{sqrt( (double)(M.x - L1.a.x)*(M.x - L1.a.x) + (M.y - L1.a.y)*(M.y - L1.a.y) )}; 302 | 303 | return { R, M }; 304 | } 305 | 306 | 307 | // TYPES_AND_MATH_H 308 | #endif 309 | -------------------------------------------------------------------------------- /o-breakout/typesNmath.h: -------------------------------------------------------------------------------- 1 | #ifndef TYPES_AND_MATH_H 2 | #define TYPES_AND_MATH_H 3 | 4 | 5 | 6 | struct SPoint 7 | { 8 | SPoint() = default; 9 | SPoint(SPoint const & src) = default; 10 | template 11 | SPoint(T const & x, T const & y) : x(x), y(y) {} 12 | template 13 | SPoint(T const & t) : x(t.x), y(t.y) {} 14 | double x{0}, y{0}; 15 | template 16 | SPoint operator = (P const & p) 17 | { 18 | x = p.x; 19 | y = p.y; 20 | return *this; 21 | } 22 | template 23 | SPoint operator -= (P const & p) 24 | { 25 | x -= p.x; 26 | y -= p.y; 27 | return *this; 28 | } 29 | template 30 | SPoint operator += (P const & p) 31 | { 32 | x += p.x; 33 | y += p.y; 34 | return *this; 35 | } 36 | }; // struct SPoint 37 | 38 | inline bool operator == (SPoint const & p1, SPoint const & p2) 39 | { 40 | return (p1.x==p2.x) && (p1.y==p2.y); 41 | } 42 | 43 | inline bool operator != (SPoint const & p1, SPoint const & p2) 44 | { 45 | return !(p1==p2); 46 | } 47 | 48 | inline SPoint operator - (SPoint const & p1, SPoint const & p2) 49 | { 50 | return {p1.x-p2.x, p1.y-p2.y}; 51 | } 52 | 53 | inline SPoint operator + (SPoint const & p1, SPoint const & p2) 54 | { 55 | return {p2.x+p1.x, p2.y+p1.y}; 56 | } 57 | 58 | inline SPoint operator / (SPoint const & p, double const & d) 59 | { 60 | return {p.x/d, p.y/d}; 61 | } 62 | 63 | inline SPoint operator * (SPoint const & p, double const & d) 64 | { 65 | return {p.x*d, p.y*d}; 66 | } 67 | 68 | struct SLine 69 | { 70 | SPoint a{0,0}; 71 | SPoint b{0,0}; 72 | }; 73 | 74 | using SEbene = SLine; 75 | 76 | struct SRect 77 | { 78 | SPoint p{0,0}; 79 | SPoint s{0,0}; 80 | }; 81 | 82 | struct SFrame 83 | { 84 | SPoint p{0,0}; 85 | SPoint s{0,0}; 86 | }; 87 | 88 | struct SUmkreis 89 | { 90 | double r{0}; 91 | SPoint p{.0,.0}; 92 | }; 93 | 94 | struct SLineWidth 95 | { 96 | double w{1}; 97 | }; 98 | 99 | struct SColor 100 | { 101 | double r{0},g{0},b{0}; 102 | }; 103 | 104 | struct SHit 105 | { 106 | bool bHit{false}; 107 | SPoint tOffset{.0,.0}; 108 | }; 109 | 110 | struct SButton 111 | { 112 | double x{0},y{0},w{0},h{0}; 113 | std::string const sTitle; 114 | std::string const sFunct; 115 | 116 | SButton (double const & x, double const & y, 117 | double const & w, double const & h, 118 | std::string const t, 119 | std::string const f) 120 | : x(x), y(y), w(w), h(h), sTitle(t), sFunct(f) {} 121 | 122 | bool Collision(SPoint const & p) const 123 | { 124 | return ( p.x > x && p.x < x+w && p.y > y && p.y < y+h ); 125 | } 126 | }; 127 | 128 | using VButtons = std::vector; 129 | using VPoints = std::vector; 130 | 131 | 132 | SColor constexpr BLACK {.0,.0,.0}; 133 | SColor constexpr DARKRED {.6,.0,.0}; 134 | SColor constexpr DARKGREEN {.0,.6,.0}; 135 | SColor constexpr DARKBLUE {.0,.0,.6}; 136 | SColor constexpr DARKCYAN {.0,.6,.6}; 137 | SColor constexpr DARKMAGENTA{.6,.0,.6}; 138 | SColor constexpr DARKYELLOW {.6,.6,.0}; 139 | SColor constexpr GRAY {.6,.6,.6}; 140 | SColor constexpr RED {1,0,0}; 141 | SColor constexpr GREEN {0,1,0}; 142 | SColor constexpr BLUE {0,0,1}; 143 | SColor constexpr CYAN {0,1,1}; 144 | SColor constexpr MAGENTA {1,0,1}; 145 | SColor constexpr YELLOW {1,1,0}; 146 | SColor constexpr WHITE {1,1,1}; 147 | 148 | int constexpr TEXT_LEFT {0}; 149 | int constexpr TEXT_MIDDLE {1}; 150 | int constexpr TEXT_RIGHT {2}; 151 | 152 | 153 | // calculation helpers 154 | 155 | // angel at triangle point a of triangle a-b-c 156 | inline double Alpha(double const & a, double const & b, double const & c) 157 | { 158 | auto cosinus = (pow(b,2)+pow(c,2)-pow(a,2)) / (2*b*c); 159 | if ((cosinus<-1)||(cosinus>1)) 160 | { 161 | return 0.0; 162 | } 163 | return acos( cosinus ); 164 | } 165 | 166 | inline double VectorSlope(SPoint const & a, SPoint const & b) 167 | { 168 | auto const dba = SPoint{ b.x-a.x, b.y-a.y }; 169 | double dbax{dba.x}; 170 | if ( dba.x < 0 && dba.x > -.00001) dbax = -.00001; 171 | if ( dba.x > 0 && dba.x < .00001) dbax = .00001; 172 | auto sba = atan(dba.y / dbax); 173 | 174 | if ( (dba.x>0) && (dba.y<0) ) 175 | sba = -sba; 176 | else if ( (dba.x<0) && (dba.y<0) ) 177 | sba = M_PI - sba; 178 | else if ( (dba.x<0) && (dba.y>0) ) 179 | sba = M_PI - sba; 180 | else if ( (dba.x>0) && (dba.y>0) ) 181 | sba = 2*M_PI - sba; 182 | 183 | return sba; 184 | } 185 | 186 | template 187 | double VectorAngleDiff(P const & a, T const & b) 188 | { 189 | auto sla = VectorSlope(a.a,a.b); 190 | auto slb = VectorSlope(b.a,b.b); 191 | return sla - slb; 192 | } 193 | 194 | inline double VectorDiff(SPoint const & a, SPoint const & b, SPoint const & c) 195 | { 196 | auto slb = VectorSlope(a,b); 197 | auto slc = VectorSlope(a,c); 198 | return slc - slb; 199 | } 200 | 201 | template 202 | double Distance( P const & a, T const & b ) 203 | { 204 | return sqrt( pow((a.x-b.x),2) + pow((a.y-b.y),2) ); 205 | } 206 | 207 | 208 | 209 | inline SEbene FixedLenLine(SLine & roL, double const & crnLen, bool const & crbFirst) 210 | { 211 | auto const dx { roL.a.x - roL.b.x }; 212 | auto const dy { roL.a.y - roL.b.y }; 213 | auto const nLen { sqrt(dx*dx + dy*dy) }; 214 | auto const q { (double)crnLen / ((nLen!=0)?nLen:1) }; 215 | if (crbFirst) 216 | { 217 | roL.b.x = roL.a.x - dx*q; 218 | roL.b.y = roL.a.y - dy*q; 219 | } 220 | else 221 | { 222 | roL.a.x = roL.b.x + dx*q; 223 | roL.a.y = roL.b.y + dy*q; 224 | } 225 | return roL; 226 | } // void FixedLenLine(... 227 | 228 | 229 | 230 | template 231 | SPoint Intersection(P const & E1, T const & E2) 232 | { 233 | auto const dx1 { E1.b.x - E1.a.x }; 234 | auto const dx2 { E2.b.x - E2.a.x }; 235 | 236 | auto const m1 { (E1.b.y - E1.a.y) / ((dx1==0)?1e-9:dx1) }; // Steigungen ermitteln 237 | auto const m2 { (E2.b.y - E2.a.y) / ((dx2==0)?1e-9:dx2) }; 238 | 239 | // if (ROUND(m1,MAX_ACCURACY)==ROUND(m2,MAX_ACCURACY)) return false; // Geraden sind parallel 240 | 241 | auto const n1 { E1.a.y - (m1*E1.a.x) }; // Abstände von X-Achse ermitteln 242 | auto const n2 { E2.a.y - (m2*E2.a.x) }; 243 | 244 | auto const x { (n2-n1)/(m1-m2) }; // Schnittpunktkoordinate berechnen 245 | auto const y { m1*x+n1 }; 246 | 247 | return { x, y }; 248 | } // Intersection 249 | 250 | 251 | inline SLine Perpendicle(SLine const & l) 252 | { 253 | auto const dx = (l.b.x - l.a.x)/2.0; 254 | auto const dy = (l.b.y - l.a.y)/2.0; 255 | 256 | SLine I{ {l.b.x - dy - dx, 257 | l.b.y + dx - dy}, 258 | {l.b.x + dy - dx, 259 | l.b.y - dx - dy} }; 260 | 261 | return std::move(I); 262 | } 263 | 264 | inline SPoint PointMirror(SPoint const & p, SLine const & m) 265 | { 266 | auto const dx = (m.b.x - m.a.x)/2.0; 267 | auto const dy = (m.b.y - m.a.y)/2.0; 268 | 269 | SLine I{ {p.x - dy, 270 | p.y + dx}, 271 | {p.x + dy, 272 | p.y - dx} }; 273 | 274 | auto const S { Intersection(m, I) }; 275 | auto const mx { (m.b.x + m.a.x)/2.0 }; 276 | auto const my { (m.b.y + m.a.y)/2.0 }; 277 | 278 | return { S.x + (S.x - p.x), S.y + (S.y - p.y) }; 279 | } 280 | 281 | inline SPoint Polpunkt(SEbene const & E1, SEbene const & E2) 282 | { 283 | SEbene const L1{ E1.a, E2.a }; 284 | auto const La{ Perpendicle(L1) }; 285 | 286 | SEbene const L2{ E1.b, E2.b }; 287 | auto const Lb{ Perpendicle(L2) }; 288 | 289 | return std::move(Intersection(La, Lb)); 290 | } 291 | 292 | inline SUmkreis Umkreis( SPoint const & P1, SPoint const & P2, SPoint const & P3 ) 293 | { 294 | SLine const L1{{P1.x, P1.y},{P2.x, P2.y}}; 295 | auto const La{ Perpendicle(L1) }; 296 | 297 | SLine const L2{{P1.x, P1.y},{P3.x, P3.y}}; 298 | auto const Lb{ Perpendicle(L2) }; 299 | 300 | auto const M{Intersection(La, Lb)}; 301 | auto const R{sqrt( (double)(M.x - L1.a.x)*(M.x - L1.a.x) + (M.y - L1.a.y)*(M.y - L1.a.y) )}; 302 | 303 | return { R, M }; 304 | } 305 | 306 | 307 | // TYPES_AND_MATH_H 308 | #endif 309 | -------------------------------------------------------------------------------- /f-drawing-helpers/canvas.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | #include 3 | 4 | 5 | 6 | 7 | 8 | SPoint draw_text(Cairo::RefPtr const & cr, 9 | SPoint const & pos, 10 | std::string const & crsText, double const & dScale = 1.0) 11 | { 12 | cr->save(); 13 | 14 | Pango::FontDescription font; 15 | 16 | font.set_family("Monospace"); 17 | font.set_absolute_size(12.0 * PANGO_SCALE*dScale); 18 | 19 | CCanvas w; 20 | auto layout = w.create_pango_layout(crsText); 21 | 22 | layout->set_font_description(font); 23 | int iWidth {0}; 24 | int iHeight{0}; 25 | SPoint tSize{.0,.0}; 26 | 27 | layout->get_pixel_size(iWidth, iHeight); 28 | tSize = SPoint{iWidth, iHeight}; 29 | cr->move_to(pos.x-tSize.x/2, pos.y-tSize.y/2); 30 | layout->show_in_cairo_context(cr); 31 | cr->restore(); 32 | 33 | return std::move(tSize); 34 | } 35 | 36 | bool CCanvas::Collision(SPoint const & tPoint) 37 | { 38 | m_tCollision.eWhat = SCollision::EWhat::none; 39 | 40 | int i{0}; 41 | for ( auto & a:m_vFlecken ) 42 | { 43 | if ( Distance(a, tPoint) < a.r ) 44 | { 45 | m_tCollision.tWhere = tPoint; 46 | m_tCollision.tOffset = tPoint - a; 47 | m_tCollision.eWhat = SCollision::EWhat::Fleck; 48 | m_tCollision.nIndex = i; 49 | return std::move(true); 50 | } 51 | ++i; 52 | } 53 | return false; 54 | } 55 | 56 | 57 | bool CCanvas::on_button_press_event(GdkEventButton *event) 58 | { 59 | for ( auto const & a:m_voButtons ) 60 | { 61 | if ( a.Collision(*event) ) 62 | { 63 | m_oButtonPressed = a.sFunct; 64 | return true; 65 | } 66 | } 67 | 68 | m_tMouseColor = { .0,.0,.9 }; 69 | if (event->type == GDK_BUTTON_PRESS ) 70 | { 71 | m_tEventPress = *event; 72 | m_tShiftStart = m_tShift; 73 | } 74 | else 75 | { 76 | auto const bCol { Collision(m_tMousePos) }; 77 | } 78 | 79 | if ( event->button == 3 ) 80 | { 81 | switch ( m_tCollision.eWhat ) 82 | { 83 | case SCollision::EWhat::Fleck: 84 | break; 85 | case SCollision::EWhat::Line: 86 | break; 87 | case SCollision::EWhat::none: 88 | break; 89 | } 90 | } 91 | 92 | queue_draw(); 93 | return true; 94 | } 95 | 96 | bool CCanvas::on_motion_notify_event(GdkEventMotion *event) 97 | { 98 | m_tMousePos = (*event - m_tShift)/m_dScale; 99 | 100 | if ( m_oButtonPressed > "") return true; 101 | 102 | if ( event->type & GDK_MOTION_NOTIFY ) 103 | { 104 | if ( event->state & GDK_BUTTON3_MASK ) 105 | { 106 | switch ( m_tCollision.eWhat ) 107 | { 108 | case SCollision::EWhat::Fleck: 109 | m_vFlecken[m_tCollision.nIndex] = m_tMousePos 110 | - m_tCollision.tOffset; 111 | break; 112 | case SCollision::EWhat::Line: 113 | break; 114 | case SCollision::EWhat::none: 115 | m_tShift = m_tShiftStart - (m_tEventPress - *event); 116 | break; 117 | } 118 | } 119 | else 120 | { 121 | auto const bCol { Collision(m_tMousePos) }; 122 | } 123 | } 124 | queue_draw(); 125 | return true; 126 | } 127 | 128 | std::string s{"X"}; 129 | bool CCanvas::on_button_release_event(GdkEventButton* event) 130 | { 131 | if ( m_oButtonPressed.size() > 0 ) 132 | { 133 | if ( event->state & GDK_BUTTON1_MASK ) 134 | { 135 | m_oButtonPressed = ""; 136 | for ( auto const & a:m_voButtons ) 137 | if ( a.Collision(*event) ) 138 | { 139 | m_oButtonPressed = a.sFunct; 140 | break; 141 | } 142 | if ( m_oButtonPressed == "0" ) { s="A"; } 143 | if ( m_oButtonPressed == "1" ) { s="B"; } 144 | if ( m_oButtonPressed == "2" ) { s="C"; } 145 | if ( m_oButtonPressed == "3" ) { s="D"; } 146 | if ( m_oButtonPressed == "4" ) { s="E"; } 147 | if ( m_oButtonPressed == "5" ) { s="F"; } 148 | if ( m_oButtonPressed == "6" ) { s="G"; } 149 | } 150 | m_oButtonPressed=""; 151 | queue_draw(); 152 | return true; 153 | } 154 | 155 | if ( event->type & GDK_MOTION_NOTIFY ) 156 | if ( event->state & GDK_BUTTON1_MASK ) 157 | { 158 | m_tMouseColor = { .5,.5,.5 }; 159 | m_vMouseTrail.emplace_back( (*event - m_tShift)/m_dScale ); 160 | } 161 | if ( event->state & GDK_BUTTON3_MASK ) 162 | { 163 | } 164 | 165 | queue_draw(); 166 | return true; 167 | } 168 | 169 | bool CCanvas::on_scroll_event(GdkEventScroll *event) 170 | { 171 | if ( event->delta_y>0 ) 172 | m_tMouseColor = { .9,.0,.0 }; 173 | else 174 | m_tMouseColor = { .0,.9,.0 }; 175 | 176 | SPoint const p0{ (*event - m_tShift)/m_dScale }; 177 | m_dScale *= (event->delta_y>0)?.9:1.1; if (m_dScale<.01) m_dScale=.01; 178 | SPoint const p1{ (*event - m_tShift)/m_dScale }; 179 | m_tShift -= (p0-p1)*m_dScale; 180 | 181 | queue_draw(); 182 | return true; 183 | } 184 | 185 | bool CCanvas::on_draw(Cairo::RefPtr const & cr) 186 | { 187 | auto const all { get_allocation() }; 188 | auto const m_tCtxSize { SPoint { (double)all.get_width(), 189 | (double)all.get_height() } }; 190 | 191 | static auto tHome{ SPoint { m_tCtxSize }/2 }; 192 | 193 | if ( m_bShiftInit ) 194 | { 195 | tHome = m_tShift = m_tCtxSize/2; 196 | m_bShiftInit = false; 197 | } 198 | auto const tSizeHalf{m_tCtxSize/2}; 199 | if ( tHome != tSizeHalf ) 200 | { 201 | m_tShift -= tHome - tSizeHalf; tHome = tSizeHalf; 202 | } 203 | 204 | Cairo::Matrix matrix(1.0, 0.0, 0.0, 1.0, 0.0, 0.0); 205 | matrix.scale(m_dScale,m_dScale); 206 | matrix.translate(m_tShift.x/m_dScale, m_tShift.y/m_dScale); 207 | 208 | cr->transform(matrix); 209 | 210 | 211 | 212 | if ( auto const i{m_vMouseTrail.size()} ) 213 | { 214 | cr->set_source_rgb( .0,.0,.0 ); 215 | cr->set_line_width(3); 216 | LineStrip(cr, m_vMouseTrail); 217 | 218 | cr->set_source_rgb( .6,.6,.6 ); 219 | cr->set_line_width(1); 220 | Line(cr, m_vMouseTrail[i-1], m_tMousePos); 221 | } 222 | 223 | int i{0}; 224 | for ( auto const & a:m_vFlecken ) 225 | { 226 | if ( ( m_tCollision.nIndex == i++ ) && 227 | ( m_tCollision.eWhat == SCollision::EWhat::Fleck ) ) 228 | cr->set_source_rgb( .9, .0, .0 ); 229 | else 230 | cr->set_source_rgb( .0, .9, .0 ); 231 | if ( i == 1 ) 232 | Circle(cr, SPoint{a.x + 250.0*m_dAnimatorBi, a.y}, a.r); 233 | else if ( i == 2 ) 234 | Circle(cr, SPoint{a.x, a.y - sin(2*M_PI*m_dAnimatorRot)*125.0}, a.r); 235 | else if ( i == 3 ) 236 | Circle(cr, SPoint{a.x + cos(2*M_PI*m_dAnimatorRot)*75.0, a.y + sin(2*M_PI*m_dAnimatorRot)*125.0}, a.r); 237 | else 238 | Circle(cr, a, a.r); 239 | 240 | cr->set_source_rgb( .0, .2, .0 ); 241 | cr->set_line_width(1); 242 | Ring(cr, a, a.r); 243 | } 244 | 245 | 246 | cr->set_source_rgb( m_tMouseColor.r, m_tMouseColor.b, m_tMouseColor.b ); 247 | Circle(cr, m_tMousePos, 11); 248 | 249 | cr->set_source_rgb( .5, .5, .5 ); 250 | draw_text(cr, {sin(2*M_PI*m_dAnimatorRot)*75, -60.0}, "Informational text submission", 4); 251 | 252 | 253 | // Buttons 254 | draw_text(cr, {0, -120}, s, 8/m_dScale); 255 | i=0; 256 | SPoint const tMousePos{m_tMousePos*m_dScale+m_tShift}; 257 | for ( auto const & a:m_voButtons ) 258 | { 259 | ++i; 260 | cr->set_line_width(1/m_dScale); 261 | 262 | if ( a.Collision(tMousePos) ) 263 | { 264 | cr->set_source_rgba(0,1,0,.8); 265 | } 266 | else 267 | { 268 | cr->set_source_rgba(.7,.7,.7,.8); 269 | } 270 | 271 | Rectangle( cr, (a-m_tShift)/m_dScale, SPoint{a.w/m_dScale, a.h/m_dScale} ); 272 | cr->set_source_rgb(.2,.2,.2); 273 | Frame( cr, (a-m_tShift)/m_dScale, SPoint{a.w/m_dScale, a.h/m_dScale} ); 274 | 275 | cr->set_source_rgb(0,0,0); 276 | draw_text(cr, {(a.x+a.w/2-m_tShift.x)/m_dScale, (a.y+a.h/2-m_tShift.y)/m_dScale}, a.sTitle, 1/m_dScale); 277 | } 278 | 279 | return true; 280 | } 281 | -------------------------------------------------------------------------------- /e-ui-button-bar/canvas.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | #include 3 | 4 | 5 | 6 | 7 | 8 | SPoint draw_text(Cairo::RefPtr const & cr, 9 | double posx, double posy, 10 | std::string const & crsText, double const & dScale = 1.0) 11 | { 12 | cr->save(); 13 | 14 | Pango::FontDescription font; 15 | 16 | font.set_family("Monospace"); 17 | font.set_absolute_size(12.0 * PANGO_SCALE*dScale); 18 | 19 | CCanvas w; 20 | auto layout = w.create_pango_layout(crsText); 21 | 22 | layout->set_font_description(font); 23 | int iWidth {0}; 24 | int iHeight{0}; 25 | SPoint tSize{.0,.0}; 26 | 27 | layout->get_pixel_size(iWidth, iHeight); 28 | tSize = SPoint{iWidth, iHeight}; 29 | cr->move_to(posx-tSize.x/2, posy-tSize.y/2); 30 | layout->show_in_cairo_context(cr); 31 | cr->restore(); 32 | 33 | return std::move(tSize); 34 | } 35 | 36 | bool CCanvas::Collision(SPoint const & tPoint) 37 | { 38 | m_tCollision.eWhat = SCollision::EWhat::none; 39 | 40 | int i{0}; 41 | for ( auto & a:m_vFlecken ) 42 | { 43 | if ( Distance(a, tPoint) < a.r ) 44 | { 45 | m_tCollision.tWhere = tPoint; 46 | m_tCollision.tOffset = tPoint - a; 47 | m_tCollision.eWhat = SCollision::EWhat::Fleck; 48 | m_tCollision.nIndex = i; 49 | return std::move(true); 50 | } 51 | ++i; 52 | } 53 | return false; 54 | } 55 | 56 | 57 | bool CCanvas::on_button_press_event(GdkEventButton *event) 58 | { 59 | for ( auto const & a:m_voButtons ) 60 | { 61 | if ( a.Collision(*event) ) 62 | { 63 | m_oButtonPressed = a.sFunct; 64 | return true; 65 | } 66 | } 67 | 68 | m_tMouseColor = { .0,.0,.9 }; 69 | if (event->type == GDK_BUTTON_PRESS ) 70 | { 71 | m_tEventPress = *event; 72 | m_tShiftStart = m_tShift; 73 | } 74 | else 75 | { 76 | auto const bCol { Collision(m_tMousePos) }; 77 | } 78 | 79 | if ( event->button == 3 ) 80 | { 81 | switch ( m_tCollision.eWhat ) 82 | { 83 | case SCollision::EWhat::Fleck: 84 | break; 85 | case SCollision::EWhat::Line: 86 | break; 87 | case SCollision::EWhat::none: 88 | break; 89 | } 90 | } 91 | 92 | queue_draw(); 93 | return true; 94 | } 95 | 96 | bool CCanvas::on_motion_notify_event(GdkEventMotion *event) 97 | { 98 | m_tMousePos = (*event - m_tShift)/m_dScale; 99 | 100 | if ( m_oButtonPressed > "") return true; 101 | 102 | if ( event->type & GDK_MOTION_NOTIFY ) 103 | { 104 | if ( event->state & GDK_BUTTON3_MASK ) 105 | { 106 | switch ( m_tCollision.eWhat ) 107 | { 108 | case SCollision::EWhat::Fleck: 109 | m_vFlecken[m_tCollision.nIndex] = m_tMousePos 110 | - m_tCollision.tOffset; 111 | break; 112 | case SCollision::EWhat::Line: 113 | break; 114 | case SCollision::EWhat::none: 115 | m_tShift = m_tShiftStart - (m_tEventPress - *event); 116 | break; 117 | } 118 | } 119 | else 120 | { 121 | auto const bCol { Collision(m_tMousePos) }; 122 | } 123 | } 124 | queue_draw(); 125 | return true; 126 | } 127 | 128 | std::string s{"X"}; 129 | bool CCanvas::on_button_release_event(GdkEventButton* event) 130 | { 131 | if ( m_oButtonPressed.size() > 0 ) 132 | { 133 | m_oButtonPressed = ""; 134 | for ( auto const & a:m_voButtons ) 135 | if ( a.Collision(*event) ) 136 | { 137 | m_oButtonPressed = a.sFunct; 138 | break; 139 | } 140 | if ( m_oButtonPressed == "0" ) { s="A"; } 141 | if ( m_oButtonPressed == "1" ) { s="B"; } 142 | if ( m_oButtonPressed == "2" ) { s="C"; } 143 | if ( m_oButtonPressed == "3" ) { s="D"; } 144 | if ( m_oButtonPressed == "4" ) { s="E"; } 145 | if ( m_oButtonPressed == "5" ) { s="F"; } 146 | if ( m_oButtonPressed == "6" ) { s="G"; } 147 | 148 | m_oButtonPressed=""; 149 | queue_draw(); 150 | return true; 151 | } 152 | 153 | if ( event->type & GDK_MOTION_NOTIFY ) 154 | if ( event->state & GDK_BUTTON1_MASK ) 155 | { 156 | m_tMouseColor = { .5,.5,.5 }; 157 | m_vMouseTrail.emplace_back( (*event - m_tShift)/m_dScale ); 158 | } 159 | if ( event->state & GDK_BUTTON3_MASK ) 160 | { 161 | } 162 | 163 | queue_draw(); 164 | return true; 165 | } 166 | 167 | bool CCanvas::on_scroll_event(GdkEventScroll *event) 168 | { 169 | if ( event->delta_y>0 ) 170 | m_tMouseColor = { .9,.0,.0 }; 171 | else 172 | m_tMouseColor = { .0,.9,.0 }; 173 | 174 | SPoint const p0{ (*event - m_tShift)/m_dScale }; 175 | m_dScale *= (event->delta_y>0)?.9:1.1; if (m_dScale<.01) m_dScale=.01; 176 | SPoint const p1{ (*event - m_tShift)/m_dScale }; 177 | m_tShift -= (p0-p1)*m_dScale; 178 | 179 | queue_draw(); 180 | return true; 181 | } 182 | 183 | bool CCanvas::on_draw(Cairo::RefPtr const & cr) 184 | { 185 | auto const all { get_allocation() }; 186 | auto const m_tCtxSize { SPoint { (double)all.get_width(), 187 | (double)all.get_height() } }; 188 | 189 | static auto tHome{ SPoint { m_tCtxSize }/2 }; 190 | 191 | if ( m_bShiftInit ) 192 | { 193 | tHome = m_tShift = m_tCtxSize/2; 194 | m_bShiftInit = false; 195 | } 196 | auto const tSizeHalf{m_tCtxSize/2}; 197 | if ( tHome != tSizeHalf ) 198 | { 199 | m_tShift -= tHome - tSizeHalf; tHome = tSizeHalf; 200 | } 201 | 202 | Cairo::Matrix matrix(1.0, 0.0, 0.0, 1.0, 0.0, 0.0); 203 | matrix.scale(m_dScale,m_dScale); 204 | matrix.translate(m_tShift.x/m_dScale, m_tShift.y/m_dScale); 205 | 206 | cr->transform(matrix); 207 | 208 | 209 | 210 | if ( auto const i{m_vMouseTrail.size()} ) 211 | { 212 | cr->set_source_rgb( .0,.0,.0 ); 213 | cr->set_line_width(3); 214 | cr->move_to(m_vMouseTrail[0].x,m_vMouseTrail[0].y); 215 | for (auto const & a:m_vMouseTrail) 216 | { 217 | cr->line_to( a.x, a.y); 218 | } 219 | cr->stroke(); 220 | 221 | cr->set_source_rgb( .6,.6,.6 ); 222 | cr->set_line_width(1); 223 | cr->move_to(m_vMouseTrail[i-1].x,m_vMouseTrail[i-1].y); 224 | cr->line_to( m_tMousePos.x, m_tMousePos.y ); 225 | cr->stroke(); 226 | } 227 | 228 | int i{0}; 229 | for ( auto const & a:m_vFlecken ) 230 | { 231 | if ( ( m_tCollision.nIndex == i++ ) && 232 | ( m_tCollision.eWhat == SCollision::EWhat::Fleck ) ) 233 | cr->set_source_rgb( .9, .0, .0 ); 234 | else 235 | cr->set_source_rgb( .0, .9, .0 ); 236 | if ( i == 1 ) 237 | cr->arc(a.x + 250*m_dAnimatorBi, a.y, a.r, 0, 2*M_PI); 238 | else if ( i == 2 ) 239 | cr->arc(a.x, a.y - sin(2*M_PI*m_dAnimatorRot)*125, a.r, 0, 2*M_PI); 240 | else 241 | cr->arc(a.x, a.y, a.r, 0, 2*M_PI); 242 | cr->fill(); 243 | 244 | cr->set_source_rgb( .0, .2, .0 ); 245 | cr->set_line_width(1); 246 | cr->arc(a.x, a.y, a.r, 0, 2*M_PI); 247 | cr->stroke(); 248 | } 249 | 250 | 251 | cr->set_source_rgb( m_tMouseColor.r, m_tMouseColor.b, m_tMouseColor.b ); 252 | cr->arc(m_tMousePos.x, m_tMousePos.y, 11, 0, 2*M_PI); 253 | cr->fill(); 254 | 255 | cr->set_source_rgb( .5, .5, .5 ); 256 | draw_text(cr, sin(2*M_PI*m_dAnimatorRot)*75, -60, "Informational text submission", 4); 257 | 258 | 259 | // Buttons 260 | draw_text(cr, -150, -120, s, 8/m_dScale); 261 | i=0; 262 | SPoint const tMousePos{m_tMousePos*m_dScale+m_tShift}; 263 | for ( auto const & a:m_voButtons ) 264 | { 265 | ++i; 266 | cr->set_line_width(1/m_dScale); 267 | 268 | if ( a.Collision(tMousePos) ) 269 | { 270 | cr->set_source_rgba(0,1,0,.8); 271 | } 272 | else 273 | { 274 | cr->set_source_rgba(.7,.7,.7,.8); 275 | } 276 | 277 | cr->rectangle( (a.x-m_tShift.x)/m_dScale, (a.y-m_tShift.y)/m_dScale, (a.w)/m_dScale, (a.h)/m_dScale ); 278 | cr->fill(); 279 | cr->set_source_rgb(.2,.2,.2); 280 | cr->rectangle( (a.x-m_tShift.x)/m_dScale, (a.y-m_tShift.y)/m_dScale, (a.w)/m_dScale, (a.h)/m_dScale ); 281 | cr->stroke(); 282 | 283 | cr->set_source_rgb(0,0,0); 284 | draw_text(cr, (a.x+a.w/2-m_tShift.x)/m_dScale, (a.y+a.h/2-m_tShift.y)/m_dScale, a.sTitle, 1/m_dScale); 285 | } 286 | 287 | return true; 288 | } 289 | -------------------------------------------------------------------------------- /h-3-lagen-synthese/canvas.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | 3 | #include "3lagen.h" 4 | #include "typesNmath.h" 5 | 6 | #include 7 | #include 8 | 9 | 10 | C3Lagen g_o3LS; 11 | 12 | 13 | 14 | SPoint draw_text(CairoCtx cr, 15 | SPoint const & pos, 16 | std::string const & crsText, 17 | double const & dScale, 18 | bool const & label) 19 | { 20 | cr->save(); 21 | 22 | Pango::FontDescription font; 23 | 24 | font.set_family("Sans"); 25 | font.set_absolute_size(12.0 * PANGO_SCALE*dScale); 26 | 27 | CCanvas w; 28 | auto layout = w.create_pango_layout(crsText); 29 | 30 | layout->set_font_description(font); 31 | int iWidth {0}; 32 | int iHeight{0}; 33 | SPoint tSize{.0,.0}; 34 | 35 | layout->get_pixel_size(iWidth, iHeight); 36 | tSize = SPoint{iWidth, iHeight}; 37 | 38 | if (label) 39 | { 40 | cr->save(); 41 | Color(cr, WHITE, .5); 42 | LineWidth(cr, {.0+iHeight}); 43 | Line(cr, {{pos.x-tSize.x/2+tSize.y/4, pos.y}, 44 | {pos.x+tSize.x/2-tSize.y/4, pos.y}}); 45 | cr->restore(); 46 | } 47 | 48 | cr->move_to(pos.x-tSize.x/2, pos.y-tSize.y/2); 49 | layout->show_in_cairo_context(cr); 50 | cr->restore(); 51 | 52 | return std::move(tSize); 53 | } 54 | 55 | bool CCanvas::Collision(SPoint const & tPoint) 56 | { 57 | m_tCollision = g_o3LS.Collision(tPoint); 58 | 59 | /* 60 | m_tCollision.eWhat = SCollision::EWhat::none; 61 | 62 | int i{0}; 63 | for ( auto const & a:m_vFlecken ) 64 | { 65 | if ( Distance(a, tPoint) < a.r ) 66 | { 67 | m_tCollision.tWhere = tPoint; 68 | m_tCollision.tOffset = tPoint - a; 69 | m_tCollision.eWhat = SCollision::EWhat::Fleck; 70 | m_tCollision.nIndex = i; 71 | return std::move(true); 72 | } 73 | ++i; 74 | } 75 | */ 76 | return m_tCollision.eWhat != SCollision::EWhat::none; 77 | } 78 | 79 | 80 | bool CCanvas::on_button_press_event(GdkEventButton *event) 81 | { 82 | for ( auto const & a:m_voButtons ) 83 | { 84 | if ( a.Collision(*event) ) 85 | { 86 | m_oButtonPressed = a.sFunct; 87 | return true; 88 | } 89 | } 90 | 91 | if (event->type == GDK_BUTTON_PRESS ) 92 | { 93 | m_tEventPress = *event; 94 | m_tShiftStart = m_tShift; 95 | } 96 | else 97 | { 98 | auto const bCol { Collision(m_tMousePos) }; 99 | } 100 | /* 101 | if ( event->button == 3 ) 102 | { 103 | switch ( m_tCollision.eWhat ) 104 | { 105 | case SCollision::EWhat::Ebene: 106 | break; 107 | case SCollision::EWhat::Pol: 108 | break; 109 | case SCollision::EWhat::G123: 110 | break; 111 | case SCollision::EWhat::G0: 112 | break; 113 | case SCollision::EWhat::G: 114 | break; 115 | case SCollision::EWhat::none: 116 | break; 117 | } 118 | } 119 | */ 120 | queue_draw(); 121 | return true; 122 | } 123 | 124 | bool CCanvas::on_motion_notify_event(GdkEventMotion *event) 125 | { 126 | m_tMousePos = (*event - m_tShift)/m_dScale; 127 | 128 | if ( m_oButtonPressed > "") return true; 129 | 130 | if ( event->type & GDK_MOTION_NOTIFY ) 131 | { 132 | if ( event->state & GDK_BUTTON3_MASK ) 133 | { 134 | if ( m_tCollision.eWhat == SCollision::EWhat::none ) 135 | m_tShift = m_tShiftStart - (m_tEventPress - *event); 136 | } 137 | else if ( event->state & GDK_BUTTON1_MASK ) 138 | { 139 | if ( m_tCollision.eWhat != SCollision::EWhat::none ) 140 | g_o3LS.MoveObject(m_tCollision, m_tMousePos); 141 | } 142 | else 143 | { 144 | auto const bCol { Collision(m_tMousePos) }; 145 | } 146 | } 147 | 148 | queue_draw(); 149 | return true; 150 | } 151 | 152 | std::string s{"X"}; 153 | bool CCanvas::on_button_release_event(GdkEventButton* event) 154 | { 155 | if ( m_oButtonPressed.size() > 0 ) 156 | { 157 | if ( event->state & GDK_BUTTON1_MASK ) 158 | { 159 | m_oButtonPressed = ""; 160 | for ( auto const & a:m_voButtons ) 161 | if ( a.Collision(*event) ) 162 | { 163 | m_oButtonPressed = a.sFunct; 164 | break; 165 | } 166 | if ( m_oButtonPressed == "0" ) AnimateHlt(); 167 | if ( m_oButtonPressed == "1" ) AnimateAdd(); 168 | if ( m_oButtonPressed == "2" ) AnimateSub(); 169 | if ( m_oButtonPressed == "3" ) { AnimateRev(); g_o3LS.m_bAnimReverse = m_bAnimateLeftUst; } 170 | if ( m_oButtonPressed == "4" ) g_o3LS.TraceReset(); 171 | if ( m_oButtonPressed == "5" ) g_o3LS.TraceInvrt(); 172 | if ( m_oButtonPressed == "6" ) g_o3LS.Durchschlagen(); 173 | if ( m_oButtonPressed == "7" ) g_o3LS.Rotate(); 174 | if ( m_oButtonPressed == "8" ) g_o3LS.WithText(); 175 | if ( m_oButtonPressed == "9" ) g_o3LS.WithHints(); 176 | if ( m_oButtonPressed =="11" ) g_o3LS.WithBlink(); 177 | if ( m_oButtonPressed =="12" ) g_o3LS.WithMouse(); 178 | } 179 | m_oButtonPressed=""; 180 | queue_draw(); 181 | return true; 182 | } 183 | 184 | if ( event->type & GDK_MOTION_NOTIFY ) 185 | if ( event->state & GDK_BUTTON1_MASK ) 186 | { 187 | switch (m_cNextDrop) 188 | { 189 | case 'R': 190 | break; 191 | case 'F': 192 | break; 193 | case 'C': 194 | break; 195 | case 'c': 196 | break; 197 | case 'f': 198 | break; 199 | 200 | } 201 | } 202 | if ( event->state & GDK_BUTTON3_MASK ) 203 | { 204 | } 205 | 206 | queue_draw(); 207 | return true; 208 | } 209 | 210 | bool CCanvas::on_scroll_event(GdkEventScroll *event) 211 | { 212 | SPoint const p0{ (*event - m_tShift)/m_dScale }; 213 | m_dScale *= (event->delta_y>0)?.9:1.1; if (m_dScale<.01) m_dScale=.01; 214 | SPoint const p1{ (*event - m_tShift)/m_dScale }; 215 | m_tShift -= (p0-p1)*m_dScale; 216 | 217 | queue_draw(); 218 | return true; 219 | } 220 | 221 | 222 | 223 | bool CCanvas::on_draw(CairoCtx cr) 224 | { 225 | auto const all { get_allocation() }; 226 | auto const m_tCtxSize { SPoint { (double)all.get_width(), 227 | (double)all.get_height() } }; 228 | 229 | static auto tHome{ SPoint { m_tCtxSize }/2 }; 230 | 231 | if ( m_bShiftInit ) 232 | { 233 | tHome = m_tShift = m_tCtxSize/2; 234 | m_bShiftInit = false; 235 | } 236 | auto const tSizeHalf{m_tCtxSize/2}; 237 | if ( tHome != tSizeHalf ) 238 | { 239 | m_tShift -= tHome - tSizeHalf; tHome = tSizeHalf; 240 | } 241 | 242 | // adjust the output context 243 | Cairo::Matrix matrix(1.0, 0.0, 0.0, 1.0, 0.0, 0.0); 244 | matrix.scale(m_dScale,m_dScale); 245 | matrix.translate(m_tShift.x/m_dScale, m_tShift.y/m_dScale); 246 | cr->transform(matrix); 247 | 248 | cr->set_line_cap(Cairo::LINE_CAP_ROUND); 249 | 250 | // main content 251 | 252 | // ebenen 253 | if (m_bAnimate) 254 | { 255 | SEbene e1{{-50,-50},{-50.0+sin(2*M_PI*m_dAnimatorRot )*100,-50.0+cos(2*M_PI*m_dAnimatorRot )*100}}, 256 | e2{{-90, 0},{-90.0+sin(2*M_PI*m_dAnimatorRot*2)*100, 0.0+cos(2*M_PI*m_dAnimatorRot*2)*100}}, 257 | e3{{ 40, 30},{ 40.0+sin(2*M_PI*m_dAnimatorBi )*100, 30.0+cos(2*M_PI*m_dAnimatorBi )*100}}; 258 | 259 | g_o3LS.Update(e1,0); 260 | g_o3LS.Update(e2,1); 261 | g_o3LS.Update(e3,2); 262 | 263 | g_o3LS.Update(SGrundPunkt{ 25.0+sin(2*M_PI*m_dAnimatorRot)*75, 264 | 25.0-cos(2*M_PI*m_dAnimatorRot)*75},0); 265 | g_o3LS.Update(SGrundPunkt{-25.0+sin(2*M_PI*m_dAnimatorRot)*50, 266 | 25.0+cos(2*M_PI*m_dAnimatorRot)*50},1); 267 | } 268 | 269 | 270 | g_o3LS.Show(cr, m_dScale); 271 | g_o3LS.DrawGetriebe(cr, m_dAnimatorUst, m_dAnimate); 272 | m_bAnimateLeftUst = g_o3LS.m_bAnimReverse; 273 | 274 | if (m_tCollision.eWhat != SCollision::EWhat::none) 275 | { 276 | Color(cr, RED, .5); 277 | Circle(cr, m_tCollision.tWhere - m_tCollision.tOffset, 9); 278 | } 279 | 280 | // demo objects 281 | 282 | 283 | // text output 284 | Color(cr, GRAY); 285 | // draw_text(cr, {sin(2*M_PI*m_dAnimatorRot)*75, -60.0}, "Informational text submission", 4); 286 | 287 | 288 | // Buttons 289 | // draw_text(cr, {0, -120}, s, 8/m_dScale); 290 | 291 | int i=0; 292 | SPoint const tMousePos{m_tMousePos*m_dScale+m_tShift}; 293 | for ( auto const & a:m_voButtons ) 294 | { 295 | ++i; 296 | cr->set_line_width(1/m_dScale); 297 | 298 | if ( a.Collision(tMousePos) ) 299 | { 300 | cr->set_source_rgba(0,1,0,.8); 301 | } 302 | else 303 | { 304 | cr->set_source_rgba(.7,.7,.7,.8); 305 | } 306 | 307 | Rectangle( cr, (a-m_tShift)/m_dScale, SPoint{a.w/m_dScale, a.h/m_dScale} ); 308 | cr->set_source_rgb(.2,.2,.2); 309 | Frame( cr, (a-m_tShift)/m_dScale, SPoint{a.w/m_dScale, a.h/m_dScale} ); 310 | 311 | cr->set_source_rgb(0,0,0); 312 | draw_text(cr, {(a.x+a.w/2-m_tShift.x)/m_dScale, 313 | (a.y+a.h/2-m_tShift.y)/m_dScale}, a.sTitle, 1/m_dScale); 314 | } 315 | 316 | return true; 317 | } 318 | -------------------------------------------------------------------------------- /o-breakout/canvas.cpp: -------------------------------------------------------------------------------- 1 | #include "canvas.h" 2 | 3 | #include "typesNmath.h" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | bool CCanvas::Collision(SPoint const & p) 17 | { 18 | m_tCollision.eWhat = SCollision::EWhat::none; 19 | size_t i{0}; 20 | for ( auto const & a:m_vBricks ) 21 | { 22 | // if ( p.x > a.p.x && p.x < a.p.x+a.s.x && p.y > a.p.y && p.y < a.p.y+a.s.y ) 23 | if ( p.x+11 > a.p.x && p.x-11 < a.p.x+a.s.x && p.y+11 > a.p.y && p.y-11 < a.p.y+a.s.y ) 24 | { 25 | m_tCollision.eWhat = SCollision::EWhat::Element; 26 | m_tCollision.nIndex = i; 27 | return true; 28 | } 29 | ++i; 30 | } 31 | 32 | return false; 33 | } 34 | 35 | 36 | bool CCanvas::on_button_press_event(GdkEventButton *event) 37 | { 38 | m_tMousePos = (*event - m_tShift)/m_dScale; 39 | 40 | for ( auto const & a:m_voButtons ) 41 | { 42 | if ( a.Collision(*event) ) 43 | { 44 | m_oButtonPressed = a.sFunct; 45 | return true; 46 | } 47 | } 48 | 49 | if (event->type == GDK_BUTTON_PRESS ) 50 | { 51 | m_tEventPress = *event; 52 | m_tShiftStart = m_tShift; 53 | } 54 | else 55 | { 56 | // auto const bCol { Collision(m_tMousePos) }; 57 | } 58 | 59 | m_bButtonDown = true; 60 | 61 | queue_draw(); 62 | return true; 63 | } 64 | 65 | bool CCanvas::on_motion_notify_event(GdkEventMotion *event) 66 | { 67 | m_tMousePos = (*event - m_tShift)/m_dScale; 68 | 69 | if ( m_oButtonPressed > "") return true; 70 | 71 | if ( event->type & GDK_MOTION_NOTIFY ) 72 | { 73 | if ( event->state & GDK_BUTTON3_MASK ) 74 | { 75 | // m_tShift = m_tShiftStart - (m_tEventPress - *event); 76 | } 77 | else if ( event->state & GDK_BUTTON1_MASK ) 78 | { 79 | // Collision(m_tMousePos); 80 | } 81 | else 82 | { 83 | // auto const bCol { Collision(m_tMousePos) }; 84 | } 85 | } 86 | 87 | queue_draw(); 88 | return true; 89 | } 90 | 91 | bool CCanvas::on_button_release_event(GdkEventButton* event) 92 | { 93 | m_tMousePos = (*event - m_tShift)/m_dScale; 94 | m_bButtonDown = false; 95 | 96 | if ( m_oButtonPressed.size() > 0 ) 97 | { 98 | if ( event->state & GDK_BUTTON1_MASK ) 99 | { 100 | m_oButtonPressed = ""; 101 | for ( auto const & a:m_voButtons ) 102 | if ( a.Collision(*event) ) 103 | { 104 | m_oButtonPressed = a.sFunct; 105 | break; 106 | } 107 | if ( m_oButtonPressed == "0" ) { m_vBricks.clear(); } 108 | if ( m_oButtonPressed == "1" ) {} 109 | if ( m_oButtonPressed == "2" ) {} 110 | if ( m_oButtonPressed == "3" ) {} 111 | if ( m_oButtonPressed == "4" ) {} 112 | } 113 | m_oButtonPressed=""; 114 | queue_draw(); 115 | return true; 116 | } 117 | 118 | if ( event->type & GDK_MOTION_NOTIFY ) 119 | if ( event->state & GDK_BUTTON1_MASK ) 120 | { 121 | // Collision(m_tMousePos); 122 | } 123 | if ( event->state & GDK_BUTTON3_MASK ) 124 | { 125 | m_bBallFree = true; 126 | } 127 | 128 | queue_draw(); 129 | return true; 130 | } 131 | 132 | bool CCanvas::on_scroll_event(GdkEventScroll *event) 133 | { 134 | return true; 135 | 136 | SPoint const p0{ (*event - m_tShift)/m_dScale }; 137 | m_dScale *= (event->delta_y>0)?.9:1.1; if (m_dScale<.01) m_dScale=.01; 138 | SPoint const p1{ (*event - m_tShift)/m_dScale }; 139 | m_tShift -= (p0-p1)*m_dScale; 140 | 141 | queue_draw(); 142 | return true; 143 | } 144 | 145 | 146 | 147 | bool CCanvas::on_draw(CairoCtx cr) 148 | { 149 | auto const all { get_allocation() }; 150 | auto const m_tCtxSize { SPoint { (double)all.get_width(), 151 | (double)all.get_height() } }; 152 | 153 | static auto tHome{ SPoint{ m_tCtxSize }/2 }; 154 | 155 | if ( m_bShiftInit ) 156 | { 157 | tHome = m_tShift = m_tCtxSize/2; 158 | m_bShiftInit = false; 159 | } 160 | auto const tSizeHalf{m_tCtxSize/2}; 161 | if ( tHome != tSizeHalf ) 162 | { 163 | m_tShift -= tHome - tSizeHalf; tHome = tSizeHalf; 164 | } 165 | 166 | // adj the output context 167 | Cairo::Matrix matrix(1.0, 0.0, 0.0, 1.0, 0.0, 0.0); 168 | matrix.scale(m_dScale,m_dScale); 169 | matrix.translate(m_tShift.x/m_dScale, m_tShift.y/m_dScale); 170 | cr->transform(matrix); 171 | 172 | cr->set_line_cap(Cairo::LINE_CAP_ROUND); 173 | 174 | // main content 175 | 176 | if ( !m_bBricksInitialized ) 177 | { 178 | double s = 2; 179 | SPoint pgpos{SPoint{-m_tCtxSize.x, -m_tCtxSize.y}/2+SPoint{50,100}}; 180 | double xStep{12}; 181 | double yStep{16}; 182 | double w = (m_tCtxSize.x-100)/(xStep); 183 | double h = (m_tCtxSize.y-100)/(yStep); 184 | SPoint pgsiz{w-2*s, h-2*s}; 185 | m_tPlayground = { pgpos, SPoint{m_tCtxSize.x, m_tCtxSize.y}-SPoint{100,100} }; 186 | for (int x{0}; x < xStep; ++x) 187 | for (int y{0}; y < yStep/2; ++y) 188 | m_vBricks.emplace_back( SRect{ pgpos + SPoint{w*x+s, h*y+s}, pgsiz } ); 189 | 190 | m_tPaddle = SRect{ SPoint{.0, m_tCtxSize.y/2-pgsiz.y}, pgsiz }; 191 | m_tBall = SPoint{.0, m_tCtxSize.y/2-pgsiz.y-11}; 192 | 193 | m_bBricksInitialized = true; 194 | } 195 | 196 | // playground 197 | 198 | cr->set_line_width(1/m_dScale); 199 | Color( cr, BLACK ); 200 | Rectangle( cr, SPoint{-m_tCtxSize.x, -m_tCtxSize.y}/2, SPoint{m_tCtxSize.x, m_tCtxSize.y} ); 201 | Color( cr, GRAY ); 202 | Rectangle( cr, m_tPlayground ); 203 | 204 | // paddle 205 | 206 | if ( m_tMousePos.x < m_tPlayground.p.x+m_tPaddle.s.x/2 ) 207 | m_tPaddle.p.x = m_tPlayground.p.x; 208 | else if ( m_tMousePos.x > m_tPlayground.p.x+m_tPlayground.s.x-m_tPaddle.s.x/2 ) 209 | m_tPaddle.p.x = m_tPlayground.p.x+m_tPlayground.s.x-m_tPaddle.s.x; 210 | else 211 | m_tPaddle.p.x = m_tMousePos.x - m_tPaddle.s.x/2; 212 | Color( cr, YELLOW ); 213 | Rectangle( cr, m_tPaddle ); 214 | Color( cr, GRAY ); 215 | Frame( cr, m_tPaddle ); 216 | 217 | // ball 218 | 219 | if ( !m_bBallFree ) 220 | { 221 | if ( m_tMousePos.x < m_tPlayground.p.x+11 ) 222 | m_tBall.x = m_tPlayground.p.x+11; 223 | else if ( m_tMousePos.x > m_tPlayground.p.x+m_tPlayground.s.x-11 ) 224 | m_tBall.x = m_tPlayground.p.x+m_tPlayground.s.x-11; 225 | else 226 | m_tBall.x = m_tMousePos.x; 227 | } 228 | else 229 | { 230 | } 231 | Color( cr, RED ); 232 | Circle( cr, m_tBall, 11 ); 233 | Color( cr, BLACK ); 234 | Ring( cr, m_tBall, 11 ); 235 | 236 | static double m_nTick{m_dAnimator}; 237 | if ( m_bBallFree && (m_nTick != m_dAnimator) ) 238 | { 239 | m_nTick = m_dAnimator; 240 | static double m{0}; 241 | static double s{.018}; 242 | static double u{1.2}; 243 | if (Collision(m_tBall)) s = -s; 244 | m += s; 245 | if (m > 1.0 - abs(s) || m < abs(s)) 246 | { 247 | s = -s; 248 | if ( s > 0 ) 249 | { 250 | if ( m_tBall.x < (m_tPaddle.p.x - 11) || m_tBall.x > (m_tPaddle.p.x + m_tPaddle.s.x + 11) ) 251 | { 252 | m_bBallFree = false; 253 | u = 1.2; 254 | } 255 | else 256 | { 257 | u = (m_tBall.x - (m_tPaddle.p.x+m_tPaddle.s.x/2)) / ( m_tPaddle.s.x/5 ); 258 | } 259 | } 260 | } 261 | m_tBall.y = m_tCtxSize.y/2-m_tPaddle.s.y-11 - m*(m_tPlayground.s.y-m_tPaddle.s.y-11*2); 262 | 263 | m_tBall.x += u; 264 | if ( m_tBall.x < m_tPlayground.p.x+11 || m_tBall.x > m_tPlayground.p.x+m_tPlayground.s.x-11 ) 265 | { 266 | u = -u; 267 | } 268 | } 269 | 270 | // button pressed? 271 | 272 | // the bricks 273 | 274 | if ( m_tCollision.eWhat == SCollision::EWhat::Element ) 275 | { 276 | m_vBricks.erase(m_vBricks.begin()+m_tCollision.nIndex); 277 | } 278 | 279 | int i=0; 280 | // LineWidth(cr, {m_tCtxSize.y/15/m_dScale}); 281 | LineWidth(cr, {1/m_dScale}); 282 | Color(cr, GREEN); 283 | for ( auto const & a:m_vBricks ) 284 | { 285 | Color(cr, GREEN); 286 | Rectangle(cr, a); 287 | Color(cr, BLACK); 288 | Frame(cr, a); 289 | ++i; 290 | } 291 | 292 | // clock (upper right corner) 293 | 294 | auto t = std::time(nullptr); 295 | char sDate[100]; 296 | std::strftime(sDate, sizeof(sDate), "%H:%M:%S", std::localtime(&t)); 297 | Text(cr, (SPoint{-15.0,15.0}+SPoint{m_tCtxSize.x, .0}-m_tShift)/m_dScale, sDate, 1/m_dScale, false, TEXT_RIGHT); 298 | 299 | 300 | // Buttons 301 | 302 | i=0; 303 | SPoint const tMousePos{m_tMousePos*m_dScale+m_tShift}; 304 | for ( auto const & a:m_voButtons ) 305 | { 306 | ++i; 307 | cr->set_line_width(1/m_dScale); 308 | 309 | if ( a.Collision(tMousePos) ) 310 | { 311 | Color( cr, GREEN, .8 ); 312 | } 313 | else 314 | { 315 | Color( cr, {.7,.7,.7}, .8 ); 316 | } 317 | 318 | Rectangle( cr, (a-m_tShift)/m_dScale, SPoint{a.w/m_dScale, a.h/m_dScale} ); 319 | cr->set_source_rgb(.2,.2,.2); 320 | Frame ( cr, (a-m_tShift)/m_dScale, SPoint{a.w/m_dScale, a.h/m_dScale} ); 321 | 322 | Color( cr, BLACK ); 323 | Text(cr, {(a.x+a.w/2-m_tShift.x)/m_dScale, 324 | (a.y+a.h/2-m_tShift.y)/m_dScale}, a.sTitle, 1/m_dScale); 325 | } 326 | 327 | return true; 328 | } 329 | --------------------------------------------------------------------------------