mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 17:52:45 +00:00 
			
		
		
		
	LibGUI: Simplify submenu construction
The API for adding a submenu to a menu is now:
auto& submenu = menu.add_submenu("Name");
submenu.add_action(my_action);
			
			
This commit is contained in:
		
							parent
							
								
									13dcd9a037
								
							
						
					
					
						commit
						f0cde70c18
					
				
					 9 changed files with 57 additions and 65 deletions
				
			
		|  | @ -146,14 +146,6 @@ HexEditorWidget::HexEditorWidget() | |||
|         GUI::Application::the().quit(0); | ||||
|     })); | ||||
| 
 | ||||
|     auto bytes_per_row_menu = GUI::Menu::construct("Bytes Per Row"); | ||||
|     for (int i = 8; i <= 32; i += 8) { | ||||
|         bytes_per_row_menu->add_action(GUI::Action::create(String::number(i), [this, i](auto&) { | ||||
|             m_editor->set_bytes_per_row(i); | ||||
|             m_editor->update(); | ||||
|         })); | ||||
|     } | ||||
| 
 | ||||
|     m_goto_decimal_offset_action = GUI::Action::create("Go To Offset (Decimal)...", { Mod_Ctrl | Mod_Shift, Key_G }, Gfx::Bitmap::load_from_file("/res/icons/16x16/go-forward.png"), [this](const GUI::Action&) { | ||||
|         auto input_box = GUI::InputBox::construct("Enter Decimal offset:", "Go To", window()); | ||||
|         if (input_box->exec() == GUI::InputBox::ExecOK && !input_box->text_value().is_empty()) { | ||||
|  | @ -197,7 +189,13 @@ HexEditorWidget::HexEditorWidget() | |||
|     })); | ||||
| 
 | ||||
|     auto& view_menu = menubar->add_menu("View"); | ||||
|     view_menu.add_submenu(move(bytes_per_row_menu)); | ||||
|     auto& bytes_per_row_menu = view_menu.add_submenu("Bytes per row"); | ||||
|     for (int i = 8; i <= 32; i += 8) { | ||||
|         bytes_per_row_menu.add_action(GUI::Action::create(String::number(i), [this, i](auto&) { | ||||
|             m_editor->set_bytes_per_row(i); | ||||
|             m_editor->update(); | ||||
|         })); | ||||
|     } | ||||
| 
 | ||||
