freertos_f407/User/system/sgl/widgets/keyboard/sgl_keyboard.c

552 lines
21 KiB
C

/* source/widgets/sgl_keyboard.c
*
* MIT License
*
* Copyright(c) 2023-present All contributors of SGL
* Document reference link: https://sgl-docs.readthedocs.io
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <sgl_core.h>
#include <sgl_draw.h>
#include <sgl_math.h>
#include <sgl_log.h>
#include <sgl_mm.h>
#include <sgl_theme.h>
#include <sgl_cfgfix.h>
#include <sgl_draw.h>
#include <string.h>
#include "sgl_keyboard.h"
#define KEYBOARD_ICON_ENTER ("\xEE\xA2\x86")
#define KEYBOARD_ICON_NEWLINE ("\xEE\xA6\xB8")
#define KEYBOARD_ICON_BACKSPACE ("\xEE\xA0\xBE")
#define KEYBOARD_ICON_KEYBD ("\xEE\xA6\xB7")
#define KEYBOARD_ICON_LEFT ("\xEE\xA8\xAA")
#define KEYBOARD_ICON_RIGHT ("\xEE\xA8\xAB")
#define KEYBOARD_ICON_INVALID (-1)
#define KEYBOARD_KEYMODE_UPPER (0)
#define KEYBOARD_KEYMODE_LOWER (1)
#define KEYBOARD_KEYMODE_SPEC (2)
#define KEYBOARD_KEYMODE_MAX (3)
#define KEYBOARD_BTN_LINES (4)
#define KEYBOARD_BTN_COLUMNS (12)
#define KEYBOARD_BTN_NUM (40)
#define KEYBOARD_KEY_INVALID (-1)
#define KEYBOARD_KEY_TO_UPPER (255)
#define KEYBOARD_KEY_TO_LOWER (254)
#define KEYBOARD_KEY_TO_SPEC (253)
#define KEYBOARD_KEY_TO_CLOSE (252)
#define KEYBOARD_KEY_MODE(x) ((x) >> 1)
#define KEYBOARD_KEY_BACKSPACE (11)
#define KEYBOARD_KEY_NUMBER_BACKSPACE (10)
#define KEYBOARD_KEY_SPACE (37)
#define KEYBOARD_KEY_NEWLINE (22)
#define KEYBOARD_KEY_ENTER (39)
#define KEYBOARD_KEY_CLOSE (35)
#define KEYBOARD_KEY_LEFT (36)
#define KEYBOARD_KEY_RIGHT (38)
static const uint8_t font_bitmap[] = {
/* U+E83E "" */
0x00, 0x00, 0x05, 0xde, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xec, 0x30, 0x00, 0x03, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0x00, 0x00, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xf0, 0x00, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f,
0xff, 0xff, 0xf6, 0x7f, 0xff, 0xff, 0x49, 0xff, 0xff, 0xf0, 0x0d, 0xff, 0xff, 0xfd, 0x00, 0x7f,
0xff, 0x40, 0x2f, 0xff, 0xff, 0x08, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x7f, 0x50, 0x2e, 0xff, 0xff,
0xf3, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x20, 0x1e, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff,
0xff, 0xfc, 0x00, 0x0d, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0x50, 0x00, 0x7f,
0xff, 0xff, 0xff, 0x0c, 0xff, 0xff, 0xff, 0xff, 0x50, 0x1a, 0x00, 0x7f, 0xff, 0xff, 0xf0, 0x2f,
0xff, 0xff, 0xff, 0x50, 0x1d, 0xfc, 0x00, 0x8f, 0xff, 0xff, 0x00, 0x7f, 0xff, 0xff, 0xe1, 0x1d,
0xff, 0xfc, 0x02, 0xff, 0xff, 0xf0, 0x00, 0xcf, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xfc, 0xef, 0xff,
0xff, 0x00, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x07, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x0c, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x90, 0x00, 0x00, 0x04, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x40,
/* U+E886 "" */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x1d, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xdf, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x1d, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xdf, 0xb0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1d, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xdf, 0xb0, 0x00, 0x00, 0x1c,
0x30, 0x00, 0x00, 0x1d, 0xfb, 0x00, 0x00, 0x00, 0x6f, 0xf3, 0x00, 0x01, 0xdf, 0xb0, 0x00, 0x00,
0x00, 0x08, 0xff, 0x30, 0x1d, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0xf4, 0xdf, 0xb0, 0x00,
0x00, 0x00, 0x00, 0x00, 0x08, 0xff, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0xb0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* U+E9B7 "" */
0x03, 0xcd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xc3, 0x00, 0xef, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01,
0xff, 0xd0, 0x2e, 0x04, 0xc0, 0xc4, 0x0e, 0x20, 0xdf, 0xf1, 0x1f, 0xfd, 0x01, 0xe0, 0x3c, 0x0c,
0x30, 0xe1, 0x0d, 0xff, 0x11, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0x1f,
0xfd, 0x01, 0xe0, 0x3c, 0x0c, 0x30, 0xe1, 0x0d, 0xff, 0x11, 0xff, 0xd0, 0x1e, 0x03, 0xc0, 0xc3,
0x0e, 0x10, 0xdf, 0xf1, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x11, 0xff,
0xff, 0xff, 0xee, 0xee, 0xee, 0xef, 0xff, 0xff, 0xf1, 0x1f, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00,
0xef, 0xff, 0xff, 0x10, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x0e, 0xff, 0xff, 0xf0, 0x0e, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x4c, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
0xee, 0xec, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x33, 0x33, 0x33, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0xff, 0xff, 0xf6, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x08, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00,
/* U+E9B8 "" */
0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xfb, 0x00, 0x00,
0x00, 0x00, 0x0b, 0xd1, 0x00, 0x00, 0xaf, 0xe2, 0x00, 0x00, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0x0a,
0xfe, 0x20, 0x00, 0x00, 0x00, 0x00, 0x0d, 0xf1, 0x00, 0xaf, 0xe2, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0d, 0xf1, 0x0a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0x08, 0xff, 0xfe, 0xee,
0xee, 0xee, 0xee, 0xee, 0xee, 0xe1, 0x00, 0x8f, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x08, 0xfe, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0xe3, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* U+EA2A "" */
0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x1c, 0xf8, 0x00, 0x01, 0xcf, 0xc0, 0x00, 0x1c, 0xfc, 0x00,
0x01, 0xcf, 0xc0, 0x00, 0x0c, 0xfc, 0x00, 0x00, 0x0b, 0xfd, 0x10, 0x00, 0x00, 0xbf, 0xd1, 0x00,
0x00, 0x0b, 0xfd, 0x10, 0x00, 0x00, 0xbf, 0xd1, 0x00, 0x00, 0x0b, 0xf8, 0x00, 0x00, 0x00, 0x70,
/* U+EA2B "" */
0x08, 0x10, 0x00, 0x00, 0x8f, 0xc1, 0x00, 0x00, 0x0c, 0xfc, 0x10, 0x00, 0x00, 0xcf, 0xc1, 0x00,
0x00, 0x0c, 0xfc, 0x10, 0x00, 0x00, 0xcf, 0xc0, 0x00, 0x01, 0xdf, 0xb0, 0x00, 0x1d, 0xfb, 0x00,
0x01, 0xdf, 0xb0, 0x00, 0x1d, 0xfb, 0x00, 0x00, 0x8f, 0xb0, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00
};
static const sgl_font_table_t font_table[] = {
{.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */,
{.bitmap_index = 0, .adv_w = 192, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 0, .adv_w = 368, .box_w = 23, .box_h = 18, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 207, .adv_w = 368, .box_w = 18, .box_h = 14, .ofs_x = 3, .ofs_y = 1},
{.bitmap_index = 333, .adv_w = 368, .box_w = 21, .box_h = 20, .ofs_x = 1, .ofs_y = -3},
{.bitmap_index = 543, .adv_w = 368, .box_w = 20, .box_h = 12, .ofs_x = 1, .ofs_y = 2},
{.bitmap_index = 663, .adv_w = 368, .box_w = 8, .box_h = 12, .ofs_x = 7, .ofs_y = 2},
{.bitmap_index = 711, .adv_w = 368, .box_w = 8, .box_h = 12, .ofs_x = 8, .ofs_y = 2}
};
static const uint32_t unicode_list_0[] = {
0x0000, 0xe81e, 0xe866, 0xe997, 0xe998, 0xea0a, 0xea0b
};
static const sgl_font_unicode_t font_unicode[] = {
{ .offset = 0x20, .len = 7, .list = unicode_list_0, .tab_offset = 1, }
};
const sgl_font_t keyboard_icon = {
.bitmap = font_bitmap,
.table = font_table,
.font_table_size = SGL_ARRAY_SIZE(font_table),
.font_height = 20,
.base_line = 2,
.bpp = 4,
.compress = 0,
.unicode = font_unicode,
.unicode_num = SGL_ARRAY_SIZE(font_unicode),
};
static const char keyboard_key_ascii[KEYBOARD_KEYMODE_MAX][KEYBOARD_BTN_NUM] = {
{
KEYBOARD_KEY_TO_SPEC, 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '\b',
KEYBOARD_KEY_TO_LOWER, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', '\n',
'_', '-', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '.', ',', ':',
KEYBOARD_KEY_TO_CLOSE, KEYBOARD_KEY_LEFT, ' ', KEYBOARD_KEY_RIGHT, '\r'
},
{
KEYBOARD_KEY_TO_SPEC, 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '\b',
KEYBOARD_KEY_TO_UPPER, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', '\n',
'_', '-', 'z', 'x', 'c', 'v', 'b', 'n', 'm', '.', ',', ':',
KEYBOARD_KEY_TO_CLOSE, KEYBOARD_KEY_LEFT, ' ', KEYBOARD_KEY_RIGHT, '\r'
},
{
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '\b',
KEYBOARD_KEY_TO_LOWER, '+', '-', '/', '*', '=', '%', '!', '?', '#', '<', '>',
'\\', '@', '$', '(', ')', '{', '}', '[', ']', ';', '\"', '\'',
KEYBOARD_KEY_TO_CLOSE, KEYBOARD_KEY_LEFT, ' ', KEYBOARD_KEY_RIGHT, '\r'
},
};
static const char keybd_btn_map[KEYBOARD_KEYMODE_MAX][KEYBOARD_BTN_NUM][4] = {
{
"1#", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "<<",
"abc", "A", "S", "D", "F", "G", "H", "J", "K", "L", "nl",
"_", "-", "Z", "X", "C", "V", "B", "N", "M", ".", ",", ":",
"kbd", "<", " ", ">", "OK"
},
{
"1#", "q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "<<",
"ABC", "a", "s", "d", "f", "g", "h", "j", "k", "l", "nl",
"_", "-", "z", "x", "c", "v", "b", "n", "m", ".", ",", ":",
"kbd", "<", " ", ">", "OK"
},
{
"1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "<<",
"abc", "+", "-", "/", "*", "=", "%", "!", "?", "#", "<", ">",
"\\", "@", "$", "(", ")", "{", "}", "[", "]", ";", "\"", "'",
"kbd", "<", " ", ">", "OK"
},
};
static const uint8_t keybd_btn_width[2][KEYBOARD_BTN_LINES][KEYBOARD_BTN_COLUMNS] = {
/* upper and lower mode */
{
{5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 7},
{6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{2, 2, 6, 2, 2},
},
/* number mode and spec mode */
{
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2},
{2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{2, 2, 6, 2, 2},
},
};
static const uint8_t keybd_btn_height[KEYBOARD_BTN_LINES] = {
1, 1, 1, 1
};
static const uint8_t keyboard_btn_count[2][KEYBOARD_BTN_LINES] = {
/* upper and lower mode */
{
12, 11, 12, 5
},
/* number mode and spec mode */
{
11, 12, 12, 5
}
};
static void keyboard_btn_handler(sgl_keyboard_t *keyboard)
{
char *edit = keyboard->edit;
int index = keyboard->edit_max_len;
while (*edit && index) {
edit ++;
index --;
}
if (keyboard->opcode == '\b') {
*(--edit) = '\0';
return;
}
if (index == 0) {
SGL_LOG_ERROR("keyboard edit buffer is full\n");
return;
}
switch (keyboard->opcode) {
case '\n':
case '\r':
*(edit++) = '\n';
*(edit++) = '\0';
break;
default :
*(edit++) = keyboard->opcode;
*(edit++) = '\0';
break;
}
}
static const char* keyindex_is_icon(uint8_t mode, uint8_t index)
{
if(index == KEYBOARD_KEY_NUMBER_BACKSPACE && (mode == KEYBOARD_KEYMODE_SPEC)) {
return KEYBOARD_ICON_BACKSPACE;
}
else if(index == KEYBOARD_KEY_BACKSPACE && (mode < KEYBOARD_KEYMODE_SPEC)) {
return KEYBOARD_ICON_BACKSPACE;
}
else if(index == KEYBOARD_KEY_ENTER) {
return KEYBOARD_ICON_ENTER;
}
else if(index == KEYBOARD_KEY_NEWLINE && (mode != KEYBOARD_KEYMODE_SPEC)) {
return KEYBOARD_ICON_NEWLINE;
}
else if(index == KEYBOARD_KEY_CLOSE) {
return KEYBOARD_ICON_KEYBD;
}
else if(index == KEYBOARD_KEY_LEFT) {
return KEYBOARD_ICON_LEFT;
}
else if(index == KEYBOARD_KEY_RIGHT) {
return KEYBOARD_ICON_RIGHT;
}
return NULL;
}
static inline uint8_t keyboard_index_to_ascii(uint8_t keymode, uint8_t index)
{
return keyboard_key_ascii[keymode][index];
}
static int8_t keyboard_pos_to_index(int16_t x, int16_t y, sgl_keyboard_t *keyboard, int16_t width, int16_t height)
{
sgl_obj_t *obj = &keyboard->obj;
int16_t index = 0, x_index = -1, y_index = -1, key_mode = KEYBOARD_KEY_MODE(keyboard->key_mode);
int16_t btn_width[KEYBOARD_BTN_COLUMNS] = {0};
int16_t btn_height[KEYBOARD_BTN_LINES] = {0};
sgl_rect_t btn = {0};
/* calculate button height */
sgl_split_len(keybd_btn_height, KEYBOARD_BTN_LINES, height, keyboard->key_margin, btn_height);
btn.y1 = obj->coords.y1;
for(int i = 0; i < KEYBOARD_BTN_LINES; i++) {
btn.y1 += keyboard->key_margin;
btn.y2 = btn.y1 + btn_height[i] - 1;
if(y >= btn.y1 && y <= btn.y2) {
y_index = i;
break;
}
btn.y1 += btn_height[i];
}
if(y_index < 0 || y_index >= KEYBOARD_BTN_LINES) {
return -1;
}
sgl_split_len(keybd_btn_width[key_mode][y_index], keyboard_btn_count[key_mode][y_index], width, keyboard->key_margin, btn_width);
btn.x1 = obj->coords.x1;
for(int i = 0; i < keyboard_btn_count[key_mode][y_index]; i++) {
btn.x1 += keyboard->key_margin;
btn.x2 = btn.x1 + btn_width[i] - 1;
if(x >= btn.x1 && x <= btn.x2) {
x_index = i;
break;
}
btn.x1 += btn_width[i];
}
if(x_index < 0 || x_index >= keyboard_btn_count[key_mode][y_index]) {
return -1;
}
for(int i = 0; i < y_index; i ++) {
index += keyboard_btn_count[key_mode][i];
}
return (index + x_index);
}
/**
* @brief keyboard constructor function
* @param surf: pointer to surface
* @param obj: pointer to keyboard object
* @param evt: pointer to event
* @return none
*/
static void sgl_keyboard_construct_cb(sgl_surf_t *surf, sgl_obj_t* obj, sgl_event_t *evt)
{
sgl_keyboard_t *keyboard = sgl_container_of(obj, sgl_keyboard_t, obj);
int16_t body_w = obj->coords.x2 - obj->coords.x1 + 1;
int16_t body_h = obj->coords.y2 - obj->coords.y1 + 1;
int8_t index = 0, key_mode = KEYBOARD_KEY_MODE(keyboard->key_mode);
sgl_color_t btn_color = keyboard->btn_desc.color;
int16_t text_x = 0, text_y = 0;
const char *text = NULL;
const sgl_font_t *font = keyboard->font;
int16_t btn_width[KEYBOARD_BTN_COLUMNS] = {0};
int16_t btn_height[KEYBOARD_BTN_LINES] = {0};
sgl_rect_t btn_coords = {0}, btn_area = {0};
/* calculate button height */
sgl_split_len(keybd_btn_height, KEYBOARD_BTN_LINES, body_h, keyboard->key_margin, btn_height);
if(evt->type == SGL_EVENT_DRAW_MAIN) {
sgl_draw_rect(surf, &obj->area, &obj->coords, &keyboard->body_desc);
btn_coords.y1 = obj->coords.y1;
for(int i = 0; i < KEYBOARD_BTN_LINES; i++) {
sgl_split_len(keybd_btn_width[key_mode][i], keyboard_btn_count[key_mode][i], body_w, keyboard->key_margin, btn_width);
btn_coords.x1 = obj->coords.x1;
btn_coords.y1 += keyboard->key_margin;
btn_coords.y2 = btn_coords.y1 + btn_height[i] - 1;
for(int j = 0; j < keyboard_btn_count[key_mode][i]; j++) {
btn_coords.x1 += keyboard->key_margin;
btn_coords.x2 = btn_coords.x1 + btn_width[j] - 1;
btn_area = btn_coords;
if (!sgl_area_selfclip(&btn_area, &obj->area)) {
sgl_area_init(&btn_area);
}
if(index == keyboard->key_index) {
keyboard->btn_desc.color = sgl_color_mixer(btn_color, keyboard->text_color, 128);
}
else {
keyboard->btn_desc.color = btn_color;
}
sgl_draw_rect(surf, &btn_area, &btn_coords, &keyboard->btn_desc);
text = keyindex_is_icon(keyboard->key_mode, index);
if (text != NULL) {
font = &keyboard_icon;
}
else {
font = keyboard->font;
text = keybd_btn_map[keyboard->key_mode][index];
}
text_x = btn_coords.x1 + (btn_width[j] - sgl_font_get_string_width(text, font)) / 2;
text_y = btn_coords.y1 + (btn_height[i] - font->font_height) / 2;
sgl_draw_string(surf, &btn_area, text_x, text_y, text, keyboard->text_color, SGL_ALPHA_MAX, font);
btn_coords.x1 += btn_width[j];
index ++;
}
btn_coords.y1 += btn_height[i];
}
keyboard->btn_desc.color = btn_color;
}
else if(evt->type == SGL_EVENT_PRESSED || evt->type == SGL_EVENT_OPTION_TAP) {
if (evt->type == SGL_EVENT_PRESSED) {
index = keyboard_pos_to_index(evt->pos.x, evt->pos.y, keyboard, body_w, body_h);
if(index < 0) {
return;
}
keyboard->key_index = index;
}
uint8_t key_ascii = keyboard_index_to_ascii(keyboard->key_mode, index);
if(key_ascii == KEYBOARD_KEY_TO_UPPER) {
keyboard->key_mode = KEYBOARD_KEYMODE_UPPER;
keyboard->key_index = KEYBOARD_KEY_INVALID;
}
else if(key_ascii == KEYBOARD_KEY_TO_LOWER) {
keyboard->key_mode = KEYBOARD_KEYMODE_LOWER;
keyboard->key_index = KEYBOARD_KEY_INVALID;
}
else if(key_ascii == KEYBOARD_KEY_TO_SPEC) {
keyboard->key_mode = KEYBOARD_KEYMODE_SPEC;
keyboard->key_index = KEYBOARD_KEY_INVALID;
}
else if(key_ascii == KEYBOARD_KEY_TO_CLOSE) {
sgl_obj_set_destroyed(obj);
return;
}
else {
keyboard->opcode = key_ascii;
if (keyboard->edit) {
keyboard_btn_handler(keyboard);
}
}
sgl_obj_set_dirty(obj);
}
else if(evt->type == SGL_EVENT_RELEASED) {
keyboard->key_index = KEYBOARD_KEY_INVALID;
sgl_obj_set_dirty(obj);
}
else if(evt->type == SGL_EVENT_DRAW_INIT) {
keyboard->opcode = 0;
keyboard->key_index = KEYBOARD_KEY_INVALID;
if (keyboard->key_margin == 0) {
keyboard->key_margin = sgl_max(body_w / 128, 1);
}
if (keyboard->btn_desc.radius == 0) {
keyboard->btn_desc.radius = sgl_max(keyboard->key_margin, 2);
}
SGL_ASSERT(keyboard->font != NULL);
}
else if (evt->type == SGL_EVENT_OPTION_WALK) {
keyboard->key_index ++;
if (keyboard->key_index >= KEYBOARD_BTN_NUM) {
keyboard->key_index = 0;
}
sgl_obj_set_dirty(obj);
}
}
/**
* @brief create keyboard object
* @param parent parent of object
* @return keyboard object
*/
sgl_obj_t* sgl_keyboard_create(sgl_obj_t* parent)
{
sgl_keyboard_t *keyboard = sgl_malloc(sizeof(sgl_keyboard_t));
if(keyboard == NULL) {
SGL_LOG_ERROR("sgl_keyboard_create: malloc failed");
return NULL;
}
/* set object all member to zero */
memset(keyboard, 0, sizeof(sgl_keyboard_t));
sgl_obj_t *obj = &keyboard->obj;
sgl_obj_init(&keyboard->obj, parent);
obj->construct_fn = sgl_keyboard_construct_cb;
sgl_obj_set_border_width(obj, SGL_THEME_BORDER_WIDTH);
obj->clickable = 1;
obj->needinit = 1;
keyboard->body_desc.alpha = SGL_THEME_ALPHA;
keyboard->body_desc.color = SGL_THEME_COLOR;
keyboard->body_desc.radius = SGL_THEME_RADIUS;
keyboard->body_desc.border = 1;
keyboard->body_desc.border_color = SGL_THEME_BORDER_COLOR;
keyboard->body_desc.pixmap = NULL;
keyboard->text_color = SGL_THEME_TEXT_COLOR;
keyboard->btn_desc.alpha = SGL_THEME_ALPHA;
keyboard->btn_desc.color = sgl_color_mixer(SGL_THEME_BORDER_COLOR, SGL_THEME_COLOR, 64);
keyboard->btn_desc.radius = 4;
keyboard->btn_desc.border = 0;
keyboard->btn_desc.border_color = SGL_THEME_BORDER_COLOR;
keyboard->btn_desc.pixmap = NULL;
keyboard->key_mode = KEYBOARD_KEYMODE_LOWER;
keyboard->key_margin = 0;
keyboard->font = sgl_get_system_font();
return obj;
}