Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
238 changes: 172 additions & 66 deletions src/panel/widgets/menu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
#include <glibmm/spawn.h>
#include <iostream>
#include <gtk4-layer-shell.h>
#include <gtk/gtk.h>

#include "menu.hpp"
#include "gtk-utils.hpp"
Expand All @@ -15,6 +14,134 @@

const std::string default_icon = "wayfire";

WfMenuLayout::WfMenuLayout(WayfireMenu *menu) : menu(menu)
{}

void WfMenuLayout::allocate_vfunc(const Gtk::Widget& widget, int width, int height, int baseline)
{
if (menu == nullptr)
{
return;
}

bool is_top = panel_position.value() == WF_WINDOW_POSITION_TOP;

Gtk::Widget::Measurements entry_measurements, logout_measurements, separator_measurements;
entry_measurements = menu->search_entry.measure(Gtk::Orientation::VERTICAL, width);
logout_measurements = menu->box_bottom.measure(Gtk::Orientation::VERTICAL, width);
separator_measurements = menu->separator.measure(Gtk::Orientation::VERTICAL, width);

int remaining_height = height -
(entry_measurements.sizes.minimum +
logout_measurements.sizes.minimum +
separator_measurements.sizes.natural);
if (remaining_height <= 0)
{
return;
}

search_alloc.set_x(0);
search_alloc.set_y(is_top ? 0 : height -
(logout_measurements.sizes.minimum + separator_measurements.sizes.natural +
entry_measurements.sizes.minimum));
search_alloc.set_height(entry_measurements.sizes.minimum);
search_alloc.set_width(width);
menu->search_entry.size_allocate(search_alloc, -1);

logout_alloc.set_x(0);
logout_alloc.set_y(height - logout_measurements.sizes.minimum);
logout_alloc.set_width(width);
logout_alloc.set_height(logout_measurements.sizes.minimum);
menu->box_bottom.size_allocate(logout_alloc, -1);

separator_alloc.set_x(0);
separator_alloc.set_y(height -
(logout_measurements.sizes.minimum + separator_measurements.sizes.natural));
separator_alloc.set_width(width);
separator_alloc.set_height(separator_measurements.sizes.natural);
menu->separator.size_allocate(separator_alloc, -1);

if (show_categories.value())
{
category_alloc.set_x(0);
category_alloc.set_y(is_top ? entry_measurements.sizes.minimum : 0);
category_alloc.set_width(category_width);
category_alloc.set_height(remaining_height);
menu->category_scrolled_window.size_allocate(category_alloc, -1);

flow_alloc.set_x(category_width);
flow_alloc.set_y(is_top ? entry_measurements.sizes.minimum : 0);
flow_alloc.set_width(width - category_width);
flow_alloc.set_height(remaining_height);
menu->app_scrolled_window.size_allocate(flow_alloc, -1);
} else
{
/* Even if we're not having it, allocate some space */
category_alloc.set_x(0);
category_alloc.set_y(is_top ? entry_measurements.sizes.minimum : 0);
category_alloc.set_width(width);
category_alloc.set_height(remaining_height);
menu->category_scrolled_window.size_allocate(category_alloc, -1);

flow_alloc.set_x(0);
flow_alloc.set_y(is_top ? entry_measurements.sizes.minimum : 0);
flow_alloc.set_width(width);
flow_alloc.set_height(remaining_height);
menu->app_scrolled_window.size_allocate(flow_alloc, -1);
}
}

void WfMenuLayout::measure_vfunc(const Gtk::Widget& widget, Gtk::Orientation orientation,
int for_size, int& minimum, int& natural, int& minimum_baseline,
int& natural_baseline) const
{
minimum_baseline = -1;
natural_baseline = -1;
// What is our preferred width?
if (orientation == Gtk::Orientation::HORIZONTAL)
{
if (limit_width > 0)
{
minimum = limit_width;
natural = limit_width;
return;
}

minimum = category_width + content_width;
natural = category_width + content_width;
} else
{
if (limit_height > 0)
{
minimum = limit_height;
natural = limit_height;
return;
}

Gtk::Widget::Measurements entry_measurements, logout_measurements, separator_measurements;
entry_measurements = menu->search_entry.measure(Gtk::Orientation::VERTICAL, for_size);
logout_measurements = menu->box_bottom.measure(Gtk::Orientation::VERTICAL, for_size);
separator_measurements = menu->separator.measure(Gtk::Orientation::VERTICAL, for_size);

minimum = separator_measurements.sizes.natural + entry_measurements.sizes.minimum +
logout_measurements.sizes.minimum + content_height;
natural = separator_measurements.sizes.natural + entry_measurements.sizes.minimum +
logout_measurements.sizes.minimum + content_height;
}
}

