| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589 |
- #include <stdio.h>
- extern "C" {
- #include "main.h"
- #include "cmsis_os.h"
- #include "u8g2_support.h"
- #include "u8g2/u8g2.h"
- }
- #include "ui.h"
- #include "events.h"
- // function draw basic layout -- single bmp
- void draw_bitmap(const char* bitmap, u8g2_t* u8g2, ScreenArea area) {
- if(bitmap == NULL) {
- printf("[basic layout] no content\n");
- u8g2_SetFont(u8g2, u8g2_font_6x10_mf);
- u8g2_SetDrawColor(u8g2, 1);
- u8g2_SetFontMode(u8g2, 1);
- u8g2_DrawStr(u8g2, 2, 12, "no content");
- } else {
- u8g2_SetDrawColor(u8g2, 1);
- u8g2_DrawXBM(u8g2, 0, 0, area.x + area.width, area.y + area.height, (unsigned char*)bitmap);
- }
- }
- void draw_text(const char* text, u8g2_t* u8g2, ScreenArea area) {
- // TODO proper cleanup statusbar
- u8g2_SetDrawColor(u8g2, 0);
- u8g2_DrawBox(u8g2, 0, 0, area.x + area.width, area.y + area.height);
- Block text_block = Block {
- width: area.width,
- height: area.height,
- margin_left: 0,
- margin_top: 0,
- padding_left: 3,
- padding_top: 7,
- background: 0,
- color: 1,
- font: (uint8_t*)u8g2_font_6x10_mf,
- };
- draw_block(u8g2, text, text_block, area.x, area.y);
- }
- // draw layout and switch between ui item by button and timer
- void LayoutComponent::handle(Event* event, Store* store, u8g2_t* u8g2, ScreenArea area) {
- switch(event->type) {
- // get button event
- case EventTypeButton:
- if(event->value.button.state) {
- for(size_t i = 0; i < this->actions_size; i++) {
- FlipperComponent* next = NULL;
- switch(this->actions[i].action) {
- case LayoutActionUp:
- if(event->value.button.id == ButtonsUp) {
- next = this->actions[i].item;
- }
- break;
- case LayoutActionDown:
- if(event->value.button.id == ButtonsDown) {
- next = this->actions[i].item;
- }
- break;
- case LayoutActionLeft:
- if(event->value.button.id == ButtonsLeft) {
- next = this->actions[i].item;
- }
- break;
- case LayoutActionRight:
- if(event->value.button.id == ButtonsRight) {
- next = this->actions[i].item;
- }
- break;
- case LayoutActionOk:
- if(event->value.button.id == ButtonsOk) {
- next = this->actions[i].item;
- }
- break;
- case LayoutActionBack:
- if(event->value.button.id == ButtonsBack) {
- next = this->actions[i].item;
- }
- break;
- // stub action
- case LayoutActionUsbDisconnect:
- if(event->value.button.id == ButtonsLeft) {
- next = this->actions[i].item;
- }
- break;
- case LayoutActionUsbConnect:
- if(event->value.button.id == ButtonsRight) {
- next = this->actions[i].item;
- }
- break;
- default: break;
- }
- if(next) {
- printf("[layout view] go to next item\n");
- Event send_event;
- send_event.type = EventTypeUiNext;
- next->handle(
- &send_event,
- store,
- u8g2,
- area
- );
- }
- }
- }
- break;
- case EventTypeUsb: {
- printf("get usb event\n");
-
- FlipperComponent* next = NULL;
- if(event->value.usb == UsbEventConnect) {
- for(size_t i = 0; i < this->actions_size; i++) {
- if(this->actions[i].action == LayoutActionUsbConnect) {
- next = this->actions[i].item;
- }
- }
- }
- if(event->value.usb == UsbEventDisconnect) {
- for(size_t i = 0; i < this->actions_size; i++) {
- if(this->actions[i].action == LayoutActionUsbDisconnect) {
- next = this->actions[i].item;
- }
- }
- }
- if(next) {
- printf("[layout view] go to next item\n");
- Event send_event;
- send_event.type = EventTypeUiNext;
- next->handle(
- &send_event,
- store,
- u8g2,
- area
- );
- }
- } break;
- // start component from prev
- case EventTypeUiNext:
- printf("[layout view] start component %lX\n", (uint32_t)this);
- if(this->timeout > 0) {
- // TODO start timer
- }
- // set current item to self
- store->current_component = this;
- this->wait_time = 0;
- // render layout
- this->dirty = true;
- break;
- case EventTypeTick:
- this->wait_time += event->value.tick_delta;
- if(this->wait_time > this->timeout) {
- for(size_t i = 0; i < this->actions_size; i++) {
- if(this->actions[i].action == LayoutActionTimeout ||
- this->actions[i].action == LayoutActionEndOfCycle
- ) {
- if(this->actions[i].item != NULL) {
- printf("[layout view] go to next item\n");
- Event send_event;
- send_event.type = EventTypeUiNext;
- this->actions[i].item->handle(
- &send_event,
- store,
- u8g2,
- area
- );
- return;
- }
- }
- }
- }
- if(this->dirty) {
- this->draw_fn(this->data, u8g2, area);
- store->dirty_screen = true;
- this->dirty = false;
- }
- break;
- default: break;
- }
- }
- void BlinkerComponent::handle(Event* event, Store* store, u8g2_t* u8g2, ScreenArea area) {
- switch(event->type) {
- // get button event
- case EventTypeButton:
- if(event->value.button.state && event->value.button.id == ButtonsBack) {
- if(this->prev && this->prev != this) {
- printf("[blinker view] go back\n");
- Event send_event;
- send_event.type = EventTypeUiNext;
- this->prev->handle(
- &send_event,
- store,
- u8g2,
- area
- );
- this->prev = NULL;
- store->led = ColorBlack;
- this->wait_time = 0;
- this->is_on = true;
- this->active = false;
- } else {
- printf("[blinker view] no back/loop\n");
- }
- }
- if(event->value.button.state && event->value.button.id != ButtonsBack) {
- this->active = false;
- }
- if(!event->value.button.state && event->value.button.id != ButtonsBack) {
- this->active = true;
- }
- break;
- // start component from prev
- case EventTypeUiNext:
- printf("[blinker view] start component %lX\n", (uint32_t)this);
- if(this->prev == NULL) {
- this->prev = store->current_component;
- }
- // set current item to self
- store->current_component = this;
- this->dirty = true;
- this->wait_time = 0;
- this->is_on = true;
- this->active = false;
- break;
- case EventTypeTick:
- if(this->active) {
- this->wait_time += event->value.tick_delta;
- if(this->is_on) {
- if(this->wait_time > this->config.on_time) {
- this->wait_time = 0;
- this->is_on = false;
- }
- } else {
- if(this->wait_time > this->config.off_time) {
- this->wait_time = 0;
- this->is_on = true;
- }
- }
- store->led = this->is_on ? this->config.on_color : this->config.off_color;
- } else {
- store->led = ColorBlack;
- this->wait_time = 0;
- this->is_on = true;
- }
- if(this->dirty) {
- this->draw_fn(this->data, u8g2, area);
- store->dirty_screen = true;
- this->dirty = false;
- }
- break;
- default: break;
- }
- }
- void BlinkerComponentOnBtn::handle(Event* event, Store* store, u8g2_t* u8g2, ScreenArea area) {
- switch(event->type) {
- // get button event
- case EventTypeButton:
- if(event->value.button.state && event->value.button.id == ButtonsBack) {
- if(this->prev && this->prev != this) {
- printf("[blinker view] go back\n");
- Event send_event;
- send_event.type = EventTypeUiNext;
- this->prev->handle(
- &send_event,
- store,
- u8g2,
- area
- );
- this->prev = NULL;
- store->led = ColorBlack;
- this->wait_time = 0;
- this->is_on = true;
- this->active = false;
- } else {
- printf("[blinker view] no back/loop\n");
- }
- }
- if(event->value.button.state && event->value.button.id != ButtonsBack) {
- this->active = true;
- }
- if(!event->value.button.state && event->value.button.id != ButtonsBack) {
- this->active = false;
- }
- break;
- // start component from prev
- case EventTypeUiNext:
- printf("[blinker view] start component %lX\n", (uint32_t)this);
- if(this->prev == NULL) {
- this->prev = store->current_component;
- }
- // set current item to self
- store->current_component = this;
- this->dirty = true;
- this->wait_time = 0;
- this->is_on = true;
- this->active = false;
- break;
- case EventTypeTick:
- if(this->active) {
- this->wait_time += event->value.tick_delta;
- if(this->is_on) {
- if(this->wait_time > this->config.on_time) {
- this->wait_time = 0;
- this->is_on = false;
- }
- } else {
- if(this->wait_time > this->config.off_time) {
- this->wait_time = 0;
- this->is_on = true;
- }
- }
- store->led = this->is_on ? this->config.on_color : this->config.off_color;
- } else {
- store->led = ColorBlack;
- this->wait_time = 0;
- this->is_on = true;
- }
- if(this->dirty) {
- this->draw_fn(this->data, u8g2, area);
- store->dirty_screen = true;
- this->dirty = false;
- }
- break;
- default: break;
- }
- }
- #define MENU_DRAW_LINES 4
- Point draw_block(u8g2_t* u8g2, const char* text, Block layout, uint8_t x, uint8_t y) {
- u8g2_SetDrawColor(u8g2, layout.background);
- u8g2_DrawBox(u8g2,
- x + layout.margin_left,
- y + layout.margin_top,
- layout.width, layout.height
- );
- u8g2_SetDrawColor(u8g2, layout.color);
- u8g2_SetFont(u8g2, layout.font);
- if(text != NULL) {
- u8g2_DrawStr(u8g2,
- x + layout.margin_left + layout.padding_left,
- y + layout.margin_top + layout.padding_top,
- text
- );
- }
- return {
- x: x + layout.margin_left + layout.width,
- y: y + layout.margin_top + layout.height
- };
- }
- void draw_menu(MenuCtx* ctx, u8g2_t* u8g2, ScreenArea area) {
- // u8g2_ClearBuffer(u8g2);
- // clear area
- u8g2_SetDrawColor(u8g2, 0);
- u8g2_DrawBox(u8g2, area.x, area.y, area.width, area.height);
- u8g2_SetFontMode(u8g2, 1);
- uint8_t list_start = ctx->current - ctx->cursor;
- uint8_t list_size = ctx->size > MENU_DRAW_LINES ? MENU_DRAW_LINES : ctx->size;
- // draw header
- /*
- Point next = draw_block(u8g2, (const char*)data->name, Block {
- width: 128,
- height: 14,
- margin_left: 0,
- margin_top: 0,
- padding_left: 4,
- padding_top: 13,
- background: 1,
- color: 0,
- font: (uint8_t*)u8g2_font_helvB14_tf,
- }, area.x, area.y);
- */
- Point next = {area.x, area.y};
- for(size_t i = 0; i < list_size; i++) {
- next = draw_block(u8g2, (const char*)ctx->list[list_start + i].name, Block {
- width: 128,
- height: 15,
- margin_left: 0,
- margin_top: i == 0 ? 2 : 0,
- padding_left: 2,
- padding_top: 12,
- background: i == ctx->cursor ? 1 : 0,
- color: i == ctx->cursor ? 0 : 1,
- font: (uint8_t*)u8g2_font_7x14_tf,
- }, area.x, next.y);
- }
- // u8g2_font_7x14_tf
- // u8g2_font_profont12_tf smallerbut cute
- // u8g2_font_samim_12_t_all орочий
- }
- void MenuCtx::handle(MenuEvent event) {
- uint8_t menu_size = this->size > MENU_DRAW_LINES ? MENU_DRAW_LINES : this->size;
- switch(event) {
- case MenuEventDown: {
- if(this->current < (this->size - 1)) {
- this->current++;
- if(this->cursor < menu_size - 2 || this->current == this->size - 1) {
- this->cursor++;
- }
- } else {
- this->current = 0;
- this->cursor = 0;
- }
- } break;
- case MenuEventUp: {
- if(this->current > 0) {
- this->current--;
- if(this->cursor > 1 || this->current == 0) {
- this->cursor--;
- }
- } else {
- this->current = this->size - 1;
- this->cursor = menu_size - 1;
- }
- } break;
- }
- }
- void MenuCtx::reset() {
- this->current = 0;
- this->cursor = 0;
- }
- // draw numenu and handle navigation
- void MenuComponent::handle(Event* event, Store* store, u8g2_t* u8g2, ScreenArea area) {
- switch(event->type) {
- // get button event
- case EventTypeButton: {
- if(event->value.button.id == ButtonsOk && event->value.button.state) {
- if(this->ctx.current < this->ctx.size) {
- FlipperComponent* next_item = (FlipperComponent*)this->ctx.list[this->ctx.current].item;
- if(next_item) {
- store->is_fullscreen = false;
- printf("[layout view] go to %d item\n", this->ctx.current);
- Event send_event;
- send_event.type = EventTypeUiNext;
- next_item->handle(
- &send_event,
- store,
- u8g2,
- area
- );
- } else {
- printf("[menu view] no item at %d\n", this->ctx.current);
- }
- }
- }
- if(event->value.button.id == ButtonsDown && event->value.button.state) {
- this->ctx.handle(MenuEventDown);
- this->dirty = true;
- }
- if(event->value.button.id == ButtonsUp && event->value.button.state) {
- this->ctx.handle(MenuEventUp);
- this->dirty = true;
- }
- // go back item
- if(event->value.button.id == ButtonsBack && event->value.button.state) {
- if(this->prev && this->prev != this) {
- store->is_fullscreen = false;
- printf("[menu view] go back\n");
- this->ctx.reset();
- Event send_event;
- send_event.type = EventTypeUiNext;
- this->prev->handle(
- &send_event,
- store,
- u8g2,
- area
- );
- this->prev = NULL;
- } else {
- printf("[menu view] no back/loop\n");
- }
- }
- } break;
- // start component from prev
- case EventTypeUiNext:
- printf("[menu view] start component %lX (size %d)\n", (uint32_t)this, this->ctx.size);
- // set prev item
- if(this->prev == NULL) {
- printf("[menu view] set prev element to %lX\n", (uint32_t)store->current_component);
- this->prev = store->current_component;
- }
- // set current item to self
- store->current_component = this;
- store->is_fullscreen = true;
- // render menu
- this->dirty = true;
- break;
- case EventTypeTick:
- if(this->dirty) {
- draw_menu(&this->ctx, u8g2, area);
- store->dirty_screen = true;
- this->dirty = false;
- }
- break;
- default: break;
- }
- }
|