mirror of
				https://github.com/ArthurSonzogni/FTXUI.git
				synced 2025-10-31 10:38:09 +08:00 
			
		
		
		
	Introduce ResizableSplit
This commit is contained in:
		 ArthurSonzogni
					ArthurSonzogni
				
			
				
					committed by
					
						 Arthur Sonzogni
						Arthur Sonzogni
					
				
			
			
				
	
			
			
			 Arthur Sonzogni
						Arthur Sonzogni
					
				
			
						parent
						
							aacb677e84
						
					
				
				
					commit
					bba2abbb60
				
			| @@ -101,6 +101,7 @@ add_library(component STATIC | ||||
|   src/ftxui/component/radiobox.cpp | ||||
|   src/ftxui/component/radiobox.cpp | ||||
|   src/ftxui/component/renderer.cpp | ||||
|   src/ftxui/component/resizable_split.cpp | ||||
|   src/ftxui/component/screen_interactive.cpp | ||||
|   src/ftxui/component/slider.cpp | ||||
|   src/ftxui/component/terminal_input_parser.cpp | ||||
|   | ||||
| @@ -21,3 +21,4 @@ example(slider_rgb) | ||||
| example(tab_horizontal) | ||||
| example(tab_vertical) | ||||
| example(toggle) | ||||
| example(resizable_split) | ||||
|   | ||||
							
								
								
									
										34
									
								
								examples/component/resizable_split.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								examples/component/resizable_split.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| #include "ftxui/component/component.hpp"           // for Slider | ||||
| #include "ftxui/component/screen_interactive.hpp"  // for ScreenInteractive | ||||
|  | ||||
| using namespace ftxui; | ||||
|  | ||||
| int main(int argc, const char* argv[]) { | ||||
|   auto screen = ScreenInteractive::Fullscreen(); | ||||
|  | ||||
|   auto middle = Renderer([] { return text(L"middle") | center; }); | ||||
|   auto left = Renderer([] { return text(L"Left") | center; }); | ||||
|   auto right = Renderer([] { return text(L"right") | center; }); | ||||
|   auto top = Renderer([] { return text(L"top") | center; }); | ||||
|   auto bottom = Renderer([] { return text(L"bottom") | center; }); | ||||
|  | ||||
|   int left_size = 20; | ||||
|   int right_size = 20; | ||||
|   int top_size = 10; | ||||
|   int bottom_size = 10; | ||||
|  | ||||
|   auto container = middle; | ||||
|   container = ResizableSplit::Left(left, container, &left_size); | ||||
|   container = ResizableSplit::Right(right, container, &right_size); | ||||
|   container = ResizableSplit::Top(top, container, &top_size); | ||||
|   container = ResizableSplit::Bottom(bottom, container, &bottom_size); | ||||
|  | ||||
|   auto renderer = | ||||
|       Renderer(container, [&] { return container->Render() | border; }); | ||||
|  | ||||
|   screen.Loop(renderer); | ||||
| } | ||||
|  | ||||
| // 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. | ||||
| @@ -41,8 +41,16 @@ namespace Container { | ||||
| Component Vertical(Components children); | ||||
| Component Horizontal(Components children); | ||||
| Component Tab(Components children, int* selector); | ||||
|  | ||||
| }  // namespace Container | ||||
|  | ||||
| namespace ResizableSplit { | ||||
| Component Left(Component main, Component back, int* main_size); | ||||
| Component Right(Component main, Component back, int* main_size); | ||||
| Component Top(Component main, Component back, int* main_size); | ||||
| Component Bottom(Component main, Component back, int* main_size); | ||||
| }  // namespace ResizableSplit | ||||
|  | ||||
| }  // namespace ftxui | ||||
|  | ||||
| #endif /* end of include guard: FTXUI_COMPONENT_HPP */ | ||||
|   | ||||
							
								
								
									
										257
									
								
								src/ftxui/component/resizable_split.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										257
									
								
								src/ftxui/component/resizable_split.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,257 @@ | ||||
