mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2024-12-15 04:28:10 +00:00
8761b9d7e0
* Initial commit for keyboard emulation * Added on_keyboard to some widgets * TextEdit partly * Multi key send at once * Frequency control support * Fix encoder emulation * Add keyboard to geomap * More widgets
195 lines
5.8 KiB
C++
195 lines
5.8 KiB
C++
/*
|
|
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
|
* Copyright (C) 2023 gullradriel, Nilorea Studio Inc.
|
|
* Copyright (C) 2023 Kyle Reed
|
|
*
|
|
* This file is part of PortaPack.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "ui_freqlist.hpp"
|
|
|
|
#include "baseband_api.hpp"
|
|
#include "utility.hpp"
|
|
|
|
namespace ui {
|
|
|
|
FreqManUIList::FreqManUIList(Rect parent_rect)
|
|
: Widget{parent_rect},
|
|
visible_lines_{(unsigned)parent_rect.height() / char_height} {
|
|
this->set_focusable(true);
|
|
}
|
|
|
|
void FreqManUIList::paint(Painter& painter) {
|
|
auto rect = screen_rect();
|
|
|
|
if (!db_ || db_->empty()) {
|
|
auto line_position = rect.location() + Point{7 * 8, 6 * 16};
|
|
painter.fill_rectangle(rect, Color::black());
|
|
painter.draw_string(line_position, Styles::white, "Empty Category");
|
|
return;
|
|
}
|
|
|
|
// Indicate when a file is too large by drawing in yellow.
|
|
auto over_max = db_->entry_count() > freqman_default_max_entries;
|
|
auto base_style = over_max ? &Styles::yellow : &Styles::white;
|
|
|
|
// TODO: could minimize redraw/re-read if necessary
|
|
// with better change tracking.
|
|
for (auto offset = 0u; offset < visible_lines_; ++offset) {
|
|
// The whole frame needs to be cleared so every line 'slot'
|
|
// is redrawn even when `text` just left empty.
|
|
auto text = std::string{};
|
|
auto index = start_index_ + offset;
|
|
auto line_position = rect.location() + Point{4, 1 + (int)offset * char_height};
|
|
auto is_selected = offset == selected_index_;
|
|
auto style = base_style;
|
|
|
|
if (index < db_->entry_count()) {
|
|
auto entry = (*db_)[index];
|
|
// db_ is directly backed by a file, so invalid lines cannot be
|
|
// pre-filtered. Show an empty entry if 'Unknown'.
|
|
if (entry.type != freqman_type::Unknown)
|
|
text = pretty_string(entry, line_max_length);
|
|
|
|
// Otherwise, if 'Raw' indicate an invalid entry by color.
|
|
if (entry.type == freqman_type::Raw)
|
|
style = &Styles::light_grey;
|
|
}
|
|
|
|
// Pad right with ' ' so trailing chars are cleaned up.
|
|
// draw_glyph has less flicker than fill_rect when drawing.
|
|
if (text.length() < line_max_length)
|
|
text.resize(line_max_length, ' ');
|
|
|
|
painter.draw_string(
|
|
line_position, (is_selected ? style->invert() : *style), text);
|
|
}
|
|
|
|
// Draw a bounding rectangle when focused.
|
|
painter.draw_rectangle(rect, (has_focus() ? Color::white() : Color::black()));
|
|
}
|
|
|
|
void FreqManUIList::on_focus() {
|
|
set_dirty();
|
|
}
|
|
|
|
void FreqManUIList::on_blur() {
|
|
set_dirty();
|
|
}
|
|
|
|
bool FreqManUIList::on_keyboard(const KeyboardEvent key) {
|
|
if (!db_ || db_->empty())
|
|
return false;
|
|
|
|
auto delta = 0;
|
|
if (key == '-' && get_index() > 0) delta = -1;
|
|
if (key == '+' && get_index() < db_->entry_count() - 1) delta = 1;
|
|
if (delta != 0) {
|
|
adjust_selected_index(delta);
|
|
set_dirty();
|
|
return true;
|
|
}
|
|
if (key == 10) {
|
|
if (on_select) {
|
|
on_select(get_index());
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool FreqManUIList::on_key(const KeyEvent key) {
|
|
if (!db_ || db_->empty())
|
|
return false;
|
|
|
|
if (key == KeyEvent::Select && on_select) {
|
|
on_select(get_index());
|
|
return true;
|
|
} else if (key == KeyEvent::Right && on_leave) {
|
|
on_leave();
|
|
return true;
|
|
}
|
|
|
|
auto delta = 0;
|
|
if (key == KeyEvent::Up && get_index() > 0)
|
|
delta = -1;
|
|
else if (key == KeyEvent::Down && get_index() < db_->entry_count() - 1)
|
|
delta = 1;
|
|
else
|
|
return false;
|
|
|
|
adjust_selected_index(delta);
|
|
set_dirty();
|
|
return true;
|
|
}
|
|
|
|
bool FreqManUIList::on_encoder(EncoderEvent delta) {
|
|
if (!db_ || db_->empty())
|
|
return false;
|
|
|
|
adjust_selected_index(delta);
|
|
set_dirty();
|
|
return true;
|
|
}
|
|
|
|
void FreqManUIList::set_parent_rect(Rect new_parent_rect) {
|
|
visible_lines_ = new_parent_rect.height() / char_height;
|
|
Widget::set_parent_rect(new_parent_rect);
|
|
}
|
|
|
|
void FreqManUIList::set_index(size_t index) {
|
|
start_index_ = 0;
|
|
selected_index_ = 0;
|
|
adjust_selected_index(index);
|
|
}
|
|
|
|
size_t FreqManUIList::get_index() const {
|
|
return start_index_ + selected_index_;
|
|
}
|
|
|
|
void FreqManUIList::set_db(FreqmanDB& db) {
|
|
db_ = &db;
|
|
start_index_ = 0;
|
|
selected_index_ = 0;
|
|
set_dirty();
|
|
}
|
|
|
|
void FreqManUIList::adjust_selected_index(int delta) {
|
|
int32_t new_index = selected_index_ + delta;
|
|
|
|
// The selection went off the top of the screen, move up.
|
|
if (new_index < 0) {
|
|
start_index_ = std::max<int32_t>(start_index_ + new_index, 0);
|
|
selected_index_ = 0;
|
|
}
|
|
|
|
// Selection is off the bottom of the screen, move down.
|
|
else if (new_index >= (int32_t)visible_lines_) {
|
|
start_index_ = std::min<int32_t>(start_index_ + delta, db_->entry_count() - visible_lines_);
|
|
selected_index_ = visible_lines_ - 1;
|
|
}
|
|
|
|
// Otherwise, scroll within the screen, but not past the end.
|
|
else {
|
|
selected_index_ = std::min<int32_t>(new_index, db_->entry_count() - 1);
|
|
}
|
|
}
|
|
|
|
} /* namespace ui */
|