// SPDX-License-Identifier: GPL-3.0-only /* * Copyright (c) 2024, Richard Acayan. All rights reserved. */ #include #include #include #include #include "graphics.h" #include "layout.h" #include "parser.h" #include "ufkbd.h" static struct ufkbd_layout_row *search_row(struct ufkbd_layout *layout, int y) { struct ufkbd_layout_row *row; size_t row1 = 0, row2; size_t idx; if (layout->rows == NULL) return NULL; row2 = layout->n_rows - 1; do { idx = (row1 + row2) / 2; row = &layout->rows[idx]; if (row->y1 <= y) row1 = idx; if (row->y2 >= y) row2 = idx; } while (row2 - row1 > 1); if (layout->rows[row1].y1 <= y && layout->rows[row1].y2 >= y) return &layout->rows[row1]; else if (layout->rows[row2].y1 <= y && layout->rows[row2].y2 >= y) return &layout->rows[row2]; return NULL; } static struct ufkbd_layout_column *search_col(struct ufkbd_layout_row *row, int x) { struct ufkbd_layout_column *col; size_t col1 = 0, col2; size_t idx; col2 = row->n_cols - 1; do { idx = (col1 + col2) / 2; col = &row->cols[idx]; if (col->x1 <= x) col1 = idx; if (col->x2 >= x) col2 = idx; } while (col2 - col1 > 1); if (row->cols[col1].x1 <= x && row->cols[col1].x2 >= x) return &row->cols[col1]; else if (row->cols[col2].x1 <= x && row->cols[col2].x2 >= x) return &row->cols[col2]; return NULL; } struct ufkbd_key *ufkbd_layout_search(struct ufkbd_layout *layout, int x, int y, int *x1, int *y1, int *x2, int *y2) { struct ufkbd_layout_row *row; struct ufkbd_layout_column *col; if (layout == NULL) return NULL; row = search_row(layout, y); if (row == NULL) return NULL; col = search_col(row, x); if (col == NULL) return NULL; if (x1 != NULL) *x1 = col->x1; if (y1 != NULL) *y1 = row->y1; if (x2 != NULL) *x2 = col->x2; if (y2 != NULL) *y2 = row->y2; return col->key; } void ufkbd_layout_foreach(struct ufkbd_layout *layout, void (*func)(struct ufkbd_key *key, int x1, int y1, int x2, int y2, void *data), void *data) { struct ufkbd_layout_row *row; struct ufkbd_layout_column *col; size_t y, x; for (y = 0; y < layout->n_rows; y++) { row = &layout->rows[y]; for (x = 0; x < row->n_cols; x++) { col = &row->cols[x]; func(col->key, col->x1, row->y1, col->x2, row->y2, data); } } } void ufkbd_layout_resize(struct ufkbd_layout *layout, int width, int height) { struct ufkbd_layout_row *row; struct ufkbd_layout_column *col; size_t y, x; for (y = 0; y < layout->n_rows; y++) { row = &layout->rows[y]; row->y1 = row->y1_unscaled * height / layout->n_rows; row->y2 = row->y2_unscaled * height / layout->n_rows - 1; if (row->y2 < row->y1) row->y2 = row->y1; for (x = 0; x < row->n_cols; x++) { col = &row->cols[x]; col->x1 = col->x1_unscaled * width / layout->max_cols; col->x2 = col->x2_unscaled * width / layout->max_cols - 1; if (col->x2 < col->x1) col->x2 = col->x1; } } } struct ufkbd_layout *ufkbd_layout_init(void) { struct ufkbd_layout *layout; layout = malloc(sizeof(*layout)); if (layout == NULL) return NULL; layout->max_cols = 0; layout->n_rows = 0; layout->rows = NULL; return layout; } void ufkbd_layout_uninit(struct ufkbd_layout *layout) { struct ufkbd_layout_row *row; size_t x, y; for (y = 0; y < layout->n_rows; y++) { row = &layout->rows[y]; for (x = 0; x < row->n_cols; x++) free(row->cols[x].key); free(row->cols); } free(layout->rows); free(layout); }