Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

added simplistic gui (so far windows only)

  • Loading branch information...
commit ec226e59b898ee56624b33cb852fa2826299d7bf 1 parent dc43a5b
@stg authored
View
3  .gitignore
@@ -1,4 +1,5 @@
private/
bin-win/sdl.dll
bin-win/gui_sdl12.exe
-thumbs.db
+thumbs.db
+/ui.bmp
View
BIN  bin-win/FreeImage.dll
Binary file not shown
View
BIN  bin-win/SDL2.dll
Binary file not shown
View
BIN  bin-win/gui.exe
Binary file not shown
View
BIN  bin-win/ui.bmp
Binary file not shown
View
57 gui/loader.c
@@ -0,0 +1,57 @@
+#ifdef SDL2
+#include <stdint.h>
+#include <stdbool.h>
+#include <FreeImage/FreeImage.h>
+#include "loader.h"
+
+static FIBITMAP *dib=NULL;
+static uint16_t w,h;
+
+bool image_loadpicture(const char* filename) {
+ FREE_IMAGE_FORMAT fif=FIF_UNKNOWN;
+ int flag=0;
+ fif=FreeImage_GetFileType(filename,0);
+ if(fif==FIF_UNKNOWN) {
+ fif=FreeImage_GetFIFFromFilename(filename);
+ }
+ if((fif!=FIF_UNKNOWN)&&FreeImage_FIFSupportsReading(fif)) {
+ dib=FreeImage_Load(fif,filename,flag);
+ if(dib) {
+ w=FreeImage_GetWidth(dib);
+ h=FreeImage_GetHeight(dib);
+ if(w>4000||h>4000) {
+ FreeImage_Unload(dib);
+ dib=NULL;
+ } else {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+uint16_t image_width() {
+ return w;
+}
+
+uint16_t image_height() {
+ return h;
+}
+
+void image_convert(uint8_t *p_data) {
+ uint16_t x,y;
+ RGBQUAD quad;
+ for(y=0;y<h;y++) {
+ for(x=0;x<w;x++) {
+ FreeImage_GetPixelColor(dib,x,y,&quad);
+ p_data[y*w+x]=(quad.rgbRed+quad.rgbGreen+quad.rgbBlue)/3;
+ }
+ }
+}
+
+void image_free() {
+ if(dib) FreeImage_Unload(dib);
+ dib=NULL;
+}
+
+#endif
View
9 gui/loader.h
@@ -0,0 +1,9 @@
+#ifdef SDL2
+#include <stdint.h>
+#include <stdbool.h>
+bool image_load(const char* filename,int flag);
+uint16_t image_width();
+uint16_t image_height();
+void image_convert(uint8_t *p_data);
+void image_free();
+#endif
View
569 gui/main.c
@@ -0,0 +1,569 @@
+#include <stdint.h>
+#include <stdbool.h>
+#ifdef SDL2
+#include <SDL2/SDL.h>
+#else
+#include <SDL/SDL.h>
+#endif
+#include "renderer.h"
+#include "ui.h"
+#include "machine.h"
+#include "emulate.h"
+#include "loader.h"
+
+// screen surface
+#ifdef SDL2
+static SDL_Window* window;
+static SDL_Renderer* renderer;
+#endif
+static SDL_Surface *screen;
+
+// ui enums
+enum {
+ VIEW_TOP,
+ VIEW_MACH,
+ VIEW_ADD,
+ VIEW_EMU,
+ VIEW_MSG
+};
+
+enum {
+ TOP_LIST,
+ TOP_NEW,
+ TOP_ADD,
+ TOP_EDIT,
+ TOP_DEL,
+ TOP_EMU,
+ TOP_OUT,
+ TOP_INFO,
+ TOP_COUNT
+};
+
+enum {
+ MACH_LIST,
+ MACH_OK,
+ MACH_CANCEL,
+ MACH_COUNT
+};
+
+enum {
+ ADD_W,
+ ADD_H,
+ ADD_OK,
+ ADD_CANCEL,
+ ADD_COUNT
+};
+
+enum {
+ EMU_LIST,
+ EMU_OK,
+ EMU_CANCEL,
+ EMU_COUNT
+};
+
+enum {
+ MSG_TEXT,
+ MSG_OK,
+ MSG_COUNT
+};
+
+// ui views
+static view_t *vtop,*vmach,*vadd,*vemu,*vmsg;
+static uiobj_t *top[TOP_COUNT],*mach[MACH_COUNT],*add[ADD_COUNT],*emu[EMU_COUNT],*msg[MSG_COUNT];
+
+// currently selected view
+static uint8_t view=VIEW_TOP;
+
+// in emulate mode
+static bool emulating=false;
+
+// time to quit?
+static bool quit=false;
+
+// currently selected machine
+static machine_t *p_mach;
+
+#ifdef SDL2
+// dropping files
+static uint16_t stat_add=0,stat_size=0,stat_format=0;
+#endif
+
+// sets names of all items in pattern list
+static void list_fill() {
+ listitem_t *p_item;
+ uint16_t w,h,ix=0;
+ p_item=((list_t*)top[TOP_LIST]->obj)->list;
+ while(p_item) {
+ w=((uint16_t*)p_item->data)[0];
+ h=((uint16_t*)p_item->data)[1];
+ sprintf(p_item->text,"%i IS %iX%i",p_mach->pattern_min+ix++,w,h);
+ p_item=p_item->next;
+ }
+ ui_enable(top[TOP_EMU],((list_t*)top[TOP_LIST]->obj)->count>0);
+}
+
+// build disk image under current machine
+static bool build_image() {
+ char text[60];
+ uint16_t w,h;
+ uint16_t ptn;
+ listitem_t *p_item;
+ p_item=((list_t*)top[TOP_LIST]->obj)->list;
+
+ p_mach->format();
+ p_mach->set_track(0);
+
+ ptn=p_mach->pattern_min;
+ while(p_item) {
+ w=((uint16_t*)p_item->data)[0];
+ h=((uint16_t*)p_item->data)[1];
+ if(!p_mach->add_pattern(&((uint8_t*)p_item->data)[4],w,h)) {
+ sprintf(text,"OUT OF MEMORY WHEN ADDING \nPATTERN %i. REMOVE SOME\nPATTERNS AND TRY AGAIN.",ptn);
+ ui_field_add(msg[MSG_TEXT],text);
+ return false;
+ }
+ ptn++;
+ p_item=p_item->next;
+ }
+
+ return true;
+}
+
+// event handler for top view
+static bool top_event(SDL_Event *event) {
+ uiobj_t *p_ui;
+ p_ui=event->user.data1;
+ listitem_t *p_item;
+ char text[200];
+ switch( event->type ) {
+#ifdef SDL2
+ case SDL_DROPFILE:
+ if(event->drop.file) {
+ if(p_mach) {
+ if(image_loadpicture(event->drop.file)) {
+ if(p_mach->size_check(image_width(),image_height())) {
+ p_item=ui_list_add(top[TOP_LIST],"PPP IS WWWXHHH",4+image_width()*image_height());
+ ((uint16_t*)p_item->data)[0]=image_width();
+ ((uint16_t*)p_item->data)[1]=image_height();
+ image_convert(&((uint8_t*)p_item->data)[4]);
+ list_fill();
+ stat_add++;
+ } else {
+ stat_size++;
+ }
+ image_free();
+ } else {
+ stat_format++;
+ }
+ } else {
+ ui_field_add(msg[MSG_TEXT],"NOT READY TO ACCEPT IMAGES\nAT THIS TIME. PLEASE SELECT\nMACHINE USING FORMAT FIRST.");
+ view=VIEW_MSG;
+ return true;
+ }
+ } else {
+ sprintf(text,"SUCCESSFULLY ADDED: %i\nTOO BIG FOR MACHINE: %i\nUNRECOGNIZED FORMAT: %i",stat_add,stat_size,stat_format);
+ ui_field_add(msg[MSG_TEXT],text);
+ stat_add=0;
+ stat_size=0;
+ stat_format=0;
+ view=VIEW_MSG;
+ return true;
+ }
+ break;
+#endif
+ case SDL_QUIT:
+ quit = 1; // Set time to quit
+ return true;
+ case UI_CLICK:
+ if(p_ui==top[TOP_NEW]) {
+ view=VIEW_MACH;
+ return true;
+ } else if(p_ui==top[TOP_ADD]) {
+ ui_text_set(add[ADD_W],"");
+ ui_text_set(add[ADD_H],"");
+ ui_text_valid(add[ADD_W],false);
+ ui_text_valid(add[ADD_H],false);
+ ui_enable(add[ADD_OK],false);
+ view=VIEW_ADD;
+ return true;
+ } else if(p_ui==top[TOP_EDIT]) {
+ ui_field_add(msg[MSG_TEXT],"THIS FEATURE IS UNDER\nDEVELOPMENT BUT WILL ALLOW\nPATTERN EDITING WHEN DONE.");
+ view=VIEW_MSG;
+ return true;
+ } else if(p_ui==top[TOP_DEL]) {
+ ui_list_remove(top[TOP_LIST],ui_list_selected(top[TOP_LIST]));
+ ui_enable(top[TOP_EDIT],false);
+ ui_enable(top[TOP_DEL],false);
+ list_fill();
+ } else if(p_ui==top[TOP_EMU]) {
+ if(emulating) {
+ machine_emulate_stop();
+ } else {
+ view=build_image()?VIEW_EMU:VIEW_MSG;
+ return true;
+ }
+ }
+ break;
+ case UI_CHANGE:
+ if(p_ui==top[TOP_LIST]&&!emulating) {
+ ui_enable(top[TOP_EDIT],true);
+ ui_enable(top[TOP_DEL],true);
+ }
+ break;
+ case SDL_KEYDOWN:
+ switch(event->key.keysym.sym==SDLK_ESCAPE) {
+ case 1:
+ quit = 1; // Set time to quit
+ return true;
+ /*default: // keylogger
+ char text[10];
+ sprintf(text,"%i %i",((list_t*)top[TOP_LIST]->obj)->count,event->key.keysym.scancode);
+ ui_list_add(top[TOP_LIST],text,0);
+ */
+ }
+ break;
+ }
+ return false;
+}
+
+// event handler for machine select view
+static bool mach_event(SDL_Event *event) {
+ uiobj_t *p_ui=event->user.data1;
+ switch( event->type ) {
+ case SDL_QUIT:
+ quit = 1; // Set time to quit
+ return true;
+ case UI_CLICK:
+ if(p_ui==mach[MACH_OK]||p_ui==mach[MACH_CANCEL]) {
+ if(p_ui==mach[MACH_OK]) {
+ p_mach=machine_get(ui_list_selectedindex(mach[MACH_LIST]));
+ ui_list_clear(top[TOP_LIST]);
+ ui_enable(top[TOP_ADD],true);
+ ui_enable(top[TOP_EDIT],false);
+ ui_enable(top[TOP_DEL],false);
+ ui_enable(top[TOP_EMU],false);
+ ui_field_add(top[TOP_INFO],"DRAG AND DROP\nPICTURES TO THIS\nWINDOW TO ADD\nTHEM TO THE\nLIST OF PATTERNS");
+ }
+ view=VIEW_TOP;
+ return true;
+ }
+ break;
+ case UI_CHANGE:
+ if(p_ui==mach[MACH_LIST]) {
+ ui_enable(mach[MACH_OK],true);
+ }
+ break;
+ }
+ return false;
+}
+
+// event handler for add pattern view
+static bool add_event(SDL_Event *event) {
+ uiobj_t *p_ui;
+ p_ui=event->user.data1;
+ char text[60];
+ uint16_t w,h;
+ listitem_t *p_item;
+ switch( event->type ) {
+ case SDL_QUIT:
+ quit = 1; // Set time to quit
+ return true;
+ case UI_CLICK:
+ if(p_ui==add[ADD_OK]||p_ui==add[ADD_CANCEL]) {
+ if(p_ui==add[ADD_OK]) {
+ w=atoi(ui_text_get(add[ADD_W]));
+ h=atoi(ui_text_get(add[ADD_H]));
+ if(!p_mach->size_check(w,h)) {
+ sprintf(text,"NEW PATTERN OF SIZE\n%i X %i IS TOO BIG\nFOR THE SELECTED MACHINE.",w,h);
+ ui_field_add(msg[MSG_TEXT],text);
+ view=VIEW_MSG;
+ return true;
+ }
+ p_item=ui_list_add(top[TOP_LIST],"PPP IS WWWXHHH",4+w*h);
+ ((uint16_t*)p_item->data)[0]=w;
+ ((uint16_t*)p_item->data)[1]=h;
+ list_fill();
+ }
+ view=VIEW_TOP;
+ return true;
+ }
+ break;
+ case UI_CHANGE:
+ if(p_ui==add[ADD_W]||p_ui==add[ADD_H]) {
+ if(strlen(ui_text_get(p_ui))>0) {
+ ui_text_valid(p_ui,atoi(ui_text_get(p_ui))>0);
+ } else {
+ ui_text_valid(p_ui,false);
+ }
+ ui_enable(add[ADD_OK],ui_text_isvalid(add[ADD_W])&&ui_text_isvalid(add[ADD_H]));
+ }
+ break;
+ }
+ return false;
+}
+
+// handles messages from emulator
+static void emu_message(uint8_t event,uint8_t data) {
+ char msg[40];
+ switch(event) {
+ case EMU_ERROR: // error data=errcode
+ switch(data) {
+ case EMU_ERR_WRITE: // serial write error
+ sprintf(msg,"SERIAL PORT WRITE FAIL!");
+ break;
+ case EMU_ERR_CMD: // unsupported command
+ sprintf(msg,"UNSUPPORTED COMMAND!");
+ break;
+ case EMU_ERR_SECTOR: // bad sector id
+ sprintf(msg,"BAD SECTOR ID!");
+ break;
+ case EMU_ERR_CFG: // serial port configuration fail
+ sprintf(msg,"SERIAL CONFIGURATION FAIL!");
+ break;
+ case EMU_ERR_OPEN: // serial port open fail
+ sprintf(msg,"SERIAL OPEN FAIL!");
+ break;
+ case EMU_ERR_CLOSE: // serial port close fail
+ sprintf(msg,"SERIAL CLOSE FAIL!");
+ break;
+ case EMU_ERR_DATA: // unexpected data
+ sprintf(msg,"UNEXPECTED DATA!");
+ break;
+ default:
+ sprintf(msg,"UNKNOWN ERROR!");
+ break;
+ }
+ break;
+ case EMU_OPMODE: // op-mode req. data=0
+ sprintf(msg,"MODE SELECT");
+ break;
+ case EMU_FORMAT: // format req. data=0:ok 1:wrong code
+ sprintf(msg,"FORMAT %s",data?"BAD CODE":"OK");
+ break;
+ case EMU_READID: // read id data=sector
+ sprintf(msg,"READ ID %i",data);
+ break;
+ case EMU_WRITEID: // write id data=sector
+ sprintf(msg,"WRITE ID %i",data);
+ break;
+ case EMU_READ: // read data=sector
+ sprintf(msg,"READ SECTOR %i",data);
+ break;
+ case EMU_WRITE: // write data=sector
+ sprintf(msg,"WRITE SECTOR %i",data);
+ break;
+ case EMU_FIND: // search data=80:not found <80:found
+ if(data==80) {
+ sprintf(msg,"SECTOR NOT FOUND");
+ } else {
+ sprintf(msg,"FOUND SECTOR %i",data);
+ }
+ break;
+ case EMU_READY: // ready data=0
+ sprintf(msg,"READY");
+ break;
+ default:
+ sprintf(msg,"UNKNOWN MESSAGE");
+ break;
+ }
+ SDL_mutexP(mx_ui);
+ ui_field_add(top[TOP_OUT],msg);
+ SDL_mutexV(mx_ui);
+}
+
+// emulation thread (machine_emulate is blocking)
+static int emu_thread(void *device) {
+ SDL_mutexP(mx_ui);
+ ui_field_add(top[TOP_OUT],"STARTING EMULATORù");
+ SDL_mutexV(mx_ui);
+ machine_emulate(device,NULL,emu_message);
+ SDL_mutexP(mx_ui);
+ ui_field_add(top[TOP_OUT],"EMULATOR STOPPED");
+ ui_enable(top[TOP_NEW],true);
+ ui_enable(top[TOP_ADD],true);
+ ui_enable(top[TOP_EDIT],ui_list_selected(top[TOP_LIST])!=NULL);
+ ui_enable(top[TOP_DEL],ui_list_selected(top[TOP_LIST])!=NULL);
+ ui_button_set(top[TOP_EMU],"START EMULATOR");
+ ui_field_add(top[TOP_INFO],"DRAG AND DROP\nPICTURES TO THIS\nWINDOW TO ADD\nTHEM TO THE\nLIST OF PATTERNS");
+ SDL_mutexV(mx_ui);
+ emulating=false;
+}
+
+// event handler for start emulator view
+static bool emu_event(SDL_Event *event) {
+ uiobj_t *p_ui=event->user.data1;
+ switch( event->type ) {
+ case SDL_QUIT:
+ quit = 1; // Set time to quit
+ return true;
+ case UI_CLICK:
+ if(p_ui==emu[EMU_OK]||p_ui==emu[EMU_CANCEL]) {
+ if(p_ui==emu[EMU_OK]) {
+ ui_enable(top[TOP_NEW],false);
+ ui_enable(top[TOP_ADD],false);
+ ui_enable(top[TOP_EDIT],false);
+ ui_enable(top[TOP_DEL],false);
+ emulating=true;
+ ui_button_set(top[TOP_EMU],"STOP EMULATOR");
+ ui_field_add(top[TOP_INFO],"EMULATOR\nIS RUNNING\nYOU CAN NOW\nLOAD DATA ON\nTHE MACHINE");
+#ifdef SDL2
+ SDL_CreateThread(emu_thread,"emulator",ui_list_selected(emu[EMU_LIST])->data);
+#else
+ SDL_CreateThread(emu_thread,ui_list_selected(emu[EMU_LIST])->data);
+#endif
+ }
+ view=VIEW_TOP;
+ return true;
+ }
+ break;
+ case UI_CHANGE:
+ if(p_ui==emu[EMU_LIST]) {
+ ui_enable(emu[EMU_OK],true);
+ }
+ break;
+ }
+ return false;
+}
+
+// event handler for message view
+static bool msg_event(SDL_Event *event) {
+ uiobj_t *p_ui=event->user.data1;
+ switch( event->type ) {
+ case SDL_QUIT:
+ quit = 1; // Set time to quit
+ return true;
+ case UI_CLICK:
+ if(p_ui==msg[MSG_OK]) {
+ view=VIEW_TOP;
+ return true;
+ }
+ break;
+ }
+ return false;
+}
+
+void add_port(char *p_name,char *p_device) {
+ listitem_t *p_item;
+ p_item=ui_list_add(emu[EMU_LIST],p_name,strlen(p_device)+1);
+ strcpy(p_item->data,p_device);
+}
+
+// do the nasty
+int main( int argc, char *argv[] ) {
+ uint8_t n;
+ listitem_t *p_item;
+
+ // initialize sdl
+ if(SDL_Init(SDL_INIT_VIDEO)) return 1;
+#ifdef SDL2
+ window=SDL_CreateWindow("Knitting machine interface",SDL_WINDOWPOS_CENTERED,SDL_WINDOWPOS_CENTERED,640,480,SDL_WINDOW_SHOWN);
+ renderer=SDL_CreateRenderer(window,-1,SDL_RENDERER_SOFTWARE);
+ screen=SDL_GetWindowSurface(window);
+#else
+ SDL_WM_SetCaption("Knitting machine interface","Knitting machine interface");
+ screen = SDL_SetVideoMode(640,480,24,0);
+#endif
+
+ // initialize ui and renderer
+ ui_init();
+#ifdef SDL2
+ r_init(renderer,screen);
+#else
+ r_init(screen);
+#endif
+
+ // build top view
+ vtop=ui_fsview();
+ top[TOP_LIST]=ui_add(vtop,ui_list (1,1,16,22,"PATTERNS"));
+ top[TOP_NEW] =ui_add(vtop,ui_button(22, 1," FORMAT "));
+ top[TOP_ADD] =ui_add(vtop,ui_button(22, 4," NEW PATTERN "));
+ top[TOP_EDIT]=ui_add(vtop,ui_button(22, 7," EDIT PATTERN "));
+ top[TOP_DEL] =ui_add(vtop,ui_button(22,10,"DELETE PATTERN"));
+ top[TOP_EMU] =ui_add(vtop,ui_button(22,13,"START EMULATOR"));
+ top[TOP_OUT] =ui_add(vtop,ui_field (1,24,38,5,"EMULATOR",false,true));
+ top[TOP_INFO]=ui_add(vtop,ui_field (21,17,18,7,NULL,true,false));
+ ui_enable(top[TOP_ADD],false);
+ ui_enable(top[TOP_EDIT],false);
+ ui_enable(top[TOP_DEL],false);
+ ui_enable(top[TOP_EMU],false);
+
+ // build machine select view
+ vmach=ui_view(20,15,"SELECT MACHINE");
+ mach[MACH_LIST] =ui_add(vmach,ui_list(0,0,17,12,"MACHINES"));
+ mach[MACH_OK] =ui_add(vmach,ui_button(8, 12,"OK"));
+ mach[MACH_CANCEL] =ui_add(vmach,ui_button(12, 12,"CANCEL"));
+ ui_enable(mach[MACH_OK],false);
+ vmach->ok=mach[MACH_OK];
+ vmach->cancel=mach[MACH_CANCEL];
+
+ // build add pattern view
+ vadd=ui_view(20,5,"ADD PATTERN");
+ add[ADD_W] =ui_add(vadd,ui_text(0,0,10,"WIDTH :"));
+ add[ADD_H] =ui_add(vadd,ui_text(0,1,10,"HEIGHT:"));
+ add[ADD_OK] =ui_add(vadd,ui_button(8, 3,"OK"));
+ add[ADD_CANCEL] =ui_add(vadd,ui_button(12, 3,"CANCEL"));
+ ui_enable(add[ADD_OK],false);
+ vadd->ok=add[ADD_OK];
+ vadd->cancel=add[ADD_CANCEL];
+
+ // build start emulator view
+ vemu=ui_view(30,15,"SELECT COMMUNICATIONS PORT");
+ emu[EMU_LIST] =ui_add(vemu,ui_list(0,0,27,12,"PORTS"));
+ emu[EMU_OK] =ui_add(vemu,ui_button(18, 12,"OK"));
+ emu[EMU_CANCEL] =ui_add(vemu,ui_button(22, 12,"CANCEL"));
+ ui_enable(emu[EMU_OK],false);
+ vemu->ok=emu[EMU_OK];
+ vemu->cancel=emu[EMU_CANCEL];
+ senum(add_port); // enumerate serial ports
+
+ // build message view
+ vmsg=ui_view(30,8,"OHAI, YOU HAS MESSAGE");
+ msg[MSG_TEXT] =ui_add(vmsg,ui_field(0,0,30,5,NULL,true,true));
+ msg[MSG_OK] =ui_add(vmsg,ui_button(13, 5,"OK"));
+ vmsg->ok=msg[MSG_OK];
+
+ // enumerate available machines, add to machine select view
+ machine_init();
+ for(n=0;n<255;n++) {
+ p_mach=machine_get(n);
+ if(p_mach==NULL)break;
+ p_item=ui_list_add(mach[MACH_LIST],p_mach->code,strlen(p_mach->name)+1);
+ strcpy(p_item->data,p_mach->name);
+ }
+ // TODO: remove
+ // p_mach=machine_get(0);
+ // ui_enable(top[TOP_ADD],true);
+ // ENDTODO
+
+ // initial info text
+ ui_field_add(top[TOP_OUT],"HELLO\nWORLD");
+ ui_field_add(top[TOP_INFO],"CLICK FORMAT\nTO SELECT AND\nBEGIN WORKING\nWITH A SPECIFIC\nKNITTING MACHINE");
+
+ // main loop: view switching
+ while(!quit) {
+ switch(view) {
+ case VIEW_TOP: ui_display(vtop,top_event);
+ break;
+ case VIEW_MACH: ui_display(vmach,mach_event);
+ break;
+ case VIEW_ADD: ui_display(vadd,add_event);
+ break;
+ case VIEW_EMU: ui_display(vemu,emu_event);
+ break;
+ case VIEW_MSG: ui_display(vmsg,msg_event);
+ break;
+ }
+ }
+
+ // free up allocated ui memory
+ ui_free_view(vtop);
+ ui_free_view(vmach);
+ ui_free_view(vadd);
+ ui_free_view(vemu);
+ ui_free();
+
+
+ // free up allocated renderer memory
+ r_free();
+
+}
View
387 gui/renderer.c
@@ -0,0 +1,387 @@
+#ifdef SDL2
+#include <SDL2/SDL.h>
+#else
+#include <SDL/SDL.h>
+#endif
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include "renderer.h"
+
+typedef struct {
+ uint8_t cchar;
+ uint8_t nchar;
+ uint8_t cfont;
+ uint8_t nfont;
+ int8_t ofsx;
+ int8_t ofsy;
+ int16_t tick;
+} termchar_t;
+
+static termchar_t *term;
+ uint8_t r_w, r_h;
+static SDL_Surface *font;
+static const char font_chars[] = "#!\"% '()|+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZú®¯³ÄÙÀÚ¿´ÃºÍ¼ÈÉ»awdsgyhbnvtumcri";
+static uint8_t write_index = 0;
+#ifdef SDL2
+static SDL_Renderer *renderer;
+#endif
+static SDL_Surface *screen;
+static SDL_Surface *bg;
+static char cx = -1, cy, ct;
+
+#ifdef SDL2
+static SDL_PixelFormat fmt_rgb = {
+ 0,NULL,32,4,{0,0},
+ 0xFF000000,0x00FF0000,
+ 0x0000FF00,0x000000FF,
+ 0,0,0,0,24,16,8,0,0,NULL
+
+};
+#else
+static SDL_PixelFormat fmt_rgb = {
+ NULL,32,4,0,0,0,0,24,16,8,0,
+ 0xFF000000,0x00FF0000,
+ 0x0000FF00,0x000000FF,
+ 0xFF00FF00,255
+};
+#endif
+
+// Convenience macros
+#define ABS( v ) ( v < 0 ? -v : v )
+#define TERM( x, y ) term[ (y) * r_w + (x) ]
+
+void r_cins( unsigned char x, unsigned char y ) {
+ cx = x;
+ cy = y;
+ ct = 0;
+}
+
+void r_crem() {
+ cx = -1;
+}
+
+void r_clear() {
+ memset( term, 0, sizeof( termchar_t ) * r_w * r_h );
+}
+
+static trytake(uint8_t*pix,bool taken[32][24],uint8_t sx,uint8_t sy,uint8_t w,uint8_t h) {
+ unsigned int x,y;
+ uint8_t *p_px,c;
+ float o,xf,yf;
+ for(y=sy;y<sy+h;y++) {
+ for(x=sx;x<sx+w;x++) {
+ if(taken[x][y]) return;
+ }
+ }
+ for(y=sy;y<sy+h;y++) {
+ for(x=sx;x<sx+w;x++) {
+ taken[x][y] = true;
+ }
+ }
+ o=(((float)rand())*64.0/RAND_MAX)-96.0;
+ xf=(((float)rand())*2.0/RAND_MAX)-1.0;
+ yf=(((float)rand())*2.0/RAND_MAX)-1.0;
+ xf/=w;
+ yf/=h;
+ for(y=sy*20;y<(sy+h)*20;y++) {
+ p_px=&pix[2560*y+sx*80];
+ for(x=sx*20;x<(sx+w)*20;x++) {
+ c=o+(x-(sx*20))*xf+(y-(sy*20))*yf;
+ *p_px++=255;
+ *p_px++=c;
+ *p_px++=c;
+ *p_px++=c;
+ }
+ }
+}
+
+static SDL_Surface *get_bg() {
+ SDL_Surface *temp,*bg;
+ bool taken[32][24];
+ uint8_t n,x,y;
+ memset(taken,false,sizeof(taken));
+ bg=SDL_CreateRGBSurface(SDL_SWSURFACE,screen->w,screen->h,32,fmt_rgb.Rmask,fmt_rgb.Gmask,fmt_rgb.Bmask,fmt_rgb.Amask);
+ SDL_LockSurface(bg);
+ for(n=0;n< 2;n++) trytake(bg->pixels,taken,rand()%(32-5),rand()%(24-5),5,5);
+ for(n=0;n< 5;n++) trytake(bg->pixels,taken,rand()%(32-4),rand()%(24-4),4,4);
+ for(n=0;n< 10;n++) trytake(bg->pixels,taken,rand()%(32-3),rand()%(24-3),3,3);
+ for(n=0;n<250;n++) trytake(bg->pixels,taken,rand()%(32-2),rand()%(24-2),2,2);
+ for(y=0;y<24;y++) {
+ for(x=0;x<32;x++) {
+ trytake(bg->pixels,taken,x,y,1,1);
+ }
+ }
+ SDL_UnlockSurface(bg);
+ temp=bg;
+#ifdef SDL2
+ bg=SDL_ConvertSurface(temp,screen->format,0);
+#else
+ bg=SDL_DisplayFormat(temp);
+#endif
+ SDL_FreeSurface(temp);
+ return bg;
+}
+
+static SDL_Surface *get_font() {
+ SDL_Surface *temp, *font;
+ int32_t count;
+ uint8_t color,fade;
+ uint8_t *p_src,*p_dst;
+ uint8_t r,g,b,a;
+ temp=SDL_LoadBMP("ui.bmp");
+ if(!temp) return NULL;
+ font=SDL_ConvertSurface(temp,&fmt_rgb,SDL_SWSURFACE);
+ SDL_FreeSurface(temp);
+ if(!font) return NULL;
+ temp=font;
+ font=SDL_CreateRGBSurface(SDL_SWSURFACE,temp->w,temp->h*16*4,32,fmt_rgb.Rmask,fmt_rgb.Gmask,fmt_rgb.Bmask,fmt_rgb.Amask);
+ if(!font) {
+ SDL_FreeSurface(temp);
+ return NULL;
+ }
+ SDL_LockSurface(font);
+ SDL_LockSurface(temp);
+ p_dst=font->pixels;
+ for(color=0;color<4;color++) {
+ for(fade=0;fade<16;fade++) {
+ p_src=temp->pixels;
+ for(count=0;count<temp->w*temp->h;count++) {
+ a=*p_src++;b=*p_src++;g=*p_src++;r=*p_src++;
+ if(r==255&&g==255&&b==255) {
+ g=0;
+ } else if(r>60) {
+ if(color!=0&&color!=1) r=(r>>1)+(r>>2);
+ if(color!=0&&color!=2) g=(g>>1)+(g>>2);
+ if(color!=0&&color!=3) b=(b>>1)+(b>>2);
+ if(color!=0) {
+ r+=40;
+ g+=40;
+ b+=40;
+ }
+ r=255-(((255-r)*fade)/15);
+ g=255-(((255-g)*fade)/15);
+ b=255-(((255-b)*fade)/15);
+ } else {
+ if(color!=0&&color!=1) r=(r>>1)+(r>>2);
+ if(color!=0&&color!=2) g=(g>>1)+(g>>2);
+ if(color!=0&&color!=3) b=(b>>1)+(b>>2);
+ }
+ *p_dst++=a;*p_dst++=b;*p_dst++=g;*p_dst++=r;
+ }
+ }
+ }
+ SDL_UnlockSurface(font);
+ SDL_UnlockSurface(temp);
+ SDL_FreeSurface(temp);
+ temp=font;
+#ifdef SDL2
+ font=SDL_ConvertSurface(temp,screen->format,0);
+ SDL_SetColorKey(font,SDL_TRUE,SDL_MapRGB(screen->format,0xFF,0x00,0xFF));
+#else
+ font=SDL_DisplayFormat(temp);
+ SDL_SetColorKey(font,SDL_SRCCOLORKEY,SDL_MapRGB(screen->format,0xFF,0x00,0xFF));
+#endif
+ SDL_FreeSurface(temp);
+ return font;
+}
+
+#ifdef SDL2
+void r_init( SDL_Renderer *ren, SDL_Surface *scr ) {
+#else
+void r_init( SDL_Surface *scr ) {
+#endif
+ SDL_Surface* temp;
+ char *p_pixel;
+#ifdef SDL2
+ renderer=ren;
+#endif
+ screen = scr;
+ r_w = screen->w >> 4;
+ r_h = screen->h >> 4;
+ term = malloc( sizeof( termchar_t ) * r_w * r_h );
+ r_clear();
+ font=get_font();
+ bg=get_bg();
+}
+
+void r_draw() {
+ unsigned char x, y;
+ unsigned char i, j;
+ SDL_BlitSurface(bg,NULL,screen,NULL);
+ write_index = 0;
+ SDL_Rect srcrect;
+ SDL_Rect dstrect;
+ srcrect.w = 16;
+ srcrect.h = 16;
+ for( y = 0; y < r_h; y++ ) {
+ for( x = 0; x < r_w; x++ ) {
+ if( TERM( x, y ).tick < 15 ) {
+ if( ++TERM( x, y ).tick == 0 ) {
+ TERM( x, y ).cchar = TERM( x, y ).nchar;
+ TERM( x, y ).cfont = TERM( x, y ).nfont;
+ }
+ }
+
+ if( TERM( x, y ).cchar ) {
+ dstrect.x = ( x << 4 ) + TERM( x, y ).ofsx;
+ dstrect.y = ( y << 4 ) + TERM( x, y ).ofsy;
+ srcrect.x = TERM( x, y ).cchar << 4;
+ srcrect.y = ( TERM( x, y ).tick >= 0 ? TERM( x, y ).tick << 4 : 240 ) + TERM( x, y ).cfont * 256;
+ SDL_BlitSurface( font, &srcrect, screen, &dstrect );
+ }
+ }
+ }
+ if( cx >= 0 ) {
+ srcrect.x = 0;
+ srcrect.y = ( ct > 15 ? 240 : ct << 4 );
+ dstrect.x = cx << 4;
+ dstrect.y = cy << 4;
+ SDL_BlitSurface( font, &srcrect, screen, &dstrect );
+ if( ++ct == 32 ) ct = 0;
+ }
+#ifdef SDL2
+ SDL_RenderPresent(renderer);
+#else
+ SDL_UpdateRect( screen, 0, 0, 0, 0 );
+#endif
+}
+
+void r_box( unsigned char x, unsigned char _y, unsigned char w, unsigned char h, char*caption, unsigned char fb, unsigned char fc ) {
+ char *buf=malloc(w+1);
+ unsigned char y=_y;
+ buf[w]=0;
+ memset(&buf[1],'Ä',w-2);
+ buf[0]='Ú';
+ buf[w-1]='¿';
+ if(caption) {
+ buf[1]='´';
+ memset(&buf[2],' ',strlen(caption));
+ buf[2+strlen(caption)]='Ã';
+ }
+ r_write(x,y,buf,fb);
+ if(caption) r_write(x+2,y,caption,fc);
+ memset(&buf[1],' ',w-2);
+ buf[0]='³';
+ buf[w-1]='³';
+ for(y++;y<_y+h-1;y++) r_write(x,y,buf,fb);
+ memset(&buf[1],'Ä',w-2);
+ buf[0]='À';
+ buf[w-1]='Ù';
+ r_write(x,y,buf,fb);
+ free(buf);
+}
+
+void r_button( unsigned char x, unsigned char y, char*caption, unsigned char fb, unsigned char fc) {
+ char *buf;
+ unsigned char w;
+ w=strlen(caption)+2;
+ buf=malloc(w+1);
+ buf[w]=0;
+ memset(&buf[1],'Í',w-2);
+ buf[0]='É';
+ buf[w-1]='»';
+ r_write(x,y,buf,fb);
+ memset(&buf[1],' ',w-2);
+ buf[0]='º';
+ buf[w-1]='º';
+ r_write(x,++y,buf,fb);
+ r_write(x+1,y++,caption,fc);
+ memset(&buf[1],'Í',w-2);
+ buf[0]='È';
+ buf[w-1]='¼';
+ r_write(x,y,buf,fb);
+ free(buf);
+}
+
+void r_write( unsigned char x, unsigned char y, char *s, unsigned char f ) {
+ unsigned char i, j, t = 0;
+ int len = strlen( s );
+ for( i = 0; i < len; i++ ) {
+ for( j = 0; j < sizeof( font_chars ) - 1; j++ ) {
+ if( font_chars[ j ] == s[ i ] ) {
+ if( TERM( x, y ).nchar != j || TERM( x, y ).nfont != f ) {
+ TERM( x, y ).nchar = j;
+ TERM( x, y ).nfont = f;
+ if( t == 0 && write_index == 0 ) {
+ TERM( x, y ).cchar = j;
+ TERM( x, y ).cfont = f;
+ TERM( x, y ).tick = 0;
+ } else {
+ TERM( x, y ).tick = -( t + write_index );
+ }
+ t++;
+ }
+ x++;
+ break;
+ }
+ }
+ }
+ write_index++;
+}
+
+void r_flash( unsigned char _x, unsigned char _y, unsigned char w, unsigned char h ) {
+ unsigned char x, y;
+ for(y=0;y<h;y++) {
+ for(x=0;x<w;x++) {
+ TERM(x+_x,y+_y).cchar=TERM(x+_x,y+_y).nchar;
+ TERM(x+_x,y+_y).cfont=TERM(x+_x,y+_y).nfont;
+ TERM(x+_x,y+_y).tick=0;
+ }
+ }
+}
+
+void r_done( unsigned char _x, unsigned char _y, unsigned char w, unsigned char h ) {
+ unsigned char x, y;
+ for(y=0;y<h;y++) {
+ for(x=0;x<w;x++) {
+ TERM(x+_x,y+_y).cchar=TERM(x+_x,y+_y).nchar;
+ TERM(x+_x,y+_y).cfont=TERM(x+_x,y+_y).nfont;
+ TERM(x+_x,y+_y).tick=15;
+ }
+ }
+}
+
+void r_shine( unsigned char _x, unsigned char _y, unsigned char w, unsigned char h ) {
+ unsigned char x, y;
+ for(y=0;y<h;y++) {
+ for(x=0;x<w;x++) {
+ TERM(x+_x,y+_y).cchar=TERM(x+_x,y+_y).nchar;
+ TERM(x+_x,y+_y).cfont=TERM(x+_x,y+_y).nfont;
+ TERM(x+_x,y+_y).tick=-(x+y);
+ }
+ }
+}
+
+void r_offset( unsigned char _x, unsigned char _y, unsigned char w, unsigned char h, char ox, char oy ) {
+ unsigned char x, y;
+ for(y=0;y<h;y++) {
+ for(x=0;x<w;x++) {
+ TERM(x+_x,y+_y).ofsx=ox;
+ TERM(x+_x,y+_y).ofsy=oy;
+ }
+ }
+}
+
+void r_white( unsigned char _x, unsigned char _y, unsigned char w, unsigned char h ) {
+ unsigned char x, y;
+ for(y=0;y<h;y++) {
+ for(x=0;x<w;x++) {
+ memset( &TERM(x+_x,y+_y), 0, sizeof( termchar_t ) );
+ }
+ }
+}
+
+void r_free() {
+ free( term );
+ SDL_FreeSurface( font );
+}
+
+int r_knows( char c ) {
+ int j;
+ for( j = 0; j < sizeof( font_chars ) - 1; j++ ) {
+ if( font_chars[ j ] == c ) return( 1 );
+ }
+ return( 0 );
+}
View
19 gui/renderer.h
@@ -0,0 +1,19 @@
+#ifdef SDL2
+void r_init( SDL_Renderer *ren, SDL_Surface *scr );
+#else
+void r_init( SDL_Surface *scr );
+#endif
+void r_clear();
+void r_draw();
+void r_write( unsigned char x, unsigned char y, char *s, unsigned char f );
+void r_white( unsigned char x, unsigned char y, unsigned char w, unsigned char h );
+void r_cins( unsigned char x, unsigned char y );
+void r_crem();
+void r_box( unsigned char x, unsigned char y, unsigned char w, unsigned char h, char*caption, unsigned char fb, unsigned char fc);
+void r_button( unsigned char x, unsigned char y, char*caption, unsigned char fb, unsigned char fc);
+void r_flash( unsigned char x, unsigned char y, unsigned char w, unsigned char h );
+void r_shine( unsigned char x, unsigned char y, unsigned char w, unsigned char h );
+void r_done( unsigned char x, unsigned char y, unsigned char w, unsigned char h );
+void r_offset( unsigned char _x, unsigned char _y, unsigned char w, unsigned char h, char ox, char oy );
+int r_knows( char c );
+void r_free();
View
779 gui/ui.c
@@ -0,0 +1,779 @@
+#include <stdint.h>
+#include <stdbool.h>
+#ifdef SDL2
+#include <SDL2/SDL.h>
+#else
+#include <SDL/SDL.h>
+#endif
+#include "renderer.h"
+#include "ui.h"
+
+/** GENERICS ********************************************************/
+
+SDL_mutex *mx_ui;
+
+void ui_init() {
+ mx_ui=SDL_CreateMutex();
+#ifdef SDL2
+ SDL_EventState(SDL_DROPFILE,SDL_ENABLE);
+#endif
+}
+
+void ui_free() {
+ SDL_DestroyMutex(mx_ui);
+}
+
+void ui_enable(uiobj_t*p_ui,bool enable) {
+ if(p_ui->enabled!=enable) {
+ p_ui->enabled=enable;
+ p_ui->state|=2;
+ }
+}
+
+void capstr(char *p_text) {
+ while(*p_text!=0) {
+ *p_text=toupper(*p_text);
+ if(*p_text=='\\') *p_text='/';
+ p_text++;
+ }
+}
+
+/** VIEWS ***********************************************************/
+
+view_t* ui_fsview() {
+ view_t *p_obj=malloc(sizeof(view_t));
+ p_obj->x=0;
+ p_obj->y=0;
+ p_obj->w=40;
+ p_obj->h=30;
+ p_obj->caption=NULL;
+ p_obj->ui=NULL;
+ p_obj->fullscreen=true;
+ p_obj->state=0;
+ p_obj->ok=NULL;
+ p_obj->cancel=NULL;
+ return p_obj;
+}
+
+view_t* ui_view(uint8_t w,uint8_t h,char *caption) {
+ view_t *p_obj=malloc(sizeof(view_t));
+ p_obj->x=20-w/2;
+ p_obj->y=15-h/2;
+ p_obj->w=w;
+ p_obj->h=h;
+ p_obj->caption=malloc(strlen(caption));
+ strcpy(p_obj->caption,caption);
+ p_obj->fullscreen=false;
+ p_obj->ui=NULL;
+ p_obj->state=0;
+ p_obj->ok=NULL;
+ p_obj->cancel=NULL;
+ return p_obj;
+}
+
+/** TEXT INPUT ******************************************************/
+
+uiobj_t* ui_text(uint8_t x,uint8_t y,uint8_t w,char *caption) {
+ uiobj_t *p_ui=malloc(sizeof(uiobj_t));
+ text_t *p_obj=malloc(sizeof(list_t));
+ p_ui->x=x;
+ p_ui->y=y;
+ p_ui->w=w;
+ p_ui->h=1;
+ p_obj->caption=malloc(strlen(caption)+1);
+ strcpy(p_obj->caption,caption);
+ p_obj->text=malloc(w-strlen(caption)+1);
+ p_obj->text[0]=0;
+ p_obj->valid=false;
+ p_ui->type=UI_TEXT;
+ p_ui->obj=p_obj;
+ return p_ui;
+}
+
+void ui_text_set(uiobj_t *p_ui,char *p_replace) {
+ text_t *p_text=p_ui->obj;
+ strcpy(p_text->text,p_replace);
+ p_ui->state|=2;
+}
+
+char* ui_text_get(uiobj_t *p_ui) {
+ text_t *p_text=p_ui->obj;
+ return p_text->text;
+}
+
+void ui_text_valid(uiobj_t *p_ui,bool valid) {
+ text_t *p_text=p_ui->obj;
+ if(p_text->valid!=valid) {
+ p_text->valid=valid;
+ if(p_ui->enabled) p_ui->state|=2;
+ }
+}
+
+bool ui_text_isvalid(uiobj_t *p_ui) {
+ text_t *p_text=p_ui->obj;
+ return p_text->valid;
+}
+
+static void text_draw(uiobj_t *p_ui) {
+ text_t *p_text=p_ui->obj;
+ view_t *p_view=p_ui->view;
+ if(p_ui->state&3) {
+ r_write(p_view->x+p_ui->x,p_view->y+p_ui->y,p_text->caption,p_ui->enabled?(p_text->valid?2:1):0);
+ if(p_ui->state&2) {
+ r_flash(p_view->x+p_ui->x,p_view->y+p_ui->y,strlen(p_text->caption),1);
+ }
+ }
+ if(p_ui->state&5) {
+ r_write(p_view->x+p_ui->x+strlen(p_text->caption),p_view->y+p_ui->y,p_text->text,p_ui->enabled?3:0);
+ r_white(
+ p_view->x+p_ui->x+strlen(p_text->caption)+strlen(p_text->text),p_view->y+p_ui->y,
+ p_ui->w-strlen(p_text->caption)+strlen(p_text->text),1
+ );
+ }
+ p_ui->state=0;
+}
+
+static void text_focus(uiobj_t *p_ui) {
+ text_t *p_text=p_ui->obj;
+ view_t *p_view=p_ui->view;
+ r_cins(p_view->x+p_ui->x+strlen(p_text->caption)+strlen(p_text->text),p_view->y+p_ui->y);
+}
+
+static bool text_key(uiobj_t *p_ui,uint8_t sym) {
+ text_t *p_text=p_ui->obj;
+ char key[2];
+ if((sym>=SDLK_0&&sym<=SDLK_9)||sym==SDLK_BACKSPACE) {
+ // numbers and backspace
+ if(sym==SDLK_BACKSPACE) {
+ if(strlen(p_text->text)) {
+ p_text->text[strlen(p_text->text)-1]=0;
+ p_ui->state|=4;
+ text_focus(p_ui);
+ return true;
+ }
+ } else {
+ if(strlen(p_text->caption)+strlen(p_text->text)<p_ui->w) {
+ key[0]=sym-SDLK_0+'0';
+ key[1]=0;
+ strcat(p_text->text,key);
+ p_ui->state|=4;
+ text_focus(p_ui);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+/** LISTS ***********************************************************/
+
+uiobj_t* ui_list(uint8_t x,uint8_t y,uint8_t w,uint8_t h,char *caption) {
+ uiobj_t *p_ui=malloc(sizeof(uiobj_t));
+ list_t *p_obj=malloc(sizeof(list_t));
+ p_ui->x=x;
+ p_ui->y=y;
+ p_ui->w=w;
+ p_ui->h=h;
+ p_obj->caption=malloc(strlen(caption)+1);
+ strcpy(p_obj->caption,caption);
+ p_obj->selected=NULL;
+ p_obj->count=0;
+ p_obj->top=0;
+ p_obj->list=NULL;
+ p_ui->type=UI_LIST;
+ p_ui->obj=p_obj;
+ return p_ui;
+}
+
+static void list_scroll(uiobj_t *p_ui,uint16_t top) {
+ list_t *p_list=p_ui->obj;
+ p_list->top=top;
+ if(p_list->count<(p_list->top+p_ui->h-2)) {
+ if(p_ui->h-2>p_list->count) p_list->top=0;
+ else p_list->top=p_list->count-(p_ui->h-2);
+ }
+ ui_enable(p_ui->next,p_list->top);
+ ui_enable(p_ui->next->next,p_list->count>=p_list->top+p_ui->h-1);
+ p_ui->state|=2;
+}
+
+static void list_draw(uiobj_t *p_ui) {
+ list_t *p_list=p_ui->obj;
+ view_t *p_view=p_ui->view;
+ listitem_t *p_item;
+ bool selected;
+ char *p_text;
+ uint8_t y;
+ if(p_ui->state&1) {
+ r_box(p_view->x+p_ui->x,p_view->y+p_ui->y,p_ui->w,p_ui->h,p_list->caption,0,1);
+ }
+ if(p_ui->state&3) {
+ p_text=malloc(p_ui->w-1);
+ p_text[p_ui->w-2]=0;
+ p_item=ui_list_index2item(p_ui,p_list->top);
+ r_white(p_view->x+p_ui->x+1,p_view->y+p_ui->y+1,p_ui->w-2,p_ui->h-2);
+ for(y=0;(y<p_ui->h-2)&&p_item;y++) {
+ if(strlen(p_item->text)>=p_ui->w-2) {
+ memcpy(p_text,p_item->text,p_ui->w-2);
+ } else {
+ strcpy(p_text,p_item->text);
+ }
+ selected=(p_item==p_list->selected);
+ p_item=p_item->next;
+ r_write(p_view->x+p_ui->x+1,p_view->y+p_ui->y+1+y,p_text,selected?3:0);
+ }
+ if((p_ui->state&3)==2) r_done(p_view->x+p_ui->x+1,p_view->y+p_ui->y+1,p_ui->w-2,p_ui->h-2);
+ free(p_text);
+ }
+
+ p_ui->state=0;
+}
+
+uint16_t ui_list_item2index(uiobj_t *p_ui,listitem_t *p_i) {
+ uint16_t index=0;
+ list_t *p_list=p_ui->obj;
+ listitem_t *p_item;
+ p_item=p_list->list;
+ while(p_item) {
+ if(p_item==p_i) return index;
+ p_item=p_item->next;
+ index++;
+ }
+ return -1;
+}
+
+listitem_t* ui_list_index2item(uiobj_t *p_ui,uint16_t ix) {
+ uint16_t index=0;
+ list_t *p_list=p_ui->obj;
+ listitem_t *p_item;
+ p_item=p_list->list;
+ if(p_item==NULL) return NULL;
+ while(index<ix) {
+ if(p_item->next==NULL) return NULL;
+ p_item=p_item->next;
+ index++;
+ }
+ return p_item;
+}
+
+void ui_list_remove(uiobj_t *p_ui,listitem_t *p_item) {
+ list_t *p_list=p_ui->obj;
+
+ //printf("REM: %i < %i > %i\n",p_item->prev,p_item,p_item->next);
+
+ if(p_item->prev) {
+ p_item->prev->next=p_item->next;
+ } else {
+ p_list->list=p_item->next;
+ }
+ if(p_item->next) p_item->next->prev=p_item->prev;
+ p_list->count--;
+ list_scroll(p_ui,p_list->top);
+ if(p_list->selected==p_item) p_list->selected=NULL;
+
+ free(p_item->text);
+ if(p_item->data) free(p_item->data);
+ free(p_item);
+}
+
+void ui_list_clear(uiobj_t *p_ui) {
+ list_t *p_list=p_ui->obj;
+ while(p_list->count)ui_list_remove(p_ui,p_list->list);
+}
+
+listitem_t* ui_list_add(uiobj_t *p_ui,char *text, size_t n_data) {
+ list_t *p_list=p_ui->obj;
+ listitem_t *p_item=malloc(sizeof(listitem_t));
+ listitem_t *p_temp;
+ p_item->text=malloc(strlen(text)+1);
+ strcpy(p_item->text,text);
+ capstr(p_item->text);
+ if(n_data) {
+ p_item->data=malloc(n_data);
+ } else p_item->data=NULL;
+ p_item->next=NULL;
+ if(p_list->list) {
+ p_temp=p_list->list;
+ while(p_temp->next) p_temp=p_temp->next;
+ p_temp->next=p_item;
+ p_item->prev=p_temp;
+ } else {
+ p_list->list=p_item;
+ p_item->prev=NULL;
+ }
+ p_list->count++;
+ list_scroll(p_ui,p_list->top);
+ //printf("ADD: %i = %s\n",p_item,text);
+ return p_item;
+}
+
+bool ui_list_selectindex(uiobj_t *p_ui,uint8_t index) {
+ list_t *p_list=p_ui->obj;
+ if(p_list->top+index>=p_list->count) return false;
+ p_list->selected=ui_list_index2item(p_ui,p_list->top+index);
+ //printf("SELECT: %i = %i\n",index,p_list->selected);
+ p_ui->state|=2;
+ return true;
+}
+
+void ui_list_select(uiobj_t *p_ui,listitem_t *p_item) {
+ list_t *p_list=p_ui->obj;
+ p_list->selected=p_item;
+ p_ui->state|=2;
+}
+
+listitem_t* ui_list_selected(uiobj_t *p_ui) {
+ return ((list_t*)p_ui->obj)->selected;
+}
+
+uint16_t ui_list_selectedindex(uiobj_t *p_ui) {
+ return ui_list_item2index(p_ui,((list_t*)p_ui->obj)->selected);
+}
+
+
+/** BUTTONS *********************************************************/
+
+uiobj_t* ui_button(uint8_t x,uint8_t y,char *caption) {
+ uiobj_t *p_ui=malloc(sizeof(uiobj_t));
+ button_t *p_obj=malloc(sizeof(button_t));
+ p_ui->x=x;
+ p_ui->y=y;
+ p_ui->w=strlen(caption)+2;
+ p_ui->h=3;
+ p_obj->caption=malloc(strlen(caption)+1);
+ strcpy(p_obj->caption,caption);
+ p_ui->type=UI_BUTTON;
+ p_ui->obj=p_obj;
+ return p_ui;
+}
+
+void ui_button_set(uiobj_t *p_ui,char *caption) {
+ button_t *p_button=p_ui->obj;
+ if(strlen(caption)==strlen(p_button->caption)) {
+ strcpy(p_button->caption,caption);
+ p_ui->state|=2;
+ }
+}
+
+static void button_draw(uiobj_t *p_ui) {
+ button_t *p_button=p_ui->obj;
+ view_t *p_view=p_ui->view;
+ if(p_ui->state&1) {
+ r_button(p_view->x+p_ui->x,p_view->y+p_ui->y,p_button->caption,0,p_ui->enabled?2:0);
+ } else if(p_ui->state&2) {
+ r_write(p_view->x+p_ui->x+1,p_view->y+p_ui->y+1,p_button->caption,p_ui->enabled?2:0);
+ r_flash(p_view->x+p_ui->x+1,p_view->y+p_ui->y+1,strlen(p_button->caption),1);
+ }
+ p_ui->state=0;
+}
+
+/** FIELDS **********************************************************/
+
+static void field_draw(uiobj_t *p_ui) {
+ field_t *p_field=p_ui->obj;
+ view_t *p_view=p_ui->view;
+ char *p_line;
+ uint8_t n;
+ if(p_ui->state&1) {
+ if(p_field->caption) {
+ r_box(p_view->x+p_ui->x,p_view->y+p_ui->y,p_ui->w,p_ui->h,p_field->caption,0,1);
+ }
+ }
+ if(p_ui->state&5) {
+ p_line=malloc(p_ui->w-1);
+ memset(p_line,0,p_ui->w-1);
+ // clear last line
+ if((p_ui->state&4)&&(p_field->terminal)) r_white(p_view->x+p_ui->x+1,p_view->y+p_ui->y+p_ui->h-2,p_ui->w-2,1);
+ for(n=0;n<p_ui->h-2;n++) {
+ memcpy(p_line,p_field->text+n*(p_ui->w-2),p_ui->w-2);
+ r_write(p_view->x+p_ui->x+1,p_view->y+p_ui->y+1+n,p_line,3);
+ if((n<p_ui->h-3)&&(p_ui->state&4)&&(p_field->terminal)) {
+ r_done(p_view->x+p_ui->x+1,p_view->y+p_ui->y+1+n,p_ui->w-2,1);
+ }
+ }
+ }
+ p_ui->state=0;
+}
+
+static void ui_field_addline(uiobj_t*p_ui,char*p_line,uint8_t len) {
+ field_t*p_field;
+ char *p_dst;
+ uint8_t n;
+ p_field=p_ui->obj;
+ memmove(p_field->text,p_field->text+p_ui->w-2,(p_ui->w-2)*(p_ui->h-3));
+ if(len>p_ui->w-2)len=p_ui->w-2;
+ p_dst=p_field->text+(p_ui->w-2)*(p_ui->h-3);
+ if(p_field->center) for(n=0;n<(p_ui->w-2-len)/2;n++) *p_dst++=' ';
+ memcpy(p_dst,p_line,len);
+ p_dst+=len;
+ while(p_dst<p_field->text+(p_ui->w-2)*(p_ui->h-2)) *p_dst++=' ';
+}
+
+void ui_field_add(uiobj_t*p_ui,char*p_text) {
+ field_t*p_field;
+ uint8_t len=0;
+ if(p_ui->type!=UI_FIELD) return;
+ p_field=p_ui->obj;
+ char *p_line=p_text;
+ if(!(p_ui->state&1)) p_ui->state|=4;
+ while(1) {
+ if(*p_text=='\n'||*p_text==0) {
+ if(len) ui_field_addline(p_ui,p_line,len);
+ if(*p_text==0) return;
+ len=0;
+ p_text++;
+ p_line=p_text;
+ } else {
+ p_text++;
+ len++;
+ }
+ }
+}
+
+uiobj_t* ui_field(uint8_t x,uint8_t y,uint8_t w,uint8_t h,char *caption,bool center,bool terminal) {
+ uiobj_t *p_ui=malloc(sizeof(uiobj_t));
+ field_t *p_obj=malloc(sizeof(field_t));
+ p_ui->x=x;
+ p_ui->y=y;
+ p_ui->w=w;
+ p_ui->h=h;
+ if(caption) {
+ p_obj->caption=malloc(strlen(caption)+1);
+ strcpy(p_obj->caption,caption);
+ } else p_obj->caption=NULL;
+ p_obj->center=center;
+ p_obj->terminal=terminal;
+ p_obj->text=malloc((w-2)*(h-2));
+ memset(p_obj->text,' ',(w-2)*(h-2));
+ p_ui->type=UI_FIELD;
+ p_ui->obj=p_obj;
+ return p_ui;
+}
+
+/** USER INTERFACE **************************************************/
+
+uiobj_t* ui_add(view_t *p_view,uiobj_t *p_add) {
+ uiobj_t *p_ui;
+ p_add->next=NULL;
+ p_add->view=p_view;
+ p_add->enabled=true;
+ p_add->link=NULL;
+ if(p_view->ui) {
+ p_ui=p_view->ui;
+ while(p_ui->next) p_ui=p_ui->next;
+ p_ui->next=p_add;
+ } else {
+ p_view->ui=p_add;
+ }
+ if(p_add->type==UI_LIST) {
+ p_ui=ui_button(p_add->x+p_add->w,p_add->y,"®");
+ ui_add(p_view,p_ui);
+ p_ui->link=p_add;
+ ui_enable(p_ui,false);
+ p_ui=ui_button(p_add->x+p_add->w,p_add->y+p_add->h-3,"¯");
+ ui_add(p_view,p_ui);
+ p_ui->link=p_add;
+ ui_enable(p_ui,false);
+ }
+ return p_add;
+}
+
+void ui_free_view(view_t *p_view) {
+ uiobj_t *p_ui,*p_nui;
+ void *p_obj;
+ p_ui=p_view->ui;
+ while(p_ui) {
+ p_obj=p_ui->obj;
+ switch(p_ui->type) {
+ case UI_FIELD:
+ if(((field_t*)p_obj)->caption) free(((field_t*)p_obj)->caption);
+ free(((field_t*)p_obj)->text);
+ break;
+ case UI_BUTTON:
+ free(((button_t*)p_obj)->caption);
+ break;
+ case UI_LIST:
+ ui_list_clear(p_ui);
+ free(((list_t*)p_obj)->caption);
+ break;
+ case UI_TEXT:
+ free(((text_t*)p_obj)->caption);
+ free(((text_t*)p_obj)->text);
+ break;
+ }
+ free(p_obj);
+ p_nui=p_ui->next;
+ free(p_ui);
+ p_ui=p_nui;
+ }
+ free(p_view);
+}
+
+
+static void ui_refresh(view_t *p_view) {
+ uiobj_t *p_ui;
+ p_ui=p_view->ui;
+ while(p_ui) {
+ switch(p_ui->type) {
+ case UI_FIELD: field_draw(p_ui);
+ break;
+ case UI_BUTTON: button_draw(p_ui);
+ break;
+ case UI_LIST: list_draw(p_ui);
+ break;
+ case UI_TEXT: text_draw(p_ui);
+ break;
+ }
+ p_ui=p_ui->next;
+ }
+}
+
+static void ui_reset(view_t *p_view) {
+ uiobj_t *p_ui;
+ p_ui=p_view->ui;
+ p_view->focus=NULL;
+ while(p_ui) {
+ p_ui->state=1;
+ p_ui=p_ui->next;
+ }
+}
+
+static void ui_focusprev(view_t *p_view) {
+ uiobj_t *p_ui, *p_found=NULL;
+ p_ui=p_view->focus;
+ do {
+ if(p_ui==NULL) p_ui=p_view->ui;
+ else p_ui=p_ui->next;
+ if(p_ui&&p_ui!=p_view->focus) {
+ if(p_ui->enabled) {
+ switch(p_ui->type) {
+ case UI_TEXT:
+ p_found=p_ui;
+ break;
+ }
+ }
+ }
+ } while(p_ui!=p_view->focus);
+ if(p_found) {
+ p_view->focus=p_found;
+ switch(p_found->type) {
+ case UI_TEXT:
+ text_focus(p_found);
+ break;
+ }
+ }
+}
+
+static void ui_focusnext(view_t *p_view) {
+ uiobj_t *p_ui;
+ p_ui=p_view->focus;
+ do {
+ if(p_ui==NULL) p_ui=p_view->ui;
+ else p_ui=p_ui->next;
+ if(p_ui) {
+ if(p_ui->enabled) {
+ switch(p_ui->type) {
+ case UI_TEXT:
+ p_view->focus=p_ui;
+ text_focus(p_ui);
+ return;
+ }
+ }
+ }
+ } while(p_ui!=p_view->focus);
+}
+
+static uiobj_t *find(view_t *p_view,uint8_t x,uint8_t y) {
+ uiobj_t *p_ui;
+ p_ui=p_view->ui;
+ while(p_ui) {
+ if((p_ui->x+p_view->x)<=x&&(p_ui->x+p_ui->w+p_view->x)>x) {
+ if((p_ui->y+p_view->y)<=y&&(p_ui->y+p_ui->h+p_view->y)>y) {
+ if(p_ui->enabled) return p_ui;
+ }
+ }
+ p_ui=p_ui->next;
+ }
+ return NULL;
+}
+
+void ui_display(view_t *p_view,bool(*events)(SDL_Event *e)) {
+ bool done=false;
+ uint8_t x,y,lx,ly;
+ uiobj_t *p_ui_over=NULL,*p_ui,*p_ui_down=NULL;
+ SDL_Event e;
+#ifdef SDL2
+ bool drop=false;
+#endif
+ ui_reset(p_view);
+ ui_focusnext(p_view);
+ if(!p_view->fullscreen) {
+ r_white(p_view->x-3,p_view->y-3,p_view->w+6,p_view->h+6);
+ r_box(p_view->x-2,p_view->y-2,p_view->w+4,p_view->h+4,p_view->caption,0,3);
+ } else if(p_view->state==1) {
+ r_white(0,0,40,30);
+ p_view->state=2;
+ }
+ while(!done) {
+ SDL_mutexP(mx_ui);
+ ui_refresh(p_view);
+ if(p_view->fullscreen&p_view->state==0) p_view->state=1;
+ if(p_view->state==2) {
+ r_done(0,0,40,30);
+ p_view->state=1;
+ }
+ r_draw();
+ while(SDL_PollEvent(&e)) {
+ switch(e.type) {
+#ifdef SDL2
+ case SDL_DROPFILE:
+ done|=events(&e);
+ SDL_free(e.drop.file);
+ drop=true;
+ break;
+#endif
+ case SDL_KEYDOWN:
+ done|=events(&e);
+ if(e.key.keysym.sym==SDLK_ESCAPE) { //esc
+ if(p_view->cancel) {
+ if(p_view->cancel->enabled) {
+ e.type=UI_CLICK;
+ e.user.data1=p_view->cancel;
+ done|=events(&e);
+ }
+ }
+ } if(e.key.keysym.sym==SDLK_RETURN) { //enter
+ if(p_view->ok) {
+ if(p_view->ok->enabled) {
+ e.type=UI_CLICK;
+ e.user.data1=p_view->ok;
+ done|=events(&e);
+ }
+ }
+ } if(e.key.keysym.sym==SDLK_TAB) {
+ ui_focusnext(p_view);
+ } else {
+ if(p_view->focus) {
+ switch(p_view->focus->type) {
+ case UI_TEXT:
+ if(text_key(p_view->focus,e.key.keysym.sym)) {
+ e.type=UI_CHANGE;
+ e.user.data1=p_view->focus;
+ done|=events(&e);
+ }
+ break;
+ }
+ }
+ }
+ break;
+ case SDL_MOUSEMOTION:
+ x=e.motion.x>>4;
+ y=e.motion.y>>4;
+ p_ui=find(p_view,x,y);
+ if(p_ui!=p_ui_over) {
+ if(p_ui_down) {
+ if(p_ui==p_ui_down) {
+ r_offset(p_ui_down->x+p_view->x,p_ui_down->y+p_view->y,p_ui_down->w,p_ui_down->h,2,2);
+ } else {
+ r_offset(p_ui_down->x+p_view->x,p_ui_down->y+p_view->y,p_ui_down->w,p_ui_down->h,0,0);
+ }
+ } else {
+ if(p_ui_over) {
+ e.type=UI_MOUSEOUT;
+ e.user.data1=p_ui_over;
+ done|=events(&e);
+ }
+ if(p_ui) {
+ e.type=UI_MOUSEOVER;
+ e.user.data1=p_ui;
+ done|=events(&e);
+ if(p_ui->type==UI_BUTTON||p_ui->type==UI_TEXT) {
+ r_shine(p_ui->x+p_view->x,p_ui->y+p_view->y,p_ui->w,p_ui->h);
+ }
+ }
+ }
+ p_ui_over=p_ui;
+ }
+ if(p_ui) {
+ if(y!=ly&&p_ui->type==UI_LIST) {
+ if(x>p_ui->x+p_view->x&&x<p_ui->x+p_view->x+p_ui->w-1
+ &&y>p_ui->y+p_view->y&&y<p_ui->y+p_view->y+p_ui->h-1) {
+ r_shine(p_ui->x+p_view->x+1,y,p_ui->w-2,1);
+ }
+ }
+ }
+ lx=x;
+ ly=y;
+ break;
+ case SDL_MOUSEBUTTONDOWN:
+ if(e.button.button==1) {
+ x=e.motion.x>>4;
+ y=e.motion.y>>4;
+ p_ui_down=find(p_view,x,y);
+ if(p_ui_down) {
+ switch(p_ui_down->type) {
+ case UI_BUTTON: case UI_TEXT:
+ r_offset(p_ui->x+p_view->x,p_ui->y+p_view->y,p_ui->w,p_ui->h,2,2);
+ break;
+ case UI_LIST:
+ x-=p_ui->x+p_view->x;
+ y-=p_ui->y+p_view->y;
+ if(x>0&&x<p_ui->w-1&&y>0&&y<p_ui->h-1) {
+ if(ui_list_selectindex(p_ui,y-1)) {
+ e.type=UI_CHANGE;
+ e.user.data1=p_ui_down;
+ done|=events(&e);
+ }
+ }
+ p_ui_down=NULL;
+ default:
+ p_ui_down=NULL;
+ }
+ }
+ }
+ break;
+ case SDL_MOUSEBUTTONUP:
+ if(e.button.button==1) {
+ if(p_ui_down) {
+ r_offset(p_ui_down->x+p_view->x,p_ui_down->y+p_view->y,p_ui_down->w,p_ui_down->h,0,0);
+ if(p_ui_over==p_ui_down) {
+ e.type=UI_CLICK;
+ e.user.data1=p_ui_down;
+ done|=events(&e);
+ if(p_ui_down->type==UI_TEXT) {
+ p_view->focus=p_ui_down;
+ text_focus(p_ui_down);
+ }
+ if(p_ui_over->link) {
+ if(p_ui_over->link->type==UI_LIST) {
+ if(((button_t*)p_ui_over->obj)->caption[0]=='®') {
+ if(((list_t*)p_ui_over->link->obj)->top>0) {
+ list_scroll(p_ui_over->link,((list_t*)p_ui_over->link->obj)->top-1);
+ }
+ } else {
+ list_scroll(p_ui_over->link,((list_t*)p_ui_over->link->obj)->top+1);
+ }
+ }
+ }
+ }
+ p_ui_down=NULL;
+ }
+ }
+ break;
+ default:
+ done|=events(&e);
+ }
+ if(done) break;
+ }
+#ifdef SDL2
+ if(drop) {
+ e.type=SDL_DROPFILE;
+ e.drop.file=NULL;
+ done|=events(&e);
+ }
+#endif
+ SDL_mutexV(mx_ui);
+ SDL_Delay( 10 );
+ }
+ r_crem();
+}
View
109 gui/ui.h
@@ -0,0 +1,109 @@
+typedef struct listitem_t {
+ void *data;
+ char *text;
+ struct listitem_t *prev;
+ struct listitem_t *next;
+} listitem_t;
+
+typedef struct {
+ char *caption;
+ char *text;
+ bool valid;
+} text_t;
+
+typedef struct {
+ char *caption;
+ listitem_t *list;
+ uint16_t count;
+ listitem_t *selected;
+ uint16_t top;
+} list_t;
+
+typedef struct {
+ char *caption;
+} button_t;
+
+typedef struct {
+ char *caption;
+ char *text;
+ uint8_t center;
+ bool terminal;
+} field_t;
+
+typedef struct uiobj_t {
+ uint8_t x;
+ uint8_t y;
+ uint8_t w;
+ uint8_t h;
+ char type;
+ void *obj;
+ struct uiobj_t *next;
+ struct uiobj_t *link;
+ struct view_t *view;
+ uint8_t state;
+ bool enabled;
+} uiobj_t;
+
+typedef struct view_t {
+ uint8_t x;
+ uint8_t y;
+ uint8_t w;
+ uint8_t h;
+ char *caption;
+ bool fullscreen;
+ struct uiobj_t *ui;
+ uint8_t state;
+ struct uiobj_t *focus;
+ uiobj_t *ok;
+ uiobj_t *cancel;
+} view_t;
+
+enum {
+ UI_BUTTON='B',
+ UI_LIST='L',
+ UI_FIELD='F',
+ UI_TEXT='T',
+ UI_END=' '
+};
+
+enum {
+ UI_MOUSEOVER=SDL_USEREVENT,
+ UI_MOUSEOUT=SDL_USEREVENT+1,
+ UI_CLICK=SDL_USEREVENT+2,
+ UI_CHANGE=SDL_USEREVENT+3
+};
+
+extern SDL_mutex *mx_ui;
+
+void capstr(char *p_text);
+
+view_t* ui_fsview();
+view_t* ui_view(uint8_t w,uint8_t h,char *caption);
+void ui_free_view(view_t *p_view);
+
+uiobj_t* ui_text(uint8_t x,uint8_t y,uint8_t w,char *caption);
+void ui_text_set(uiobj_t *p_ui,char *p_text);
+char* ui_text_get(uiobj_t *p_ui);
+void ui_text_valid(uiobj_t *p_ui,bool valid);
+bool ui_text_isvalid(uiobj_t *p_ui);
+
+uiobj_t* ui_field(uint8_t x,uint8_t y,uint8_t w,uint8_t h,char *caption,bool center,bool terminal);
+void ui_field_add(uiobj_t *p_ui,char*p_text);
+
+uiobj_t* ui_button(uint8_t x,uint8_t y,char *caption);
+void ui_button_set(uiobj_t *p_ui,char *caption);
+
+uiobj_t* ui_list(uint8_t x,uint8_t y,uint8_t w,uint8_t h,char *caption);
+listitem_t* ui_list_add(uiobj_t *p_ui,char *text, size_t n_data);
+void ui_list_remove(uiobj_t *p_ui,listitem_t *p_item);
+void ui_list_clear(uiobj_t *p_ui);
+listitem_t* ui_list_index2item(uiobj_t *p_ui,uint16_t ix);
+uint16_t ui_list_item2index(uiobj_t *p_ui,listitem_t *p_i);
+listitem_t* ui_list_selected(uiobj_t *p_ui);
+uint16_t ui_list_selectedindex(uiobj_t *p_ui);
+bool ui_list_selectindex(uiobj_t *p_ui,uint8_t index);
+void ui_list_select(uiobj_t *p_ui,listitem_t *p_item);
+
+uiobj_t* ui_add(view_t *p_view,uiobj_t *p_add);
+void ui_display(view_t *p_view,bool(*events)(SDL_Event *e));
+void ui_free();
View
7 win-gui-make.bat
@@ -0,0 +1,7 @@
+@echo off
+echo [bin-win\gui_sdl12.exe] building sdl1.2 gui executable...
+gcc -g gui/*.c lib/src/*.c -I lib/include/ -mwindows -lmingw32 -lsdlmain -lsdl -lsetupapi -o bin-win\gui_sdl12.exe
+strip bin-win\gui_sdl12.exe
+echo [bin-win\gui.exe] building sdl2.0 gui executable...
+gcc -g gui/*.c lib/src/*.c -I lib/include/ -mwindows -lwinmm -lmingw32 -lsdl2main -lsdl2 -lsdl2.dll -lsetupapi -DSDL2 -lfreeimage -o bin-win\gui.exe
+strip bin-win\gui.exe
Please sign in to comment.
Something went wrong with that request. Please try again.