|     auto& help_menu = menubar->add_menu("Help"); | ||||
|     help_menu.add_action(GUI::Action::create("About", [&](auto&) { | ||||
|  |  | |||
|  | @ -283,16 +283,15 @@ void IRCAppWindow::setup_menus() | |||
|     channel_menu.add_action(*m_invite_user_action); | ||||
|     channel_menu.add_action(*m_banlist_action); | ||||
| 
 | ||||
|     RefPtr<GUI::Menu> channel_control_menu = GUI::Menu::construct("Control"); | ||||
|     channel_menu.add_submenu(*channel_control_menu); | ||||
|     channel_control_menu->add_action(*m_voice_user_action); | ||||
|     channel_control_menu->add_action(*m_devoice_user_action); | ||||
|     channel_control_menu->add_action(*m_hop_user_action); | ||||
|     channel_control_menu->add_action(*m_dehop_user_action); | ||||
|     channel_control_menu->add_action(*m_op_user_action); | ||||
|     channel_control_menu->add_action(*m_deop_user_action); | ||||
|     channel_control_menu->add_separator(); | ||||
|     channel_control_menu->add_action(*m_kick_user_action); | ||||
|     auto& channel_control_menu = channel_menu.add_submenu("Control"); | ||||
|     channel_control_menu.add_action(*m_voice_user_action); | ||||
|     channel_control_menu.add_action(*m_devoice_user_action); | ||||
|     channel_control_menu.add_action(*m_hop_user_action); | ||||
|     channel_control_menu.add_action(*m_dehop_user_action); | ||||
|     channel_control_menu.add_action(*m_op_user_action); | ||||
|     channel_control_menu.add_action(*m_deop_user_action); | ||||
|     channel_control_menu.add_separator(); | ||||
|     channel_control_menu.add_action(*m_kick_user_action); | ||||
| 
 | ||||
|     channel_menu.add_separator(); | ||||
|     channel_menu.add_action(*m_cycle_channel_action); | ||||
|  |  | |||
|  | @ -90,10 +90,9 @@ IRCWindow::IRCWindow(IRCClient& client, void* owner, Type type, const String& na | |||
|                 m_client.handle_whois_action(m_client.nick_without_prefix(nick.characters())); | ||||
|             })); | ||||
| 
 | ||||
|             RefPtr<GUI::Menu> m_context_control_menu = GUI::Menu::construct("Control"); | ||||
|             m_context_menu->add_submenu(*m_context_control_menu); | ||||
|             auto& context_control_menu = m_context_menu->add_submenu("Control"); | ||||
| 
 | ||||
|             m_context_control_menu->add_action(GUI::Action::create("Voice", [&](const GUI::Action&) { | ||||
|             context_control_menu.add_action(GUI::Action::create("Voice", [&](const GUI::Action&) { | ||||
|                 auto nick = channel().member_model()->nick_at(member_view.selection().first()); | ||||
|                 if (nick.is_empty()) | ||||
|                     return; | ||||
|  | @ -101,44 +100,44 @@ IRCWindow::IRCWindow(IRCClient& client, void* owner, Type type, const String& na | |||
|                 m_client.handle_voice_user_action(m_name.characters(), m_client.nick_without_prefix(nick.characters())); | ||||
|             })); | ||||
| 
 | ||||
|             m_context_control_menu->add_action(GUI::Action::create("DeVoice", [&](const GUI::Action&) { | ||||
|             context_control_menu.add_action(GUI::Action::create("DeVoice", [&](const GUI::Action&) { | ||||
|                 auto nick = channel().member_model()->nick_at(member_view.selection().first()); | ||||
|                 if (nick.is_empty()) | ||||
|                     return; | ||||
|                 m_client.handle_devoice_user_action(m_name.characters(), m_client.nick_without_prefix(nick.characters())); | ||||
|             })); | ||||
| 
 | ||||
|             m_context_control_menu->add_action(GUI::Action::create("Hop", [&](const GUI::Action&) { | ||||
|             context_control_menu.add_action(GUI::Action::create("Hop", [&](const GUI::Action&) { | ||||
|                 auto nick = channel().member_model()->nick_at(member_view.selection().first()); | ||||
|                 if (nick.is_empty()) | ||||
|                     return; | ||||
|                 m_client.handle_hop_user_action(m_name.characters(), m_client.nick_without_prefix(nick.characters())); | ||||
|             })); | ||||
| 
 | ||||
|             m_context_control_menu->add_action(GUI::Action::create("DeHop", [&](const GUI::Action&) { | ||||
|             context_control_menu.add_action(GUI::Action::create("DeHop", [&](const GUI::Action&) { | ||||
|                 auto nick = channel().member_model()->nick_at(member_view.selection().first()); | ||||
|                 if (nick.is_empty()) | ||||
|                     return; | ||||
|                 m_client.handle_dehop_user_action(m_name.characters(), m_client.nick_without_prefix(nick.characters())); | ||||
|             })); | ||||
| 
 | ||||
|             m_context_control_menu->add_action(GUI::Action::create("Op", [&](const GUI::Action&) { | ||||
|             context_control_menu.add_action(GUI::Action::create("Op", [&](const GUI::Action&) { | ||||
|                 auto nick = channel().member_model()->nick_at(member_view.selection().first()); | ||||
|                 if (nick.is_empty()) | ||||
|                     return; | ||||
|                 m_client.handle_op_user_action(m_name.characters(), m_client.nick_without_prefix(nick.characters())); | ||||
|             })); | ||||
| 
 | ||||
|             m_context_control_menu->add_action(GUI::Action::create("DeOp", [&](const GUI::Action&) { | ||||
|             context_control_menu.add_action(GUI::Action::create("DeOp", [&](const GUI::Action&) { | ||||
|                 auto nick = channel().member_model()->nick_at(member_view.selection().first()); | ||||
|                 if (nick.is_empty()) | ||||
|                     return; | ||||
|                 m_client.handle_deop_user_action(m_name.characters(), m_client.nick_without_prefix(nick.characters())); | ||||
|             })); | ||||
| 
 | ||||
|             m_context_control_menu->add_separator(); | ||||
|             context_control_menu.add_separator(); | ||||
| 
 | ||||
|             m_context_control_menu->add_action(GUI::Action::create("Kick", [&](const GUI::Action&) { | ||||
|             context_control_menu.add_action(GUI::Action::create("Kick", [&](const GUI::Action&) { | ||||
|                 auto nick = channel().member_model()->nick_at(member_view.selection().first()); | ||||
|                 if (nick.is_empty()) | ||||
|                     return; | ||||
|  | @ -149,38 +148,37 @@ IRCWindow::IRCWindow(IRCClient& client, void* owner, Type type, const String& na | |||
|                     m_client.handle_kick_user_action(m_name.characters(), m_client.nick_without_prefix(nick.characters()), input_box->text_value()); | ||||
|             })); | ||||
| 
 | ||||
|             RefPtr<GUI::Menu> m_context_ctcp_menu = GUI::Menu::construct("CTCP"); | ||||
|             m_context_menu->add_submenu(*m_context_ctcp_menu); | ||||
|             auto& context_ctcp_menu = m_context_menu->add_submenu("CTCP"); | ||||
| 
 | ||||
|             m_context_ctcp_menu->add_action(GUI::Action::create("User info", [&](const GUI::Action&) { | ||||
|             context_ctcp_menu.add_action(GUI::Action::create("User info", [&](const GUI::Action&) { | ||||
|                 auto nick = channel().member_model()->nick_at(member_view.selection().first()); | ||||
|                 if (nick.is_empty()) | ||||
|                     return; | ||||
|                 m_client.handle_ctcp_user_action(m_client.nick_without_prefix(nick.characters()), "USERINFO"); | ||||
|             })); | ||||
| 
 | ||||
|             m_context_ctcp_menu->add_action(GUI::Action::create("Finger", [&](const GUI::Action&) { | ||||
|             context_ctcp_menu.add_action(GUI::Action::create("Finger", [&](const GUI::Action&) { | ||||
|                 auto nick = channel().member_model()->nick_at(member_view.selection().first()); | ||||
|                 if (nick.is_empty()) | ||||
|                     return; | ||||
|                 m_client.handle_ctcp_user_action(m_client.nick_without_prefix(nick.characters()), "FINGER"); | ||||
|             })); | ||||
| 
 | ||||
|             m_context_ctcp_menu->add_action(GUI::Action::create("Time", [&](const GUI::Action&) { | ||||
|             context_ctcp_menu.add_action(GUI::Action::create("Time", [&](const GUI::Action&) { | ||||
|                 auto nick = channel().member_model()->nick_at(member_view.selection().first()); | ||||
|                 if (nick.is_empty()) | ||||
|                     return; | ||||
|                 m_client.handle_ctcp_user_action(m_client.nick_without_prefix(nick.characters()), "TIME"); | ||||
|             })); | ||||
| 
 | ||||
|             m_context_ctcp_menu->add_action(GUI::Action::create("Version", [&](const GUI::Action&) { | ||||
|             context_ctcp_menu.add_action(GUI::Action::create("Version", [&](const GUI::Action&) { | ||||
|                 auto nick = channel().member_model()->nick_at(member_view.selection().first()); | ||||
|                 if (nick.is_empty()) | ||||
|                     return; | ||||
|                 m_client.handle_ctcp_user_action(m_client.nick_without_prefix(nick.characters()), "VERSION"); | ||||
|             })); | ||||
| 
 | ||||
|             m_context_ctcp_menu->add_action(GUI::Action::create("Client info", [&](const GUI::Action&) { | ||||
|             context_ctcp_menu.add_action(GUI::Action::create("Client info", [&](const GUI::Action&) { | ||||
|                 auto nick = channel().member_model()->nick_at(member_view.selection().first()); | ||||
|                 if (nick.is_empty()) | ||||
|                     return; | ||||
|  |  | |||
|  | @ -137,9 +137,8 @@ NonnullRefPtr<GUI::Menu> build_system_menu() | |||
| 
 | ||||
|         if (g_app_category_menus.contains(category)) | ||||
|             continue; | ||||
|         auto category_menu = GUI::Menu::construct(category); | ||||
|         system_menu->add_submenu(category_menu); | ||||
|         g_app_category_menus.set(category, move(category_menu)); | ||||
|         auto& category_menu = system_menu->add_submenu(category); | ||||
|         g_app_category_menus.set(category, category_menu); | ||||
|     } | ||||
| 
 | ||||
|     // Then we create and insert all the app menu items into the right place.
 | ||||
|  | @ -171,9 +170,8 @@ NonnullRefPtr<GUI::Menu> build_system_menu() | |||
| 
 | ||||
|     g_themes_group.set_exclusive(true); | ||||
|     g_themes_group.set_unchecking_allowed(false); | ||||
|     g_themes_menu = GUI::Menu::construct("Themes"); | ||||
| 
 | ||||
|     system_menu->add_submenu(*g_themes_menu); | ||||
|     g_themes_menu = &system_menu->add_submenu("Themes"); | ||||
| 
 | ||||
|     { | ||||
|         Core::DirIterator dt("/res/themes", Core::DirIterator::SkipDots); | ||||
|  |  | |||
|  | @ -384,7 +384,19 @@ TextEditorWidget::TextEditorWidget() | |||
|     edit_menu.add_action(*m_replace_previous_action); | ||||
|     edit_menu.add_action(*m_replace_all_action); | ||||
| 
 | ||||
|     auto& font_menu = menubar->add_menu("Font"); | ||||
|     m_markdown_preview_action = GUI::Action::create_checkable( | ||||
|         "Markdown preview", [this](auto& action) { | ||||
|             set_markdown_preview_enabled(action.is_checked()); | ||||
|         }, | ||||
|         this); | ||||
| 
 | ||||
|     auto& view_menu = menubar->add_menu("View"); | ||||
|     view_menu.add_action(*m_line_wrapping_setting_action); | ||||
|     view_menu.add_separator(); | ||||
|     view_menu.add_action(*m_markdown_preview_action); | ||||
|     view_menu.add_separator(); | ||||
| 
 | ||||
|     auto& font_menu = view_menu.add_submenu("Font"); | ||||
|     GUI::FontDatabase::the().for_each_fixed_width_font([&](const StringView& font_name) { | ||||
|         font_menu.add_action(GUI::Action::create(font_name, [this](const GUI::Action& action) { | ||||
|             m_editor->set_font(GUI::FontDatabase::the().get_by_name(action.text())); | ||||
|  | @ -392,10 +404,9 @@ TextEditorWidget::TextEditorWidget() | |||
|         })); | ||||
|     }); | ||||
| 
 | ||||
|     syntax_actions = GUI::ActionGroup {}; | ||||
|     syntax_actions.set_exclusive(true); | ||||
| 
 | ||||
|     auto& syntax_menu = menubar->add_menu("Syntax"); | ||||
|     auto& syntax_menu = view_menu.add_submenu("Syntax"); | ||||
|     m_plain_text_highlight = GUI::Action::create_checkable("Plain text", [&](auto&) { | ||||
|         m_editor->set_syntax_highlighter(nullptr); | ||||
|         m_editor->update(); | ||||
|  | @ -418,20 +429,6 @@ TextEditorWidget::TextEditorWidget() | |||
|     syntax_actions.add_action(*m_js_highlight); | ||||
|     syntax_menu.add_action(*m_js_highlight); | ||||
| 
 | ||||
|     m_markdown_preview_action = GUI::Action::create_checkable( | ||||
|         "Markdown preview", [this](auto& action) { | ||||
|             set_markdown_preview_enabled(action.is_checked()); | ||||
|         }, | ||||
|         this); | ||||
| 
 | ||||
|     auto& view_menu = menubar->add_menu("View"); | ||||
|     view_menu.add_action(*m_line_wrapping_setting_action); | ||||
|     view_menu.add_separator(); | ||||
|     view_menu.add_action(*m_markdown_preview_action); | ||||
|     view_menu.add_separator(); | ||||
|     view_menu.add_submenu(move(font_menu)); | ||||
|     view_menu.add_submenu(move(syntax_menu)); | ||||
| 
 | ||||
|     auto& help_menu = menubar->add_menu("Help"); | ||||
|     help_menu.add_action(GUI::Action::create("About", [&](auto&) { | ||||
|         GUI::AboutDialog::show("Text Editor", Gfx::Bitmap::load_from_file("/res/icons/32x32/app-texteditor.png"), window()); | ||||
|  |  | |||
|  | @ -71,9 +71,11 @@ void Menu::add_action(NonnullRefPtr<Action> action) | |||
| #endif | ||||
| } | ||||
| 
 | ||||
| void Menu::add_submenu(NonnullRefPtr<Menu> submenu) | ||||
| Menu& Menu::add_submenu(const String& name) | ||||
| { | ||||
|     m_items.append(make<MenuItem>(m_menu_id, move(submenu))); | ||||
|     auto submenu = Menu::construct(name); | ||||
|     m_items.append(make<MenuItem>(m_menu_id, submenu)); | ||||
|     return submenu; | ||||
| } | ||||
| 
 | ||||
| void Menu::add_separator() | ||||
|  |  | |||
|  | @ -54,7 +54,7 @@ public: | |||
| 
 | ||||
|     void add_action(NonnullRefPtr<Action>); | ||||
|     void add_separator(); | ||||
|     void add_submenu(NonnullRefPtr<Menu>); | ||||
|     Menu& add_submenu(const String& name); | ||||
| 
 | ||||
|     void popup(const Gfx::Point& screen_position); | ||||
|     void dismiss(); | ||||
|  |  | |||
|  | @ -37,7 +37,7 @@ MenuItem::MenuItem(unsigned menu_id, Type type) | |||
| { | ||||
| } | ||||
| 
 | ||||
| MenuItem::MenuItem(unsigned menu_id, NonnullRefPtr<Action>&& action) | ||||
| MenuItem::MenuItem(unsigned menu_id, NonnullRefPtr<Action> action) | ||||
|     : m_type(Type::Action) | ||||
|     , m_menu_id(menu_id) | ||||
|     , m_action(move(action)) | ||||
|  | @ -49,7 +49,7 @@ MenuItem::MenuItem(unsigned menu_id, NonnullRefPtr<Action>&& action) | |||
|         m_checked = m_action->is_checked(); | ||||
| } | ||||
| 
 | ||||
| MenuItem::MenuItem(unsigned menu_id, NonnullRefPtr<Menu>&& submenu) | ||||
| MenuItem::MenuItem(unsigned menu_id, NonnullRefPtr<Menu> submenu) | ||||
|     : m_type(Type::Submenu) | ||||
|     , m_menu_id(menu_id) | ||||
|     , m_submenu(move(submenu)) | ||||
|  |  | |||
|  | @ -42,8 +42,8 @@ public: | |||
|     }; | ||||
| 
 | ||||
|     MenuItem(unsigned menu_id, Type); | ||||
|     MenuItem(unsigned menu_id, NonnullRefPtr<Action>&&); | ||||
|     MenuItem(unsigned menu_id, NonnullRefPtr<Menu>&&); | ||||
|     MenuItem(unsigned menu_id, NonnullRefPtr<Action>); | ||||
|     MenuItem(unsigned menu_id, NonnullRefPtr<Menu>); | ||||
|     ~MenuItem(); | ||||
| 
 | ||||
|     Type type() const { return m_type; } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling