fxIP-fork/src/ui.c

272 lines
5.9 KiB
C

#include "ui.h"
#include <gint/display.h>
#include <gint/keyboard.h>
#include <stdarg.h>
#include <gint/std/stdio.h>
#include <gint/std/stdlib.h>
#include <gint/std/string.h>
#include "util.h"
#include "log.h"
#include "uip/uip.h"
#include "uip/irc.h"
extern struct uip_stats uip_stat;
extern const char irc_username[];
uint8_t cursor_blink = 0;
char page_irc_channel_input_buffer[128];
uint8_t objectlog_storage[2048];
objectlog_t objectlog;
void ui_cursor_blink()
{
cursor_blink = !cursor_blink;
}
void ui_page_irc_message_submit(page_t *page)
{
printflength = snprintf(messagebuffer, sizeof(messagebuffer) - 1, "<%s> %s", irc_username, page->input_buffer);
printflength = MIN(sizeof(messagebuffer), printflength);
ui_write_log(PAGE_IRC_CHANNEL, 0, 0, messagebuffer, printflength);
messagelength = snprintf(messagebuffer, sizeof(messagebuffer), "PRIVMSG ##whitequark :%s", page->input_buffer);
messagelength = MIN(sizeof(messagebuffer), messagelength);
}
const page_t pages[] = {
{
/* Logs */
.id = PAGE_LOGS,
.key = KEY_F1,
.render_callback = ui_render_logs,
.input_enabled = 0,
},
{
/* Statistics */
.id = PAGE_STATISTICS,
.key = KEY_F2,
.render_callback = ui_render_statistics,
.input_enabled = 0
},
{
/* IRC Overview */
.id = PAGE_IRC_OVERVIEW,
.key = KEY_F3,
.render_callback = ui_render_logs,
.input_enabled = 0
},
{
/* IRC Channel */
.id = PAGE_IRC_CHANNEL,
.key = KEY_F4,
.render_callback = ui_render_logs,
.input_enabled = 1,
.input_buffer = page_irc_channel_input_buffer,
.input_buffer_size = sizeof(page_irc_channel_input_buffer),
.input_submit_callback = ui_page_irc_message_submit
},
};
page_t *current_page = &pages[0];
void ui_update()
{
dclear(C_WHITE);
current_page->render_callback(current_page);
if (current_page->input_enabled)
{
drect(0, 55, 128, 64, C_BLACK);
char *scrolled_input = current_page->input_buffer;
if (current_page->input_offset > UI_DISPLAY_CHARS)
{
scrolled_input += MIN(current_page->input_scroll_offset,
current_page->input_offset - UI_DISPLAY_CHARS);
}
uint16_t scrolled_input_length = strlen(scrolled_input);
dtext_opt(1, 56, C_WHITE, C_NONE, DTEXT_LEFT, DTEXT_TOP, scrolled_input, scrolled_input_length);
if (cursor_blink)
{
int width = 0;
int height = 0;
dnsize(scrolled_input, scrolled_input_length, NULL, &width, &height);
dtext_opt(1 + width, 56, C_WHITE, C_NONE, DTEXT_LEFT, DTEXT_TOP, "_", 1);
}
}
dupdate();
}
void ui_update_logs()
{
if (current_page->id == 0)
{
ui_update();
}
}
void ui_render_logs(page_t *page)
{
uint16_t lines_drawn = 0;
uint8_t max_lines = UI_DISPLAY_LINES;
if (page->input_enabled)
{
max_lines--;
}
for (unsigned int i = 0; i < objectlog.num_entries && lines_drawn < max_lines; i++)
{
uint8_t pencil_x = 0;
uint8_t pencil_y = (max_lines - lines_drawn) * 8;
int width = 0;
int height = 0;
message_hdr_t hdr;
hdr.page_id = 0xFF;
uint8_t length;
objectlog_iterator_t iter;
const uint8_t *ptr;
ptr = ui_objectlog_get_message(&objectlog, -i, page->scroll_x, &iter, &hdr, &length);
if (hdr.page_id == page->id)
{
if (!ptr)
{
lines_drawn++;
continue;
}
do {
if (length)
{
dtext_opt(pencil_x, pencil_y, C_BLACK, C_NONE, DTEXT_LEFT, DTEXT_TOP, ptr, length);
dnsize(ptr, length, NULL, &width, &height);
pencil_x += width;
if (pencil_x > UI_DISPLAY_PIXEL_X)
{
break;
}
}
iter = objectlog_next(&objectlog, iter);
ptr = objectlog_get_fragment(&objectlog, iter, &length);
} while (iter >= 0);
lines_drawn++;
}
}
}
const void *ui_objectlog_get_message(objectlog_t *log, int object_idx, unsigned offset, objectlog_iterator_t *riter, message_hdr_t *hdr, uint8_t *len)
{
uint8_t length;
uint8_t bytes_read = 0;
const uint8_t *ptr;
objectlog_iterator_t iter = objectlog_iterator(log, object_idx);
if (iter < 0)
{
return NULL;
}
do {
ptr = objectlog_get_fragment(log, iter, &length);
uint8_t cpylen = MIN(sizeof(message_hdr_t) - bytes_read, length);
memcpy(((uint8_t*)hdr) + bytes_read, ptr, cpylen);
bytes_read += cpylen;
} while (bytes_read < sizeof(message_hdr_t));
length -= bytes_read;
ptr += bytes_read;
while (offset)
{
unsigned int read_len = length;
if (read_len > offset)
{
read_len = offset;
}
ptr += read_len;
offset -= read_len;
length -= read_len;
if (!length)
{
iter = objectlog_next(&objectlog, iter);
if (iter <= 0)
{
return NULL;
}
ptr = objectlog_get_fragment(&objectlog, iter, &length);
}
}
*riter = iter;
*len = length;
return ptr;
}
void ui_init()
{
for (unsigned int i = 0; i < ARRAY_SIZE(pages); i++)
{
if (pages[i].input_buffer)
{
memset(pages[i].input_buffer, 0x00, pages[i].input_buffer_size);
}
}
objectlog_init(&objectlog, objectlog_storage, sizeof(objectlog_storage));
}
void ui_write_log(uint8_t page_id, uint8_t type, uint8_t channel, char *data, uint16_t length)
{
message_hdr_t hdr;
hdr.page_id = page_id;
hdr.type = type;
hdr.channel = channel;
scatter_object_t scatter_list[] = {
{ .ptr = &hdr, .len = sizeof(hdr) },
{ .ptr = data, .len = length },
{ .len = 0 }
};
objectlog_write_scattered_object(&objectlog, scatter_list);
}
void ui_render_statistics(page_t *page)
{
ui_printf(0, 0, C_BLACK, "IP RX: %u TX: %u", uip_stat.ip.recv, uip_stat.ip.sent);
ui_printf(20, 10, C_BLACK, "Dropped: %u", uip_stat.ip.drop);
ui_printf(0, 23, C_BLACK, "ICMP RX: %u TX: %u", uip_stat.icmp.recv, uip_stat.icmp.sent);
ui_printf(1, 35, C_BLACK, "TCP:");
ui_printf(10, 45, C_BLACK, "Chksum err: %u", uip_stat.tcp.chkerr);
ui_printf(10, 55, C_BLACK, "Rexmit: %u", uip_stat.tcp.rexmit);
}
extern char printf_buffer[128];
void ui_printf(int x, int y, int fg, const char * format, ...)
{
va_list args;
va_start (args, format);
vsnprintf (printf_buffer, sizeof(printf_buffer), format, args);
dtext(x, y, fg, printf_buffer);
va_end (args);
}