/* * Copyright (c) 2018-2021, Andreas Kling * Copyright (c) 2021-2023, Sam Atkins * Copyright (c) 2021, Mustafa Quraish * Copyright (c) 2022, the SerenityOS developers. * * SPDX-License-Identifier: BSD-2-Clause */ #include "PathBreadcrumbbar.h" #include #include #include #include #include #include #include #include REGISTER_WIDGET(GUI, PathBreadcrumbbar) namespace GUI { ErrorOr> PathBreadcrumbbar::try_create() { auto location_text_box = TRY(TextBox::try_create()); auto breadcrumbbar = TRY(Breadcrumbbar::try_create()); auto path_breadcrumbbar = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) PathBreadcrumbbar(*location_text_box, *breadcrumbbar))); (void)TRY(path_breadcrumbbar->try_set_layout()); TRY(path_breadcrumbbar->try_add_child(location_text_box)); TRY(path_breadcrumbbar->try_add_child(breadcrumbbar)); return path_breadcrumbbar; } PathBreadcrumbbar::PathBreadcrumbbar(NonnullRefPtr location_text_box, NonnullRefPtr breadcrumbbar) : Widget() , m_location_text_box(move(location_text_box)) , m_breadcrumbbar(move(breadcrumbbar)) { m_location_text_box->set_visible(false); m_location_text_box->on_escape_pressed = [&] { hide_location_text_box(); }; m_location_text_box->on_focusout = [&] { hide_location_text_box(); }; m_location_text_box->on_return_pressed = [&] { if (Core::DeprecatedFile::is_directory(m_location_text_box->text())) { set_current_path(m_location_text_box->text()); hide_location_text_box(); } }; m_breadcrumbbar->set_visible(true); m_breadcrumbbar->on_segment_change = [&](Optional segment_index) { if (!segment_index.has_value()) return; if (!on_path_change) return; auto segment_path = m_breadcrumbbar->segment_data(*segment_index); on_path_change(segment_path); }; m_breadcrumbbar->on_segment_drag_enter = [&](size_t, GUI::DragEvent& event) { if (event.mime_types().contains_slow("text/uri-list")) event.accept(); }; m_breadcrumbbar->on_segment_drop = [&](size_t segment_index, GUI::DropEvent const& event) { if (!event.mime_data().has_urls()) return; if (on_paths_drop) on_paths_drop(m_breadcrumbbar->segment_data(segment_index), event); }; m_breadcrumbbar->on_doubleclick = [&](auto) { show_location_text_box(); }; } PathBreadcrumbbar::~PathBreadcrumbbar() = default; void PathBreadcrumbbar::set_current_path(DeprecatedString const& new_path) { if (new_path == m_current_path) return; LexicalPath lexical_path(new_path); m_current_path = new_path; auto segment_index_of_new_path_in_breadcrumbbar = m_breadcrumbbar->find_segment_with_data(new_path); if (segment_index_of_new_path_in_breadcrumbbar.has_value()) { auto new_segment_index = segment_index_of_new_path_in_breadcrumbbar.value(); m_breadcrumbbar->set_selected_segment(new_segment_index); // If the path change was because the directory we were in was deleted, // remove the breadcrumbs for it. if ((new_segment_index + 1 < m_breadcrumbbar->segment_count()) && !Core::DeprecatedFile::is_directory(m_breadcrumbbar->segment_data(new_segment_index + 1))) { m_breadcrumbbar->remove_end_segments(new_segment_index + 1); } } else { m_breadcrumbbar->clear_segments(); m_breadcrumbbar->append_segment("/", GUI::FileIconProvider::icon_for_path("/").bitmap_for_size(16), "/", "/"); StringBuilder builder; for (auto& part : lexical_path.parts()) { // NOTE: We rebuild the path as we go, so we have something to pass to GUI::FileIconProvider. builder.append('/'); builder.append(part); m_breadcrumbbar->append_segment(part, GUI::FileIconProvider::icon_for_path(builder.string_view()).bitmap_for_size(16), builder.string_view(), builder.string_view()); } m_breadcrumbbar->set_selected_segment(m_breadcrumbbar->segment_count() - 1); } } bool PathBreadcrumbbar::has_parent_segment() const { return m_breadcrumbbar->has_parent_segment(); } bool PathBreadcrumbbar::has_child_segment() const { return m_breadcrumbbar->has_child_segment(); } void PathBreadcrumbbar::select_parent_segment() { if (!has_parent_segment()) return; m_breadcrumbbar->set_selected_segment(m_breadcrumbbar->selected_segment().value() - 1); } void PathBreadcrumbbar::select_child_segment() { if (!has_child_segment()) return; m_breadcrumbbar->set_selected_segment(m_breadcrumbbar->selected_segment().value() + 1); } void PathBreadcrumbbar::show_location_text_box() { if (m_location_text_box->is_visible()) return; m_location_text_box->set_visible(true); m_breadcrumbbar->set_visible(false); m_location_text_box->set_icon(GUI::FileIconProvider::icon_for_path(m_current_path).bitmap_for_size(16)); m_location_text_box->set_text(m_current_path); m_location_text_box->select_all(); m_location_text_box->set_focus(true); } void PathBreadcrumbbar::hide_location_text_box() { if (!m_location_text_box->is_visible()) return; m_location_text_box->set_visible(false); m_breadcrumbbar->set_visible(true); m_location_text_box->set_focus(false); if (on_hide_location_box) on_hide_location_box(); } }