unfettered-keyboard/layout.c
2024-04-15 22:11:20 -04:00

184 lines
3.5 KiB
C

// SPDX-License-Identifier: GPL-3.0-only
/*
* Copyright (c) 2024, Richard Acayan. All rights reserved.
*/
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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);
}