void WfMenuLayout::set_limit(int w, int h)
{
if ((w == limit_width) && (h == limit_height))
{
return;
}

limit_width = w;
limit_height = h;
menu->popover_layout_box.queue_resize();
}

WfMenuCategory::WfMenuCategory(std::string _name, std::string _icon_name) :
name(_name), icon_name(_icon_name)
{}
Expand Down Expand Up @@ -488,7 +615,6 @@ void WayfireMenu::on_search_changed()
/* Text has been unset, show categories again */
populate_menu_items(category);
category_scrolled_window.show();
app_scrolled_window.set_min_content_width(int(menu_min_content_width));
} else
{
/* User is filtering, hide categories, ignore chosen category */
Expand Down Expand Up @@ -576,35 +702,30 @@ void WayfireMenu::setup_popover_layout()
{
button->set_popup_child(popover_layout_box);

popover_layout_box.append(app_scrolled_window);
popover_layout_box.append(category_scrolled_window);
popover_layout_box.append(search_entry);
popover_layout_box.append(separator);
popover_layout_box.append(box_bottom);

flowbox.set_selection_mode(Gtk::SelectionMode::SINGLE);
flowbox.set_activate_on_single_click(true);
flowbox.set_valign(Gtk::Align::START);
flowbox.set_homogeneous(true);
flowbox.set_sort_func(sigc::mem_fun(*this, &WayfireMenu::on_sort));
flowbox.set_filter_func(sigc::mem_fun(*this, &WayfireMenu::on_filter));
flowbox.add_css_class("app-list");
flowbox.set_size_request(int(menu_min_content_width), int(menu_min_content_height));
flowbox.set_vexpand(true);
flowbox.set_hexpand(true);

flowbox_container.append(flowbox);

scroll_pair.append(category_scrolled_window);
scroll_pair.append(app_scrolled_window);
scroll_pair.set_homogeneous(false);
scroll_pair.set_vexpand(true);

app_scrolled_window.set_min_content_width(int(menu_min_content_width));
app_scrolled_window.set_min_content_height(int(menu_min_content_height));
app_scrolled_window.set_child(flowbox_container);
app_scrolled_window.add_css_class("app-list-scroll");
app_scrolled_window.set_policy(Gtk::PolicyType::NEVER, Gtk::PolicyType::AUTOMATIC);
app_scrolled_window.set_vexpand(true);

category_box.add_css_class("category-list");
category_box.set_orientation(Gtk::Orientation::VERTICAL);

category_scrolled_window.set_min_content_width(int(menu_min_category_width));
category_scrolled_window.set_min_content_height(int(menu_min_content_height));
category_scrolled_window.set_child(category_box);
category_scrolled_window.add_css_class("categtory-list-scroll");
category_scrolled_window.set_policy(Gtk::PolicyType::NEVER, Gtk::PolicyType::AUTOMATIC);
Expand Down Expand Up @@ -676,31 +797,19 @@ void WayfireMenu::setup_popover_layout()
}
}, false));
popover_layout_box.add_controller(typing_gesture);

layout = std::make_shared<WfMenuLayout>(this);
popover_layout_box.set_layout_manager(layout);
}

void WayfireMenu::update_popover_layout()
{
/* Layout was already initialized, make sure to remove widgets before
* adding them again */
auto children = popover_layout_box.get_children();
if (std::count(children.begin(), children.end(), &search_entry))
{
popover_layout_box.remove(search_entry);
}

if (std::count(children.begin(), children.end(), &scroll_pair))
{
popover_layout_box.remove(scroll_pair);
}

if (std::count(children.begin(), children.end(), &separator))
if (!menu_show_categories)
{
popover_layout_box.remove(separator);
}

if (std::count(children.begin(), children.end(), &box_bottom))
category_scrolled_window.hide();
} else
{
popover_layout_box.remove(box_bottom);
category_scrolled_window.show();
}

if (menu_list)
Expand All @@ -710,25 +819,6 @@ void WayfireMenu::update_popover_layout()
{
flowbox.set_max_children_per_line(-1);
}

if ((std::string)panel_position == WF_WINDOW_POSITION_TOP)
{
popover_layout_box.append(search_entry);
popover_layout_box.append(scroll_pair);
popover_layout_box.append(separator);
popover_layout_box.append(box_bottom);
} else
{
popover_layout_box.append(scroll_pair);
popover_layout_box.append(search_entry);
popover_layout_box.append(separator);
popover_layout_box.append(box_bottom);
}

if (!menu_show_categories)
{
category_scrolled_window.hide();
}
}