| #include "ftxui/component/captured_mouse.hpp"  // for CapturedMouse | ||||
| #include "ftxui/component/component.hpp" | ||||
| #include "ftxui/component/component_base.hpp" | ||||
| #include "ftxui/component/event.hpp" | ||||
| #include "ftxui/dom/elements.hpp" | ||||
|  | ||||
| namespace ftxui { | ||||
| namespace { | ||||
|  | ||||
| class ResizableSplitLeft : public ComponentBase { | ||||
|  public: | ||||
|   ResizableSplitLeft(Component main, Component child, int* main_size) | ||||
|       : main_(main), child_(child), main_size_(main_size) { | ||||
|     Add(Container::Horizontal({ | ||||
|         main, | ||||
|         child, | ||||
|     })); | ||||
|   } | ||||
|  | ||||
|   bool OnEvent(Event event) final { | ||||
|     if (event.is_mouse()) | ||||
|       return OnMouseEvent(std::move(event)); | ||||
|     return ComponentBase::OnEvent(std::move(event)); | ||||
|   } | ||||
|  | ||||
|   bool OnMouseEvent(Event event) { | ||||
|     if (captured_mouse_ && event.mouse().motion == Mouse::Released) { | ||||
|       captured_mouse_.reset(); | ||||
|       return true; | ||||
|     } | ||||
|  | ||||
|     if (event.mouse().button == Mouse::Left && | ||||
|         event.mouse().motion == Mouse::Pressed && | ||||
|         separator_box_.Contain(event.mouse().x, event.mouse().y) && | ||||
|         !captured_mouse_) { | ||||
|       captured_mouse_ = CaptureMouse(event); | ||||
|       return true; | ||||
|     } | ||||
|  | ||||
|     if (captured_mouse_) { | ||||
|       *main_size_ = event.mouse().x - global_box_.x_min; | ||||
|       return true; | ||||
|     } | ||||
|  | ||||
|     return ComponentBase::OnEvent(event); | ||||
|   } | ||||
|  | ||||
|   Element Render() final { | ||||
|     return hbox({ | ||||
|                main_->Render() | size(WIDTH, EQUAL, *main_size_), | ||||
|                separator() | reflect(separator_box_), | ||||
|                child_->Render() | xflex, | ||||
|            }) | | ||||
|            reflect(global_box_); | ||||
|   }; | ||||
|  | ||||
|  private: | ||||
|   Component main_; | ||||
|   Component child_; | ||||
|   int* const main_size_; | ||||
|   CapturedMouse captured_mouse_; | ||||
|   Box separator_box_; | ||||
|   Box global_box_; | ||||
| }; | ||||
|  | ||||
| class ResizableSplitRight: public ComponentBase { | ||||
|  public: | ||||
|   ResizableSplitRight(Component main, Component child, int* main_size) | ||||
|       : main_(main), child_(child), main_size_(main_size) { | ||||
|     Add(Container::Horizontal({ | ||||
|         child, | ||||
|         main, | ||||
|     })); | ||||
|   } | ||||
|  | ||||
|   bool OnEvent(Event event) final { | ||||
|     if (event.is_mouse()) | ||||
|       return OnMouseEvent(std::move(event)); | ||||
|     return ComponentBase::OnEvent(std::move(event)); | ||||
|   } | ||||
|  | ||||
|   bool OnMouseEvent(Event event) { | ||||
|     if (captured_mouse_ && event.mouse().motion == Mouse::Released) { | ||||
|       captured_mouse_.reset(); | ||||
|       return true; | ||||
|     } | ||||
|  | ||||
|     if (event.mouse().button == Mouse::Left && | ||||
|         event.mouse().motion == Mouse::Pressed && | ||||
|         separator_box_.Contain(event.mouse().x, event.mouse().y) && | ||||
|         !captured_mouse_) { | ||||
|       captured_mouse_ = CaptureMouse(event); | ||||
|       return true; | ||||
|     } | ||||
|  | ||||
|     if (captured_mouse_) { | ||||
|       *main_size_ = global_box_.x_max - event.mouse().x; | ||||
|       return true; | ||||
|     } | ||||
|  | ||||
|     return ComponentBase::OnEvent(event); | ||||
|   } | ||||
|  | ||||
|   Element Render() final { | ||||
|     return hbox({ | ||||
|                child_->Render() | xflex, | ||||
|                separator() | reflect(separator_box_), | ||||
|                main_->Render() | size(WIDTH, EQUAL, *main_size_), | ||||
|            }) | | ||||
|            reflect(global_box_); | ||||
|   }; | ||||
|  | ||||
|  private: | ||||
|   Component main_; | ||||
|   Component child_; | ||||
|   int* const main_size_; | ||||
|   CapturedMouse captured_mouse_; | ||||
|   Box separator_box_; | ||||
|   Box global_box_; | ||||
| }; | ||||
|  | ||||
| class ResizableSplitTop: public ComponentBase { | ||||
|  public: | ||||
|   ResizableSplitTop(Component main, Component child, int* main_size) | ||||
|       : main_(main), child_(child), main_size_(main_size) { | ||||
|     Add(Container::Vertical({ | ||||
|         main, | ||||
|         child, | ||||
|     })); | ||||
|   } | ||||
|  | ||||
|   bool OnEvent(Event event) final { | ||||
|     if (event.is_mouse()) | ||||
|       return OnMouseEvent(std::move(event)); | ||||
|     return ComponentBase::OnEvent(std::move(event)); | ||||
|   } | ||||
|  | ||||
|   bool OnMouseEvent(Event event) { | ||||
|     if (captured_mouse_ && event.mouse().motion == Mouse::Released) { | ||||
|       captured_mouse_.reset(); | ||||
|       return true; | ||||
|     } | ||||
|  | ||||
|     if (event.mouse().button == Mouse::Left && | ||||
|         event.mouse().motion == Mouse::Pressed && | ||||
|         separator_box_.Contain(event.mouse().x, event.mouse().y) && | ||||
|         !captured_mouse_) { | ||||
|       captured_mouse_ = CaptureMouse(event); | ||||
|       return true; | ||||
|     } | ||||
|  | ||||
|     if (captured_mouse_) { | ||||
|       *main_size_ = event.mouse().y - global_box_.y_min; | ||||
|       return true; | ||||
|     } | ||||
|  | ||||
|     return ComponentBase::OnEvent(event); | ||||
|   } | ||||
|  | ||||
|   Element Render() final { | ||||
|     return vbox({ | ||||
|                main_->Render() | size(HEIGHT, EQUAL, *main_size_), | ||||
|                separator() | reflect(separator_box_), | ||||
|                child_->Render() | yflex, | ||||
|            }) | | ||||
|            reflect(global_box_); | ||||
|   }; | ||||
|  | ||||
|  private: | ||||
|   Component main_; | ||||
|   Component child_; | ||||
|   int* const main_size_; | ||||
|   CapturedMouse captured_mouse_; | ||||
|   Box separator_box_; | ||||
|   Box global_box_; | ||||
| }; | ||||
|  | ||||
| class ResizableSplitBottom: public ComponentBase { | ||||
|  public: | ||||
|   ResizableSplitBottom(Component main, Component child, int* main_size) | ||||
|       : main_(main), child_(child), main_size_(main_size) { | ||||
|     Add(Container::Vertical({ | ||||
|         child, | ||||
|         main, | ||||
|     })); | ||||
|   } | ||||
|  | ||||
|   bool OnEvent(Event event) final { | ||||
|     if (event.is_mouse()) | ||||
|       return OnMouseEvent(std::move(event)); | ||||
|     return ComponentBase::OnEvent(std::move(event)); | ||||
|   } | ||||
|  | ||||
|   bool OnMouseEvent(Event event) { | ||||
|     if (captured_mouse_ && event.mouse().motion == Mouse::Released) { | ||||
|       captured_mouse_.reset(); | ||||
|       return true; | ||||
|     } | ||||
|  | ||||
|     if (event.mouse().button == Mouse::Left && | ||||
|         event.mouse().motion == Mouse::Pressed && | ||||
|         separator_box_.Contain(event.mouse().x, event.mouse().y) && | ||||
|         !captured_mouse_) { | ||||
|       captured_mouse_ = CaptureMouse(event); | ||||
|       return true; | ||||
|     } | ||||
|  | ||||
|     if (captured_mouse_) { | ||||
|       *main_size_ = global_box_.y_max - event.mouse().y; | ||||
|       return true; | ||||
|     } | ||||
|  | ||||
|     return ComponentBase::OnEvent(event); | ||||
|   } | ||||
|  | ||||
|   Element Render() final { | ||||
|     return vbox({ | ||||
|                child_->Render() | yflex, | ||||
|                separator() | reflect(separator_box_), | ||||
|                main_->Render() | size(HEIGHT, EQUAL, *main_size_), | ||||
|            }) | | ||||
|            reflect(global_box_); | ||||
|   }; | ||||
|  | ||||
|  private: | ||||
|   Component main_; | ||||
|   Component child_; | ||||
|   int* const main_size_; | ||||
|   CapturedMouse captured_mouse_; | ||||
|   Box separator_box_; | ||||
|   Box global_box_; | ||||
| }; | ||||
|  | ||||
| }  // namespace | ||||
|  | ||||
| namespace ResizableSplit { | ||||
| Component Left(Component main, Component back, int* main_size) { | ||||
|   return Make<ResizableSplitLeft>(std::move(main), std::move(back), main_size); | ||||
| } | ||||
| Component Right(Component main, Component back, int* main_size) { | ||||
|   return Make<ResizableSplitRight>(std::move(main), std::move(back), main_size); | ||||
| } | ||||
| Component Top(Component main, Component back, int* main_size) { | ||||
|   return Make<ResizableSplitTop>(std::move(main), std::move(back), main_size); | ||||
| } | ||||
| Component Bottom(Component main, Component back, int* main_size) { | ||||
|   return Make<ResizableSplitBottom>(std::move(main), std::move(back), main_size); | ||||
| } | ||||
| //Component Top(Component main, Component back, int main_size) { | ||||
|   //return Make<ResizableSplitTop>(std::move(main), std::move(back), main_size); | ||||
| //} | ||||
| //Component Bottom(Component main, Component back, int main_size) { | ||||
|   //return Make<ResizableSplitBottom>(std::move(main), std::move(back), | ||||
|                                     //main_size); | ||||
| //} | ||||
| }  // namespace ResizableSplit | ||||
| }  // namespace ftxui | ||||
		Reference in New Issue
	
	Block a user