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

View File

@ -26,31 +26,37 @@
//BUG: No audio in about when shown second time //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) //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: Weird LCR AFSK scrambling ?
//TODO: Use msgpack !
//TODO: Frequency manager //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: Morse coder
//TODO: Playdead amnesia and login
//TODO: Touch screen calibration //Multimon-style stuff:
//TODO: Check jammer bandwidths
//TODO: GSM channel detector
//TODO: AFSK receiver //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: 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: Bodet :)
//TODO: Whistler //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: Setup: Play dead by default ? Enable/disable ?
//TODO: Hide statusview when playing dead //TODO: Hide statusview when playing dead
//TODO: Persistent playdead ! //TODO: Persistent playdead !
//TODO: LCR full message former (see norm) //TODO: Show MD5 mismatches for modules not found, etc...
//TODO: AFSK NRZI //TODO: Module name/filename in modules.hpp to indicate requirement in case it's not found ui_loadmodule
//TODO: TX power setting
//TODO: Draw on touchscreen and transmit as spectrum paint
//TODO: Two players tic-tac-toe //TODO: Two players tic-tac-toe
#include "ch.h" #include "ch.h"

View File

@ -1,5 +1,6 @@
/* /*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc. * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
* *
* This file is part of PortaPack. * This file is part of PortaPack.
* *
@ -20,10 +21,11 @@
*/ */
#include "ui_menu.hpp" #include "ui_menu.hpp"
#include "time.hpp"
namespace ui { namespace ui {
/* MenuViewItem **********************************************************/ /* MenuItemView **********************************************************/
void MenuItemView::select() { void MenuItemView::select() {
if( item.on_select ) { if( item.on_select ) {
@ -72,27 +74,67 @@ void MenuItemView::paint(Painter& painter) {
/* MenuView **************************************************************/ /* 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() { MenuView::~MenuView() {
/* TODO: Double-check this */ /* TODO: Double-check this */
for(auto child : children_) { for (auto child : children_) {
delete child; 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) { void MenuView::add_item(const MenuItem item) {
add_child(new MenuItemView { item }); add_child(new MenuItemView { item });
} }
void MenuView::set_parent_rect(const Rect new_parent_rect) { void MenuView::set_parent_rect(const Rect new_parent_rect) {
View::set_parent_rect(new_parent_rect); View::set_parent_rect(new_parent_rect);
update_items();
}
void MenuView::update_items() {
constexpr size_t item_height = 24; constexpr size_t item_height = 24;
size_t i = 0; size_t i = 0;
for(auto child : children_) { Coord y_pos;
child->set_parent_rect({
{ 0, static_cast<ui::Coord>(i * item_height) }, if (MENU_MAX + offset_ < (children_.size() - 1))
{ size().w, item_height } 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++; 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 /* TODO: Terrible cast! Take it as a sign I must be doing something
* shamefully wrong here, right? * 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 { size_t MenuView::highlighted() const {
@ -109,10 +151,20 @@ size_t MenuView::highlighted() const {
} }
bool MenuView::set_highlighted(const size_t new_value) { 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; 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(); item_view(highlighted())->unhighlight();
highlighted_ = new_value; highlighted_ = new_value;
item_view(highlighted())->highlight(); item_view(highlighted())->highlight();

View File

@ -25,11 +25,15 @@
#include "ui.hpp" #include "ui.hpp"
#include "ui_widget.hpp" #include "ui_widget.hpp"
#include "ui_painter.hpp" #include "ui_painter.hpp"
#include "bitmap.hpp"
#include "signal.hpp"
#include <cstddef> #include <cstddef>
#include <string> #include <string>
#include <functional> #include <functional>
#define MENU_MAX 11
namespace ui { namespace ui {
struct MenuItem { struct MenuItem {
@ -64,17 +68,14 @@ class MenuView : public View {
public: public:
std::function<void(void)> on_left; std::function<void(void)> on_left;
MenuView() { MenuView();
set_focusable(true);
}
~MenuView(); ~MenuView();
void add_item(const MenuItem item); void add_item(const MenuItem item);
template<size_t N> template<size_t N>
void add_items(const std::array<MenuItem, N>& items) { void add_items(const std::array<MenuItem, N>& items) {
for(const auto& item : items) { for (const auto& item : items) {
add_item(item); add_item(item);
} }
} }
@ -93,7 +94,22 @@ public:
//bool on_touch(const TouchEvent event) override; //bool on_touch(const TouchEvent event) override;
private: 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 highlighted_ { 0 };
size_t offset_ { 0 };
}; };
} /* namespace ui */ } /* namespace ui */

View File

@ -1,5 +1,6 @@
/* /*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
* *
* This file is part of PortaPack. * This file is part of PortaPack.
* *
@ -33,7 +34,6 @@
#include "ui_setup.hpp" #include "ui_setup.hpp"
#include "ui_debug.hpp" #include "ui_debug.hpp"
#include "ui_handwrite.hpp" // DEBUG
#include "ui_soundboard.hpp" // DEBUG #include "ui_soundboard.hpp" // DEBUG
#include "ui_closecall.hpp" // DEBUG #include "ui_closecall.hpp" // DEBUG
#include "ui_freqman.hpp" // DEBUG #include "ui_freqman.hpp" // DEBUG
@ -238,36 +238,35 @@ ReceiverMenuView::ReceiverMenuView(NavigationView& nav) {
/* SystemMenuView ********************************************************/ /* SystemMenuView ********************************************************/
SystemMenuView::SystemMenuView(NavigationView& nav) { SystemMenuView::SystemMenuView(NavigationView& nav) {
add_items<11>({ { add_items<14>({ {
{ "Play dead", ui::Color::red(), [&nav](){ nav.push<PlayDeadView>(false); } }, { "Play dead", ui::Color::red(), [&nav](){ nav.push<PlayDeadView>(false); } },
{ "Receiver RX", ui::Color::cyan(), [&nav](){ nav.push<ReceiverMenuView>(); } }, { "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>(); } }, { "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); } }, //{ "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); } }, //{ "Audio TX", ui::Color::yellow(), [&nav](){ nav.push<LoadModuleView>(md5_baseband_tx, AudioTX); } },
//{ "Frequency manager", ui::Color::white(), [&nav](){ nav.push<FreqManView>(); } }, //{ "Frequency manager", ui::Color::white(), [&nav](){ nav.push<FreqManView>(); } },
//{ "EPAR TX", ui::Color::green(), [&nav](){ nav.push<LoadModuleView>(md5_baseband_tx, EPAR); } }, //{ "EPAR TX", ui::Color::green(), [&nav](){ nav.push<LoadModuleView>(md5_baseband_tx, EPAR); } },
{ "Xylos TX", ui::Color::green(), [&nav](){ nav.push<XylosView>(); } }, { "Xylos TX", ui::Color::green(), [&nav](){ nav.push<XylosView>(); } },
{ "TEDI/LCR TX", ui::Color::orange(), [&nav](){ nav.push<LCRView>(); } }, { "TEDI/LCR TX", ui::Color::yellow(), [&nav](){ nav.push<LCRView>(); } },
{ "RDS TX", ui::Color::yellow(), [&nav](){ nav.push<RDSView>(); } }, { "OOK encoder TX", ui::Color::orange(), [&nav](){ nav.push<NotImplementedView>(); } },
//{ "Capture", ui::Color::white(), [&nav](){ nav.push<NotImplementedView>(); } }, { "RDS TX", ui::Color::red(), [&nav](){ nav.push<RDSView>(); } },
//{ "Analyze", ui::Color::white(), [&nav](){ nav.push<NotImplementedView>(); } }, //{ "Analyze", ui::Color::white(), [&nav](){ nav.push<NotImplementedView>(); } },
{ "Setup", ui::Color::white(), [&nav](){ nav.push<SetupMenuView>(); } }, { "Setup", ui::Color::white(), [&nav](){ nav.push<SetupMenuView>(); } },
{ "Debug", ui::Color::white(), [&nav](){ nav.push<DebugMenuView>(); } }, { "Debug", ui::Color::white(), [&nav](){ nav.push<DebugMenuView>(); } },
{ "HackRF", ui::Color::white(), [&nav](){ nav.push<HackRFFirmwareView>(); } }, { "HackRF", ui::Color::white(), [&nav](){ nav.push<HackRFFirmwareView>(); } },
{ "About", ui::Color::white(), [&nav](){ nav.push<AboutView>(); } } { "About", ui::Color::white(), [&nav](){ nav.push<AboutView>(); } }
} }); } });
//{ "Nordic/BTLE RX", ui::Color::cyan(), [&nav](){ nav.push(new NotImplementedView { nav }); } }, //{ "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)); } }, //{ "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 }); } }, //{ "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 }}); } }, //{ "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 }}); } }, //{ "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 }}); } }, //{ "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 }}); } }, //{ "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.