#include #if !defined (__APPLE__) #include #else #include #include "CoreFoundation/CoreFoundation.h" // yee apple path rubbish #endif #include // for wm hints #include // 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; } } }