commit 94a883640ac427d72fb2fcbef4db4cdf4d6ce6ac
parent 5fa10341abe96782477d69416815a6f0c0e976c5
Author: deurzen <max@deurzen.net>
Date: Sat, 4 Jun 2022 10:33:27 +0200
implements track-bound cycle and drag
Diffstat:
5 files changed, 269 insertions(+), 15 deletions(-)
diff --git a/include/kranewl/cycle.hh b/include/kranewl/cycle.hh
@@ -62,6 +62,131 @@ public:
Index next_index(Direction) const;
Index next_index_from(Index, Direction) const;
+ template<typename UnaryPredicate>
+ std::optional<Index>
+ next_index_with_condition(
+ Direction direction,
+ UnaryPredicate predicate
+ ) const
+ {
+ if (m_index >= m_elements.size())
+ return std::nullopt;
+
+ switch (direction) {
+ case Direction::Forward:
+ {
+ auto after_it = m_index != last_index()
+ ? std::find_if(
+ m_elements.begin() + m_index + 1,
+ m_elements.end(),
+ predicate
+ )
+ : m_elements.end();
+
+ if (after_it != m_elements.end())
+ return std::distance(m_elements.begin(), after_it);
+
+ auto before_it = std::find_if(
+ m_elements.begin(),
+ m_elements.begin() + m_index,
+ predicate
+ );
+
+ if (before_it != m_elements.begin() + m_index)
+ return std::distance(m_elements.begin(), before_it);
+
+ break;
+ }
+ case Direction::Backward:
+ {
+ auto after_it = m_index != 0
+ ? std::find_if(
+ m_elements.rbegin() + (m_elements.size() - m_index - 1) + 1,
+ m_elements.rend(),
+ predicate
+ )
+ : m_elements.rend();
+
+ if (after_it != m_elements.rend())
+ return std::distance(after_it, m_elements.rend()) - 1;
+
+ auto before_it = std::find_if(
+ m_elements.rbegin(),
+ m_elements.rbegin() + (m_elements.size() - m_index - 1),
+ predicate
+ );
+
+ if (before_it != m_elements.rbegin() + (m_elements.size() - m_index - 1))
+ return std::distance(before_it, m_elements.rend()) - 1;
+
+ break;
+ }
+ }
+
+ return std::nullopt;
+ }
+
+ template<typename UnaryPredicate>
+ std::optional<Index>
+ next_index_with_condition_from(
+ Index index,
+ Direction direction,
+ UnaryPredicate predicate
+ ) const
+ {
+ if (index >= m_elements.size())
+ return std::nullopt;
+
+ switch (direction) {
+ case Direction::Forward:
+ {
+ auto after_it = std::find_if(
+ m_elements.begin() + index,
+ m_elements.end(),
+ predicate
+ );
+
+ if (after_it != m_elements.end())
+ return std::distance(m_elements.begin(), after_it);
+
+ auto before_it = std::find_if(
+ m_elements.begin(),
+ m_elements.begin() + index,
+ predicate
+ );
+
+ if (before_it != m_elements.begin() + index)
+ return std::distance(m_elements.begin(), before_it);
+
+ break;
+ }
+ case Direction::Backward:
+ {
+ auto after_it = std::find_if(
+ m_elements.rbegin() + (m_elements.size() - index - 1),
+ m_elements.rend(),
+ predicate
+ );
+
+ if (after_it != m_elements.rend())
+ return std::distance(m_elements.rbegin(), after_it);
+
+ auto before_it = std::find_if(
+ m_elements.rbegin(),
+ m_elements.rbegin() + (m_elements.size() - index - 1),
+ predicate
+ );
+
+ if (before_it != m_elements.rbegin() + (m_elements.size() - index - 1))
+ return std::distance(m_elements.rbegin(), before_it);
+
+ break;
+ }
+ }
+
+ return std::nullopt;
+ }
+
std::optional<Index> index_of_element(const T) const;
std::optional<T> next_element(Direction) const;
@@ -72,7 +197,8 @@ public:
std::optional<T> element_at_back(T) const;
template<typename UnaryPredicate>
- std::optional<T> first_element_with_condition(UnaryPredicate predicate)
+ std::optional<T>
+ first_element_with_condition(UnaryPredicate predicate)
{
auto it = std::find_if(
m_elements.begin(),
@@ -83,7 +209,7 @@ public:
if (it != m_elements.end())
return *it;
- return {};
+ return std::nullopt;
}
void activate_first();
@@ -92,7 +218,8 @@ public:
void activate_element(T);
template<typename UnaryPredicate>
- void activate_for_condition(UnaryPredicate predicate)
+ void
+ activate_for_condition(UnaryPredicate predicate)
{
auto it = std::find_if(
m_elements.begin(),
@@ -110,7 +237,8 @@ public:
bool remove_element(T);
template<typename UnaryPredicate>
- bool remove_for_condition(UnaryPredicate predicate)
+ bool
+ remove_for_condition(UnaryPredicate predicate)
{
auto it = std::find_if(
m_elements.begin(),
@@ -136,6 +264,75 @@ public:
std::optional<T> cycle_active(Direction);
std::optional<T> drag_active(Direction);
+ template<typename UnaryPredicate>
+ std::optional<T>
+ cycle_active_with_condition(
+ Direction direction,
+ UnaryPredicate predicate,
+ bool wraps
+ )
+ {
+ std::optional<Index> index
+ = next_index_with_condition(direction, predicate);
+
+ if (!index)
+ return std::nullopt;
+
+ switch (direction) {
+ case Direction::Forward:
+ {
+ if (!wraps && *index <= active_index())
+ return std::nullopt;
+ break;
+ }
+ case Direction::Backward:
+ {
+ if (!wraps && *index >= last_index())
+ return std::nullopt;
+ break;
+ }
+ }
+
+ push_active_to_stack();
+ m_index = *index;
+ return active_element();
+ }
+
+ template<typename UnaryPredicate>
+ std::optional<T>
+ drag_active_with_condition(
+ Direction direction,
+ UnaryPredicate predicate,
+ bool wraps
+ )
+ {
+ std::optional<Index> index
+ = next_index_with_condition(direction, predicate);
+
+ if (!index)
+ return std::nullopt;
+
+ switch (direction) {
+ case Direction::Forward:
+ {
+ if (!wraps && *index <= active_index())
+ return std::nullopt;
+ break;
+ }
+ case Direction::Backward:
+ {
+ if (!wraps && *index >= last_index())
+ return std::nullopt;
+ break;
+ }
+ }
+
+ if (m_index != *index && m_index < m_elements.size() && *index < m_elements.size())
+ std::iter_swap(m_elements.begin() + m_index, m_elements.begin() + *index);
+
+ return cycle_active_with_condition(direction, predicate, wraps);
+ }
+
void insert_at_front(T);
void insert_at_back(T);
void insert_before_index(Index, T);
@@ -184,12 +381,14 @@ public:
return m_elements.cend();
}
- T operator[](std::size_t index)
+ T
+ operator[](std::size_t index)
{
return m_elements[index];
}
- const T operator[](std::size_t index) const
+ const T
+ operator[](std::size_t index) const
{
return m_elements[index];
}
diff --git a/include/kranewl/input/key-bindings.hh b/include/kranewl/input/key-bindings.hh
@@ -218,13 +218,13 @@ static const KeyBindings key_bindings = {
},
{ { XKB_KEY_j, MODKEY },
{
- .action = CALL(cycle_focus(Direction::Forward)),
+ .action = CALL(cycle_track(Direction::Forward)),
.repeatable = true
}
},
{ { XKB_KEY_k, MODKEY },
{
- .action = CALL(cycle_focus(Direction::Backward)),
+ .action = CALL(cycle_track(Direction::Backward)),
.repeatable = true
}
},
diff --git a/include/kranewl/model.hh b/include/kranewl/model.hh
@@ -101,7 +101,9 @@ public:
void abort_cursor_interactive();
void cycle_focus(Direction);
+ void cycle_track(Direction);
void drag_focus(Direction);
+ void drag_track(Direction);
void sync_focus();
void relayer_views(Workspace_ptr);
@@ -236,7 +238,7 @@ private:
View_ptr mp_focus;
View_ptr mp_jumped_from;
- SceneLayer m_track;
+ SceneLayer m_current_track;
std::vector<std::tuple<SearchSelector_ptr, Rules>> m_default_rules;
diff --git a/include/kranewl/workspace.hh b/include/kranewl/workspace.hh
@@ -120,6 +120,29 @@ public:
void cycle(Direction);
void drag(Direction);
+
+ template<typename UnaryPredicate>
+ void
+ cycle_with_condition(
+ Direction direction,
+ UnaryPredicate predicate
+ )
+ {
+ m_views.cycle_active_with_condition(direction, predicate, layout_wraps());
+ mp_active = m_views.active_element().value_or(nullptr);
+ }
+
+ template<typename UnaryPredicate>
+ void
+ drag_with_condition(
+ Direction direction,
+ UnaryPredicate predicate
+ )
+ {
+ m_views.drag_active_with_condition(direction, predicate, layout_wraps());
+ mp_active = m_views.active_element().value_or(nullptr);
+ }
+
void reverse();
void rotate(Direction);
void shuffle_main(Direction);
diff --git a/src/kranewl/model.cc b/src/kranewl/model.cc
@@ -56,7 +56,7 @@ Model::Model(Config const& config)
m_sticky_views{},
mp_focus(nullptr),
mp_jumped_from(nullptr),
- m_track(SceneLayer::SCENE_LAYER_TILE),
+ m_current_track(SceneLayer::SCENE_LAYER_TILE),
m_key_bindings(Bindings::key_bindings),
m_cursor_bindings(Bindings::cursor_bindings)
{
@@ -310,7 +310,7 @@ Model::focus_view(View_ptr view)
view->set_urgent(false);
mp_focus = view;
- m_track = view->scene_layer();
+ m_current_track = view->scene_layer();
if (mp_workspace->layout_is_persistent() || mp_workspace->layout_is_single())
apply_layout(mp_workspace);
@@ -558,7 +558,7 @@ Model::relayer_views(Workspace_ptr workspace)
if (mp_focus) {
mp_focus->raise();
- m_track = mp_focus->scene_layer();
+ m_current_track = mp_focus->scene_layer();
}
}
@@ -587,6 +587,17 @@ Model::cycle_focus(Direction direction)
}
void
+Model::cycle_track(Direction direction)
+{
+ TRACE();
+
+ mp_workspace->cycle_with_condition(direction, [this](View_ptr view) {
+ return belongs_to_track(view);
+ });
+ sync_focus();
+}
+
+void
Model::drag_focus(Direction direction)
{
TRACE();
@@ -596,7 +607,21 @@ Model::drag_focus(Direction direction)
mp_workspace->drag(direction);
sync_focus();
+ apply_layout(mp_workspace);
+}
+
+void
+Model::drag_track(Direction direction)
+{
+ TRACE();
+
+ if (mp_workspace->size() <= 1)
+ return;
+ mp_workspace->drag_with_condition(direction, [this](View_ptr view) {
+ return belongs_to_track(view);
+ });
+ sync_focus();
apply_layout(mp_workspace);
}
@@ -610,7 +635,6 @@ Model::reverse_views()
mp_workspace->reverse();
sync_focus();
-
apply_layout(mp_workspace);
}
@@ -1366,6 +1390,9 @@ Model::set_floating_view(Toggle toggle, View_ptr view)
}
apply_layout(view->mp_workspace);
+
+ if (view == mp_focus)
+ m_current_track = view->scene_layer();
}
void
@@ -1424,6 +1451,9 @@ Model::set_fullscreen_view(Toggle toggle, View_ptr view)
Workspace_ptr workspace = view->mp_workspace;
apply_layout(workspace);
+
+ if (view == mp_focus)
+ m_current_track = view->scene_layer();
}
void
@@ -2074,7 +2104,7 @@ Model::initialize_view(View_ptr view, Workspace_ptr workspace)
set_fullscreen_view(*rules.do_fullscreen ? Toggle::On : Toggle::Off, view);
if (view == mp_focus)
- m_track = view->scene_layer();
+ m_current_track = view->scene_layer();
}
XDGView_ptr
@@ -2232,7 +2262,7 @@ Model::is_free(View_ptr view) const
bool
Model::belongs_to_track(View_ptr view) const
{
- return m_track == view->scene_layer();
+ return m_current_track == view->scene_layer();
}
void