void WayfireLogoutUI::on_logout_click()
Expand Down Expand Up @@ -942,9 +1032,9 @@ void WayfireMenu::init(Gtk::Box *container)
flowbox.set_column_spacing(flowbox_spacing.value());
flowbox.set_column_spacing(flowbox_spacing.value());
});
menu_min_category_width.set_callback([=] () { update_category_width(); });
menu_min_content_height.set_callback([=] () { update_content_height(); });
menu_min_content_width.set_callback([=] () { update_content_width(); });
menu_min_category_width.set_callback([=] () { update_size(); });
menu_min_content_height.set_callback([=] () { update_size(); });
menu_min_content_width.set_callback([=] () { update_size(); });
panel_position.set_callback([=] () { update_popover_layout(); });
menu_show_categories.set_callback([=] () { update_popover_layout(); });
menu_list.set_callback([=] () { update_popover_layout(); });
Expand Down Expand Up @@ -1015,22 +1105,38 @@ void WayfireMenu::init(Gtk::Box *container)
box.show();
main_image.show();
button->show();
}

void WayfireMenu::update_category_width()
{
category_scrolled_window.set_min_content_width(int(menu_min_category_width));
signals.push_back(button->get_scroll().signal_map().connect([=] ()
{
update_size();
}));
}

void WayfireMenu::update_content_height()
void WayfireMenu::update_size()
{
category_scrolled_window.set_min_content_height(int(menu_min_content_height));
app_scrolled_window.set_min_content_height(int(menu_min_content_height));
}
int width = button->get_scroll().get_width();
int height = button->get_scroll().get_height();
if ((width <= 0) || (height <= 0))
{
/* Not yet allocated, do it next tick */
width = menu_min_content_width;
height = menu_min_content_height;
if (menu_show_categories.value())
{
width += menu_min_category_width;
}

void WayfireMenu::update_content_width()
{
app_scrolled_window.set_min_content_width(int(menu_min_content_width));
layout->set_limit(width, height);

Glib::signal_idle().connect_once([=] ()
{
update_size();
});
return;
}

/* We know the size of the outside of the scrollbox, use it */
layout->set_limit(width, height);
}

void WayfireMenu::toggle_menu()
Expand Down
39 changes: 31 additions & 8 deletions src/panel/widgets/menu.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,36 @@
#include <sigc++/connection.h>
#include <set>

#include "../widget.hpp"
#include "gtkmm/enums.h"
#include "gtkmm/orientable.h"
#include "widget.hpp"
#include "wf-popover.hpp"

class WayfireMenu;
using AppInfo = Glib::RefPtr<Gio::DesktopAppInfo>;

class WfMenuLayout : public Gtk::LayoutManager
{
protected:
Gtk::Allocation search_alloc, logout_alloc, category_alloc, flow_alloc, separator_alloc;

void allocate_vfunc(const Gtk::Widget& widget, int width, int height, int baseline) override;
void measure_vfunc(const Gtk::Widget& widget, Gtk::Orientation orientation, int for_size, int& minimum,
int& natural, int& minimum_baseline, int& natural_baseline) const override;
WayfireMenu *menu;
int limit_width = 0, limit_height = 0;

WfOption<bool> show_categories{"panel/menu_show_categories"};
WfOption<int> category_width{"panel/menu_min_category_width"};
WfOption<int> content_width{"panel/menu_min_content_width"};
WfOption<int> content_height{"panel/menu_min_content_height"};
WfOption<std::string> panel_position{"panel/position"};

public:
WfMenuLayout(WayfireMenu *menu);

void set_limit(int x, int y);
};


class WfMenuCategory
{
public:
Expand Down Expand Up @@ -122,9 +144,9 @@ class WayfireMenu : public WayfireWidget
{
WayfireOutput *output;

public:
Gtk::Box flowbox_container;
Gtk::Box box, box_bottom, scroll_pair;
Gtk::Box bottom_pad;
Gtk::Box box, box_bottom;
Gtk::Box popover_layout_box;
Gtk::Box category_box;
Gtk::Separator separator;
Expand All @@ -134,6 +156,9 @@ class WayfireMenu : public WayfireWidget
Gtk::Button logout_button;
Gtk::Image logout_image;
Gtk::ScrolledWindow app_scrolled_window, category_scrolled_window;

private:
std::shared_ptr<WfMenuLayout> layout;
std::unique_ptr<WayfireMenuWidget> button;
std::unique_ptr<WayfireLogoutUI> logout_ui;

Expand Down Expand Up @@ -180,9 +205,7 @@ class WayfireMenu : public WayfireWidget
WfOption<bool> menu_fullscreen{"panel/menu_fullscreen"};
void setup_popover_layout();
void update_popover_layout();
void update_category_width();
void update_content_height();
void update_content_width();
void update_size();
void create_logout_ui();
void on_logout_click();
void key_press_search();
Expand Down
Loading
Loading