timesynk/tile_editor/sdl.c

1770 lines
65 KiB
C

#include <SDL/SDL.h>
#if !defined (__APPLE__)
#include <SDL/SDL_image.h>
#else
#include <SDL_image.h>
#include "CoreFoundation/CoreFoundation.h" // yee apple path rubbish
#endif
#include <SDL/SDL_syswm.h> // for wm hints
#include <unistd.h> // for getcwd
#include "stubs.h"
#include "sdl.h"
#include "assets.h"
#include "elements.h"
#include "font.h"
#include "../common/data.h"
#include "../common/fio.h"
int interfaceInit() {
#ifdef __APPLE__
char path[PATH_MAX];
CFURLRef res = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle());
CFURLGetFileSystemRepresentation(res, TRUE, (UInt8 *)path, PATH_MAX);
CFRelease(res);
// there's likely a better way to do this!
size_t path_len = strlen(path);
int p_i = path_len;
int p_c = 0;
while (p_i > 0) {
if (path[p_i] == '/') {
p_c++;
}
if (p_c == 3) break;
p_i--;
}
char bundle_path[p_i+1];
memcpy(bundle_path, path, p_i);
bundle_path[p_i] = '\0';
chdir(bundle_path);
#endif
// TODO: move to newData function
tiles_data = malloc(sizeof(struct Data));
tiles_data->size = SET_SIZE;
tiles_data->id = malloc(sizeof(int)*SET_SIZE);
tiles_data->set = malloc(sizeof(struct TileSetData*)*SET_SIZE);
memset(tiles_data->set, 0, sizeof(struct TileSetData*)*SET_SIZE);
tiles_data->set_count = 0;
// TODO: move to newTileSetData function or similar
int i=0;
while (i < 7) {
tiles_data->set[i] = malloc(sizeof(struct TileSetData));
tiles_data->set[i]->tid = i;
tiles_data->set[i]->tile_count = 0;
tiles_data->set[i]->size = SET_SIZE;
tiles_data->set[i]->keys = newTable(SET_SIZE);
tiles_data->set[i]->tile = malloc(sizeof(struct TileData*)*SET_SIZE);
int j = 0;
while (j < SET_SIZE) {
tiles_data->set[i]->tile[j++] = NULL;
}
i++;
}
g_data = 1;
g_width = 400;
g_height = 480;
// since we use threads, Mac OS 10+ support only. Also threaded os.
SDL_Init(SDL_INIT_VIDEO);
// Enable Unicode, for later text input
SDL_EnableUNICODE(SDL_ENABLE);
// Set up our SDL Window
if ((screen = SDL_SetVideoMode(g_width, g_height, 32, SDL_SWSURFACE|SDL_DOUBLEBUF)) == NULL) {
return -1;
}
SDL_WM_SetCaption("TS:Tile Editor", NULL);
menu_area = SDL_CreateRGBSurface(screen->flags, g_width, 112, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask);
tile_area_rect.y = 112;
tile_area = SDL_CreateRGBSurface(screen->flags, g_width, 392, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask);
sprite_area_rect.x = g_width;
sprite_area = SDL_CreateRGBSurface(screen->flags, g_width, screen->h, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask);
loadFont(&font, font_images, font_images_length, 8, 8);
first_element = NULL;
last_element = NULL;
focus_element = NULL;
menu_elements = newElementList();
hookElementList(menu_elements, HOOK_ADD, &addElementHook);
setElementListUser(menu_elements, menu_area);
editor_elements = newElementList();
hookElementList(editor_elements, HOOK_ADD, &addElementHook);
setElementListUser(editor_elements, tile_area);
// load up our elements
button_quit = newElement(TYPE_BUTTON);
setElementText(button_quit, "QUIT");
setElementPosition(button_quit, menu_area->w - getElementWidth(button_quit)-13, 2+font.height*2);
setElementCallback(button_quit, &Quit);
addElementToList(menu_elements, button_quit);
text_console = newElement(TYPE_TEXT);
//setElementPosition(text_console, 0, 2+font.height*2);
setElementPosition(text_console, 0, 2);
addElementToList(menu_elements, text_console);
/* graphics input */
text_graphics = newElement(TYPE_TEXT);
setElementText(text_graphics, "graphics:");
setElementPosition(text_graphics, 2, 2 + font.height*4);
addElementToList(menu_elements, text_graphics);
input_graphics = newElement(TYPE_TEXT_INPUT);
setElementPosition(input_graphics, getElementWidth(text_graphics) + font.width + 4, 2 + font.height*4);
setElementCallback(input_graphics, &loadGraphicsCallback);
setElementSize(input_graphics, 27);
addElementToList(menu_elements, input_graphics);
button_graphics = newElement(TYPE_BUTTON);
setElementText(button_graphics, "load");
setElementPosition(button_graphics, getElementWidth(text_graphics) + getElementWidth(input_graphics) + (font.width*2) + 4, 2 + font.height*4);
setElementCallback(button_graphics, &loadGraphicsCallback);
addElementToList(menu_elements, button_graphics);
/* tileset data input */
text_data = newElement(TYPE_TEXT);
setElementText(text_data, "data: ");
setElementPosition(text_data, 2, 2 + font.height*6);
addElementToList(menu_elements, text_data);
input_data = newElement(TYPE_TEXT_INPUT);
setElementPosition(input_data, getElementWidth(text_data) + font.width + 4, 2 + font.height*6);
setElementCallback(input_data, &loadDataCallback);
setElementSize(input_data, 27);
addElementToList(menu_elements, input_data);
button_data = newElement(TYPE_BUTTON);
setElementText(button_data, "load");
setElementPosition(button_data, getElementWidth(text_data) + getElementWidth(input_data) + (font.width*2) + 4, 2 + font.height*6);
setElementCallback(button_data, &loadDataCallback);
addElementToList(menu_elements, button_data);
button_data_save = newElement(TYPE_BUTTON);
setElementText(button_data_save, "save");
setElementPosition(button_data_save, getElementWidth(text_data) + getElementWidth(input_data) + getElementWidth(button_data) + (font.width*3) + 4, 2 + font.height*6);
setElementCallback(button_data_save, &saveDataCallback);
addElementToList(menu_elements, button_data_save);
/* set input */
text_set = newElement(TYPE_TEXT);
setElementText(text_set, "set:");
setElementPosition(text_set, 2, 2 + font.height*9);
addElementToList(menu_elements, text_set);
g_set = 0;
input_set = newElement(TYPE_SPINNER);
setElementPosition(input_set, getElementWidth(text_set) + font.width + 4, 2 + font.height*9);
setElementCallback(input_set, &setSetCallback);
setElementSize(input_set, 3);
setElementValue(input_set, 0);
addElementToList(menu_elements, input_set);
/*button_set = newElement(TYPE_BUTTON);
setElementText(button_set, "ok");
setElementPosition(button_set, getElementWidth(text_set) + getElementWidth(input_set) + (font.width*2) + 4, 2 + font.height*9);
setElementCallback(button_set, &setSetCallback);
addElement(button_set, menu_area);*/
/* tile id input */
text_id = newElement(TYPE_TEXT);
setElementText(text_id, "id: ");
setElementPosition(text_id, 2, 2 + font.height*11);
addElementToList(menu_elements, text_id);
g_id = 0;
input_id = newElement(TYPE_SPINNER);
setElementPosition(input_id, getElementWidth(text_id) + font.width + 4, 2 + font.height*11);
setElementCallback(input_id, &setIdCallback);
setElementSize(input_id, 3);
setElementValue(input_id, 0);
addElementToList(menu_elements, input_id);
SDL_FillRect(menu_area, NULL, SDL_MapRGB(menu_area->format, 8, 16, 12));
image_tile = newElement(TYPE_IMAGE);
//setElementPosition(image_tile, getElementWidth(button_id) + getElementWidth(text_id) + getElementWidth(input_id) + (font.width*3) + 4, 2 + font.height*9);
setElementPosition(image_tile, getElementWidth(text_set) + getElementWidth(input_set) + (font.width*3) + 4, 2 + font.height*9);
setElementCallback(image_tile, &showSpritesheet);
SDL_Surface *tile_surface = SDL_CreateRGBSurface(menu_area->flags, 32, 32, menu_area->format->BitsPerPixel, menu_area->format->Rmask, menu_area->format->Gmask, menu_area->format->Bmask, menu_area->format->Amask);
setElementImage(image_tile, tile_surface, 32, 32);
addElementToList(menu_elements, image_tile);
char cwd[128];
getcwd(cwd, sizeof(cwd));
printConsole(cwd);
/* now load up our tile area stuff */
/*text_name = newElement(TYPE_TEXT);
setElementText(text_name, "...... name ......");
setElementPosition(text_name, 2, 2);
addElementToList(editor_elements, text_name);
text_value = newElement(TYPE_TEXT);
setElementText(text_value, "...... value ......");
setElementPosition(text_value, 2 + (20 * font.width), 2);
addElementToList(editor_elements, text_value);*/
SDL_FillRect(tile_area, NULL, SDL_MapRGB(tile_area->format, 8, 16, 24));
drawElements();
SDL_Flip(screen);
return 0;
}
int interfaceLoop() {
while (SDL_WaitEvent(&event)) {
switch(event.type) {
case SDL_QUIT:
return 0;
break;
case SDL_MOUSEBUTTONDOWN:
handleMouseDown(&event.button);
break;
case SDL_MOUSEBUTTONUP:
handleMouseUp(&event.button);
break;
case SDL_MOUSEMOTION:
handleMouseMove(&event.motion);
break;
case SDL_KEYDOWN:
if (event.key.state == SDL_PRESSED) {
handleKeyDown(&event.key);
}
break;
default:
break;
}
//SDL_BlitSurface(menu_area, &update_rect, screen, &update_rect);
//SDL_Surface *scaled_area = SDL_ScaleSurface(menu_area, 2.0f, 2.0f);
SDL_BlitSurface(menu_area, NULL, screen, NULL);
SDL_BlitSurface(tile_area, NULL, screen, &tile_area_rect);
//SDL_BlitSurface(scaled_area, NULL, screen, NULL);
SDL_Flip(screen);
}
return 0;
}
void interfaceClose() {
SDL_FreeSurface(screen);
struct Element *t_element = first_element;
while (t_element) {
struct Element *next_element = t_element->next;
if (t_element->type == TYPE_IMAGE) {
if (((struct ImageElement*)t_element->data)->image)
SDL_FreeSurface(((struct ImageElement*)t_element->data)->image);
}
freeElement(t_element);
t_element = next_element;
}
SDL_Quit();
}
void Quit() {
SDL_Event event;
event.type = SDL_QUIT;
SDL_PushEvent(&event);
}
void addElement(struct Element *element, SDL_Surface *surface) {
if (first_element == NULL) {
first_element = element;
} else {
struct Element *t_element = first_element;
while (t_element->next != NULL) {
t_element = t_element->next;
}
t_element->next = element;
}
element->user = surface;
}
void addElementHook(struct ElementList *list, struct Element *element) {
element->user = list->user;
}
void drawElements() {
struct Element *element = menu_elements->first;
while (element != NULL) {
drawElement(element);
element = element->next;
}
element = editor_elements->first;
while (element != NULL) {
drawElement(element);
element = element->next;
}
}
/* drawing functions */
void drawElement(const struct Element *element) {
if (element != NULL) {
SDL_Rect get_rect_son = {element->x, element->y, 0, 0};
switch (element->type) {
case TYPE_BUTTON:
// clear area
get_rect_son.w = (font.width * ((struct ButtonElement*)element->data)->length) + 4;
get_rect_son.h = font.height + 4;
SDL_FillRect(element->user, &get_rect_son, SDL_MapRGB(((SDL_Surface*)element->user)->format, 8, 16, 12));
if (element->state == STATE_NORMAL) {
get_rect_son.w = (font.width * ((struct ButtonElement*)element->data)->length) + 2;
get_rect_son.h = font.height + 2;
SDL_FillRect(element->user, &get_rect_son, SDL_MapRGB(((SDL_Surface*)element->user)->format, 32, 32, 48));
get_rect_son.x = element->x+2;
get_rect_son.y = element->y+2;
SDL_FillRect(element->user, &get_rect_son, SDL_MapRGB(((SDL_Surface*)element->user)->format, 48, 48, 64));
drawString(&font, element->user, element->x+3, element->y+3, ((struct ButtonElement*)element->data)->string);
} else if (element->state == STATE_PRESSED) {
get_rect_son.w = (font.width * ((struct ButtonElement*)element->data)->length) + 2;
get_rect_son.h = font.height + 2;
SDL_FillRect(element->user, &get_rect_son, SDL_MapRGB(((SDL_Surface*)element->user)->format, 32, 32, 48));
get_rect_son.x = element->x+1;
get_rect_son.y = element->y+1;
get_rect_son.w = (font.width * ((struct ButtonElement*)element->data)->length) + 2;
get_rect_son.h = font.height + 2;
SDL_FillRect(element->user, &get_rect_son, SDL_MapRGB(((SDL_Surface*)element->user)->format, 48, 48, 64));
drawString(&font, element->user, element->x+2, element->y+2, ((struct ButtonElement*)element->data)->string);
}
break;
case TYPE_SPINNER:
get_rect_son.x = element->x-1;
get_rect_son.y = element->y-1;
get_rect_son.w = font.width * ((((struct SpinnerElement*)element->data)->size)+1) + 4;
get_rect_son.h = font.height + 4;
if (element->state == STATE_FOCUS) {
SDL_FillRect(element->user, &get_rect_son, SDL_MapRGB(((SDL_Surface*)element->user)->format, 128, 128, 200));
} else {
SDL_FillRect(element->user, &get_rect_son, SDL_MapRGB(((SDL_Surface*)element->user)->format, 48, 48, 64));
}
get_rect_son.x = element->x;
get_rect_son.y = element->y;
get_rect_son.w = font.width * ((((struct SpinnerElement*)element->data)->size)+1) + 2;
get_rect_son.h = font.height + 2;
SDL_FillRect(element->user, &get_rect_son, SDL_MapRGB(((SDL_Surface*)element->user)->format, 32, 32, 48));
// draw string
drawString(&font, element->user, element->x+1, element->y+1, ((struct SpinnerElement*)element->data)->string);
if (element->state == STATE_FOCUS) {
get_rect_son.x = element->x + (font.width * ((struct SpinnerElement*)element->data)->cursor);
get_rect_son.y = element->y+1;
get_rect_son.w = 2;
get_rect_son.h = font.height;
SDL_FillRect(element->user, &get_rect_son, SDL_MapRGB(((SDL_Surface*)element->user)->format, 128, 128, 200));
}
// draw button bg
get_rect_son.x = element->x + (font.width * ((((struct SpinnerElement*)element->data)->size)+1)) + 3;
get_rect_son.y = element->y-1;
get_rect_son.w = font.width + 2;
get_rect_son.h = font.height + 4;
SDL_FillRect(element->user, &get_rect_son, SDL_MapRGB(((SDL_Surface*)element->user)->format, 32, 32, 48));
// draw top button
get_rect_son.x = element->x + (font.width * ((((struct SpinnerElement*)element->data)->size)+1)) + 4;
get_rect_son.y = element->y-1;
get_rect_son.w = font.width;
get_rect_son.h = font.height/2;
SDL_FillRect(element->user, &get_rect_son, SDL_MapRGB(((SDL_Surface*)element->user)->format, 48, 48, 64));
get_rect_son.x = element->x + (font.width * ((((struct SpinnerElement*)element->data)->size)+1)) + 5;
get_rect_son.y = element->y;
get_rect_son.w = font.width-2;
get_rect_son.h = font.height/4;
SDL_FillRect(element->user, &get_rect_son, SDL_MapRGB(((SDL_Surface*)element->user)->format, 128, 128, 200));
// draw bottom button
get_rect_son.x = element->x + (font.width * ((((struct SpinnerElement*)element->data)->size)+1)) + 4;
get_rect_son.y = element->y + 3 + font.height/2;
get_rect_son.w = font.width;
get_rect_son.h = font.height/2;
SDL_FillRect(element->user, &get_rect_son, SDL_MapRGB(((SDL_Surface*)element->user)->format, 48, 48, 64));
get_rect_son.x = element->x + (font.width * ((((struct SpinnerElement*)element->data)->size)+1)) + 1 + font.width/2;
get_rect_son.y = element->y + font.height/2 + font.height/2;
get_rect_son.w = font.width-2;
get_rect_son.h = font.height/4;
SDL_FillRect(element->user, &get_rect_son, SDL_MapRGB(((SDL_Surface*)element->user)->format, 128, 128, 200));
break;
case TYPE_TEXT:
get_rect_son.w = (font.width * ((struct TextElement*)element->data)->length) + 2;
get_rect_son.h = font.height + 2;
SDL_FillRect(element->user, &get_rect_son, SDL_MapRGB(((SDL_Surface*)element->user)->format, 32, 32, 48));
drawString(&font, element->user, element->x+1, element->y+1, ((struct TextElement*)element->data)->string);
break;
case TYPE_TEXT_INPUT:
get_rect_son.x = element->x-1;
get_rect_son.y = element->y-1;
get_rect_son.w = (font.width * ((struct TextInputElement*)element->data)->size) + 4;
get_rect_son.h = font.height + 4;
if (element->state == STATE_FOCUS) {
SDL_FillRect(element->user, &get_rect_son, SDL_MapRGB(((SDL_Surface*)element->user)->format, 128, 128, 200));
} else {
SDL_FillRect(element->user, &get_rect_son, SDL_MapRGB(((SDL_Surface*)element->user)->format, 48, 48, 64));
}
get_rect_son.x = element->x;
get_rect_son.y = element->y;
get_rect_son.w = (font.width * ((struct TextInputElement*)element->data)->size) + 2;
get_rect_son.h = font.height + 2;
SDL_FillRect(element->user, &get_rect_son, SDL_MapRGB(((SDL_Surface*)element->user)->format, 32, 32, 48));
// draw string
drawString(&font, element->user, element->x+1, element->y+1, ((struct TextInputElement*)element->data)->string);
if (element->state == STATE_FOCUS) {
get_rect_son.x = element->x + (font.width * ((struct TextInputElement*)element->data)->cursor);
get_rect_son.y = element->y+1;
get_rect_son.w = 2;
get_rect_son.h = font.height;
SDL_FillRect(element->user, &get_rect_son, SDL_MapRGB(((SDL_Surface*)element->user)->format, 128, 128, 200));
}
break;
case TYPE_IMAGE:
get_rect_son.w = ((struct ImageElement*)element->data)->width;
get_rect_son.h = ((struct ImageElement*)element->data)->height;
SDL_BlitSurface(((struct ImageElement*)element->data)->image, NULL, element->user, &get_rect_son);
break;
}
}
}
void drawChar(const struct Font *font, SDL_Surface *surface, int x, int y, const char ch) {
int y_offset = ch / 16;
int x_offset = ch - (y_offset*16);
SDL_Rect character_offset = { x_offset*font->width, y_offset*font->height, font->width, font->height};
SDL_Rect render_position = {x, y, font->width, font->height};
SDL_BlitSurface(font->surface, &character_offset, surface, &render_position);
}
void drawString(const struct Font *font, SDL_Surface *surface, int x, int y, const char *string) {
int i = 0;
while (string[i] != '\0') {
drawChar(font, surface, x + (i*font->width), y, string[i]);
i++;
}
}
void clearElement(const struct Element* element) {
SDL_Rect clear_rect = { element->x, element->y, getElementWidth(element), getElementHeight(element) };
SDL_FillRect(element->user, &clear_rect, SDL_MapRGB(screen->format, 8, 16, 12));
}
/* Element information functions */
int getElementWidth(const struct Element* element) {
switch (element->type) {
case TYPE_TEXT_INPUT:
return (font.width * ((struct TextInputElement*)element->data)->size) + 4;
break;
case TYPE_TEXT:
return (font.width * ((struct TextElement*)element->data)->length) + 2;
break;
case TYPE_SPINNER:
return font.width * (((struct SpinnerElement*)element->data)->size+2) + 4;
break;
case TYPE_BUTTON:
return (font.width * ((struct ButtonElement*)element->data)->length) + 4;
break;
case TYPE_IMAGE:
return ((struct ImageElement*)element->data)->width;
break;
default:
break;
}
return 0;
}
int getElementHeight(const struct Element* element) {
switch (element->type) {
case TYPE_TEXT_INPUT:
case TYPE_SPINNER:
return font.height+4;
break;
case TYPE_TEXT:
return font.height*2;
break;
case TYPE_BUTTON:
return font.height + 4;
break;
case TYPE_IMAGE:
return ((struct ImageElement*)element->data)->height;
break;
default:
break;
}
return 0;
}
/* begin handler functions */
void handleKeyDown(const SDL_KeyboardEvent *event) {
printf("sdl keysym unicode: %d, scancode: %d, keycode: %d, mod: %d\n", event->keysym.unicode, event->keysym.scancode, event->keysym.sym, event->keysym.mod);
// F11 = fullscreen/windowed toggle
if (event->keysym.sym == 292) {
if (g_fullscreen == 1) {
screen = SDL_SetVideoMode(g_width, g_height, 32, SDL_SWSURFACE|SDL_DOUBLEBUF);
g_fullscreen = 0;
} else {
screen = SDL_SetVideoMode(g_width, g_height, 32, SDL_FULLSCREEN|SDL_SWSURFACE|SDL_DOUBLEBUF);
g_fullscreen = 1;
}
return;
} else if (event->keysym.sym == 9) { // tab
if (focus_element != NULL) {
if (focus_element->next != NULL) {
focus_element->state = STATE_NORMAL;
drawElement(focus_element);
focus_element = focus_element->next;
while (focus_element->next != NULL) {
if (focus_element->type == TYPE_SPINNER || focus_element->type == TYPE_TEXT_INPUT) {
break;
} else {
focus_element = focus_element->next;
}
}
focus_element->state = STATE_FOCUS;
drawElement(focus_element);
}
}
return;
}
int mod = SDL_GetModState();
if (focus_element != NULL) {
if (mod != 0) {
if (mod & KMOD_SHIFT) {
handleInputElement(focus_element, event->keysym.unicode);
} else {
handleInputElement(focus_element, event->keysym.sym);
}
} else {
handleInputElement(focus_element, event->keysym.sym);
}
drawElement(focus_element);
}
}
void handleMouseDown(const SDL_MouseButtonEvent *event) {
if (event->x >= menu_area->w) {
return;
}
int x_offset = 0;
int y_offset = 0;
struct Element *element = NULL;
if (event->x <= menu_area->w && event->y <= menu_area->h) {
element = menu_elements->first;
} else if (event->x <= tile_area->w && event->y <= tile_area->h) {
element = editor_elements->first;
x_offset = tile_area_rect.x;
y_offset = tile_area_rect.y;
}
int t_x, t_y, t_w, t_h = 0;
while (element != NULL) {
switch (element->type) {
case TYPE_BUTTON:
t_w = x_offset + element->x+2 +(font.width * ((struct ButtonElement*)element->data)->length) + 2;
t_h = y_offset + element->y+2 + font.height + 2;
t_x = x_offset + element->x+2;
t_y = y_offset + element->y+2;
break;
case TYPE_TEXT_INPUT:
t_w = x_offset + element->x-1 +(font.width * ((struct TextInputElement*)element->data)->size) + 4;
t_h = y_offset + element->y-1 + font.height + 4;
t_x = x_offset + element->x-1;
t_y = y_offset + element->y-1;
break;
case TYPE_SPINNER:
t_w = x_offset + element->x-1 + (font.width * (((struct SpinnerElement*)element->data)->size+2)) + 4;
t_h = y_offset + element->y-1 + font.height + 4;
t_x = x_offset + element->x-1;
t_y = y_offset + element->y-1;
break;
case TYPE_IMAGE:
t_w = x_offset + element->x + ((struct ImageElement*)element->data)->width;
t_h = y_offset + element->y + ((struct ImageElement*)element->data)->height;
t_x = x_offset + element->x;
t_y = y_offset + element->y;
break;
}
if ((t_x <= event->x && t_w >= event->x) && (t_y <= event->y && t_h >= event->y)) {
element->state = STATE_PRESSED;
if (last_element != NULL) {
if (last_element != element) {
last_element->state = STATE_NORMAL;
drawElement(last_element);
}
}
last_element = element;
drawElement(element);
break;
}
element = element->next;
}
update_rect.x = t_x-2;
update_rect.y = t_y-2;
update_rect.w = t_w+2;
update_rect.h = t_h+2;
}
void handleMouseUp(const SDL_MouseButtonEvent *event) {
if (event->x >= menu_area->w) {
handleSpritesheetClick(event->x-menu_area->w, event->y);
return;
}
int x_offset = 0;
int y_offset = 0;
if (event->x <= menu_area->w && event->y <= menu_area->h) {
} else if (event->x <= tile_area->w && event->y <= tile_area->h) {
x_offset = tile_area_rect.x;
y_offset = tile_area_rect.y;
}
if (last_element != NULL) {
int t_x, t_y, t_w, t_h = 0;
switch (last_element->type) {
case TYPE_BUTTON:
t_w = x_offset + last_element->x+2 +(font.width * ((struct ButtonElement*)last_element->data)->length) + 2;
t_h = y_offset + last_element->y+2 + font.height + 2;
t_x = x_offset + last_element->x+2;
t_y = y_offset + last_element->y+2;
break;
case TYPE_TEXT_INPUT:
t_w = x_offset + last_element->x-1 +(font.width * ((struct TextInputElement*)last_element->data)->size) + 4;
t_h = y_offset + last_element->y-1 + font.height + 4;
t_x = x_offset + last_element->x-1;
t_y = y_offset + last_element->y-1;
break;
case TYPE_SPINNER:
t_w = x_offset + last_element->x-1 + font.width * (((struct SpinnerElement*)last_element->data)->size+2) + 4;
t_h = y_offset + last_element->y-1 + font.height + 4;
t_x = x_offset + last_element->x-1;
t_y = y_offset + last_element->y-1;
break;
case TYPE_IMAGE:
t_w = x_offset + last_element->x + ((struct ImageElement*)last_element->data)->width;
t_h = y_offset + last_element->y + ((struct ImageElement*)last_element->data)->height;
t_x = x_offset + last_element->x;
t_y = y_offset + last_element->y;
break;
}
last_element->state = STATE_NORMAL;
drawElement(last_element);
if ((t_x <= event->x && t_w >= event->x) && (t_y <= event->y && t_h >= event->y)) {
// check against spinner up + down buttons
if (last_element->type == TYPE_SPINNER) {
t_x = last_element->x + (font.width * ((((struct SpinnerElement*)last_element->data)->size)+1)) + 4;
t_w = font.width + t_x;
t_h = t_y + font.height/2;
if ((t_x <= event->x && t_w >= event->x) && (t_y <= event->y && t_h >= event->y)) {
if (event->button < 4)
handleMouseButton(last_element, 4);
else
handleMouseButton(last_element, event->button);
} else {
// bottom
t_y = last_element->y + 3 + font.height/2;
t_h = t_y + font.height/2;
if ((t_x <= event->x && t_w >= event->x) && (t_y <= event->y && t_h >= event->y)) {
if (event->button < 4)
handleMouseButton(last_element, 5);
else
handleMouseButton(last_element, event->button);
} else {
int cursor = (event->x - last_element->x) / font.width;
if (((struct SpinnerElement*)last_element->data)->length >= cursor) {
((struct SpinnerElement*)last_element->data)->cursor = cursor;
}
handleMouseButton(last_element, event->button);
}
}
} else if (last_element->type == TYPE_TEXT_INPUT) {
int cursor = (event->x - last_element->x) / font.width;
if (((struct TextInputElement*)last_element->data)->length >= cursor) {
((struct TextInputElement*)last_element->data)->cursor = cursor;
}
handleMouseButton(last_element, event->button);
} else {
handleMouseButton(last_element, event->button);
}
// chance of last_element being free'd or otherwise at this point, so check if NULL
if (last_element != NULL) {
if (last_element->type == TYPE_TEXT_INPUT || last_element->type == TYPE_SPINNER) {
focus_element = last_element;
focus_element->state = STATE_FOCUS;
}
}
} else {
focus_element = NULL;
}
if (last_element != NULL) {
drawElement(last_element);
}
update_rect.x = t_x-2;
update_rect.y = t_y-2;
update_rect.w = t_w+2;
update_rect.h = t_h+2;
}
}
void handleMouseMove(const SDL_MouseMotionEvent *event) {
}
void handleSpritesheetClick(int x, int y) {
struct Spritesheet *spritesheet;
switch (g_set) {
case PLAYER:
spritesheet = &player_sprites;
break;
case FLOOR:
spritesheet = &floor_sprites;
break;
case WALL:
spritesheet = &wall_sprites;
break;
case DOOR:
spritesheet = &door_sprites;
break;
case ITEM:
spritesheet = &item_sprites;
break;
case EQUIP:
spritesheet = &equip_sprites;
break;
case NPC:
spritesheet = &npc_sprites;
break;
default:
return;
break;
}
/* now load small preview of tile */
int id = (x / spritesheet->width) + ((y / spritesheet->height)*spritesheet->columns);
setElementValue(input_id, id);
setIdCallback();
drawElement(input_id);
//int y_offset = g_id / spritesheet->columns;
//int x_offset = g_id - (y_offset * spritesheet->columns);
}
void positionElements() {
struct Element *element = editor_elements->first;
struct Element *delete_element = NULL;
int x_offset = 2;
//int y_offset = 2;
int y_offset = getElementHeight(button_add_pair)+6;
while (element != NULL) {
switch (element->id) {
case ID_DELETE:
x_offset = 2;
delete_element = element;
setElementPosition(element, x_offset, y_offset-1);
x_offset += getElementWidth(element)+6;
break;
case ID_KEY:
setElementPosition(element, x_offset, y_offset);
x_offset += getElementWidth(element)+2;
break;
case ID_VALUE:
setElementPosition(element, x_offset, y_offset);
y_offset += getElementHeight(element)+2;
x_offset = 2;
break;
case ID_INV_ADD:
setElementPosition(element, x_offset, y_offset);
y_offset += getElementHeight(element)+2;
x_offset = getElementWidth(delete_element)+2;
break;
case ID_ITEM_DEL:
x_offset = getElementWidth(delete_element) + 2;
setElementPosition(element, x_offset, y_offset);
x_offset += getElementWidth(element)+4;
break;
case ID_ITEM_NAME:
setElementPosition(element, x_offset, y_offset);
x_offset += getElementWidth(element)+2;
break;
case ID_ITEM_NAME_VAL:
setElementPosition(element, x_offset, y_offset);
x_offset = (getElementWidth(delete_element)*2)+6;
y_offset += getElementHeight(element)+2;
break;
case ID_ITEM_MIN:
case ID_ITEM_MAX:
case ID_ITEM_CHANCE:
setElementPosition(element, x_offset, y_offset);
x_offset += getElementWidth(element)+2;
break;
case ID_ITEM_MIN_VAL:
case ID_ITEM_MAX_VAL:
setElementPosition(element, x_offset, y_offset);
x_offset += getElementWidth(element)+4;
break;
case ID_ITEM_CHANCE_VAL:
setElementPosition(element, x_offset, y_offset);
x_offset = 2;
y_offset += getElementHeight(element)+2;
break;
default:
break;
}
element = element->next;
}
}
/* button callback */
void loadGraphicsCallback() {
printConsole("loading gfx");
int ret = 0;
char temp[64];
char temp_2[96];
sprintf(temp, "%s/%s", getElementText(input_graphics), "players.png");
sprintf(temp_2, "loading %s", temp);
printConsole(temp_2);
ret = loadSpritesheetFromFile(&player_sprites, temp, 16, 32, 6);
if (ret != 0) {
sprintf(temp_2, "error(%d) loading %s", ret, temp);
printConsole(temp_2);
return;
}
sprintf(temp, "%s/%s", getElementText(input_graphics), "items.png");
sprintf(temp_2, "loading %s", temp);
printConsole(temp_2);
ret = loadSpritesheetFromFile(&item_sprites, temp, 16, 32, 16);
if (ret != 0) {
sprintf(temp_2, "error(%d) loading %s", ret, temp);
printConsole(temp_2);
return;
}
sprintf(temp, "%s/%s", getElementText(input_graphics), "equips.png");
sprintf(temp_2, "loading %s", temp);
printConsole(temp_2);
ret = loadSpritesheetFromFile(&equip_sprites, temp, 16, 32, 16);
if (ret != 0) {
sprintf(temp_2, "error(%d) loading %s", ret, temp);
printConsole(temp_2);
return;
}
sprintf(temp, "%s/%s", getElementText(input_graphics), "doors.png");
sprintf(temp_2, "loading %s", temp);
printConsole(temp_2);
ret = loadSpritesheetFromFile(&door_sprites, temp, 16, 32, 16);
if (ret != 0) {
sprintf(temp_2, "error(%d) loading %s", ret, temp);
printConsole(temp_2);
return;
}
sprintf(temp, "%s/%s", getElementText(input_graphics), "npcs.png");
sprintf(temp_2, "loading %s", temp);
printConsole(temp_2);
ret = loadSpritesheetFromFile(&npc_sprites, temp, 16, 32, 16);
if (ret != 0) {
sprintf(temp_2, "error(%d) loading %s", ret, temp);
printConsole(temp_2);
return;
}
sprintf(temp, "%s/%s", getElementText(input_graphics), "floors.png");
sprintf(temp_2, "loading %s", temp);
printConsole(temp_2);
ret = loadSpritesheetFromFile(&floor_sprites, temp, 16, 32, 16);
if (ret != 0) {
sprintf(temp_2, "error(%d) loading %s", ret, temp);
printConsole(temp_2);
return;
}
sprintf(temp, "%s/%s", getElementText(input_graphics), "walls.png");
sprintf(temp_2, "loading %s", temp);
printConsole(temp_2);
ret = loadSpritesheetFromFile(&wall_sprites, temp, 16, 32, 16);
if (ret != 0) {
sprintf(temp_2, "error(%d) loading %s", ret, temp);
printConsole(temp_2);
return;
}
sprintf(temp_2, "OK, graphics loaded successfully");
g_gfx = 1;
printConsole(temp_2);
reloadImagePreview();
showSpritesheet();
}
void loadDataCallback() {
printConsole("loading data");
char *buffer = NULL;
char temp[128];
int size = fileToMemory(&buffer, getElementText(input_data));
if (size > 0) {
if (tiles_data != NULL) {
freeData(tiles_data);
tiles_data = loadDataFromMemory(buffer, size);
} else {
tiles_data = loadDataFromMemory(buffer, size);
}
sprintf(temp, "loaded %d tile sets!\n", tiles_data->set_count);
//g_data = 1;
} else {
sprintf(temp, "ERR, could not load %s", getElementText(input_data));
}
printConsole(temp);
if (buffer != NULL) {
loadTile(g_set, g_id);
free(buffer);
}
}
void saveDataCallback() {
char temp[256];
sprintf(temp, "saving data to %s", getElementText(input_data));
printConsole(temp);
int return_value;
if ((return_value = saveDataToFile(tiles_data, getElementText(input_data))) > 0) {
sprintf(temp, "OK(%d), data saved to %s!", return_value, getElementText(input_data));
} else {
sprintf(temp, "ERR(%d), could not save to %s", return_value, getElementText(input_data));
}
printConsole(temp);
}
void loadTile(int set, int id) {
char temp[128];
if (g_data != 1) {
return;
}
/* delete old elements */
SDL_FillRect(tile_area, NULL, SDL_MapRGB(tile_area->format, 8, 16, 24));
deleteElementsFromList(editor_elements);
if (set < 0) {
sprintf(temp, "ERR, set(%d) must be non-negative!", set);
printConsole(temp);
return;
}
if (id < 0) {
sprintf(temp, "ERR, id(%d) must be non-negative!", id);
printConsole(temp);
return;
}
button_add_pair = newElement(TYPE_BUTTON);
setElementText(button_add_pair, "add pair");
setElementPosition(button_add_pair, 2, 2);
setElementCallback(button_add_pair, &addPairCallback);
addElementToList(editor_elements, button_add_pair);
button_add_inventory = newElement(TYPE_BUTTON);
setElementText(button_add_inventory, "add inventory");
setElementCallback(button_add_inventory, &addInventoryCallback);
setElementPosition(button_add_inventory, 4+getElementWidth(button_add_pair), 2);
addElementToList(editor_elements, button_add_inventory);
button_commit = newElement(TYPE_BUTTON);
setElementText(button_commit, "commit changes");
setElementCallback(button_commit, &commitChangesCallback);
setElementPosition(button_commit, tile_area->w - getElementWidth(button_commit) - 2, 2);
addElementToList(editor_elements, button_commit);
drawElement(button_add_inventory);
drawElement(button_add_pair);
drawElement(button_commit);
struct TileData *tile = getTileDataById(tiles_data, set, id);
if (tile == NULL) {
sprintf(temp, "tile %d:%d does not exist(yet!)\n", set, id);
printConsole(temp);
return;
}
sprintf(temp, "loaded %d:%d(%s)\n", set, id, (char*)getTablePairValue(tile->table, "name"));
int i;
int j = 0;
for(i = 0;i < tile->table->size;i++) {
struct TablePair *table_pair = tile->table->pair[i];
while(table_pair != NULL) {
struct InventoryData *inv;
struct Element *extra_element;
struct Element *delete_element;
delete_element = newElement(TYPE_BUTTON);
setElementText(delete_element, "x");
setElementCallback(delete_element, &deleteElementCallback);
setElementId(delete_element, ID_DELETE);
addElementToList(editor_elements, delete_element);
struct Element *value_element;
struct Element *key_element = newElement(TYPE_TEXT_INPUT); // @@ memory leak here
setElementSize(key_element, 16);
setElementText(key_element, table_pair->key);
setElementId(key_element, ID_KEY);
addElementToList(editor_elements, key_element);
setElementParent(delete_element, key_element);
addElementChild(key_element, delete_element);
switch(table_pair->type) {
case T_STRING:
value_element = newElement(TYPE_TEXT_INPUT); // and here
addElementChild(key_element, value_element);
setElementParent(value_element, key_element);
setElementSize(value_element, 30);
setElementText(value_element, table_pair->value);
setElementCallback(value_element, &changeValueCallback);
setElementId(value_element, ID_VALUE);
addElementToList(editor_elements, value_element);
break;
case T_INT:
value_element = newElement(TYPE_TEXT_INPUT); // and here
addElementChild(key_element, value_element);
setElementParent(value_element, key_element);
setElementSize(value_element, 30);
setElementValue(value_element, (*(int*)table_pair->value));
setElementCallback(value_element, &changeValueCallback);
setElementId(value_element, ID_VALUE);
addElementToList(editor_elements, value_element);
break;
case T_PROTO_INVENTORY:
setElementGid(key_element, GID_INVENTORY);
setElementGid(delete_element, GID_INVENTORY);
extra_element = newElement(TYPE_BUTTON);
setElementText(extra_element, "add");
addElementToList(editor_elements, extra_element);
setElementId(extra_element, ID_INV_ADD);
setElementGid(extra_element, GID_INVENTORY);
setElementCallback(extra_element, &addInventoryElementCallback);
addElementChild(key_element, extra_element);
setElementParent(extra_element, key_element);
inv = table_pair->value;
while (inv != NULL) {
j++;
// delete element button
delete_element = newElement(TYPE_BUTTON);
setElementText(delete_element, "x");
addElementToList(editor_elements, delete_element);
addElementChild(key_element, delete_element);
setElementParent(delete_element, key_element);
setElementCallback(delete_element, &deleteInventoryElementCallback);
setElementId(delete_element, ID_ITEM_DEL);
setElementGid(delete_element, GID_INVENTORY);
// name key
extra_element = newElement(TYPE_TEXT);
setElementSize(extra_element, 10);
setElementText(extra_element, "name");
addElementChild(key_element, extra_element);
addElementToList(editor_elements, extra_element);
setElementId(extra_element, ID_ITEM_NAME);
setElementGid(extra_element, GID_INVENTORY);
// name value
value_element = newElement(TYPE_TEXT_INPUT);
addElementChild(key_element, value_element);
setElementParent(value_element, key_element);
addElementChild(key_element, value_element);
setElementSize(value_element, 30);
setElementText(value_element, inv->name);
setElementCallback(value_element, &changeValueCallback);
addElementToList(editor_elements, value_element);
setElementId(value_element, ID_ITEM_NAME_VAL);
setElementGid(value_element, GID_INVENTORY);
j++;
// count min key
struct Element *count_min_key_element = newElement(TYPE_TEXT);
setElementSize(count_min_key_element, 4);
setElementText(count_min_key_element, "min");
addElementChild(key_element, count_min_key_element);
addElementToList(editor_elements, count_min_key_element);
setElementId(count_min_key_element, ID_ITEM_MIN);
setElementGid(count_min_key_element, GID_INVENTORY);
// count min count_min_value
struct Element *count_min_value_element = newElement(TYPE_SPINNER);
addElementChild(key_element, count_min_value_element);
setElementParent(count_min_value_element, key_element);
setElementSize(count_min_value_element, 4);
setElementValue(count_min_value_element, inv->count.min);
addElementToList(editor_elements, count_min_value_element);
setElementId(count_min_value_element, ID_ITEM_MIN_VAL);
setElementGid(count_min_value_element, GID_INVENTORY);
// count max key
struct Element *count_max_key_element = newElement(TYPE_TEXT);
setElementSize(count_max_key_element, 4);
setElementText(count_max_key_element, "max");
addElementChild(key_element, count_max_key_element);
addElementToList(editor_elements, count_max_key_element);
setElementId(count_max_key_element, ID_ITEM_MAX);
setElementGid(count_max_key_element, GID_INVENTORY);
// count max count_max_value
struct Element *count_max_value_element = newElement(TYPE_SPINNER);
addElementChild(key_element, count_max_value_element);
setElementParent(count_max_value_element, key_element);
setElementSize(count_max_value_element, 4);
setElementValue(count_max_value_element, inv->count.max);
addElementToList(editor_elements, count_max_value_element);
setElementId(count_max_value_element, ID_ITEM_MAX_VAL);
setElementGid(count_max_value_element, GID_INVENTORY);
// count max key
struct Element *chance_key_element = newElement(TYPE_TEXT);
setElementSize(chance_key_element, 7);
setElementText(chance_key_element, "chance");
addElementChild(key_element, chance_key_element);
addElementToList(editor_elements, chance_key_element);
setElementId(chance_key_element, ID_ITEM_CHANCE);
setElementGid(chance_key_element, GID_INVENTORY);
// count max chance_value
struct Element *chance_value_element = newElement(TYPE_SPINNER);
addElementChild(key_element, chance_value_element);
setElementParent(chance_value_element, key_element);
setElementSize(chance_value_element, 4);
setElementValue(chance_value_element, inv->chance);
addElementToList(editor_elements, chance_value_element);
setElementId(chance_value_element, ID_ITEM_CHANCE_VAL);
setElementGid(chance_value_element, GID_INVENTORY);
inv = inv->next;
}
break;
default:
break;
}
setElementCallback(key_element, &changeKeyCallback);
table_pair = table_pair->next;
j++;
}
}
positionElements();
drawElements();
printConsole(temp);
}
void addPairCallback(struct Element *element) {
struct Element *delete_element = newElement(TYPE_BUTTON);
setElementText(delete_element, "x");
setElementCallback(delete_element, &deleteElementCallback);
setElementId(delete_element, ID_DELETE);
addElementToList(editor_elements, delete_element);
struct Element *key_element = newElement(TYPE_TEXT_INPUT);
setElementSize(key_element, 16);
setElementText(key_element, "");
setElementId(key_element, ID_KEY);
setElementParent(delete_element, key_element);
addElementChild(key_element, delete_element);
addElementToList(editor_elements, key_element);
struct Element *value_element = newElement(TYPE_TEXT_INPUT);
setElementSize(value_element, 30);
setElementText(value_element, "");
setElementCallback(value_element, &changeValueCallback);
setElementId(value_element, ID_VALUE);
setElementParent(value_element, key_element);
addElementChild(key_element, value_element);
addElementToList(editor_elements, value_element);
SDL_FillRect(tile_area, NULL, SDL_MapRGB(tile_area->format, 8, 16, 24));
positionElements();
drawElements();
}
void addInventoryCallback(struct Element *element) {
struct Element *delete_element = newElement(TYPE_BUTTON);
setElementText(delete_element, "x");
setElementCallback(delete_element, &deleteElementCallback);
setElementId(delete_element, ID_DELETE);
addElementToList(editor_elements, delete_element);
struct Element *key_element = newElement(TYPE_TEXT_INPUT);
setElementSize(key_element, 16);
setElementText(key_element, "");
setElementId(key_element, ID_KEY);
setElementParent(delete_element, key_element);
addElementChild(key_element, delete_element);
addElementToList(editor_elements, key_element);
struct Element *extra_element = newElement(TYPE_BUTTON);
setElementText(extra_element, "add");
addElementToList(editor_elements, extra_element);
setElementId(extra_element, ID_INV_ADD);
setElementParent(extra_element, key_element);
setElementCallback(extra_element, &addInventoryElementCallback);
setElementGid(extra_element, GID_INVENTORY);
addElementChild(key_element, extra_element);
// delete element button
delete_element = newElement(TYPE_BUTTON);
setElementText(delete_element, "x");
addElementToList(editor_elements, delete_element);
addElementChild(key_element, delete_element);
setElementParent(delete_element, key_element);
setElementCallback(delete_element, &deleteInventoryElementCallback);
setElementId(delete_element, ID_ITEM_DEL);
setElementGid(delete_element, GID_INVENTORY);
// name key
extra_element = newElement(TYPE_TEXT);
setElementSize(extra_element, 10);
setElementText(extra_element, "name");
addElementChild(key_element, extra_element);
addElementToList(editor_elements, extra_element);
setElementId(extra_element, ID_ITEM_NAME);
setElementGid(extra_element, GID_INVENTORY);
// name value
struct Element *value_element = newElement(TYPE_TEXT_INPUT);
addElementChild(key_element, value_element);
setElementParent(value_element, key_element);
addElementChild(key_element, value_element);
setElementSize(value_element, 30);
setElementText(value_element, "");
setElementCallback(value_element, &changeValueCallback);
addElementToList(editor_elements, value_element);
setElementId(value_element, ID_ITEM_NAME_VAL);
setElementGid(value_element, GID_INVENTORY);
// count min key
struct Element *count_min_key_element = newElement(TYPE_TEXT);
setElementSize(count_min_key_element, 4);
setElementText(count_min_key_element, "min");
addElementChild(key_element, count_min_key_element);
addElementToList(editor_elements, count_min_key_element);
setElementId(count_min_key_element, ID_ITEM_MIN);
setElementGid(count_min_key_element, GID_INVENTORY);
// count min count_min_value
struct Element *count_min_value_element = newElement(TYPE_SPINNER);
addElementChild(key_element, count_min_value_element);
setElementParent(count_min_value_element, key_element);
setElementSize(count_min_value_element, 4);
setElementValue(count_min_value_element, 1);
addElementToList(editor_elements, count_min_value_element);
setElementId(count_min_value_element, ID_ITEM_MIN_VAL);
setElementGid(count_min_value_element, GID_INVENTORY);
// count max key
struct Element *count_max_key_element = newElement(TYPE_TEXT);
setElementSize(count_max_key_element, 4);
setElementText(count_max_key_element, "max");
addElementChild(key_element, count_max_key_element);
addElementToList(editor_elements, count_max_key_element);
setElementId(count_max_key_element, ID_ITEM_MAX);
setElementGid(count_max_key_element, GID_INVENTORY);
// count max count_max_value
struct Element *count_max_value_element = newElement(TYPE_SPINNER);
addElementChild(key_element, count_max_value_element);
setElementParent(count_max_value_element, key_element);
setElementSize(count_max_value_element, 4);
setElementValue(count_max_value_element, 1);
addElementToList(editor_elements, count_max_value_element);
setElementId(count_max_value_element, ID_ITEM_MAX_VAL);
setElementGid(count_max_value_element, GID_INVENTORY);
// count max key
struct Element *chance_key_element = newElement(TYPE_TEXT);
setElementSize(chance_key_element, 7);
setElementText(chance_key_element, "chance");
addElementChild(key_element, chance_key_element);
addElementToList(editor_elements, chance_key_element);
setElementId(chance_key_element, ID_ITEM_CHANCE);
setElementGid(chance_key_element, GID_INVENTORY);
// count max chance_value
struct Element *chance_value_element = newElement(TYPE_SPINNER);
addElementChild(key_element, chance_value_element);
setElementParent(chance_value_element, key_element);
setElementSize(chance_value_element, 4);
setElementValue(chance_value_element, 100);
addElementToList(editor_elements, chance_value_element);
setElementId(chance_value_element, ID_ITEM_CHANCE_VAL);
setElementGid(chance_value_element, GID_INVENTORY);
positionElements();
drawElements();
}
void addInventoryElementCallback(struct Element *element) {
struct Element *current = element;
struct Element *previous = NULL;
struct Element *next = current->next;
while (current != NULL) {
next = current->next;
if (current->id == ID_DELETE) {
break;
}
previous = current;
current = next;
}
struct Element *key_element = element->parent; // parent of add item is always the root key (inventory name)
// delete element button
struct Element *delete_element = newElement(TYPE_BUTTON);
setElementText(delete_element, "x");
addElementChild(key_element, delete_element);
setElementParent(delete_element, key_element);
setElementCallback(delete_element, &deleteInventoryElementCallback);
setElementId(delete_element, ID_ITEM_DEL);
setElementGid(delete_element, GID_INVENTORY);
addElementHook(editor_elements, delete_element); // call hook manually
previous->next = delete_element;
// name key
struct Element *extra_element = newElement(TYPE_TEXT);
setElementSize(extra_element, 10);
setElementText(extra_element, "name");
addElementChild(key_element, extra_element);
setElementId(extra_element, ID_ITEM_NAME);
setElementGid(extra_element, GID_INVENTORY);
addElementHook(editor_elements, extra_element); // call hook manually
delete_element->next = extra_element;
// name value
struct Element *value_element = newElement(TYPE_TEXT_INPUT);
addElementChild(key_element, value_element);
setElementParent(value_element, key_element);
addElementChild(key_element, value_element);
setElementSize(value_element, 30);
setElementText(value_element, "");
setElementCallback(value_element, &changeValueCallback);
setElementId(value_element, ID_ITEM_NAME_VAL);
setElementGid(value_element, GID_INVENTORY);
addElementHook(editor_elements, value_element); // call hook manually
extra_element->next = value_element;
// count min key
struct Element *count_min_key_element = newElement(TYPE_TEXT);
setElementSize(count_min_key_element, 4);
setElementText(count_min_key_element, "min");
addElementChild(key_element, count_min_key_element);
setElementId(count_min_key_element, ID_ITEM_MIN);
setElementGid(count_min_key_element, GID_INVENTORY);
addElementHook(editor_elements, count_min_key_element); // call hook manually
value_element->next = count_min_key_element;
// count min count_min_value
struct Element *count_min_value_element = newElement(TYPE_SPINNER);
addElementChild(key_element, count_min_value_element);
setElementParent(count_min_value_element, key_element);
setElementSize(count_min_value_element, 4);
setElementValue(count_min_value_element, 1);
setElementId(count_min_value_element, ID_ITEM_MIN_VAL);
setElementGid(count_min_value_element, GID_INVENTORY);
addElementHook(editor_elements, count_min_value_element); // call hook manually
count_min_key_element->next = count_min_value_element;
// count max key
struct Element *count_max_key_element = newElement(TYPE_TEXT);
setElementSize(count_max_key_element, 4);
setElementText(count_max_key_element, "max");
addElementChild(key_element, count_max_key_element);
setElementId(count_max_key_element, ID_ITEM_MAX);
setElementGid(count_max_key_element, GID_INVENTORY);
addElementHook(editor_elements, count_max_key_element); // call hook manually
count_min_value_element->next = count_max_key_element;
// count max count_max_value
struct Element *count_max_value_element = newElement(TYPE_SPINNER);
addElementChild(key_element, count_max_value_element);
setElementParent(count_max_value_element, key_element);
setElementSize(count_max_value_element, 4);
setElementValue(count_max_value_element, 1);
setElementId(count_max_value_element, ID_ITEM_MAX_VAL);
setElementGid(count_max_value_element, GID_INVENTORY);
addElementHook(editor_elements, count_max_value_element); // call hook manually
count_max_key_element->next = count_max_value_element;
// count max key
struct Element *chance_key_element = newElement(TYPE_TEXT);
setElementSize(chance_key_element, 7);
setElementText(chance_key_element, "chance");
addElementChild(key_element, chance_key_element);
setElementId(chance_key_element, ID_ITEM_CHANCE);
setElementGid(chance_key_element, GID_INVENTORY);
addElementHook(editor_elements, chance_key_element); // call hook manually
count_max_value_element->next = chance_key_element;
// count max chance_value
struct Element *chance_value_element = newElement(TYPE_SPINNER);
addElementChild(key_element, chance_value_element);
setElementParent(chance_value_element, key_element);
setElementSize(chance_value_element, 4);
setElementValue(chance_value_element, 100);
setElementId(chance_value_element, ID_ITEM_CHANCE_VAL);
setElementGid(chance_value_element, GID_INVENTORY);
addElementHook(editor_elements, chance_value_element); // call hook manually
chance_key_element->next = chance_value_element;
chance_value_element->next = current;
if (current == NULL) {
editor_elements->last = chance_value_element;
}
positionElements();
SDL_FillRect(tile_area, NULL, SDL_MapRGB(tile_area->format, 8, 16, 24));
drawElements();
}
void deleteInventoryElementCallback(struct Element *element) {
struct Element *current = element;
while (current != NULL) {
struct Element *next = current->next;
if (current->id == ID_ITEM_DEL) { // reached ourself or next inventory item
if (current != element) { // if next, bail out
break;
} else { // otherwise, delete self
removeElementFromList(editor_elements, current);
freeElement(current);
}
} else if (current->id == ID_DELETE) { // reached next key=>value pair
break;
} else { // reached element that is part of this inventory item
removeElementFromList(editor_elements, current);
freeElement(current);
}
current = next;
}
last_element = NULL;
focus_element = NULL;
positionElements();
SDL_FillRect(tile_area, NULL, SDL_MapRGB(tile_area->format, 8, 16, 24));
drawElements();
}
void deleteElementCallback(struct Element *element) {
struct Element *current = element;
while (current != NULL) {
struct Element *next = current->next;
if (current->id == ID_DELETE) {
if (current != element) { // if it is not this element, it is next pair
break;
} else { // otherwise, delete self
removeElementFromList(editor_elements, current);
freeElement(current);
}
} else {
removeElementFromList(editor_elements, current);
freeElement(current);
}
current = next;
}
last_element = NULL;
focus_element = NULL;
positionElements();
SDL_FillRect(tile_area, NULL, SDL_MapRGB(tile_area->format, 8, 16, 24));
drawElements();
}
void commitChangesCallback(struct Element *element) {
struct Element *current = element->next;
const char *current_key;
const char *current_value;
int min_count = 0;
int max_count = 0;
int chance = 0;
/* completely delete old TileData */
struct TileData *tile = getTileDataById(tiles_data, g_set, g_id);
if (tile != NULL) {
freeTileData(tile);
tiles_data->set[g_set]->tile[g_id] = NULL;
}
/* create new TileData for commit rewrite */
tile = newTileData(8);
tile->id = g_id;
tiles_data->set[g_set]->tile[g_id] = tile;
while (current != NULL) {
switch(current->id) {
case ID_DELETE:
break;
case ID_KEY:
current_key = getElementText(current);
break;
case ID_VALUE:
current_value = getElementText(current);
addTablePair(tile->table, current_key, (void*)current_value, strlen(current_value)+1, T_STRING);
break;
case ID_ITEM_NAME_VAL:
current_value = getElementText(current);
break;
case ID_ITEM_MIN_VAL:
min_count = getElementValue(current);
break;
case ID_ITEM_MAX_VAL:
max_count = getElementValue(current);
break;
case ID_ITEM_CHANCE_VAL:
chance = getElementValue(current);
struct TablePair *pair = getTablePair(tile->table, current_key);
if (pair != NULL) {
// inventory exists, walk down the chain and append new InventoryData
if (pair->type == T_PROTO_INVENTORY) {
struct InventoryData *inv = pair->value;
while (inv->next != NULL) {
inv = inv->next;
}
struct InventoryData *inventory = newInventoryData();
inventory->count.min = min_count;
inventory->count.max = max_count;
inventory->chance = chance;
setInventoryDataName(inventory, current_value);
inv->next = inventory;
}
} else {
// inventory does not exist, create it
struct InventoryData *inventory = newInventoryData();
inventory->count.min = min_count;
inventory->count.max = max_count;
inventory->chance = chance;
setInventoryDataName(inventory, current_value);
addTablePairPointer(tile->table, current_key, inventory, T_PROTO_INVENTORY);
}
break;
default:
break;
}
current = current->next;
}
// table has no key=>value pairs, thus meaning there are no elements - free & remove it!
if (tile->table->count <= 0) {
freeTileData(tile);
tiles_data->set[g_set]->tile[g_id] = NULL;
}
char temp[128];
sprintf(temp, "Changes committed for %d:%d", g_set, g_id);
printConsole(temp);
}
void changeKeyCallback() {
printf("changing key\n");
}
void changeValueCallback() {
printf("changing value\n");
}
void setSetCallback() {
g_set = atoi(getElementText(input_set));
if (g_gfx == 1) {
reloadImagePreview();
showSpritesheet();
}
if (g_data == 1) {
loadTile(g_set, g_id);
}
}
void setIdCallback() {
g_id = atoi(getElementText(input_id));
if (g_gfx == 1) {
reloadImagePreview();
showSpritesheet(); // TODO: just reload the area on the sheet surface that has changed
}
if (g_data == 1) {
loadTile(g_set, g_id);
}
}
void showSpritesheet() {
if (g_gfx != 1)
return;
struct Spritesheet *spritesheet;
switch (g_set) {
case PLAYER:
spritesheet = &player_sprites;
break;
case FLOOR:
spritesheet = &floor_sprites;
break;
case WALL:
spritesheet = &wall_sprites;
break;
case DOOR:
spritesheet = &door_sprites;
break;
case ITEM:
spritesheet = &item_sprites;
break;
case EQUIP:
spritesheet = &equip_sprites;
break;
case NPC:
spritesheet = &npc_sprites;
break;
default:
return;
break;
}
screen = SDL_SetVideoMode(g_width+spritesheet->spritesheet->w, g_height, 32, SDL_SWSURFACE|SDL_DOUBLEBUF);
int rows = spritesheet->spritesheet->h / spritesheet->height;
int i, j = 0;
Uint32 color_a = SDL_MapRGB(screen->format, 95, 95, 128);
Uint32 color_b = SDL_MapRGB(screen->format, 128, 128, 95);
for (i = 0;i < spritesheet->columns;i++) {
for (j = 0;j < rows;j++) {
SDL_Rect sprite_rect = { i*spritesheet->width, j*spritesheet->height, spritesheet->width, spritesheet->height};
SDL_FillRect(sprite_area, &sprite_rect, (((j+i) & 1) == 1 ? color_a : color_b));
}
}
// draw different bg for current id
int y_offset = g_id / spritesheet->columns;
int x_offset = g_id - (y_offset * spritesheet->columns);
SDL_Rect sprite_rect = { x_offset*spritesheet->width, y_offset*spritesheet->height, spritesheet->width, spritesheet->height};
SDL_FillRect(sprite_area, &sprite_rect, SDL_MapRGB(screen->format, 196, 196, 95));
//SDL_FillRect(sprite_area, &spritesheet_rect, SDL_MapRGB(screen->format, 95, 95, 128));
SDL_BlitSurface(spritesheet->spritesheet, NULL, sprite_area, NULL);
SDL_BlitSurface(sprite_area, NULL, screen, &sprite_area_rect);
}
void reloadImagePreview() {
struct Spritesheet *spritesheet;
switch (g_set) {
case PLAYER:
spritesheet = &player_sprites;
break;
case FLOOR:
spritesheet = &floor_sprites;
break;
case WALL:
spritesheet = &wall_sprites;
break;
case DOOR:
spritesheet = &door_sprites;
break;
case ITEM:
spritesheet = &item_sprites;
break;
case EQUIP:
spritesheet = &equip_sprites;
break;
case NPC:
spritesheet = &npc_sprites;
break;
default:
return;
break;
}
/* now load small preview of tile */
int y_offset = g_id / spritesheet->columns;
int x_offset = g_id - (y_offset * spritesheet->columns);
SDL_Rect sprite_offset = { x_offset*spritesheet->width, y_offset*spritesheet->height, spritesheet->width, spritesheet->height};
SDL_Rect render_position = {0, 0, spritesheet->width, spritesheet->height};
SDL_FillRect(((struct ImageElement *)image_tile->data)->image, NULL, SDL_MapRGB(menu_area->format, 96, 96, 128));
SDL_BlitSurface(spritesheet->spritesheet, &sprite_offset, ((struct ImageElement*)image_tile->data)->image, &render_position);
drawElement(image_tile);
}
void printConsole(const char *string) {
clearElement(text_console);
setElementText(text_console, string);
drawElement(text_console);
}
/* font stuff */
void loadFont(struct Font *font, unsigned char *memory, unsigned int length, int width, int height) {
font->width = width;
font->height = height;
font->surface = IMG_Load_RW(SDL_RWFromMem(memory, length), 1);
}
void freeFont(struct Font *font) {
SDL_FreeSurface(font->surface);
}
/* spritesheet stuff */
int loadSpritesheetFromFile(struct Spritesheet *spritesheet, char *file_name, int width, int height, int columns) {
spritesheet->width = width;
spritesheet->height = height;
spritesheet->columns = columns;
spritesheet->spritesheet = IMG_Load(file_name);
if (spritesheet->spritesheet == NULL)
return -1;
spritesheet->scale_x = 1.0f;
spritesheet->scale_y = 1.0f;
spritesheet->s_spritesheet = SDL_ScaleSurface(spritesheet->spritesheet, 1.0f, 1.0f);
spritesheet->s_width = width;
spritesheet->s_height = height;
return 0;
}
void freeSpritesheet(struct Spritesheet *spritesheet) {
SDL_FreeSurface(spritesheet->s_spritesheet);
SDL_FreeSurface(spritesheet->spritesheet);
}
/* sdl helper stuff */
SDL_Surface *SDL_ScaleSurface(SDL_Surface *surface, float scale_x, float scale_y) {
long x;
long y;
long output_x;
long output_y;
long new_width = (long)((float)surface->w * scale_x+0.5f);
long new_height = (long)((float)surface->h * scale_y+0.5f);
SDL_Surface *new_surface = SDL_CreateRGBSurface(surface->flags, new_width, new_height, surface->format->BitsPerPixel, surface->format->Rmask, surface->format->Gmask, surface->format->Bmask, surface->format->Amask);
for (y = 0;y < surface->h;y++) {
for (x = 0;x < surface->w;x++) {
for (output_y = 0;output_y < scale_y; ++output_y) {
for (output_x = 0;output_x < scale_x; ++output_x) {
putpixel(new_surface, (Sint32)(scale_x*x) + output_x, (Sint32)(scale_y*y)+output_y, getpixel(surface, x, y));
}
}
}
}
return new_surface;
}
Uint32 getpixel(SDL_Surface *surface, int x, int y) {
if (y >= 0 && x >= 0 && x <= surface->w && y <= surface->h) {
int bpp = surface->format->BytesPerPixel;
/* Here p is the address to the pixel we want to retrieve */
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
switch(bpp) {
case 1:
return *p;
break;
case 2:
return *(Uint16 *)p;
break;
case 3:
if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
return p[0] << 16 | p[1] << 8 | p[2];
else
return p[0] | p[1] << 8 | p[2] << 16;
break;
case 4:
return *(Uint32 *)p;
break;
default:
return 0; /* shouldn't happen, but avoids warnings */
}
}
return 0;
}
void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel) {
if (y >= 0 && x >= 0 && x <= surface->w && y <= surface->h) {
int bpp = surface->format->BytesPerPixel;
/* Here p is the address to the pixel we want to set */
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
switch(bpp) {
case 1:
*p = pixel;
break;
case 2:
*(Uint16 *)p = pixel;
break;
case 3:
if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
p[0] = (pixel >> 16) & 0xff;
p[1] = (pixel >> 8) & 0xff;
p[2] = pixel & 0xff;
} else {
p[0] = pixel & 0xff;
p[1] = (pixel >> 8) & 0xff;
p[2] = (pixel >> 16) & 0xff;
}
break;
case 4:
*(Uint32 *)p = pixel;
break;
}
}
}