mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-18 21:30:38 +01:00
Merge "Adds a text_input function to get text."
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
app_objs += $(addprefix app/, app.o)
|
||||
app_objs += $(addprefix app/,\
|
||||
app.o\
|
||||
text_input.o)
|
||||
products += $(app_objs) app.elf app.hex app.bin
|
||||
|
||||
app.elf: $(app_objs)
|
||||
|
||||
84
app/app.cpp
84
app/app.cpp
@@ -6,6 +6,8 @@ extern "C" {
|
||||
|
||||
#include <poincare.h>
|
||||
|
||||
#include "text_input.h"
|
||||
|
||||
void draw_lines_from_center() {
|
||||
KDCoordinate width = SCREEN_WIDTH;
|
||||
KDCoordinate height = SCREEN_HEIGHT;
|
||||
@@ -41,7 +43,6 @@ void plot(Expression * e, float xMin, float xMax, float yMin, float yMax) {
|
||||
for (KDCoordinate i=0;i<screenWidth; i++) {
|
||||
float x = xMin + (xMax-xMin)/screenWidth*i;
|
||||
Float xExp = Float(x);
|
||||
//plotContext["x"] = xExp;
|
||||
plotContext.setExpressionForSymbolName(&xExp, "x");
|
||||
float y = e->approximate(plotContext);
|
||||
KDCoordinate j = ((y-yMin)/(yMax-yMin)*screenHeight);
|
||||
@@ -59,79 +60,38 @@ void funnyPlot() {
|
||||
delete e;
|
||||
}
|
||||
|
||||
void parseInlineExpression() {
|
||||
char * expression = (char*) "1+2/3+4/5+6";
|
||||
Expression * e = Expression::parse(expression);
|
||||
ExpressionLayout * l = e->createLayout(nullptr);
|
||||
l->draw(KDPointMake(0,100));
|
||||
delete l;
|
||||
delete e;
|
||||
static void clear_screen() {
|
||||
KDRect r;
|
||||
r.x = 0;
|
||||
r.y = 0;
|
||||
r.width = SCREEN_WIDTH;
|
||||
r.height = SCREEN_HEIGHT;
|
||||
KDFillRect(r, 0x00);
|
||||
}
|
||||
|
||||
void interactive_expression_parsing() {
|
||||
char input[255];
|
||||
int index = 0;
|
||||
int max = 1;
|
||||
|
||||
static void interactive_expression_parsing() {
|
||||
while (1) {
|
||||
char character = ion_getchar();
|
||||
if (character == '=') {
|
||||
input[index] = 0;
|
||||
index = 0;
|
||||
max = index+1;
|
||||
Expression * e = Expression::parse(input);
|
||||
if (e) {
|
||||
ExpressionLayout * l = e->createLayout(nullptr);
|
||||
if (l) {
|
||||
l->draw(KDPointMake(0,100));
|
||||
plot(e, 0.0f, 3.0f, 0.0f, 2.0f);
|
||||
delete l;
|
||||
}
|
||||
delete e;
|
||||
} else {
|
||||
KDDrawString("PARSING ERROR", KDPointMake(10,10));
|
||||
char * text_input = get_text();
|
||||
clear_screen();
|
||||
Expression * e = Expression::parse(text_input);
|
||||
if (e) {
|
||||
ExpressionLayout * l = e->createLayout(nullptr);
|
||||
if (l) {
|
||||
l->draw(KDPointMake(0,10));
|
||||
delete l;
|
||||
}
|
||||
} else if (character == LEFT_ARROW_KEY) {
|
||||
index--;
|
||||
if (index < 0) {
|
||||
index = 0;
|
||||
}
|
||||
} else if (character == RIGHT_ARROW_KEY) {
|
||||
if (index < max) {
|
||||
index++;
|
||||
}
|
||||
delete e;
|
||||
} else {
|
||||
if (index == 0) {
|
||||
KDRect r;
|
||||
r.x = 0;
|
||||
r.y = 0;
|
||||
r.width = SCREEN_WIDTH;
|
||||
r.height = SCREEN_HEIGHT;
|
||||
KDFillRect(r, 0x00);
|
||||
}
|
||||
input[index++] = character;
|
||||
// We are at the end of the line.
|
||||
if (index == max) {
|
||||
input[max++] = ' ';
|
||||
input[max+1] = 0;
|
||||
}
|
||||
KDDrawString("PARSING ERROR", KDPointMake(10,10));
|
||||
}
|
||||
// Here we draw the input and inverse the pixels under the cursor.
|
||||
// FIXME: hard coded value
|
||||
KDDrawLine(KDPointMake(0, SCREEN_HEIGHT - 30),
|
||||
KDPointMake(SCREEN_WIDTH, SCREEN_HEIGHT - 30), 0xff);
|
||||
KDDrawString(input, KDPointMake(0, SCREEN_HEIGHT - 15));
|
||||
KDDrawInverseChar(input[index] ? input[index] : ' ',
|
||||
KDPointMake(index*7, SCREEN_HEIGHT - 15));
|
||||
// We dealocate the memory allocated by get_text;
|
||||
free(text_input);
|
||||
}
|
||||
}
|
||||
|
||||
void ion_app() {
|
||||
KDDrawString("Hello, world!", KDPointMake(10,10));
|
||||
interactive_expression_parsing();
|
||||
//parseInlineExpression();
|
||||
//funnyPlot();
|
||||
//interactive_expression_parsing();
|
||||
while (1) {
|
||||
ion_sleep();
|
||||
}
|
||||
|
||||
68
app/text_input.cpp
Normal file
68
app/text_input.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
extern "C" {
|
||||
#include <kandinsky.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ion.h>
|
||||
}
|
||||
|
||||
#define PROMPT_HEIGHT 30
|
||||
|
||||
static void clear_prompt() {
|
||||
KDRect r;
|
||||
r.x = 0;
|
||||
r.y = SCREEN_HEIGHT - PROMPT_HEIGHT;
|
||||
r.width = SCREEN_WIDTH;
|
||||
r.height = PROMPT_HEIGHT;
|
||||
KDFillRect(r, 0x00);
|
||||
}
|
||||
|
||||
static void print_prompt(char* text, int index) {
|
||||
// Here we draw the input and inverse the pixels under the cursor.
|
||||
// FIXME: hard coded value
|
||||
KDDrawLine(KDPointMake(0, SCREEN_HEIGHT - PROMPT_HEIGHT),
|
||||
KDPointMake(SCREEN_WIDTH, SCREEN_HEIGHT - PROMPT_HEIGHT), 0xff);
|
||||
KDDrawString(text, KDPointMake(0, SCREEN_HEIGHT - (PROMPT_HEIGHT / 2)));
|
||||
// The hardcoded 7 is the width of the font.
|
||||
KDDrawInverseChar(text[index],
|
||||
KDPointMake(index*7, SCREEN_HEIGHT - (PROMPT_HEIGHT / 2)));
|
||||
}
|
||||
|
||||
char* get_text() {
|
||||
char input[255] = {0};
|
||||
int index = 0;
|
||||
int max = 0;
|
||||
input[max] = ' ';
|
||||
input[max+1] = '\0';
|
||||
|
||||
while (1) {
|
||||
clear_prompt();
|
||||
print_prompt(input, index);
|
||||
ion_event_t event = ion_get_event();
|
||||
if (event == EQUAL) {
|
||||
break;
|
||||
} else if (event == LEFT_ARROW) {
|
||||
index--;
|
||||
if (index < 0) {
|
||||
index = 0;
|
||||
}
|
||||
} else if (event == RIGHT_ARROW) {
|
||||
if (index < max) {
|
||||
index++;
|
||||
}
|
||||
} else if (event <= 0x7f) {
|
||||
input[index++] = (char) event;
|
||||
// We are at the end of the line.
|
||||
if (index > max) {
|
||||
max++;
|
||||
input[max] = ' ';
|
||||
input[max+1] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clear_prompt();
|
||||
input[max] = '\0';
|
||||
char* output = (char*) malloc(sizeof(char) * (index + 1));
|
||||
memcpy(output, input, (size_t) (index + 1));
|
||||
return output;
|
||||
}
|
||||
8
app/text_input.h
Normal file
8
app/text_input.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef APP_TEXTINPUT_H
|
||||
#define APP_TEXTINPUT_H
|
||||
|
||||
/* Returns a pointer to an input text, allocated by the functions (it is thus
|
||||
* the caller's role to free it). */
|
||||
char* get_text();
|
||||
|
||||
#endif // APP_TEXTINPUT_H
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef ION_ION_H
|
||||
#define ION_ION_H
|
||||
|
||||
#include <ion/events.h>
|
||||
#include <ion/framebuffer.h>
|
||||
#include <ion/keyboard.h>
|
||||
|
||||
|
||||
84
ion/include/ion/events.h
Normal file
84
ion/include/ion/events.h
Normal file
@@ -0,0 +1,84 @@
|
||||
#ifndef ION_EVENTS_H
|
||||
#define ION_EVENTS_H
|
||||
|
||||
typedef enum {
|
||||
LEFT_PARENTHESIS = '(', // 0x28
|
||||
RIGHT_PARENTHESIS = ')', // 0x29
|
||||
PRODUCT = '*', // 0x2a
|
||||
PLUS = '+', // 0x2b
|
||||
MINUS = '-', // 0x2d
|
||||
DOT = '.', // 0x2e
|
||||
DIVISION = '/', // 0x2f
|
||||
ZERO = '0', // 0x30
|
||||
ONE = '1',
|
||||
TWO = '2',
|
||||
THREE = '3',
|
||||
FOUR = '4',
|
||||
FIVE = '5',
|
||||
SIX = '6',
|
||||
SEVEN = '7',
|
||||
EIGHT = '8',
|
||||
NINE = '9',
|
||||
EQUAL = '=', // 0x3d
|
||||
UPPER_CASE_A = 'A', // 0x41
|
||||
UPPER_CASE_B,
|
||||
UPPER_CASE_C,
|
||||
UPPER_CASE_D,
|
||||
UPPER_CASE_E,
|
||||
UPPER_CASE_F,
|
||||
UPPER_CASE_G,
|
||||
UPPER_CASE_H,
|
||||
UPPER_CASE_I,
|
||||
UPPER_CASE_J,
|
||||
UPPER_CASE_K,
|
||||
UPPER_CASE_L,
|
||||
UPPER_CASE_M,
|
||||
UPPER_CASE_N,
|
||||
UPPER_CASE_O,
|
||||
UPPER_CASE_P,
|
||||
UPPER_CASE_Q,
|
||||
UPPER_CASE_R,
|
||||
UPPER_CASE_S,
|
||||
UPPER_CASE_T,
|
||||
UPPER_CASE_U,
|
||||
UPPER_CASE_V,
|
||||
UPPER_CASE_W,
|
||||
UPPER_CASE_X,
|
||||
UPPER_CASE_Y,
|
||||
UPPER_CASE_Z,
|
||||
POWER = '^', // 0x5e
|
||||
LOWER_CASE_A = 'a', // 0X61
|
||||
LOWER_CASE_B,
|
||||
LOWER_CASE_C,
|
||||
LOWER_CASE_D,
|
||||
LOWER_CASE_E,
|
||||
LOWER_CASE_F,
|
||||
LOWER_CASE_G,
|
||||
LOWER_CASE_H,
|
||||
LOWER_CASE_I,
|
||||
LOWER_CASE_J,
|
||||
LOWER_CASE_K,
|
||||
LOWER_CASE_L,
|
||||
LOWER_CASE_M,
|
||||
LOWER_CASE_N,
|
||||
LOWER_CASE_O,
|
||||
LOWER_CASE_P,
|
||||
LOWER_CASE_Q,
|
||||
LOWER_CASE_R,
|
||||
LOWER_CASE_S,
|
||||
LOWER_CASE_T,
|
||||
LOWER_CASE_U,
|
||||
LOWER_CASE_V,
|
||||
LOWER_CASE_W,
|
||||
LOWER_CASE_X,
|
||||
LOWER_CASE_Y,
|
||||
LOWER_CASE_Z,
|
||||
LEFT_ARROW = 0x100, // events for things outside of ASCII.
|
||||
RIGHT_ARROW,
|
||||
MENU_TRIG,
|
||||
ERROR = 0xffffffff,
|
||||
} ion_event_t;
|
||||
|
||||
ion_event_t ion_get_event();
|
||||
|
||||
#endif
|
||||
@@ -49,13 +49,6 @@ typedef enum {
|
||||
|
||||
#define ION_NUMBER_OF_KEYS 35
|
||||
|
||||
#define LEFT_ARROW_KEY '@'
|
||||
#define RIGHT_ARROW_KEY '?'
|
||||
|
||||
// FIXME: Which state is "true"?
|
||||
bool ion_key_down(ion_key_t key);
|
||||
|
||||
// This is our keymap
|
||||
char ion_getchar();
|
||||
|
||||
#endif
|
||||
|
||||
@@ -62,7 +62,7 @@ bool ion_key_down(ion_key_t key) {
|
||||
GPIO_ODR(GPIOA) = new_odr;
|
||||
// We changed the outputs, give the hardware some time to react to this change
|
||||
// FIXME: Real delay!
|
||||
for (int i=0;i<1000; i++) {
|
||||
for (volatile int i=0;i<1000; i++) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
objs += $(addprefix ion/src/shared/, keyboard.o)
|
||||
objs += $(addprefix ion/src/shared/,\
|
||||
events.o)
|
||||
|
||||
69
ion/src/shared/events.c
Normal file
69
ion/src/shared/events.c
Normal file
@@ -0,0 +1,69 @@
|
||||
#include <ion.h>
|
||||
|
||||
// More event type will be added later.
|
||||
typedef enum {
|
||||
KEY_DOWN,
|
||||
} ion_key_event_type_t;
|
||||
|
||||
typedef struct {
|
||||
ion_key_t key;
|
||||
ion_key_event_type_t event;
|
||||
} ion_key_event_t;
|
||||
|
||||
// Debouncing, qnd change to get_key event.
|
||||
static ion_key_event_t ion_get_key_event() {
|
||||
// Let's start by saving which keys we've seen up
|
||||
bool key_seen_up[ION_NUMBER_OF_KEYS];
|
||||
for (ion_key_t k=0; k<ION_NUMBER_OF_KEYS; k++) {
|
||||
key_seen_up[k] = !ion_key_down(k);
|
||||
}
|
||||
|
||||
// Wait a little to debounce the button.
|
||||
// FIXME: REAL SLEEP
|
||||
for (volatile int i=0;i<10000;i++) {
|
||||
}
|
||||
|
||||
/* Let's discard the keys we previously saw up but which aren't anymore: those
|
||||
* were probably bouncing! */
|
||||
for (ion_key_t k=0; k<ION_NUMBER_OF_KEYS; k++) {
|
||||
key_seen_up[k] &= !ion_key_down(k);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
for (ion_key_t k=0; k<ION_NUMBER_OF_KEYS; k++) {
|
||||
if (ion_key_down(k)) {
|
||||
if (key_seen_up[k]) {
|
||||
return (ion_key_event_t) {.key = k, .event = KEY_DOWN};
|
||||
}
|
||||
} else {
|
||||
key_seen_up[k] = 1;
|
||||
}
|
||||
}
|
||||
ion_sleep();
|
||||
// FIXME: REAL SLEEP
|
||||
for (int i=0;i<10000;i++) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For now this is a bit silly but needed for instreface purpose.
|
||||
static const ion_event_t kEventForKeyDown[ION_NUMBER_OF_KEYS] = {
|
||||
UPPER_CASE_A, UPPER_CASE_B, UPPER_CASE_C, UPPER_CASE_D, UPPER_CASE_E,
|
||||
UPPER_CASE_F, UPPER_CASE_G, UPPER_CASE_H, UPPER_CASE_I, UPPER_CASE_J,
|
||||
UPPER_CASE_K, UPPER_CASE_L, UPPER_CASE_M, LEFT_ARROW, RIGHT_ARROW,
|
||||
SEVEN, EIGHT, NINE, LEFT_PARENTHESIS, RIGHT_PARENTHESIS,
|
||||
FOUR, FIVE, SIX, PRODUCT, DIVISION,
|
||||
ONE, TWO, THREE, PLUS, MINUS,
|
||||
ZERO, DOT, LOWER_CASE_X, POWER, EQUAL
|
||||
};
|
||||
|
||||
ion_event_t ion_get_event() {
|
||||
// First we get a key event.
|
||||
const ion_key_event_t key_event = ion_get_key_event();
|
||||
// We then generate the event associated to this key event.
|
||||
if (key_event.event == KEY_DOWN) {
|
||||
return kEventForKeyDown[key_event.key];
|
||||
} else {
|
||||
return ERROR;
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
#include <ion.h>
|
||||
#include <string.h>
|
||||
|
||||
static const char kCharForKey[ION_NUMBER_OF_KEYS] = {
|
||||
'A', 'B', 'C', 'D', 'E',
|
||||
'F', 'G', 'H', 'I', 'J',
|
||||
'K', 'L', 'M', LEFT_ARROW_KEY, RIGHT_ARROW_KEY,
|
||||
'7', '8', '9', '(', ')',
|
||||
'4', '5', '6', '*', '/',
|
||||
'1', '2', '3', '+', '-',
|
||||
'0', '.', 'x', '^', '='
|
||||
};
|
||||
|
||||
char ion_getchar() {
|
||||
// Let's start by saving which keys we've seen up
|
||||
bool key_seen_up[ION_NUMBER_OF_KEYS];
|
||||
for (ion_key_t k=0; k<ION_NUMBER_OF_KEYS; k++) {
|
||||
key_seen_up[k] = !ion_key_down(k);
|
||||
}
|
||||
|
||||
// Wait a little to debounce the button.
|
||||
// FIXME: REAL SLEEP
|
||||
for (int i=0;i<10000;i++) {
|
||||
}
|
||||
/* Let's discard the keys we previously saw up but which aren't anymore: those
|
||||
* were probably bouncing! */
|
||||
for (ion_key_t k=0; k<ION_NUMBER_OF_KEYS; k++) {
|
||||
key_seen_up[k] &= !ion_key_down(k);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
for (ion_key_t k=0; k<ION_NUMBER_OF_KEYS; k++) {
|
||||
if (ion_key_down(k)) {
|
||||
if (key_seen_up[k]) {
|
||||
return kCharForKey[k];
|
||||
}
|
||||
} else {
|
||||
key_seen_up[k] = 1;
|
||||
}
|
||||
}
|
||||
ion_sleep();
|
||||
// FIXME: REAL SLEEP
|
||||
for (int i=0;i<10000;i++) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,9 +5,6 @@
|
||||
KDRect KDRectZero = {.x = 0, .y = 0, .width = 0, .height = 0};
|
||||
|
||||
void KDFillRect(KDRect rect, KDColor color) {
|
||||
//for (KDCoordinate y = rect.y ; y < (rect.y + rect.height); y++) {
|
||||
//memset(KDPixelAddress((KDPoint){.x=rect.x, .y=y}), color, rect.width);
|
||||
//}
|
||||
KDPoint p;
|
||||
for (p.x = rect.x; p.x<(rect.x+rect.width); p.x++) {
|
||||
for (p.y = rect.y; p.y<(rect.y+rect.height); p.y++) {
|
||||
|
||||
Reference in New Issue
Block a user