Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add coverflow menu style. #314

Open
wants to merge 2 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const char* const menu_style_names[MenuStyleCount] = {
"C64",
"Compact",
"MNTM",
"CoverFlow",
};
static void momentum_app_scene_interface_mainmenu_menu_style_changed(VariableItem* item) {
MomentumApp* app = variable_item_get_context(item);
Expand Down
42 changes: 34 additions & 8 deletions applications/services/gui/canvas.c
Original file line number Diff line number Diff line change
Expand Up @@ -294,27 +294,53 @@ void canvas_draw_bitmap(
canvas_draw_u8g2_bitmap(&canvas->fb, x, y, width, height, bitmap_data, IconRotation0);
}

void canvas_draw_icon_animation(
static void _canvas_draw_icon_animation(
Canvas* canvas,
int32_t x,
int32_t y,
int32_t width_scale,
int32_t height_scale,
CodyTolene marked this conversation as resolved.
Show resolved Hide resolved
IconAnimation* icon_animation) {
furi_check(canvas);
furi_check(icon_animation);
// Ensure scale % is > 0
furi_assert(width_scale > 0 && height_scale > 0);
// Ensure scale % is <= 100: animated icons > 100% are buggy
// TODO: Future, allow scaling > 100
furi_assert(width_scale <= 100 && height_scale <= 100);

x += canvas->offset_x;
y += canvas->offset_y;

uint8_t* icon_data = NULL;
compress_icon_decode(
canvas->compress_icon, icon_animation_get_data(icon_animation), &icon_data);

int32_t width = icon_animation_get_width(icon_animation);
int32_t height = icon_animation_get_height(icon_animation);
int32_t width_scaled = (width * width_scale) / 100;
int32_t height_scaled = (height * height_scale) / 100;

canvas_draw_u8g2_bitmap(
&canvas->fb,
x,
y,
icon_animation_get_width(icon_animation),
icon_animation_get_height(icon_animation),
icon_data,
IconRotation0);
&canvas->fb, x, y, width_scaled, height_scaled, icon_data, IconRotation0);
}

void canvas_draw_icon_animation(
Canvas* canvas,
int32_t x,
int32_t y,
IconAnimation* icon_animation) {
_canvas_draw_icon_animation(canvas, x, y, 100, 100, icon_animation);
}

void canvas_draw_icon_animation_ex(
Canvas* canvas,
int32_t x,
int32_t y,
int32_t width_scale,
int32_t height_scale,
IconAnimation* icon_animation) {
_canvas_draw_icon_animation(canvas, x, y, width_scale, height_scale, icon_animation);
}

static void canvas_draw_u8g2_bitmap_int(
Expand Down
23 changes: 23 additions & 0 deletions applications/services/gui/canvas.h
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,9 @@ void canvas_draw_icon_ex(
IconRotation rotation);

/** Draw animation at position defined by x,y.
*
* This function is retained for backward compatibility and draws the animation
* at the specified position without scaling.
*
* @param canvas Canvas instance
* @param x x coordinate
Expand All @@ -270,6 +273,26 @@ void canvas_draw_icon_animation(
int32_t y,
IconAnimation* icon_animation);

/** Draw animation at position defined by x,y with scaling.
*
* This extended version allows scaling of the animation dimensions by percentage.
* The width and height are scaled independently.
*
* @param canvas Canvas instance
* @param x x coordinate
* @param y y coordinate
* @param width_scale Scaled (%) width of the icon (1–100%)
* @param height_scale Scaled (%) height of the icon (1–100%)
* @param icon_animation IconAnimation instance
*/
void canvas_draw_icon_animation_ex(
Canvas* canvas,
int32_t x,
int32_t y,
int32_t width_scale,
int32_t height_scale,
IconAnimation* icon_animation);

/** Draw icon at position defined by x,y.
*
* @param canvas Canvas instance
Expand Down
135 changes: 133 additions & 2 deletions applications/services/gui/modules/menu.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,24 @@ static void menu_centered_icon(
item->icon);
}

static void menu_centered_icon_scaled(
Canvas* canvas,
MenuItem* item,
size_t x,
size_t y,
size_t width,
size_t height,
size_t width_scale,
size_t height_scale) {
canvas_draw_icon_animation_ex(
canvas,
x + (width - item->icon->icon->width) / 2,
y + (height - item->icon->icon->height) / 2,
width_scale,
height_scale,
item->icon);
}

static size_t menu_scroll_counter(MenuModel* model, bool selected) {
if(!selected) return 0;
size_t scroll_counter = model->scroll_counter;
Expand Down Expand Up @@ -442,6 +460,115 @@ static void menu_draw_callback(Canvas* canvas, void* _model) {
}
break;
}
case MenuStyleCoverFlow: {
canvas_clear(canvas);
canvas_set_font(canvas, FontPrimary);

// Draw frames
canvas_set_bitmap_mode(canvas, true);
canvas_draw_frame(canvas, 0, 0, 128, 64);
canvas_draw_frame(canvas, 44, 2, 40, 40);

// Draw left side albums
canvas_draw_line(canvas, 6, 40, 17, 35);
canvas_draw_line(canvas, 19, 40, 30, 35);
canvas_draw_line(canvas, 32, 40, 43, 35);
canvas_draw_line(canvas, 6, 3, 17, 8);
canvas_draw_line(canvas, 19, 3, 30, 8);
canvas_draw_line(canvas, 32, 3, 43, 8);
canvas_draw_line(canvas, 18, 2, 18, 41);
canvas_draw_line(canvas, 31, 2, 31, 41);
canvas_draw_line(canvas, 5, 2, 5, 41);
canvas_draw_line(canvas, 4, 8, 1, 7);
canvas_draw_line(canvas, 5, 35, 1, 36);

// Draw right side albums
canvas_draw_line(canvas, 95, 40, 84, 35);
canvas_draw_line(canvas, 108, 40, 97, 35);
canvas_draw_line(canvas, 121, 40, 110, 35);
canvas_draw_line(canvas, 84, 8, 95, 3);
canvas_draw_line(canvas, 97, 8, 108, 3);
canvas_draw_line(canvas, 110, 8, 121, 3);
canvas_draw_line(canvas, 96, 2, 96, 41);
canvas_draw_line(canvas, 109, 2, 109, 41);
canvas_draw_line(canvas, 122, 2, 122, 41);
canvas_draw_line(canvas, 123, 8, 126, 7);
canvas_draw_line(canvas, 123, 35, 126, 36);

const int32_t pos_x_center = 128 / 2;
const int32_t pos_y_center = 64 / 2;
const int32_t pos_y_offset = 10;
const int32_t icon_size = 20;
const int32_t side_icon_width = icon_size / 2;
const int32_t padding_center_icon = 14;
const int32_t spacing_between_icons = 3;
const int32_t scale_base = 100;

MenuItem* center_item = NULL;

// Draw 7 icons, where index 0 is the center icon
// [-3, -2, -1, 0, 1, 2, 3]
for(int8_t i = -3; i <= 3; i++) {
shift_position = (position + items_count + i) % items_count;
item = MenuItemArray_get(model->items, shift_position);

int32_t pos_x = pos_x_center;
int32_t pos_y = pos_y_center;

int32_t scale_width = scale_base;
int32_t scale_height = scale_base;

if(i < 0) {
// Left sided icons
pos_x -= padding_center_icon;
pos_x -= ((-i) * (side_icon_width + spacing_between_icons));
pos_x -= (side_icon_width / 2) / 2;
pos_y = (pos_y_center - icon_size / 2) - pos_y_offset;
scale_width = 50;
} else if(i > 0) {
// Right sided icons
pos_x += padding_center_icon;
pos_x += (i * (side_icon_width + spacing_between_icons));
pos_x -= side_icon_width;
pos_y = (pos_y_center - icon_size / 2) - pos_y_offset;
scale_width = 50;
} else if(i == 0) {
// Center icon
pos_x -= icon_size / 2;
pos_y = (pos_y_center - (icon_size / 2)) - pos_y_offset;
// Scaling > 100% doesn't look good, keep 100% for now
scale_width = scale_base; // TODO: 200%
scale_height = scale_base; // TODO: 200%
// Save center item pointer for later
center_item = item;
}

// Draw the icon
menu_centered_icon_scaled(
canvas, item, pos_x, pos_y, icon_size, icon_size, scale_width, scale_height);
}

// Draw label for center item
if(center_item) {
FuriString* name = furi_string_alloc();
menu_get_name(center_item, name, false);
elements_scrollable_text_line_centered(
canvas,
pos_x_center,
(pos_y_center + icon_size / 2) + pos_y_offset,
126,
name,
0,
false,
true);
furi_string_free(name);
}

// Add scrollbar element
elements_scrollbar_horizontal(canvas, 0, 60, 128, position, items_count);

break;
}
default:
break;
}
Expand Down Expand Up @@ -818,7 +945,9 @@ static void menu_process_left(Menu* menu) {
position = position - 8;
}
break;

case MenuStyleCoverFlow:
position = (position + count - 1) % count;
break;
default:
break;
}
Expand Down Expand Up @@ -882,7 +1011,9 @@ static void menu_process_right(Menu* menu) {
position = position - 8;
}
break;

case MenuStyleCoverFlow:
position = (position + 1) % count;
break;
default:
break;
}
Expand Down
1 change: 1 addition & 0 deletions lib/momentum/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ typedef enum {
MenuStyleC64,
MenuStyleCompact,
MenuStyleMNTM,
MenuStyleCoverFlow,
MenuStyleCount,
} MenuStyle;

Expand Down
2 changes: 1 addition & 1 deletion targets/f18/api_symbols.csv
Original file line number Diff line number Diff line change
Expand Up @@ -737,7 +737,7 @@ Function,+,canvas_draw_dot,void,"Canvas*, int32_t, int32_t"
Function,+,canvas_draw_frame,void,"Canvas*, int32_t, int32_t, size_t, size_t"
Function,+,canvas_draw_glyph,void,"Canvas*, int32_t, int32_t, uint16_t"
Function,+,canvas_draw_icon,void,"Canvas*, int32_t, int32_t, const Icon*"
Function,+,canvas_draw_icon_animation,void,"Canvas*, int32_t, int32_t, IconAnimation*"
Function,+,canvas_draw_icon_animation,void,"Canvas*, int32_t, int32_t, int32_t, int32_t, IconAnimation*"
Function,+,canvas_draw_icon_ex,void,"Canvas*, int32_t, int32_t, const Icon*, IconRotation"
Function,+,canvas_draw_line,void,"Canvas*, int32_t, int32_t, int32_t, int32_t"
Function,+,canvas_draw_rbox,void,"Canvas*, int32_t, int32_t, size_t, size_t, size_t"
Expand Down
1 change: 1 addition & 0 deletions targets/f7/api_symbols.csv
Original file line number Diff line number Diff line change
Expand Up @@ -834,6 +834,7 @@ Function,+,canvas_draw_frame,void,"Canvas*, int32_t, int32_t, size_t, size_t"
Function,+,canvas_draw_glyph,void,"Canvas*, int32_t, int32_t, uint16_t"
Function,+,canvas_draw_icon,void,"Canvas*, int32_t, int32_t, const Icon*"
Function,+,canvas_draw_icon_animation,void,"Canvas*, int32_t, int32_t, IconAnimation*"
Function,+,canvas_draw_icon_animation_ex,void,"Canvas*, int32_t, int32_t, int32_t, int32_t, IconAnimation*"
Function,+,canvas_draw_icon_ex,void,"Canvas*, int32_t, int32_t, const Icon*, IconRotation"
Function,+,canvas_draw_line,void,"Canvas*, int32_t, int32_t, int32_t, int32_t"
Function,+,canvas_draw_rbox,void,"Canvas*, int32_t, int32_t, size_t, size_t, size_t"
Expand Down