libezgl: Updating libs/EXTERNAL/libezgl/ (external git subtree from https://github.com/mariobadr/ezgl.git master)
diff --git a/libs/EXTERNAL/libezgl/CMakeLists.txt b/libs/EXTERNAL/libezgl/CMakeLists.txt
index 164887e..6ab3345 100644
--- a/libs/EXTERNAL/libezgl/CMakeLists.txt
+++ b/libs/EXTERNAL/libezgl/CMakeLists.txt
@@ -3,7 +3,7 @@
# create the project
project(
ezgl
- VERSION 0.0.1
+ VERSION 1.0.1
LANGUAGES CXX
)
diff --git a/libs/EXTERNAL/libezgl/README.adoc b/libs/EXTERNAL/libezgl/README.adoc
index da62577..836033e 100644
--- a/libs/EXTERNAL/libezgl/README.adoc
+++ b/libs/EXTERNAL/libezgl/README.adoc
@@ -1,5 +1,7 @@
= EZGL - An Easy Graphics Library
+image:https://codedocs.xyz/mariobadr/ezgl.svg[link="https://codedocs.xyz/mariobadr/ezgl"]
+
EZGL is a library for use in ece297 as a simple way to create a GUI application.
The library provides a thin wrapper around GTK and drawing functionality.
diff --git a/libs/EXTERNAL/libezgl/examples/basic-application/basic_application.cpp b/libs/EXTERNAL/libezgl/examples/basic-application/basic_application.cpp
index 11071b0..2b5e288 100644
--- a/libs/EXTERNAL/libezgl/examples/basic-application/basic_application.cpp
+++ b/libs/EXTERNAL/libezgl/examples/basic-application/basic_application.cpp
@@ -29,7 +29,7 @@
void act_on_mouse_press(ezgl::application *application, GdkEventButton *event, double x, double y);
void act_on_mouse_move(ezgl::application *application, GdkEventButton *event, double x, double y);
void act_on_key_press(ezgl::application *application, GdkEventKey *event, char *key_name);
-void initial_setup(ezgl::application *application);
+void initial_setup(ezgl::application *application, bool new_window);
void test_button(GtkWidget *widget, ezgl::application *application);
/**
@@ -37,19 +37,19 @@
*
* The graphics object expects that x and y values will be in the main canvas' world coordinate system.
*/
-void draw_main_canvas(ezgl::renderer &g);
+void draw_main_canvas(ezgl::renderer *g);
/**
* draw_main_canvas helper functions
*/
-void draw_rectangle_example(ezgl::renderer &g);
-void draw_arc_example(ezgl::renderer &g);
-void rotated_text_example(ezgl::renderer &g);
-void draw_poly_example(ezgl::renderer &g);
-void draw_text_example(ezgl::renderer &g);
-void draw_line_example(ezgl::renderer &g);
-void screen_coordinates_example(ezgl::renderer &g);
-void draw_png_example(ezgl::renderer &g);
+void draw_rectangle_example(ezgl::renderer *g);
+void draw_arc_example(ezgl::renderer *g);
+void rotated_text_example(ezgl::renderer *g);
+void draw_poly_example(ezgl::renderer *g);
+void draw_text_example(ezgl::renderer *g);
+void draw_line_example(ezgl::renderer *g);
+void screen_coordinates_example(ezgl::renderer *g);
+void draw_png_example(ezgl::renderer *g);
static ezgl::rectangle initial_world{{0, 0}, 1100, 1150};
@@ -99,7 +99,7 @@
/**
* The redrawing function for still pictures
*/
-void draw_main_canvas(ezgl::renderer &g)
+void draw_main_canvas(ezgl::renderer *g)
{
// Draw some rectangles
draw_rectangle_example(g);
@@ -129,7 +129,7 @@
/**
* Draw some rectangles with different colors
*/
-void draw_rectangle_example(ezgl::renderer &g)
+void draw_rectangle_example(ezgl::renderer *g)
{
const float rectangle_width = 50;
const float rectangle_height = rectangle_width;
@@ -152,25 +152,25 @@
};
// format text font and color
- g.set_color(ezgl::BLACK);
- g.format_font("monospace", ezgl::font_slant::normal, ezgl::font_weight::normal, 10);
+ g->set_color(ezgl::BLACK);
+ g->format_font("monospace", ezgl::font_slant::normal, ezgl::font_weight::normal, 10);
// draw text
- g.draw_text({110, color_rectangle.center_y()}, "colors", 2 * (start_point.x - 110), rectangle_height);
+ g->draw_text({110, color_rectangle.center_y()}, "colors", 2 * (start_point.x - 110), rectangle_height);
for (size_t i = 0; i < sizeof (color_indicies) / sizeof (color_indicies[0]); ++i) {
// Change the color of next draw calls
- g.set_color(color_indicies[i]);
+ g->set_color(color_indicies[i]);
// Draw filled in rectangles
- g.fill_rectangle(color_rectangle);
+ g->fill_rectangle(color_rectangle);
// Increment the start point
color_rectangle += {rectangle_width, 0};
}
// Draw text
- g.draw_text({400, color_rectangle.center_y()}, "fill_rectangle", DBL_MAX, rectangle_height);
+ g->draw_text({400, color_rectangle.center_y()}, "fill_rectangle", DBL_MAX, rectangle_height);
/* Draw some rectangles with RGB triplet colors and alpha (transparency) */
@@ -182,162 +182,162 @@
color_rectangle += {rectangle_width, 0};
// Change the next draw calls color. rgb and alpha values range from 0 to 255
- g.set_color(std::rand() % 256, std::rand() % 256, std::rand() % 256, 255);
+ g->set_color(std::rand() % 256, std::rand() % 256, std::rand() % 256, 255);
// Draw filled in rectangles
- g.fill_rectangle(color_rectangle);
+ g->fill_rectangle(color_rectangle);
}
/* Draw a black border rectangle */
// Change the next draw calls color to black
- g.set_color(ezgl::BLACK);
+ g->set_color(ezgl::BLACK);
// Change the next draw calls line width
- g.set_line_width(1);
+ g->set_line_width(1);
// Draw a rectangle bordering all the drawn rectangles
- g.draw_rectangle(start_point, color_rectangle.top_right());
+ g->draw_rectangle(start_point, color_rectangle.top_right());
}
/**
* Draw some example lines, shapes, and arcs
*/
-void draw_arc_example(ezgl::renderer &g)
+void draw_arc_example(ezgl::renderer *g)
{
float radius = 50;
// Draw solid line
- g.set_color(ezgl::BLACK);
- g.draw_text({250, 150}, "draw_line", 150.0, DBL_MAX);
- g.set_line_dash(ezgl::line_dash::none);
- g.draw_line({200, 120}, {200, 200});
+ g->set_color(ezgl::BLACK);
+ g->draw_text({250, 150}, "draw_line", 150.0, DBL_MAX);
+ g->set_line_dash(ezgl::line_dash::none);
+ g->draw_line({200, 120}, {200, 200});
// Draw dashed line
- g.set_line_dash(ezgl::line_dash::asymmetric_5_3);
- g.draw_line({300, 120}, {300, 200});
+ g->set_line_dash(ezgl::line_dash::asymmetric_5_3);
+ g->draw_line({300, 120}, {300, 200});
// Draw elliptic arc
- g.set_color(ezgl::MAGENTA);
- g.draw_text({450, 160}, "draw_elliptic_arc", 150.0, DBL_MAX);
- g.draw_elliptic_arc({550, 160}, 30, 60, 90, 270);
+ g->set_color(ezgl::MAGENTA);
+ g->draw_text({450, 160}, "draw_elliptic_arc", 150.0, DBL_MAX);
+ g->draw_elliptic_arc({550, 160}, 30, 60, 90, 270);
// Draw filled in elliptic arc
- g.draw_text({700, 160}, "fill_elliptic_arc", 150.0, DBL_MAX);
- g.fill_elliptic_arc({800, 160}, 30, 60, 90, 270);
+ g->draw_text({700, 160}, "fill_elliptic_arc", 150.0, DBL_MAX);
+ g->fill_elliptic_arc({800, 160}, 30, 60, 90, 270);
// Draw arcs
- g.set_color(ezgl::BLUE);
- g.draw_text({190, 300}, "draw_arc", radius * 2, 150);
- g.draw_arc({190, 300}, radius, 0, 270);
- g.draw_arc({300, 300}, radius, 0, -180);
+ g->set_color(ezgl::BLUE);
+ g->draw_text({190, 300}, "draw_arc", radius * 2, 150);
+ g->draw_arc({190, 300}, radius, 0, 270);
+ g->draw_arc({300, 300}, radius, 0, -180);
// Draw filled in arcs
- g.fill_arc({410, 300}, radius, 90, -90);
- g.fill_arc({520, 300}, radius, 0, 360);
- g.set_color(ezgl::BLACK);
- g.draw_text({520, 300}, "fill_arc", radius * 2, 150);
- g.set_color(ezgl::BLUE);
- g.fill_arc({630, 300}, radius, 90, 180);
- g.fill_arc({740, 300}, radius, 90, 270);
- g.fill_arc({850, 300}, radius, 90, 30);
+ g->fill_arc({410, 300}, radius, 90, -90);
+ g->fill_arc({520, 300}, radius, 0, 360);
+ g->set_color(ezgl::BLACK);
+ g->draw_text({520, 300}, "fill_arc", radius * 2, 150);
+ g->set_color(ezgl::BLUE);
+ g->fill_arc({630, 300}, radius, 90, 180);
+ g->fill_arc({740, 300}, radius, 90, 270);
+ g->fill_arc({850, 300}, radius, 90, 30);
}
/**
* Draw some rotated text
*/
-void rotated_text_example(ezgl::renderer &g)
+void rotated_text_example(ezgl::renderer *g)
{
const float textsquare_width = 200;
ezgl::rectangle textsquare = {{100, 400}, textsquare_width, textsquare_width};
- g.set_color(ezgl::BLUE);
- g.draw_rectangle(textsquare);
+ g->set_color(ezgl::BLUE);
+ g->draw_rectangle(textsquare);
- g.set_color(ezgl::GREEN);
- g.draw_rectangle(textsquare.center(), {textsquare.right(), textsquare.top()});
- g.draw_rectangle({textsquare.left(), textsquare.bottom()}, textsquare.center());
+ g->set_color(ezgl::GREEN);
+ g->draw_rectangle(textsquare.center(), {textsquare.right(), textsquare.top()});
+ g->draw_rectangle({textsquare.left(), textsquare.bottom()}, textsquare.center());
- g.set_color(ezgl::RED);
- g.draw_line({textsquare.left(), textsquare.bottom()}, {textsquare.right(), textsquare.top()});
- g.draw_line({textsquare.left(), textsquare.top()}, {textsquare.right(), textsquare.bottom()});
+ g->set_color(ezgl::RED);
+ g->draw_line({textsquare.left(), textsquare.bottom()}, {textsquare.right(), textsquare.top()});
+ g->draw_line({textsquare.left(), textsquare.top()}, {textsquare.right(), textsquare.bottom()});
- g.set_color(0, 0, 0, 100);
- g.set_font_size(14);
- g.draw_text({textsquare.center_x(), textsquare.bottom()}, "0 degrees", textsquare.width(), textsquare.height());
+ g->set_color(0, 0, 0, 100);
+ g->set_font_size(14);
+ g->draw_text({textsquare.center_x(), textsquare.bottom()}, "0 degrees", textsquare.width(), textsquare.height());
- g.set_text_rotation(90);
- g.draw_text({textsquare.right(), textsquare.center_y()}, "90 degrees", textsquare.width(), textsquare.height());
+ g->set_text_rotation(90);
+ g->draw_text({textsquare.right(), textsquare.center_y()}, "90 degrees", textsquare.width(), textsquare.height());
- g.set_text_rotation(180);
- g.draw_text({textsquare.center_x(), textsquare.top()}, "180 degrees", textsquare.width(), textsquare.height());
+ g->set_text_rotation(180);
+ g->draw_text({textsquare.center_x(), textsquare.top()}, "180 degrees", textsquare.width(), textsquare.height());
- g.set_text_rotation(270);
- g.draw_text({textsquare.left(), textsquare.center_y()}, "270 degrees", textsquare.width(), textsquare.height());
+ g->set_text_rotation(270);
+ g->draw_text({textsquare.left(), textsquare.center_y()}, "270 degrees", textsquare.width(), textsquare.height());
- g.set_text_rotation(45);
- g.draw_text(textsquare.center(), "45 degrees", textsquare.width(), textsquare.height());
+ g->set_text_rotation(45);
+ g->draw_text(textsquare.center(), "45 degrees", textsquare.width(), textsquare.height());
- g.set_text_rotation(135);
- g.draw_text(textsquare.center(), "135 degrees", textsquare.width(), textsquare.height());
+ g->set_text_rotation(135);
+ g->draw_text(textsquare.center(), "135 degrees", textsquare.width(), textsquare.height());
// It is probably a good idea to set text rotation back to zero,
- g.set_text_rotation(0);
+ g->set_text_rotation(0);
}
/**
* Draw some Polygons
*/
-void draw_poly_example(ezgl::renderer &g)
+void draw_poly_example(ezgl::renderer *g)
{
- g.set_font_size(10);
- g.set_color(ezgl::RED);
+ g->set_font_size(10);
+ g->set_color(ezgl::RED);
// Draw a triangle
- g.fill_poly({{500, 400}, {440, 480}, {560, 480}});
+ g->fill_poly({{500, 400}, {440, 480}, {560, 480}});
// Draw a 4-point polygon
- g.fill_poly({{700, 400}, {650, 480}, {750, 480}, {800, 400}});
+ g->fill_poly({{700, 400}, {650, 480}, {750, 480}, {800, 400}});
- g.set_color(ezgl::BLACK);
- g.draw_text({500, 450}, "fill_poly", 80.0, DBL_MAX);
- g.draw_text({725, 440}, "fill_poly", 100.0, DBL_MAX);
+ g->set_color(ezgl::BLACK);
+ g->draw_text({500, 450}, "fill_poly", 80.0, DBL_MAX);
+ g->draw_text({725, 440}, "fill_poly", 100.0, DBL_MAX);
- g.set_color(ezgl::DARK_GREEN);
- g.set_line_dash(ezgl::line_dash::none);
+ g->set_color(ezgl::DARK_GREEN);
+ g->set_line_dash(ezgl::line_dash::none);
ezgl::rectangle rect = {{350, 550}, {650, 670}};
- g.draw_text(rect.center(), "draw_rectangle", rect.width(), rect.height());
- g.draw_rectangle(rect);
+ g->draw_text(rect.center(), "draw_rectangle", rect.width(), rect.height());
+ g->draw_rectangle(rect);
/* Draw some semi-transparent primitives */
- g.set_font_size(10);
+ g->set_font_size(10);
- g.set_color(255, 0, 0, 255);
- g.fill_rectangle({1000, 400}, {1050, 800});
+ g->set_color(255, 0, 0, 255);
+ g->fill_rectangle({1000, 400}, {1050, 800});
- g.set_color(0, 0, 255, 255);
- g.fill_rectangle({1000+50, 400}, {1050+50, 800});
+ g->set_color(0, 0, 255, 255);
+ g->fill_rectangle({1000+50, 400}, {1050+50, 800});
- g.set_color(0, 255, 0, 255/2); // 50% transparent
- g.fill_rectangle({1000+25, 400-100}, {1050+25, 800-200});
+ g->set_color(0, 255, 0, 255/2); // 50% transparent
+ g->fill_rectangle({1000+25, 400-100}, {1050+25, 800-200});
- g.set_color(255, 100, 255, 255/2);
- g.fill_poly({{465, 380}, {400, 450}, {765, 450}, {850, 380}});
+ g->set_color(255, 100, 255, 255/2);
+ g->fill_poly({{465, 380}, {400, 450}, {765, 450}, {850, 380}});
- g.set_color(100, 100, 255, 255/3);
- g.fill_poly({{550, 420}, {475, 500}, {875, 500}});
+ g->set_color(100, 100, 255, 255/3);
+ g->fill_poly({{550, 420}, {475, 500}, {875, 500}});
- g.set_color(ezgl::BLACK);
- g.set_text_rotation(90);
- g.draw_text({1000 - 50, 500}, "Partially transparent polys", 500, DBL_MAX);
- g.set_text_rotation(0);
+ g->set_color(ezgl::BLACK);
+ g->set_text_rotation(90);
+ g->draw_text({1000 - 50, 500}, "Partially transparent polys", 500, DBL_MAX);
+ g->set_text_rotation(0);
}
/**
* Draw some example text, with the bounding box functions
*/
-void draw_text_example(ezgl::renderer &g)
+void draw_text_example(ezgl::renderer *g)
{
const float text_example_width = 800;
@@ -362,16 +362,16 @@
{24, 32}
};
- g.set_color(ezgl::BLACK);
- g.set_line_dash(ezgl::line_dash::asymmetric_5_3);
+ g->set_color(ezgl::BLACK);
+ g->set_line_dash(ezgl::line_dash::asymmetric_5_3);
for (int i = 0; i < num_lines; ++i) {
ezgl::rectangle text_bbox = {{100., 710. + i * 60.}, text_example_width / num_strings_per_line[i], 60.};
for (int j = 0; j < num_strings_per_line[i]; ++j) {
- g.set_font_size(text_sizes[i][j]);
- g.draw_text(text_bbox.center(), line_text[i][j], text_bbox.width(), text_bbox.height());
- g.draw_rectangle(text_bbox);
+ g->set_font_size(text_sizes[i][j]);
+ g->draw_text(text_bbox.center(), line_text[i][j], text_bbox.width(), text_bbox.height());
+ g->draw_rectangle(text_bbox);
text_bbox = {{text_bbox.left() + text_example_width / num_strings_per_line[i], text_bbox.bottom()} , text_bbox.width(), text_bbox.height()};
}
}
@@ -380,52 +380,52 @@
/**
* Draw wide lines with different end shapes
*/
-void draw_line_example(ezgl::renderer &g)
+void draw_line_example(ezgl::renderer *g)
{
- g.set_font_size(10);
+ g->set_font_size(10);
for (int i = 0; i <= 2; ++i)
{
double offsetY = 50*i;
- g.set_horiz_text_just(ezgl::text_just::left);
+ g->set_horiz_text_just(ezgl::text_just::left);
if (i == 0) {
- g.set_color(ezgl::BLACK);
- g.set_line_cap(ezgl::line_cap::butt); // Butt ends
- g.set_line_dash(ezgl::line_dash::none); // Solid line
- g.draw_text({950, 920+offsetY}, "Butt ends, opaque", 400, DBL_MAX);
+ g->set_color(ezgl::BLACK);
+ g->set_line_cap(ezgl::line_cap::butt); // Butt ends
+ g->set_line_dash(ezgl::line_dash::none); // Solid line
+ g->draw_text({950, 920+offsetY}, "Butt ends, opaque", 400, DBL_MAX);
}
else if (i == 1) {
- g.set_color(ezgl::GREEN, 255*2/3); // Green line that is 33% transparent)
- g.set_line_cap(ezgl::line_cap::round); // Round ends
- g.set_line_dash(ezgl::line_dash::none); // Solid line
- g.draw_text({950, 920+offsetY}, "Round ends, 33% transparent", 400, DBL_MAX);
+ g->set_color(ezgl::GREEN, 255*2/3); // Green line that is 33% transparent)
+ g->set_line_cap(ezgl::line_cap::round); // Round ends
+ g->set_line_dash(ezgl::line_dash::none); // Solid line
+ g->draw_text({950, 920+offsetY}, "Round ends, 33% transparent", 400, DBL_MAX);
}
else {
- g.set_color(ezgl::RED, 255/3); // Red line that is 67% transparent
- g.set_line_cap(ezgl::line_cap::butt); // butt ends
- g.set_line_dash(ezgl::line_dash::asymmetric_5_3); // Dashed line
- g.draw_text({950, 920+offsetY}, "Butt ends, 67% transparent", 400, DBL_MAX);
+ g->set_color(ezgl::RED, 255/3); // Red line that is 67% transparent
+ g->set_line_cap(ezgl::line_cap::butt); // butt ends
+ g->set_line_dash(ezgl::line_dash::asymmetric_5_3); // Dashed line
+ g->draw_text({950, 920+offsetY}, "Butt ends, 67% transparent", 400, DBL_MAX);
}
- g.set_horiz_text_just(ezgl::text_just::center);
+ g->set_horiz_text_just(ezgl::text_just::center);
- g.draw_text({200, 900+offsetY}, "Thin line (width 1)", 200, DBL_MAX);
- g.set_line_width(1);
- g.draw_line({100, 920+offsetY}, {300, 920+offsetY});
+ g->draw_text({200, 900+offsetY}, "Thin line (width 1)", 200, DBL_MAX);
+ g->set_line_width(1);
+ g->draw_line({100, 920+offsetY}, {300, 920+offsetY});
- g.draw_text({500, 900+offsetY}, "Width 3 Line", 200, DBL_MAX);
- g.set_line_width(3);
- g.draw_line({400, 920+offsetY}, {600, 920+offsetY});
+ g->draw_text({500, 900+offsetY}, "Width 3 Line", 200, DBL_MAX);
+ g->set_line_width(3);
+ g->draw_line({400, 920+offsetY}, {600, 920+offsetY});
- g.draw_text({800, 900+offsetY}, "Width 6 Line", 200, DBL_MAX);
- g.set_line_width(6);
- g.draw_line({700, 920+offsetY}, {900, 920+offsetY});
+ g->draw_text({800, 900+offsetY}, "Width 6 Line", 200, DBL_MAX);
+ g->set_line_width(6);
+ g->draw_line({700, 920+offsetY}, {900, 920+offsetY});
- g.set_line_width(1);
+ g->set_line_width(1);
}
}
@@ -433,33 +433,33 @@
* Draw to screen coordinates where (0,0) is the top-left corner of the window
* These coordinates are not transformed so the object will not pan or zoom.
*/
-void screen_coordinates_example(ezgl::renderer &g)
+void screen_coordinates_example(ezgl::renderer *g)
{
// Set the coordinate system to SCREEN
- g.set_coordinate_system(ezgl::SCREEN);
+ g->set_coordinate_system(ezgl::SCREEN);
- g.set_color(255, 0, 0, 255);
- g.set_line_dash(ezgl::line_dash::none);
- g.draw_rectangle({10, 10}, {100, 100});
- g.set_font_size(10);
- g.draw_text({55, 33}, "Screen coord");
- g.draw_text({55, 66}, "Fixed loc");
+ g->set_color(255, 0, 0, 255);
+ g->set_line_dash(ezgl::line_dash::none);
+ g->draw_rectangle({10, 10}, {100, 100});
+ g->set_font_size(10);
+ g->draw_text({55, 33}, "Screen coord");
+ g->draw_text({55, 66}, "Fixed loc");
// Set the coordinate system back to WORLD
- g.set_coordinate_system(ezgl::WORLD);
+ g->set_coordinate_system(ezgl::WORLD);
}
/**
* Draw a small PNG
*/
-void draw_png_example(ezgl::renderer &g)
+void draw_png_example(ezgl::renderer *g)
{
ezgl::surface *png_surface = ezgl::renderer::load_png("small_image.png");
- g.draw_surface(png_surface, {50, 200});
+ g->draw_surface(png_surface, {50, 200});
ezgl::renderer::free_surface(png_surface);
- g.set_font_size(10);
- g.set_color(ezgl::BLACK);
- g.draw_text ({50, 225}, "draw_surface", 200, DBL_MAX);
+ g->set_font_size(10);
+ g->set_color(ezgl::BLACK);
+ g->draw_text ({50, 225}, "draw_surface", 200, DBL_MAX);
}
/**
@@ -467,7 +467,7 @@
* Can be used to create additional buttons, initialize the status message,
* or connect added widgets to their callback functions
*/
-void initial_setup(ezgl::application *application)
+void initial_setup(ezgl::application *application, bool /*new_window*/)
{
// Update the status bar message
application->update_message("EZGL Application");
@@ -540,10 +540,10 @@
application->refresh_drawing();
// Draw a temporary rectangle border
- ezgl::renderer g = application->get_renderer();
- g.set_line_width(1);
- g.set_color(ezgl::BLACK);
- g.draw_rectangle({{0, 0}, 1100, 1150});
+ ezgl::renderer *g = application->get_renderer();
+ g->set_line_width(1);
+ g->set_color(ezgl::BLACK);
+ g->draw_rectangle({{0, 0}, 1100, 1150});
application->flush_drawing();
}
diff --git a/libs/EXTERNAL/libezgl/include/ezgl/application.hpp b/libs/EXTERNAL/libezgl/include/ezgl/application.hpp
index 256d0b0..8015f2e 100644
--- a/libs/EXTERNAL/libezgl/include/ezgl/application.hpp
+++ b/libs/EXTERNAL/libezgl/include/ezgl/application.hpp
@@ -48,7 +48,7 @@
/**
* The signature of a setup callback function
*/
-using setup_callback_fn = void (*)(application *app);
+using setup_callback_fn = void (*)(application *app, bool new_window);
/**
* The signature of a button callback function
@@ -225,16 +225,14 @@
void refresh_drawing();
/**
- * Get a temporary renderer that can be used to draw on top of the main canvas
- *
- * The returned renderer should be used only in the same callback in which this function is called
+ * Get a renderer that can be used to draw on top of the main canvas
*/
- renderer get_renderer();
+ renderer *get_renderer();
/**
* Flush the drawings done by the renderer, returned from get_renderer(), to the on-screen buffer
*
- * The flushing is done after returning to the GTK event loop
+ * The flushing is done immediately
*/
void flush_drawing();
@@ -357,6 +355,9 @@
// A flag that indicates if the run() was called before or not to allow multiple reruns
bool first_run;
+ // A flag that indicates if we are resuming an older run to allow proper quitting
+ bool resume_run;
+
private:
// Called when our GtkApplication is initialized for the first time.
static void startup(GtkApplication *gtk_app, gpointer user_data);
diff --git a/libs/EXTERNAL/libezgl/include/ezgl/canvas.hpp b/libs/EXTERNAL/libezgl/include/ezgl/canvas.hpp
index 5bf4636..b6aa475 100644
--- a/libs/EXTERNAL/libezgl/include/ezgl/canvas.hpp
+++ b/libs/EXTERNAL/libezgl/include/ezgl/canvas.hpp
@@ -40,7 +40,7 @@
/**
* The signature of a function that draws to an ezgl::canvas.
*/
-using draw_canvas_fn = void (*)(renderer &);
+using draw_canvas_fn = void (*)(renderer*);
/**
* Responsible for creating, destroying, and maintaining the rendering context of a GtkWidget.
@@ -100,11 +100,9 @@
}
/**
- * Create a temporary renderer that can be used to draw on top of the current canvas
- *
- * The created renderer should be used only in the same callback in which it was created
+ * Create an animation renderer that can be used to draw on top of the current canvas
*/
- renderer create_temporary_renderer();
+ renderer *create_animation_renderer();
/**
* print_pdf, print_svg, and print_png generate a PDF, SVG, or PNG output file showing
@@ -158,6 +156,9 @@
// The off-screen cairo context that can be drawn to
cairo_t *m_context = nullptr;
+ // The animation renderer
+ renderer *m_animation_renderer = nullptr;
+
private:
// Called each time our drawing area widget has changed (e.g., in size).
static gboolean configure_event(GtkWidget *widget, GdkEventConfigure *event, gpointer data);
diff --git a/libs/EXTERNAL/libezgl/include/ezgl/graphics.hpp b/libs/EXTERNAL/libezgl/include/ezgl/graphics.hpp
index d9fd36a..35e41d4 100644
--- a/libs/EXTERNAL/libezgl/include/ezgl/graphics.hpp
+++ b/libs/EXTERNAL/libezgl/include/ezgl/graphics.hpp
@@ -467,6 +467,14 @@
*/
renderer(cairo_t *cairo, transform_fn transform, camera *m_camera, cairo_surface_t *m_surface);
+ /**
+ * Update the renderer when the cairo surface/context changes
+ *
+ * @param cairo The new cairo graphics state
+ * @param m_surface The new cairo surface
+ */
+ void update_renderer(cairo_t *cairo, cairo_surface_t *m_surface);
+
private:
void draw_rectangle_path(point2d start, point2d end, bool fill_flag);
@@ -496,16 +504,7 @@
// The x11 context
GC x11_context;
- // Current line width
- int current_line_width = 1;
-
- // Current line cap
- line_cap current_line_cap = line_cap::butt;
-
- // Current line dash
- line_dash current_line_dash = line_dash::none;
-
- // Transparency flag, if set cairo will be used
+ // Transparency flag, if set, cairo will be used
bool transparency_flag = false;
#endif
@@ -522,6 +521,18 @@
// Current vertical text justification
text_just vert_text_just = text_just::center;
+
+ // Current line width
+ int current_line_width = 1;
+
+ // Current line cap
+ line_cap current_line_cap = line_cap::butt;
+
+ // Current line dash
+ line_dash current_line_dash = line_dash::none;
+
+ // Current color
+ color current_color = {0, 0, 0, 255};
};
}
diff --git a/libs/EXTERNAL/libezgl/src/application.cpp b/libs/EXTERNAL/libezgl/src/application.cpp
index b850f86..0a1cdf7 100644
--- a/libs/EXTERNAL/libezgl/src/application.cpp
+++ b/libs/EXTERNAL/libezgl/src/application.cpp
@@ -63,7 +63,7 @@
}
if(ezgl_app->initial_setup_callback != nullptr)
- ezgl_app->initial_setup_callback(ezgl_app);
+ ezgl_app->initial_setup_callback(ezgl_app, true);
g_info("application::activate successful.");
}
@@ -87,6 +87,7 @@
g_signal_connect(m_application, "activate", G_CALLBACK(activate), this);
first_run = true;
+ resume_run = false;
}
application::~application()
@@ -156,9 +157,35 @@
mouse_move_callback = mouse_move_user_callback;
key_press_callback = key_press_user_callback;
+ if(first_run) {
+ // set the first_run flag to false
+ first_run = false;
+
+ g_info("The event loop is now starting.");
+
+ // see: https://developer.gnome.org/gio/stable/GApplication.html#g-application-run
+ return g_application_run(G_APPLICATION(m_application), 0, 0);
+ }
// The result of calling g_application_run() again after it returns is unspecified.
- // So we have to destruct and reconstruct the GTKApplication
- if(!first_run) {
+ // So in the subsequent runs instead of calling g_application_run(), we will go back to the event loop using gtk_main()
+ else if(!first_run && gtk_application_get_active_window(m_application) != nullptr) {
+
+ // Call user's initial setup call
+ if(initial_setup_callback != nullptr)
+ initial_setup_callback(this, false);
+
+ // set the resume_run flag to true
+ resume_run = true;
+
+ g_info("The event loop is now resuming.");
+
+ // see: https://developer.gnome.org/gtk3/stable/gtk3-General.html#gtk-main
+ gtk_main();
+
+ return 0;
+ }
+ // But if the GTK window is closed, we will have to destruct and reconstruct the GTKApplication
+ else {
// Destroy the GTK application
g_object_unref(m_application);
g_object_unref(m_builder);
@@ -168,25 +195,26 @@
m_builder = (gtk_builder_new());
g_signal_connect(m_application, "startup", G_CALLBACK(startup), this);
g_signal_connect(m_application, "activate", G_CALLBACK(activate), this);
+
+ // set the resume_run flag to false
+ resume_run = false;
+
+ g_info("The event loop is now restarting.");
+
+ // see: https://developer.gnome.org/gio/stable/GApplication.html#g-application-run
+ return g_application_run(G_APPLICATION(m_application), 0, 0);
}
-
- // set the first_run flag to false
- first_run = false;
-
- g_info("The event loop is now starting.");
-
- // see: https://developer.gnome.org/gio/unstable/GApplication.html#g-application-run
- return g_application_run(G_APPLICATION(m_application), 0, 0);
}
void application::quit()
{
- // Close the current window
- GObject *window = get_object(m_window_id.c_str());
- gtk_window_close(GTK_WINDOW(window));
-
- // Quit the GTK application
- g_application_quit(G_APPLICATION(m_application));
+ if(resume_run) {
+ // Quit the event loop (exit gtk_main())
+ gtk_main_quit();
+ } else {
+ // Quit the GTK application (exit g_application_run())
+ g_application_quit(G_APPLICATION(m_application));
+ }
}
void application::register_default_events_callbacks(ezgl::application *application)
@@ -213,6 +241,9 @@
// Connect scroll_mouse function to the mouse scroll event (up, down, left and right)
g_signal_connect(main_canvas, "scroll_event", G_CALLBACK(scroll_mouse), application);
+
+ // Connect press_proceed function to the close button of the MainWindow
+ g_signal_connect(window, "destroy", G_CALLBACK(press_proceed), application);
}
void application::register_default_buttons_callbacks(ezgl::application *application)
@@ -410,14 +441,18 @@
// queue a redraw of the GtkWidget
gtk_widget_queue_draw(drawing_area);
+
+ // run the main loop on pending events
+ while(gtk_events_pending())
+ gtk_main_iteration();
}
-renderer application::get_renderer()
+renderer *application::get_renderer()
{
// get the main canvas
canvas *cnv = get_canvas(m_canvas_id);
- return cnv->create_temporary_renderer();
+ return cnv->create_animation_renderer();
}
void set_disable_event_loop(bool new_setting)
diff --git a/libs/EXTERNAL/libezgl/src/canvas.cpp b/libs/EXTERNAL/libezgl/src/canvas.cpp
index fcf72f7..9821036 100644
--- a/libs/EXTERNAL/libezgl/src/canvas.cpp
+++ b/libs/EXTERNAL/libezgl/src/canvas.cpp
@@ -86,7 +86,7 @@
camera pdf_cam = m_camera;
pdf_cam.update_widget(surface_width, surface_height);
renderer g(context, std::bind(&camera::world_to_screen, pdf_cam, _1), &pdf_cam, pdf_surface);
- m_draw_callback(g);
+ m_draw_callback(&g);
// free surface & context
cairo_surface_destroy(pdf_surface);
@@ -125,7 +125,7 @@
camera svg_cam = m_camera;
svg_cam.update_widget(surface_width, surface_height);
renderer g(context, std::bind(&camera::world_to_screen, svg_cam, _1), &svg_cam, svg_surface);
- m_draw_callback(g);
+ m_draw_callback(&g);
// free surface & context
cairo_surface_destroy(svg_surface);
@@ -164,7 +164,7 @@
camera png_cam = m_camera;
png_cam.update_widget(surface_width, surface_height);
renderer g(context, std::bind(&camera::world_to_screen, png_cam, _1), &png_cam, png_surface);
- m_draw_callback(g);
+ m_draw_callback(&g);
// create png output file
cairo_surface_write_to_png(png_surface, file_name);
@@ -205,6 +205,10 @@
// Draw to the newly created surface.
ezgl_canvas->redraw();
+ // Update the animation renderer
+ if(ezgl_canvas->m_animation_renderer != nullptr)
+ ezgl_canvas->m_animation_renderer->update_renderer(p_context, p_surface);
+
g_info("canvas::configure_event has been handled.");
return TRUE; // the configure event was handled
}
@@ -241,6 +245,10 @@
if(m_context != nullptr) {
cairo_destroy(m_context);
}
+
+ if(m_animation_renderer != nullptr) {
+ delete m_animation_renderer;
+ }
}
int canvas::width() const
@@ -287,19 +295,21 @@
cairo_paint(m_context);
using namespace std::placeholders;
- renderer g(m_context, std::bind(&camera::world_to_screen, m_camera, _1), &m_camera, m_surface);
- m_draw_callback(g);
+ renderer g(m_context, std::bind(&camera::world_to_screen, &m_camera, _1), &m_camera, m_surface);
+ m_draw_callback(&g);
gtk_widget_queue_draw(m_drawing_area);
g_info("The canvas will be redrawn.");
}
-renderer canvas::create_temporary_renderer()
+renderer *canvas::create_animation_renderer()
{
- using namespace std::placeholders;
- renderer g(m_context, std::bind(&camera::world_to_screen, m_camera, _1), &m_camera, m_surface);
+ if(m_animation_renderer == nullptr) {
+ using namespace std::placeholders;
+ m_animation_renderer = new renderer(m_context, std::bind(&camera::world_to_screen, &m_camera, _1), &m_camera, m_surface);
+ }
- return g;
+ return m_animation_renderer;
}
} // namespace ezgl
diff --git a/libs/EXTERNAL/libezgl/src/graphics.cpp b/libs/EXTERNAL/libezgl/src/graphics.cpp
index b7574c4..28ce32f 100644
--- a/libs/EXTERNAL/libezgl/src/graphics.cpp
+++ b/libs/EXTERNAL/libezgl/src/graphics.cpp
@@ -56,6 +56,36 @@
#endif
}
+void renderer::update_renderer(cairo_t *cairo, cairo_surface_t *m_surface)
+{
+ // Update Cairo Context
+ m_cairo = cairo;
+
+ // Update X11 Context
+#ifdef EZGL_USE_X11
+ // Check if the created cairo surface is an XLIB surface
+ if (cairo_surface_get_type(m_surface) == CAIRO_SURFACE_TYPE_XLIB) {
+ // get the underlying x11 drawable used by cairo surface
+ x11_drawable = cairo_xlib_surface_get_drawable(m_surface);
+
+ // get the x11 display
+ x11_display = cairo_xlib_surface_get_display(m_surface);
+
+ // create the x11 context from the drawable of the cairo surface
+ if (x11_display != nullptr) {
+ XFreeGC(x11_display, x11_context);
+ x11_context = XCreateGC(x11_display, x11_drawable, 0, 0);
+ }
+ }
+#endif
+
+ // Restore graphics attributes
+ set_color(current_color);
+ set_line_width(current_line_width);
+ set_line_cap(current_line_cap);
+ set_line_dash(current_line_dash);
+}
+
void renderer::set_coordinate_system(t_coordinate_system new_coordinate_system)
{
current_coordinate_system = new_coordinate_system;
@@ -161,6 +191,9 @@
// set color for cairo
cairo_set_source_rgba(m_cairo, red / 255.0, green / 255.0, blue / 255.0, alpha / 255.0);
+ // set current_color
+ current_color = {red, green, blue, alpha};
+
#ifdef EZGL_USE_X11
// check transparency
if(alpha != 255)
@@ -185,9 +218,10 @@
auto cairo_cap = static_cast<cairo_line_cap_t>(cap);
cairo_set_line_cap(m_cairo, cairo_cap);
+ current_line_cap = cap;
+
#ifdef EZGL_USE_X11
if (x11_display != nullptr) {
- current_line_cap = cap;
XSetLineAttributes(x11_display, x11_context, current_line_width,
current_line_dash == line_dash::none ? LineSolid : LineOnOffDash,
current_line_cap == line_cap::butt ? CapButt : CapRound, JoinMiter);
@@ -208,9 +242,10 @@
cairo_set_dash(m_cairo, dashes, num_dashes, 0);
}
+ current_line_dash = dash;
+
#ifdef EZGL_USE_X11
if (x11_display != nullptr) {
- current_line_dash = dash;
XSetLineAttributes(x11_display, x11_context, current_line_width,
current_line_dash == line_dash::none ? LineSolid : LineOnOffDash,
current_line_cap == line_cap::butt ? CapButt : CapRound, JoinMiter);
@@ -222,9 +257,10 @@
{
cairo_set_line_width(m_cairo, width == 0 ? 1 : width);
+ current_line_width = width;
+
#ifdef EZGL_USE_X11
if (x11_display != nullptr) {
- current_line_width = width;
XSetLineAttributes(x11_display, x11_context, current_line_width,
current_line_dash == line_dash::none ? LineSolid : LineOnOffDash,
current_line_cap == line_cap::butt ? CapButt : CapRound, JoinMiter);