pebble/src/fw/applib/ui/action_menu_hierarchy.c
2025-01-27 11:38:16 -08:00

125 lines
3.5 KiB
C

/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "action_menu_hierarchy.h"
#include "action_menu_window_private.h"
#include "applib/applib_malloc.auto.h"
#include "kernel/pbl_malloc.h"
// Item
/////////////////////////////////
char *action_menu_item_get_label(const ActionMenuItem *item) {
if (item == NULL) {
return NULL;
}
return (char *)item->label;
}
void *action_menu_item_get_action_data(const ActionMenuItem *item) {
if (item == NULL || !item->is_leaf) {
return NULL;
}
return (void *)item->action_data;
}
// Level
/////////////////////////////////
ActionMenuLevel *action_menu_level_create(uint16_t max_items) {
// TODO add applib-malloc padding
ActionMenuLevel *level = applib_malloc(applib_type_size(ActionMenuLevel) +
max_items * applib_type_size(ActionMenuItem));
if (!level) return NULL;
*level = (ActionMenuLevel){
.max_items = max_items,
.display_mode = ActionMenuLevelDisplayModeWide,
};
return level;
}
void action_menu_level_set_display_mode(ActionMenuLevel *level,
ActionMenuLevelDisplayMode display_mode) {
if (!level) return;
level->display_mode = display_mode;
}
ActionMenuItem *action_menu_level_add_action(ActionMenuLevel *level,
const char *label,
ActionMenuPerformActionCb cb,
void *action_data) {
if (!level || !label || !cb ||
(level->num_items >= level->max_items)) {
return NULL;
}
ActionMenuItem *item = &level->items[level->num_items];
*item = (ActionMenuItem) {
.label = label,
.perform_action = cb,
.action_data = action_data,
};
++level->num_items;
return item;
}
ActionMenuItem *action_menu_level_add_child(ActionMenuLevel *level,
ActionMenuLevel *child,
const char *label) {
if (!level || !child || !label ||
(level->num_items >= level->max_items)) {
return NULL;
}
child->parent_level = level;
ActionMenuItem *item = &level->items[level->num_items];
*item = (ActionMenuItem) {
.label = label,
.next_level = child,
};
++level->num_items;
return item;
}
// Hierarchy
/////////////////////////////////
static void prv_cleanup_helper(const ActionMenuLevel *level,
ActionMenuEachItemCb each_cb,
void *context) {
for (int i = 0; i < level->num_items; ++i) {
const ActionMenuItem *item = &level->items[i];
if (!item->is_leaf && item->next_level) {
prv_cleanup_helper(item->next_level, each_cb, context);
}
if (each_cb) {
each_cb(item, context);
}
}
applib_free((void *)level);
}
void action_menu_hierarchy_destroy(const ActionMenuLevel *root,
ActionMenuEachItemCb each_cb,
void *context) {
if (root) {
prv_cleanup_helper(root, each_cb, context);
}
}