mirror of
https://github.com/steredbits/pelagia.git
synced 2026-10-17 20:01:26 +02:00
155 lines
3.8 KiB
C++
155 lines
3.8 KiB
C++
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
// Copyright (C) 2026 steredbits and Pelagia contributors
|
|
#include "ui/focus.h"
|
|
|
|
namespace ui {
|
|
|
|
namespace {
|
|
|
|
int clamp(int v, int lo, int hi) { return v < lo ? lo : (v > hi ? hi : v); }
|
|
|
|
// Minimal scrolling: the window [top, top + visible) follows position.
|
|
int follow(int top, int position, int visible, int count) {
|
|
if (visible < 1) {
|
|
visible = 1;
|
|
}
|
|
if (position < top) {
|
|
top = position;
|
|
} else if (position >= top + visible) {
|
|
top = position - visible + 1;
|
|
}
|
|
return clamp(top, 0, count > visible ? count - visible : 0);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
void ListFocus::set_count(int count) {
|
|
count_ = count < 0 ? 0 : count;
|
|
index_ = clamp(index_, 0, count_ > 0 ? count_ - 1 : 0);
|
|
}
|
|
|
|
void ListFocus::set_index(int index) { index_ = clamp(index, 0, count_ > 0 ? count_ - 1 : 0); }
|
|
|
|
bool ListFocus::move(Dir dir) {
|
|
if (dir == Dir::Up && index_ > 0) {
|
|
--index_;
|
|
return true;
|
|
}
|
|
if (dir == Dir::Down && index_ + 1 < count_) {
|
|
++index_;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
int ListFocus::scroll_top(int visible) {
|
|
top_ = follow(top_, index_, visible, count_);
|
|
return top_;
|
|
}
|
|
|
|
void GridFocus::set_count(int count) {
|
|
count_ = count < 0 ? 0 : count;
|
|
index_ = clamp(index_, 0, count_ > 0 ? count_ - 1 : 0);
|
|
}
|
|
|
|
void GridFocus::set_index(int index) { index_ = clamp(index, 0, count_ > 0 ? count_ - 1 : 0); }
|
|
|
|
bool GridFocus::move(Dir dir) {
|
|
if (count_ == 0) {
|
|
return false;
|
|
}
|
|
switch (dir) {
|
|
case Dir::Left:
|
|
if (col() == 0) return false;
|
|
--index_;
|
|
return true;
|
|
case Dir::Right:
|
|
if (col() == columns_ - 1 || index_ + 1 >= count_) return false;
|
|
++index_;
|
|
return true;
|
|
case Dir::Up:
|
|
if (row() == 0) return false;
|
|
index_ -= columns_;
|
|
return true;
|
|
case Dir::Down:
|
|
if (row() + 1 >= rows()) return false;
|
|
index_ = index_ + columns_ < count_ ? index_ + columns_ : count_ - 1;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
int GridFocus::scroll_row(int visible_rows) {
|
|
top_row_ = follow(top_row_, row(), visible_rows, rows());
|
|
return top_row_;
|
|
}
|
|
|
|
void RowsFocus::set_rows(const std::vector<int>& counts) {
|
|
counts_ = counts;
|
|
indexes_.resize(counts.size(), 0);
|
|
scrolls_.resize(counts.size(), 0);
|
|
for (size_t r = 0; r < counts.size(); ++r) {
|
|
indexes_[r] = clamp(indexes_[r], 0, counts[r] > 0 ? counts[r] - 1 : 0);
|
|
}
|
|
row_ = clamp(row_, 0, counts.empty() ? 0 : static_cast<int>(counts.size()) - 1);
|
|
// Current row empty: first non-empty row.
|
|
if (!counts_.empty() && counts_[row_] == 0) {
|
|
for (size_t r = 0; r < counts_.size(); ++r) {
|
|
if (counts_[r] > 0) {
|
|
row_ = static_cast<int>(r);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int RowsFocus::index() const { return index_in(row_); }
|
|
|
|
int RowsFocus::index_in(int row) const {
|
|
return row >= 0 && row < row_count() ? indexes_[row] : 0;
|
|
}
|
|
|
|
void RowsFocus::set_position(int row, int index) {
|
|
if (row < 0 || row >= row_count()) {
|
|
return;
|
|
}
|
|
row_ = row;
|
|
indexes_[row] = clamp(index, 0, counts_[row] > 0 ? counts_[row] - 1 : 0);
|
|
}
|
|
|
|
bool RowsFocus::move(Dir dir) {
|
|
if (counts_.empty()) {
|
|
return false;
|
|
}
|
|
if (dir == Dir::Left || dir == Dir::Right) {
|
|
int& i = indexes_[row_];
|
|
if (dir == Dir::Left && i > 0) {
|
|
--i;
|
|
return true;
|
|
}
|
|
if (dir == Dir::Right && i + 1 < counts_[row_]) {
|
|
++i;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
const int step = dir == Dir::Up ? -1 : 1;
|
|
for (int r = row_ + step; r >= 0 && r < row_count(); r += step) {
|
|
if (counts_[r] > 0) {
|
|
row_ = r;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
int RowsFocus::scroll_in(int row, int visible) {
|
|
if (row < 0 || row >= row_count()) {
|
|
return 0;
|
|
}
|
|
scrolls_[row] = follow(scrolls_[row], indexes_[row], visible, counts_[row]);
|
|
return scrolls_[row];
|
|
}
|
|
|
|
} // namespace ui
|