Scrollable menuview

This commit is contained in:
furrtek 2016-07-30 05:27:28 +02:00
parent b4afdad7e6
commit 94b27ec45c
6 changed files with 139 additions and 62 deletions

View File

@ -27,24 +27,28 @@
namespace ui {
/*
00000000 00000000 00000000
11110001 11100111 10111110
10001010 00001000 00001000
10001010 00001000 00001000
11110001 11000111 00001000
10010000 00100000 10001000
10001000 00100000 10001000
10001011 11001111 00111110
00000000 00000000 00000000
11111100 01111000 01111000
10000100 01001000 01001000
10000100 01001000 01001000
10000100 01001000 01001000
10000100 01001000 01001000
10000100 01001000 01001000
10000111 11001111 11001110
*/
static constexpr uint8_t bitmap_more_data[] = {
0x00, 0x00,
0xC0, 0x03,
0xC0, 0x03,
0xC0, 0x03,
0xC0, 0x03,
0xC0, 0x03,
0xC0, 0x03,
0xC0, 0x03,
0xC6, 0x63,
0xCF, 0xF3,
0xDE, 0x7B,
0xFC, 0x3F,
0xF8, 0x1F,
0xF0, 0x0F,
0xE0, 0x07,
0xC0, 0x03
};
static constexpr Bitmap bitmap_more {
{ 16, 16 }, bitmap_more_data
};
static constexpr uint8_t bitmap_rssipwm_data[] = {
0x00, 0x00, 0x00,

View File

@ -26,31 +26,37 @@
//BUG: No audio in about when shown second time
//BUG: Description doesn't show up first time going to system>module info (UI drawn on top)
//TODO: Check AFSK transmit end, skips last bits ?
//TODO: Weird LCR AFSK scrambling ?
//TODO: Use msgpack !
//TODO: Frequency manager
//TODO: SD card wiper
//TODO: Draw on touchscreen and transmit as spectrum paint
//TODO: Use progressbars
//TODO: LCR receiver
//TODO: Xylos receiver
//TODO: Morse coder
//TODO: Playdead amnesia and login
//TODO: Touch screen calibration
//TODO: Check jammer bandwidths
//TODO: GSM channel detector
//Multimon-style stuff:
//TODO: AFSK receiver
//TODO: Xylos receiver
//TODO: Check jammer bandwidths
//TODO: Closecall wide range fix
//TODO: SD card wiper
//TODO: Use progressbars
//TODO: GSM channel detector
//TODO: SIGFOX RX/TX
//TODO: Show MD5 mismatches for modules not found, etc...
//TODO: Module name/filename in modules.hpp to indicate requirement in case it's not found ui_loadmodule
//TODO: Check bw setting in LCR TX
//TODO: Bodet :)
//TODO: Whistler
//TODO: LCR full message former (see norm)
//TODO: AFSK NRZI, parity and format
//TODO: TX power setting
//TODO: Playdead amnesia and login
//TODO: Setup: Play dead by default ? Enable/disable ?
//TODO: Hide statusview when playing dead
//TODO: Persistent playdead !
//TODO: LCR full message former (see norm)
//TODO: AFSK NRZI
//TODO: TX power setting
//TODO: Show MD5 mismatches for modules not found, etc...
//TODO: Module name/filename in modules.hpp to indicate requirement in case it's not found ui_loadmodule
//TODO: Draw on touchscreen and transmit as spectrum paint
//TODO: Two players tic-tac-toe
#include "ch.h"

View File

@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
*
* This file is part of PortaPack.
*
@ -20,10 +21,11 @@
*/
#include "ui_menu.hpp"
#include "time.hpp"
namespace ui {
/* MenuViewItem **********************************************************/
/* MenuItemView **********************************************************/
void MenuItemView::select() {
if( item.on_select ) {
@ -72,27 +74,67 @@ void MenuItemView::paint(Painter& painter) {
/* MenuView **************************************************************/
MenuView::MenuView() {
set_focusable(true);
add_child(&arrow_more);
signal_token_tick_second = time::signal_tick_second += [this]() {
this->on_tick_second();
};
arrow_more.set_parent_rect( { 216, 320 - 16 - 24, 16, 16 } );
arrow_more.set_focusable(false);
}
MenuView::~MenuView() {
/* TODO: Double-check this */
for(auto child : children_) {
for (auto child : children_) {
delete child;
}
}
void MenuView::on_tick_second() {
if (more_ && blink_)
arrow_more.set_foreground(Color::white());
else
arrow_more.set_foreground(Color::black());
blink_ = !blink_;
arrow_more.set_dirty();
}
void MenuView::add_item(const MenuItem item) {
add_child(new MenuItemView { item });
}
void MenuView::set_parent_rect(const Rect new_parent_rect) {
View::set_parent_rect(new_parent_rect);
update_items();
}
void MenuView::update_items() {
constexpr size_t item_height = 24;
size_t i = 0;
for(auto child : children_) {
child->set_parent_rect({
{ 0, static_cast<ui::Coord>(i * item_height) },
{ size().w, item_height }
});
Coord y_pos;
if (MENU_MAX + offset_ < (children_.size() - 1))
more_ = true;
else
more_ = false;
for (auto child : children_) {
if (i) { // Skip arrow widget
y_pos = (i - 1 - offset_) * item_height;
child->set_parent_rect({
{ 0, y_pos },
{ size().w, item_height }
});
if ((y_pos < 0) || (y_pos >= (320 - 16 - 24 - 16)))
child->hidden(true);
else
child->hidden(false);
}
i++;
}
}
@ -101,7 +143,7 @@ MenuItemView* MenuView::item_view(size_t index) const {
/* TODO: Terrible cast! Take it as a sign I must be doing something
* shamefully wrong here, right?
*/
return static_cast<MenuItemView*>(children_[index]);
return static_cast<MenuItemView*>(children_[index + 1]); // Skip arrow widget
}
size_t MenuView::highlighted() const {
@ -109,9 +151,19 @@ size_t MenuView::highlighted() const {
}
bool MenuView::set_highlighted(const size_t new_value) {
if( new_value >= children_.size() ) {
if( new_value >= (children_.size() - 1) ) { // Skip arrow widget
return false;
}
if ((new_value - offset_ + 1) >= MENU_MAX) {
// Shift MenuView up
offset_ = new_value - MENU_MAX + 1;
update_items();
} else if (new_value < offset_) {
// Shift MenuView down
offset_ = new_value;
update_items();
}
item_view(highlighted())->unhighlight();
highlighted_ = new_value;

View File

@ -25,11 +25,15 @@
#include "ui.hpp"
#include "ui_widget.hpp"
#include "ui_painter.hpp"
#include "bitmap.hpp"
#include "signal.hpp"
#include <cstddef>
#include <string>
#include <functional>
#define MENU_MAX 11
namespace ui {
struct MenuItem {
@ -64,23 +68,20 @@ class MenuView : public View {
public:
std::function<void(void)> on_left;
MenuView() {
set_focusable(true);
}
MenuView();
~MenuView();
void add_item(const MenuItem item);
template<size_t N>
void add_items(const std::array<MenuItem, N>& items) {
for(const auto& item : items) {
for (const auto& item : items) {
add_item(item);
}
}
void set_parent_rect(const Rect new_parent_rect) override;
MenuItemView* item_view(size_t index) const;
size_t highlighted() const;
@ -93,7 +94,22 @@ public:
//bool on_touch(const TouchEvent event) override;
private:
void update_items();
void on_tick_second();
SignalToken signal_token_tick_second;
Image arrow_more {
{ 216, 320 - 16 - 24, 16, 16 },
&bitmap_more,
Color::white(),
Color::black()
};
bool blink_ = false;
bool more_ = false;
size_t highlighted_ { 0 };
size_t offset_ { 0 };
};
} /* namespace ui */

View File

@ -1,5 +1,6 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
*
* This file is part of PortaPack.
*
@ -33,7 +34,6 @@
#include "ui_setup.hpp"
#include "ui_debug.hpp"
#include "ui_handwrite.hpp" // DEBUG
#include "ui_soundboard.hpp" // DEBUG
#include "ui_closecall.hpp" // DEBUG
#include "ui_freqman.hpp" // DEBUG
@ -238,36 +238,35 @@ ReceiverMenuView::ReceiverMenuView(NavigationView& nav) {
/* SystemMenuView ********************************************************/
SystemMenuView::SystemMenuView(NavigationView& nav) {
add_items<11>({ {
{ "Play dead", ui::Color::red(), [&nav](){ nav.push<PlayDeadView>(false); } },
add_items<14>({ {
{ "Play dead", ui::Color::red(), [&nav](){ nav.push<PlayDeadView>(false); } },
{ "Receiver RX", ui::Color::cyan(), [&nav](){ nav.push<ReceiverMenuView>(); } },
{ "Capture RX", ui::Color::orange(), [&nav](){ nav.push<CaptureAppView>(); } },
{ "Capture RX", ui::Color::cyan(), [&nav](){ nav.push<CaptureAppView>(); } },
{ "Close Call RX", ui::Color::cyan(), [&nav](){ nav.push<CloseCallView>(); } },
//{ "Pokemon GO Away TX", ui::Color::blue(), [&nav](){ nav.push<JammerView>(); } },
{ "Numbers station TX", ui::Color::purple(), [&nav](){ nav.push<NotImplementedView>(); } }, //nav.push<NumbersStationView>();
{ "Pokemon GO Away TX", ui::Color::blue(), [&nav](){ nav.push<JammerView>(); } },
//{ "Soundboard TX", ui::Color::yellow(), [&nav](){ nav.push<LoadModuleView>(md5_baseband_tx, SoundBoard); } },
//{ "Audio TX", ui::Color::yellow(), [&nav](){ nav.push<LoadModuleView>(md5_baseband_tx, AudioTX); } },
//{ "Frequency manager", ui::Color::white(), [&nav](){ nav.push<FreqManView>(); } },
//{ "EPAR TX", ui::Color::green(), [&nav](){ nav.push<LoadModuleView>(md5_baseband_tx, EPAR); } },
{ "Xylos TX", ui::Color::green(), [&nav](){ nav.push<XylosView>(); } },
{ "TEDI/LCR TX", ui::Color::orange(), [&nav](){ nav.push<LCRView>(); } },
{ "RDS TX", ui::Color::yellow(), [&nav](){ nav.push<RDSView>(); } },
//{ "Capture", ui::Color::white(), [&nav](){ nav.push<NotImplementedView>(); } },
{ "TEDI/LCR TX", ui::Color::yellow(), [&nav](){ nav.push<LCRView>(); } },
{ "OOK encoder TX", ui::Color::orange(), [&nav](){ nav.push<NotImplementedView>(); } },
{ "RDS TX", ui::Color::red(), [&nav](){ nav.push<RDSView>(); } },
//{ "Analyze", ui::Color::white(), [&nav](){ nav.push<NotImplementedView>(); } },
{ "Setup", ui::Color::white(), [&nav](){ nav.push<SetupMenuView>(); } },
{ "Debug", ui::Color::white(), [&nav](){ nav.push<DebugMenuView>(); } },
{ "HackRF", ui::Color::white(), [&nav](){ nav.push<HackRFFirmwareView>(); } },
{ "About", ui::Color::white(), [&nav](){ nav.push<AboutView>(); } }
{ "Setup", ui::Color::white(), [&nav](){ nav.push<SetupMenuView>(); } },
{ "Debug", ui::Color::white(), [&nav](){ nav.push<DebugMenuView>(); } },
{ "HackRF", ui::Color::white(), [&nav](){ nav.push<HackRFFirmwareView>(); } },
{ "About", ui::Color::white(), [&nav](){ nav.push<AboutView>(); } }
} });
//{ "Nordic/BTLE RX", ui::Color::cyan(), [&nav](){ nav.push(new NotImplementedView { nav }); } },
//{ "Jammer", ui::Color::white(), [&nav](){ nav.push<LoadModuleView>(md5_baseband, new JammerView(nav)); } },
//{ "Audio file TX", ui::Color::white(), [&nav](){ nav.push(new NotImplementedView { nav }); } },
//{ "Encoder TX", ui::Color::green(), [&nav](){ nav.push(new NotImplementedView { nav }); } },
//{ "Whistle", ui::Color::purple(), [&nav](){ nav.push(new LoadModuleView { nav, md5_baseband, new WhistleView { nav, transmitter_model }}); } },
//{ "SIGFOX RX", ui::Color::orange(), [&nav](){ nav.push(new LoadModuleView { nav, md5_baseband, new SIGFRXView { nav, receiver_model }}); } },
//{ "Xylos RX", ui::Color::green(), [&nav](){ nav.push(new LoadModuleView { nav, md5_baseband_tx, new XylosRXView { nav, receiver_model }}); } },
//{ "AFSK RX", ui::Color::cyan(), [&nav](){ nav.push(new LoadModuleView { nav, md5_baseband, new AFSKRXView { nav, receiver_model }}); } },
//{ "Numbers station", ui::Color::purple(), [&nav](){ nav.push(new LoadModuleView { nav, md5_baseband_tx, new NumbersStationView { nav, transmitter_model }}); } },
}

Binary file not shown.