aboutsummaryrefslogtreecommitdiff
path: root/src/c/gw2et.c
blob: e5918684ce2fa7da59c9ea463692ac4aba5da6f8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*
 * Copyright (C) 2026 Reiner Herrmann
 * SPDX-License-Identifier: GPL-3.0-or-later
 */

#include <pebble.h>
#include "event.h"

#define DEFAULT_NUM_EVENTS 30

static Window *main_window;
static MenuLayer *main_menu;

static uint16_t get_num_rows_callback(MenuLayer *menu_layer, uint16_t section_index, void *context) {
	// TODO: make this configurable
	return DEFAULT_NUM_EVENTS;
}

static int16_t get_cell_height_callback(struct MenuLayer *menu_layer, MenuIndex *cell_index, void *context) {
	// TODO: adjust for round displays (large in center, smaller above/below)
	return 50;
}

static void draw_row_callback(GContext *ctx, const Layer *cell_layer, MenuIndex *cell_index, void *context) {
	const struct Gw2Event *event = get_next_event(cell_index->row);

	const int16_t timer_box_width = 40;

	/* event title and region */
	GRect box = layer_get_bounds(cell_layer);
	box.size.w -= timer_box_width;
	box.origin.x += timer_box_width;
	box.size.h /= 2;
	graphics_draw_text(ctx, event->name, fonts_get_system_font(FONT_KEY_GOTHIC_24_BOLD),
	                   box, GTextOverflowModeTrailingEllipsis, GTextAlignmentLeft, NULL);
	box.origin.y += box.size.h;
	graphics_draw_text(ctx, event->location, fonts_get_system_font(FONT_KEY_GOTHIC_18),
	                   box, GTextOverflowModeTrailingEllipsis, GTextAlignmentLeft, NULL);

	/* color indicator for region */
#if defined(PBL_COLOR)
	GRect color_box = layer_get_bounds(cell_layer);
	color_box.size.w = timer_box_width - 3;
	const GColor8 category_color = color_for_category(event->category);
	graphics_context_set_fill_color(ctx, category_color);
	graphics_fill_rect(ctx, color_box, 0, 0);
	graphics_context_set_text_color(ctx, gcolor_legible_over(category_color));
#endif

	/* remaining minutes until start of event */
	const int minutes_remaining = minutes_to_event(event);
	const int hours = minutes_remaining / 60;
	const int minutes = minutes_remaining % 60;
	char timebuf[16];
	snprintf(timebuf, sizeof(timebuf), "%02d:%02d", hours, minutes);

	GRect timer_box = layer_get_bounds(cell_layer);
	timer_box.origin.x += 2;
	timer_box.origin.y += 15;
	timer_box.size.w = timer_box_width - 5;
	timer_box.size.h -= 15;
	graphics_draw_text(ctx, timebuf, fonts_get_system_font(FONT_KEY_GOTHIC_18),
                       timer_box, GTextOverflowModeTrailingEllipsis, GTextAlignmentLeft, NULL);
}

static void draw_header_callback(GContext *ctx, const Layer *cell_layer, uint16_t section_index, void *callback_context) {
	menu_cell_basic_header_draw(ctx, cell_layer, "Upcoming Events");
}

static int16_t get_header_height_callback(struct MenuLayer *menu_layer, uint16_t section_index, void *callback_context) {
	return MENU_CELL_BASIC_HEADER_HEIGHT;
}

static int16_t get_separator_height_callback(struct MenuLayer *menu_layer, MenuIndex *cell_index, void *callback_context) {
	return 1;
}

static void select_callback(struct MenuLayer *menu_layer, MenuIndex *cell_index, void *context) {
}

static void main_window_load(Window *window) {
	Layer *window_layer = window_get_root_layer(window);
	const GRect bounds = layer_get_unobstructed_bounds(window_layer);

	main_menu = menu_layer_create(bounds);
	menu_layer_set_click_config_onto_window(main_menu, window);
	menu_layer_set_callbacks(main_menu, NULL, (MenuLayerCallbacks) {
		.get_num_rows = get_num_rows_callback,
		.draw_row = draw_row_callback,
		.get_cell_height = get_cell_height_callback,
		.get_header_height = get_header_height_callback,
		.draw_header = draw_header_callback,
		.select_click = select_callback,
		.get_separator_height = get_separator_height_callback,
	});

	layer_add_child(window_layer, menu_layer_get_layer(main_menu));
}

static void main_window_unload(Window *window) {
	menu_layer_destroy(main_menu);
}

static void tick_handler(struct tm *tick_time, TimeUnits units_changed) {
	update_event_index();
	menu_layer_reload_data(main_menu);
}

static void init() {
	main_window = window_create();
	window_set_window_handlers(main_window, (WindowHandlers) {
		.load = main_window_load,
		.unload = main_window_unload,
	});
	window_stack_push(main_window, true);

	tick_timer_service_subscribe(MINUTE_UNIT, tick_handler);
	init_events();
}

static void deinit() {
	tick_timer_service_unsubscribe();
	window_destroy(main_window);
	cleanup_events();
}

int main() {
	init();
	app_event_loop();
	deinit();
}