mirror of
				https://github.com/ArthurSonzogni/FTXUI.git
				synced 2025-10-31 10:38:09 +08:00 
			
		
		
		
	Feature: Canvas (#287)
Draw using braille and block characters on a grid.
This commit is contained in:
		| @@ -1,7 +1,7 @@ | ||||
| set(EXAMPLES_DIR ${CMAKE_CURRENT_SOURCE_DIR}) | ||||
| function(example name) | ||||
|   add_executable(${name} ${name}.cpp) | ||||
|   target_link_libraries(${name} PUBLIC ${DIRECTORY_LIB}) | ||||
|   add_executable(ftxui_example_${name} ${name}.cpp) | ||||
|   target_link_libraries(ftxui_example_${name} PUBLIC ${DIRECTORY_LIB}) | ||||
|   file(RELATIVE_PATH dir ${EXAMPLES_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) | ||||
|   set_property(GLOBAL APPEND PROPERTY FTXUI::EXAMPLES ${dir}/${name}) | ||||
| endfunction(example) | ||||
|   | ||||
| @@ -1,16 +1,17 @@ | ||||
| set(DIRECTORY_LIB component) | ||||
|  | ||||
| example(button) | ||||
| example(canvas_animated) | ||||
| example(checkbox) | ||||
| example(checkbox_in_frame) | ||||
| example(composition) | ||||
| example(dropdown) | ||||
| example(flexbox) | ||||
| example(flexbox_gallery) | ||||
| example(focus) | ||||
| example(gallery) | ||||
| example(homescreen) | ||||
| example(input) | ||||
| example(maybe) | ||||
| example(focus) | ||||
| example(menu) | ||||
| example(menu2) | ||||
| example(menu_entries) | ||||
|   | ||||
							
								
								
									
										257
									
								
								examples/component/canvas_animated.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										257
									
								
								examples/component/canvas_animated.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,257 @@ | ||||
| #include <stddef.h>                // for size_t | ||||
| #include <stdio.h>                 // for getchar | ||||
| #include <ftxui/dom/elements.hpp>  // for operator|, size, Element, text, hcenter, Decorator, Fit, WIDTH, hflow, window, EQUAL, GREATER_THAN, HEIGHT, bold, border, dim, LESS_THAN | ||||
| #include <ftxui/screen/screen.hpp>  // for Full, Screen | ||||
| #include <memory>                   // for allocator, shared_ptr | ||||
| #include <string>  // for operator+, to_string, char_traits, string | ||||
|  | ||||
| #include "ftxui/component/component.hpp" | ||||
| #include "ftxui/component/screen_interactive.hpp" | ||||
|  | ||||
| #include <cmath> | ||||
| int main(int argc, const char* argv[]) { | ||||
|   using namespace ftxui; | ||||
|  | ||||
|   int mouse_x = 0; | ||||
|   int mouse_y = 0; | ||||
|  | ||||
|   // A triangle following the mouse, using braille characters. | ||||
|   auto renderer_line_braille = Renderer([&] { | ||||
|     auto c = Canvas(100, 100); | ||||
|     c.DrawText(0,0, "Several lines (braille)"); | ||||
|     c.DrawPointLine(mouse_x, mouse_y, 80, 10, Color::Red); | ||||
|     c.DrawPointLine(80, 10, 80, 40, Color::Blue); | ||||
|     c.DrawPointLine(80, 40, mouse_x, mouse_y, Color::Green); | ||||
|     return ElementFrom(std::move(c)); | ||||
|   }); | ||||
|  | ||||
|   // A triangle following the mouse, using block characters. | ||||
|   auto renderer_line_block = Renderer([&] { | ||||
|     auto c = Canvas(100, 100); | ||||
|     c.DrawText(0,0, "Several lines (block)"); | ||||
|     c.DrawBlockLine(mouse_x, mouse_y, 80, 10, Color::Red); | ||||
|     c.DrawBlockLine(80, 10, 80, 40, Color::Blue); | ||||
|     c.DrawBlockLine(80, 40, mouse_x, mouse_y, Color::Green); | ||||
|     return ElementFrom(std::move(c)); | ||||
|   }); | ||||
|  | ||||
|   // A circle following the mouse, using braille characters. | ||||
|   auto renderer_circle_braille = Renderer([&] { | ||||
|     auto c = Canvas(100, 100); | ||||
|     c.DrawText(0,0, "A circle (braille)"); | ||||
|     c.DrawPointCircle(mouse_x, mouse_y, 30); | ||||
|     return ElementFrom(std::move(c)); | ||||
|   }); | ||||
|  | ||||
|   // A circle following the mouse, using block characters. | ||||
|   auto renderer_circle_block = Renderer([&] { | ||||
|     auto c = Canvas(100, 100); | ||||
|     c.DrawText(0,0, "A circle (block)"); | ||||
|     c.DrawBlockCircle(mouse_x, mouse_y, 30); | ||||
|     return ElementFrom(std::move(c)); | ||||
|   }); | ||||
|  | ||||
|   // A filled circle following the mouse, using braille characters. | ||||
|   auto renderer_circle_filled_braille = Renderer([&] { | ||||
|     auto c = Canvas(100, 100); | ||||
|     c.DrawText(0,0, "A circle filled (braille)"); | ||||
|     c.DrawPointCircleFilled(mouse_x, mouse_y, 30); | ||||
|     return ElementFrom(std::move(c)); | ||||
|   }); | ||||
|  | ||||
|   // A filled circle following the mouse, using block characters. | ||||
|   auto renderer_circle_filled_block = Renderer([&] { | ||||
|     auto c = Canvas(100, 100); | ||||
|     c.DrawText(0,0, "A circle filled (block)"); | ||||
|     c.DrawBlockCircleFilled(mouse_x, mouse_y, 30); | ||||
|     return ElementFrom(std::move(c)); | ||||
|   }); | ||||
|  | ||||
|   // An ellipse following the mouse, using braille characters. | ||||
|   auto renderer_ellipse_braille = Renderer([&] { | ||||
|     auto c = Canvas(100, 100); | ||||
|     c.DrawText(0,0, "An ellipse (braille)"); | ||||
|     c.DrawPointEllipse(mouse_x / 2, mouse_y / 2, mouse_x / 2, mouse_y / 2); | ||||
|     return ElementFrom(std::move(c)); | ||||
|   }); | ||||
|  | ||||
|   // An ellipse following the mouse, using block characters. | ||||
|   auto renderer_ellipse_block = Renderer([&] { | ||||
|     auto c = Canvas(100, 100); | ||||
|     c.DrawText(0,0, "An ellipse (block)"); | ||||
|     c.DrawBlockEllipse(mouse_x / 2, mouse_y / 2, mouse_x / 2, mouse_y / 2); | ||||
|     return ElementFrom(std::move(c)); | ||||
|   }); | ||||
|  | ||||
|   // An ellipse following the mouse filled, using braille characters. | ||||
|   auto renderer_ellipse_filled_braille = Renderer([&] { | ||||
|     auto c = Canvas(100, 100); | ||||
|     c.DrawText(0,0, "A filled ellipse (braille)"); | ||||
|     c.DrawPointEllipseFilled(mouse_x / 2, mouse_y / 2, mouse_x / 2, | ||||
|                               mouse_y / 2); | ||||
|     return ElementFrom(std::move(c)); | ||||
|   }); | ||||
|  | ||||
|   // An ellipse following the mouse filled, using block characters. | ||||
|   auto renderer_ellipse_filled_block = Renderer([&] { | ||||
|     auto c = Canvas(100, 100); | ||||
|     c.DrawText(0,0, "A filled ellipse (block)"); | ||||
|     c.DrawBlockEllipseFilled(mouse_x / 2, mouse_y / 2, mouse_x / 2, | ||||
|                               mouse_y / 2); | ||||
|     c.DrawBlockEllipse(mouse_x / 2, mouse_y / 2, mouse_x / 2, mouse_y / 2); | ||||
|     return ElementFrom(std::move(c)); | ||||
|   }); | ||||
|  | ||||
|   // A text following the mouse | ||||
|   auto renderer_text = Renderer([&] { | ||||
|     auto c = Canvas(100, 100); | ||||
|     c.DrawText(0, 0, "A piece of text"); | ||||
|     c.DrawText(mouse_x, mouse_y, "This is a piece of text with effects", | ||||
|                [](Pixel& p) { | ||||
|                  p.foreground_color = Color::Red; | ||||
|                  p.underlined = true; | ||||
|                  p.bold = true; | ||||
|                }); | ||||
|     return ElementFrom(std::move(c)); | ||||
|   }); | ||||
|  | ||||
|   auto renderer_plot_1 = Renderer([&] { | ||||
|     auto c = Canvas(100, 100); | ||||
|     c.DrawText(0, 0, "A graph"); | ||||
|  | ||||
|     std::vector<int> ys(100); | ||||
|     for (int x = 0; x < 100; x++) { | ||||
|       float dx = x - mouse_x; | ||||
|       float dy = 50; | ||||
|       ys[x] = dy + 20 * cos(dx * 0.14) + 10 * sin(dx * 0.42); | ||||
|     } | ||||
|     for (int x = 1; x < 99; x++) | ||||
|       c.DrawPointLine(x, ys[x], x + 1, ys[x + 1]); | ||||
|  | ||||
|     return ElementFrom(std::move(c)); | ||||
|   }); | ||||
|  | ||||
|   auto renderer_plot_2 = Renderer([&] { | ||||
|     auto c = Canvas(100, 100); | ||||
|     c.DrawText(0, 0, "A symmetrical graph filled"); | ||||
|     std::vector<int> ys(100); | ||||
|     for (int x = 0; x < 100; x++) { | ||||
|       ys[x] = 30 +  // | ||||
|               10 * cos(x * 0.2 - mouse_x * 0.05) + // | ||||
|               5 * sin(x * 0.4) + // | ||||
|               5 * sin(x * 0.3 - mouse_y * 0.05); // | ||||
|     } | ||||
|     for (int x = 0; x < 100; x++) { | ||||
|       c.DrawPointLine(x, 50+ys[x], x, 50-ys[x], Color::Red); | ||||
|     } | ||||
|  | ||||
|     return ElementFrom(std::move(c)); | ||||
|   }); | ||||
|  | ||||
|   auto renderer_plot_3 = Renderer([&] { | ||||
|     auto c = Canvas(100, 100); | ||||
|     c.DrawText(0, 0, "A 2D gaussian plot"); | ||||
|     int size = 15; | ||||
|  | ||||
|     // mouse_x = 5mx + 3*my  | ||||
|     // mouse_y = 0mx + -5my + 90 | ||||
|     float my = (mouse_y - 90) / -5.f; | ||||
|     float mx = (mouse_x - 3 * my) / 5.f; | ||||
|     std::vector<std::vector<float>> ys(size, std::vector<float>(size)); | ||||
|     for (int y = 0; y < size; y++) { | ||||
|       for (int x = 0; x < size; x++) { | ||||
|         float dx = x-mx; | ||||
|         float dy = y-my; | ||||
|         ys[y][x] = -1.5 + 3.0 * std::exp(-0.2f * (dx*dx+dy*dy)); | ||||
|       } | ||||
|     } | ||||
|     for (int y = 0; y < size; y++) { | ||||
|       for (int x = 0; x < size; x++) { | ||||
|         if (x != 0) { | ||||
|           c.DrawPointLine( | ||||
|               5 * (x - 1) + 3 * (y - 0), 90 - 5 * (y - 0) - 5 * ys[y][x - 1], | ||||
|               5 * (x - 0) + 3 * (y - 0), 90 - 5 * (y - 0) - 5 * ys[y][x]); | ||||
|         } | ||||
|         if (y != 0) { | ||||
|           c.DrawPointLine( | ||||
|               5 * (x - 0) + 3 * (y - 1), 90 - 5 * (y - 1) - 5 * ys[y - 1][x], | ||||
|               5 * (x - 0) + 3 * (y - 0), 90 - 5 * (y - 0) - 5 * ys[y][x]); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     return ElementFrom(std::move(c)); | ||||
|   }); | ||||
|  | ||||
|  | ||||
|   int selected_tab = 0; | ||||
|   auto tab = Container::Tab({ | ||||
|       renderer_line_braille, | ||||
|       renderer_line_block, | ||||
|       renderer_circle_braille, | ||||
|       renderer_circle_block, | ||||
|       renderer_circle_filled_braille, | ||||
|       renderer_circle_filled_block, | ||||
|       renderer_ellipse_braille, | ||||
|       renderer_ellipse_block, | ||||
|       renderer_ellipse_filled_braille, | ||||
|       renderer_ellipse_filled_block, | ||||
|  | ||||
|       renderer_plot_1, | ||||
|       renderer_plot_2, | ||||
|       renderer_plot_3, | ||||
|  | ||||
|       renderer_text, | ||||
|   }, &selected_tab); | ||||
|  | ||||
|   // This capture the last mouse position. | ||||
|   auto tab_with_mouse = CatchEvent(tab, [&](Event e) { | ||||
|     if (e.is_mouse()) { | ||||
|       mouse_x = (e.mouse().x - 1) * 2; | ||||
|       mouse_y = (e.mouse().y - 1) * 4; | ||||
|     } | ||||
|     return false; | ||||
|   }); | ||||
|  | ||||
|   std::vector<std::string> tab_titles = { | ||||
|       "line (braille)", | ||||
|       "line (block)", | ||||
|       "circle (braille)", | ||||
|       "circle (block)", | ||||
|       "circle filled (braille)", | ||||
|       "circle filled (block)", | ||||
|       "ellipse (braille)", | ||||
|       "ellipse (block)", | ||||
|       "ellipse filled (braille)", | ||||
|       "ellipse filled (block)", | ||||
|       "plot_1 simple", | ||||
|       "plot_2 filled", | ||||
|       "plot_3 3D", | ||||
|       "text", | ||||
|   }; | ||||
|   auto tab_toggle = Menu(&tab_titles, &selected_tab); | ||||
|  | ||||
|   auto component = Container::Horizontal({ | ||||
|       tab_with_mouse, | ||||
|       tab_toggle, | ||||
|   }); | ||||
|  | ||||
|   // Add some separator to decorate the whole component: | ||||
|   auto component_renderer = Renderer(component, [&] { | ||||
|     return hbox({ | ||||
|                tab_with_mouse->Render(), | ||||
|                separator(), | ||||
|                tab_toggle->Render(), | ||||
|            }) | | ||||
|            border; | ||||
|   }); | ||||
|  | ||||
|   auto screen = ScreenInteractive::FitComponent(); | ||||
|   screen.Loop(component_renderer); | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| // Copyright 2021 Arthur Sonzogni. All rights reserved. | ||||
| // Use of this source code is governed by the MIT license that can be found in | ||||
| // the LICENSED file. | ||||
| @@ -37,8 +37,8 @@ int main(int argc, const char* argv[]) { | ||||
|   float focus_x = 0.0f; | ||||
|   float focus_y = 0.0f; | ||||
|  | ||||
|   auto slider_x = Slider("x", &focus_x, 0.f, 1.f, 0.05f); | ||||
|   auto slider_y = Slider("y", &focus_y, 0.f, 1.f, 0.05f); | ||||
|   auto slider_x = Slider("x", &focus_x, 0.f, 1.f, 0.01f); | ||||
|   auto slider_y = Slider("y", &focus_y, 0.f, 1.f, 0.01f); | ||||
|  | ||||
|   auto renderer = Renderer( | ||||
|       Container::Vertical({ | ||||
|   | ||||
| @@ -406,8 +406,7 @@ int main(int argc, const char* argv[]) { | ||||
|                    make_box(6, 3), | ||||
|                }), | ||||
|            }) | | ||||
|            // vscroll_indicator | yflex; | ||||
|            yflex | vscroll_indicator; | ||||
|            vscroll_indicator | yframe | flex; | ||||
|   }); | ||||
|  | ||||
|   auto paragraph_renderer_right = Renderer([] { | ||||
|   | ||||
| @@ -7,11 +7,11 @@ example(color_info_palette256) | ||||
| example(color_truecolor_HSV) | ||||
| example(color_truecolor_RGB) | ||||
| example(dbox) | ||||
| example(canvas) | ||||
| example(gauge) | ||||
| example(graph) | ||||
| example(gridbox) | ||||
| example(hflow) | ||||
| example(vflow) | ||||
| example(html_like) | ||||
| example(package_manager) | ||||
| example(paragraph) | ||||
| @@ -28,4 +28,5 @@ example(style_inverted) | ||||
| example(style_underlined) | ||||
| example(table) | ||||
| example(vbox_hbox) | ||||
| example(vflow) | ||||
| example(window) | ||||
|   | ||||
							
								
								
									
										50
									
								
								examples/dom/canvas.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								examples/dom/canvas.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,50 @@ | ||||
| #include <stddef.h>                // for size_t | ||||
| #include <stdio.h>                 // for getchar | ||||
| #include <ftxui/dom/elements.hpp>  // for operator|, size, Element, text, hcenter, Decorator, Fit, WIDTH, hflow, window, EQUAL, GREATER_THAN, HEIGHT, bold, border, dim, LESS_THAN | ||||
| #include <ftxui/screen/screen.hpp>  // for Full, Screen | ||||
| #include <memory>                   // for allocator, shared_ptr | ||||
| #include <string>  // for operator+, to_string, char_traits, string | ||||
|  | ||||
| #include "ftxui/dom/flexbox_config.hpp"  // for ftxui | ||||
| #include "ftxui/dom/node.hpp"            // for Render | ||||
|  | ||||
| #include <cmath> | ||||
| int main(int argc, const char* argv[]) { | ||||
|   using namespace ftxui; | ||||
|  | ||||
|   auto canvas = Canvas(100, 100); | ||||
|  | ||||
|   canvas.DrawText(0, 0, "This is a canvas", [](Pixel& p) -> void { | ||||
|     p.foreground_color = Color::Red; | ||||
|     p.underlined = true; | ||||
|   }); | ||||
|  | ||||
|   // Triangle: | ||||
|   canvas.DrawPointLine(10, 10, 80, 10, Color::Red); | ||||
|   canvas.DrawPointLine(80, 10, 80, 40, Color::Blue); | ||||
|   canvas.DrawPointLine(80, 40, 10, 10, Color::Green); | ||||
|  | ||||
|   // Circle, not filled and filled: | ||||
|   canvas.DrawPointCircle(30, 50, 20); | ||||
|   canvas.DrawPointCircleFilled(40, 40, 10); | ||||
|  | ||||
|   // Plot a function: | ||||
|   std::vector<int> ys(100); | ||||
|   for (int x = 0; x < 100; x++) | ||||
|     ys[x] = 80 + 20 * cos(x * 0.2); | ||||
|   for (int x = 0; x < 99; x++)  | ||||
|     canvas.DrawPointLine(x, ys[x], x + 1, ys[x + 1], Color::Red); | ||||
|  | ||||
|   auto document = ElementFrom(&canvas) | border; | ||||
|  | ||||
|   auto screen = Screen::Create(Dimension::Fit(document)); | ||||
|   Render(screen, document); | ||||
|   screen.Print(); | ||||
|   getchar(); | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| // Copyright 2020 Arthur Sonzogni. All rights reserved. | ||||
| // Use of this source code is governed by the MIT license that can be found in | ||||
| // the LICENSE file. | ||||
							
								
								
									
										38
									
								
								examples/dom/flexbox.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								examples/dom/flexbox.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| #include <stddef.h>                // for size_t | ||||
| #include <stdio.h>                 // for getchar | ||||
| #include <ftxui/dom/elements.hpp>  // for operator|, size, Element, text, hcenter, Decorator, Fit, WIDTH, hflow, window, EQUAL, GREATER_THAN, HEIGHT, bold, border, dim, LESS_THAN | ||||
| #include <ftxui/screen/screen.hpp>  // for Full, Screen | ||||
| #include <memory>                   // for allocator, shared_ptr | ||||
| #include <string>  // for operator+, to_string, char_traits, string | ||||
|  | ||||
| #include "ftxui/dom/flexbox_config.hpp"  // for ftxui | ||||
| #include "ftxui/dom/node.hpp"            // for Render | ||||
|  | ||||
| int main(int argc, const char* argv[]) { | ||||
|   using namespace ftxui; | ||||
|  | ||||
|   auto image = Canvas(100, 100); | ||||
|  | ||||
|   auto document = vbox({ | ||||
|     make_box("header"), | ||||
|     hbox({ | ||||
|       make_box("left side"), | ||||
|       make_box("center") | flex, | ||||
|       make_box("right side"), | ||||
|     }) | flex, | ||||
|     make_box("footer") | ||||
|   }); | ||||
|  | ||||
|   //auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); | ||||
|   //auto screen = Screen::Create(Dimension::Fit(document)); | ||||
|   auto screen = Screen::Create(Dimension::Full()); | ||||
|   Render(screen, document); | ||||
|   screen.Print(); | ||||
|   getchar(); | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| // Copyright 2020 Arthur Sonzogni. All rights reserved. | ||||
| // Use of this source code is governed by the MIT license that can be found in | ||||
| // the LICENSE file. | ||||
| @@ -71,7 +71,10 @@ | ||||
|       postRun: [], | ||||
|       onRuntimeInitialized: () => {}, | ||||
|     }; | ||||
|     document.querySelector("#example_script").src = example + '.js'; | ||||
|  | ||||
|     const words = example.split('/') | ||||
|     words[1] = "ftxui_example_" + words[1] + ".js" | ||||
|     document.querySelector("#example_script").src = words.join('/'); | ||||
|   </script> | ||||
|  | ||||
|   <style> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Arthur Sonzogni
					Arthur Sonzogni