446 lines
19 KiB
C
446 lines
19 KiB
C
#include "elements.h"
|
|
#include <stddef.h> // for that NULL
|
|
#include <stdlib.h> // for dat malloc
|
|
#include <string.h> // memcpy
|
|
#include <limits.h> // INT_MAX, etc.
|
|
#include "helper.h"
|
|
|
|
struct Element *newElement(int type) {
|
|
struct Element *element = malloc(sizeof(struct Element));
|
|
element->state = STATE_NORMAL;
|
|
element->type = type;
|
|
element->next = NULL;
|
|
element->callback = NULL;
|
|
element->user = NULL;
|
|
switch(type) {
|
|
case TYPE_BUTTON:
|
|
element->data = malloc(sizeof(struct ButtonElement));
|
|
((struct ButtonElement*)element->data)->length = 0;
|
|
((struct ButtonElement*)element->data)->string = malloc(1);
|
|
((struct ButtonElement*)element->data)->string[0] = '\0';
|
|
break;
|
|
case TYPE_SPINNER:
|
|
element->data = malloc(sizeof(struct SpinnerElement));
|
|
((struct SpinnerElement*)element->data)->length = 0;
|
|
((struct SpinnerElement*)element->data)->string = malloc(1);
|
|
((struct SpinnerElement*)element->data)->string[0] = '\0';
|
|
((struct SpinnerElement*)element->data)->size = 3;
|
|
((struct SpinnerElement*)element->data)->cursor = 0;
|
|
break;
|
|
case TYPE_TEXT:
|
|
element->data = malloc(sizeof(struct TextElement));
|
|
((struct TextElement*)element->data)->length = 0;
|
|
((struct TextElement*)element->data)->string = malloc(1);
|
|
((struct TextElement*)element->data)->string[0] = '\0';
|
|
break;
|
|
case TYPE_TEXT_INPUT:
|
|
element->data = malloc(sizeof(struct TextInputElement));
|
|
((struct TextInputElement*)element->data)->length = 0;
|
|
((struct TextInputElement*)element->data)->string = malloc(1);
|
|
((struct TextInputElement*)element->data)->string[0] = '\0';
|
|
((struct TextInputElement*)element->data)->size = 8;
|
|
((struct TextInputElement*)element->data)->cursor = 0;
|
|
break;
|
|
case TYPE_IMAGE:
|
|
element->data = malloc(sizeof(struct ImageElement));
|
|
((struct ImageElement*)element->data)->width = 0;
|
|
((struct ImageElement*)element->data)->height = 0;
|
|
((struct ImageElement*)element->data)->image = NULL;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return element;
|
|
}
|
|
|
|
/****
|
|
Fairly self-explanatory function, as it simply takens an Element pointer and frees the memory. However, given that Image Elements are implementation specific (i.e., SDL Surface data stored in the image property of ImageElement), these must be free'd manually (e.g., outside of this function).
|
|
****/
|
|
void freeElement(struct Element *element) {
|
|
switch (element->type) {
|
|
case TYPE_BUTTON:
|
|
free(((struct ButtonElement*)element->data)->string);
|
|
free(element->data);
|
|
break;
|
|
case TYPE_SPINNER:
|
|
free(((struct SpinnerElement*)element->data)->string);
|
|
free(element->data);
|
|
break;
|
|
case TYPE_TEXT:
|
|
free(((struct TextElement*)element->data)->string);
|
|
free(element->data);
|
|
break;
|
|
case TYPE_TEXT_INPUT:
|
|
free(((struct TextInputElement*)element->data)->string);
|
|
free(element->data);
|
|
break;
|
|
case TYPE_IMAGE:
|
|
free(element->data);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/****
|
|
if the passed Element's type is TYPE_BUTTON or TYPE_TEXT, set either the TextElement or ButtonElemnt's string to the passed string, realloc'ing as needed. If passed string is NULL, the Text or Button's string is realloc'd to fit one char, which is set to '\0'.
|
|
****/
|
|
int setElementText(struct Element *element, const char *string) {
|
|
if (string != NULL) {
|
|
int length = strlen(string);
|
|
switch(element->type) {
|
|
case TYPE_BUTTON:
|
|
((struct ButtonElement*)element->data)->string = realloc(((struct ButtonElement*)element->data)->string, length+1);
|
|
if (((struct ButtonElement*)element->data)->string == NULL)
|
|
return -2;
|
|
memcpy(((struct ButtonElement*)element->data)->string, string, length+1);
|
|
((struct ButtonElement*)element->data)->length = length;
|
|
break;
|
|
case TYPE_SPINNER:
|
|
((struct SpinnerElement*)element->data)->string = realloc(((struct SpinnerElement*)element->data)->string, length+1);
|
|
if (((struct SpinnerElement*)element->data)->string == NULL)
|
|
return -3;
|
|
memcpy(((struct SpinnerElement*)element->data)->string, string, length+1);
|
|
((struct SpinnerElement*)element->data)->length = length;
|
|
break;
|
|
case TYPE_TEXT:
|
|
((struct TextElement*)element->data)->string = realloc(((struct TextElement*)element->data)->string, length+1);
|
|
if (((struct TextElement*)element->data)->string == NULL)
|
|
return -3;
|
|
memcpy(((struct TextElement*)element->data)->string, string, length+1);
|
|
((struct TextElement*)element->data)->length = length;
|
|
break;
|
|
case TYPE_TEXT_INPUT:
|
|
((struct TextInputElement*)element->data)->string = realloc(((struct TextInputElement*)element->data)->string, length+1);
|
|
if (((struct TextInputElement*)element->data)->string == NULL)
|
|
return -4;
|
|
memcpy(((struct TextInputElement*)element->data)->string, string, length+1);
|
|
((struct TextInputElement*)element->data)->length = length;
|
|
((struct TextInputElement*)element->data)->cursor = length;
|
|
default:
|
|
break;
|
|
}
|
|
return 0;
|
|
} else {
|
|
switch(element->type) {
|
|
case TYPE_BUTTON:
|
|
((struct ButtonElement*)element->data)->string = realloc(((struct ButtonElement*)element->data)->string, 1);
|
|
if (((struct ButtonElement*)element->data)->string == NULL)
|
|
return -12;
|
|
((struct ButtonElement*)element->data)->string[0] = '\0';
|
|
((struct ButtonElement*)element->data)->length = 0;
|
|
break;
|
|
case TYPE_TEXT:
|
|
((struct TextElement*)element->data)->string = realloc(((struct TextElement*)element->data)->string, 1);
|
|
if (((struct TextElement*)element->data)->string == NULL)
|
|
return -13;
|
|
((struct TextElement*)element->data)->string[0] = '\0';
|
|
((struct TextElement*)element->data)->length = 0;
|
|
break;
|
|
case TYPE_TEXT_INPUT:
|
|
((struct TextInputElement*)element->data)->string = realloc(((struct TextInputElement*)element->data)->string, 1);
|
|
if (((struct TextInputElement*)element->data)->string == NULL)
|
|
return -14;
|
|
((struct TextInputElement*)element->data)->string[0] = '\0';
|
|
((struct TextInputElement*)element->data)->length = 0;
|
|
((struct TextInputElement*)element->data)->cursor = 0;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return 1;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int setElementValue(struct Element *element, int value) {
|
|
char value_string[128];
|
|
switch(element->type) {
|
|
case TYPE_SPINNER:
|
|
((struct SpinnerElement*)element->data)->value = value;
|
|
itoa(value, value_string, 10);
|
|
setElementText(element, value_string);
|
|
return 0;
|
|
break;
|
|
default:
|
|
return -2;
|
|
break;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int setElementPosition(struct Element *element, int x, int y) {
|
|
element->x = x;
|
|
element->y = y;
|
|
return 0;
|
|
}
|
|
|
|
int setElementCallback(struct Element *element, void(*callback)) {
|
|
element->callback = callback;
|
|
return 0;
|
|
}
|
|
|
|
int setElementSize(struct Element *element, int size) {
|
|
switch (element->type) {
|
|
case TYPE_TEXT_INPUT:
|
|
((struct TextInputElement*)element->data)->size = size;
|
|
break;
|
|
case TYPE_SPINNER:
|
|
((struct SpinnerElement*)element->data)->size = size;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int setElementUser(struct Element *element, void *user) {
|
|
element->user = user;
|
|
return 0;
|
|
}
|
|
|
|
int setElementImage(struct Element *element, void *image, int width, int height) {
|
|
if (element->type == TYPE_IMAGE) {
|
|
((struct ImageElement*)element->data)->image = image;
|
|
((struct ImageElement*)element->data)->width = width;
|
|
((struct ImageElement*)element->data)->height = height;
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/* dynamic setting ops */
|
|
|
|
int handleInputElement(struct Element *element, int ch) {
|
|
printf("got %d\n", ch);
|
|
if (element->type == TYPE_TEXT_INPUT) {
|
|
switch (ch) {
|
|
case 0:
|
|
break;
|
|
case 276: // left
|
|
if (((struct TextInputElement*)element->data)->cursor > 0) {
|
|
((struct TextInputElement*)element->data)->cursor--;
|
|
}
|
|
break;
|
|
case 275: // right
|
|
if (((struct TextInputElement*)element->data)->cursor < ((struct TextInputElement*)element->data)->length) {
|
|
((struct TextInputElement*)element->data)->cursor++;
|
|
}
|
|
break;
|
|
case 13: // enter
|
|
if (element->callback != NULL) {
|
|
element->callback();
|
|
}
|
|
break;
|
|
case '\b':
|
|
case 127:
|
|
if (((struct TextInputElement*)element->data)->cursor > 0) {
|
|
if (((struct TextInputElement*)element->data)->cursor < ((struct TextInputElement*)element->data)->length) {
|
|
((struct TextInputElement*)element->data)->length--;
|
|
int offset = ((struct TextInputElement*)element->data)->cursor;
|
|
char temp_string[256];
|
|
int i = offset;
|
|
int temp_offset = 0;
|
|
while(((struct TextInputElement*)element->data)->string[i] != '\0') {
|
|
temp_string[temp_offset++] = ((struct TextInputElement*)element->data)->string[i];
|
|
i++;
|
|
}
|
|
temp_string[temp_offset] = '\0';
|
|
// let's readd the end of the string after added char
|
|
((struct TextInputElement*)element->data)->cursor--;
|
|
i = offset-1;
|
|
temp_offset = 0;
|
|
while (temp_string[temp_offset] != '\0') {
|
|
((struct TextInputElement*)element->data)->string[i++] = temp_string[temp_offset++];
|
|
}
|
|
((struct TextInputElement*)element->data)->string[i] = '\0';
|
|
} else {
|
|
((struct TextInputElement*)element->data)->cursor--;
|
|
((struct TextInputElement*)element->data)->length--;
|
|
((struct TextInputElement*)element->data)->string[((struct TextInputElement*)element->data)->cursor] = '\0';
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
if (((struct TextInputElement*)element->data)->cursor < ((struct TextInputElement*)element->data)->size) {
|
|
//printf("cursor: %d, length: %d, string: \"%s\"\n", ((struct TextInputElement*)element->data)->cursor, ((struct TextInputElement*)element->data)->length, ((struct TextInputElement*)element->data)->string);
|
|
if (((struct TextInputElement*)element->data)->cursor < ((struct TextInputElement*)element->data)->length) {
|
|
//printf("adding %c, now is %s!\n", ch, ((struct TextInputElement*)element->data)->string);
|
|
((struct TextInputElement*)element->data)->length++;
|
|
int offset = ((struct TextInputElement*)element->data)->cursor;
|
|
char temp_string[256];
|
|
int i = offset;
|
|
int temp_offset = 0;
|
|
while(((struct TextInputElement*)element->data)->string[i] != '\0') {
|
|
temp_string[temp_offset++] = ((struct TextInputElement*)element->data)->string[i];
|
|
i++;
|
|
}
|
|
temp_string[temp_offset] = '\0';
|
|
((struct TextInputElement*)element->data)->string[((struct TextInputElement*)element->data)->cursor++] = ch;
|
|
// let's readd the end of the string after added char
|
|
i = offset+1;
|
|
temp_offset = 0;
|
|
while (temp_string[temp_offset] != '\0') {
|
|
((struct TextInputElement*)element->data)->string[i++] = temp_string[temp_offset++];
|
|
}
|
|
((struct TextInputElement*)element->data)->string[i] = '\0';
|
|
} else {
|
|
//printf("cursor: %d, length: %d, size: %d, string: \"%s\"\n", ((struct TextInputElement*)element->data)->cursor, ((struct TextInputElement*)element->data)->length, ((struct TextInputElement*)element->data)->size, ((struct TextInputElement*)element->data)->string);
|
|
((struct TextInputElement*)element->data)->length++;
|
|
((struct TextInputElement*)element->data)->string = realloc(((struct TextInputElement*)element->data)->string, ((struct TextInputElement*)element->data)->length+1);
|
|
((struct TextInputElement*)element->data)->string[((struct TextInputElement*)element->data)->cursor++] = ch;
|
|
((struct TextInputElement*)element->data)->string[((struct TextInputElement*)element->data)->cursor] = '\0';
|
|
//printf("max size is %d, cursor is at %d\n", ((struct TextInputElement*)element->data)->size, ((struct TextInputElement*)element->data)->cursor);
|
|
//printf("adding %c, now is %s!\n", ch, ((struct TextInputElement*)element->data)->string);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
return 0;
|
|
} else if (element->type == TYPE_SPINNER) {
|
|
switch (ch) {
|
|
case 0:
|
|
break;
|
|
case 276: // left
|
|
if (((struct SpinnerElement*)element->data)->cursor > 0) {
|
|
((struct SpinnerElement*)element->data)->cursor--;
|
|
}
|
|
break;
|
|
case 275: // right
|
|
if (((struct SpinnerElement*)element->data)->cursor < ((struct SpinnerElement*)element->data)->length) {
|
|
((struct SpinnerElement*)element->data)->cursor++;
|
|
}
|
|
break;
|
|
case 273: // up
|
|
if (((struct SpinnerElement*)element->data)->value < INT_MAX) {
|
|
char temp_string[256];
|
|
itoa(((struct SpinnerElement*)element->data)->value+1, temp_string, 10);
|
|
if (((struct SpinnerElement*)element->data)->value+1 >= 0) {
|
|
if (strlen(temp_string) <= ((struct SpinnerElement*)element->data)->size) {
|
|
setElementValue(element, ((struct SpinnerElement*)element->data)->value+1);
|
|
}
|
|
} else {
|
|
if (strlen(temp_string) <= ((struct SpinnerElement*)element->data)->size+1) {
|
|
setElementValue(element, ((struct SpinnerElement*)element->data)->value+1);
|
|
}
|
|
}
|
|
}
|
|
if (element->callback != NULL) {
|
|
element->callback();
|
|
}
|
|
break;
|
|
case 274: // down
|
|
if (((struct SpinnerElement*)element->data)->value > INT_MIN) {
|
|
char temp_string[256];
|
|
itoa(((struct SpinnerElement*)element->data)->value-1, temp_string, 10);
|
|
if (((struct SpinnerElement*)element->data)->value-1 >= 0) {
|
|
if (strlen(temp_string) <= ((struct SpinnerElement*)element->data)->size) {
|
|
setElementValue(element, ((struct SpinnerElement*)element->data)->value-1);
|
|
}
|
|
} else {
|
|
// +1 size due to negative sign, rendering must render width as size + 1 as well!
|
|
if (strlen(temp_string) <= ((struct SpinnerElement*)element->data)->size+1) {
|
|
setElementValue(element, ((struct SpinnerElement*)element->data)->value-1);
|
|
}
|
|
}
|
|
}
|
|
if (element->callback != NULL) {
|
|
element->callback();
|
|
}
|
|
break;
|
|
case 13: // enter
|
|
if (element->callback != NULL) {
|
|
element->callback();
|
|
}
|
|
break;
|
|
case '\b':
|
|
case 127:
|
|
if (((struct SpinnerElement*)element->data)->cursor > 0) {
|
|
if (((struct SpinnerElement*)element->data)->cursor < ((struct SpinnerElement*)element->data)->length) {
|
|
((struct SpinnerElement*)element->data)->length--;
|
|
int offset = ((struct SpinnerElement*)element->data)->cursor;
|
|
char temp_string[256];
|
|
int i = offset;
|
|
int temp_offset = 0;
|
|
while(((struct SpinnerElement*)element->data)->string[i] != '\0') {
|
|
temp_string[temp_offset++] = ((struct SpinnerElement*)element->data)->string[i];
|
|
i++;
|
|
}
|
|
temp_string[temp_offset] = '\0';
|
|
// let's readd the end of the string after added char
|
|
((struct SpinnerElement*)element->data)->cursor--;
|
|
i = offset-1;
|
|
temp_offset = 0;
|
|
while (temp_string[temp_offset] != '\0') {
|
|
((struct SpinnerElement*)element->data)->string[i++] = temp_string[temp_offset++];
|
|
}
|
|
((struct SpinnerElement*)element->data)->string[i] = '\0';
|
|
} else {
|
|
((struct SpinnerElement*)element->data)->cursor--;
|
|
((struct SpinnerElement*)element->data)->length--;
|
|
((struct SpinnerElement*)element->data)->string[((struct SpinnerElement*)element->data)->cursor] = '\0';
|
|
}
|
|
}
|
|
setElementValue(element, atoi(((struct SpinnerElement*)element->data)->string));
|
|
break;
|
|
default:
|
|
if ((ch >= 48 && ch <= 57) || ch == 45) {
|
|
if (((struct SpinnerElement*)element->data)->cursor < ((struct SpinnerElement*)element->data)->size) {
|
|
if (((struct SpinnerElement*)element->data)->cursor < ((struct SpinnerElement*)element->data)->length) {
|
|
((struct SpinnerElement*)element->data)->length++;
|
|
int offset = ((struct SpinnerElement*)element->data)->cursor;
|
|
char temp_string[256];
|
|
int i = offset;
|
|
int temp_offset = 0;
|
|
while(((struct SpinnerElement*)element->data)->string[i] != '\0') {
|
|
temp_string[temp_offset++] = ((struct SpinnerElement*)element->data)->string[i];
|
|
i++;
|
|
}
|
|
temp_string[temp_offset] = '\0';
|
|
((struct SpinnerElement*)element->data)->string[((struct SpinnerElement*)element->data)->cursor++] = ch;
|
|
// let's readd the end of the string after added char
|
|
i = offset+1;
|
|
temp_offset = 0;
|
|
while (temp_string[temp_offset] != '\0') {
|
|
((struct SpinnerElement*)element->data)->string[i++] = temp_string[temp_offset++];
|
|
}
|
|
((struct SpinnerElement*)element->data)->string[i] = '\0';
|
|
} else {
|
|
((struct SpinnerElement*)element->data)->length++;
|
|
((struct SpinnerElement*)element->data)->string = realloc(((struct SpinnerElement*)element->data)->string, ((struct SpinnerElement*)element->data)->length+1);
|
|
((struct SpinnerElement*)element->data)->string[((struct SpinnerElement*)element->data)->cursor++] = ch;
|
|
((struct SpinnerElement*)element->data)->string[((struct SpinnerElement*)element->data)->cursor] = '\0';
|
|
}
|
|
}
|
|
setElementValue(element, atoi(((struct SpinnerElement*)element->data)->string));
|
|
|
|
printf("got number\n");
|
|
}
|
|
break;
|
|
}
|
|
} else {
|
|
return -1;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* gettin' operations */
|
|
|
|
const char *getElementText(struct Element *element) {
|
|
switch (element->type) {
|
|
case TYPE_TEXT_INPUT:
|
|
return ((struct TextInputElement*)element->data)->string;
|
|
break;
|
|
case TYPE_TEXT:
|
|
return ((struct TextElement*)element->data)->string;
|
|
break;
|
|
case TYPE_SPINNER:
|
|
return ((struct SpinnerElement*)element->data)->string;
|
|
break;
|
|
case TYPE_BUTTON:
|
|
return ((struct ButtonElement*)element->data)->string;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return "";
|
|
}
|