Merge branch 'release-candidate' into release
This commit is contained in:
commit
ce74a35066
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -11,7 +11,7 @@ on:
|
||||
|
||||
env:
|
||||
TARGETS: f6 f7
|
||||
DEFAULT_TARGET: f6
|
||||
DEFAULT_TARGET: f7
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
9
.gitmodules
vendored
9
.gitmodules
vendored
@ -7,3 +7,12 @@
|
||||
[submodule "lib/littlefs"]
|
||||
path = lib/littlefs
|
||||
url = https://github.com/littlefs-project/littlefs.git
|
||||
[submodule "lib/nanopb"]
|
||||
path = lib/nanopb
|
||||
url = https://github.com/nanopb/nanopb.git
|
||||
[submodule "assets/protobuf"]
|
||||
path = assets/protobuf
|
||||
url = https://github.com/flipperdevices/flipperzero-protobuf.git
|
||||
[submodule "lib/libusb_stm32"]
|
||||
path = lib/libusb_stm32
|
||||
url = https://github.com/flipperdevices/libusb_stm32.git
|
||||
|
||||
128
CODE_OF_CONDUCT.md
Normal file
128
CODE_OF_CONDUCT.md
Normal file
@ -0,0 +1,128 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, religion, or sexual identity
|
||||
and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the
|
||||
overall community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or
|
||||
advances of any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email
|
||||
address, without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
hello@flipperdevices.com.
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series
|
||||
of actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or
|
||||
permanent ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within
|
||||
the community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.0, available at
|
||||
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
||||
|
||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||
enforcement ladder](https://github.com/mozilla/diversity).
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
https://www.contributor-covenant.org/faq. Translations are available at
|
||||
https://www.contributor-covenant.org/translations.
|
||||
71
CONTRIBUTING.md
Normal file
71
CONTRIBUTING.md
Normal file
@ -0,0 +1,71 @@
|
||||
# Welcome to FlipperZero contributing guide <!-- omit in toc -->
|
||||
|
||||
Thank you for investing your time in contributing to our project!
|
||||
|
||||
Read our [Code of Coduct](CODE_OF_CONDUCT.md) to keep our community approachable and respectable.
|
||||
|
||||
In this guide you will get an overview of the contribution workflow from opening an issue, creating a PR, reviewing, and merging the PR.
|
||||
|
||||
## New contributor guide
|
||||
|
||||
See the [ReadMe](ReadMe.md) to get an overview of the project. Here are some helpful resources to get you comfortable with open source contribution:
|
||||
|
||||
- [Finding ways to contribute to open source on GitHub](https://docs.github.com/en/get-started/exploring-projects-on-github/finding-ways-to-contribute-to-open-source-on-github)
|
||||
- [Set up Git](https://docs.github.com/en/get-started/quickstart/set-up-git)
|
||||
- [GitHub flow](https://docs.github.com/en/get-started/quickstart/github-flow)
|
||||
- [Collaborating with pull requests](https://docs.github.com/en/github/collaborating-with-pull-requests)
|
||||
|
||||
## Getting started
|
||||
|
||||
Before writing code and creating PR make sure that it aligns with our mission and guidlines:
|
||||
|
||||
- All our devices are intended for research and education.
|
||||
- PR that contains code intended to commit crimes is not going to be accepted.
|
||||
- Your PR must contain code compatiable with project [LICENSE](LICENSE).
|
||||
- PR will only be merged if it pass CI/CD.
|
||||
- PR will only be merged if it pass review by code owner.
|
||||
|
||||
Feel free to ask questions in issues if you're not sure.
|
||||
|
||||
### Issues
|
||||
|
||||
#### Create a new issue
|
||||
|
||||
If you found a problem, [search if an issue already exists](https://docs.github.com/en/github/searching-for-information-on-github/searching-on-github/searching-issues-and-pull-requests#search-by-the-title-body-or-comments). If a related issue doesn't exist, you can open a new issue using a relevant [issue form](https://github.com/flipperdevices/flipperzero-firmware/issues/new/choose).
|
||||
|
||||
#### Solve an issue
|
||||
|
||||
Scan through our [existing issues](https://github.com/flipperdevices/flipperzero-firmware/issues) to find one that interests you.
|
||||
|
||||
### Make Changes
|
||||
|
||||
1. Fork the repository.
|
||||
- Using GitHub Desktop:
|
||||
- [Getting started with GitHub Desktop](https://docs.github.com/en/desktop/installing-and-configuring-github-desktop/getting-started-with-github-desktop) will guide you through setting up Desktop.
|
||||
- Once Desktop is set up, you can use it to [fork the repo](https://docs.github.com/en/desktop/contributing-and-collaborating-using-github-desktop/cloning-and-forking-repositories-from-github-desktop)!
|
||||
|
||||
- Using the command line:
|
||||
- [Fork the repo](https://docs.github.com/en/github/getting-started-with-github/fork-a-repo#fork-an-example-repository) so that you can make your changes without affecting the original project until you're ready to merge them.
|
||||
|
||||
2. Install build requirements
|
||||
|
||||
3. Create a working branch and start with your changes!
|
||||
|
||||
### Commit your update
|
||||
|
||||
Commit the changes once you are happy with them. Make sure that code compilation is not broken and passes tests. Check syntax and formatting.
|
||||
|
||||
### Pull Request
|
||||
|
||||
When you're done making the changes, open a pull request, often referred to as a PR.
|
||||
- Fill out the "Ready for review" template so we can review your PR. This template helps reviewers understand your changes and the purpose of your pull request.
|
||||
- Don't forget to [link PR to issue](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue) if you are solving one.
|
||||
- Enable the checkbox to [allow maintainer edits](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/allowing-changes-to-a-pull-request-branch-created-from-a-fork) so the branch can be updated for a merge.
|
||||
Once you submit your PR, a Docs team member will review your proposal. We may ask questions or request for additional information.
|
||||
- We may ask for changes to be made before a PR can be merged, either using [suggested changes](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/incorporating-feedback-in-your-pull-request) or pull request comments. You can apply suggested changes directly through the UI. You can make any other changes in your fork, then commit them to your branch.
|
||||
- As you update your PR and apply changes, mark each conversation as [resolved](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/commenting-on-a-pull-request#resolving-conversations).
|
||||
- If you run into any merge issues, checkout this [git tutorial](https://lab.github.com/githubtraining/managing-merge-conflicts) to help you resolve merge conflicts and other issues.
|
||||
|
||||
### Your PR is merged!
|
||||
|
||||
Congratulations :tada::tada: The FlipperDevices team thanks you :sparkles:.
|
||||
@ -162,6 +162,7 @@ Finally, you will have **`firmware/.obj/f6/full.dfu`** file that can be distribu
|
||||
- core - core libraries: home for furi
|
||||
- debug - debug helpers, plugins and tools
|
||||
- docker - docker image sources (used for automated firmware build)
|
||||
- documentation - documentation generation system configs and input files
|
||||
- firmware - firmware for flipper
|
||||
* targets - targets' hal and implementation
|
||||
- lib - different libraries and drivers that apps and firmware uses
|
||||
|
||||
49
applications/applications.c
Executable file → Normal file
49
applications/applications.c
Executable file → Normal file
@ -2,6 +2,7 @@
|
||||
#include <assets_icons.h>
|
||||
|
||||
// Services
|
||||
extern int32_t rpc_srv(void* p);
|
||||
extern int32_t bt_srv(void* p);
|
||||
extern int32_t cli_srv(void* p);
|
||||
extern int32_t dialogs_srv(void* p);
|
||||
@ -19,8 +20,8 @@ extern int32_t desktop_srv(void* p);
|
||||
extern int32_t accessor_app(void* p);
|
||||
extern int32_t archive_app(void* p);
|
||||
extern int32_t blink_test_app(void* p);
|
||||
extern int32_t flipper_test_app(void* p);
|
||||
extern int32_t gpio_test_app(void* p);
|
||||
extern int32_t delay_test_app(void* p);
|
||||
extern int32_t gpio_app(void* p);
|
||||
extern int32_t ibutton_app(void* p);
|
||||
extern int32_t irda_app(void* p);
|
||||
extern int32_t irda_monitor_app(void* p);
|
||||
@ -33,6 +34,9 @@ extern int32_t storage_test_app(void* p);
|
||||
extern int32_t subghz_app(void* p);
|
||||
extern int32_t vibro_test_app(void* p);
|
||||
extern int32_t bt_debug_app(void* p);
|
||||
extern int32_t usb_test_app(void* p);
|
||||
extern int32_t usb_mouse_app(void* p);
|
||||
extern int32_t bad_usb_app(void* p);
|
||||
|
||||
// Plugins
|
||||
extern int32_t music_player_app(void* p);
|
||||
@ -47,6 +51,7 @@ extern void nfc_cli_init();
|
||||
extern void storage_cli_init();
|
||||
extern void subghz_cli_init();
|
||||
extern void power_cli_init();
|
||||
extern void unit_tests_cli_init();
|
||||
|
||||
// Settings
|
||||
extern int32_t notification_settings_app(void* p);
|
||||
@ -58,6 +63,10 @@ extern int32_t power_settings_app(void* p);
|
||||
|
||||
const FlipperApplication FLIPPER_SERVICES[] = {
|
||||
/* Services */
|
||||
#ifdef SRV_RPC
|
||||
{.app = rpc_srv, .name = "RPC", .stack_size = 1024 * 4, .icon = NULL},
|
||||
#endif
|
||||
|
||||
#ifdef SRV_BT
|
||||
{.app = bt_srv, .name = "BT", .stack_size = 1024, .icon = NULL},
|
||||
#endif
|
||||
@ -116,24 +125,24 @@ const FlipperApplication FLIPPER_APPS[] = {
|
||||
{.app = subghz_app, .name = "Sub-GHz", .stack_size = 2048, .icon = &A_Sub1ghz_14},
|
||||
#endif
|
||||
|
||||
#ifdef APP_NFC
|
||||
{.app = nfc_app, .name = "NFC", .stack_size = 4096, .icon = &A_NFC_14},
|
||||
#endif
|
||||
|
||||
#ifdef APP_LF_RFID
|
||||
{.app = lfrfid_app, .name = "125 kHz RFID", .stack_size = 2048, .icon = &A_125khz_14},
|
||||
#endif
|
||||
|
||||
#ifdef APP_NFC
|
||||
{.app = nfc_app, .name = "NFC", .stack_size = 4096, .icon = &A_NFC_14},
|
||||
#endif
|
||||
|
||||
#ifdef APP_IRDA
|
||||
{.app = irda_app, .name = "Infrared", .stack_size = 1024 * 3, .icon = &A_Infrared_14},
|
||||
#endif
|
||||
|
||||
#ifdef APP_IBUTTON
|
||||
{.app = ibutton_app, .name = "iButton", .stack_size = 2048, .icon = &A_iButton_14},
|
||||
#ifdef APP_GPIO
|
||||
{.app = gpio_app, .name = "GPIO", .stack_size = 1024, .icon = &A_GPIO_14},
|
||||
#endif
|
||||
|
||||
#ifdef APP_GPIO_TEST
|
||||
{.app = gpio_test_app, .name = "GPIO", .stack_size = 1024, .icon = &A_GPIO_14},
|
||||
#ifdef APP_IBUTTON
|
||||
{.app = ibutton_app, .name = "iButton", .stack_size = 2048, .icon = &A_iButton_14},
|
||||
#endif
|
||||
|
||||
};
|
||||
@ -177,6 +186,10 @@ const FlipperOnStartHook FLIPPER_ON_SYSTEM_START[] = {
|
||||
#ifdef SRV_STORAGE
|
||||
storage_cli_init,
|
||||
#endif
|
||||
|
||||
#ifdef APP_UNIT_TESTS
|
||||
unit_tests_cli_init,
|
||||
#endif
|
||||
};
|
||||
|
||||
const size_t FLIPPER_ON_SYSTEM_START_COUNT =
|
||||
@ -210,8 +223,16 @@ const FlipperApplication FLIPPER_DEBUG_APPS[] = {
|
||||
{.app = accessor_app, .name = "Accessor", .stack_size = 4096, .icon = &A_Plugins_14},
|
||||
#endif
|
||||
|
||||
#ifdef APP_UNIT_TESTS
|
||||
{.app = flipper_test_app, .name = "Unit Tests", .stack_size = 1024, .icon = &A_Plugins_14},
|
||||
#ifdef APP_USB_TEST
|
||||
{.app = usb_test_app, .name = "USB Test", .stack_size = 1024, .icon = &A_Plugins_14},
|
||||
#endif
|
||||
|
||||
#ifdef APP_USB_MOUSE
|
||||
{.app = usb_mouse_app, .name = "USB Mouse demo", .stack_size = 1024, .icon = &A_Plugins_14},
|
||||
#endif
|
||||
|
||||
#ifdef APP_BAD_USB
|
||||
{.app = bad_usb_app, .name = "Bad USB test", .stack_size = 2048, .icon = &A_Plugins_14},
|
||||
#endif
|
||||
|
||||
#ifdef APP_IRDA_MONITOR
|
||||
@ -229,6 +250,10 @@ const FlipperApplication FLIPPER_DEBUG_APPS[] = {
|
||||
#ifdef SRV_BT
|
||||
{.app = bt_debug_app, .name = "Bluetooth Debug", .stack_size = 1024, .icon = NULL},
|
||||
#endif
|
||||
|
||||
#ifdef APP_UNIT_TESTS
|
||||
{.app = delay_test_app, .name = "Delay Test App", .stack_size = 1024, .icon = &A_Plugins_14},
|
||||
#endif
|
||||
};
|
||||
|
||||
const size_t FLIPPER_DEBUG_APPS_COUNT = sizeof(FLIPPER_DEBUG_APPS) / sizeof(FlipperApplication);
|
||||
|
||||
@ -2,8 +2,8 @@ APP_DIR = $(PROJECT_ROOT)/applications
|
||||
LIB_DIR = $(PROJECT_ROOT)/lib
|
||||
|
||||
CFLAGS += -I$(APP_DIR)
|
||||
C_SOURCES += $(shell find $(APP_DIR) -name *.c)
|
||||
CPP_SOURCES += $(shell find $(APP_DIR) -name *.cpp)
|
||||
C_SOURCES += $(shell find $(APP_DIR) -name "*.c")
|
||||
CPP_SOURCES += $(shell find $(APP_DIR) -name "*.cpp")
|
||||
|
||||
|
||||
APP_RELEASE ?= 1
|
||||
@ -19,12 +19,13 @@ SRV_LOADER = 1
|
||||
SRV_NOTIFICATION = 1
|
||||
SRV_POWER = 1
|
||||
SRV_POWER_OBSERVER = 1
|
||||
SRV_RPC = 1
|
||||
SRV_STORAGE = 1
|
||||
|
||||
# Apps
|
||||
SRV_DESKTOP = 1
|
||||
APP_ARCHIVE = 1
|
||||
APP_GPIO_TEST = 1
|
||||
APP_GPIO = 1
|
||||
APP_IBUTTON = 1
|
||||
APP_IRDA = 1
|
||||
APP_LF_RFID = 1
|
||||
@ -41,8 +42,10 @@ APP_BLINK = 1
|
||||
APP_IRDA_MONITOR = 1
|
||||
APP_KEYPAD_TEST = 1
|
||||
APP_SD_TEST = 1
|
||||
APP_UNIT_TESTS = 0
|
||||
APP_VIBRO_DEMO = 1
|
||||
APP_USB_TEST = 1
|
||||
APP_USB_MOUSE = 1
|
||||
APP_BAD_USB = 1
|
||||
endif
|
||||
|
||||
|
||||
@ -58,7 +61,7 @@ SRV_GUI = 1
|
||||
endif
|
||||
|
||||
|
||||
APP_UNIT_TESTS ?= 0
|
||||
APP_UNIT_TESTS ?= 0
|
||||
ifeq ($(APP_UNIT_TESTS), 1)
|
||||
CFLAGS += -DAPP_UNIT_TESTS
|
||||
endif
|
||||
@ -121,6 +124,27 @@ SRV_GUI = 1
|
||||
endif
|
||||
|
||||
|
||||
APP_USB_TEST ?= 0
|
||||
ifeq ($(APP_USB_TEST), 1)
|
||||
CFLAGS += -DAPP_USB_TEST
|
||||
SRV_INPUT = 1
|
||||
SRV_GUI = 1
|
||||
endif
|
||||
|
||||
APP_USB_MOUSE ?= 0
|
||||
ifeq ($(APP_USB_MOUSE), 1)
|
||||
CFLAGS += -DAPP_USB_MOUSE
|
||||
SRV_INPUT = 1
|
||||
SRV_GUI = 1
|
||||
endif
|
||||
|
||||
APP_BAD_USB ?= 0
|
||||
ifeq ($(APP_BAD_USB), 1)
|
||||
CFLAGS += -DAPP_BAD_USB
|
||||
SRV_INPUT = 1
|
||||
SRV_GUI = 1
|
||||
endif
|
||||
|
||||
APP_KEYPAD_TEST ?= 0
|
||||
ifeq ($(APP_KEYPAD_TEST), 1)
|
||||
CFLAGS += -DAPP_KEYPAD_TEST
|
||||
@ -135,9 +159,9 @@ SRV_GUI = 1
|
||||
endif
|
||||
|
||||
|
||||
APP_GPIO_TEST ?= 0
|
||||
ifeq ($(APP_GPIO_TEST), 1)
|
||||
CFLAGS += -DAPP_GPIO_TEST
|
||||
APP_GPIO ?= 0
|
||||
ifeq ($(APP_GPIO), 1)
|
||||
CFLAGS += -DAPP_GPIO
|
||||
SRV_GUI = 1
|
||||
endif
|
||||
|
||||
@ -197,6 +221,10 @@ SRV_GUI = 1
|
||||
SRV_CLI = 1
|
||||
endif
|
||||
|
||||
SRV_RPC ?= 0
|
||||
ifeq ($(SRV_RPC), 1)
|
||||
CFLAGS += -DSRV_RPC
|
||||
endif
|
||||
|
||||
SRV_LOADER ?= 0
|
||||
ifeq ($(SRV_LOADER), 1)
|
||||
|
||||
@ -10,7 +10,9 @@ void archive_update_offset(ArchiveBrowserView* browser) {
|
||||
|
||||
if(array_size > 3 && model->idx >= array_size - 1) {
|
||||
model->list_offset = model->idx - 3;
|
||||
} else if(model->last_offset && model->last_offset != model->list_offset) {
|
||||
} else if(
|
||||
model->last_offset && model->last_offset != model->list_offset &&
|
||||
model->tab_idx == model->last_tab) {
|
||||
model->list_offset = model->last_offset;
|
||||
model->last_offset = !model->last_offset;
|
||||
} else if(model->list_offset < model->idx - bounds) {
|
||||
@ -18,7 +20,6 @@ void archive_update_offset(ArchiveBrowserView* browser) {
|
||||
} else if(model->list_offset > model->idx - bounds) {
|
||||
model->list_offset = CLAMP(model->idx - 1, array_size - bounds, 0);
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
@ -75,6 +76,31 @@ void archive_file_array_rm_selected(ArchiveBrowserView* browser) {
|
||||
archive_update_offset(browser);
|
||||
}
|
||||
|
||||
void archive_file_array_swap(ArchiveBrowserView* browser, int8_t d) {
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
ArchiveFile_t temp;
|
||||
size_t array_size = files_array_size(model->files) - 1;
|
||||
uint8_t swap_idx = CLAMP(model->idx + d, array_size, 0);
|
||||
|
||||
if(model->idx == 0 && d < 0) {
|
||||
ArchiveFile_t_init(&temp);
|
||||
files_array_pop_at(&temp, model->files, array_size);
|
||||
files_array_push_at(model->files, model->idx, temp);
|
||||
ArchiveFile_t_clear(&temp);
|
||||
} else if(model->idx == array_size && d > 0) {
|
||||
ArchiveFile_t_init(&temp);
|
||||
files_array_pop_at(&temp, model->files, model->last_idx);
|
||||
files_array_push_at(model->files, array_size, temp);
|
||||
ArchiveFile_t_clear(&temp);
|
||||
} else {
|
||||
files_array_swap_at(model->files, model->idx, swap_idx);
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
void archive_file_array_rm_all(ArchiveBrowserView* browser) {
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
@ -94,6 +120,18 @@ ArchiveFile_t* archive_get_current_file(ArchiveBrowserView* browser) {
|
||||
return selected;
|
||||
}
|
||||
|
||||
ArchiveFile_t* archive_get_file_at(ArchiveBrowserView* browser, size_t idx) {
|
||||
ArchiveFile_t* selected;
|
||||
idx = CLAMP(idx, archive_file_array_size(browser), 0);
|
||||
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
selected = files_array_size(model->files) ? files_array_get(model->files, idx) : NULL;
|
||||
return false;
|
||||
});
|
||||
return selected;
|
||||
}
|
||||
|
||||
ArchiveTabEnum archive_get_tab(ArchiveBrowserView* browser) {
|
||||
ArchiveTabEnum tab_id;
|
||||
with_view_model(
|
||||
@ -178,6 +216,14 @@ void archive_show_file_menu(ArchiveBrowserView* browser, bool show) {
|
||||
});
|
||||
}
|
||||
|
||||
void archive_favorites_move_mode(ArchiveBrowserView* browser, bool active) {
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
model->move_fav = active;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void archive_switch_dir(ArchiveBrowserView* browser, const char* path) {
|
||||
furi_assert(browser);
|
||||
furi_assert(path);
|
||||
|
||||
@ -52,9 +52,11 @@ void archive_update_focus(ArchiveBrowserView* browser, const char* target);
|
||||
|
||||
size_t archive_file_array_size(ArchiveBrowserView* browser);
|
||||
void archive_file_array_rm_selected(ArchiveBrowserView* browser);
|
||||
void archive_file_array_swap(ArchiveBrowserView* browser, int8_t d);
|
||||
void archive_file_array_rm_all(ArchiveBrowserView* browser);
|
||||
|
||||
ArchiveFile_t* archive_get_current_file(ArchiveBrowserView* browser);
|
||||
ArchiveFile_t* archive_get_file_at(ArchiveBrowserView* browser, size_t idx);
|
||||
ArchiveTabEnum archive_get_tab(ArchiveBrowserView* browser);
|
||||
uint8_t archive_get_depth(ArchiveBrowserView* browser);
|
||||
const char* archive_get_path(ArchiveBrowserView* browser);
|
||||
@ -62,6 +64,7 @@ const char* archive_get_name(ArchiveBrowserView* browser);
|
||||
|
||||
void archive_add_item(ArchiveBrowserView* browser, FileInfo* file_info, const char* name);
|
||||
void archive_show_file_menu(ArchiveBrowserView* browser, bool show);
|
||||
void archive_favorites_move_mode(ArchiveBrowserView* browser, bool active);
|
||||
|
||||
void archive_switch_tab(ArchiveBrowserView* browser, InputKey key);
|
||||
void archive_enter_dir(ArchiveBrowserView* browser, string_t name);
|
||||
|
||||
@ -34,7 +34,7 @@ uint16_t archive_favorites_count(void* context) {
|
||||
bool archive_favorites_read(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
ArchiveBrowserView* archive_view = context;
|
||||
ArchiveBrowserView* browser = context;
|
||||
FileWorker* file_worker = file_worker_alloc(true);
|
||||
|
||||
string_t buffer;
|
||||
@ -52,7 +52,7 @@ bool archive_favorites_read(void* context) {
|
||||
break;
|
||||
}
|
||||
|
||||
archive_add_item(archive_view, &file_info, string_get_cstr(buffer));
|
||||
archive_add_item(browser, &file_info, string_get_cstr(buffer));
|
||||
string_clean(buffer);
|
||||
}
|
||||
}
|
||||
@ -63,17 +63,15 @@ bool archive_favorites_read(void* context) {
|
||||
}
|
||||
|
||||
bool archive_favorites_delete(const char* format, ...) {
|
||||
string_t buffer;
|
||||
string_t filename;
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
uint8_t len = vsnprintf(NULL, 0, format, args);
|
||||
char filename[len + 1];
|
||||
vsnprintf(filename, len + 1, format, args);
|
||||
string_init_vprintf(filename, format, args);
|
||||
va_end(args);
|
||||
|
||||
FileWorker* file_worker = file_worker_alloc(true);
|
||||
|
||||
string_t buffer;
|
||||
string_init(buffer);
|
||||
FileWorker* file_worker = file_worker_alloc(true);
|
||||
|
||||
bool result = file_worker_open(file_worker, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING);
|
||||
if(result) {
|
||||
@ -85,13 +83,14 @@ bool archive_favorites_delete(const char* format, ...) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(string_search_str(buffer, filename)) {
|
||||
archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\r\n", string_get_cstr(buffer));
|
||||
if(string_search(buffer, filename)) {
|
||||
archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(buffer));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string_clear(buffer);
|
||||
string_clear(filename);
|
||||
|
||||
file_worker_close(file_worker);
|
||||
file_worker_remove(file_worker, ARCHIVE_FAV_PATH);
|
||||
@ -103,16 +102,15 @@ bool archive_favorites_delete(const char* format, ...) {
|
||||
}
|
||||
|
||||
bool archive_is_favorite(const char* format, ...) {
|
||||
string_t buffer;
|
||||
string_t filename;
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
uint8_t len = vsnprintf(NULL, 0, format, args);
|
||||
char filename[len + 1];
|
||||
vsnprintf(filename, len + 1, format, args);
|
||||
string_init_vprintf(filename, format, args);
|
||||
va_end(args);
|
||||
|
||||
FileWorker* file_worker = file_worker_alloc(true);
|
||||
string_t buffer;
|
||||
string_init(buffer);
|
||||
FileWorker* file_worker = file_worker_alloc(true);
|
||||
|
||||
bool found = false;
|
||||
bool result = file_worker_open(file_worker, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING);
|
||||
@ -125,7 +123,7 @@ bool archive_is_favorite(const char* format, ...) {
|
||||
if(!string_size(buffer)) {
|
||||
break;
|
||||
}
|
||||
if(!string_search_str(buffer, filename)) {
|
||||
if(!string_search(buffer, filename)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
@ -133,6 +131,7 @@ bool archive_is_favorite(const char* format, ...) {
|
||||
}
|
||||
|
||||
string_clear(buffer);
|
||||
string_clear(filename);
|
||||
file_worker_close(file_worker);
|
||||
file_worker_free(file_worker);
|
||||
|
||||
@ -166,7 +165,7 @@ bool archive_favorites_rename(const char* file_path, const char* src, const char
|
||||
|
||||
archive_file_append(
|
||||
ARCHIVE_FAV_TEMP_PATH,
|
||||
"%s\r\n",
|
||||
"%s\n",
|
||||
string_search(buffer, path) ? string_get_cstr(buffer) : dst);
|
||||
}
|
||||
}
|
||||
@ -186,5 +185,22 @@ bool archive_favorites_rename(const char* file_path, const char* src, const char
|
||||
void archive_add_to_favorites(const char* file_path) {
|
||||
furi_assert(file_path);
|
||||
|
||||
archive_file_append(ARCHIVE_FAV_PATH, "%s\r\n", file_path);
|
||||
archive_file_append(ARCHIVE_FAV_PATH, "%s\n", file_path);
|
||||
}
|
||||
|
||||
void archive_favorites_save(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
ArchiveBrowserView* browser = context;
|
||||
FileWorker* file_worker = file_worker_alloc(true);
|
||||
|
||||
for(size_t i = 0; i < archive_file_array_size(browser); i++) {
|
||||
ArchiveFile_t* item = archive_get_file_at(browser, i);
|
||||
archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(item->name));
|
||||
}
|
||||
|
||||
file_worker_remove(file_worker, ARCHIVE_FAV_PATH);
|
||||
file_worker_rename(file_worker, ARCHIVE_FAV_TEMP_PATH, ARCHIVE_FAV_PATH);
|
||||
|
||||
file_worker_free(file_worker);
|
||||
}
|
||||
@ -9,4 +9,5 @@ bool archive_favorites_read(void* context);
|
||||
bool archive_favorites_delete(const char* format, ...);
|
||||
bool archive_is_favorite(const char* format, ...);
|
||||
bool archive_favorites_rename(const char* file_path, const char* src, const char* dst);
|
||||
void archive_add_to_favorites(const char* file_path);
|
||||
void archive_add_to_favorites(const char* file_path);
|
||||
void archive_favorites_save(void* context);
|
||||
|
||||
@ -138,11 +138,10 @@ bool archive_read_dir(void* context, const char* path) {
|
||||
void archive_file_append(const char* path, const char* format, ...) {
|
||||
furi_assert(path);
|
||||
|
||||
string_t string;
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
uint8_t len = vsnprintf(NULL, 0, format, args);
|
||||
char cstr_buff[len + 1];
|
||||
vsnprintf(cstr_buff, len + 1, format, args);
|
||||
string_init_vprintf(string, format, args);
|
||||
va_end(args);
|
||||
|
||||
FileWorker* file_worker = file_worker_alloc(false);
|
||||
@ -151,7 +150,7 @@ void archive_file_append(const char* path, const char* format, ...) {
|
||||
FURI_LOG_E("Archive", "Append open error");
|
||||
}
|
||||
|
||||
if(!file_worker_write(file_worker, cstr_buff, strlen(cstr_buff))) {
|
||||
if(!file_worker_write(file_worker, string_get_cstr(string), string_size(string))) {
|
||||
FURI_LOG_E("Archive", "Append write error");
|
||||
}
|
||||
|
||||
@ -159,26 +158,28 @@ void archive_file_append(const char* path, const char* format, ...) {
|
||||
file_worker_free(file_worker);
|
||||
}
|
||||
|
||||
void archive_delete_file(void* context, string_t path, string_t name) {
|
||||
void archive_delete_file(void* context, const char* format, ...) {
|
||||
furi_assert(context);
|
||||
furi_assert(path);
|
||||
furi_assert(name);
|
||||
|
||||
string_t filename;
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
string_init_vprintf(filename, format, args);
|
||||
va_end(args);
|
||||
|
||||
ArchiveBrowserView* browser = context;
|
||||
FileWorker* file_worker = file_worker_alloc(true);
|
||||
|
||||
string_t full_path;
|
||||
string_init_printf(full_path, "%s/%s", string_get_cstr(path), string_get_cstr(name));
|
||||
|
||||
bool res = file_worker_remove(file_worker, string_get_cstr(full_path));
|
||||
bool res = file_worker_remove(file_worker, string_get_cstr(filename));
|
||||
file_worker_free(file_worker);
|
||||
|
||||
if(archive_is_favorite(string_get_cstr(full_path))) {
|
||||
archive_favorites_delete(string_get_cstr(full_path));
|
||||
if(archive_is_favorite("%s", string_get_cstr(filename))) {
|
||||
archive_favorites_delete("%s", string_get_cstr(filename));
|
||||
}
|
||||
|
||||
if(res) {
|
||||
archive_file_array_rm_selected(browser);
|
||||
}
|
||||
|
||||
string_clear(full_path);
|
||||
}
|
||||
string_clear(filename);
|
||||
}
|
||||
@ -54,4 +54,4 @@ bool archive_get_filenames(void* context, const char* path);
|
||||
bool archive_dir_empty(void* context, const char* path);
|
||||
bool archive_read_dir(void* context, const char* path);
|
||||
void archive_file_append(const char* path, const char* format, ...);
|
||||
void archive_delete_file(void* context, string_t path, string_t name);
|
||||
void archive_delete_file(void* context, const char* format, ...);
|
||||
@ -76,25 +76,32 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) {
|
||||
if(favorites) {
|
||||
archive_favorites_delete(name);
|
||||
archive_file_array_rm_selected(browser);
|
||||
archive_show_file_menu(browser, false);
|
||||
} else if(known_app) {
|
||||
if(archive_is_favorite("%s/%s", path, name)) {
|
||||
archive_favorites_delete("%s/%s", path, name);
|
||||
} else {
|
||||
archive_file_append(ARCHIVE_FAV_PATH, "%s/%s\r\n", path, name);
|
||||
archive_file_append(ARCHIVE_FAV_PATH, "%s/%s\n", path, name);
|
||||
}
|
||||
archive_show_file_menu(browser, false);
|
||||
}
|
||||
archive_show_file_menu(browser, false);
|
||||
consumed = true;
|
||||
break;
|
||||
|
||||
case ArchiveBrowserEventFileMenuRename:
|
||||
if(known_app && !favorites) {
|
||||
case ArchiveBrowserEventFileMenuAction:
|
||||
if(favorites) {
|
||||
browser->callback(ArchiveBrowserEventEnterFavMove, browser->context);
|
||||
} else if(known_app) {
|
||||
scene_manager_next_scene(archive->scene_manager, ArchiveAppSceneRename);
|
||||
}
|
||||
consumed = true;
|
||||
break;
|
||||
case ArchiveBrowserEventFileMenuDelete:
|
||||
archive_delete_file(browser, browser->path, selected->name);
|
||||
if(favorites) {
|
||||
archive_delete_file(browser, "%s", name);
|
||||
} else {
|
||||
archive_delete_file(browser, "%s/%s", path, name);
|
||||
}
|
||||
archive_show_file_menu(browser, false);
|
||||
consumed = true;
|
||||
break;
|
||||
@ -102,6 +109,30 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) {
|
||||
archive_enter_dir(browser, selected->name);
|
||||
consumed = true;
|
||||
break;
|
||||
case ArchiveBrowserEventFavMoveUp:
|
||||
archive_file_array_swap(browser, 1);
|
||||
consumed = true;
|
||||
break;
|
||||
case ArchiveBrowserEventFavMoveDown:
|
||||
archive_file_array_swap(browser, -1);
|
||||
consumed = true;
|
||||
break;
|
||||
case ArchiveBrowserEventEnterFavMove:
|
||||
strlcpy(archive->text_store, archive_get_name(browser), MAX_NAME_LEN);
|
||||
archive_show_file_menu(browser, false);
|
||||
archive_favorites_move_mode(archive->browser, true);
|
||||
consumed = true;
|
||||
break;
|
||||
case ArchiveBrowserEventExitFavMove:
|
||||
archive_update_focus(browser, archive->text_store);
|
||||
archive_favorites_move_mode(archive->browser, false);
|
||||
consumed = true;
|
||||
break;
|
||||
case ArchiveBrowserEventSaveFavMove:
|
||||
archive_favorites_move_mode(archive->browser, false);
|
||||
archive_favorites_save(archive->browser);
|
||||
consumed = true;
|
||||
break;
|
||||
|
||||
case ArchiveBrowserEventExit:
|
||||
if(archive_get_depth(browser)) {
|
||||
|
||||
@ -55,7 +55,7 @@ static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) {
|
||||
string_set_str(menu[1], "Unpin");
|
||||
} else if(model->tab_idx == ArchiveTabFavorites) {
|
||||
string_set_str(menu[1], "Unpin");
|
||||
string_set_str(menu[2], "---");
|
||||
string_set_str(menu[2], "Move");
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < MENU_ITEMS; i++) {
|
||||
@ -66,16 +66,23 @@ static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) {
|
||||
canvas_draw_icon(canvas, 74, 20 + model->menu_idx * 11, &I_ButtonRight_4x7);
|
||||
}
|
||||
|
||||
static void archive_draw_frame(Canvas* canvas, uint16_t idx, bool scrollbar) {
|
||||
static void archive_draw_frame(Canvas* canvas, uint16_t idx, bool scrollbar, bool moving) {
|
||||
uint8_t x_offset = moving ? MOVE_OFFSET : 0;
|
||||
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
canvas_draw_box(canvas, 0, 15 + idx * FRAME_HEIGHT, scrollbar ? 122 : 127, FRAME_HEIGHT);
|
||||
canvas_draw_box(
|
||||
canvas,
|
||||
0 + x_offset,
|
||||
15 + idx * FRAME_HEIGHT,
|
||||
(scrollbar ? 122 : 127) - x_offset,
|
||||
FRAME_HEIGHT);
|
||||
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
canvas_draw_dot(canvas, 0, 15 + idx * FRAME_HEIGHT);
|
||||
canvas_draw_dot(canvas, 1, 15 + idx * FRAME_HEIGHT);
|
||||
canvas_draw_dot(canvas, 0, (15 + idx * FRAME_HEIGHT) + 1);
|
||||
canvas_draw_dot(canvas, 0 + x_offset, 15 + idx * FRAME_HEIGHT);
|
||||
canvas_draw_dot(canvas, 1 + x_offset, 15 + idx * FRAME_HEIGHT);
|
||||
canvas_draw_dot(canvas, 0 + x_offset, (15 + idx * FRAME_HEIGHT) + 1);
|
||||
|
||||
canvas_draw_dot(canvas, 0, (15 + idx * FRAME_HEIGHT) + 11);
|
||||
canvas_draw_dot(canvas, 0 + x_offset, (15 + idx * FRAME_HEIGHT) + 11);
|
||||
canvas_draw_dot(canvas, scrollbar ? 121 : 126, 15 + idx * FRAME_HEIGHT);
|
||||
canvas_draw_dot(canvas, scrollbar ? 121 : 126, (15 + idx * FRAME_HEIGHT) + 11);
|
||||
}
|
||||
@ -89,23 +96,26 @@ static void draw_list(Canvas* canvas, ArchiveBrowserViewModel* model) {
|
||||
for(size_t i = 0; i < MIN(array_size, MENU_ITEMS); ++i) {
|
||||
string_t str_buff;
|
||||
char cstr_buff[MAX_NAME_LEN];
|
||||
|
||||
size_t idx = CLAMP(i + model->list_offset, array_size, 0);
|
||||
uint8_t x_offset = (model->move_fav && model->idx == idx) ? MOVE_OFFSET : 0;
|
||||
|
||||
ArchiveFile_t* file = files_array_get(model->files, CLAMP(idx, array_size - 1, 0));
|
||||
|
||||
strlcpy(cstr_buff, string_get_cstr(file->name), string_size(file->name) + 1);
|
||||
archive_trim_file_path(cstr_buff, is_known_app(file->type));
|
||||
string_init_set_str(str_buff, cstr_buff);
|
||||
elements_string_fit_width(canvas, str_buff, scrollbar ? MAX_LEN_PX - 6 : MAX_LEN_PX);
|
||||
elements_string_fit_width(
|
||||
canvas, str_buff, (scrollbar ? MAX_LEN_PX - 6 : MAX_LEN_PX) - x_offset);
|
||||
|
||||
if(model->idx == idx) {
|
||||
archive_draw_frame(canvas, i, scrollbar);
|
||||
archive_draw_frame(canvas, i, scrollbar, model->move_fav);
|
||||
} else {
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
}
|
||||
|
||||
canvas_draw_icon(canvas, 2, 16 + i * FRAME_HEIGHT, ArchiveItemIcons[file->type]);
|
||||
canvas_draw_str(canvas, 15, 24 + i * FRAME_HEIGHT, string_get_cstr(str_buff));
|
||||
canvas_draw_icon(
|
||||
canvas, 2 + x_offset, 16 + i * FRAME_HEIGHT, ArchiveItemIcons[file->type]);
|
||||
canvas_draw_str(canvas, 15 + x_offset, 24 + i * FRAME_HEIGHT, string_get_cstr(str_buff));
|
||||
string_clear(str_buff);
|
||||
}
|
||||
|
||||
@ -139,8 +149,13 @@ static void archive_render_status_bar(Canvas* canvas, ArchiveBrowserViewModel* m
|
||||
canvas_draw_line(canvas, 107, 1, 107, 11);
|
||||
canvas_draw_line(canvas, 108, 12, 126, 12);
|
||||
|
||||
canvas_draw_icon(canvas, 112, 2, &I_ButtonLeft_4x7);
|
||||
canvas_draw_icon(canvas, 120, 2, &I_ButtonRight_4x7);
|
||||
if(model->move_fav) {
|
||||
canvas_draw_icon(canvas, 111, 4, &I_ButtonUp_7x4);
|
||||
canvas_draw_icon(canvas, 118, 4, &I_ButtonDown_7x4);
|
||||
} else {
|
||||
canvas_draw_icon(canvas, 112, 2, &I_ButtonLeft_4x7);
|
||||
canvas_draw_icon(canvas, 120, 2, &I_ButtonRight_4x7);
|
||||
}
|
||||
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
canvas_draw_dot(canvas, 50, 0);
|
||||
@ -174,9 +189,11 @@ bool archive_view_input(InputEvent* event, void* context) {
|
||||
ArchiveBrowserView* browser = context;
|
||||
|
||||
bool in_menu;
|
||||
bool move_fav_mode;
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
in_menu = model->menu;
|
||||
move_fav_mode = model->move_fav;
|
||||
return false;
|
||||
});
|
||||
|
||||
@ -210,11 +227,17 @@ bool archive_view_input(InputEvent* event, void* context) {
|
||||
} else {
|
||||
if(event->type == InputTypeShort) {
|
||||
if(event->key == InputKeyLeft || event->key == InputKeyRight) {
|
||||
if(move_fav_mode) return false;
|
||||
archive_switch_tab(browser, event->key);
|
||||
} else if(event->key == InputKeyBack) {
|
||||
browser->callback(ArchiveBrowserEventExit, browser->context);
|
||||
if(move_fav_mode) {
|
||||
browser->callback(ArchiveBrowserEventExitFavMove, browser->context);
|
||||
} else {
|
||||
browser->callback(ArchiveBrowserEventExit, browser->context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(event->key == InputKeyUp || event->key == InputKeyDown) {
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
@ -222,8 +245,15 @@ bool archive_view_input(InputEvent* event, void* context) {
|
||||
if((event->type == InputTypeShort || event->type == InputTypeRepeat)) {
|
||||
if(event->key == InputKeyUp) {
|
||||
model->idx = ((model->idx - 1) + num_elements) % num_elements;
|
||||
if(move_fav_mode) {
|
||||
browser->callback(ArchiveBrowserEventFavMoveUp, browser->context);
|
||||
}
|
||||
} else if(event->key == InputKeyDown) {
|
||||
model->idx = (model->idx + 1) % num_elements;
|
||||
if(move_fav_mode) {
|
||||
browser->callback(
|
||||
ArchiveBrowserEventFavMoveDown, browser->context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -241,14 +271,20 @@ bool archive_view_input(InputEvent* event, void* context) {
|
||||
|
||||
if(event->type == InputTypeShort) {
|
||||
if(favorites) {
|
||||
browser->callback(ArchiveBrowserEventFileMenuRun, browser->context);
|
||||
if(move_fav_mode) {
|
||||
browser->callback(ArchiveBrowserEventSaveFavMove, browser->context);
|
||||
} else {
|
||||
browser->callback(ArchiveBrowserEventFileMenuRun, browser->context);
|
||||
}
|
||||
} else if(folder) {
|
||||
browser->callback(ArchiveBrowserEventEnterDir, browser->context);
|
||||
} else {
|
||||
browser->callback(ArchiveBrowserEventFileMenuOpen, browser->context);
|
||||
}
|
||||
} else if(event->type == InputTypeLong) {
|
||||
if(folder || favorites) {
|
||||
if(move_fav_mode) {
|
||||
browser->callback(ArchiveBrowserEventSaveFavMove, browser->context);
|
||||
} else if(folder || favorites) {
|
||||
browser->callback(ArchiveBrowserEventFileMenuOpen, browser->context);
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,14 +14,15 @@
|
||||
#define FRAME_HEIGHT 12
|
||||
#define MENU_ITEMS 4
|
||||
#define MAX_DEPTH 32
|
||||
#define MOVE_OFFSET 5
|
||||
|
||||
typedef enum {
|
||||
ArchiveTabFavorites,
|
||||
ArchiveTabLFRFID,
|
||||
ArchiveTabSubGhz,
|
||||
ArchiveTabLFRFID,
|
||||
ArchiveTabNFC,
|
||||
ArchiveTabIButton,
|
||||
ArchiveTabIrda,
|
||||
ArchiveTabIButton,
|
||||
ArchiveTabBrowser,
|
||||
ArchiveTabTotal,
|
||||
} ArchiveTabEnum;
|
||||
@ -31,16 +32,21 @@ typedef enum {
|
||||
ArchiveBrowserEventFileMenuClose,
|
||||
ArchiveBrowserEventFileMenuRun,
|
||||
ArchiveBrowserEventFileMenuPin,
|
||||
ArchiveBrowserEventFileMenuRename,
|
||||
ArchiveBrowserEventFileMenuAction,
|
||||
ArchiveBrowserEventFileMenuDelete,
|
||||
ArchiveBrowserEventEnterDir,
|
||||
ArchiveBrowserEventFavMoveUp,
|
||||
ArchiveBrowserEventFavMoveDown,
|
||||
ArchiveBrowserEventEnterFavMove,
|
||||
ArchiveBrowserEventExitFavMove,
|
||||
ArchiveBrowserEventSaveFavMove,
|
||||
ArchiveBrowserEventExit,
|
||||
} ArchiveBrowserEvent;
|
||||
|
||||
static const uint8_t file_menu_actions[MENU_ITEMS] = {
|
||||
[0] = ArchiveBrowserEventFileMenuRun,
|
||||
[1] = ArchiveBrowserEventFileMenuPin,
|
||||
[2] = ArchiveBrowserEventFileMenuRename,
|
||||
[2] = ArchiveBrowserEventFileMenuAction,
|
||||
[3] = ArchiveBrowserEventFileMenuDelete,
|
||||
};
|
||||
|
||||
@ -68,6 +74,7 @@ typedef struct {
|
||||
files_array_t files;
|
||||
|
||||
uint8_t menu_idx;
|
||||
bool move_fav;
|
||||
bool menu;
|
||||
|
||||
uint16_t idx;
|
||||
|
||||
@ -33,7 +33,10 @@ static void bt_battery_level_changed_callback(const void* _event, void* context)
|
||||
Bt* bt = context;
|
||||
const PowerEvent* event = _event;
|
||||
if(event->type == PowerEventTypeBatteryLevelChanged) {
|
||||
bt_update_battery_level(bt, event->data.battery_level);
|
||||
BtMessage message = {
|
||||
.type = BtMessageTypeUpdateBatteryLevel,
|
||||
.data.battery_level = event->data.battery_level};
|
||||
furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK);
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,9 +64,84 @@ Bt* bt_alloc() {
|
||||
PubSub* power_pubsub = power_get_pubsub(bt->power);
|
||||
subscribe_pubsub(power_pubsub, bt_battery_level_changed_callback, bt);
|
||||
|
||||
// RPC
|
||||
bt->rpc = furi_record_open("rpc");
|
||||
bt->rpc_sem = osSemaphoreNew(1, 0, NULL);
|
||||
|
||||
return bt;
|
||||
}
|
||||
|
||||
// Called from GAP thread from Serial service
|
||||
static void bt_on_data_received_callback(uint8_t* data, uint16_t size, void* context) {
|
||||
furi_assert(context);
|
||||
Bt* bt = context;
|
||||
|
||||
size_t bytes_processed = rpc_feed_bytes(bt->rpc_session, data, size, 1000);
|
||||
if(bytes_processed != size) {
|
||||
FURI_LOG_E(BT_SERVICE_TAG, "Only %d of %d bytes processed by RPC", bytes_processed, size);
|
||||
}
|
||||
}
|
||||
|
||||
// Called from GAP thread from Serial service
|
||||
static void bt_on_data_sent_callback(void* context) {
|
||||
furi_assert(context);
|
||||
Bt* bt = context;
|
||||
|
||||
osSemaphoreRelease(bt->rpc_sem);
|
||||
}
|
||||
|
||||
// Called from RPC thread
|
||||
static void bt_rpc_send_bytes_callback(void* context, uint8_t* bytes, size_t bytes_len) {
|
||||
furi_assert(context);
|
||||
Bt* bt = context;
|
||||
|
||||
size_t bytes_sent = 0;
|
||||
while(bytes_sent < bytes_len) {
|
||||
size_t bytes_remain = bytes_len - bytes_sent;
|
||||
if(bytes_remain > FURI_HAL_BT_PACKET_SIZE_MAX) {
|
||||
furi_hal_bt_tx(&bytes[bytes_sent], FURI_HAL_BT_PACKET_SIZE_MAX);
|
||||
bytes_sent += FURI_HAL_BT_PACKET_SIZE_MAX;
|
||||
} else {
|
||||
furi_hal_bt_tx(&bytes[bytes_sent], bytes_remain);
|
||||
bytes_sent += bytes_remain;
|
||||
}
|
||||
osSemaphoreAcquire(bt->rpc_sem, osWaitForever);
|
||||
}
|
||||
}
|
||||
|
||||
// Called from GAP thread
|
||||
static void bt_on_gap_event_callback(BleEvent event, void* context) {
|
||||
furi_assert(context);
|
||||
Bt* bt = context;
|
||||
|
||||
if(event.type == BleEventTypeConnected) {
|
||||
FURI_LOG_I(BT_SERVICE_TAG, "Open RPC connection");
|
||||
bt->rpc_session = rpc_open_session(bt->rpc);
|
||||
rpc_set_send_bytes_callback(bt->rpc_session, bt_rpc_send_bytes_callback, bt);
|
||||
furi_hal_bt_set_data_event_callbacks(
|
||||
bt_on_data_received_callback, bt_on_data_sent_callback, bt);
|
||||
// Update battery level
|
||||
PowerInfo info;
|
||||
power_get_info(bt->power, &info);
|
||||
BtMessage message = {
|
||||
.type = BtMessageTypeUpdateBatteryLevel, .data.battery_level = info.charge};
|
||||
furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK);
|
||||
} else if(event.type == BleEventTypeDisconnected) {
|
||||
FURI_LOG_I(BT_SERVICE_TAG, "Close RPC connection");
|
||||
if(bt->rpc_session) {
|
||||
rpc_close_session(bt->rpc_session);
|
||||
bt->rpc_session = NULL;
|
||||
}
|
||||
} else if(event.type == BleEventTypeStartAdvertising || event.type == BleEventTypeStopAdvertising) {
|
||||
BtMessage message = {.type = BtMessageTypeUpdateStatusbar};
|
||||
furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK);
|
||||
} else if(event.type == BleEventTypePinCodeShow) {
|
||||
BtMessage message = {
|
||||
.type = BtMessageTypePinCodeShow, .data.pin_code = event.data.pin_code};
|
||||
furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t bt_srv() {
|
||||
Bt* bt = bt_alloc();
|
||||
furi_record_create("bt", bt);
|
||||
@ -72,11 +150,10 @@ int32_t bt_srv() {
|
||||
FURI_LOG_E(BT_SERVICE_TAG, "Core2 startup failed");
|
||||
} else {
|
||||
view_port_enabled_set(bt->statusbar_view_port, true);
|
||||
if(furi_hal_bt_init_app()) {
|
||||
if(furi_hal_bt_init_app(bt_on_gap_event_callback, bt)) {
|
||||
FURI_LOG_I(BT_SERVICE_TAG, "BLE stack started");
|
||||
if(bt->bt_settings.enabled) {
|
||||
furi_hal_bt_start_advertising();
|
||||
FURI_LOG_I(BT_SERVICE_TAG, "Start advertising");
|
||||
}
|
||||
} else {
|
||||
FURI_LOG_E(BT_SERVICE_TAG, "BT App start failed");
|
||||
|
||||
@ -9,12 +9,6 @@ extern "C" {
|
||||
|
||||
typedef struct Bt Bt;
|
||||
|
||||
void bt_update_statusbar(Bt* bt);
|
||||
|
||||
void bt_update_battery_level(Bt* bt, uint8_t battery_level);
|
||||
|
||||
bool bt_pin_code_show(Bt* bt, uint32_t pin_code);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1,21 +0,0 @@
|
||||
#include "bt.h"
|
||||
#include "bt_i.h"
|
||||
|
||||
void bt_update_statusbar(Bt* bt) {
|
||||
furi_assert(bt);
|
||||
BtMessage message = {.type = BtMessageTypeUpdateStatusbar};
|
||||
furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK);
|
||||
}
|
||||
|
||||
void bt_update_battery_level(Bt* bt, uint8_t battery_level) {
|
||||
furi_assert(bt);
|
||||
BtMessage message = {
|
||||
.type = BtMessageTypeUpdateBatteryLevel, .data.battery_level = battery_level};
|
||||
furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK);
|
||||
}
|
||||
|
||||
bool bt_pin_code_show(Bt* bt, uint32_t pin_code) {
|
||||
furi_assert(bt);
|
||||
BtMessage message = {.type = BtMessageTypePinCodeShow, .data.pin_code = pin_code};
|
||||
return osMessageQueuePut(bt->message_queue, &message, 0, 0) == osOK;
|
||||
}
|
||||
@ -11,6 +11,7 @@
|
||||
|
||||
#include <dialogs/dialogs.h>
|
||||
#include <power/power_service/power.h>
|
||||
#include <applications/rpc/rpc.h>
|
||||
|
||||
#include "../bt_settings.h"
|
||||
|
||||
@ -38,4 +39,7 @@ struct Bt {
|
||||
DialogsApp* dialogs;
|
||||
DialogMessage* dialog_message;
|
||||
Power* power;
|
||||
Rpc* rpc;
|
||||
RpcSession* rpc_session;
|
||||
osSemaphoreId_t rpc_sem;
|
||||
};
|
||||
|
||||
@ -1,11 +1,16 @@
|
||||
/**
|
||||
* @file cli.h
|
||||
* Cli API
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <m-string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <m-string.h>
|
||||
|
||||
typedef enum {
|
||||
CliSymbolAsciiSOH = 0x01,
|
||||
CliSymbolAsciiETX = 0x03,
|
||||
@ -21,30 +26,29 @@ typedef enum {
|
||||
} CliSymbols;
|
||||
|
||||
typedef enum {
|
||||
CliCommandFlagDefault = 0, /** Default, loader lock is used */
|
||||
CliCommandFlagDefault = 0, /**< Default, loader lock is used */
|
||||
CliCommandFlagParallelSafe =
|
||||
(1 << 0), /** Safe to run in parallel with other apps, loader lock is not used */
|
||||
CliCommandFlagInsomniaSafe = (1 << 1), /** Safe to run with insomnia mode on */
|
||||
(1 << 0), /**< Safe to run in parallel with other apps, loader lock is not used */
|
||||
CliCommandFlagInsomniaSafe = (1 << 1), /**< Safe to run with insomnia mode on */
|
||||
} CliCommandFlag;
|
||||
|
||||
/* Cli type
|
||||
* Anonymous structure. Use cli_i.h if you need to go deeper.
|
||||
*/
|
||||
/** Cli type anonymous structure */
|
||||
typedef struct Cli Cli;
|
||||
|
||||
/* Cli callback function pointer.
|
||||
* Implement this interface and use add_cli_command
|
||||
* @param args - string with what was passed after command
|
||||
* @param context - pointer to whatever you gave us on cli_add_command
|
||||
/** Cli callback function pointer. Implement this interface and use
|
||||
* add_cli_command
|
||||
* @param args string with what was passed after command
|
||||
* @param context pointer to whatever you gave us on cli_add_command
|
||||
*/
|
||||
typedef void (*CliCallback)(Cli* cli, string_t args, void* context);
|
||||
|
||||
/* Add cli command
|
||||
* Registers you command callback
|
||||
* @param cli - pointer to cli instance
|
||||
* @param name - command name
|
||||
* @param callback - callback function
|
||||
* @param context - pointer to whatever we need to pass to callback
|
||||
/** Add cli command Registers you command callback
|
||||
*
|
||||
* @param cli pointer to cli instance
|
||||
* @param name command name
|
||||
* @param flags CliCommandFlag
|
||||
* @param callback callback function
|
||||
* @param context pointer to whatever we need to pass to callback
|
||||
*/
|
||||
void cli_add_command(
|
||||
Cli* cli,
|
||||
@ -53,51 +57,56 @@ void cli_add_command(
|
||||
CliCallback callback,
|
||||
void* context);
|
||||
|
||||
/* Print unified cmd usage tip
|
||||
* @param cmd - cmd name
|
||||
* @param usage - usage tip
|
||||
* @param arg - arg passed by user
|
||||
/** Print unified cmd usage tip
|
||||
*
|
||||
* @param cmd cmd name
|
||||
* @param usage usage tip
|
||||
* @param arg arg passed by user
|
||||
*/
|
||||
|
||||
void cli_print_usage(const char* cmd, const char* usage, const char* arg);
|
||||
|
||||
/* Delete cli command
|
||||
* @param cli - pointer to cli instance
|
||||
* @param name - command name
|
||||
/** Delete cli command
|
||||
*
|
||||
* @param cli pointer to cli instance
|
||||
* @param name command name
|
||||
*/
|
||||
void cli_delete_command(Cli* cli, const char* name);
|
||||
|
||||
/* Read from terminal
|
||||
* Do it only from inside of cli call.
|
||||
* @param cli - Cli instance
|
||||
* @param buffer - pointer to buffer
|
||||
* @param size - size of buffer in bytes
|
||||
* @return bytes written
|
||||
/** Read from terminal Do it only from inside of cli call.
|
||||
*
|
||||
* @param cli Cli instance
|
||||
* @param buffer pointer to buffer
|
||||
* @param size size of buffer in bytes
|
||||
*
|
||||
* @return bytes written
|
||||
*/
|
||||
size_t cli_read(Cli* cli, uint8_t* buffer, size_t size);
|
||||
|
||||
/* Not blocking check for interrupt command received
|
||||
* @param cli - Cli instance
|
||||
/** Not blocking check for interrupt command received
|
||||
*
|
||||
* @param cli Cli instance
|
||||
*
|
||||
* @return true if received
|
||||
*/
|
||||
bool cli_cmd_interrupt_received(Cli* cli);
|
||||
|
||||
/* Write to terminal
|
||||
* Do it only from inside of cli call.
|
||||
* @param cli - Cli instance
|
||||
* @param buffer - pointer to buffer
|
||||
* @param size - size of buffer in bytes
|
||||
* @return bytes written
|
||||
/** Write to terminal Do it only from inside of cli call.
|
||||
*
|
||||
* @param cli Cli instance
|
||||
* @param buffer pointer to buffer
|
||||
* @param size size of buffer in bytes
|
||||
*/
|
||||
void cli_write(Cli* cli, const uint8_t* buffer, size_t size);
|
||||
|
||||
/* Read character
|
||||
* @param cli - Cli instance
|
||||
* @return char
|
||||
/** Read character
|
||||
*
|
||||
* @param cli Cli instance
|
||||
*
|
||||
* @return char
|
||||
*/
|
||||
char cli_getc(Cli* cli);
|
||||
|
||||
/* New line
|
||||
* Send new ine sequence
|
||||
/** New line Send new ine sequence
|
||||
*/
|
||||
void cli_nl();
|
||||
|
||||
|
||||
@ -7,14 +7,47 @@
|
||||
#include <notification/notification-messages.h>
|
||||
#include <shci.h>
|
||||
|
||||
#define ENCLAVE_SIGNATURE_KEY_SLOT 1
|
||||
#define ENCLAVE_SIGNATURE_KEY_SLOTS 10
|
||||
#define ENCLAVE_SIGNATURE_SIZE 16
|
||||
static const uint8_t enclave_signature_iv[16] =
|
||||
{0x32, 0xe6, 0xa7, 0x85, 0x20, 0xae, 0x0b, 0xf0, 0x00, 0xb6, 0x30, 0x9b, 0xd5, 0x42, 0x9e, 0xa6};
|
||||
static const uint8_t enclave_signature_input[ENCLAVE_SIGNATURE_SIZE] =
|
||||
{0xdc, 0x76, 0x15, 0x1e, 0x69, 0xe8, 0xdc, 0xd3, 0x4a, 0x71, 0x0b, 0x42, 0x71, 0xe0, 0xa9, 0x78};
|
||||
static const uint8_t enclave_signature_expected[ENCLAVE_SIGNATURE_SIZE] =
|
||||
{0x1b, 0xb3, 0xcf, 0x16, 0xc, 0x27, 0xf7, 0xf2, 0xf0, 0x7e, 0x5f, 0xbe, 0xfe, 0x89, 0x52, 0xe1};
|
||||
|
||||
static const uint8_t enclave_signature_iv[ENCLAVE_SIGNATURE_KEY_SLOTS][16] = {
|
||||
{0xac, 0x5d, 0x68, 0xb8, 0x79, 0x74, 0xfc, 0x7f, 0x45, 0x02, 0x82, 0xf1, 0x48, 0x7e, 0x75, 0x8a},
|
||||
{0x38, 0xe6, 0x6a, 0x90, 0x5e, 0x5b, 0x8a, 0xa6, 0x70, 0x30, 0x04, 0x72, 0xc2, 0x42, 0xea, 0xaf},
|
||||
{0x73, 0xd5, 0x8e, 0xfb, 0x0f, 0x4b, 0xa9, 0x79, 0x0f, 0xde, 0x0e, 0x53, 0x44, 0x7d, 0xaa, 0xfd},
|
||||
{0x3c, 0x9a, 0xf4, 0x43, 0x2b, 0xfe, 0xea, 0xae, 0x8c, 0xc6, 0xd1, 0x60, 0xd2, 0x96, 0x64, 0xa9},
|
||||
{0x10, 0xac, 0x7b, 0x63, 0x03, 0x7f, 0x43, 0x18, 0xec, 0x9d, 0x9c, 0xc4, 0x01, 0xdc, 0x35, 0xa7},
|
||||
{0x26, 0x21, 0x64, 0xe6, 0xd0, 0xf2, 0x47, 0x49, 0xdc, 0x36, 0xcd, 0x68, 0x0c, 0x91, 0x03, 0x44},
|
||||
{0x7a, 0xbd, 0xce, 0x9c, 0x24, 0x7a, 0x2a, 0xb1, 0x3c, 0x4f, 0x5a, 0x7d, 0x80, 0x3e, 0xfc, 0x0d},
|
||||
{0xcd, 0xdd, 0xd3, 0x02, 0x85, 0x65, 0x43, 0x83, 0xf9, 0xac, 0x75, 0x2f, 0x21, 0xef, 0x28, 0x6b},
|
||||
{0xab, 0x73, 0x70, 0xe8, 0xe2, 0x56, 0x0f, 0x58, 0xab, 0x29, 0xa5, 0xb1, 0x13, 0x47, 0x5e, 0xe8},
|
||||
{0x4f, 0x3c, 0x43, 0x77, 0xde, 0xed, 0x79, 0xa1, 0x8d, 0x4c, 0x1f, 0xfd, 0xdb, 0x96, 0x87, 0x2e},
|
||||
};
|
||||
|
||||
static const uint8_t enclave_signature_input[ENCLAVE_SIGNATURE_KEY_SLOTS][ENCLAVE_SIGNATURE_SIZE] = {
|
||||
{0x9f, 0x5c, 0xb1, 0x43, 0x17, 0x53, 0x18, 0x8c, 0x66, 0x3d, 0x39, 0x45, 0x90, 0x13, 0xa9, 0xde},
|
||||
{0xc5, 0x98, 0xe9, 0x17, 0xb8, 0x97, 0x9e, 0x03, 0x33, 0x14, 0x13, 0x8f, 0xce, 0x74, 0x0d, 0x54},
|
||||
{0x34, 0xba, 0x99, 0x59, 0x9f, 0x70, 0x67, 0xe9, 0x09, 0xee, 0x64, 0x0e, 0xb3, 0xba, 0xfb, 0x75},
|
||||
{0xdc, 0xfa, 0x6c, 0x9a, 0x6f, 0x0a, 0x3e, 0xdc, 0x42, 0xf6, 0xae, 0x0d, 0x3c, 0xf7, 0x83, 0xaf},
|
||||
{0xea, 0x2d, 0xe3, 0x1f, 0x02, 0x99, 0x1a, 0x7e, 0x6d, 0x93, 0x4c, 0xb5, 0x42, 0xf0, 0x7a, 0x9b},
|
||||
{0x53, 0x5e, 0x04, 0xa2, 0x49, 0xa0, 0x73, 0x49, 0x56, 0xb0, 0x88, 0x8c, 0x12, 0xa0, 0xe4, 0x18},
|
||||
{0x7d, 0xa7, 0xc5, 0x21, 0x7f, 0x12, 0x95, 0xdd, 0x4d, 0x77, 0x01, 0xfa, 0x71, 0x88, 0x2b, 0x7f},
|
||||
{0xdc, 0x9b, 0xc5, 0xa7, 0x6b, 0x84, 0x5c, 0x37, 0x7c, 0xec, 0x05, 0xa1, 0x9f, 0x91, 0x17, 0x3b},
|
||||
{0xea, 0xcf, 0xd9, 0x9b, 0x86, 0xcd, 0x2b, 0x43, 0x54, 0x45, 0x82, 0xc6, 0xfe, 0x73, 0x1a, 0x1a},
|
||||
{0x77, 0xb8, 0x1b, 0x90, 0xb4, 0xb7, 0x32, 0x76, 0x8f, 0x8a, 0x57, 0x06, 0xc7, 0xdd, 0x08, 0x90},
|
||||
};
|
||||
|
||||
static const uint8_t enclave_signature_expected[ENCLAVE_SIGNATURE_KEY_SLOTS][ENCLAVE_SIGNATURE_SIZE] = {
|
||||
{0xe9, 0x9a, 0xce, 0xe9, 0x4d, 0xe1, 0x7f, 0x55, 0xcb, 0x8a, 0xbf, 0xf2, 0x4d, 0x98, 0x27, 0x67},
|
||||
{0x34, 0x27, 0xa7, 0xea, 0xa8, 0x98, 0x66, 0x9b, 0xed, 0x43, 0xd3, 0x93, 0xb5, 0xa2, 0x87, 0x8e},
|
||||
{0x6c, 0xf3, 0x01, 0x78, 0x53, 0x1b, 0x11, 0x32, 0xf0, 0x27, 0x2f, 0xe3, 0x7d, 0xa6, 0xe2, 0xfd},
|
||||
{0xdf, 0x7f, 0x37, 0x65, 0x2f, 0xdb, 0x7c, 0xcf, 0x5b, 0xb6, 0xe4, 0x9c, 0x63, 0xc5, 0x0f, 0xe0},
|
||||
{0x9b, 0x5c, 0xee, 0x44, 0x0e, 0xd1, 0xcb, 0x5f, 0x28, 0x9f, 0x12, 0x17, 0x59, 0x64, 0x40, 0xbb},
|
||||
{0x94, 0xc2, 0x09, 0x98, 0x62, 0xa7, 0x2b, 0x93, 0xed, 0x36, 0x1f, 0x10, 0xbc, 0x26, 0xbd, 0x41},
|
||||
{0x4d, 0xb2, 0x2b, 0xc5, 0x96, 0x47, 0x61, 0xf4, 0x16, 0xe0, 0x81, 0xc3, 0x8e, 0xb9, 0x9c, 0x9b},
|
||||
{0xc3, 0x6b, 0x83, 0x55, 0x90, 0x38, 0x0f, 0xea, 0xd1, 0x65, 0xbf, 0x32, 0x4f, 0x8e, 0x62, 0x5b},
|
||||
{0x8d, 0x5e, 0x27, 0xbc, 0x14, 0x4f, 0x08, 0xa8, 0x2b, 0x14, 0x89, 0x5e, 0xdf, 0x77, 0x04, 0x31},
|
||||
{0xc9, 0xf7, 0x03, 0xf1, 0x6c, 0x65, 0xad, 0x49, 0x74, 0xbe, 0x00, 0x54, 0xfd, 0xa6, 0x9c, 0x32},
|
||||
};
|
||||
|
||||
/*
|
||||
* Device Info Command
|
||||
@ -99,15 +132,23 @@ void cli_command_device_info(Cli* cli, string_t args, void* context) {
|
||||
|
||||
// Signature verification
|
||||
uint8_t buffer[ENCLAVE_SIGNATURE_SIZE];
|
||||
bool enclave_valid = false;
|
||||
if(furi_hal_crypto_store_load_key(ENCLAVE_SIGNATURE_KEY_SLOT, enclave_signature_iv)) {
|
||||
if(furi_hal_crypto_encrypt(enclave_signature_input, buffer, ENCLAVE_SIGNATURE_SIZE)) {
|
||||
enclave_valid =
|
||||
memcmp(buffer, enclave_signature_expected, ENCLAVE_SIGNATURE_SIZE) == 0;
|
||||
size_t enclave_valid_keys = 0;
|
||||
for(size_t key_slot = 0; key_slot < ENCLAVE_SIGNATURE_KEY_SLOTS; key_slot++) {
|
||||
if(furi_hal_crypto_store_load_key(key_slot + 1, enclave_signature_iv[key_slot])) {
|
||||
if(furi_hal_crypto_encrypt(
|
||||
enclave_signature_input[key_slot], buffer, ENCLAVE_SIGNATURE_SIZE)) {
|
||||
enclave_valid_keys += memcmp(
|
||||
buffer,
|
||||
enclave_signature_expected[key_slot],
|
||||
ENCLAVE_SIGNATURE_SIZE) == 0;
|
||||
}
|
||||
furi_hal_crypto_store_unload_key(key_slot + 1);
|
||||
}
|
||||
furi_hal_crypto_store_unload_key(ENCLAVE_SIGNATURE_KEY_SLOT);
|
||||
}
|
||||
printf("enclave_valid : %s\r\n", enclave_valid ? "true" : "false");
|
||||
printf("enclave_valid_keys : %d\r\n", enclave_valid_keys);
|
||||
printf(
|
||||
"enclave_valid : %s\r\n",
|
||||
(enclave_valid_keys == ENCLAVE_SIGNATURE_KEY_SLOTS) ? "true" : "false");
|
||||
} else {
|
||||
printf("radio_alive : false\r\n");
|
||||
}
|
||||
|
||||
364
applications/debug_tools/bad_usb.c
Normal file
364
applications/debug_tools/bad_usb.c
Normal file
@ -0,0 +1,364 @@
|
||||
#include <furi.h>
|
||||
#include <furi-hal.h>
|
||||
#include <gui/gui.h>
|
||||
#include <input/input.h>
|
||||
#include <lib/toolbox/args.h>
|
||||
#include <furi-hal-usb-hid.h>
|
||||
#include <storage/storage.h>
|
||||
|
||||
typedef enum {
|
||||
EventTypeInput,
|
||||
EventTypeWorkerState,
|
||||
} EventType;
|
||||
|
||||
typedef enum {
|
||||
WorkerStateDone,
|
||||
WorkerStateNoFile,
|
||||
WorkerStateScriptError,
|
||||
WorkerStateDisconnected,
|
||||
} WorkerState;
|
||||
|
||||
typedef enum {
|
||||
AppStateWait,
|
||||
AppStateRunning,
|
||||
AppStateError,
|
||||
AppStateExit,
|
||||
} AppState;
|
||||
|
||||
typedef enum {
|
||||
WorkerCmdStart = (1 << 0),
|
||||
WorkerCmdStop = (1 << 1),
|
||||
} WorkerCommandFlags;
|
||||
|
||||
// Event message from worker
|
||||
typedef struct {
|
||||
WorkerState state;
|
||||
uint16_t line;
|
||||
} BadUsbWorkerState;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
InputEvent input;
|
||||
BadUsbWorkerState worker;
|
||||
};
|
||||
EventType type;
|
||||
} BadUsbEvent;
|
||||
|
||||
typedef struct {
|
||||
uint32_t defdelay;
|
||||
char msg_text[32];
|
||||
osThreadAttr_t thread_attr;
|
||||
osThreadId_t thread;
|
||||
osMessageQueueId_t event_queue;
|
||||
} BadUsbParams;
|
||||
|
||||
typedef struct {
|
||||
char* name;
|
||||
uint16_t keycode;
|
||||
} DuckyKey;
|
||||
|
||||
static const DuckyKey ducky_keys[] = {
|
||||
{"CTRL", KEY_MOD_LEFT_CTRL},
|
||||
{"CONTROL", KEY_MOD_LEFT_CTRL},
|
||||
{"SHIFT", KEY_MOD_LEFT_SHIFT},
|
||||
{"ALT", KEY_MOD_LEFT_ALT},
|
||||
{"GUI", KEY_MOD_LEFT_GUI},
|
||||
{"WINDOWS", KEY_MOD_LEFT_GUI},
|
||||
|
||||
{"DOWNARROW", KEY_DOWN_ARROW},
|
||||
{"DOWN", KEY_DOWN_ARROW},
|
||||
{"LEFTARROW", KEY_LEFT_ARROW},
|
||||
{"LEFT", KEY_LEFT_ARROW},
|
||||
{"RIGHTARROW", KEY_RIGHT_ARROW},
|
||||
{"RIGHT", KEY_RIGHT_ARROW},
|
||||
{"UPARROW", KEY_UP_ARROW},
|
||||
{"UP", KEY_UP_ARROW},
|
||||
|
||||
{"ENTER", KEY_ENTER},
|
||||
{"BREAK", KEY_PAUSE},
|
||||
{"PAUSE", KEY_PAUSE},
|
||||
{"CAPSLOCK", KEY_CAPS_LOCK},
|
||||
{"DELETE", KEY_DELETE},
|
||||
{"BACKSPACE", KEY_BACKSPACE},
|
||||
{"END", KEY_END},
|
||||
{"ESC", KEY_ESC},
|
||||
{"ESCAPE", KEY_ESC},
|
||||
{"HOME", KEY_HOME},
|
||||
{"INSERT", KEY_INSERT},
|
||||
{"NUMLOCK", KEY_NUM_LOCK},
|
||||
{"PAGEUP", KEY_PAGE_UP},
|
||||
{"PAGEDOWN", KEY_PAGE_DOWN},
|
||||
{"PRINTSCREEN", KEY_PRINT},
|
||||
{"SCROLLOCK", KEY_SCROLL_LOCK},
|
||||
{"SPACE", KEY_SPACE},
|
||||
{"TAB", KEY_TAB},
|
||||
{"MENU", KEY_APPLICATION},
|
||||
{"APP", KEY_APPLICATION},
|
||||
};
|
||||
|
||||
static const char ducky_cmd_comment[] = {"REM"};
|
||||
static const char ducky_cmd_delay[] = {"DELAY"};
|
||||
static const char ducky_cmd_string[] = {"STRING"};
|
||||
static const char ducky_cmd_defdelay_1[] = {"DEFAULT_DELAY"};
|
||||
static const char ducky_cmd_defdelay_2[] = {"DEFAULTDELAY"};
|
||||
|
||||
static bool ducky_get_delay_val(char* param, uint32_t* val) {
|
||||
uint32_t delay_val = 0;
|
||||
if(sscanf(param, "%lu", &delay_val) == 1) {
|
||||
*val = delay_val;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool ducky_string(char* param) {
|
||||
uint32_t i = 0;
|
||||
while(param[i] != '\0') {
|
||||
furi_hal_hid_kb_press(HID_ASCII_TO_KEY(param[i]));
|
||||
furi_hal_hid_kb_release(HID_ASCII_TO_KEY(param[i]));
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint16_t ducky_get_keycode(char* param, bool accept_chars) {
|
||||
for(uint8_t i = 0; i < (sizeof(ducky_keys) / sizeof(ducky_keys[0])); i++) {
|
||||
if(strncmp(param, ducky_keys[i].name, strlen(ducky_keys[i].name)) == 0)
|
||||
return ducky_keys[i].keycode;
|
||||
}
|
||||
if((accept_chars) && (strlen(param) > 0)) {
|
||||
return (HID_ASCII_TO_KEY(param[0]) & 0xFF);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool ducky_parse_line(string_t line, BadUsbParams* app) {
|
||||
//uint32_t line_len = string_size(line);
|
||||
char* line_t = (char*)string_get_cstr(line);
|
||||
bool state = false;
|
||||
|
||||
// General commands
|
||||
if(strncmp(line_t, ducky_cmd_comment, strlen(ducky_cmd_comment)) == 0) {
|
||||
// REM - comment line
|
||||
return true;
|
||||
} else if(strncmp(line_t, ducky_cmd_delay, strlen(ducky_cmd_delay)) == 0) {
|
||||
// DELAY
|
||||
line_t = &line_t[args_get_first_word_length(line) + 1];
|
||||
uint32_t delay_val = 0;
|
||||
state = ducky_get_delay_val(line_t, &delay_val);
|
||||
if((state) && (delay_val > 0)) {
|
||||
// Using ThreadFlagsWait as delay function allows exiting task on WorkerCmdStop command
|
||||
if(osThreadFlagsWait(WorkerCmdStop, osFlagsWaitAny | osFlagsNoClear, delay_val) ==
|
||||
WorkerCmdStop)
|
||||
return true;
|
||||
}
|
||||
return state;
|
||||
} else if(
|
||||
(strncmp(line_t, ducky_cmd_defdelay_1, strlen(ducky_cmd_defdelay_1)) == 0) ||
|
||||
(strncmp(line_t, ducky_cmd_defdelay_2, strlen(ducky_cmd_defdelay_2)) == 0)) {
|
||||
// DEFAULT_DELAY
|
||||
line_t = &line_t[args_get_first_word_length(line) + 1];
|
||||
return ducky_get_delay_val(line_t, &app->defdelay);
|
||||
} else if(strncmp(line_t, ducky_cmd_string, strlen(ducky_cmd_string)) == 0) {
|
||||
// STRING
|
||||
if(app->defdelay > 0) {
|
||||
if(osThreadFlagsWait(WorkerCmdStop, osFlagsWaitAny | osFlagsNoClear, app->defdelay) ==
|
||||
WorkerCmdStop)
|
||||
return true;
|
||||
}
|
||||
line_t = &line_t[args_get_first_word_length(line) + 1];
|
||||
return ducky_string(line_t);
|
||||
} else {
|
||||
// Special keys + modifiers
|
||||
uint16_t key = ducky_get_keycode(line_t, false);
|
||||
if(key == KEY_NONE) return false;
|
||||
if((key & 0xFF00) != 0) {
|
||||
// It's a modifier key
|
||||
line_t = &line_t[args_get_first_word_length(line) + 1];
|
||||
key |= ducky_get_keycode(line_t, true);
|
||||
}
|
||||
if(app->defdelay > 0) {
|
||||
if(osThreadFlagsWait(WorkerCmdStop, osFlagsWaitAny | osFlagsNoClear, app->defdelay) ==
|
||||
WorkerCmdStop)
|
||||
return true;
|
||||
}
|
||||
furi_hal_hid_kb_press(key);
|
||||
furi_hal_hid_kb_release(key);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void badusb_worker(void* context) {
|
||||
BadUsbParams* app = context;
|
||||
FURI_LOG_I("BadUSB worker", "Init");
|
||||
File* script_file = storage_file_alloc(furi_record_open("storage"));
|
||||
BadUsbEvent evt;
|
||||
string_t line;
|
||||
uint32_t line_cnt = 0;
|
||||
string_init(line);
|
||||
if(storage_file_open(script_file, "/ext/badusb.txt", FSAM_READ, FSOM_OPEN_EXISTING)) {
|
||||
char buffer[16];
|
||||
uint16_t ret;
|
||||
uint32_t flags =
|
||||
osThreadFlagsWait(WorkerCmdStart | WorkerCmdStop, osFlagsWaitAny, osWaitForever);
|
||||
if(flags & WorkerCmdStart) {
|
||||
FURI_LOG_I("BadUSB worker", "Start");
|
||||
do {
|
||||
ret = storage_file_read(script_file, buffer, 16);
|
||||
for(uint16_t i = 0; i < ret; i++) {
|
||||
if(buffer[i] == '\n' && string_size(line) > 0) {
|
||||
line_cnt++;
|
||||
if(ducky_parse_line(line, app) == false) {
|
||||
ret = 0;
|
||||
FURI_LOG_E("BadUSB worker", "Unknown command at line %lu", line_cnt);
|
||||
evt.type = EventTypeWorkerState;
|
||||
evt.worker.state = WorkerStateScriptError;
|
||||
evt.worker.line = line_cnt;
|
||||
osMessageQueuePut(app->event_queue, &evt, 0, osWaitForever);
|
||||
break;
|
||||
}
|
||||
flags = osThreadFlagsGet();
|
||||
if(flags == WorkerCmdStop) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
string_clean(line);
|
||||
} else {
|
||||
string_push_back(line, buffer[i]);
|
||||
}
|
||||
}
|
||||
} while(ret > 0);
|
||||
}
|
||||
} else {
|
||||
FURI_LOG_E("BadUSB worker", "Script file open error");
|
||||
evt.type = EventTypeWorkerState;
|
||||
evt.worker.state = WorkerStateNoFile;
|
||||
osMessageQueuePut(app->event_queue, &evt, 0, osWaitForever);
|
||||
}
|
||||
string_clean(line);
|
||||
string_clear(line);
|
||||
|
||||
furi_hal_hid_kb_release_all();
|
||||
storage_file_close(script_file);
|
||||
storage_file_free(script_file);
|
||||
|
||||
FURI_LOG_I("BadUSB worker", "End");
|
||||
evt.type = EventTypeWorkerState;
|
||||
evt.worker.state = WorkerStateDone;
|
||||
osMessageQueuePut(app->event_queue, &evt, 0, osWaitForever);
|
||||
|
||||
osThreadExit();
|
||||
}
|
||||
|
||||
static void bad_usb_render_callback(Canvas* canvas, void* ctx) {
|
||||
BadUsbParams* app = (BadUsbParams*)ctx;
|
||||
|
||||
canvas_clear(canvas);
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str(canvas, 0, 10, "Bad USB test");
|
||||
|
||||
if(strlen(app->msg_text) > 0) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str(canvas, 0, 62, app->msg_text);
|
||||
}
|
||||
}
|
||||
|
||||
static void bad_usb_input_callback(InputEvent* input_event, void* ctx) {
|
||||
osMessageQueueId_t event_queue = ctx;
|
||||
|
||||
BadUsbEvent event;
|
||||
event.type = EventTypeInput;
|
||||
event.input = *input_event;
|
||||
osMessageQueuePut(event_queue, &event, 0, osWaitForever);
|
||||
}
|
||||
|
||||
int32_t bad_usb_app(void* p) {
|
||||
BadUsbParams* app = furi_alloc(sizeof(BadUsbParams));
|
||||
app->event_queue = osMessageQueueNew(8, sizeof(BadUsbEvent), NULL);
|
||||
furi_check(app->event_queue);
|
||||
ViewPort* view_port = view_port_alloc();
|
||||
|
||||
UsbMode usb_mode_prev = furi_hal_usb_get_config();
|
||||
furi_hal_usb_set_config(UsbModeHid);
|
||||
|
||||
view_port_draw_callback_set(view_port, bad_usb_render_callback, app);
|
||||
view_port_input_callback_set(view_port, bad_usb_input_callback, app->event_queue);
|
||||
|
||||
// Open GUI and register view_port
|
||||
Gui* gui = furi_record_open("gui");
|
||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||
|
||||
app->thread = NULL;
|
||||
app->thread_attr.name = "bad_usb_worker";
|
||||
app->thread_attr.stack_size = 2048;
|
||||
app->thread = osThreadNew(badusb_worker, app, &app->thread_attr);
|
||||
bool worker_running = true;
|
||||
AppState app_state = AppStateWait;
|
||||
snprintf(app->msg_text, sizeof(app->msg_text), "Press [OK] to start");
|
||||
view_port_update(view_port);
|
||||
|
||||
BadUsbEvent event;
|
||||
while(1) {
|
||||
osStatus_t event_status = osMessageQueueGet(app->event_queue, &event, NULL, osWaitForever);
|
||||
|
||||
if(event_status == osOK) {
|
||||
if(event.type == EventTypeInput) {
|
||||
if(event.input.type == InputTypeShort && event.input.key == InputKeyBack) {
|
||||
if(worker_running) {
|
||||
osThreadFlagsSet(app->thread, WorkerCmdStop);
|
||||
app_state = AppStateExit;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
if(event.input.type == InputTypeShort && event.input.key == InputKeyOk) {
|
||||
if(worker_running) {
|
||||
app_state = AppStateRunning;
|
||||
osThreadFlagsSet(app->thread, WorkerCmdStart);
|
||||
snprintf(app->msg_text, sizeof(app->msg_text), "Running...");
|
||||
view_port_update(view_port);
|
||||
}
|
||||
}
|
||||
} else if(event.type == EventTypeWorkerState) {
|
||||
FURI_LOG_I("BadUSB app", "ev: %d", event.worker.state);
|
||||
if(event.worker.state == WorkerStateDone) {
|
||||
worker_running = false;
|
||||
if(app_state == AppStateExit)
|
||||
break;
|
||||
else if(app_state == AppStateRunning) {
|
||||
//done
|
||||
app->thread = osThreadNew(badusb_worker, app, &app->thread_attr);
|
||||
worker_running = true;
|
||||
app_state = AppStateWait;
|
||||
snprintf(app->msg_text, sizeof(app->msg_text), "Press [OK] to start");
|
||||
view_port_update(view_port);
|
||||
}
|
||||
} else if(event.worker.state == WorkerStateNoFile) {
|
||||
app_state = AppStateError;
|
||||
snprintf(app->msg_text, sizeof(app->msg_text), "File not found!");
|
||||
view_port_update(view_port);
|
||||
} else if(event.worker.state == WorkerStateScriptError) {
|
||||
app_state = AppStateError;
|
||||
snprintf(
|
||||
app->msg_text,
|
||||
sizeof(app->msg_text),
|
||||
"Error at line %u",
|
||||
event.worker.line);
|
||||
view_port_update(view_port);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
furi_hal_usb_set_config(usb_mode_prev);
|
||||
|
||||
// remove & free all stuff created by app
|
||||
gui_remove_view_port(gui, view_port);
|
||||
view_port_free(view_port);
|
||||
|
||||
osMessageQueueDelete(app->event_queue);
|
||||
free(app);
|
||||
|
||||
return 0;
|
||||
}
|
||||
121
applications/debug_tools/usb_mouse.c
Normal file
121
applications/debug_tools/usb_mouse.c
Normal file
@ -0,0 +1,121 @@
|
||||
#include <furi.h>
|
||||
#include <furi-hal.h>
|
||||
#include <gui/gui.h>
|
||||
#include <input/input.h>
|
||||
|
||||
#define MOUSE_MOVE_SHORT 5
|
||||
#define MOUSE_MOVE_LONG 20
|
||||
|
||||
typedef enum {
|
||||
EventTypeInput,
|
||||
} EventType;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
InputEvent input;
|
||||
};
|
||||
EventType type;
|
||||
} UsbMouseEvent;
|
||||
|
||||
static void usb_mouse_render_callback(Canvas* canvas, void* ctx) {
|
||||
canvas_clear(canvas);
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str(canvas, 0, 10, "USB Mouse demo");
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str(canvas, 0, 63, "Hold [back] to exit");
|
||||
}
|
||||
|
||||
static void usb_mouse_input_callback(InputEvent* input_event, void* ctx) {
|
||||
osMessageQueueId_t event_queue = ctx;
|
||||
|
||||
UsbMouseEvent event;
|
||||
event.type = EventTypeInput;
|
||||
event.input = *input_event;
|
||||
osMessageQueuePut(event_queue, &event, 0, osWaitForever);
|
||||
}
|
||||
|
||||
int32_t usb_mouse_app(void* p) {
|
||||
osMessageQueueId_t event_queue = osMessageQueueNew(8, sizeof(UsbMouseEvent), NULL);
|
||||
furi_check(event_queue);
|
||||
ViewPort* view_port = view_port_alloc();
|
||||
|
||||
UsbMode usb_mode_prev = furi_hal_usb_get_config();
|
||||
furi_hal_usb_set_config(UsbModeHid);
|
||||
|
||||
view_port_draw_callback_set(view_port, usb_mouse_render_callback, NULL);
|
||||
view_port_input_callback_set(view_port, usb_mouse_input_callback, event_queue);
|
||||
|
||||
// Open GUI and register view_port
|
||||
Gui* gui = furi_record_open("gui");
|
||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||
|
||||
UsbMouseEvent event;
|
||||
while(1) {
|
||||
osStatus_t event_status = osMessageQueueGet(event_queue, &event, NULL, osWaitForever);
|
||||
|
||||
if(event_status == osOK) {
|
||||
if(event.type == EventTypeInput) {
|
||||
if(event.input.type == InputTypeLong && event.input.key == InputKeyBack) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(event.input.type == InputTypeShort && event.input.key == InputKeyBack) {
|
||||
furi_hal_hid_mouse_press(HID_MOUSE_BTN_RIGHT);
|
||||
furi_hal_hid_mouse_release(HID_MOUSE_BTN_RIGHT);
|
||||
}
|
||||
|
||||
if(event.input.key == InputKeyOk) {
|
||||
if(event.input.type == InputTypePress) {
|
||||
furi_hal_hid_mouse_press(HID_MOUSE_BTN_LEFT);
|
||||
} else if(event.input.type == InputTypeRelease) {
|
||||
furi_hal_hid_mouse_release(HID_MOUSE_BTN_LEFT);
|
||||
}
|
||||
}
|
||||
|
||||
if(event.input.key == InputKeyRight) {
|
||||
if(event.input.type == InputTypePress) {
|
||||
furi_hal_hid_mouse_move(MOUSE_MOVE_SHORT, 0);
|
||||
} else if(event.input.type == InputTypeRepeat) {
|
||||
furi_hal_hid_mouse_move(MOUSE_MOVE_LONG, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if(event.input.key == InputKeyLeft) {
|
||||
if(event.input.type == InputTypePress) {
|
||||
furi_hal_hid_mouse_move(-MOUSE_MOVE_SHORT, 0);
|
||||
} else if(event.input.type == InputTypeRepeat) {
|
||||
furi_hal_hid_mouse_move(-MOUSE_MOVE_LONG, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if(event.input.key == InputKeyDown) {
|
||||
if(event.input.type == InputTypePress) {
|
||||
furi_hal_hid_mouse_move(0, MOUSE_MOVE_SHORT);
|
||||
} else if(event.input.type == InputTypeRepeat) {
|
||||
furi_hal_hid_mouse_move(0, MOUSE_MOVE_LONG);
|
||||
}
|
||||
}
|
||||
|
||||
if(event.input.key == InputKeyUp) {
|
||||
if(event.input.type == InputTypePress) {
|
||||
furi_hal_hid_mouse_move(0, -MOUSE_MOVE_SHORT);
|
||||
} else if(event.input.type == InputTypeRepeat) {
|
||||
furi_hal_hid_mouse_move(0, -MOUSE_MOVE_LONG);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
view_port_update(view_port);
|
||||
}
|
||||
|
||||
furi_hal_usb_set_config(usb_mode_prev);
|
||||
|
||||
// remove & free all stuff created by app
|
||||
gui_remove_view_port(gui, view_port);
|
||||
view_port_free(view_port);
|
||||
osMessageQueueDelete(event_queue);
|
||||
|
||||
return 0;
|
||||
}
|
||||
103
applications/debug_tools/usb_test.c
Normal file
103
applications/debug_tools/usb_test.c
Normal file
@ -0,0 +1,103 @@
|
||||
#include <furi.h>
|
||||
#include <furi-hal.h>
|
||||
#include <gui/view.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/modules/submenu.h>
|
||||
#include <gui/gui.h>
|
||||
#include <cmsis_os.h>
|
||||
|
||||
typedef struct {
|
||||
Gui* gui;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
Submenu* submenu;
|
||||
} UsbTestApp;
|
||||
|
||||
typedef enum {
|
||||
UsbTestSubmenuIndexEnable,
|
||||
UsbTestSubmenuIndexDisable,
|
||||
UsbTestSubmenuIndexVcpSingle,
|
||||
UsbTestSubmenuIndexVcpDual,
|
||||
UsbTestSubmenuIndexHid,
|
||||
UsbTestSubmenuIndexHidU2F,
|
||||
} SubmenuIndex;
|
||||
|
||||
void usb_test_submenu_callback(void* context, uint32_t index) {
|
||||
furi_assert(context);
|
||||
//UsbTestApp* app = context;
|
||||
if(index == UsbTestSubmenuIndexEnable) {
|
||||
furi_hal_usb_enable();
|
||||
} else if(index == UsbTestSubmenuIndexDisable) {
|
||||
furi_hal_usb_disable();
|
||||
} else if(index == UsbTestSubmenuIndexVcpSingle) {
|
||||
furi_hal_usb_set_config(UsbModeVcpSingle);
|
||||
} else if(index == UsbTestSubmenuIndexVcpDual) {
|
||||
furi_hal_usb_set_config(UsbModeVcpDual);
|
||||
} else if(index == UsbTestSubmenuIndexHid) {
|
||||
furi_hal_usb_set_config(UsbModeHid);
|
||||
} else if(index == UsbTestSubmenuIndexHidU2F) {
|
||||
//furi_hal_usb_set_config(UsbModeU2F);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t usb_test_exit(void* context) {
|
||||
return VIEW_NONE;
|
||||
}
|
||||
|
||||
UsbTestApp* usb_test_app_alloc() {
|
||||
UsbTestApp* app = furi_alloc(sizeof(UsbTestApp));
|
||||
|
||||
// Gui
|
||||
app->gui = furi_record_open("gui");
|
||||
|
||||
// View dispatcher
|
||||
app->view_dispatcher = view_dispatcher_alloc();
|
||||
view_dispatcher_enable_queue(app->view_dispatcher);
|
||||
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
||||
|
||||
// Views
|
||||
app->submenu = submenu_alloc();
|
||||
submenu_add_item(
|
||||
app->submenu, "Enable", UsbTestSubmenuIndexEnable, usb_test_submenu_callback, app);
|
||||
submenu_add_item(
|
||||
app->submenu, "Disable", UsbTestSubmenuIndexDisable, usb_test_submenu_callback, app);
|
||||
submenu_add_item(
|
||||
app->submenu, "Single VCP", UsbTestSubmenuIndexVcpSingle, usb_test_submenu_callback, app);
|
||||
submenu_add_item(
|
||||
app->submenu, "Dual VCP", UsbTestSubmenuIndexVcpDual, usb_test_submenu_callback, app);
|
||||
submenu_add_item(
|
||||
app->submenu, "HID KB+Mouse", UsbTestSubmenuIndexHid, usb_test_submenu_callback, app);
|
||||
submenu_add_item(
|
||||
app->submenu, "TODO: HID U2F", UsbTestSubmenuIndexHidU2F, usb_test_submenu_callback, app);
|
||||
view_set_previous_callback(submenu_get_view(app->submenu), usb_test_exit);
|
||||
view_dispatcher_add_view(app->view_dispatcher, 0, submenu_get_view(app->submenu));
|
||||
|
||||
// Switch to menu
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, 0);
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
void usb_test_app_free(UsbTestApp* app) {
|
||||
furi_assert(app);
|
||||
|
||||
// Free views
|
||||
view_dispatcher_remove_view(app->view_dispatcher, 0);
|
||||
submenu_free(app->submenu);
|
||||
view_dispatcher_free(app->view_dispatcher);
|
||||
|
||||
// Close gui record
|
||||
furi_record_close("gui");
|
||||
app->gui = NULL;
|
||||
|
||||
// Free rest
|
||||
free(app);
|
||||
}
|
||||
|
||||
int32_t usb_test_app(void* p) {
|
||||
UsbTestApp* app = usb_test_app_alloc();
|
||||
|
||||
view_dispatcher_run(app->view_dispatcher);
|
||||
|
||||
usb_test_app_free(app);
|
||||
return 0;
|
||||
}
|
||||
@ -40,7 +40,7 @@ Desktop* desktop_alloc() {
|
||||
desktop->locked_view = desktop_locked_alloc();
|
||||
desktop->debug_view = desktop_debug_alloc();
|
||||
desktop->first_start_view = desktop_first_start_alloc();
|
||||
desktop->hw_mismatch_view = desktop_hw_mismatch_alloc();
|
||||
desktop->hw_mismatch_popup = popup_alloc();
|
||||
|
||||
view_dispatcher_add_view(
|
||||
desktop->view_dispatcher, DesktopViewMain, desktop_main_get_view(desktop->main_view));
|
||||
@ -61,7 +61,7 @@ Desktop* desktop_alloc() {
|
||||
view_dispatcher_add_view(
|
||||
desktop->view_dispatcher,
|
||||
DesktopViewHwMismatch,
|
||||
desktop_hw_mismatch_get_view(desktop->hw_mismatch_view));
|
||||
popup_get_view(desktop->hw_mismatch_popup));
|
||||
|
||||
// Lock icon
|
||||
desktop->lock_viewport = view_port_alloc();
|
||||
@ -91,7 +91,7 @@ void desktop_free(Desktop* desktop) {
|
||||
desktop_locked_free(desktop->locked_view);
|
||||
desktop_debug_free(desktop->debug_view);
|
||||
desktop_first_start_free(desktop->first_start_view);
|
||||
desktop_hw_mismatch_free(desktop->hw_mismatch_view);
|
||||
popup_free(desktop->hw_mismatch_popup);
|
||||
|
||||
furi_record_close("gui");
|
||||
desktop->gui = NULL;
|
||||
|
||||
@ -7,24 +7,21 @@
|
||||
|
||||
#include <gui/gui.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/modules/popup.h>
|
||||
#include <gui/scene_manager.h>
|
||||
#include <assets_icons.h>
|
||||
#include <storage/storage.h>
|
||||
|
||||
#include "views/desktop_main.h"
|
||||
#include "views/desktop_first_start.h"
|
||||
#include "views/desktop_hw_mismatch.h"
|
||||
#include "views/desktop_lock_menu.h"
|
||||
#include "views/desktop_locked.h"
|
||||
#include "views/desktop_debug.h"
|
||||
|
||||
#include "scenes/desktop_scene.h"
|
||||
|
||||
#include "helpers/desktop_animation.h"
|
||||
#include "desktop/desktop_settings/desktop_settings.h"
|
||||
|
||||
#define HINT_TIMEOUT_L 2
|
||||
#define HINT_TIMEOUT_H 11
|
||||
|
||||
typedef enum {
|
||||
DesktopViewMain,
|
||||
DesktopViewLockMenu,
|
||||
@ -44,7 +41,7 @@ struct Desktop {
|
||||
SceneManager* scene_manager;
|
||||
|
||||
DesktopFirstStartView* first_start_view;
|
||||
DesktopHwMismatchView* hw_mismatch_view;
|
||||
Popup* hw_mismatch_popup;
|
||||
DesktopMainView* main_view;
|
||||
DesktopLockMenuView* lock_menu;
|
||||
DesktopLockedView* locked_view;
|
||||
|
||||
26
applications/desktop/helpers/desktop_animation.c
Normal file
26
applications/desktop/helpers/desktop_animation.c
Normal file
@ -0,0 +1,26 @@
|
||||
#include "desktop_animation.h"
|
||||
|
||||
static const Icon* idle_scenes[] = {&A_Wink_128x64, &A_WatchingTV_128x64};
|
||||
|
||||
const Icon* desktop_get_icon() {
|
||||
uint8_t new = 0;
|
||||
|
||||
#if 0
|
||||
// checking dolphin state here to choose appropriate animation
|
||||
|
||||
Dolphin* dolphin = furi_record_open("dolphin");
|
||||
DolphinStats stats = dolphin_stats(dolphin);
|
||||
float timediff = fabs(difftime(stats.timestamp, dolphin_state_timestamp()));
|
||||
|
||||
FURI_LOG_I("desktop-animation", "background change");
|
||||
FURI_LOG_I("desktop-animation", "icounter: %d", stats.icounter);
|
||||
FURI_LOG_I("desktop-animation", "butthurt: %d", stats.butthurt);
|
||||
FURI_LOG_I("desktop-animation", "time since deeed: %.0f", timediff);
|
||||
#endif
|
||||
|
||||
if((random() % 100) > 50) { // temp rnd selection
|
||||
new = random() % COUNT_OF(idle_scenes);
|
||||
}
|
||||
|
||||
return idle_scenes[new];
|
||||
}
|
||||
10
applications/desktop/helpers/desktop_animation.h
Normal file
10
applications/desktop/helpers/desktop_animation.h
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi.h>
|
||||
#include <math.h>
|
||||
#include <assets_icons.h>
|
||||
#include "dolphin/dolphin.h"
|
||||
#include "dolphin/helpers/dolphin_state.h"
|
||||
#include "time.h"
|
||||
|
||||
const Icon* desktop_get_icon();
|
||||
@ -26,7 +26,7 @@ bool desktop_scene_debug_on_event(void* context, SceneManagerEvent event) {
|
||||
switch(event.event) {
|
||||
case DesktopDebugEventExit:
|
||||
scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain);
|
||||
dolphin_save(dolphin);
|
||||
dolphin_flush(dolphin);
|
||||
consumed = true;
|
||||
break;
|
||||
|
||||
@ -43,7 +43,7 @@ bool desktop_scene_debug_on_event(void* context, SceneManagerEvent event) {
|
||||
break;
|
||||
|
||||
case DesktopDebugEventSaveState:
|
||||
dolphin_save(dolphin);
|
||||
dolphin_flush(dolphin);
|
||||
consumed = true;
|
||||
break;
|
||||
|
||||
|
||||
@ -1,16 +1,26 @@
|
||||
#include "../desktop_i.h"
|
||||
#include "../views/desktop_hw_mismatch.h"
|
||||
#include <furi-hal-version.h>
|
||||
|
||||
void desktop_scene_hw_mismatch_callback(DesktopHwMismatchEvent event, void* context) {
|
||||
#define HW_MISMATCH_BACK_EVENT (0UL)
|
||||
|
||||
void desktop_scene_hw_mismatch_callback(void* context) {
|
||||
Desktop* desktop = (Desktop*)context;
|
||||
view_dispatcher_send_custom_event(desktop->view_dispatcher, event);
|
||||
view_dispatcher_send_custom_event(desktop->view_dispatcher, HW_MISMATCH_BACK_EVENT);
|
||||
}
|
||||
|
||||
void desktop_scene_hw_mismatch_on_enter(void* context) {
|
||||
Desktop* desktop = (Desktop*)context;
|
||||
|
||||
desktop_hw_mismatch_set_callback(
|
||||
desktop->hw_mismatch_view, desktop_scene_hw_mismatch_callback, desktop);
|
||||
Popup* popup = desktop->hw_mismatch_popup;
|
||||
char buffer[256]; // strange but smaller buffer not making it
|
||||
snprintf(
|
||||
buffer,
|
||||
sizeof(buffer),
|
||||
"HW target: F%d\nFW target: " TARGET,
|
||||
furi_hal_version_get_hw_target());
|
||||
popup_set_context(popup, desktop);
|
||||
popup_set_header(popup, "!!!! HW Mismatch !!!!", 60, 14, AlignCenter, AlignCenter);
|
||||
popup_set_text(popup, buffer, 60, 37, AlignCenter, AlignCenter);
|
||||
popup_set_callback(popup, desktop_scene_hw_mismatch_callback);
|
||||
view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewHwMismatch);
|
||||
}
|
||||
|
||||
@ -20,7 +30,7 @@ bool desktop_scene_hw_mismatch_on_event(void* context, SceneManagerEvent event)
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case DesktopHwMismatchEventExit:
|
||||
case HW_MISMATCH_BACK_EVENT:
|
||||
scene_manager_previous_scene(desktop->scene_manager);
|
||||
consumed = true;
|
||||
break;
|
||||
@ -33,5 +43,10 @@ bool desktop_scene_hw_mismatch_on_event(void* context, SceneManagerEvent event)
|
||||
}
|
||||
|
||||
void desktop_scene_hw_mismatch_on_exit(void* context) {
|
||||
// Desktop* desktop = (Desktop*)context;
|
||||
Desktop* desktop = (Desktop*)context;
|
||||
Popup* popup = desktop->hw_mismatch_popup;
|
||||
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
|
||||
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
|
||||
popup_set_callback(popup, NULL);
|
||||
popup_set_context(popup, NULL);
|
||||
}
|
||||
|
||||
@ -13,6 +13,7 @@ void desktop_scene_locked_on_enter(void* context) {
|
||||
desktop_locked_set_callback(locked_view, desktop_scene_locked_callback, desktop);
|
||||
desktop_locked_reset_door_pos(locked_view);
|
||||
desktop_locked_update_hint_timeout(locked_view);
|
||||
desktop_locked_set_dolphin_animation(locked_view);
|
||||
|
||||
view_port_enabled_set(desktop->lock_viewport, true);
|
||||
osTimerStart(locked_view->timer, 63);
|
||||
@ -45,7 +46,6 @@ bool desktop_scene_locked_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
void desktop_scene_locked_on_exit(void* context) {
|
||||
Desktop* desktop = (Desktop*)context;
|
||||
DesktopLockedView* locked_view = desktop->locked_view;
|
||||
desktop_locked_reset_counter(desktop->locked_view);
|
||||
osTimerStop(locked_view->timer);
|
||||
osTimerStop(desktop->locked_view->timer);
|
||||
}
|
||||
|
||||
@ -39,6 +39,7 @@ void desktop_scene_main_on_enter(void* context) {
|
||||
desktop_main_unlocked(desktop->main_view);
|
||||
}
|
||||
|
||||
desktop_main_switch_dolphin_animation(desktop->main_view);
|
||||
view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewMain);
|
||||
}
|
||||
|
||||
@ -59,7 +60,7 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) {
|
||||
break;
|
||||
|
||||
case DesktopMainEventOpenDebug:
|
||||
scene_manager_next_scene(desktop->scene_manager, DesktopViewDebug);
|
||||
scene_manager_next_scene(desktop->scene_manager, DesktopSceneDebug);
|
||||
consumed = true;
|
||||
break;
|
||||
|
||||
@ -67,6 +68,7 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) {
|
||||
desktop_switch_to_app(desktop, &FLIPPER_ARCHIVE);
|
||||
consumed = true;
|
||||
break;
|
||||
|
||||
case DesktopMainEventOpenFavorite:
|
||||
desktop_settings_load(&desktop->settings);
|
||||
desktop_switch_to_app(desktop, &FLIPPER_APPS[desktop->settings.favorite]);
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
#include "../desktop_i.h"
|
||||
#include "desktop_debug.h"
|
||||
|
||||
#include "applications/dolphin/helpers/dolphin_state.h"
|
||||
#include "applications/dolphin/dolphin.h"
|
||||
#include "dolphin/helpers/dolphin_state.h"
|
||||
#include "dolphin/dolphin.h"
|
||||
|
||||
void desktop_debug_set_callback(
|
||||
DesktopDebugView* debug_view,
|
||||
@ -21,7 +21,7 @@ void desktop_debug_render(Canvas* canvas, void* model) {
|
||||
const Version* ver;
|
||||
char buffer[64];
|
||||
|
||||
static const char* headers[] = {"FW Version info:", "Boot Version info:", "Desktop info:"};
|
||||
static const char* headers[] = {"FW Version info:", "Boot Version info:", "Dolphin info:"};
|
||||
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
@ -56,7 +56,7 @@ void desktop_debug_render(Canvas* canvas, void* model) {
|
||||
"%s [%s]",
|
||||
version_get_version(ver),
|
||||
version_get_builddate(ver));
|
||||
canvas_draw_str(canvas, 5, 33, buffer);
|
||||
canvas_draw_str(canvas, 5, 32, buffer);
|
||||
|
||||
snprintf(
|
||||
buffer,
|
||||
@ -68,16 +68,22 @@ void desktop_debug_render(Canvas* canvas, void* model) {
|
||||
|
||||
snprintf(
|
||||
buffer, sizeof(buffer), "[%s] %s", version_get_target(ver), version_get_gitbranch(ver));
|
||||
canvas_draw_str(canvas, 5, 53, buffer);
|
||||
canvas_draw_str(canvas, 5, 54, buffer);
|
||||
|
||||
} else {
|
||||
char buffer[64];
|
||||
uint32_t current_lvl = dolphin_state_get_level(m->icounter);
|
||||
uint32_t remaining = dolphin_state_xp_to_levelup(m->icounter, current_lvl, true);
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
snprintf(buffer, 64, "Icounter: %ld", m->icounter);
|
||||
canvas_draw_str(canvas, 5, 30, buffer);
|
||||
snprintf(buffer, 64, "Butthurt: %ld", m->butthurt);
|
||||
canvas_draw_str(canvas, 5, 40, buffer);
|
||||
snprintf(buffer, 64, "Icounter: %ld Butthurt %ld", m->icounter, m->butthurt);
|
||||
canvas_draw_str(canvas, 5, 23, buffer);
|
||||
|
||||
snprintf(buffer, 64, "Level: %ld To level up: %ld", current_lvl, remaining);
|
||||
canvas_draw_str(canvas, 5, 33, buffer);
|
||||
|
||||
snprintf(buffer, 64, "%s", asctime(localtime((const time_t*)&m->timestamp)));
|
||||
canvas_draw_str(canvas, 5, 43, buffer);
|
||||
canvas_draw_str(canvas, 0, 53, "[< >] icounter value [ok] save");
|
||||
}
|
||||
}
|
||||
@ -146,11 +152,12 @@ void desktop_debug_free(DesktopDebugView* debug_view) {
|
||||
|
||||
void desktop_debug_get_dolphin_data(DesktopDebugView* debug_view) {
|
||||
Dolphin* dolphin = furi_record_open("dolphin");
|
||||
DolphinDeedWeight stats = dolphin_stats(dolphin);
|
||||
DolphinStats stats = dolphin_stats(dolphin);
|
||||
with_view_model(
|
||||
debug_view->view, (DesktopDebugViewModel * model) {
|
||||
model->icounter = stats.icounter;
|
||||
model->butthurt = stats.butthurt;
|
||||
model->timestamp = stats.timestamp;
|
||||
return true;
|
||||
});
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
#include <gui/elements.h>
|
||||
#include <furi.h>
|
||||
#include <storage/storage.h>
|
||||
#include <time.h>
|
||||
|
||||
typedef enum {
|
||||
DesktopDebugEventDeed,
|
||||
@ -35,6 +36,7 @@ struct DesktopDebugView {
|
||||
typedef struct {
|
||||
uint32_t icounter;
|
||||
uint32_t butthurt;
|
||||
uint64_t timestamp;
|
||||
DesktopViewStatsScreens screen;
|
||||
} DesktopDebugViewModel;
|
||||
|
||||
|
||||
@ -1,66 +0,0 @@
|
||||
#include <furi.h>
|
||||
#include "../desktop_i.h"
|
||||
#include <furi-hal.h>
|
||||
#include <furi-hal-version.h>
|
||||
|
||||
#include "desktop_hw_mismatch.h"
|
||||
|
||||
void desktop_hw_mismatch_set_callback(
|
||||
DesktopHwMismatchView* main_view,
|
||||
DesktopHwMismatchViewCallback callback,
|
||||
void* context) {
|
||||
furi_assert(main_view);
|
||||
furi_assert(callback);
|
||||
main_view->callback = callback;
|
||||
main_view->context = context;
|
||||
}
|
||||
|
||||
void desktop_hw_mismatch_render(Canvas* canvas, void* model) {
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str(canvas, 2, 15, "!!!! HW Mismatch !!!!");
|
||||
|
||||
char buffer[64];
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
snprintf(buffer, 64, "HW target: F%d", furi_hal_version_get_hw_target());
|
||||
canvas_draw_str(canvas, 5, 27, buffer);
|
||||
canvas_draw_str(canvas, 5, 38, "FW target: " TARGET);
|
||||
}
|
||||
|
||||
View* desktop_hw_mismatch_get_view(DesktopHwMismatchView* hw_mismatch_view) {
|
||||
furi_assert(hw_mismatch_view);
|
||||
return hw_mismatch_view->view;
|
||||
}
|
||||
|
||||
bool desktop_hw_mismatch_input(InputEvent* event, void* context) {
|
||||
furi_assert(event);
|
||||
furi_assert(context);
|
||||
|
||||
DesktopHwMismatchView* hw_mismatch_view = context;
|
||||
|
||||
if(event->type == InputTypeShort) {
|
||||
hw_mismatch_view->callback(DesktopHwMismatchEventExit, hw_mismatch_view->context);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
DesktopHwMismatchView* desktop_hw_mismatch_alloc() {
|
||||
DesktopHwMismatchView* hw_mismatch_view = furi_alloc(sizeof(DesktopHwMismatchView));
|
||||
hw_mismatch_view->view = view_alloc();
|
||||
view_allocate_model(
|
||||
hw_mismatch_view->view, ViewModelTypeLocking, sizeof(DesktopHwMismatchViewModel));
|
||||
view_set_context(hw_mismatch_view->view, hw_mismatch_view);
|
||||
view_set_draw_callback(hw_mismatch_view->view, (ViewDrawCallback)desktop_hw_mismatch_render);
|
||||
view_set_input_callback(hw_mismatch_view->view, desktop_hw_mismatch_input);
|
||||
|
||||
return hw_mismatch_view;
|
||||
}
|
||||
|
||||
void desktop_hw_mismatch_free(DesktopHwMismatchView* hw_mismatch_view) {
|
||||
furi_assert(hw_mismatch_view);
|
||||
|
||||
view_free(hw_mismatch_view->view);
|
||||
free(hw_mismatch_view);
|
||||
}
|
||||
@ -1,38 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/gui_i.h>
|
||||
#include <gui/view.h>
|
||||
#include <gui/canvas.h>
|
||||
#include <gui/elements.h>
|
||||
#include <furi.h>
|
||||
|
||||
typedef enum {
|
||||
DesktopHwMismatchEventExit,
|
||||
} DesktopHwMismatchEvent;
|
||||
|
||||
typedef struct DesktopHwMismatchView DesktopHwMismatchView;
|
||||
|
||||
typedef void (*DesktopHwMismatchViewCallback)(DesktopHwMismatchEvent event, void* context);
|
||||
|
||||
struct DesktopHwMismatchView {
|
||||
View* view;
|
||||
DesktopHwMismatchViewCallback callback;
|
||||
void* context;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
IconAnimation* animation;
|
||||
uint8_t scene_num;
|
||||
uint8_t hint_timeout;
|
||||
bool locked;
|
||||
} DesktopHwMismatchViewModel;
|
||||
|
||||
void desktop_hw_mismatch_set_callback(
|
||||
DesktopHwMismatchView* hw_mismatch_view,
|
||||
DesktopHwMismatchViewCallback callback,
|
||||
void* context);
|
||||
|
||||
View* desktop_hw_mismatch_get_view(DesktopHwMismatchView* hw_mismatch_view);
|
||||
|
||||
DesktopHwMismatchView* desktop_hw_mismatch_alloc();
|
||||
void desktop_hw_mismatch_free(DesktopHwMismatchView* hw_mismatch_view);
|
||||
@ -29,7 +29,7 @@ static void lock_menu_callback(void* context, uint8_t index) {
|
||||
default: // wip message
|
||||
with_view_model(
|
||||
lock_menu->view, (DesktopLockMenuViewModel * model) {
|
||||
model->hint_timeout = HINT_TIMEOUT_L;
|
||||
model->hint_timeout = HINT_TIMEOUT;
|
||||
return true;
|
||||
});
|
||||
break;
|
||||
|
||||
@ -6,6 +6,8 @@
|
||||
#include <gui/elements.h>
|
||||
#include <furi.h>
|
||||
|
||||
#define HINT_TIMEOUT 2
|
||||
|
||||
typedef enum {
|
||||
DesktopLockMenuEventLock,
|
||||
DesktopLockMenuEventUnlock,
|
||||
@ -25,7 +27,6 @@ struct DesktopLockMenuView {
|
||||
typedef struct {
|
||||
uint8_t idx;
|
||||
uint8_t hint_timeout;
|
||||
bool locked;
|
||||
} DesktopLockMenuViewModel;
|
||||
|
||||
void desktop_lock_menu_set_callback(
|
||||
|
||||
@ -2,8 +2,6 @@
|
||||
#include "../desktop_i.h"
|
||||
#include "desktop_locked.h"
|
||||
|
||||
static const Icon* idle_scenes[] = {&A_Wink_128x64, &A_WatchingTV_128x64};
|
||||
|
||||
void desktop_locked_set_callback(
|
||||
DesktopLockedView* locked_view,
|
||||
DesktopLockedViewCallback callback,
|
||||
@ -20,13 +18,12 @@ void locked_view_timer_callback(void* context) {
|
||||
}
|
||||
|
||||
// temporary locked screen animation managment
|
||||
static void
|
||||
desktop_scene_handler_set_scene(DesktopLockedView* locked_view, const Icon* icon_data) {
|
||||
void desktop_locked_set_dolphin_animation(DesktopLockedView* locked_view) {
|
||||
with_view_model(
|
||||
locked_view->view, (DesktopLockedViewModel * model) {
|
||||
if(model->animation) icon_animation_free(model->animation);
|
||||
model->animation = icon_animation_alloc(icon_data);
|
||||
icon_animation_start(model->animation);
|
||||
model->animation = icon_animation_alloc(desktop_get_icon());
|
||||
view_tie_icon_animation(locked_view->view, model->animation);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
@ -34,7 +31,7 @@ static void
|
||||
void desktop_locked_update_hint_timeout(DesktopLockedView* locked_view) {
|
||||
with_view_model(
|
||||
locked_view->view, (DesktopLockedViewModel * model) {
|
||||
model->hint_timeout = HINT_TIMEOUT_H;
|
||||
model->hint_expire_at = osKernelGetTickCount() + osKernelGetTickFreq();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
@ -43,8 +40,8 @@ void desktop_locked_reset_door_pos(DesktopLockedView* locked_view) {
|
||||
with_view_model(
|
||||
locked_view->view, (DesktopLockedViewModel * model) {
|
||||
model->animation_seq_end = false;
|
||||
model->door_left_x = -57;
|
||||
model->door_right_x = 115;
|
||||
model->door_left_x = DOOR_L_POS;
|
||||
model->door_right_x = DOOR_R_POS;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
@ -58,9 +55,12 @@ void desktop_locked_manage_redraw(DesktopLockedView* locked_view) {
|
||||
animation_seq_end = model->animation_seq_end;
|
||||
|
||||
if(!model->animation_seq_end) {
|
||||
model->door_left_x = CLAMP(model->door_left_x + 5, 0, -57);
|
||||
model->door_right_x = CLAMP(model->door_right_x - 5, 115, 60);
|
||||
model->door_left_x = CLAMP(model->door_left_x + 5, DOOR_L_POS_MAX, DOOR_L_POS);
|
||||
model->door_right_x = CLAMP(model->door_right_x - 5, DOOR_R_POS, DOOR_R_POS_MIN);
|
||||
} else {
|
||||
model->hint_expire_at = !model->hint_expire_at;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
@ -75,14 +75,14 @@ void desktop_locked_reset_counter(DesktopLockedView* locked_view) {
|
||||
|
||||
with_view_model(
|
||||
locked_view->view, (DesktopLockedViewModel * model) {
|
||||
model->hint_timeout = 0;
|
||||
model->hint_expire_at = 0;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void desktop_locked_render(Canvas* canvas, void* model) {
|
||||
DesktopLockedViewModel* m = model;
|
||||
|
||||
uint32_t now = osKernelGetTickCount();
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
@ -95,12 +95,11 @@ void desktop_locked_render(Canvas* canvas, void* model) {
|
||||
canvas_draw_icon_animation(canvas, 0, -3, m->animation);
|
||||
}
|
||||
|
||||
if(m->hint_timeout) {
|
||||
m->hint_timeout--;
|
||||
|
||||
if(now < m->hint_expire_at) {
|
||||
if(!m->animation_seq_end) {
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
elements_multiline_text_framed(canvas, 42, 30, "Locked");
|
||||
|
||||
} else {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_icon(canvas, 13, 5, &I_LockPopup_100x49);
|
||||
@ -120,15 +119,10 @@ bool desktop_locked_input(InputEvent* event, void* context) {
|
||||
|
||||
DesktopLockedView* locked_view = context;
|
||||
if(event->type == InputTypeShort) {
|
||||
with_view_model(
|
||||
locked_view->view, (DesktopLockedViewModel * model) {
|
||||
model->hint_timeout = HINT_TIMEOUT_L;
|
||||
return true;
|
||||
});
|
||||
desktop_locked_update_hint_timeout(locked_view);
|
||||
|
||||
if(event->key == InputKeyBack) {
|
||||
uint32_t press_time = HAL_GetTick();
|
||||
|
||||
uint32_t press_time = osKernelGetTickCount();
|
||||
// check if pressed sequentially
|
||||
if(press_time - locked_view->lock_lastpress > UNLOCK_RST_TIMEOUT) {
|
||||
locked_view->lock_lastpress = press_time;
|
||||
@ -148,6 +142,26 @@ bool desktop_locked_input(InputEvent* event, void* context) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void desktop_locked_enter(void* context) {
|
||||
DesktopLockedView* locked_view = context;
|
||||
|
||||
with_view_model(
|
||||
locked_view->view, (DesktopLockedViewModel * model) {
|
||||
if(model->animation) icon_animation_start(model->animation);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
void desktop_locked_exit(void* context) {
|
||||
DesktopLockedView* locked_view = context;
|
||||
|
||||
with_view_model(
|
||||
locked_view->view, (DesktopLockedViewModel * model) {
|
||||
if(model->animation) icon_animation_stop(model->animation);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
DesktopLockedView* desktop_locked_alloc() {
|
||||
DesktopLockedView* locked_view = furi_alloc(sizeof(DesktopLockedView));
|
||||
locked_view->view = view_alloc();
|
||||
@ -158,8 +172,9 @@ DesktopLockedView* desktop_locked_alloc() {
|
||||
view_set_context(locked_view->view, locked_view);
|
||||
view_set_draw_callback(locked_view->view, (ViewDrawCallback)desktop_locked_render);
|
||||
view_set_input_callback(locked_view->view, desktop_locked_input);
|
||||
view_set_enter_callback(locked_view->view, desktop_locked_enter);
|
||||
view_set_exit_callback(locked_view->view, desktop_locked_exit);
|
||||
|
||||
desktop_scene_handler_set_scene(locked_view, idle_scenes[random() % COUNT_OF(idle_scenes)]);
|
||||
return locked_view;
|
||||
}
|
||||
|
||||
|
||||
@ -6,9 +6,14 @@
|
||||
#include <gui/elements.h>
|
||||
#include <furi.h>
|
||||
|
||||
#define UNLOCK_RST_TIMEOUT 200
|
||||
#define UNLOCK_RST_TIMEOUT 300
|
||||
#define UNLOCK_CNT 2 // 3 actually
|
||||
|
||||
#define DOOR_L_POS -57
|
||||
#define DOOR_L_POS_MAX 0
|
||||
#define DOOR_R_POS 115
|
||||
#define DOOR_R_POS_MIN 60
|
||||
|
||||
typedef enum {
|
||||
DesktopLockedEventUnlock,
|
||||
DesktopLockedEventUpdate,
|
||||
@ -30,10 +35,11 @@ struct DesktopLockedView {
|
||||
|
||||
typedef struct {
|
||||
IconAnimation* animation;
|
||||
uint32_t hint_expire_at;
|
||||
|
||||
uint8_t scene_num;
|
||||
int8_t door_left_x;
|
||||
int8_t door_right_x;
|
||||
uint8_t hint_timeout;
|
||||
bool animation_seq_end;
|
||||
|
||||
} DesktopLockedViewModel;
|
||||
@ -43,6 +49,7 @@ void desktop_locked_set_callback(
|
||||
DesktopLockedViewCallback callback,
|
||||
void* context);
|
||||
|
||||
void desktop_locked_set_dolphin_animation(DesktopLockedView* locked_view);
|
||||
void desktop_locked_update_hint_timeout(DesktopLockedView* locked_view);
|
||||
void desktop_locked_reset_counter(DesktopLockedView* locked_view);
|
||||
void desktop_locked_reset_door_pos(DesktopLockedView* locked_view);
|
||||
|
||||
@ -2,8 +2,6 @@
|
||||
#include "../desktop_i.h"
|
||||
#include "desktop_main.h"
|
||||
|
||||
static const Icon* idle_scenes[] = {&A_Wink_128x64, &A_WatchingTV_128x64};
|
||||
|
||||
void desktop_main_set_callback(
|
||||
DesktopMainView* main_view,
|
||||
DesktopMainViewCallback callback,
|
||||
@ -17,30 +15,17 @@ void desktop_main_set_callback(
|
||||
void desktop_main_reset_hint(DesktopMainView* main_view) {
|
||||
with_view_model(
|
||||
main_view->view, (DesktopMainViewModel * model) {
|
||||
model->hint_timeout = 0;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
// temporary main screen animation managment
|
||||
void desktop_scene_handler_set_scene(DesktopMainView* main_view, const Icon* icon_data) {
|
||||
with_view_model(
|
||||
main_view->view, (DesktopMainViewModel * model) {
|
||||
if(model->animation) icon_animation_free(model->animation);
|
||||
model->animation = icon_animation_alloc(icon_data);
|
||||
icon_animation_start(model->animation);
|
||||
model->hint_expire_at = 0;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void desktop_scene_handler_switch_scene(DesktopMainView* main_view) {
|
||||
void desktop_main_switch_dolphin_animation(DesktopMainView* main_view) {
|
||||
with_view_model(
|
||||
main_view->view, (DesktopMainViewModel * model) {
|
||||
if(icon_animation_is_last_frame(model->animation)) {
|
||||
if(model->animation) icon_animation_free(model->animation);
|
||||
model->animation = icon_animation_alloc(idle_scenes[model->scene_num]);
|
||||
icon_animation_start(model->animation);
|
||||
model->scene_num = random() % COUNT_OF(idle_scenes);
|
||||
}
|
||||
if(model->animation) icon_animation_free(model->animation);
|
||||
model->animation = icon_animation_alloc(desktop_get_icon());
|
||||
view_tie_icon_animation(main_view->view, model->animation);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
@ -48,13 +33,13 @@ void desktop_scene_handler_switch_scene(DesktopMainView* main_view) {
|
||||
void desktop_main_render(Canvas* canvas, void* model) {
|
||||
canvas_clear(canvas);
|
||||
DesktopMainViewModel* m = model;
|
||||
uint32_t now = osKernelGetTickCount();
|
||||
|
||||
if(m->animation) {
|
||||
canvas_draw_icon_animation(canvas, 0, -3, m->animation);
|
||||
}
|
||||
|
||||
if(m->unlocked && m->hint_timeout) {
|
||||
m->hint_timeout = CLAMP(m->hint_timeout - 1, 2, 0);
|
||||
if(now < m->hint_expire_at) {
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
elements_multiline_text_framed(canvas, 42, 30, "Unlocked");
|
||||
}
|
||||
@ -87,6 +72,25 @@ bool desktop_main_input(InputEvent* event, void* context) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void desktop_main_enter(void* context) {
|
||||
DesktopMainView* main_view = context;
|
||||
|
||||
with_view_model(
|
||||
main_view->view, (DesktopMainViewModel * model) {
|
||||
if(model->animation) icon_animation_start(model->animation);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
void desktop_main_exit(void* context) {
|
||||
DesktopMainView* main_view = context;
|
||||
with_view_model(
|
||||
main_view->view, (DesktopMainViewModel * model) {
|
||||
if(model->animation) icon_animation_stop(model->animation);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
DesktopMainView* desktop_main_alloc() {
|
||||
DesktopMainView* main_view = furi_alloc(sizeof(DesktopMainView));
|
||||
main_view->view = view_alloc();
|
||||
@ -94,8 +98,8 @@ DesktopMainView* desktop_main_alloc() {
|
||||
view_set_context(main_view->view, main_view);
|
||||
view_set_draw_callback(main_view->view, (ViewDrawCallback)desktop_main_render);
|
||||
view_set_input_callback(main_view->view, desktop_main_input);
|
||||
|
||||
desktop_scene_handler_set_scene(main_view, idle_scenes[random() % COUNT_OF(idle_scenes)]);
|
||||
view_set_enter_callback(main_view->view, desktop_main_enter);
|
||||
view_set_exit_callback(main_view->view, desktop_main_exit);
|
||||
|
||||
return main_view;
|
||||
}
|
||||
@ -109,8 +113,7 @@ void desktop_main_free(DesktopMainView* main_view) {
|
||||
void desktop_main_unlocked(DesktopMainView* main_view) {
|
||||
with_view_model(
|
||||
main_view->view, (DesktopMainViewModel * model) {
|
||||
model->unlocked = true;
|
||||
model->hint_timeout = 2;
|
||||
model->hint_expire_at = osKernelGetTickCount() + osKernelGetTickFreq();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
@ -28,8 +28,7 @@ struct DesktopMainView {
|
||||
typedef struct {
|
||||
IconAnimation* animation;
|
||||
uint8_t scene_num;
|
||||
uint8_t hint_timeout;
|
||||
bool unlocked;
|
||||
uint32_t hint_expire_at;
|
||||
} DesktopMainViewModel;
|
||||
|
||||
void desktop_main_set_callback(
|
||||
@ -40,4 +39,7 @@ void desktop_main_set_callback(
|
||||
View* desktop_main_get_view(DesktopMainView* main_view);
|
||||
|
||||
DesktopMainView* desktop_main_alloc();
|
||||
|
||||
void desktop_main_free(DesktopMainView* main_view);
|
||||
|
||||
void desktop_main_switch_dolphin_animation(DesktopMainView* main_view);
|
||||
|
||||
@ -60,3 +60,14 @@ DialogMessageButton dialog_message_show(DialogsApp* context, const DialogMessage
|
||||
|
||||
return return_data.dialog_value;
|
||||
}
|
||||
|
||||
/****************** Storage error ******************/
|
||||
|
||||
void dialog_message_show_storage_error(DialogsApp* context, const char* error_text) {
|
||||
DialogMessage* message = dialog_message_alloc();
|
||||
dialog_message_set_text(message, error_text, 88, 32, AlignCenter, AlignCenter);
|
||||
dialog_message_set_icon(message, &I_SDQuestion_35x43, 5, 6);
|
||||
dialog_message_set_buttons(message, "Back", NULL, NULL);
|
||||
dialog_message_show(context, message);
|
||||
dialog_message_free(message);
|
||||
}
|
||||
@ -123,6 +123,13 @@ void dialog_message_set_buttons(
|
||||
*/
|
||||
DialogMessageButton dialog_message_show(DialogsApp* context, const DialogMessage* message);
|
||||
|
||||
/**
|
||||
* Show SD error message (with question sign)
|
||||
* @param context
|
||||
* @param error_text
|
||||
*/
|
||||
void dialog_message_show_storage_error(DialogsApp* context, const char* error_text);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@ -1,34 +1,39 @@
|
||||
#include "dolphin_i.h"
|
||||
#include <furi.h>
|
||||
|
||||
bool dolphin_load(Dolphin* dolphin) {
|
||||
furi_assert(dolphin);
|
||||
return dolphin_state_load(dolphin->state);
|
||||
}
|
||||
|
||||
void dolphin_save(Dolphin* dolphin) {
|
||||
furi_assert(dolphin);
|
||||
DolphinEvent event;
|
||||
event.type = DolphinEventTypeSave;
|
||||
furi_check(osMessageQueuePut(dolphin->event_queue, &event, 0, osWaitForever) == osOK);
|
||||
}
|
||||
#define DOLPHIN_TIMEGATE 86400 // one day
|
||||
#define DOLPHIN_LOCK_EVENT_FLAG (0x1)
|
||||
|
||||
void dolphin_deed(Dolphin* dolphin, DolphinDeed deed) {
|
||||
furi_assert(dolphin);
|
||||
DolphinEvent event;
|
||||
event.type = DolphinEventTypeDeed;
|
||||
event.deed = deed;
|
||||
furi_check(osMessageQueuePut(dolphin->event_queue, &event, 0, osWaitForever) == osOK);
|
||||
dolphin_event_send_async(dolphin, &event);
|
||||
}
|
||||
|
||||
DolphinDeedWeight dolphin_stats(Dolphin* dolphin) {
|
||||
DolphinDeedWeight stats;
|
||||
stats.butthurt = dolphin_state_get_butthurt(dolphin->state);
|
||||
stats.icounter = dolphin_state_get_icounter(dolphin->state);
|
||||
DolphinStats dolphin_stats(Dolphin* dolphin) {
|
||||
furi_assert(dolphin);
|
||||
|
||||
DolphinStats stats;
|
||||
DolphinEvent event;
|
||||
|
||||
event.type = DolphinEventTypeStats;
|
||||
event.stats = &stats;
|
||||
|
||||
dolphin_event_send_wait(dolphin, &event);
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
void dolphin_flush(Dolphin* dolphin) {
|
||||
furi_assert(dolphin);
|
||||
|
||||
DolphinEvent event;
|
||||
event.type = DolphinEventTypeFlush;
|
||||
|
||||
dolphin_event_send_wait(dolphin, &event);
|
||||
}
|
||||
|
||||
Dolphin* dolphin_alloc() {
|
||||
Dolphin* dolphin = furi_alloc(sizeof(Dolphin));
|
||||
|
||||
@ -47,27 +52,72 @@ void dolphin_free(Dolphin* dolphin) {
|
||||
free(dolphin);
|
||||
}
|
||||
|
||||
void dolphin_event_send_async(Dolphin* dolphin, DolphinEvent* event) {
|
||||
furi_assert(dolphin);
|
||||
furi_assert(event);
|
||||
event->flag = NULL;
|
||||
furi_check(osMessageQueuePut(dolphin->event_queue, event, 0, osWaitForever) == osOK);
|
||||
}
|
||||
|
||||
void dolphin_event_send_wait(Dolphin* dolphin, DolphinEvent* event) {
|
||||
furi_assert(dolphin);
|
||||
furi_assert(event);
|
||||
event->flag = osEventFlagsNew(NULL);
|
||||
furi_check(event->flag);
|
||||
furi_check(osMessageQueuePut(dolphin->event_queue, event, 0, osWaitForever) == osOK);
|
||||
furi_check(
|
||||
osEventFlagsWait(event->flag, DOLPHIN_LOCK_EVENT_FLAG, osFlagsWaitAny, osWaitForever) ==
|
||||
DOLPHIN_LOCK_EVENT_FLAG);
|
||||
furi_check(osEventFlagsDelete(event->flag) == osOK);
|
||||
}
|
||||
|
||||
void dolphin_event_release(Dolphin* dolphin, DolphinEvent* event) {
|
||||
if(event->flag) {
|
||||
osEventFlagsSet(event->flag, DOLPHIN_LOCK_EVENT_FLAG);
|
||||
}
|
||||
}
|
||||
|
||||
static void dolphin_check_butthurt(DolphinState* state) {
|
||||
furi_assert(state);
|
||||
float diff_time = difftime(dolphin_state_get_timestamp(state), dolphin_state_timestamp());
|
||||
|
||||
#if 0
|
||||
FURI_LOG_I("dolphin-state", "Butthurt check, time since deed %.0f", fabs(diff_time));
|
||||
#endif
|
||||
|
||||
if((fabs(diff_time)) > DOLPHIN_TIMEGATE) {
|
||||
// increase butthurt
|
||||
FURI_LOG_I("dolphin-state", "Increasing butthurt");
|
||||
dolphin_state_butthurted(state);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t dolphin_srv(void* p) {
|
||||
Dolphin* dolphin = dolphin_alloc();
|
||||
furi_record_create("dolphin", dolphin);
|
||||
|
||||
dolphin_state_load(dolphin->state);
|
||||
|
||||
DolphinEvent event;
|
||||
while(1) {
|
||||
furi_check(osMessageQueueGet(dolphin->event_queue, &event, NULL, osWaitForever) == osOK);
|
||||
switch(event.type) {
|
||||
case DolphinEventTypeDeed:
|
||||
dolphin_state_on_deed(dolphin->state, event.deed);
|
||||
break;
|
||||
|
||||
case DolphinEventTypeSave:
|
||||
if(osMessageQueueGet(dolphin->event_queue, &event, NULL, 60000) == osOK) {
|
||||
if(event.type == DolphinEventTypeDeed) {
|
||||
dolphin_state_on_deed(dolphin->state, event.deed);
|
||||
} else if(event.type == DolphinEventTypeStats) {
|
||||
event.stats->icounter = dolphin_state_get_icounter(dolphin->state);
|
||||
event.stats->butthurt = dolphin_state_get_butthurt(dolphin->state);
|
||||
event.stats->timestamp = dolphin_state_get_timestamp(dolphin->state);
|
||||
} else if(event.type == DolphinEventTypeFlush) {
|
||||
dolphin_state_save(dolphin->state);
|
||||
}
|
||||
dolphin_event_release(dolphin, &event);
|
||||
} else {
|
||||
dolphin_check_butthurt(dolphin->state);
|
||||
dolphin_state_save(dolphin->state);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dolphin_free(dolphin);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -4,27 +4,24 @@
|
||||
|
||||
typedef struct Dolphin Dolphin;
|
||||
|
||||
/* Load Dolphin state
|
||||
* Thread safe
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t icounter;
|
||||
uint32_t butthurt;
|
||||
uint64_t timestamp;
|
||||
} DolphinStats;
|
||||
|
||||
bool dolphin_load(Dolphin* dolphin);
|
||||
|
||||
/* Deed complete notification. Call it on deed completion.
|
||||
/** Deed complete notification. Call it on deed completion.
|
||||
* See dolphin_deed.h for available deeds. In futures it will become part of assets.
|
||||
* Thread safe
|
||||
* Thread safe, async
|
||||
*/
|
||||
|
||||
void dolphin_deed(Dolphin* dolphin, DolphinDeed deed);
|
||||
|
||||
/* Save Dolphin state (write to permanent memory)
|
||||
* Thread safe
|
||||
/** Retrieve dolphin stats
|
||||
* Thread safe, blocking
|
||||
*/
|
||||
DolphinStats dolphin_stats(Dolphin* dolphin);
|
||||
|
||||
void dolphin_save(Dolphin* dolphin);
|
||||
|
||||
/* Retrieve dolphin's icounter and butthurt values
|
||||
* Thread safe
|
||||
/** Flush dolphin queue and save state
|
||||
* Thread safe, blocking
|
||||
*/
|
||||
|
||||
DolphinDeedWeight dolphin_stats(Dolphin* dolphin);
|
||||
void dolphin_flush(Dolphin* dolphin);
|
||||
@ -8,14 +8,16 @@
|
||||
|
||||
typedef enum {
|
||||
DolphinEventTypeDeed,
|
||||
DolphinEventTypeSave,
|
||||
DolphinEventTypeTick,
|
||||
DolphinEventTypeStats,
|
||||
DolphinEventTypeFlush,
|
||||
} DolphinEventType;
|
||||
|
||||
typedef struct {
|
||||
DolphinEventType type;
|
||||
osEventFlagsId_t flag;
|
||||
union {
|
||||
DolphinDeed deed;
|
||||
DolphinStats* stats;
|
||||
};
|
||||
} DolphinEvent;
|
||||
|
||||
@ -29,3 +31,9 @@ struct Dolphin {
|
||||
Dolphin* dolphin_alloc();
|
||||
|
||||
void dolphin_free(Dolphin* dolphin);
|
||||
|
||||
void dolphin_event_send_async(Dolphin* dolphin, DolphinEvent* event);
|
||||
|
||||
void dolphin_event_send_wait(Dolphin* dolphin, DolphinEvent* event);
|
||||
|
||||
void dolphin_event_release(Dolphin* dolphin, DolphinEvent* event);
|
||||
|
||||
@ -25,6 +25,7 @@ typedef struct {
|
||||
uint32_t flags;
|
||||
uint32_t icounter;
|
||||
uint32_t butthurt;
|
||||
uint64_t timestamp;
|
||||
} DolphinStoreData;
|
||||
|
||||
typedef struct {
|
||||
@ -35,6 +36,7 @@ typedef struct {
|
||||
struct DolphinState {
|
||||
Storage* fs_api;
|
||||
DolphinStoreData data;
|
||||
bool dirty;
|
||||
};
|
||||
|
||||
DolphinState* dolphin_state_alloc() {
|
||||
@ -49,8 +51,12 @@ void dolphin_state_free(DolphinState* dolphin_state) {
|
||||
}
|
||||
|
||||
bool dolphin_state_save(DolphinState* dolphin_state) {
|
||||
if(!dolphin_state->dirty) {
|
||||
return true;
|
||||
}
|
||||
|
||||
FURI_LOG_I("dolphin-state", "State is dirty, saving to \"%s\"", DOLPHIN_STORE_KEY);
|
||||
DolphinStore store;
|
||||
FURI_LOG_I("dolphin-state", "Saving state to \"%s\"", DOLPHIN_STORE_KEY);
|
||||
// Calculate checksum
|
||||
uint8_t* source = (uint8_t*)&dolphin_state->data;
|
||||
uint8_t checksum = 0;
|
||||
@ -88,7 +94,10 @@ bool dolphin_state_save(DolphinState* dolphin_state) {
|
||||
storage_file_close(file);
|
||||
storage_file_free(file);
|
||||
|
||||
dolphin_state->dirty = !save_result;
|
||||
|
||||
FURI_LOG_I("dolphin-state", "Saved");
|
||||
|
||||
return save_result;
|
||||
}
|
||||
|
||||
@ -99,8 +108,12 @@ bool dolphin_state_load(DolphinState* dolphin_state) {
|
||||
|
||||
File* file = storage_file_alloc(dolphin_state->fs_api);
|
||||
bool load_result = storage_file_open(file, DOLPHIN_STORE_KEY, FSAM_READ, FSOM_OPEN_EXISTING);
|
||||
|
||||
if(load_result) {
|
||||
if(!load_result) {
|
||||
FURI_LOG_E(
|
||||
"dolphin-state",
|
||||
"Load failed. Storage returned: %s",
|
||||
storage_file_get_error_desc(file));
|
||||
} else {
|
||||
uint16_t bytes_count = storage_file_read(file, &store, sizeof(DolphinStore));
|
||||
|
||||
if(bytes_count != sizeof(DolphinStore)) {
|
||||
@ -109,12 +122,8 @@ bool dolphin_state_load(DolphinState* dolphin_state) {
|
||||
}
|
||||
|
||||
if(!load_result) {
|
||||
FURI_LOG_E(
|
||||
"dolphin-state",
|
||||
"Load failed. Storage returned: %s",
|
||||
storage_file_get_error_desc(file));
|
||||
FURI_LOG_E("dolphin-state", "DolphinStore size mismatch");
|
||||
} else {
|
||||
FURI_LOG_I("dolphin-state", "State loaded, verifying header");
|
||||
if(store.header.magic == DOLPHIN_STORE_HEADER_MAGIC &&
|
||||
store.header.version == DOLPHIN_STORE_HEADER_VERSION) {
|
||||
FURI_LOG_I(
|
||||
@ -142,7 +151,7 @@ bool dolphin_state_load(DolphinState* dolphin_state) {
|
||||
} else {
|
||||
FURI_LOG_E(
|
||||
"dolphin-state",
|
||||
"Magic(%d != %d) and Version(%d != %d) mismatch",
|
||||
"Magic(%d != %d) or Version(%d != %d) mismatch",
|
||||
store.header.magic,
|
||||
DOLPHIN_STORE_HEADER_MAGIC,
|
||||
store.header.version,
|
||||
@ -153,6 +162,9 @@ bool dolphin_state_load(DolphinState* dolphin_state) {
|
||||
|
||||
storage_file_close(file);
|
||||
storage_file_free(file);
|
||||
|
||||
dolphin_state->dirty = !load_result;
|
||||
|
||||
return load_result;
|
||||
}
|
||||
|
||||
@ -160,13 +172,43 @@ void dolphin_state_clear(DolphinState* dolphin_state) {
|
||||
memset(&dolphin_state->data, 0, sizeof(DolphinStoreData));
|
||||
}
|
||||
|
||||
uint64_t dolphin_state_timestamp() {
|
||||
RTC_TimeTypeDef time;
|
||||
RTC_DateTypeDef date;
|
||||
struct tm current;
|
||||
|
||||
HAL_RTC_GetTime(&hrtc, &time, RTC_FORMAT_BIN);
|
||||
HAL_RTC_GetDate(&hrtc, &date, RTC_FORMAT_BIN);
|
||||
|
||||
current.tm_year = date.Year + 100;
|
||||
current.tm_mday = date.Date;
|
||||
current.tm_mon = date.Month - 1;
|
||||
|
||||
current.tm_hour = time.Hours;
|
||||
current.tm_min = time.Minutes;
|
||||
current.tm_sec = time.Seconds;
|
||||
|
||||
return mktime(¤t);
|
||||
}
|
||||
|
||||
void dolphin_state_on_deed(DolphinState* dolphin_state, DolphinDeed deed) {
|
||||
const DolphinDeedWeight* deed_weight = dolphin_deed_weight(deed);
|
||||
int32_t icounter = dolphin_state->data.icounter + deed_weight->icounter;
|
||||
int32_t butthurt = dolphin_state->data.butthurt;
|
||||
|
||||
if(icounter >= 0) {
|
||||
dolphin_state->data.icounter = icounter;
|
||||
dolphin_state->data.butthurt = MAX(butthurt - deed_weight->icounter, 0);
|
||||
dolphin_state->data.timestamp = dolphin_state_timestamp();
|
||||
}
|
||||
|
||||
dolphin_state->dirty = true;
|
||||
}
|
||||
|
||||
void dolphin_state_butthurted(DolphinState* dolphin_state) {
|
||||
dolphin_state->data.butthurt++;
|
||||
dolphin_state->data.timestamp = dolphin_state_timestamp();
|
||||
dolphin_state->dirty = true;
|
||||
}
|
||||
|
||||
uint32_t dolphin_state_get_icounter(DolphinState* dolphin_state) {
|
||||
@ -177,13 +219,14 @@ uint32_t dolphin_state_get_butthurt(DolphinState* dolphin_state) {
|
||||
return dolphin_state->data.butthurt;
|
||||
}
|
||||
|
||||
uint32_t dolphin_state_get_level(DolphinState* dolphin_state) {
|
||||
return 0.5f +
|
||||
sqrtf(1.0f + 8.0f * ((float)dolphin_state->data.icounter / DOLPHIN_LVL_THRESHOLD)) /
|
||||
2.0f;
|
||||
uint64_t dolphin_state_get_timestamp(DolphinState* dolphin_state) {
|
||||
return dolphin_state->data.timestamp;
|
||||
}
|
||||
|
||||
uint32_t dolphin_state_xp_to_levelup(DolphinState* dolphin_state, uint32_t level, bool remaining) {
|
||||
return (DOLPHIN_LVL_THRESHOLD * level * (level + 1) / 2) -
|
||||
(remaining ? dolphin_state->data.icounter : 0);
|
||||
uint32_t dolphin_state_get_level(uint32_t icounter) {
|
||||
return 0.5f + sqrtf(1.0f + 8.0f * ((float)icounter / DOLPHIN_LVL_THRESHOLD)) / 2.0f;
|
||||
}
|
||||
|
||||
uint32_t dolphin_state_xp_to_levelup(uint32_t icounter, uint32_t level, bool remaining) {
|
||||
return (DOLPHIN_LVL_THRESHOLD * level * (level + 1) / 2) - (remaining ? icounter : 0);
|
||||
}
|
||||
@ -3,6 +3,8 @@
|
||||
#include "dolphin_deed.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <rtc.h>
|
||||
#include <time.h>
|
||||
|
||||
typedef struct DolphinState DolphinState;
|
||||
|
||||
@ -16,12 +18,18 @@ bool dolphin_state_load(DolphinState* dolphin_state);
|
||||
|
||||
void dolphin_state_clear(DolphinState* dolphin_state);
|
||||
|
||||
uint64_t dolphin_state_timestamp();
|
||||
|
||||
void dolphin_state_on_deed(DolphinState* dolphin_state, DolphinDeed deed);
|
||||
|
||||
void dolphin_state_butthurted(DolphinState* dolphin_state);
|
||||
|
||||
uint32_t dolphin_state_get_icounter(DolphinState* dolphin_state);
|
||||
|
||||
uint32_t dolphin_state_get_butthurt(DolphinState* dolphin_state);
|
||||
|
||||
uint32_t dolphin_state_get_level(DolphinState* dolphin_state);
|
||||
uint64_t dolphin_state_get_timestamp(DolphinState* dolphin_state);
|
||||
|
||||
uint32_t dolphin_state_xp_to_levelup(DolphinState* dolphin_state, uint32_t level, bool remaining);
|
||||
uint32_t dolphin_state_get_level(uint32_t icounter);
|
||||
|
||||
uint32_t dolphin_state_xp_to_levelup(uint32_t icounter, uint32_t level, bool remaining);
|
||||
@ -1,148 +0,0 @@
|
||||
#include <furi.h>
|
||||
#include <furi-hal.h>
|
||||
|
||||
#include <gui/gui.h>
|
||||
#include <notification/notification-messages.h>
|
||||
|
||||
typedef struct {
|
||||
const char* name;
|
||||
const GpioPin* pin;
|
||||
} GpioItem;
|
||||
|
||||
static const GpioItem GPIO_PINS[] = {
|
||||
{"1.2: PA7", &gpio_ext_pa7},
|
||||
{"1.3: PA6", &gpio_ext_pa6},
|
||||
{"1.4: PA4", &gpio_ext_pa4},
|
||||
{"1.5: PB3", &gpio_ext_pb3},
|
||||
{"1.6: PB2", &gpio_ext_pb2},
|
||||
{"1.7: PC3", &gpio_ext_pc3},
|
||||
{"2.7: PC1", &gpio_ext_pc1},
|
||||
{"2.8: PC0", &gpio_ext_pc0},
|
||||
{"*.*: ALL", NULL},
|
||||
};
|
||||
|
||||
static const size_t GPIO_PINS_COUNT = sizeof(GPIO_PINS) / sizeof(GPIO_PINS[0]);
|
||||
|
||||
typedef struct {
|
||||
osMessageQueueId_t input_queue;
|
||||
uint8_t gpio_index;
|
||||
ViewPort* view_port;
|
||||
Gui* gui;
|
||||
NotificationApp* notification;
|
||||
} GpioTest;
|
||||
|
||||
static void gpio_test_render_callback(Canvas* canvas, void* ctx) {
|
||||
GpioTest* gpio_test = ctx;
|
||||
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str(canvas, 2, 10, "GPIO Control");
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str(canvas, 2, 25, GPIO_PINS[gpio_test->gpio_index].name);
|
||||
}
|
||||
|
||||
static void gpio_test_input_callback(InputEvent* input_event, void* ctx) {
|
||||
GpioTest* gpio_test = ctx;
|
||||
|
||||
osMessageQueuePut(gpio_test->input_queue, input_event, 0, 0);
|
||||
}
|
||||
|
||||
static void gpio_test_configure_pins(GpioMode mode) {
|
||||
for(size_t i = 0; i < GPIO_PINS_COUNT; i++) {
|
||||
if(!GPIO_PINS[i].pin) continue;
|
||||
hal_gpio_write(GPIO_PINS[i].pin, false);
|
||||
hal_gpio_init(GPIO_PINS[i].pin, mode, GpioPullNo, GpioSpeedVeryHigh);
|
||||
}
|
||||
}
|
||||
|
||||
static void gpio_test_set_pin(uint8_t index, bool level) {
|
||||
if(GPIO_PINS[index].pin) {
|
||||
hal_gpio_write(GPIO_PINS[index].pin, level);
|
||||
} else {
|
||||
for(size_t i = 0; i < GPIO_PINS_COUNT; i++) {
|
||||
if(!GPIO_PINS[i].pin) continue;
|
||||
hal_gpio_write(GPIO_PINS[i].pin, level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GpioTest* gpio_test_alloc() {
|
||||
GpioTest* instance = furi_alloc(sizeof(GpioTest));
|
||||
|
||||
gpio_test_configure_pins(GpioModeOutputPushPull);
|
||||
|
||||
instance->input_queue = osMessageQueueNew(8, sizeof(InputEvent), NULL);
|
||||
furi_check(instance->input_queue);
|
||||
|
||||
instance->view_port = view_port_alloc();
|
||||
view_port_draw_callback_set(instance->view_port, gpio_test_render_callback, instance);
|
||||
view_port_input_callback_set(instance->view_port, gpio_test_input_callback, instance);
|
||||
|
||||
instance->gui = furi_record_open("gui");
|
||||
gui_add_view_port(instance->gui, instance->view_port, GuiLayerFullscreen);
|
||||
|
||||
instance->notification = furi_record_open("notification");
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
void gpio_test_free(GpioTest* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
furi_record_close("notification");
|
||||
|
||||
view_port_enabled_set(instance->view_port, false);
|
||||
gui_remove_view_port(instance->gui, instance->view_port);
|
||||
furi_record_close("gui");
|
||||
|
||||
view_port_free(instance->view_port);
|
||||
|
||||
osMessageQueueDelete(instance->input_queue);
|
||||
|
||||
gpio_test_configure_pins(GpioModeAnalog);
|
||||
|
||||
free(instance);
|
||||
}
|
||||
|
||||
int32_t gpio_test_app(void* p) {
|
||||
GpioTest* gpio_test = gpio_test_alloc();
|
||||
|
||||
InputEvent event;
|
||||
while(osMessageQueueGet(gpio_test->input_queue, &event, NULL, osWaitForever) == osOK) {
|
||||
if(event.type == InputTypeShort) {
|
||||
if(event.key == InputKeyBack) {
|
||||
notification_message(gpio_test->notification, &sequence_reset_green);
|
||||
break;
|
||||
}
|
||||
|
||||
if(event.key == InputKeyRight) {
|
||||
if(gpio_test->gpio_index < (GPIO_PINS_COUNT - 1)) {
|
||||
gpio_test->gpio_index++;
|
||||
}
|
||||
}
|
||||
|
||||
if(event.key == InputKeyLeft) {
|
||||
if(gpio_test->gpio_index > 0) {
|
||||
gpio_test->gpio_index--;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(event.key == InputKeyOk) {
|
||||
if(event.type == InputTypePress) {
|
||||
gpio_test_set_pin(gpio_test->gpio_index, true);
|
||||
notification_message(gpio_test->notification, &sequence_set_green_255);
|
||||
} else if(event.type == InputTypeRelease) {
|
||||
gpio_test_set_pin(gpio_test->gpio_index, false);
|
||||
notification_message(gpio_test->notification, &sequence_reset_green);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
view_port_update(gpio_test->view_port);
|
||||
}
|
||||
|
||||
gpio_test_free(gpio_test);
|
||||
|
||||
return 0;
|
||||
}
|
||||
76
applications/gpio/gpio_app.c
Executable file
76
applications/gpio/gpio_app.c
Executable file
@ -0,0 +1,76 @@
|
||||
#include "gpio_app_i.h"
|
||||
|
||||
#include <furi.h>
|
||||
#include <furi-hal.h>
|
||||
|
||||
static bool gpio_app_custom_event_callback(void* context, uint32_t event) {
|
||||
furi_assert(context);
|
||||
GpioApp* app = context;
|
||||
return scene_manager_handle_custom_event(app->scene_manager, event);
|
||||
}
|
||||
|
||||
static bool gpio_app_back_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
GpioApp* app = context;
|
||||
return scene_manager_handle_back_event(app->scene_manager);
|
||||
}
|
||||
|
||||
GpioApp* gpio_app_alloc() {
|
||||
GpioApp* app = furi_alloc(sizeof(GpioApp));
|
||||
|
||||
app->gui = furi_record_open("gui");
|
||||
app->notifications = furi_record_open("notification");
|
||||
|
||||
app->view_dispatcher = view_dispatcher_alloc();
|
||||
app->scene_manager = scene_manager_alloc(&gpio_scene_handlers, app);
|
||||
view_dispatcher_enable_queue(app->view_dispatcher);
|
||||
view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
|
||||
|
||||
view_dispatcher_set_custom_event_callback(
|
||||
app->view_dispatcher, gpio_app_custom_event_callback);
|
||||
view_dispatcher_set_navigation_event_callback(
|
||||
app->view_dispatcher, gpio_app_back_event_callback);
|
||||
|
||||
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
||||
|
||||
app->var_item_list = variable_item_list_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher,
|
||||
GpioAppViewVarItemList,
|
||||
variable_item_list_get_view(app->var_item_list));
|
||||
app->gpio_test = gpio_test_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, GpioAppViewGpioTest, gpio_test_get_view(app->gpio_test));
|
||||
|
||||
scene_manager_next_scene(app->scene_manager, GpioSceneStart);
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
void gpio_app_free(GpioApp* app) {
|
||||
furi_assert(app);
|
||||
|
||||
// Views
|
||||
view_dispatcher_remove_view(app->view_dispatcher, GpioAppViewVarItemList);
|
||||
variable_item_list_free(app->var_item_list);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, GpioAppViewGpioTest);
|
||||
gpio_test_free(app->gpio_test);
|
||||
// View dispatcher
|
||||
view_dispatcher_free(app->view_dispatcher);
|
||||
scene_manager_free(app->scene_manager);
|
||||
// Close records
|
||||
furi_record_close("gui");
|
||||
furi_record_close("notification");
|
||||
|
||||
free(app);
|
||||
}
|
||||
|
||||
int32_t gpio_app(void* p) {
|
||||
GpioApp* gpio_app = gpio_app_alloc();
|
||||
|
||||
view_dispatcher_run(gpio_app->view_dispatcher);
|
||||
|
||||
gpio_app_free(gpio_app);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1,11 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void MX_USB_Device_Init();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct GpioApp GpioApp;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
28
applications/gpio/gpio_app_i.h
Normal file
28
applications/gpio/gpio_app_i.h
Normal file
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "gpio_app.h"
|
||||
#include "gpio_item.h"
|
||||
#include "scenes/gpio_scene.h"
|
||||
|
||||
#include <gui/gui.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/scene_manager.h>
|
||||
#include <notification/notification-messages.h>
|
||||
|
||||
#include <gui/modules/variable-item-list.h>
|
||||
#include "views/gpio_test.h"
|
||||
|
||||
struct GpioApp {
|
||||
Gui* gui;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
SceneManager* scene_manager;
|
||||
NotificationApp* notifications;
|
||||
|
||||
VariableItemList* var_item_list;
|
||||
GpioTest* gpio_test;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
GpioAppViewVarItemList,
|
||||
GpioAppViewGpioTest,
|
||||
} GpioAppView;
|
||||
51
applications/gpio/gpio_item.c
Normal file
51
applications/gpio/gpio_item.c
Normal file
@ -0,0 +1,51 @@
|
||||
#include "gpio_item.h"
|
||||
|
||||
#include <furi-hal-resources.h>
|
||||
|
||||
typedef struct {
|
||||
const char* name;
|
||||
const GpioPin* pin;
|
||||
} GpioItem;
|
||||
|
||||
static const GpioItem gpio_item[GPIO_ITEM_COUNT] = {
|
||||
{"1.2: PA7", &gpio_ext_pa7},
|
||||
{"1.3: PA6", &gpio_ext_pa6},
|
||||
{"1.4: PA4", &gpio_ext_pa4},
|
||||
{"1.5: PB3", &gpio_ext_pb3},
|
||||
{"1.6: PB2", &gpio_ext_pb2},
|
||||
{"1.7: PC3", &gpio_ext_pc3},
|
||||
{"2.7: PC1", &gpio_ext_pc1},
|
||||
{"2.8: PC0", &gpio_ext_pc0},
|
||||
};
|
||||
|
||||
void gpio_item_configure_pin(uint8_t index, GpioMode mode) {
|
||||
furi_assert(index < GPIO_ITEM_COUNT);
|
||||
hal_gpio_write(gpio_item[index].pin, false);
|
||||
hal_gpio_init(gpio_item[index].pin, mode, GpioPullNo, GpioSpeedVeryHigh);
|
||||
}
|
||||
|
||||
void gpio_item_configure_all_pins(GpioMode mode) {
|
||||
for(uint8_t i = 0; i < GPIO_ITEM_COUNT; i++) {
|
||||
gpio_item_configure_pin(i, mode);
|
||||
}
|
||||
}
|
||||
|
||||
void gpio_item_set_pin(uint8_t index, bool level) {
|
||||
furi_assert(index < GPIO_ITEM_COUNT);
|
||||
hal_gpio_write(gpio_item[index].pin, level);
|
||||
}
|
||||
|
||||
void gpio_item_set_all_pins(bool level) {
|
||||
for(uint8_t i = 0; i < GPIO_ITEM_COUNT; i++) {
|
||||
gpio_item_set_pin(i, level);
|
||||
}
|
||||
}
|
||||
|
||||
const char* gpio_item_get_pin_name(uint8_t index) {
|
||||
furi_assert(index < GPIO_ITEM_COUNT + 1);
|
||||
if(index == GPIO_ITEM_COUNT) {
|
||||
return "ALL";
|
||||
} else {
|
||||
return gpio_item[index].name;
|
||||
}
|
||||
}
|
||||
15
applications/gpio/gpio_item.h
Normal file
15
applications/gpio/gpio_item.h
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi-hal-gpio.h>
|
||||
|
||||
#define GPIO_ITEM_COUNT 8
|
||||
|
||||
void gpio_item_configure_pin(uint8_t index, GpioMode mode);
|
||||
|
||||
void gpio_item_configure_all_pins(GpioMode mode);
|
||||
|
||||
void gpio_item_set_pin(uint8_t index, bool level);
|
||||
|
||||
void gpio_item_set_all_pins(bool level);
|
||||
|
||||
const char* gpio_item_get_pin_name(uint8_t index);
|
||||
30
applications/gpio/scenes/gpio_scene.c
Normal file
30
applications/gpio/scenes/gpio_scene.c
Normal file
@ -0,0 +1,30 @@
|
||||
#include "gpio_scene.h"
|
||||
|
||||
// Generate scene on_enter handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
|
||||
void (*const gpio_scene_on_enter_handlers[])(void*) = {
|
||||
#include "gpio_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_event handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
|
||||
bool (*const gpio_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = {
|
||||
#include "gpio_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_exit handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
|
||||
void (*const gpio_scene_on_exit_handlers[])(void* context) = {
|
||||
#include "gpio_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Initialize scene handlers configuration structure
|
||||
const SceneManagerHandlers gpio_scene_handlers = {
|
||||
.on_enter_handlers = gpio_scene_on_enter_handlers,
|
||||
.on_event_handlers = gpio_scene_on_event_handlers,
|
||||
.on_exit_handlers = gpio_scene_on_exit_handlers,
|
||||
.scene_num = GpioSceneNum,
|
||||
};
|
||||
29
applications/gpio/scenes/gpio_scene.h
Normal file
29
applications/gpio/scenes/gpio_scene.h
Normal file
@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/scene_manager.h>
|
||||
|
||||
// Generate scene id and total number
|
||||
#define ADD_SCENE(prefix, name, id) GpioScene##id,
|
||||
typedef enum {
|
||||
#include "gpio_scene_config.h"
|
||||
GpioSceneNum,
|
||||
} GpioScene;
|
||||
#undef ADD_SCENE
|
||||
|
||||
extern const SceneManagerHandlers gpio_scene_handlers;
|
||||
|
||||
// Generate scene on_enter handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
|
||||
#include "gpio_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_event handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) \
|
||||
bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
|
||||
#include "gpio_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_exit handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
|
||||
#include "gpio_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
2
applications/gpio/scenes/gpio_scene_config.h
Normal file
2
applications/gpio/scenes/gpio_scene_config.h
Normal file
@ -0,0 +1,2 @@
|
||||
ADD_SCENE(gpio, start, Start)
|
||||
ADD_SCENE(gpio, test, Test)
|
||||
92
applications/gpio/scenes/gpio_scene_start.c
Executable file
92
applications/gpio/scenes/gpio_scene_start.c
Executable file
@ -0,0 +1,92 @@
|
||||
#include "../gpio_app_i.h"
|
||||
#include "furi-hal-power.h"
|
||||
|
||||
#define GPIO_SCENE_START_CUSTOM_EVENT_OTG_OFF (0UL)
|
||||
#define GPIO_SCENE_START_CUSTOM_EVENT_OTG_ON (1UL)
|
||||
#define GPIO_SCENE_START_CUSTOM_EVENT_TEST (2UL)
|
||||
|
||||
enum GpioItem {
|
||||
GpioItemOtg,
|
||||
GpioItemTest,
|
||||
};
|
||||
|
||||
enum GpioOtg {
|
||||
GpioOtgOff,
|
||||
GpioOtgOn,
|
||||
GpioOtgSettingsNum,
|
||||
};
|
||||
|
||||
const char* const gpio_otg_text[GpioOtgSettingsNum] = {
|
||||
"Off",
|
||||
"On",
|
||||
};
|
||||
|
||||
static void gpio_scene_start_var_list_enter_callback(void* context, uint32_t index) {
|
||||
furi_assert(context);
|
||||
GpioApp* app = context;
|
||||
if(index == GpioItemTest) {
|
||||
view_dispatcher_send_custom_event(
|
||||
app->view_dispatcher, GPIO_SCENE_START_CUSTOM_EVENT_TEST);
|
||||
}
|
||||
}
|
||||
|
||||
static void gpio_scene_start_var_list_change_callback(VariableItem* item) {
|
||||
GpioApp* app = variable_item_get_context(item);
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
|
||||
variable_item_set_current_value_text(item, gpio_otg_text[index]);
|
||||
if(index == GpioOtgOff) {
|
||||
view_dispatcher_send_custom_event(
|
||||
app->view_dispatcher, GPIO_SCENE_START_CUSTOM_EVENT_OTG_OFF);
|
||||
} else if(index == GpioOtgOn) {
|
||||
view_dispatcher_send_custom_event(
|
||||
app->view_dispatcher, GPIO_SCENE_START_CUSTOM_EVENT_OTG_ON);
|
||||
}
|
||||
}
|
||||
|
||||
void gpio_scene_start_on_enter(void* context) {
|
||||
GpioApp* app = context;
|
||||
VariableItemList* var_item_list = app->var_item_list;
|
||||
|
||||
VariableItem* item;
|
||||
variable_item_list_set_enter_callback(
|
||||
var_item_list, gpio_scene_start_var_list_enter_callback, app);
|
||||
item = variable_item_list_add(
|
||||
var_item_list,
|
||||
"5V on GPIO",
|
||||
GpioOtgSettingsNum,
|
||||
gpio_scene_start_var_list_change_callback,
|
||||
app);
|
||||
if(furi_hal_power_is_otg_enabled()) {
|
||||
variable_item_set_current_value_index(item, GpioOtgOn);
|
||||
variable_item_set_current_value_text(item, gpio_otg_text[GpioOtgOn]);
|
||||
} else {
|
||||
variable_item_set_current_value_index(item, GpioOtgOff);
|
||||
variable_item_set_current_value_text(item, gpio_otg_text[GpioOtgOff]);
|
||||
}
|
||||
variable_item_list_add(var_item_list, "GPIO tester", 0, NULL, NULL);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, GpioAppViewVarItemList);
|
||||
}
|
||||
|
||||
bool gpio_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||
GpioApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == GPIO_SCENE_START_CUSTOM_EVENT_OTG_ON) {
|
||||
furi_hal_power_enable_otg();
|
||||
} else if(event.event == GPIO_SCENE_START_CUSTOM_EVENT_OTG_OFF) {
|
||||
furi_hal_power_disable_otg();
|
||||
} else if(event.event == GPIO_SCENE_START_CUSTOM_EVENT_TEST) {
|
||||
scene_manager_next_scene(app->scene_manager, GpioSceneTest);
|
||||
}
|
||||
consumed = true;
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void gpio_scene_start_on_exit(void* context) {
|
||||
GpioApp* app = context;
|
||||
variable_item_list_clean(app->var_item_list);
|
||||
}
|
||||
27
applications/gpio/scenes/gpio_scene_test.c
Normal file
27
applications/gpio/scenes/gpio_scene_test.c
Normal file
@ -0,0 +1,27 @@
|
||||
#include "../gpio_app_i.h"
|
||||
|
||||
void gpio_scene_test_ok_callback(InputType type, void* context) {
|
||||
furi_assert(context);
|
||||
GpioApp* app = context;
|
||||
|
||||
if(type == InputTypePress) {
|
||||
notification_message(app->notifications, &sequence_set_green_255);
|
||||
} else if(type == InputTypeRelease) {
|
||||
notification_message(app->notifications, &sequence_reset_green);
|
||||
}
|
||||
}
|
||||
|
||||
void gpio_scene_test_on_enter(void* context) {
|
||||
GpioApp* app = context;
|
||||
gpio_item_configure_all_pins(GpioModeOutputPushPull);
|
||||
gpio_test_set_ok_callback(app->gpio_test, gpio_scene_test_ok_callback, app);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, GpioAppViewGpioTest);
|
||||
}
|
||||
|
||||
bool gpio_scene_test_on_event(void* context, SceneManagerEvent event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void gpio_scene_test_on_exit(void* context) {
|
||||
gpio_item_configure_all_pins(GpioModeAnalog);
|
||||
}
|
||||
130
applications/gpio/views/gpio_test.c
Executable file
130
applications/gpio/views/gpio_test.c
Executable file
@ -0,0 +1,130 @@
|
||||
#include "gpio_test.h"
|
||||
#include "../gpio_item.h"
|
||||
|
||||
#include <gui/elements.h>
|
||||
|
||||
struct GpioTest {
|
||||
View* view;
|
||||
GpioTestOkCallback callback;
|
||||
void* context;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint8_t pin_idx;
|
||||
} GpioTestModel;
|
||||
|
||||
static bool gpio_test_process_left(GpioTest* gpio_test);
|
||||
static bool gpio_test_process_right(GpioTest* gpio_test);
|
||||
static bool gpio_test_process_ok(GpioTest* gpio_test, InputEvent* event);
|
||||
|
||||
static void gpio_test_draw_callback(Canvas* canvas, void* _model) {
|
||||
GpioTestModel* model = _model;
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
elements_multiline_text_aligned(canvas, 64, 2, AlignCenter, AlignTop, "Gpio Output mode test");
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
elements_multiline_text_aligned(
|
||||
canvas, 64, 16, AlignCenter, AlignTop, "Press < or > to change pin");
|
||||
elements_multiline_text_aligned(
|
||||
canvas, 64, 32, AlignCenter, AlignTop, gpio_item_get_pin_name(model->pin_idx));
|
||||
}
|
||||
|
||||
static bool gpio_test_input_callback(InputEvent* event, void* context) {
|
||||
furi_assert(context);
|
||||
GpioTest* gpio_test = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == InputTypeShort) {
|
||||
if(event->key == InputKeyRight) {
|
||||
consumed = gpio_test_process_right(gpio_test);
|
||||
} else if(event->key == InputKeyLeft) {
|
||||
consumed = gpio_test_process_left(gpio_test);
|
||||
}
|
||||
} else if(event->key == InputKeyOk) {
|
||||
consumed = gpio_test_process_ok(gpio_test, event);
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
static bool gpio_test_process_left(GpioTest* gpio_test) {
|
||||
with_view_model(
|
||||
gpio_test->view, (GpioTestModel * model) {
|
||||
if(model->pin_idx) {
|
||||
model->pin_idx--;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool gpio_test_process_right(GpioTest* gpio_test) {
|
||||
with_view_model(
|
||||
gpio_test->view, (GpioTestModel * model) {
|
||||
if(model->pin_idx < GPIO_ITEM_COUNT) {
|
||||
model->pin_idx++;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool gpio_test_process_ok(GpioTest* gpio_test, InputEvent* event) {
|
||||
bool consumed = false;
|
||||
|
||||
with_view_model(
|
||||
gpio_test->view, (GpioTestModel * model) {
|
||||
if(event->type == InputTypePress) {
|
||||
if(model->pin_idx < GPIO_ITEM_COUNT) {
|
||||
gpio_item_set_pin(model->pin_idx, true);
|
||||
} else {
|
||||
gpio_item_set_all_pins(true);
|
||||
}
|
||||
consumed = true;
|
||||
} else if(event->type == InputTypeRelease) {
|
||||
if(model->pin_idx < GPIO_ITEM_COUNT) {
|
||||
gpio_item_set_pin(model->pin_idx, false);
|
||||
} else {
|
||||
gpio_item_set_all_pins(false);
|
||||
}
|
||||
consumed = true;
|
||||
}
|
||||
gpio_test->callback(event->type, gpio_test->context);
|
||||
return true;
|
||||
});
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
GpioTest* gpio_test_alloc() {
|
||||
GpioTest* gpio_test = furi_alloc(sizeof(GpioTest));
|
||||
|
||||
gpio_test->view = view_alloc();
|
||||
view_allocate_model(gpio_test->view, ViewModelTypeLocking, sizeof(GpioTestModel));
|
||||
view_set_context(gpio_test->view, gpio_test);
|
||||
view_set_draw_callback(gpio_test->view, gpio_test_draw_callback);
|
||||
view_set_input_callback(gpio_test->view, gpio_test_input_callback);
|
||||
|
||||
return gpio_test;
|
||||
}
|
||||
|
||||
void gpio_test_free(GpioTest* gpio_test) {
|
||||
furi_assert(gpio_test);
|
||||
view_free(gpio_test->view);
|
||||
free(gpio_test);
|
||||
}
|
||||
|
||||
View* gpio_test_get_view(GpioTest* gpio_test) {
|
||||
furi_assert(gpio_test);
|
||||
return gpio_test->view;
|
||||
}
|
||||
|
||||
void gpio_test_set_ok_callback(GpioTest* gpio_test, GpioTestOkCallback callback, void* context) {
|
||||
furi_assert(gpio_test);
|
||||
furi_assert(callback);
|
||||
with_view_model(
|
||||
gpio_test->view, (GpioTestModel * model) {
|
||||
gpio_test->callback = callback;
|
||||
gpio_test->context = context;
|
||||
return false;
|
||||
});
|
||||
}
|
||||
14
applications/gpio/views/gpio_test.h
Executable file
14
applications/gpio/views/gpio_test.h
Executable file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
|
||||
typedef struct GpioTest GpioTest;
|
||||
typedef void (*GpioTestOkCallback)(InputType type, void* context);
|
||||
|
||||
GpioTest* gpio_test_alloc();
|
||||
|
||||
void gpio_test_free(GpioTest* gpio_test);
|
||||
|
||||
View* gpio_test_get_view(GpioTest* gpio_test);
|
||||
|
||||
void gpio_test_set_ok_callback(GpioTest* gpio_test, GpioTestOkCallback callback, void* context);
|
||||
@ -110,11 +110,13 @@ void canvas_set_font(Canvas* canvas, Font font) {
|
||||
furi_assert(canvas);
|
||||
u8g2_SetFontMode(&canvas->fb, 1);
|
||||
if(font == FontPrimary) {
|
||||
u8g2_SetFont(&canvas->fb, u8g2_font_helvB08_tf);
|
||||
u8g2_SetFont(&canvas->fb, u8g2_font_helvB08_tr);
|
||||
} else if(font == FontSecondary) {
|
||||
u8g2_SetFont(&canvas->fb, u8g2_font_haxrcorp4089_tr);
|
||||
} else if(font == FontKeyboard) {
|
||||
u8g2_SetFont(&canvas->fb, u8g2_font_profont11_mf);
|
||||
u8g2_SetFont(&canvas->fb, u8g2_font_profont11_mr);
|
||||
} else if(font == FontBigNumbers) {
|
||||
u8g2_SetFont(&canvas->fb, u8g2_font_profont22_tn);
|
||||
} else {
|
||||
furi_crash(NULL);
|
||||
}
|
||||
|
||||
@ -1,3 +1,8 @@
|
||||
/**
|
||||
* @file canvas.h
|
||||
* GUI: Canvas API
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
@ -8,13 +13,16 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Color enumeration */
|
||||
typedef enum {
|
||||
ColorWhite = 0x00,
|
||||
ColorBlack = 0x01,
|
||||
} Color;
|
||||
|
||||
typedef enum { FontPrimary, FontSecondary, FontKeyboard } Font;
|
||||
/** Fonts enumeration */
|
||||
typedef enum { FontPrimary, FontSecondary, FontKeyboard, FontBigNumbers } Font;
|
||||
|
||||
/** Alignment enumeration */
|
||||
typedef enum {
|
||||
AlignLeft,
|
||||
AlignRight,
|
||||
@ -23,59 +31,85 @@ typedef enum {
|
||||
AlignCenter,
|
||||
} Align;
|
||||
|
||||
/** Canvas Orientation */
|
||||
typedef enum {
|
||||
CanvasOrientationHorizontal,
|
||||
CanvasOrientationVertical,
|
||||
} CanvasOrientation;
|
||||
|
||||
/** Canvas anonymouse structure */
|
||||
typedef struct Canvas Canvas;
|
||||
|
||||
/*
|
||||
* Canvas width
|
||||
* @return width in pixels.
|
||||
/** Get Canvas width
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
*
|
||||
* @return width in pixels.
|
||||
*/
|
||||
uint8_t canvas_width(Canvas* canvas);
|
||||
|
||||
/*
|
||||
* Canvas height
|
||||
* @return height in pixels.
|
||||
/** Get Canvas height
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
*
|
||||
* @return height in pixels.
|
||||
*/
|
||||
uint8_t canvas_height(Canvas* canvas);
|
||||
|
||||
/*
|
||||
* Get current font height
|
||||
* @return height in pixels.
|
||||
/** Get current font height
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
*
|
||||
* @return height in pixels.
|
||||
*/
|
||||
uint8_t canvas_current_font_height(Canvas* canvas);
|
||||
|
||||
/*
|
||||
* Clear canvas, clear rendering buffer
|
||||
/** Clear canvas
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
*/
|
||||
void canvas_clear(Canvas* canvas);
|
||||
|
||||
/*
|
||||
* Set drawing color
|
||||
/** Set drawing color
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
* @param color Color
|
||||
*/
|
||||
void canvas_set_color(Canvas* canvas, Color color);
|
||||
|
||||
/*
|
||||
* Invert drawing color
|
||||
/** Invert drawing color
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
*/
|
||||
void canvas_invert_color(Canvas* canvas);
|
||||
|
||||
/*
|
||||
* Set drawing font
|
||||
/** Set drawing font
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
* @param font Font
|
||||
*/
|
||||
void canvas_set_font(Canvas* canvas, Font font);
|
||||
|
||||
/*
|
||||
* Draw string at position of baseline defined by x, y.
|
||||
/** Draw string at position of baseline defined by x, y.
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
* @param x anchor point x coordinate
|
||||
* @param y anchor point y coordinate
|
||||
* @param str C-string
|
||||
*/
|
||||
void canvas_draw_str(Canvas* canvas, uint8_t x, uint8_t y, const char* str);
|
||||
|
||||
/*
|
||||
* Draw aligned string defined by x, y.
|
||||
* Align calculated from position of baseline, string width and ascent (height of the glyphs above the baseline)
|
||||
/** Draw aligned string defined by x, y.
|
||||
*
|
||||
* Align calculated from position of baseline, string width and ascent (height
|
||||
* of the glyphs above the baseline)
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
* @param x anchor point x coordinate
|
||||
* @param y anchor point y coordinate
|
||||
* @param horizontal horizontal alignment
|
||||
* @param vertical vertical alignment
|
||||
* @param str C-string
|
||||
*/
|
||||
void canvas_draw_str_aligned(
|
||||
Canvas* canvas,
|
||||
@ -85,22 +119,30 @@ void canvas_draw_str_aligned(
|
||||
Align vertical,
|
||||
const char* str);
|
||||
|
||||
/*
|
||||
* Get string width
|
||||
* @return width in pixels.
|
||||
/** Get string width
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
* @param str C-string
|
||||
*
|
||||
* @return width in pixels.
|
||||
*/
|
||||
uint16_t canvas_string_width(Canvas* canvas, const char* str);
|
||||
|
||||
/** Get glyph width
|
||||
* @return width in pixels
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
* @param[in] symbol character
|
||||
*
|
||||
* @return width in pixels
|
||||
*/
|
||||
uint8_t canvas_glyph_width(Canvas* canvas, char symbol);
|
||||
|
||||
/** Draw animation at position defined by x,y.
|
||||
* @param canvas - canvas instance
|
||||
* @param x - x coordinate
|
||||
* @param y - y coordinate
|
||||
* @param icon_animation - data pointer to IconAnimation
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
* @param x x coordinate
|
||||
* @param y y coordinate
|
||||
* @param icon_animation IconAnimation instance
|
||||
*/
|
||||
void canvas_draw_icon_animation(
|
||||
Canvas* canvas,
|
||||
@ -109,15 +151,22 @@ void canvas_draw_icon_animation(
|
||||
IconAnimation* icon_animation);
|
||||
|
||||
/** Draw icon at position defined by x,y.
|
||||
* @param canvas - canvas instance
|
||||
* @param x - x coordinate
|
||||
* @param y - y coordinate
|
||||
* @param icon - data pointer to Icon
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
* @param x x coordinate
|
||||
* @param y y coordinate
|
||||
* @param icon Icon instance
|
||||
*/
|
||||
void canvas_draw_icon(Canvas* canvas, uint8_t x, uint8_t y, const Icon* icon);
|
||||
|
||||
/*
|
||||
* Draw xbm icon of width, height at position defined by x,y.
|
||||
/** Draw XBM bitmap
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
* @param x x coordinate
|
||||
* @param y y coordinate
|
||||
* @param w bitmap width
|
||||
* @param h bitmap height
|
||||
* @param bitmap pointer to XBM bitmap data
|
||||
*/
|
||||
void canvas_draw_xbm(
|
||||
Canvas* canvas,
|
||||
@ -127,48 +176,86 @@ void canvas_draw_xbm(
|
||||
uint8_t h,
|
||||
const uint8_t* bitmap);
|
||||
|
||||
/*
|
||||
* Draw dot at x,y
|
||||
/** Draw dot at x,y
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
* @param x x coordinate
|
||||
* @param y y coordinate
|
||||
*/
|
||||
void canvas_draw_dot(Canvas* canvas, uint8_t x, uint8_t y);
|
||||
|
||||
/*
|
||||
* Draw box of width, height at x,y
|
||||
/** Draw box of width, height at x,y
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
* @param x x coordinate
|
||||
* @param y y coordinate
|
||||
* @param width box width
|
||||
* @param height box height
|
||||
*/
|
||||
void canvas_draw_box(Canvas* canvas, uint8_t x, uint8_t y, uint8_t width, uint8_t height);
|
||||
|
||||
/*
|
||||
* Draw frame of width, height at x,y
|
||||
/** Draw frame of width, height at x,y
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
* @param x x coordinate
|
||||
* @param y y coordinate
|
||||
* @param width frame width
|
||||
* @param height frame height
|
||||
*/
|
||||
void canvas_draw_frame(Canvas* canvas, uint8_t x, uint8_t y, uint8_t width, uint8_t height);
|
||||
|
||||
/*
|
||||
* Draw line from x1,y1 to x2,y2
|
||||
/** Draw line from x1,y1 to x2,y2
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
* @param x1 x1 coordinate
|
||||
* @param y1 y1 coordinate
|
||||
* @param x2 x2 coordinate
|
||||
* @param y2 y2 coordinate
|
||||
*/
|
||||
void canvas_draw_line(Canvas* canvas, uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2);
|
||||
|
||||
/*
|
||||
* Draw circle at x,y with radius r
|
||||
/** Draw circle at x,y with radius r
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
* @param x x coordinate
|
||||
* @param y y coordinate
|
||||
* @param r radius
|
||||
*/
|
||||
void canvas_draw_circle(Canvas* canvas, uint8_t x, uint8_t y, uint8_t r);
|
||||
|
||||
/*
|
||||
* Draw disc at x,y with radius r
|
||||
/** Draw disc at x,y with radius r
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
* @param x x coordinate
|
||||
* @param y y coordinate
|
||||
* @param r radius
|
||||
*/
|
||||
void canvas_draw_disc(Canvas* canvas, uint8_t x, uint8_t y, uint8_t r);
|
||||
|
||||
/*
|
||||
* Draw glyph
|
||||
/** Draw glyph
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
* @param x x coordinate
|
||||
* @param y y coordinate
|
||||
* @param ch character
|
||||
*/
|
||||
void canvas_draw_glyph(Canvas* canvas, uint8_t x, uint8_t y, uint16_t ch);
|
||||
|
||||
/*
|
||||
* Set transparency mode
|
||||
/** Set transparency mode
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
* @param alpha transparency mode
|
||||
*/
|
||||
void canvas_set_bitmap_mode(Canvas* canvas, bool alpha);
|
||||
|
||||
/*
|
||||
* Draw rounded-corner frame of width, height at x,y, with round value raduis
|
||||
/** Draw rounded-corner frame of width, height at x,y, with round value raduis
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
* @param x x coordinate
|
||||
* @param y y coordinate
|
||||
* @param width frame width
|
||||
* @param height frame height
|
||||
* @param radius frame corner radius
|
||||
*/
|
||||
void canvas_draw_rframe(
|
||||
Canvas* canvas,
|
||||
@ -178,8 +265,14 @@ void canvas_draw_rframe(
|
||||
uint8_t height,
|
||||
uint8_t radius);
|
||||
|
||||
/*
|
||||
* Draw rounded-corner box of width, height at x,y, with round value raduis
|
||||
/** Draw rounded-corner box of width, height at x,y, with round value raduis
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
* @param x x coordinate
|
||||
* @param y y coordinate
|
||||
* @param width box width
|
||||
* @param height box height
|
||||
* @param radius box corner radius
|
||||
*/
|
||||
void canvas_draw_rbox(
|
||||
Canvas* canvas,
|
||||
|
||||
@ -1,8 +1,15 @@
|
||||
/**
|
||||
* @file canvas_i.h
|
||||
* GUI: internal Canvas API
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "canvas.h"
|
||||
#include <u8g2.h>
|
||||
|
||||
/** Canvas structure
|
||||
*/
|
||||
struct Canvas {
|
||||
u8g2_t fb;
|
||||
CanvasOrientation orientation;
|
||||
@ -12,40 +19,53 @@ struct Canvas {
|
||||
uint8_t height;
|
||||
};
|
||||
|
||||
/*
|
||||
* Allocate memory and initialize canvas
|
||||
/** Allocate memory and initialize canvas
|
||||
*
|
||||
* @return Canvas instance
|
||||
*/
|
||||
Canvas* canvas_init();
|
||||
|
||||
/*
|
||||
* Free canvas memory
|
||||
/** Free canvas memory
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
*/
|
||||
void canvas_free(Canvas* canvas);
|
||||
|
||||
/*
|
||||
* Reset canvas drawing tools configuration
|
||||
/** Reset canvas drawing tools configuration
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
*/
|
||||
void canvas_reset(Canvas* canvas);
|
||||
|
||||
/*
|
||||
* Commit canvas. Send buffer to display
|
||||
/** Commit canvas. Send buffer to display
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
*/
|
||||
void canvas_commit(Canvas* canvas);
|
||||
|
||||
/*
|
||||
* Get canvas buffer.
|
||||
* @return pointer to buffer
|
||||
/** Get canvas buffer.
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
*
|
||||
* @return pointer to buffer
|
||||
*/
|
||||
uint8_t* canvas_get_buffer(Canvas* canvas);
|
||||
|
||||
/*
|
||||
* Get canvas buffer size.
|
||||
* @return size of canvas in bytes
|
||||
/** Get canvas buffer size.
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
*
|
||||
* @return size of canvas in bytes
|
||||
*/
|
||||
size_t canvas_get_buffer_size(Canvas* canvas);
|
||||
|
||||
/*
|
||||
* Set drawing region relative to real screen buffer
|
||||
/** Set drawing region relative to real screen buffer
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
* @param offset_x x coordinate offset
|
||||
* @param offset_y y coordinate offset
|
||||
* @param width width
|
||||
* @param height height
|
||||
*/
|
||||
void canvas_frame_set(
|
||||
Canvas* canvas,
|
||||
@ -54,12 +74,17 @@ void canvas_frame_set(
|
||||
uint8_t width,
|
||||
uint8_t height);
|
||||
|
||||
/*
|
||||
* Set canvas orientation
|
||||
/** Set canvas orientation
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
* @param orientation CanvasOrientation
|
||||
*/
|
||||
void canvas_set_orientation(Canvas* canvas, CanvasOrientation orientation);
|
||||
|
||||
/*
|
||||
* Get canvas orientation
|
||||
/** Get canvas orientation
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
*
|
||||
* @return CanvasOrientation
|
||||
*/
|
||||
CanvasOrientation canvas_get_orientation(const Canvas* canvas);
|
||||
|
||||
@ -278,7 +278,7 @@ void elements_multiline_text(Canvas* canvas, uint8_t x, uint8_t y, const char* t
|
||||
canvas_draw_str(canvas, x, y, string_get_cstr(str));
|
||||
start = end + 1;
|
||||
y += font_height;
|
||||
} while(end);
|
||||
} while(end && y < 64);
|
||||
string_clear(str);
|
||||
}
|
||||
|
||||
|
||||
@ -1,3 +1,11 @@
|
||||
/**
|
||||
* @file elements.h
|
||||
* GUI: Elements API
|
||||
*
|
||||
* Canvas helpers and UI building blocks.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
@ -335,7 +335,7 @@ void gui_remove_view_port(Gui* gui, ViewPort* view_port) {
|
||||
gui_unlock(gui);
|
||||
}
|
||||
|
||||
void gui_send_view_port_front(Gui* gui, ViewPort* view_port) {
|
||||
void gui_view_port_send_to_front(Gui* gui, ViewPort* view_port) {
|
||||
furi_assert(gui);
|
||||
furi_assert(view_port);
|
||||
|
||||
@ -361,7 +361,7 @@ void gui_send_view_port_front(Gui* gui, ViewPort* view_port) {
|
||||
gui_unlock(gui);
|
||||
}
|
||||
|
||||
void gui_send_view_port_back(Gui* gui, ViewPort* view_port) {
|
||||
void gui_view_port_send_to_back(Gui* gui, ViewPort* view_port) {
|
||||
furi_assert(gui);
|
||||
furi_assert(view_port);
|
||||
|
||||
|
||||
@ -1,3 +1,8 @@
|
||||
/**
|
||||
* @file gui.h
|
||||
* GUI: main API
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "view_port.h"
|
||||
@ -7,60 +12,74 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Gui layers */
|
||||
/** Gui layers */
|
||||
typedef enum {
|
||||
GuiLayerNone, /* Special layer for internal use only */
|
||||
GuiLayerNone, /**< Special layer for internal use only */
|
||||
|
||||
GuiLayerStatusBarLeft, /* Status bar left-side layer, auto-layout */
|
||||
GuiLayerStatusBarRight, /* Status bar right-side layer, auto-layout */
|
||||
GuiLayerMain, /* Main layer, status bar is shown */
|
||||
GuiLayerFullscreen, /* Fullscreen layer */
|
||||
GuiLayerStatusBarLeft, /**< Status bar left-side layer, auto-layout */
|
||||
GuiLayerStatusBarRight, /**< Status bar right-side layer, auto-layout */
|
||||
GuiLayerMain, /**< Main layer, status bar is shown */
|
||||
GuiLayerFullscreen, /**< Fullscreen layer */
|
||||
|
||||
GuiLayerMAX /* Don't use or move, special value */
|
||||
GuiLayerMAX /**< Don't use or move, special value */
|
||||
} GuiLayer;
|
||||
|
||||
/* Gui frame buffer callback */
|
||||
/** Gui Canvas Commit Callback */
|
||||
typedef void (*GuiCanvasCommitCallback)(uint8_t* data, size_t size, void* context);
|
||||
|
||||
typedef struct Gui Gui;
|
||||
|
||||
/*
|
||||
* Add view_port to view_port tree
|
||||
* @remarks thread safe
|
||||
/** Add view_port to view_port tree
|
||||
*
|
||||
* @remark thread safe
|
||||
*
|
||||
* @param gui Gui instance
|
||||
* @param view_port ViewPort instance
|
||||
* @param[in] layer GuiLayer where to place view_port
|
||||
*/
|
||||
void gui_add_view_port(Gui* gui, ViewPort* view_port, GuiLayer layer);
|
||||
|
||||
/*
|
||||
* Remove view_port from rendering tree
|
||||
* @remarks thread safe
|
||||
/** Remove view_port from rendering tree
|
||||
*
|
||||
* @remark thread safe
|
||||
*
|
||||
* @param gui Gui instance
|
||||
* @param view_port ViewPort instance
|
||||
*/
|
||||
void gui_remove_view_port(Gui* gui, ViewPort* view_port);
|
||||
|
||||
/* Send ViewPort to the front
|
||||
/** Send ViewPort to the front
|
||||
*
|
||||
* Places selected ViewPort to the top of the drawing stack
|
||||
* @param gui - Gui instance
|
||||
* @param view_port - ViewPort instance
|
||||
*
|
||||
* @param gui Gui instance
|
||||
* @param view_port ViewPort instance
|
||||
*/
|
||||
void gui_send_view_port_front(Gui* gui, ViewPort* view_port);
|
||||
void gui_view_port_send_to_front(Gui* gui, ViewPort* view_port);
|
||||
|
||||
/* Send ViewPort to the back
|
||||
/** Send ViewPort to the back
|
||||
*
|
||||
* Places selected ViewPort to the bottom of the drawing stack
|
||||
* @param gui - Gui instance
|
||||
* @param view_port - ViewPort instance
|
||||
*
|
||||
* @param gui Gui instance
|
||||
* @param view_port ViewPort instance
|
||||
*/
|
||||
void gui_send_view_port_back(Gui* gui, ViewPort* view_port);
|
||||
void gui_view_port_send_to_back(Gui* gui, ViewPort* view_port);
|
||||
|
||||
/* Set gui canvas commit callback
|
||||
* This callback will be called upon Canvas commit
|
||||
* Callback dispatched from GUI thread and is time critical
|
||||
* @param gui - Gui instance
|
||||
* @param callback - GuiCanvasCommitCallback
|
||||
/** Set gui canvas commit callback
|
||||
*
|
||||
* This callback will be called upon Canvas commit Callback dispatched from GUI
|
||||
* thread and is time critical
|
||||
*
|
||||
* @param gui Gui instance
|
||||
* @param callback GuiCanvasCommitCallback
|
||||
*/
|
||||
void gui_set_framebuffer_callback(Gui* gui, GuiCanvasCommitCallback callback);
|
||||
|
||||
/* Set gui canvas commit callback context
|
||||
* @param gui - Gui instance
|
||||
* @param context - pointer to context
|
||||
/** Set gui canvas commit callback context
|
||||
*
|
||||
* @param gui Gui instance
|
||||
* @param context pointer to context
|
||||
*/
|
||||
void gui_set_framebuffer_callback_context(Gui* gui, void* context);
|
||||
|
||||
|
||||
@ -1,3 +1,8 @@
|
||||
/**
|
||||
* @file gui_i.h
|
||||
* GUI: main API internals
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gui.h"
|
||||
@ -31,6 +36,7 @@
|
||||
|
||||
ARRAY_DEF(ViewPortArray, ViewPort*, M_PTR_OPLIST);
|
||||
|
||||
/** Gui structure */
|
||||
struct Gui {
|
||||
// Thread and lock
|
||||
osThreadId_t thread;
|
||||
@ -54,8 +60,9 @@ struct Gui {
|
||||
|
||||
ViewPort* gui_view_port_find_enabled(ViewPortArray_t array);
|
||||
|
||||
/* Update GUI, request redraw
|
||||
* @param gui, Gui instance
|
||||
/** Update GUI, request redraw
|
||||
*
|
||||
* @param gui Gui instance
|
||||
*/
|
||||
void gui_update(Gui* gui);
|
||||
|
||||
@ -67,4 +74,4 @@ void gui_unlock(Gui* gui);
|
||||
|
||||
void gui_cli_screen_stream_callback(uint8_t* data, size_t size, void* context);
|
||||
|
||||
void gui_cli_screen_stream(Cli* cli, string_t args, void* context);
|
||||
void gui_cli_screen_stream(Cli* cli, string_t args, void* context);
|
||||
|
||||
@ -1,3 +1,8 @@
|
||||
/**
|
||||
* @file icon.h
|
||||
* GUI: Icon API
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
@ -8,10 +13,28 @@ extern "C" {
|
||||
|
||||
typedef struct Icon Icon;
|
||||
|
||||
/** Get icon width
|
||||
*
|
||||
* @param[in] instance pointer to Icon data
|
||||
*
|
||||
* @return width in pixels
|
||||
*/
|
||||
uint8_t icon_get_width(const Icon* instance);
|
||||
|
||||
/** Get icon height
|
||||
*
|
||||
* @param[in] instance pointer to Icon data
|
||||
*
|
||||
* @return height in pixels
|
||||
*/
|
||||
uint8_t icon_get_height(const Icon* instance);
|
||||
|
||||
/** Get Icon XBM bitmap data
|
||||
*
|
||||
* @param[in] instance pointer to Icon data
|
||||
*
|
||||
* @return pointer to XBM bitmap data
|
||||
*/
|
||||
const uint8_t* icon_get_data(const Icon* instance);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@ -2,31 +2,32 @@
|
||||
#include "icon_i.h"
|
||||
|
||||
#include <furi.h>
|
||||
#include <timers.h>
|
||||
|
||||
IconAnimation* icon_animation_alloc(const Icon* icon) {
|
||||
furi_assert(icon);
|
||||
IconAnimation* instance = furi_alloc(sizeof(IconAnimation));
|
||||
instance->icon = icon;
|
||||
instance->timer = osTimerNew(icon_animation_timer_callback, osTimerPeriodic, instance, NULL);
|
||||
return instance;
|
||||
}
|
||||
|
||||
void icon_animation_free(IconAnimation* instance) {
|
||||
furi_assert(instance);
|
||||
furi_check(osTimerDelete(instance->timer) == osOK);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
const uint8_t* icon_animation_get_data(IconAnimation* instance) {
|
||||
void icon_animation_set_update_callback(
|
||||
IconAnimation* instance,
|
||||
IconAnimationCallback callback,
|
||||
void* context) {
|
||||
furi_assert(instance);
|
||||
if(instance->tick) {
|
||||
uint32_t now = osKernelGetTickCount();
|
||||
if(now < instance->tick) {
|
||||
instance->tick = now;
|
||||
icon_animation_next_frame(instance);
|
||||
} else if(now - instance->tick > osKernelGetTickFreq() / instance->icon->frame_rate) {
|
||||
instance->tick = now;
|
||||
icon_animation_next_frame(instance);
|
||||
}
|
||||
}
|
||||
instance->callback = callback;
|
||||
instance->callback_context = context;
|
||||
}
|
||||
|
||||
const uint8_t* icon_animation_get_data(IconAnimation* instance) {
|
||||
return instance->icon->frames[instance->frame];
|
||||
}
|
||||
|
||||
@ -35,6 +36,19 @@ void icon_animation_next_frame(IconAnimation* instance) {
|
||||
instance->frame = (instance->frame + 1) % instance->icon->frame_count;
|
||||
}
|
||||
|
||||
void icon_animation_timer_callback(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
IconAnimation* instance = context;
|
||||
|
||||
if(!instance->animating) return;
|
||||
|
||||
icon_animation_next_frame(instance);
|
||||
if(instance->callback) {
|
||||
instance->callback(instance, instance->callback_context);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t icon_animation_get_width(IconAnimation* instance) {
|
||||
furi_assert(instance);
|
||||
return instance->icon->width;
|
||||
@ -45,33 +59,27 @@ uint8_t icon_animation_get_height(IconAnimation* instance) {
|
||||
return instance->icon->height;
|
||||
}
|
||||
|
||||
bool icon_animation_is_animated(IconAnimation* instance) {
|
||||
furi_assert(instance);
|
||||
return instance->icon->frame_count > 1;
|
||||
}
|
||||
|
||||
bool icon_animation_is_animating(IconAnimation* instance) {
|
||||
furi_assert(instance);
|
||||
return instance->tick > 0;
|
||||
}
|
||||
|
||||
void icon_animation_start(IconAnimation* instance) {
|
||||
furi_assert(instance);
|
||||
instance->tick = osKernelGetTickCount();
|
||||
if(!instance->animating) {
|
||||
instance->animating = true;
|
||||
furi_check(
|
||||
xTimerChangePeriod(
|
||||
instance->timer, (osKernelGetTickFreq() / instance->icon->frame_rate), 0) ==
|
||||
pdPASS);
|
||||
}
|
||||
}
|
||||
|
||||
void icon_animation_stop(IconAnimation* instance) {
|
||||
furi_assert(instance);
|
||||
instance->tick = 0;
|
||||
instance->frame = 0;
|
||||
}
|
||||
|
||||
uint8_t icon_animation_get_current_frame(IconAnimation* instance) {
|
||||
furi_assert(instance);
|
||||
return instance->frame;
|
||||
if(instance->animating) {
|
||||
instance->animating = false;
|
||||
furi_check(xTimerStop(instance->timer, 0) == pdPASS);
|
||||
instance->frame = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool icon_animation_is_last_frame(IconAnimation* instance) {
|
||||
furi_assert(instance);
|
||||
return instance->icon->frame_count - instance->frame <= 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,64 +1,87 @@
|
||||
/**
|
||||
* @file icon_animation.h
|
||||
* GUI: IconAnimation API
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <assets_icons.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <assets_icons.h>
|
||||
|
||||
/** Icon Animation */
|
||||
typedef struct IconAnimation IconAnimation;
|
||||
|
||||
/*
|
||||
* Allocate icon animation instance with const icon data.
|
||||
/** Icon Animation Callback. Used for update notification */
|
||||
typedef void (*IconAnimationCallback)(IconAnimation* instance, void* context);
|
||||
|
||||
/** Allocate icon animation instance with const icon data.
|
||||
*
|
||||
* always returns Icon or stops system if not enough memory
|
||||
*
|
||||
* @param[in] icon pointer to Icon data
|
||||
*
|
||||
* @return IconAnimation instance
|
||||
*/
|
||||
IconAnimation* icon_animation_alloc(const Icon* icon);
|
||||
|
||||
/*
|
||||
* Release icon animation instance
|
||||
/** Release icon animation instance
|
||||
*
|
||||
* @param instance IconAnimation instance
|
||||
*/
|
||||
void icon_animation_free(IconAnimation* instance);
|
||||
|
||||
/*
|
||||
* Get icon animation width
|
||||
/** Set IconAnimation update callback
|
||||
*
|
||||
* Normally you do not need to use this function, use view_tie_icon_animation
|
||||
* instead.
|
||||
*
|
||||
* @param instance IconAnimation instance
|
||||
* @param[in] callback IconAnimationCallback
|
||||
* @param context callback context
|
||||
*/
|
||||
void icon_animation_set_update_callback(
|
||||
IconAnimation* instance,
|
||||
IconAnimationCallback callback,
|
||||
void* context);
|
||||
|
||||
/** Get icon animation width
|
||||
*
|
||||
* @param instance IconAnimation instance
|
||||
*
|
||||
* @return width in pixels
|
||||
*/
|
||||
uint8_t icon_animation_get_width(IconAnimation* instance);
|
||||
|
||||
/*
|
||||
* Get icon animation height
|
||||
/** Get icon animation height
|
||||
*
|
||||
* @param instance IconAnimation instance
|
||||
*
|
||||
* @return height in pixels
|
||||
*/
|
||||
uint8_t icon_animation_get_height(IconAnimation* instance);
|
||||
|
||||
/*
|
||||
* Check if icon is animated
|
||||
*/
|
||||
bool icon_animation_is_animated(IconAnimation* instance);
|
||||
|
||||
/*
|
||||
* Check if icon animation is active
|
||||
*/
|
||||
bool icon_animation_is_animating(IconAnimation* instance);
|
||||
|
||||
/*
|
||||
* Start icon animation
|
||||
/** Start icon animation
|
||||
*
|
||||
* @param instance IconAnimation instance
|
||||
*/
|
||||
void icon_animation_start(IconAnimation* instance);
|
||||
|
||||
/*
|
||||
* Stop icon animation
|
||||
/** Stop icon animation
|
||||
*
|
||||
* @param instance IconAnimation instance
|
||||
*/
|
||||
void icon_animation_stop(IconAnimation* instance);
|
||||
|
||||
/*
|
||||
* Get current frame
|
||||
*/
|
||||
uint8_t icon_animation_get_current_frame(IconAnimation* instance);
|
||||
|
||||
/*
|
||||
* Returns true if current frame is a last one
|
||||
/** Returns true if current frame is a last one
|
||||
*
|
||||
* @param instance IconAnimation instance
|
||||
*
|
||||
* @return true if last frame
|
||||
*/
|
||||
bool icon_animation_is_last_frame(IconAnimation* instance);
|
||||
|
||||
|
||||
@ -1,21 +1,39 @@
|
||||
/**
|
||||
* @file icon_animation_i.h
|
||||
* GUI: internal IconAnimation API
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "icon_animation.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <furi.h>
|
||||
|
||||
struct IconAnimation {
|
||||
const Icon* icon;
|
||||
uint8_t frame;
|
||||
uint32_t tick;
|
||||
bool animating;
|
||||
osTimerId_t timer;
|
||||
IconAnimationCallback callback;
|
||||
void* callback_context;
|
||||
};
|
||||
|
||||
/*
|
||||
* Get pointer to current frame data
|
||||
/** Get pointer to current frame data
|
||||
*
|
||||
* @param instance IconAnimation instance
|
||||
*
|
||||
* @return pointer to current frame XBM bitmap data
|
||||
*/
|
||||
const uint8_t* icon_animation_get_data(IconAnimation* instance);
|
||||
|
||||
/*
|
||||
* Advance to next frame
|
||||
/** Advance to next frame
|
||||
*
|
||||
* @param instance IconAnimation instance
|
||||
*/
|
||||
void icon_animation_next_frame(IconAnimation* instance);
|
||||
|
||||
/** IconAnimation timer callback
|
||||
*
|
||||
* @param context pointer to IconAnimation
|
||||
*/
|
||||
void icon_animation_timer_callback(void* context);
|
||||
|
||||
@ -1,3 +1,8 @@
|
||||
/**
|
||||
* @file icon_i.h
|
||||
* GUI: internal Icon API
|
||||
*/
|
||||
|
||||
#include "icon.h"
|
||||
|
||||
struct Icon {
|
||||
|
||||
@ -1,4 +1,10 @@
|
||||
/**
|
||||
* @file button_menu.h
|
||||
* GUI: ButtonMenu view module API
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <gui/view.h>
|
||||
|
||||
@ -6,40 +12,48 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ButtonMenu anonymous structure */
|
||||
/** ButtonMenu anonymous structure */
|
||||
typedef struct ButtonMenu ButtonMenu;
|
||||
|
||||
/** ButtonMenuItem anonymous structure */
|
||||
typedef struct ButtonMenuItem ButtonMenuItem;
|
||||
|
||||
/* Callback for any button menu actions */
|
||||
/** Callback for any button menu actions */
|
||||
typedef void (*ButtonMenuItemCallback)(void* context, int32_t index, InputType type);
|
||||
|
||||
/* Type of button. Difference in drawing buttons. */
|
||||
/** Type of button. Difference in drawing buttons. */
|
||||
typedef enum {
|
||||
ButtonMenuItemTypeCommon,
|
||||
ButtonMenuItemTypeControl,
|
||||
} ButtonMenuItemType;
|
||||
|
||||
/**
|
||||
* @brief Get button menu view
|
||||
* @param button_menu - ButtonMenu instance
|
||||
* @return View instance that can be used for embedding
|
||||
/** Get button menu view
|
||||
*
|
||||
* @param button_menu ButtonMenu instance
|
||||
*
|
||||
* @return View instance that can be used for embedding
|
||||
*/
|
||||
View* button_menu_get_view(ButtonMenu* button_menu);
|
||||
|
||||
/**
|
||||
* @brief Clean button menu
|
||||
* @param button_menu - ButtonMenu instance
|
||||
/** Clean button menu
|
||||
*
|
||||
* @param button_menu ButtonMenu instance
|
||||
*/
|
||||
void button_menu_clean(ButtonMenu* button_menu);
|
||||
|
||||
/**
|
||||
* @brief Add item to button menu instance
|
||||
* @param button_menu - ButtonMenu instance
|
||||
* @param label - text inside new button
|
||||
* @param index - value to distinct between buttons inside ButtonMenuItemCallback
|
||||
* @param type - type of button to create. Differ by button drawing.
|
||||
* Control buttons have no frames, and have more squared borders.
|
||||
* @return pointer to just-created item
|
||||
/** Add item to button menu instance
|
||||
*
|
||||
* @param button_menu ButtonMenu instance
|
||||
* @param label text inside new button
|
||||
* @param index value to distinct between buttons inside
|
||||
* ButtonMenuItemCallback
|
||||
* @param callback The callback
|
||||
* @param type type of button to create. Differ by button
|
||||
* drawing. Control buttons have no frames, and
|
||||
* have more squared borders.
|
||||
* @param callback_context The callback context
|
||||
*
|
||||
* @return pointer to just-created item
|
||||
*/
|
||||
ButtonMenuItem* button_menu_add_item(
|
||||
ButtonMenu* button_menu,
|
||||
@ -49,29 +63,29 @@ ButtonMenuItem* button_menu_add_item(
|
||||
ButtonMenuItemType type,
|
||||
void* callback_context);
|
||||
|
||||
/**
|
||||
* @brief Allocate and initialize new instance of ButtonMenu model
|
||||
* @return just-created ButtonMenu model
|
||||
/** Allocate and initialize new instance of ButtonMenu model
|
||||
*
|
||||
* @return just-created ButtonMenu model
|
||||
*/
|
||||
ButtonMenu* button_menu_alloc(void);
|
||||
|
||||
/**
|
||||
* @brief Free ButtonMenu element
|
||||
* @param button_menu - ButtonMenu instance
|
||||
/** Free ButtonMenu element
|
||||
*
|
||||
* @param button_menu ButtonMenu instance
|
||||
*/
|
||||
void button_menu_free(ButtonMenu* button_menu);
|
||||
|
||||
/**
|
||||
* @brief Set ButtonMenu header on top of canvas
|
||||
* @param button_menu - ButtonMenu instance
|
||||
* @param header - header on the top of button menu
|
||||
/** Set ButtonMenu header on top of canvas
|
||||
*
|
||||
* @param button_menu ButtonMenu instance
|
||||
* @param header header on the top of button menu
|
||||
*/
|
||||
void button_menu_set_header(ButtonMenu* button_menu, const char* header);
|
||||
|
||||
/**
|
||||
* @brief Set selected item
|
||||
* @param button_menu - ButtonMenu instance
|
||||
* @param index - index of ButtonMenu to be selected
|
||||
/** Set selected item
|
||||
*
|
||||
* @param button_menu ButtonMenu instance
|
||||
* @param index index of ButtonMenu to be selected
|
||||
*/
|
||||
void button_menu_set_selected_item(ButtonMenu* button_menu, uint32_t index);
|
||||
|
||||
|
||||
@ -1,4 +1,10 @@
|
||||
/**
|
||||
* @file button_panel.h
|
||||
* GUI: ButtonPanel view module API
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
@ -10,37 +16,39 @@ typedef struct ButtonPanel ButtonPanel;
|
||||
|
||||
/** Callback type to call for handling selecting button_panel items */
|
||||
typedef void (*ButtonItemCallback)(void* context, uint32_t index);
|
||||
|
||||
/** Callback type for additional drawings above main button_panel screen */
|
||||
typedef void (*ButtonPanelDrawCallback)(Canvas* canvas, void* _model);
|
||||
|
||||
/** Callback type to intercept input events of button_panel */
|
||||
typedef bool (*ButtonPanelInputCallback)(InputEvent* event, void* context);
|
||||
|
||||
/** Allocate new button_panel module.
|
||||
*
|
||||
* @return just-created module
|
||||
* @return ButtonPanel instance
|
||||
*/
|
||||
ButtonPanel* button_panel_alloc(void);
|
||||
|
||||
/** Free button_panel module.
|
||||
*
|
||||
* @param button_panel - module to free
|
||||
* @param button_panel ButtonPanel instance
|
||||
*/
|
||||
void button_panel_free(ButtonPanel* button_panel);
|
||||
|
||||
/** Free items from button_panel module. Preallocated matrix stays unchanged.
|
||||
*
|
||||
* @param button_panel - module to clean
|
||||
* @param button_panel ButtonPanel instance
|
||||
*/
|
||||
void button_panel_clean(ButtonPanel* button_panel);
|
||||
|
||||
/** Reserve space for adding items.
|
||||
*
|
||||
* One does not simply use button_panel_add_item() without this function.
|
||||
* It should be allocated space for it first.
|
||||
* One does not simply use button_panel_add_item() without this function. It
|
||||
* should be allocated space for it first.
|
||||
*
|
||||
* @param button_panel - module to modify
|
||||
* @param reserve_x - number of columns in button_panel
|
||||
* @param reserve_y - number of rows in button_panel
|
||||
* @param button_panel ButtonPanel instance
|
||||
* @param reserve_x number of columns in button_panel
|
||||
* @param reserve_y number of rows in button_panel
|
||||
*/
|
||||
void button_panel_reserve(ButtonPanel* button_panel, size_t reserve_x, size_t reserve_y);
|
||||
|
||||
@ -48,20 +56,20 @@ void button_panel_reserve(ButtonPanel* button_panel, size_t reserve_x, size_t re
|
||||
*
|
||||
* Have to set element in bounds of allocated size by X and by Y.
|
||||
*
|
||||
* @param button_panel - module
|
||||
* @param index - value to pass to callback
|
||||
* @param matrix_place_x - coordinates by x-axis on virtual grid, it
|
||||
* is only used for naviagation
|
||||
* @param matrix_place_y - coordinates by y-axis on virtual grid, it
|
||||
* is only used for naviagation
|
||||
* @param x - x-coordinate to draw icon on
|
||||
* @param y - y-coordinate to draw icon on
|
||||
* @param icon_name - name of the icon to draw
|
||||
* @param icon_name_selected - name of the icon to draw when current
|
||||
* element is selected
|
||||
* @param callback - function to call when specific element is selected
|
||||
* (pressed Ok on selected item)
|
||||
* @param callback_context - context to pass to callback
|
||||
* @param button_panel ButtonPanel instance
|
||||
* @param index value to pass to callback
|
||||
* @param matrix_place_x coordinates by x-axis on virtual grid, it
|
||||
* is only used for naviagation
|
||||
* @param matrix_place_y coordinates by y-axis on virtual grid, it
|
||||
* is only used for naviagation
|
||||
* @param x x-coordinate to draw icon on
|
||||
* @param y y-coordinate to draw icon on
|
||||
* @param icon_name name of the icon to draw
|
||||
* @param icon_name_selected name of the icon to draw when current
|
||||
* element is selected
|
||||
* @param callback function to call when specific element is
|
||||
* selected (pressed Ok on selected item)
|
||||
* @param callback_context context to pass to callback
|
||||
*/
|
||||
void button_panel_add_item(
|
||||
ButtonPanel* button_panel,
|
||||
@ -77,17 +85,19 @@ void button_panel_add_item(
|
||||
|
||||
/** Get button_panel view.
|
||||
*
|
||||
* @param button_panel - module to get view from
|
||||
* @return acquired view
|
||||
* @param button_panel ButtonPanel instance
|
||||
*
|
||||
* @return acquired view
|
||||
*/
|
||||
View* button_panel_get_view(ButtonPanel* button_panel);
|
||||
|
||||
/** Add label to button_panel module.
|
||||
*
|
||||
* @param x - x-coordinate to place label
|
||||
* @param y - y-coordinate to place label
|
||||
* @param font - font to write label with
|
||||
* @param label_str - string label to write
|
||||
* @param button_panel ButtonPanel instance
|
||||
* @param x x-coordinate to place label
|
||||
* @param y y-coordinate to place label
|
||||
* @param font font to write label with
|
||||
* @param label_str string label to write
|
||||
*/
|
||||
void button_panel_add_label(
|
||||
ButtonPanel* button_panel,
|
||||
@ -101,9 +111,9 @@ void button_panel_add_label(
|
||||
*
|
||||
* Used to add popup drawings after main draw callback is done.
|
||||
*
|
||||
* @param button_panel - module to modify
|
||||
* @param callback - callback function to set for draw event
|
||||
* @param context - context to pass to callback
|
||||
* @param button_panel ButtonPanel instance
|
||||
* @param callback callback function to set for draw event
|
||||
* @param context context to pass to callback
|
||||
*/
|
||||
void button_panel_set_popup_draw_callback(
|
||||
ButtonPanel* button_panel,
|
||||
@ -112,12 +122,12 @@ void button_panel_set_popup_draw_callback(
|
||||
|
||||
/** Set popup input callback for button_panel module.
|
||||
*
|
||||
* Used to add popup input callback. It will intercept all input
|
||||
* events for current view.
|
||||
* Used to add popup input callback. It will intercept all input events for
|
||||
* current view.
|
||||
*
|
||||
* @param button_panel - module to modify
|
||||
* @param callback - function to overwrite main input callbacks
|
||||
* @param context - context to pass to callback
|
||||
* @param button_panel ButtonPanel instance
|
||||
* @param callback function to overwrite main input callbacks
|
||||
* @param context context to pass to callback
|
||||
*/
|
||||
void button_panel_set_popup_input_callback(
|
||||
ButtonPanel* button_panel,
|
||||
|
||||
@ -1,59 +1,53 @@
|
||||
/**
|
||||
* @file byte_input.h
|
||||
* GUI: ByteInput keyboard view module API
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Byte input anonymous structure
|
||||
*
|
||||
*/
|
||||
/** Byte input anonymous structure */
|
||||
typedef struct ByteInput ByteInput;
|
||||
|
||||
/**
|
||||
* @brief callback that is executed on save button press
|
||||
*
|
||||
*/
|
||||
/** callback that is executed on save button press */
|
||||
typedef void (*ByteInputCallback)(void* context);
|
||||
|
||||
/**
|
||||
* @brief callback that is executed when byte buffer is changed
|
||||
*
|
||||
*/
|
||||
/** callback that is executed when byte buffer is changed */
|
||||
typedef void (*ByteChangedCallback)(void* context);
|
||||
|
||||
/**
|
||||
* @brief Allocate and initialize byte input. This byte input is used to enter bytes.
|
||||
*
|
||||
* @return ByteInput instance pointer
|
||||
/** Allocate and initialize byte input. This byte input is used to enter bytes.
|
||||
*
|
||||
* @return ByteInput instance pointer
|
||||
*/
|
||||
ByteInput* byte_input_alloc();
|
||||
|
||||
/**
|
||||
* @brief Deinitialize and free byte input
|
||||
*
|
||||
* @param byte_input Byte input instance
|
||||
/** Deinitialize and free byte input
|
||||
*
|
||||
* @param byte_input Byte input instance
|
||||
*/
|
||||
void byte_input_free(ByteInput* byte_input);
|
||||
|
||||
/**
|
||||
* @brief Get byte input view
|
||||
*
|
||||
* @param byte_input byte input instance
|
||||
* @return View instance that can be used for embedding
|
||||
/** Get byte input view
|
||||
*
|
||||
* @param byte_input byte input instance
|
||||
*
|
||||
* @return View instance that can be used for embedding
|
||||
*/
|
||||
View* byte_input_get_view(ByteInput* byte_input);
|
||||
|
||||
/**
|
||||
* @brief Set byte input result callback
|
||||
*
|
||||
* @param byte_input byte input instance
|
||||
* @param input_callback input callback fn
|
||||
* @param changed_callback changed callback fn
|
||||
* @param callback_context callback context
|
||||
* @param bytes buffer to use
|
||||
* @param bytes_count buffer length
|
||||
/** Set byte input result callback
|
||||
*
|
||||
* @param byte_input byte input instance
|
||||
* @param input_callback input callback fn
|
||||
* @param changed_callback changed callback fn
|
||||
* @param callback_context callback context
|
||||
* @param bytes buffer to use
|
||||
* @param bytes_count buffer length
|
||||
*/
|
||||
void byte_input_set_result_callback(
|
||||
ByteInput* byte_input,
|
||||
@ -63,11 +57,10 @@ void byte_input_set_result_callback(
|
||||
uint8_t* bytes,
|
||||
uint8_t bytes_count);
|
||||
|
||||
/**
|
||||
* @brief Set byte input header text
|
||||
*
|
||||
* @param byte_input byte input instance
|
||||
* @param text text to be shown
|
||||
/** Set byte input header text
|
||||
*
|
||||
* @param byte_input byte input instance
|
||||
* @param text text to be shown
|
||||
*/
|
||||
void byte_input_set_header_text(ByteInput* byte_input, const char* text);
|
||||
|
||||
|
||||
@ -1,77 +1,95 @@
|
||||
/**
|
||||
* @file dialog.h
|
||||
* GUI: Dialog view module API
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Dialog anonymous structure */
|
||||
/** Dialog anonymous structure */
|
||||
typedef struct Dialog Dialog;
|
||||
|
||||
/* Dialog result */
|
||||
/** Dialog result */
|
||||
typedef enum {
|
||||
DialogResultLeft,
|
||||
DialogResultRight,
|
||||
DialogResultBack,
|
||||
} DialogResult;
|
||||
|
||||
/* Dialog result callback type
|
||||
* @warning comes from GUI thread
|
||||
/** Dialog result callback type
|
||||
* @warning comes from GUI thread
|
||||
*/
|
||||
typedef void (*DialogResultCallback)(DialogResult result, void* context);
|
||||
|
||||
/* Allocate and initialize dialog
|
||||
/** Allocate and initialize dialog
|
||||
*
|
||||
* This dialog used to ask simple questions like Yes/
|
||||
*
|
||||
* @return Dialog instance
|
||||
*/
|
||||
Dialog* dialog_alloc();
|
||||
|
||||
/* Deinitialize and free dialog
|
||||
* @param dialog - Dialog instance
|
||||
/** Deinitialize and free dialog
|
||||
*
|
||||
* @param dialog Dialog instance
|
||||
*/
|
||||
void dialog_free(Dialog* dialog);
|
||||
|
||||
/* Get dialog view
|
||||
* @param dialog - Dialog instance
|
||||
* @return View instance that can be used for embedding
|
||||
/** Get dialog view
|
||||
*
|
||||
* @param dialog Dialog instance
|
||||
*
|
||||
* @return View instance that can be used for embedding
|
||||
*/
|
||||
View* dialog_get_view(Dialog* dialog);
|
||||
|
||||
/* Set dialog result callback
|
||||
* @param dialog - Dialog instance
|
||||
* @param callback - result callback function
|
||||
/** Set dialog result callback
|
||||
*
|
||||
* @param dialog Dialog instance
|
||||
* @param callback result callback function
|
||||
*/
|
||||
void dialog_set_result_callback(Dialog* dialog, DialogResultCallback callback);
|
||||
|
||||
/* Set dialog context
|
||||
* @param dialog - Dialog instance
|
||||
* @param context - context pointer, will be passed to result callback
|
||||
/** Set dialog context
|
||||
*
|
||||
* @param dialog Dialog instance
|
||||
* @param context context pointer, will be passed to result callback
|
||||
*/
|
||||
void dialog_set_context(Dialog* dialog, void* context);
|
||||
|
||||
/* Set dialog header text
|
||||
* @param dialog - Dialog instance
|
||||
* @param text - text to be shown
|
||||
/** Set dialog header text
|
||||
*
|
||||
* @param dialog Dialog instance
|
||||
* @param text text to be shown
|
||||
*/
|
||||
void dialog_set_header_text(Dialog* dialog, const char* text);
|
||||
|
||||
/* Set dialog text
|
||||
* @param dialog - Dialog instance
|
||||
* @param text - text to be shown
|
||||
/** Set dialog text
|
||||
*
|
||||
* @param dialog Dialog instance
|
||||
* @param text text to be shown
|
||||
*/
|
||||
void dialog_set_text(Dialog* dialog, const char* text);
|
||||
|
||||
/* Set left button text
|
||||
* @param dialog - Dialog instance
|
||||
* @param text - text to be shown
|
||||
/** Set left button text
|
||||
*
|
||||
* @param dialog Dialog instance
|
||||
* @param text text to be shown
|
||||
*/
|
||||
void dialog_set_left_button_text(Dialog* dialog, const char* text);
|
||||
|
||||
/* Set right button text
|
||||
* @param dialog - Dialog instance
|
||||
* @param text - text to be shown
|
||||
/** Set right button text
|
||||
*
|
||||
* @param dialog Dialog instance
|
||||
* @param text text to be shown
|
||||
*/
|
||||
void dialog_set_right_button_text(Dialog* dialog, const char* text);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -1,4 +1,10 @@
|
||||
/**
|
||||
* @file dialog_ex.h
|
||||
* GUI: DialogEx view module API
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
@ -21,40 +27,51 @@ typedef enum {
|
||||
typedef void (*DialogExResultCallback)(DialogExResult result, void* context);
|
||||
|
||||
/** Allocate and initialize dialog
|
||||
*
|
||||
* This dialog used to ask simple questions
|
||||
* @return DialogEx instance
|
||||
*
|
||||
* @return DialogEx instance
|
||||
*/
|
||||
DialogEx* dialog_ex_alloc();
|
||||
|
||||
/** Deinitialize and free dialog
|
||||
* @param dialog - DialogEx instance
|
||||
*
|
||||
* @param dialog_ex DialogEx instance
|
||||
*/
|
||||
void dialog_ex_free(DialogEx* dialog_ex);
|
||||
|
||||
/** Get dialog view
|
||||
* @param dialog - DialogEx instance
|
||||
* @return View instance that can be used for embedding
|
||||
*
|
||||
* @param dialog_ex DialogEx instance
|
||||
*
|
||||
* @return View instance that can be used for embedding
|
||||
*/
|
||||
View* dialog_ex_get_view(DialogEx* dialog_ex);
|
||||
|
||||
/** Set dialog result callback
|
||||
* @param dialog_ex - DialogEx instance
|
||||
* @param callback - result callback function
|
||||
*
|
||||
* @param dialog_ex DialogEx instance
|
||||
* @param callback result callback function
|
||||
*/
|
||||
void dialog_ex_set_result_callback(DialogEx* dialog_ex, DialogExResultCallback callback);
|
||||
|
||||
/** Set dialog context
|
||||
* @param dialog_ex - DialogEx instance
|
||||
* @param context - context pointer, will be passed to result callback
|
||||
*
|
||||
* @param dialog_ex DialogEx instance
|
||||
* @param context context pointer, will be passed to result callback
|
||||
*/
|
||||
void dialog_ex_set_context(DialogEx* dialog_ex, void* context);
|
||||
|
||||
/** Set dialog header text
|
||||
*
|
||||
* If text is null, dialog header will not be rendered
|
||||
* @param dialog - DialogEx instance
|
||||
* @param text - text to be shown, can be multiline
|
||||
* @param x, y - text position
|
||||
* @param horizontal, vertical - text aligment
|
||||
*
|
||||
* @param dialog_ex DialogEx instance
|
||||
* @param text text to be shown, can be multiline
|
||||
* @param x x position
|
||||
* @param y y position
|
||||
* @param horizontal horizontal text aligment
|
||||
* @param vertical vertical text aligment
|
||||
*/
|
||||
void dialog_ex_set_header(
|
||||
DialogEx* dialog_ex,
|
||||
@ -65,11 +82,15 @@ void dialog_ex_set_header(
|
||||
Align vertical);
|
||||
|
||||
/** Set dialog text
|
||||
*
|
||||
* If text is null, dialog text will not be rendered
|
||||
* @param dialog - DialogEx instance
|
||||
* @param text - text to be shown, can be multiline
|
||||
* @param x, y - text position
|
||||
* @param horizontal, vertical - text aligment
|
||||
*
|
||||
* @param dialog_ex DialogEx instance
|
||||
* @param text text to be shown, can be multiline
|
||||
* @param x x position
|
||||
* @param y y position
|
||||
* @param horizontal horizontal text aligment
|
||||
* @param vertical vertical text aligment
|
||||
*/
|
||||
void dialog_ex_set_text(
|
||||
DialogEx* dialog_ex,
|
||||
@ -80,36 +101,47 @@ void dialog_ex_set_text(
|
||||
Align vertical);
|
||||
|
||||
/** Set dialog icon
|
||||
*
|
||||
* If x or y is negative, dialog icon will not be rendered
|
||||
* @param dialog - DialogEx instance
|
||||
* @param x, y - icon position
|
||||
* @param name - icon to be shown
|
||||
*
|
||||
* @param dialog_ex DialogEx instance
|
||||
* @param x x position
|
||||
* @param y y position
|
||||
* @param icon The icon
|
||||
* @param name icon to be shown
|
||||
*/
|
||||
void dialog_ex_set_icon(DialogEx* dialog_ex, uint8_t x, uint8_t y, const Icon* icon);
|
||||
|
||||
/** Set left button text
|
||||
*
|
||||
* If text is null, left button will not be rendered and processed
|
||||
* @param dialog - DialogEx instance
|
||||
* @param text - text to be shown
|
||||
*
|
||||
* @param dialog_ex DialogEx instance
|
||||
* @param text text to be shown
|
||||
*/
|
||||
void dialog_ex_set_left_button_text(DialogEx* dialog_ex, const char* text);
|
||||
|
||||
/** Set center button text
|
||||
*
|
||||
* If text is null, center button will not be rendered and processed
|
||||
* @param dialog - DialogEx instance
|
||||
* @param text - text to be shown
|
||||
*
|
||||
* @param dialog_ex DialogEx instance
|
||||
* @param text text to be shown
|
||||
*/
|
||||
void dialog_ex_set_center_button_text(DialogEx* dialog_ex, const char* text);
|
||||
|
||||
/** Set right button text
|
||||
*
|
||||
* If text is null, right button will not be rendered and processed
|
||||
* @param dialog - DialogEx instance
|
||||
* @param text - text to be shown
|
||||
*
|
||||
* @param dialog_ex DialogEx instance
|
||||
* @param text text to be shown
|
||||
*/
|
||||
void dialog_ex_set_right_button_text(DialogEx* dialog_ex, const char* text);
|
||||
|
||||
/** Clean dialog
|
||||
* @param dialog_ex DialogEx instance
|
||||
*
|
||||
* @param dialog_ex DialogEx instance
|
||||
*/
|
||||
void dialog_ex_clean(DialogEx* dialog_ex);
|
||||
|
||||
|
||||
@ -1,26 +1,38 @@
|
||||
/**
|
||||
* @file empty_screen.h
|
||||
* GUI: EmptyScreen view module API
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Empty screen anonymous structure */
|
||||
/** Empty screen anonymous structure */
|
||||
typedef struct EmptyScreen EmptyScreen;
|
||||
|
||||
/* Allocate and initialize empty screen
|
||||
/** Allocate and initialize empty screen
|
||||
*
|
||||
* This empty screen used to ask simple questions like Yes/
|
||||
*
|
||||
* @return EmptyScreen instance
|
||||
*/
|
||||
EmptyScreen* empty_screen_alloc();
|
||||
|
||||
/* Deinitialize and free empty screen
|
||||
* @param empty_screen - Empty screen instance
|
||||
/** Deinitialize and free empty screen
|
||||
*
|
||||
* @param empty_screen Empty screen instance
|
||||
*/
|
||||
void empty_screen_free(EmptyScreen* empty_screen);
|
||||
|
||||
/* Get empty screen view
|
||||
* @param empty_screen - Empty screen instance
|
||||
* @return View instance that can be used for embedding
|
||||
/** Get empty screen view
|
||||
*
|
||||
* @param empty_screen Empty screen instance
|
||||
*
|
||||
* @return View instance that can be used for embedding
|
||||
*/
|
||||
View* empty_screen_get_view(EmptyScreen* empty_screen);
|
||||
|
||||
|
||||
@ -1,4 +1,10 @@
|
||||
/**
|
||||
* @file file_select.h
|
||||
* GUI: FileSelect view module API
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
54
applications/gui/modules/menu.c
Executable file → Normal file
54
applications/gui/modules/menu.c
Executable file → Normal file
@ -20,7 +20,7 @@ ARRAY_DEF(MenuItemArray, MenuItem, M_POD_OPLIST);
|
||||
|
||||
typedef struct {
|
||||
MenuItemArray_t items;
|
||||
uint8_t position;
|
||||
size_t position;
|
||||
} MenuModel;
|
||||
|
||||
static void menu_process_up(Menu* menu);
|
||||
@ -32,7 +32,7 @@ static void menu_draw_callback(Canvas* canvas, void* _model) {
|
||||
|
||||
canvas_clear(canvas);
|
||||
|
||||
uint8_t position = model->position;
|
||||
size_t position = model->position;
|
||||
size_t items_count = MenuItemArray_size(model->items);
|
||||
if(items_count) {
|
||||
MenuItem* item;
|
||||
@ -43,7 +43,6 @@ static void menu_draw_callback(Canvas* canvas, void* _model) {
|
||||
item = MenuItemArray_get(model->items, shift_position);
|
||||
if(item->icon) {
|
||||
canvas_draw_icon_animation(canvas, 4, 3, item->icon);
|
||||
icon_animation_stop(item->icon);
|
||||
}
|
||||
canvas_draw_str(canvas, 22, 14, item->label);
|
||||
// Second line main
|
||||
@ -52,7 +51,6 @@ static void menu_draw_callback(Canvas* canvas, void* _model) {
|
||||
item = MenuItemArray_get(model->items, shift_position);
|
||||
if(item->icon) {
|
||||
canvas_draw_icon_animation(canvas, 4, 25, item->icon);
|
||||
icon_animation_start(item->icon);
|
||||
}
|
||||
canvas_draw_str(canvas, 22, 36, item->label);
|
||||
// Third line
|
||||
@ -61,7 +59,6 @@ static void menu_draw_callback(Canvas* canvas, void* _model) {
|
||||
item = MenuItemArray_get(model->items, shift_position);
|
||||
if(item->icon) {
|
||||
canvas_draw_icon_animation(canvas, 4, 47, item->icon);
|
||||
icon_animation_stop(item->icon);
|
||||
}
|
||||
canvas_draw_str(canvas, 22, 58, item->label);
|
||||
// Frame and scrollbar
|
||||
@ -93,6 +90,30 @@ static bool menu_input_callback(InputEvent* event, void* context) {
|
||||
return consumed;
|
||||
}
|
||||
|
||||
static void menu_enter(void* context) {
|
||||
Menu* menu = context;
|
||||
with_view_model(
|
||||
menu->view, (MenuModel * model) {
|
||||
MenuItem* item = MenuItemArray_get(model->items, model->position);
|
||||
if(item && item->icon) {
|
||||
icon_animation_start(item->icon);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
static void menu_exit(void* context) {
|
||||
Menu* menu = context;
|
||||
with_view_model(
|
||||
menu->view, (MenuModel * model) {
|
||||
MenuItem* item = MenuItemArray_get(model->items, model->position);
|
||||
if(item && item->icon) {
|
||||
icon_animation_stop(item->icon);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
Menu* menu_alloc() {
|
||||
Menu* menu = furi_alloc(sizeof(Menu));
|
||||
menu->view = view_alloc(menu->view);
|
||||
@ -100,6 +121,8 @@ Menu* menu_alloc() {
|
||||
view_allocate_model(menu->view, ViewModelTypeLocking, sizeof(MenuModel));
|
||||
view_set_draw_callback(menu->view, menu_draw_callback);
|
||||
view_set_input_callback(menu->view, menu_input_callback);
|
||||
view_set_enter_callback(menu->view, menu_enter);
|
||||
view_set_exit_callback(menu->view, menu_exit);
|
||||
|
||||
with_view_model(
|
||||
menu->view, (MenuModel * model) {
|
||||
@ -143,6 +166,7 @@ void menu_add_item(
|
||||
item = MenuItemArray_push_new(model->items);
|
||||
item->label = label;
|
||||
item->icon = icon;
|
||||
view_tie_icon_animation(menu->view, item->icon);
|
||||
item->index = index;
|
||||
item->callback = callback;
|
||||
item->callback_context = context;
|
||||
@ -175,11 +199,21 @@ void menu_set_selected_item(Menu* menu, uint32_t index) {
|
||||
static void menu_process_up(Menu* menu) {
|
||||
with_view_model(
|
||||
menu->view, (MenuModel * model) {
|
||||
MenuItem* item = MenuItemArray_get(model->items, model->position);
|
||||
if(item && item->icon) {
|
||||
icon_animation_stop(item->icon);
|
||||
}
|
||||
|
||||
if(model->position > 0) {
|
||||
model->position--;
|
||||
} else {
|
||||
model->position = MenuItemArray_size(model->items) - 1;
|
||||
}
|
||||
|
||||
item = MenuItemArray_get(model->items, model->position);
|
||||
if(item && item->icon) {
|
||||
icon_animation_start(item->icon);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
@ -187,11 +221,21 @@ static void menu_process_up(Menu* menu) {
|
||||
static void menu_process_down(Menu* menu) {
|
||||
with_view_model(
|
||||
menu->view, (MenuModel * model) {
|
||||
MenuItem* item = MenuItemArray_get(model->items, model->position);
|
||||
if(item && item->icon) {
|
||||
icon_animation_stop(item->icon);
|
||||
}
|
||||
|
||||
if(model->position < MenuItemArray_size(model->items) - 1) {
|
||||
model->position++;
|
||||
} else {
|
||||
model->position = 0;
|
||||
}
|
||||
|
||||
item = MenuItemArray_get(model->items, model->position);
|
||||
if(item && item->icon) {
|
||||
icon_animation_start(item->icon);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
@ -1,4 +1,10 @@
|
||||
/**
|
||||
* @file menu.h
|
||||
* GUI: Menu view module API
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
@ -7,31 +13,38 @@ extern "C" {
|
||||
|
||||
/** Menu anonymous structure */
|
||||
typedef struct Menu Menu;
|
||||
|
||||
/** Menu Item Callback */
|
||||
typedef void (*MenuItemCallback)(void* context, uint32_t index);
|
||||
|
||||
/** Menu allocation and initialization
|
||||
* @return Menu instance
|
||||
*
|
||||
* @return Menu instance
|
||||
*/
|
||||
Menu* menu_alloc();
|
||||
|
||||
/** Free menu
|
||||
* @param menu - Menu instance
|
||||
*
|
||||
* @param menu Menu instance
|
||||
*/
|
||||
void menu_free(Menu* menu);
|
||||
|
||||
/** Get Menu view
|
||||
* @param menu - Menu instance
|
||||
* @return View instance
|
||||
*
|
||||
* @param menu Menu instance
|
||||
*
|
||||
* @return View instance
|
||||
*/
|
||||
View* menu_get_view(Menu* menu);
|
||||
|
||||
/** Add item to menu
|
||||
* @param menu - Menu instance
|
||||
* @param label - menu item string label
|
||||
* @param icon - IconAnimation instance
|
||||
* @param index - menu item index
|
||||
* @param callback - MenuItemCallback instance
|
||||
* @param context - pointer to context
|
||||
*
|
||||
* @param menu Menu instance
|
||||
* @param label menu item string label
|
||||
* @param icon IconAnimation instance
|
||||
* @param index menu item index
|
||||
* @param callback MenuItemCallback instance
|
||||
* @param context pointer to context
|
||||
*/
|
||||
void menu_add_item(
|
||||
Menu* menu,
|
||||
@ -42,14 +55,16 @@ void menu_add_item(
|
||||
void* context);
|
||||
|
||||
/** Clean menu
|
||||
* Note: this function does not free menu instance
|
||||
* @param menu - Menu instance
|
||||
* @note this function does not free menu instance
|
||||
*
|
||||
* @param menu Menu instance
|
||||
*/
|
||||
void menu_clean(Menu* menu);
|
||||
|
||||
/** Set current menu item
|
||||
* @param submenu
|
||||
* @param index
|
||||
*
|
||||
* @param menu Menu instance
|
||||
* @param index The index
|
||||
*/
|
||||
void menu_set_selected_item(Menu* menu, uint32_t index);
|
||||
|
||||
|
||||
@ -1,52 +1,70 @@
|
||||
/**
|
||||
* @file popup.h
|
||||
* GUI: Popup view module API
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Popup anonymous structure */
|
||||
/** Popup anonymous structure */
|
||||
typedef struct Popup Popup;
|
||||
|
||||
/* Popup result callback type
|
||||
* @warning comes from GUI thread
|
||||
/** Popup result callback type
|
||||
* @warning comes from GUI thread
|
||||
*/
|
||||
typedef void (*PopupCallback)(void* context);
|
||||
|
||||
/* Allocate and initialize popup
|
||||
/** Allocate and initialize popup
|
||||
*
|
||||
* This popup used to ask simple questions like Yes/
|
||||
*
|
||||
* @return Popup instance
|
||||
*/
|
||||
Popup* popup_alloc();
|
||||
|
||||
/* Deinitialize and free popup
|
||||
* @param popup - Popup instance
|
||||
/** Deinitialize and free popup
|
||||
*
|
||||
* @param popup Popup instance
|
||||
*/
|
||||
void popup_free(Popup* popup);
|
||||
|
||||
/* Get popup view
|
||||
* @param popup - Popup instance
|
||||
* @return View instance that can be used for embedding
|
||||
/** Get popup view
|
||||
*
|
||||
* @param popup Popup instance
|
||||
*
|
||||
* @return View instance that can be used for embedding
|
||||
*/
|
||||
View* popup_get_view(Popup* popup);
|
||||
|
||||
/* Set popup header text
|
||||
* @param popup - Popup instance
|
||||
* @param text - text to be shown
|
||||
/** Set popup header text
|
||||
*
|
||||
* @param popup Popup instance
|
||||
* @param callback PopupCallback
|
||||
*/
|
||||
void popup_set_callback(Popup* popup, PopupCallback callback);
|
||||
|
||||
/* Set popup context
|
||||
* @param popup - Popup instance
|
||||
* @param context - context pointer, will be passed to result callback
|
||||
/** Set popup context
|
||||
*
|
||||
* @param popup Popup instance
|
||||
* @param context context pointer, will be passed to result callback
|
||||
*/
|
||||
void popup_set_context(Popup* popup, void* context);
|
||||
|
||||
/* Set popup header text
|
||||
/** Set popup header text
|
||||
*
|
||||
* If text is null, popup header will not be rendered
|
||||
* @param popup - Popup instance
|
||||
* @param text - text to be shown, can be multiline
|
||||
* @param x, y - text position
|
||||
* @param horizontal, vertical - text aligment
|
||||
*
|
||||
* @param popup Popup instance
|
||||
* @param text text to be shown, can be multiline
|
||||
* @param x x position
|
||||
* @param y y position
|
||||
* @param horizontal horizontal alignment
|
||||
* @param vertical vertical aligment
|
||||
*/
|
||||
void popup_set_header(
|
||||
Popup* popup,
|
||||
@ -56,12 +74,16 @@ void popup_set_header(
|
||||
Align horizontal,
|
||||
Align vertical);
|
||||
|
||||
/* Set popup text
|
||||
/** Set popup text
|
||||
*
|
||||
* If text is null, popup text will not be rendered
|
||||
* @param popup - Popup instance
|
||||
* @param text - text to be shown, can be multiline
|
||||
* @param x, y - text position
|
||||
* @param horizontal, vertical - text aligment
|
||||
*
|
||||
* @param popup Popup instance
|
||||
* @param text text to be shown, can be multiline
|
||||
* @param x x position
|
||||
* @param y y position
|
||||
* @param horizontal horizontal alignment
|
||||
* @param vertical vertical aligment
|
||||
*/
|
||||
void popup_set_text(
|
||||
Popup* popup,
|
||||
@ -71,30 +93,36 @@ void popup_set_text(
|
||||
Align horizontal,
|
||||
Align vertical);
|
||||
|
||||
/* Set popup icon
|
||||
/** Set popup icon
|
||||
*
|
||||
* If icon position is negative, popup icon will not be rendered
|
||||
* @param popup - Popup instance
|
||||
* @param x, y - icon position
|
||||
* @param name - icon to be shown
|
||||
*
|
||||
* @param popup Popup instance
|
||||
* @param x x position
|
||||
* @param y y position
|
||||
* @param icon pointer to Icon data
|
||||
*/
|
||||
void popup_set_icon(Popup* popup, uint8_t x, uint8_t y, const Icon* icon);
|
||||
|
||||
/* Set popup timeout
|
||||
* @param popup - Popup instance
|
||||
* @param timeout_in_ms - popup timeout value in milliseconds
|
||||
/** Set popup timeout
|
||||
*
|
||||
* @param popup Popup instance
|
||||
* @param timeout_in_ms popup timeout value in milliseconds
|
||||
*/
|
||||
void popup_set_timeout(Popup* popup, uint32_t timeout_in_ms);
|
||||
|
||||
/* Enable popup timeout
|
||||
* @param popup - Popup instance
|
||||
/** Enable popup timeout
|
||||
*
|
||||
* @param popup Popup instance
|
||||
*/
|
||||
void popup_enable_timeout(Popup* popup);
|
||||
|
||||
/* Disable popup timeout
|
||||
* @param popup - Popup instance
|
||||
/** Disable popup timeout
|
||||
*
|
||||
* @param popup Popup instance
|
||||
*/
|
||||
void popup_disable_timeout(Popup* popup);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -1,40 +1,50 @@
|
||||
/**
|
||||
* @file submenu.h
|
||||
* GUI: SubMenu view module API
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Submenu anonymous structure */
|
||||
/** Submenu anonymous structure */
|
||||
typedef struct Submenu Submenu;
|
||||
typedef void (*SubmenuItemCallback)(void* context, uint32_t index);
|
||||
|
||||
/**
|
||||
* @brief Allocate and initialize submenu
|
||||
/** Allocate and initialize submenu
|
||||
*
|
||||
* This submenu is used to select one option
|
||||
*
|
||||
* @return Submenu instance
|
||||
*/
|
||||
Submenu* submenu_alloc();
|
||||
|
||||
/**
|
||||
* @brief Deinitialize and free submenu
|
||||
* @param submenu - Submenu instance
|
||||
/** Deinitialize and free submenu
|
||||
*
|
||||
* @param submenu Submenu instance
|
||||
*/
|
||||
void submenu_free(Submenu* submenu);
|
||||
|
||||
/**
|
||||
* @brief Get submenu view
|
||||
* @param submenu - Submenu instance
|
||||
* @return View instance that can be used for embedding
|
||||
/** Get submenu view
|
||||
*
|
||||
* @param submenu Submenu instance
|
||||
*
|
||||
* @return View instance that can be used for embedding
|
||||
*/
|
||||
View* submenu_get_view(Submenu* submenu);
|
||||
|
||||
/**
|
||||
* @brief Add item to submenu
|
||||
* @param submenu - Submenu instance
|
||||
* @param label - menu item label
|
||||
* @param index - menu item index, used for callback, may be the same with other items
|
||||
* @param callback - menu item callback
|
||||
* @param callback_context - menu item callback context
|
||||
/** Add item to submenu
|
||||
*
|
||||
* @param submenu Submenu instance
|
||||
* @param label menu item label
|
||||
* @param index menu item index, used for callback, may be
|
||||
* the same with other items
|
||||
* @param callback menu item callback
|
||||
* @param callback_context menu item callback context
|
||||
*/
|
||||
void submenu_add_item(
|
||||
Submenu* submenu,
|
||||
@ -43,23 +53,23 @@ void submenu_add_item(
|
||||
SubmenuItemCallback callback,
|
||||
void* callback_context);
|
||||
|
||||
/**
|
||||
* @brief Remove all items from submenu
|
||||
* @param submenu - Submenu instance
|
||||
/** Remove all items from submenu
|
||||
*
|
||||
* @param submenu Submenu instance
|
||||
*/
|
||||
void submenu_clean(Submenu* submenu);
|
||||
|
||||
/**
|
||||
* @brief Set submenu item selector
|
||||
* @param submenu
|
||||
* @param index
|
||||
/** Set submenu item selector
|
||||
*
|
||||
* @param submenu Submenu instance
|
||||
* @param index The index
|
||||
*/
|
||||
void submenu_set_selected_item(Submenu* submenu, uint32_t index);
|
||||
|
||||
/**
|
||||
* @brief Set optional header for submenu
|
||||
* @param submenu - submenu entity
|
||||
* @param header - header to set
|
||||
/** Set optional header for submenu
|
||||
*
|
||||
* @param submenu Submenu instance
|
||||
* @param header header to set
|
||||
*/
|
||||
void submenu_set_header(Submenu* submenu, const char* header);
|
||||
|
||||
|
||||
@ -1,11 +1,17 @@
|
||||
/**
|
||||
* @file text_box.h
|
||||
* GUI: TextBox view module API
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* TextBox anonymous structure */
|
||||
/** TextBox anonymous structure */
|
||||
typedef struct TextBox TextBox;
|
||||
typedef void (*TextBoxExitCallback)(void* context);
|
||||
|
||||
@ -15,46 +21,56 @@ typedef enum {
|
||||
} TextBoxFont;
|
||||
|
||||
/** Allocate and initialize text_box
|
||||
*
|
||||
* @return TextBox instance
|
||||
*/
|
||||
TextBox* text_box_alloc();
|
||||
|
||||
/** Deinitialize and free text_box
|
||||
* @param text_box text_box instance
|
||||
*
|
||||
* @param text_box text_box instance
|
||||
*/
|
||||
void text_box_free(TextBox* text_box);
|
||||
|
||||
/** Get text_box view
|
||||
* @param text_box TextBox instance
|
||||
* @return View instance that can be used for embedding
|
||||
*
|
||||
* @param text_box TextBox instance
|
||||
*
|
||||
* @return View instance that can be used for embedding
|
||||
*/
|
||||
View* text_box_get_view(TextBox* text_box);
|
||||
|
||||
/** Clean text_box
|
||||
* @param text_box TextBox instance
|
||||
*
|
||||
* @param text_box TextBox instance
|
||||
*/
|
||||
void text_box_clean(TextBox* text_box);
|
||||
|
||||
/** Set text for text_box
|
||||
* @param text_box TextBox instance
|
||||
* @param text text to set
|
||||
*
|
||||
* @param text_box TextBox instance
|
||||
* @param text text to set
|
||||
*/
|
||||
void text_box_set_text(TextBox* text_box, const char* text);
|
||||
|
||||
/** Set TextBox font
|
||||
* @param text_box TextBox instance
|
||||
* @param font TextBoxFont instance
|
||||
*
|
||||
* @param text_box TextBox instance
|
||||
* @param font TextBoxFont instance
|
||||
*/
|
||||
void text_box_set_font(TextBox* text_box, TextBoxFont font);
|
||||
|
||||
/** Set text_box context
|
||||
* @param text_box TextBox instance
|
||||
* @param context context pointer
|
||||
*
|
||||
* @param text_box TextBox instance
|
||||
* @param context context pointer
|
||||
*/
|
||||
void text_box_set_context(TextBox* text_box, void* context);
|
||||
|
||||
/** Set exit callback
|
||||
* @param text_box TextBox instance
|
||||
* @param callback TextBoxExitCallback callback pointer
|
||||
*
|
||||
* @param text_box TextBox instance
|
||||
* @param callback TextBoxExitCallback callback pointer
|
||||
*/
|
||||
void text_box_set_exit_callback(TextBox* text_box, TextBoxExitCallback callback);
|
||||
|
||||
|
||||
@ -1,44 +1,59 @@
|
||||
/**
|
||||
* @file text_input.h
|
||||
* GUI: TextInput keybord view module API
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Text input anonymous structure */
|
||||
/** Text input anonymous structure */
|
||||
typedef struct TextInput TextInput;
|
||||
typedef void (*TextInputCallback)(void* context);
|
||||
|
||||
/** Allocate and initialize text input
|
||||
/** Allocate and initialize text input
|
||||
*
|
||||
* This text input is used to enter string
|
||||
* @return TextInput instance
|
||||
*
|
||||
* @return TextInput instance
|
||||
*/
|
||||
TextInput* text_input_alloc();
|
||||
|
||||
/** Deinitialize and free text input
|
||||
* @param text_input - TextInput instance
|
||||
*
|
||||
* @param text_input TextInput instance
|
||||
*/
|
||||
void text_input_free(TextInput* text_input);
|
||||
|
||||
/** Clean text input view
|
||||
* Note: this function does not free memory
|
||||
* @param text_input - Text input instance
|
||||
/** Clean text input view Note: this function does not free memory
|
||||
*
|
||||
* @param text_input Text input instance
|
||||
*/
|
||||
void text_input_clean(TextInput* text_input);
|
||||
|
||||
/** Get text input view
|
||||
* @param text_input - TextInput instance
|
||||
* @return View instance that can be used for embedding
|
||||
*
|
||||
* @param text_input TextInput instance
|
||||
*
|
||||
* @return View instance that can be used for embedding
|
||||
*/
|
||||
View* text_input_get_view(TextInput* text_input);
|
||||
|
||||
/** Set text input result callback
|
||||
* @param text_input - TextInput instance
|
||||
* @param callback - callback fn
|
||||
* @param callback_context - callback context
|
||||
* @param text_buffer - pointer to YOUR text buffer, that we going to modify
|
||||
* @param text_buffer_size - YOUR text buffer size in bytes. Max string length will be text_buffer_size - 1.
|
||||
* @param clear_default_text - clear text from text_buffer on first OK event
|
||||
*
|
||||
* @param text_input TextInput instance
|
||||
* @param callback callback fn
|
||||
* @param callback_context callback context
|
||||
* @param text_buffer pointer to YOUR text buffer, that we going
|
||||
* to modify
|
||||
* @param text_buffer_size YOUR text buffer size in bytes. Max string
|
||||
* length will be text_buffer_size-1.
|
||||
* @param clear_default_text clear text from text_buffer on first OK
|
||||
* event
|
||||
*/
|
||||
void text_input_set_result_callback(
|
||||
TextInput* text_input,
|
||||
@ -49,8 +64,9 @@ void text_input_set_result_callback(
|
||||
bool clear_default_text);
|
||||
|
||||
/** Set text input header text
|
||||
* @param text_input - TextInput instance
|
||||
* @param text - text to be shown
|
||||
*
|
||||
* @param text_input TextInput instance
|
||||
* @param text text to be shown
|
||||
*/
|
||||
void text_input_set_header_text(TextInput* text_input, const char* text);
|
||||
|
||||
|
||||
29
applications/gui/modules/variable-item-list.c
Normal file → Executable file
29
applications/gui/modules/variable-item-list.c
Normal file → Executable file
@ -18,6 +18,8 @@ ARRAY_DEF(VariableItemArray, VariableItem, M_POD_OPLIST);
|
||||
|
||||
struct VariableItemList {
|
||||
View* view;
|
||||
VariableItemListEnterCallback callback;
|
||||
void* context;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@ -30,6 +32,7 @@ static void variable_item_list_process_up(VariableItemList* variable_item_list);
|
||||
static void variable_item_list_process_down(VariableItemList* variable_item_list);
|
||||
static void variable_item_list_process_left(VariableItemList* variable_item_list);
|
||||
static void variable_item_list_process_right(VariableItemList* variable_item_list);
|
||||
static void variable_item_list_process_ok(VariableItemList* variable_item_list);
|
||||
|
||||
static void variable_item_list_draw_callback(Canvas* canvas, void* _model) {
|
||||
VariableItemListModel* model = _model;
|
||||
@ -104,6 +107,9 @@ static bool variable_item_list_input_callback(InputEvent* event, void* context)
|
||||
consumed = true;
|
||||
variable_item_list_process_right(variable_item_list);
|
||||
break;
|
||||
case InputKeyOk:
|
||||
variable_item_list_process_ok(variable_item_list);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -198,6 +204,16 @@ void variable_item_list_process_right(VariableItemList* variable_item_list) {
|
||||
});
|
||||
}
|
||||
|
||||
void variable_item_list_process_ok(VariableItemList* variable_item_list) {
|
||||
with_view_model(
|
||||
variable_item_list->view, (VariableItemListModel * model) {
|
||||
if(variable_item_list->callback) {
|
||||
variable_item_list->callback(variable_item_list->context, model->position);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
VariableItemList* variable_item_list_alloc() {
|
||||
VariableItemList* variable_item_list = furi_alloc(sizeof(VariableItemList));
|
||||
variable_item_list->view = view_alloc();
|
||||
@ -280,6 +296,19 @@ VariableItem* variable_item_list_add(
|
||||
return item;
|
||||
}
|
||||
|
||||
void variable_item_list_set_enter_callback(
|
||||
VariableItemList* variable_item_list,
|
||||
VariableItemListEnterCallback callback,
|
||||
void* context) {
|
||||
furi_assert(callback);
|
||||
with_view_model(
|
||||
variable_item_list->view, (VariableItemListModel * model) {
|
||||
variable_item_list->callback = callback;
|
||||
variable_item_list->context = context;
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
void variable_item_set_current_value_index(VariableItem* item, uint8_t current_value_index) {
|
||||
item->current_value_index = current_value_index;
|
||||
}
|
||||
|
||||
72
applications/gui/modules/variable-item-list.h
Normal file → Executable file
72
applications/gui/modules/variable-item-list.h
Normal file → Executable file
@ -1,4 +1,10 @@
|
||||
/**
|
||||
* @file variable-item-list.h
|
||||
* GUI: VariableItemList view module API
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
@ -8,28 +14,43 @@ extern "C" {
|
||||
typedef struct VariableItemList VariableItemList;
|
||||
typedef struct VariableItem VariableItem;
|
||||
typedef void (*VariableItemChangeCallback)(VariableItem* item);
|
||||
typedef void (*VariableItemListEnterCallback)(void* context, uint32_t index);
|
||||
|
||||
/** Allocate and initialize VariableItemList
|
||||
* @return VariableItemList*
|
||||
*
|
||||
* @return VariableItemList*
|
||||
*/
|
||||
VariableItemList* variable_item_list_alloc();
|
||||
|
||||
/** Deinitialize and free VariableItemList
|
||||
* @param variable_item_list VariableItemList instance
|
||||
*
|
||||
* @param variable_item_list VariableItemList instance
|
||||
*/
|
||||
void variable_item_list_free(VariableItemList* variable_item_list);
|
||||
|
||||
/** Clear all elements from list
|
||||
*
|
||||
* @param variable_item_list VariableItemList instance
|
||||
*/
|
||||
void variable_item_list_clean(VariableItemList* variable_item_list);
|
||||
|
||||
/** Get VariableItemList View instance
|
||||
*
|
||||
* @param variable_item_list VariableItemList instance
|
||||
*
|
||||
* @return View instance
|
||||
*/
|
||||
View* variable_item_list_get_view(VariableItemList* variable_item_list);
|
||||
|
||||
/** Add item to VariableItemList
|
||||
* @param variable_item_list VariableItemList instance
|
||||
* @param label item name
|
||||
* @param values_count item values count
|
||||
* @param change_callback called on value change in gui
|
||||
* @param context item context
|
||||
* @return VariableItem* item instance
|
||||
*
|
||||
* @param variable_item_list VariableItemList instance
|
||||
* @param label item name
|
||||
* @param values_count item values count
|
||||
* @param change_callback called on value change in gui
|
||||
* @param context item context
|
||||
*
|
||||
* @return VariableItem* item instance
|
||||
*/
|
||||
VariableItem* variable_item_list_add(
|
||||
VariableItemList* variable_item_list,
|
||||
@ -38,30 +59,47 @@ VariableItem* variable_item_list_add(
|
||||
VariableItemChangeCallback change_callback,
|
||||
void* context);
|
||||
|
||||
/** Set enter callback
|
||||
*
|
||||
* @param variable_item_list VariableItemList instance
|
||||
* @param callback VariableItemListEnterCallback instance
|
||||
* @param context pointer to context
|
||||
*/
|
||||
void variable_item_list_set_enter_callback(
|
||||
VariableItemList* variable_item_list,
|
||||
VariableItemListEnterCallback callback,
|
||||
void* context);
|
||||
|
||||
/** Set item current selected index
|
||||
* @param item VariableItem* instance
|
||||
* @param current_value_index
|
||||
*
|
||||
* @param item VariableItem* instance
|
||||
* @param current_value_index The current value index
|
||||
*/
|
||||
void variable_item_set_current_value_index(VariableItem* item, uint8_t current_value_index);
|
||||
|
||||
/** Set item current selected text
|
||||
* @param item VariableItem* instance
|
||||
* @param current_value_text
|
||||
*
|
||||
* @param item VariableItem* instance
|
||||
* @param current_value_text The current value text
|
||||
*/
|
||||
void variable_item_set_current_value_text(VariableItem* item, const char* current_value_text);
|
||||
|
||||
/** Get item current selected index
|
||||
* @param item VariableItem* instance
|
||||
* @return uint8_t current selected index
|
||||
*
|
||||
* @param item VariableItem* instance
|
||||
*
|
||||
* @return uint8_t current selected index
|
||||
*/
|
||||
uint8_t variable_item_get_current_value_index(VariableItem* item);
|
||||
|
||||
/** Get item context
|
||||
* @param item VariableItem* instance
|
||||
* @return void* item context
|
||||
*
|
||||
* @param item VariableItem* instance
|
||||
*
|
||||
* @return void* item context
|
||||
*/
|
||||
void* variable_item_get_context(VariableItem* item);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -1,38 +1,51 @@
|
||||
/**
|
||||
* @file widget.h
|
||||
* GUI: Widget view module API
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "widget_elements/widget_element_i.h"
|
||||
|
||||
typedef struct Widget Widget;
|
||||
typedef struct WidgetElement WidgetElement;
|
||||
|
||||
/** Allocate Widget that holds Widget Elements
|
||||
* @return Widget instance
|
||||
*
|
||||
* @return Widget instance
|
||||
*/
|
||||
Widget* widget_alloc();
|
||||
|
||||
/** Free Widget
|
||||
* @note this function free allocated Widget Elements
|
||||
* @param widget Widget instance
|
||||
* @note this function free allocated Widget Elements
|
||||
*
|
||||
* @param widget Widget instance
|
||||
*/
|
||||
void widget_free(Widget* widget);
|
||||
|
||||
/** Clear Widget
|
||||
* @param widget Widget instance
|
||||
*
|
||||
* @param widget Widget instance
|
||||
*/
|
||||
void widget_clear(Widget* widget);
|
||||
|
||||
/** Get Widget view
|
||||
* @param widget Widget instance
|
||||
* @return View instance
|
||||
*
|
||||
* @param widget Widget instance
|
||||
*
|
||||
* @return View instance
|
||||
*/
|
||||
View* widget_get_view(Widget* widget);
|
||||
|
||||
/** Add Multi String Element
|
||||
* @param widget Widget instance
|
||||
* @param x - x coordinate
|
||||
* @param y - y coordinate
|
||||
* @param horizontal - Align instance
|
||||
* @param vertical - Align instance
|
||||
* @param font Font instance
|
||||
*
|
||||
* @param widget Widget instance
|
||||
* @param x x coordinate
|
||||
* @param y y coordinate
|
||||
* @param horizontal Align instance
|
||||
* @param vertical Align instance
|
||||
* @param font Font instance
|
||||
* @param[in] text The text
|
||||
*/
|
||||
void widget_add_string_multiline_element(
|
||||
Widget* widget,
|
||||
@ -44,12 +57,14 @@ void widget_add_string_multiline_element(
|
||||
const char* text);
|
||||
|
||||
/** Add String Element
|
||||
* @param widget Widget instance
|
||||
* @param x - x coordinate
|
||||
* @param y - y coordinate
|
||||
* @param horizontal - Align instance
|
||||
* @param vertical - Align instance
|
||||
* @param font Font instance
|
||||
*
|
||||
* @param widget Widget instance
|
||||
* @param x x coordinate
|
||||
* @param y y coordinate
|
||||
* @param horizontal Align instance
|
||||
* @param vertical Align instance
|
||||
* @param font Font instance
|
||||
* @param[in] text The text
|
||||
*/
|
||||
void widget_add_string_element(
|
||||
Widget* widget,
|
||||
@ -61,11 +76,12 @@ void widget_add_string_element(
|
||||
const char* text);
|
||||
|
||||
/** Add Button Element
|
||||
* @param widget Widget instance
|
||||
* @param button_type GuiButtonType instance
|
||||
* @param text text on allocated button
|
||||
* @param callback ButtonCallback instance
|
||||
* @param context pointer to context
|
||||
*
|
||||
* @param widget Widget instance
|
||||
* @param button_type GuiButtonType instance
|
||||
* @param text text on allocated button
|
||||
* @param callback ButtonCallback instance
|
||||
* @param context pointer to context
|
||||
*/
|
||||
void widget_add_button_element(
|
||||
Widget* widget,
|
||||
@ -75,20 +91,22 @@ void widget_add_button_element(
|
||||
void* context);
|
||||
|
||||
/** Add Icon Element
|
||||
* @param widget Widget instance
|
||||
* @param x top left x coordinate
|
||||
* @param y top left y coordinate
|
||||
* @param icon Icon instance
|
||||
*
|
||||
* @param widget Widget instance
|
||||
* @param x top left x coordinate
|
||||
* @param y top left y coordinate
|
||||
* @param icon Icon instance
|
||||
*/
|
||||
void widget_add_icon_element(Widget* widget, uint8_t x, uint8_t y, const Icon* icon);
|
||||
|
||||
/** Add Frame Element
|
||||
* @param widget Widget instance
|
||||
* @param x top left x coordinate
|
||||
* @param y top left y coordinate
|
||||
* @param width frame width
|
||||
* @param height frame height
|
||||
* @param radius frame radius
|
||||
*
|
||||
* @param widget Widget instance
|
||||
* @param x top left x coordinate
|
||||
* @param y top left y coordinate
|
||||
* @param width frame width
|
||||
* @param height frame height
|
||||
* @param radius frame radius
|
||||
*/
|
||||
void widget_add_frame_element(
|
||||
Widget* widget,
|
||||
|
||||
@ -1,3 +1,8 @@
|
||||
/**
|
||||
* @file widget_element_i.h
|
||||
* GUI: internal Widget Element API
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <furi.h>
|
||||
#include <gui/view.h>
|
||||
@ -29,7 +34,7 @@ struct WidgetElement {
|
||||
Widget* parent;
|
||||
};
|
||||
|
||||
/* Create multi string element */
|
||||
/** Create multi string element */
|
||||
WidgetElement* widget_element_string_multiline_create(
|
||||
uint8_t x,
|
||||
uint8_t y,
|
||||
@ -38,7 +43,7 @@ WidgetElement* widget_element_string_multiline_create(
|
||||
Font font,
|
||||
const char* text);
|
||||
|
||||
/* Create string element */
|
||||
/** Create string element */
|
||||
WidgetElement* widget_element_string_create(
|
||||
uint8_t x,
|
||||
uint8_t y,
|
||||
@ -47,20 +52,20 @@ WidgetElement* widget_element_string_create(
|
||||
Font font,
|
||||
const char* text);
|
||||
|
||||
/* Create button element */
|
||||
/** Create button element */
|
||||
WidgetElement* widget_element_button_create(
|
||||
GuiButtonType button_type,
|
||||
const char* text,
|
||||
ButtonCallback callback,
|
||||
void* context);
|
||||
|
||||
/* Create icon element */
|
||||
/** Create icon element */
|
||||
WidgetElement* widget_element_icon_create(uint8_t x, uint8_t y, const Icon* icon);
|
||||
|
||||
/* Create frame element */
|
||||
/** Create frame element */
|
||||
WidgetElement* widget_element_frame_create(
|
||||
uint8_t x,
|
||||
uint8_t y,
|
||||
uint8_t width,
|
||||
uint8_t height,
|
||||
uint8_t radius);
|
||||
uint8_t radius);
|
||||
|
||||
@ -1,14 +1,18 @@
|
||||
/**
|
||||
* @file scene_manager.h
|
||||
* GUI: SceneManager API
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/** Scene Manager events type
|
||||
*/
|
||||
/** Scene Manager events type */
|
||||
typedef enum {
|
||||
SceneManagerEventTypeCustom,
|
||||
SceneManagerEventTypeBack,
|
||||
@ -44,86 +48,110 @@ typedef struct {
|
||||
typedef struct SceneManager SceneManager;
|
||||
|
||||
/** Set Scene state
|
||||
* @param scene_manager SceneManager instance
|
||||
* @param scene_id Scene ID
|
||||
* @param state Scene new state
|
||||
*
|
||||
* @param scene_manager SceneManager instance
|
||||
* @param scene_id Scene ID
|
||||
* @param state Scene new state
|
||||
*/
|
||||
void scene_manager_set_scene_state(SceneManager* scene_manager, uint32_t scene_id, uint32_t state);
|
||||
|
||||
/** Get Scene state
|
||||
* @param scene_manager SceneManager instance
|
||||
* @param scene_id Scene ID
|
||||
* @return Scene state
|
||||
*
|
||||
* @param scene_manager SceneManager instance
|
||||
* @param scene_id Scene ID
|
||||
*
|
||||
* @return Scene state
|
||||
*/
|
||||
uint32_t scene_manager_get_scene_state(SceneManager* scene_manager, uint32_t scene_id);
|
||||
|
||||
/** Scene Manager allocation and configuration
|
||||
*
|
||||
* Scene Manager allocates all scenes internally
|
||||
* @param app_scene_handlers SceneManagerHandlers instance
|
||||
* @param context context to be set on Scene handlers calls
|
||||
* @return SceneManager instance
|
||||
*
|
||||
* @param app_scene_handlers SceneManagerHandlers instance
|
||||
* @param context context to be set on Scene handlers calls
|
||||
*
|
||||
* @return SceneManager instance
|
||||
*/
|
||||
SceneManager* scene_manager_alloc(const SceneManagerHandlers* app_scene_handlers, void* context);
|
||||
|
||||
/** Free Scene Manager with allocated Scenes
|
||||
* @param scene_manager SceneManager instance
|
||||
*
|
||||
* @param scene_manager SceneManager instance
|
||||
*/
|
||||
void scene_manager_free(SceneManager* scene_manager);
|
||||
|
||||
/** Custom event handler
|
||||
*
|
||||
* Calls Scene event handler with Custom event parameter
|
||||
* @param scene_manager SceneManager instance
|
||||
* @param custom_event Custom event code
|
||||
* @return true if event was consumed, false otherwise
|
||||
*
|
||||
* @param scene_manager SceneManager instance
|
||||
* @param custom_event Custom event code
|
||||
*
|
||||
* @return true if event was consumed, false otherwise
|
||||
*/
|
||||
bool scene_manager_handle_custom_event(SceneManager* scene_manager, uint32_t custom_event);
|
||||
|
||||
/** Back event handler
|
||||
*
|
||||
* Calls Scene event handler with Back event parameter
|
||||
* @param scene_manager SceneManager instance
|
||||
* @return true if event was consumed, false otherwise
|
||||
*
|
||||
* @param scene_manager SceneManager instance
|
||||
*
|
||||
* @return true if event was consumed, false otherwise
|
||||
*/
|
||||
bool scene_manager_handle_back_event(SceneManager* scene_manager);
|
||||
|
||||
/** Tick event handler
|
||||
*
|
||||
* Calls Scene event handler with Tick event parameter
|
||||
* @param scene_manager SceneManager instance
|
||||
* @return true if event was consumed, false otherwise
|
||||
*
|
||||
* @param scene_manager SceneManager instance
|
||||
* @return true if event was consumed, false otherwise
|
||||
*/
|
||||
void scene_manager_handle_tick_event(SceneManager* scene_manager);
|
||||
|
||||
/** Add and run next Scene
|
||||
* @param scene_manager SceneManager instance
|
||||
* @param next_scene_id next Scene ID
|
||||
*
|
||||
* @param scene_manager SceneManager instance
|
||||
* @param next_scene_id next Scene ID
|
||||
*/
|
||||
void scene_manager_next_scene(SceneManager* scene_manager, uint32_t next_scene_id);
|
||||
|
||||
/** Run previous Scene
|
||||
* @param scene_manager SceneManager instance
|
||||
* @return true if previous scene was found, false otherwise
|
||||
*
|
||||
* @param scene_manager SceneManager instance
|
||||
*
|
||||
* @return true if previous scene was found, false otherwise
|
||||
*/
|
||||
bool scene_manager_previous_scene(SceneManager* scene_manager);
|
||||
|
||||
/** Search previous Scene
|
||||
* @param scene_manager SceneManager instance
|
||||
* @param scene_id Scene ID
|
||||
* @return true if previous scene was found, false otherwise
|
||||
*
|
||||
* @param scene_manager SceneManager instance
|
||||
* @param scene_id Scene ID
|
||||
*
|
||||
* @return true if previous scene was found, false otherwise
|
||||
*/
|
||||
bool scene_manager_has_previous_scene(SceneManager* scene_manager, uint32_t scene_id);
|
||||
|
||||
/** Search and switch to previous Scene
|
||||
* @param scene_manager SceneManager instance
|
||||
* @param scene_id Scene ID
|
||||
* @return true if previous scene was found, false otherwise
|
||||
*
|
||||
* @param scene_manager SceneManager instance
|
||||
* @param scene_id Scene ID
|
||||
*
|
||||
* @return true if previous scene was found, false otherwise
|
||||
*/
|
||||
bool scene_manager_search_and_switch_to_previous_scene(
|
||||
SceneManager* scene_manager,
|
||||
uint32_t scene_id);
|
||||
|
||||
/** Clear Scene stack and switch to another Scene
|
||||
* @param scene_manager SceneManager instance
|
||||
* @param scene_id Scene ID
|
||||
* @return true if previous scene was found, false otherwise
|
||||
*
|
||||
* @param scene_manager SceneManager instance
|
||||
* @param scene_id Scene ID
|
||||
*
|
||||
* @return true if previous scene was found, false otherwise
|
||||
*/
|
||||
bool scene_manager_search_and_switch_to_another_scene(
|
||||
SceneManager* scene_manager,
|
||||
|
||||
@ -1,3 +1,8 @@
|
||||
/**
|
||||
* @file scene_manager_i.h
|
||||
* GUI: internal SceneManager API
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "scene_manager.h"
|
||||
|
||||
@ -12,6 +12,11 @@ void view_free(View* view) {
|
||||
free(view);
|
||||
}
|
||||
|
||||
void view_tie_icon_animation(View* view, IconAnimation* icon_animation) {
|
||||
furi_assert(view);
|
||||
icon_animation_set_update_callback(icon_animation, view_icon_animation_callback, view);
|
||||
}
|
||||
|
||||
void view_set_draw_callback(View* view, ViewDrawCallback callback) {
|
||||
furi_assert(view);
|
||||
furi_assert(view->draw_callback == NULL);
|
||||
@ -120,6 +125,14 @@ void view_commit_model(View* view, bool update) {
|
||||
}
|
||||
}
|
||||
|
||||
void view_icon_animation_callback(IconAnimation* instance, void* context) {
|
||||
furi_assert(context);
|
||||
View* view = context;
|
||||
if(view->update_callback) {
|
||||
view->update_callback(view, view->update_callback_context);
|
||||
}
|
||||
}
|
||||
|
||||
void view_unlock_model(View* view) {
|
||||
furi_assert(view);
|
||||
if(view->model_type == ViewModelTypeLocking) {
|
||||
|
||||
@ -1,6 +1,13 @@
|
||||
/**
|
||||
* @file view.h
|
||||
* GUI: View API
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <input/input.h>
|
||||
|
||||
#include "icon_animation.h"
|
||||
#include "canvas.h"
|
||||
|
||||
#include <stddef.h>
|
||||
@ -10,9 +17,10 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Hides drawing view_port */
|
||||
/** Hides drawing view_port */
|
||||
#define VIEW_NONE 0xFFFFFFFF
|
||||
/* Ignore navigation event */
|
||||
|
||||
/** Ignore navigation event */
|
||||
#define VIEW_IGNORE 0xFFFFFFFE
|
||||
|
||||
typedef enum {
|
||||
@ -20,158 +28,181 @@ typedef enum {
|
||||
ViewOrientationVertical,
|
||||
} ViewOrientation;
|
||||
|
||||
/* View, anonymous type */
|
||||
/** View, anonymous type */
|
||||
typedef struct View View;
|
||||
|
||||
/* View Draw callback
|
||||
* @param canvas, pointer to canvas
|
||||
* @param view_model, pointer to context
|
||||
* @warning called from GUI thread
|
||||
/** View Draw callback
|
||||
* @param canvas, pointer to canvas
|
||||
* @param view_model, pointer to context
|
||||
* @warning called from GUI thread
|
||||
*/
|
||||
typedef void (*ViewDrawCallback)(Canvas* canvas, void* model);
|
||||
|
||||
/* View Input callback
|
||||
* @param event, pointer to input event data
|
||||
* @param context, pointer to context
|
||||
* @return true if event handled, false if event ignored
|
||||
* @warning called from GUI thread
|
||||
/** View Input callback
|
||||
* @param event, pointer to input event data
|
||||
* @param context, pointer to context
|
||||
* @return true if event handled, false if event ignored
|
||||
* @warning called from GUI thread
|
||||
*/
|
||||
typedef bool (*ViewInputCallback)(InputEvent* event, void* context);
|
||||
|
||||
/* View Custom callback
|
||||
* @param event, number of custom event
|
||||
* @param context, pointer to context
|
||||
* @return true if event handled, false if event ignored
|
||||
/** View Custom callback
|
||||
* @param event, number of custom event
|
||||
* @param context, pointer to context
|
||||
* @return true if event handled, false if event ignored
|
||||
*/
|
||||
typedef bool (*ViewCustomCallback)(uint32_t event, void* context);
|
||||
|
||||
/* View navigation callback
|
||||
* @param context, pointer to context
|
||||
* @return next view id
|
||||
* @warning called from GUI thread
|
||||
/** View navigation callback
|
||||
* @param context, pointer to context
|
||||
* @return next view id
|
||||
* @warning called from GUI thread
|
||||
*/
|
||||
typedef uint32_t (*ViewNavigationCallback)(void* context);
|
||||
|
||||
/* View callback
|
||||
* @param context, pointer to context
|
||||
* @warning called from GUI thread
|
||||
/** View callback
|
||||
* @param context, pointer to context
|
||||
* @warning called from GUI thread
|
||||
*/
|
||||
typedef void (*ViewCallback)(void* context);
|
||||
|
||||
/* View Update Callback
|
||||
* Called upon model change, need to be propagated to GUI throw ViewPort update
|
||||
* @param view, pointer to view
|
||||
* @param context, pointer to context
|
||||
* @warning called from GUI thread
|
||||
/** View Update Callback Called upon model change, need to be propagated to GUI
|
||||
* throw ViewPort update
|
||||
* @param view, pointer to view
|
||||
* @param context, pointer to context
|
||||
* @warning called from GUI thread
|
||||
*/
|
||||
typedef void (*ViewUpdateCallback)(View* view, void* context);
|
||||
|
||||
/* View model types */
|
||||
/** View model types */
|
||||
typedef enum {
|
||||
/* Model is not allocated */
|
||||
/** Model is not allocated */
|
||||
ViewModelTypeNone,
|
||||
/* Model consist of atomic types and/or partial update is not critical for rendering.
|
||||
/** Model consist of atomic types and/or partial update is not critical for rendering.
|
||||
* Lock free.
|
||||
*/
|
||||
ViewModelTypeLockFree,
|
||||
/* Model access is guarded with mutex.
|
||||
/** Model access is guarded with mutex.
|
||||
* Locking gui thread.
|
||||
*/
|
||||
ViewModelTypeLocking,
|
||||
} ViewModelType;
|
||||
|
||||
/* Allocate and init View
|
||||
* @return pointer to View
|
||||
/** Allocate and init View
|
||||
* @return View instance
|
||||
*/
|
||||
View* view_alloc();
|
||||
|
||||
/* Free View
|
||||
* @param pointer to View
|
||||
/** Free View
|
||||
*
|
||||
* @param view instance
|
||||
*/
|
||||
void view_free(View* view);
|
||||
|
||||
/* Set View Draw callback
|
||||
* @param view, pointer to View
|
||||
* @param callback, draw callback
|
||||
/** Tie IconAnimation with View
|
||||
*
|
||||
* @param view View instance
|
||||
* @param icon_animation IconAnimation instance
|
||||
*/
|
||||
void view_tie_icon_animation(View* view, IconAnimation* icon_animation);
|
||||
|
||||
/** Set View Draw callback
|
||||
*
|
||||
* @param view View instance
|
||||
* @param callback draw callback
|
||||
*/
|
||||
void view_set_draw_callback(View* view, ViewDrawCallback callback);
|
||||
|
||||
/* Set View Input callback
|
||||
* @param view, pointer to View
|
||||
* @param callback, input callback
|
||||
/** Set View Input callback
|
||||
*
|
||||
* @param view View instance
|
||||
* @param callback input callback
|
||||
*/
|
||||
void view_set_input_callback(View* view, ViewInputCallback callback);
|
||||
|
||||
/* Set View Custom callback
|
||||
* @param view, pointer to View
|
||||
* @param callback, input callback
|
||||
/** Set View Custom callback
|
||||
*
|
||||
* @param view View instance
|
||||
* @param callback input callback
|
||||
*/
|
||||
void view_set_custom_callback(View* view, ViewCustomCallback callback);
|
||||
|
||||
/* Set Navigation Previous callback
|
||||
* @param view, pointer to View
|
||||
* @param callback, input callback
|
||||
/** Set Navigation Previous callback
|
||||
*
|
||||
* @param view View instance
|
||||
* @param callback input callback
|
||||
*/
|
||||
void view_set_previous_callback(View* view, ViewNavigationCallback callback);
|
||||
|
||||
/* Set Enter callback
|
||||
* @param view, pointer to View
|
||||
* @param callback, callback
|
||||
/** Set Enter callback
|
||||
*
|
||||
* @param view View instance
|
||||
* @param callback callback
|
||||
*/
|
||||
void view_set_enter_callback(View* view, ViewCallback callback);
|
||||
|
||||
/* Set Exit callback
|
||||
* @param view, pointer to View
|
||||
* @param callback, callback
|
||||
/** Set Exit callback
|
||||
*
|
||||
* @param view View instance
|
||||
* @param callback callback
|
||||
*/
|
||||
void view_set_exit_callback(View* view, ViewCallback callback);
|
||||
|
||||
/* Set Update callback
|
||||
* @param view, pointer to View
|
||||
* @param callback, callback
|
||||
/** Set Update callback
|
||||
*
|
||||
* @param view View instance
|
||||
* @param callback callback
|
||||
*/
|
||||
void view_set_update_callback(View* view, ViewUpdateCallback callback);
|
||||
|
||||
/* Set View Draw callback
|
||||
* @param view, pointer to View
|
||||
* @param context, context for callbacks
|
||||
/** Set View Draw callback
|
||||
*
|
||||
* @param view View instance
|
||||
* @param context context for callbacks
|
||||
*/
|
||||
void view_set_update_callback_context(View* view, void* context);
|
||||
|
||||
/* Set View Draw callback
|
||||
* @param view, pointer to View
|
||||
* @param context, context for callbacks
|
||||
/** Set View Draw callback
|
||||
*
|
||||
* @param view View instance
|
||||
* @param context context for callbacks
|
||||
*/
|
||||
void view_set_context(View* view, void* context);
|
||||
|
||||
/* Set View Orientation
|
||||
* @param view, pointer to View
|
||||
* @param orientation, either vertical or horizontal
|
||||
/** Set View Orientation
|
||||
*
|
||||
* @param view View instance
|
||||
* @param orientation either vertical or horizontal
|
||||
*/
|
||||
void view_set_orientation(View* view, ViewOrientation orientation);
|
||||
|
||||
/* Allocate view model.
|
||||
* @param view, pointer to View
|
||||
* @param type, View Model Type
|
||||
* @param size, size
|
||||
/** Allocate view model.
|
||||
*
|
||||
* @param view View instance
|
||||
* @param type View Model Type
|
||||
* @param size size
|
||||
*/
|
||||
void view_allocate_model(View* view, ViewModelType type, size_t size);
|
||||
|
||||
/* Free view model data memory.
|
||||
* @param view, pointer to View
|
||||
/** Free view model data memory.
|
||||
*
|
||||
* @param view View instance
|
||||
*/
|
||||
void view_free_model(View* view);
|
||||
|
||||
/* Get view model data
|
||||
* @param view, pointer to View
|
||||
* @return pointer to model data
|
||||
* @warning Don't forget to commit model changes
|
||||
/** Get view model data
|
||||
*
|
||||
* @param view View instance
|
||||
*
|
||||
* @return pointer to model data
|
||||
* @warning Don't forget to commit model changes
|
||||
*/
|
||||
void* view_get_model(View* view);
|
||||
|
||||
/* Commit view model
|
||||
* @param view, pointer to View
|
||||
* @param update, true if you want to emit view update, false otherwise
|
||||
/** Commit view model
|
||||
*
|
||||
* @param view View instance
|
||||
* @param update true if you want to emit view update, false otherwise
|
||||
*/
|
||||
void view_commit_model(View* view, bool update);
|
||||
|
||||
@ -187,11 +218,13 @@ void view_commit_model(View* view, bool update);
|
||||
view_commit_model(view, update); \
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* With clause for view model
|
||||
* @param view, View instance pointer
|
||||
* @param function_body a (){} lambda declaration, executed within you parent function context
|
||||
* @return true if you want to emit view update, false otherwise
|
||||
/** With clause for view model
|
||||
*
|
||||
* @param view View instance pointer
|
||||
* @param function_body a (){} lambda declaration, executed within you
|
||||
* parent function context
|
||||
*
|
||||
* @return true if you want to emit view update, false otherwise
|
||||
*/
|
||||
#define with_view_model(view, function_body) \
|
||||
{ \
|
||||
|
||||
@ -177,6 +177,18 @@ void view_dispatcher_switch_to_view(ViewDispatcher* view_dispatcher, uint32_t vi
|
||||
}
|
||||
}
|
||||
|
||||
void view_dispatcher_send_to_front(ViewDispatcher* view_dispatcher) {
|
||||
furi_assert(view_dispatcher);
|
||||
furi_assert(view_dispatcher->gui);
|
||||
gui_view_port_send_to_front(view_dispatcher->gui, view_dispatcher->view_port);
|
||||
}
|
||||
|
||||
void view_dispatcher_send_to_back(ViewDispatcher* view_dispatcher) {
|
||||
furi_assert(view_dispatcher);
|
||||
furi_assert(view_dispatcher->gui);
|
||||
gui_view_port_send_to_front(view_dispatcher->gui, view_dispatcher->view_port);
|
||||
}
|
||||
|
||||
void view_dispatcher_attach_to_gui(
|
||||
ViewDispatcher* view_dispatcher,
|
||||
Gui* gui,
|
||||
|
||||
@ -1,3 +1,8 @@
|
||||
/**
|
||||
* @file view_dispatcher.h
|
||||
* GUI: ViewDispatcher API
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "view.h"
|
||||
@ -8,8 +13,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** ViewDispatcher view_port placement
|
||||
*/
|
||||
/** ViewDispatcher view_port placement */
|
||||
typedef enum {
|
||||
ViewDispatcherTypeNone, /**< Special layer for internal use only */
|
||||
ViewDispatcherTypeWindow, /**< Main view_port layer, status bar is shown */
|
||||
@ -18,61 +22,70 @@ typedef enum {
|
||||
|
||||
typedef struct ViewDispatcher ViewDispatcher;
|
||||
|
||||
/** Prototype for custom event callback
|
||||
*/
|
||||
/** Prototype for custom event callback */
|
||||
typedef bool (*ViewDispatcherCustomEventCallback)(void* context, uint32_t event);
|
||||
|
||||
/** Prototype for navigation event callback
|
||||
*/
|
||||
/** Prototype for navigation event callback */
|
||||
typedef bool (*ViewDispatcherNavigationEventCallback)(void* context);
|
||||
|
||||
/** Prototype for tick event callback
|
||||
*/
|
||||
/** Prototype for tick event callback */
|
||||
typedef void (*ViewDispatcherTickEventCallback)(void* context);
|
||||
|
||||
/** Allocate ViewDispatcher instance
|
||||
* @return pointer to ViewDispatcher instance
|
||||
*
|
||||
* @return pointer to ViewDispatcher instance
|
||||
*/
|
||||
ViewDispatcher* view_dispatcher_alloc();
|
||||
|
||||
/** Free ViewDispatcher instance
|
||||
* @param view_dispatcher pointer to ViewDispatcher
|
||||
*
|
||||
* @param view_dispatcher pointer to ViewDispatcher
|
||||
*/
|
||||
void view_dispatcher_free(ViewDispatcher* view_dispatcher);
|
||||
|
||||
/** Enable queue support
|
||||
* If queue enabled all input and custom events will be dispatched throw internal queue
|
||||
* @param view_dispatcher ViewDispatcher instance
|
||||
*
|
||||
* If queue enabled all input and custom events will be dispatched throw
|
||||
* internal queue
|
||||
*
|
||||
* @param view_dispatcher ViewDispatcher instance
|
||||
*/
|
||||
void view_dispatcher_enable_queue(ViewDispatcher* view_dispatcher);
|
||||
|
||||
/** Send custom event
|
||||
* @param view_dispatcher ViewDispatcher instance
|
||||
*
|
||||
* @param view_dispatcher ViewDispatcher instance
|
||||
* @param[in] event The event
|
||||
*/
|
||||
void view_dispatcher_send_custom_event(ViewDispatcher* view_dispatcher, uint32_t event);
|
||||
|
||||
/** Set custom event handler
|
||||
*
|
||||
* Called on Custom Event, if it is not consumed by view
|
||||
* @param view_dispatcher ViewDispatcher instance
|
||||
* @param callback ViewDispatcherCustomEventCallback instance
|
||||
*
|
||||
* @param view_dispatcher ViewDispatcher instance
|
||||
* @param callback ViewDispatcherCustomEventCallback instance
|
||||
*/
|
||||
void view_dispatcher_set_custom_event_callback(
|
||||
ViewDispatcher* view_dispatcher,
|
||||
ViewDispatcherCustomEventCallback callback);
|
||||
|
||||
/** Set navigation event handler
|
||||
*
|
||||
* Called on Input Short Back Event, if it is not consumed by view
|
||||
* @param view_dispatcher ViewDispatcher instance
|
||||
* @param callback ViewDispatcherNavigationEventCallback instance
|
||||
*
|
||||
* @param view_dispatcher ViewDispatcher instance
|
||||
* @param callback ViewDispatcherNavigationEventCallback instance
|
||||
*/
|
||||
void view_dispatcher_set_navigation_event_callback(
|
||||
ViewDispatcher* view_dispatcher,
|
||||
ViewDispatcherNavigationEventCallback callback);
|
||||
|
||||
/** Set tick event handler
|
||||
* @param view_dispatcher ViewDispatcher instance
|
||||
* @param callback ViewDispatcherTickEventCallback
|
||||
* @param tick_period callback call period
|
||||
*
|
||||
* @param view_dispatcher ViewDispatcher instance
|
||||
* @param callback ViewDispatcherTickEventCallback
|
||||
* @param tick_period callback call period
|
||||
*/
|
||||
void view_dispatcher_set_tick_event_callback(
|
||||
ViewDispatcher* view_dispatcher,
|
||||
@ -80,46 +93,69 @@ void view_dispatcher_set_tick_event_callback(
|
||||
uint32_t tick_period);
|
||||
|
||||
/** Set event callback context
|
||||
* @param view_dispatcher ViewDispatcher instance
|
||||
* @param context pointer to context
|
||||
*
|
||||
* @param view_dispatcher ViewDispatcher instance
|
||||
* @param context pointer to context
|
||||
*/
|
||||
void view_dispatcher_set_event_callback_context(ViewDispatcher* view_dispatcher, void* context);
|
||||
|
||||
/** Run ViewDispatcher
|
||||
*
|
||||
* Use only after queue enabled
|
||||
* @param view_dispatcher ViewDispatcher instance
|
||||
*
|
||||
* @param view_dispatcher ViewDispatcher instance
|
||||
*/
|
||||
void view_dispatcher_run(ViewDispatcher* view_dispatcher);
|
||||
|
||||
/** Stop ViewDispatcher
|
||||
*
|
||||
* Use only after queue enabled
|
||||
* @param view_dispatcher ViewDispatcher instance
|
||||
*
|
||||
* @param view_dispatcher ViewDispatcher instance
|
||||
*/
|
||||
void view_dispatcher_stop(ViewDispatcher* view_dispatcher);
|
||||
|
||||
/** Add view to ViewDispatcher
|
||||
* @param view_dispatcher, ViewDispatcher instance
|
||||
* @param view_id View id to register
|
||||
* @param view View instance
|
||||
*
|
||||
* @param view_dispatcher ViewDispatcher instance
|
||||
* @param view_id View id to register
|
||||
* @param view View instance
|
||||
*/
|
||||
void view_dispatcher_add_view(ViewDispatcher* view_dispatcher, uint32_t view_id, View* view);
|
||||
|
||||
/** Remove view from ViewDispatcher
|
||||
* @param view_dispatcher ViewDispatcher instance
|
||||
* @param view_id View id to remove
|
||||
*
|
||||
* @param view_dispatcher ViewDispatcher instance
|
||||
* @param view_id View id to remove
|
||||
*/
|
||||
void view_dispatcher_remove_view(ViewDispatcher* view_dispatcher, uint32_t view_id);
|
||||
|
||||
/** Switch to View
|
||||
* @param view_dispatcher ViewDispatcher instance
|
||||
* @param view_id View id to register
|
||||
* @warning switching may be delayed till input events complementarity reached
|
||||
*
|
||||
* @param view_dispatcher ViewDispatcher instance
|
||||
* @param view_id View id to register
|
||||
* @warning switching may be delayed till input events complementarity
|
||||
* reached
|
||||
*/
|
||||
void view_dispatcher_switch_to_view(ViewDispatcher* view_dispatcher, uint32_t view_id);
|
||||
|
||||
/** Send ViewPort of this ViewDispatcher instance to front
|
||||
*
|
||||
* @param view_dispatcher ViewDispatcher instance
|
||||
*/
|
||||
void view_dispatcher_send_to_front(ViewDispatcher* view_dispatcher);
|
||||
|
||||
/** Send ViewPort of this ViewDispatcher instance to back
|
||||
*
|
||||
* @param view_dispatcher ViewDispatcher instance
|
||||
*/
|
||||
void view_dispatcher_send_to_back(ViewDispatcher* view_dispatcher);
|
||||
|
||||
/** Attach ViewDispatcher to GUI
|
||||
* @param view_dispatcher ViewDispatcher instance
|
||||
* @param gui GUI instance to attach to
|
||||
*
|
||||
* @param view_dispatcher ViewDispatcher instance
|
||||
* @param gui GUI instance to attach to
|
||||
* @param[in] type The type
|
||||
*/
|
||||
void view_dispatcher_attach_to_gui(
|
||||
ViewDispatcher* view_dispatcher,
|
||||
|
||||
@ -1,3 +1,8 @@
|
||||
/**
|
||||
* @file view_dispatcher_i.h
|
||||
* GUI: ViewDispatcher API
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <furi.h>
|
||||
@ -41,23 +46,23 @@ typedef struct {
|
||||
};
|
||||
} ViewDispatcherMessage;
|
||||
|
||||
/* ViewPort Draw Callback */
|
||||
/** ViewPort Draw Callback */
|
||||
void view_dispatcher_draw_callback(Canvas* canvas, void* context);
|
||||
|
||||
/* ViewPort Input Callback */
|
||||
/** ViewPort Input Callback */
|
||||
void view_dispatcher_input_callback(InputEvent* event, void* context);
|
||||
|
||||
/* Input handler */
|
||||
/** Input handler */
|
||||
void view_dispatcher_handle_input(ViewDispatcher* view_dispatcher, InputEvent* event);
|
||||
|
||||
/* Tick handler */
|
||||
/** Tick handler */
|
||||
void view_dispatcher_handle_tick_event(ViewDispatcher* view_dispatcher);
|
||||
|
||||
/* Custom event handler */
|
||||
/** Custom event handler */
|
||||
void view_dispatcher_handle_custom_event(ViewDispatcher* view_dispatcher, uint32_t event);
|
||||
|
||||
/* Set current view, dispatches view enter and exit */
|
||||
/** Set current view, dispatches view enter and exit */
|
||||
void view_dispatcher_set_current_view(ViewDispatcher* view_dispatcher, View* view);
|
||||
|
||||
/* ViewDispatcher update event */
|
||||
/** ViewDispatcher update event */
|
||||
void view_dispatcher_update(View* view, void* context);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user