esphome/esphome/components/display_menu_base/display_menu_base.cpp

330 lines
7.5 KiB
C++

#include "display_menu_base.h"
#include <algorithm>
namespace esphome {
namespace display_menu_base {
void DisplayMenuComponent::up() {
if (this->check_healthy_and_active_()) {
bool changed = false;
if (this->editing_) {
switch (this->mode_) {
case MENU_MODE_ROTARY:
changed = this->get_selected_item_()->select_prev();
break;
default:
break;
}
} else {
changed = this->cursor_up_();
}
if (changed)
this->draw_and_update();
}
}
void DisplayMenuComponent::down() {
if (this->check_healthy_and_active_()) {
bool changed = false;
if (this->editing_) {
switch (this->mode_) {
case MENU_MODE_ROTARY:
changed = this->get_selected_item_()->select_next();
break;
default:
break;
}
} else {
changed = this->cursor_down_();
}
if (changed)
this->draw_and_update();
}
}
void DisplayMenuComponent::left() {
if (this->check_healthy_and_active_()) {
bool changed = false;
switch (this->get_selected_item_()->get_type()) {
case MENU_ITEM_SELECT:
case MENU_ITEM_SWITCH:
case MENU_ITEM_NUMBER:
case MENU_ITEM_CUSTOM:
switch (this->mode_) {
case MENU_MODE_ROTARY:
if (this->editing_) {
this->finish_editing_();
changed = true;
} else {
changed = this->leave_menu_();
}
break;
case MENU_MODE_JOYSTICK:
if (this->editing_ || this->get_selected_item_()->get_immediate_edit())
changed = this->get_selected_item_()->select_prev();
break;
default:
break;
}
break;
case MENU_ITEM_BACK:
changed = this->leave_menu_();
break;
default:
break;
}
if (changed)
this->draw_and_update();
}
}
void DisplayMenuComponent::right() {
if (this->check_healthy_and_active_()) {
bool changed = false;
switch (this->get_selected_item_()->get_type()) {
case MENU_ITEM_SELECT:
case MENU_ITEM_SWITCH:
case MENU_ITEM_NUMBER:
case MENU_ITEM_CUSTOM:
switch (this->mode_) {
case MENU_MODE_JOYSTICK:
if (this->editing_ || this->get_selected_item_()->get_immediate_edit())
changed = this->get_selected_item_()->select_next();
default:
break;
}
break;
case MENU_ITEM_MENU:
changed = this->enter_menu_();
break;
default:
break;
}
if (changed)
this->draw_and_update();
}
}
void DisplayMenuComponent::enter() {
if (this->check_healthy_and_active_()) {
bool changed = false;
MenuItem *item = this->get_selected_item_();
if (this->editing_) {
this->finish_editing_();
changed = true;
} else {
switch (item->get_type()) {
case MENU_ITEM_MENU:
changed = this->enter_menu_();
break;
case MENU_ITEM_BACK:
changed = this->leave_menu_();
break;
case MENU_ITEM_SELECT:
case MENU_ITEM_SWITCH:
case MENU_ITEM_CUSTOM:
if (item->get_immediate_edit()) {
changed = item->select_next();
} else {
this->editing_ = true;
item->on_enter();
changed = true;
}
break;
case MENU_ITEM_NUMBER:
// A number cannot be immediate in the rotary mode
if (!item->get_immediate_edit() || this->mode_ == MENU_MODE_ROTARY) {
this->editing_ = true;
item->on_enter();
changed = true;
}
break;
case MENU_ITEM_COMMAND:
changed = item->select_next();
break;
default:
break;
}
}
if (changed)
this->draw_and_update();
}
}
void DisplayMenuComponent::draw() {
if (this->check_healthy_and_active_())
this->draw_menu();
}
void DisplayMenuComponent::show_main() {
bool disp_changed = false;
if (this->is_failed())
return;
this->process_initial_();
this->on_before_show();
if (this->active_ && this->editing_)
this->finish_editing_();
if (this->displayed_item_ != this->root_item_) {
this->displayed_item_->on_leave();
disp_changed = true;
}
this->reset_();
this->active_ = true;
if (disp_changed) {
this->displayed_item_->on_enter();
}
this->draw_and_update();
this->on_after_show();
}
void DisplayMenuComponent::show() {
if (this->is_failed())
return;
this->process_initial_();
this->on_before_show();
if (!this->active_) {
this->active_ = true;
this->draw_and_update();
}
this->on_after_show();
}
void DisplayMenuComponent::hide() {
if (this->check_healthy_and_active_()) {
this->on_before_hide();
if (this->editing_)
this->finish_editing_();
this->active_ = false;
this->update();
this->on_after_hide();
}
}
void DisplayMenuComponent::reset_() {
this->displayed_item_ = this->root_item_;
this->cursor_index_ = this->top_index_ = 0;
this->selection_stack_.clear();
}
void DisplayMenuComponent::process_initial_() {
if (!this->root_on_enter_called_) {
this->root_item_->on_enter();
this->root_on_enter_called_ = true;
}
}
bool DisplayMenuComponent::check_healthy_and_active_() {
if (this->is_failed())
return false;
this->process_initial_();
return this->active_;
}
bool DisplayMenuComponent::cursor_up_() {
bool changed = false;
if (this->cursor_index_ > 0) {
changed = true;
--this->cursor_index_;
if (this->cursor_index_ < this->top_index_)
this->top_index_ = this->cursor_index_;
}
return changed;
}
bool DisplayMenuComponent::cursor_down_() {
bool changed = false;
if (this->cursor_index_ + 1 < this->displayed_item_->items_size()) {
changed = true;
++this->cursor_index_;
if (this->cursor_index_ >= this->top_index_ + this->rows_)
this->top_index_ = this->cursor_index_ - this->rows_ + 1;
}
return changed;
}
bool DisplayMenuComponent::enter_menu_() {
this->displayed_item_->on_leave();
this->displayed_item_ = static_cast<MenuItemMenu *>(this->get_selected_item_());
this->selection_stack_.push_front({this->top_index_, this->cursor_index_});
this->cursor_index_ = this->top_index_ = 0;
this->displayed_item_->on_enter();
return true;
}
bool DisplayMenuComponent::leave_menu_() {
bool changed = false;
if (this->displayed_item_->get_parent() != nullptr) {
this->displayed_item_->on_leave();
this->displayed_item_ = this->displayed_item_->get_parent();
this->top_index_ = this->selection_stack_.front().first;
this->cursor_index_ = this->selection_stack_.front().second;
this->selection_stack_.pop_front();
this->displayed_item_->on_enter();
changed = true;
}
return changed;
}
void DisplayMenuComponent::finish_editing_() {
switch (this->get_selected_item_()->get_type()) {
case MENU_ITEM_SELECT:
case MENU_ITEM_NUMBER:
case MENU_ITEM_SWITCH:
case MENU_ITEM_CUSTOM:
this->get_selected_item_()->on_leave();
break;
default:
break;
}
this->editing_ = false;
}
void DisplayMenuComponent::draw_menu() {
for (size_t i = 0; i < this->rows_ && this->top_index_ + i < this->displayed_item_->items_size(); ++i) {
this->draw_item(this->displayed_item_->get_item(this->top_index_ + i), i,
this->top_index_ + i == this->cursor_index_);
}
}
} // namespace display_menu_base
} // namespace esphome