ui.c (12024B)
1 #define _DEFAULT_SOURCE 2 3 #include <dirent.h> 4 #include "fileops.h" 5 #include "animation.h" 6 #include "ui.h" 7 #include "spritesheet.h" 8 9 static int cols = 1; 10 static UIWindow *modal_win = NULL; 11 static UIImageDisplay *img_disp = NULL; 12 static UILabel *lbl_header = NULL; 13 static Animation *img = NULL; 14 15 static int FilelistFilter(const struct dirent *f) { 16 if (strncmp(f->d_name, ".", 255)==0) return 0; 17 if (f->d_type==DT_DIR) return 1; 18 //@todo not very efficient but dirent doesn't have the length :c 19 size_t len = strlen(f->d_name); 20 // checking for the ".webp" at the very end 21 if (len<6) return 0; 22 return strncmp(f->d_name+len-5, ".webp", 255)==0; 23 } 24 25 static int FilelistCompare(const struct dirent **a, const struct dirent **b) { 26 if ((*a)->d_type==DT_DIR && (*b)->d_type==DT_DIR) { 27 if (strncmp((*a)->d_name, "..", 255)==0) return -1; 28 else if (strncmp((*b)->d_name, "..", 255)==0) return 1; 29 else return alphasort(a, b); 30 } 31 if ((*a)->d_type==DT_DIR) return -1; 32 if ((*b)->d_type==DT_DIR) return 1; 33 return alphasort(a, b); 34 } 35 36 UIWindow * MainWindowCreate(const char *wname, int w, int h) { 37 //UIFont *font = UIFontActivate(UIFontCreate("../font.ttf", 19)); 38 //assert(font!=NULL); 39 UIWindow *win = UIWindowCreate(0, 0, wname, w, h); 40 win->e.messageUser = WinMainEvent; 41 UIPanel *panelv = UIPanelCreate(&win->e, UI_PANEL_GRAY|UI_PANEL_MEDIUM_SPACING); 42 lbl_header = UILabelCreate(&panelv->e, 0, "webp 2 spritesheet converter", -1); 43 44 UIPanel *panelh = UIPanelCreate(&panelv->e, UI_PANEL_GRAY|UI_PANEL_MEDIUM_SPACING|UI_PANEL_HORIZONTAL); 45 UILabel *label = UILabelCreate(&panelh->e, 0, "Size: 0x0px", -1); 46 UISlider *slider = UISliderCreate(&panelh->e, 0); 47 UIButton *btnopen = UIButtonCreate(&panelh->e, 0, "Open", -1); 48 btnopen->e.messageUser = ButtonOpenEvent; 49 UIButton *btnsave = UIButtonCreate(&panelh->e, 0, "Save", -1); 50 btnsave->e.messageUser = ButtonSaveEvent; 51 btnsave->e.cp = win; 52 UIButton *btn_exit = UIButtonCreate(&panelh->e, 0, "Exit", -1); 53 btn_exit->e.messageUser = ButtonCloseEvent; 54 55 img_disp = UIImageDisplayCreate(&panelv->e, UI_ELEMENT_V_FILL|UI_ELEMENT_H_FILL|UI_IMAGE_DISPLAY_INTERACTIVE|_UI_IMAGE_DISPLAY_ZOOM_FIT, NULL, 0, 0, 0); 56 img_disp->e.cp = label; 57 slider->e.messageUser = SliderEvent; 58 slider->e.cp = img_disp; 59 return win; 60 } 61 62 int WinModalEvent(UIElement *element, UIMessage msg, int di, void *dp) { 63 if (msg==UI_MSG_DESTROY) { 64 //printf("modal bye\n"); 65 assert(element==(UIElement *)modal_win); 66 modal_win = NULL; 67 } 68 return 0; 69 } 70 71 int ButtonDialogSaveEvent(UIElement *element, UIMessage msg, int di, void *dp) { 72 if (msg==UI_MSG_CLICKED) { 73 // get values of path and filename inputs 74 UITextbox *path_input = (UITextbox *)element->parent->children; 75 UITextbox *filename_input = (UITextbox *)path_input->e.next; 76 // printf("path_input: %p\nfilename_input: %p\n", path_input, filename_input); 77 // that printf might work incorrectly because path_input->string might not contain valid C string with \0 at the end 78 // printf("path_input: %s(%d)\nfilename_input: %s(%d)\n", path_input->string, path_input->bytes, filename_input->string, filename_input->bytes); 79 int path_len = path_input->bytes + filename_input->bytes + 2; // DIR_SEPARATOR and '\0' 80 // printf("path_len: %d\n", path_len); 81 char out_name[path_len]; 82 out_name[path_input->bytes] = DIR_SEPARATOR; 83 out_name[path_len-1] = '\0'; 84 memcpy(out_name, path_input->string, path_input->bytes); 85 memcpy(out_name+path_input->bytes+1, filename_input->string, filename_input->bytes); 86 // printf("strlen(out_name): %d\n", strlen(out_name)); 87 // printf("out_name: %s\n", out_name); 88 WebpWrite(out_name, img, cols); 89 // printf("save dialog window close\n"); 90 assert(element->window==modal_win); 91 UIElementDestroy(&element->window->e); 92 } 93 return 0; 94 } 95 96 int ButtonDialogOpenEvent(UIElement *element, UIMessage msg, int di, void *dp) { 97 if (msg==UI_MSG_CLICKED) { 98 // printf("open dialog window close\n"); 99 UITextbox *path_input = (UITextbox *)element->parent->children; 100 UITextbox *filename_input = (UITextbox *)path_input->e.next; 101 // printf("path_input: %p\nfilename_input: %p\n", path_input, filename_input); 102 // printf("path_input: %s(%d)\nfilename_input: %s(%d)\n", path_input->string, strlen(path_input->string), filename_input->string, strlen(filename_input->string)); 103 104 UIElementDestroy(&element->window->e); 105 106 int path_len = path_input->bytes + filename_input->bytes + 2; // DIR_SEPARATOR and '\0' 107 char filepath[path_len]; 108 filepath[path_input->bytes] = DIR_SEPARATOR; 109 filepath[path_len-1] = '\0'; 110 memcpy(filepath, path_input->string, path_input->bytes); 111 memcpy(filepath+path_input->bytes+1, filename_input->string, filename_input->bytes); 112 113 if (img != NULL) { 114 ImageUnload(&img); 115 assert(img==NULL); 116 } 117 img = ImageLoad(filepath); 118 assert(img!=NULL); 119 PreviewUpdate(img, img_disp); 120 UILabelSetContent(lbl_header, img->path, -1); 121 } 122 return 0; 123 } 124 125 int TableEvent(UIElement *element, UIMessage msg, int di, void *dp) { 126 static int selected = -1; 127 static struct dirent **filelist = NULL; 128 char *dir_name = element->cp; 129 UITable *table = (UITable *)element; 130 if (filelist==NULL) { 131 table->itemCount = scandir(dir_name, &filelist, FilelistFilter, FilelistCompare); 132 // printf("populated dir %s with %d items\n", dir_name, table->itemCount); 133 } 134 if (msg==UI_MSG_TABLE_GET_ITEM) { 135 UITableGetItem *m = (UITableGetItem *)dp; 136 m->isSelected = selected==m->index; 137 bool is_dir = filelist[m->index]->d_type==DT_DIR; 138 //printf("render %s (%d)\n", filelist[m->index]->d_name, m->bufferBytes); 139 int ret = snprintf(m->buffer, m->bufferBytes, is_dir?"[%s]":"%s", filelist[m->index]->d_name); 140 //printf("%s - %d (%d)\n", filelist[m->index]->d_name, ret, m->bufferBytes); 141 return ret; 142 } else if (msg==UI_MSG_CLICKED) { 143 int hit = UITableHitTest(table, element->window->cursorX, element->window->cursorY); 144 if (hit!=-1 && selected==hit) { 145 if (filelist[hit]->d_type==DT_DIR) { 146 char newpath[PATH_MAX]; 147 bzero(newpath, PATH_MAX); 148 strcpy(newpath, element->cp); 149 strcat(newpath, "/"); 150 strcat(newpath, filelist[hit]->d_name); 151 free(element->cp); 152 element->cp = realpath(newpath, NULL); 153 //free(filelist); 154 filelist = NULL; 155 selected = -1; 156 //@todo duplicated code 157 UIPanel *panel_out = (UIPanel *)element->parent; 158 UILabel *label = (UILabel *)panel_out->e.children; 159 UIPanel *panel_top = (UIPanel *)label->e.next; 160 UITextbox *path_input = (UITextbox *)panel_top->e.children; 161 UITextboxClear(path_input, false); 162 UITextboxReplace(path_input, (char *)element->cp, -1, false); 163 UIElementRepaint(&path_input->e, NULL); 164 UITableEnsureVisible(table, -1); 165 } 166 } else { 167 selected = hit; 168 if (!UITableEnsureVisible(table, selected)) { 169 UIElementRepaint(element, NULL); 170 } 171 //@todo remove copypasta 172 if (hit!=-1 && filelist[hit]->d_type!=DT_DIR) { 173 UIPanel *panel_out = (UIPanel *)element->parent; 174 UILabel *label = (UILabel *)panel_out->e.children; 175 UIPanel *panel_top = (UIPanel *)label->e.next; 176 UITextbox *path_input = (UITextbox *)panel_top->e.children; 177 UITextbox *file_input = (UITextbox *)path_input->e.next; 178 UITextboxClear(path_input, false); 179 UITextboxClear(file_input, false); 180 UITextboxReplace(path_input, (char *)element->cp, -1, false); 181 UITextboxReplace(file_input, filelist[hit]->d_name, -1, false); 182 UIElementRepaint(&path_input->e, NULL); 183 UIElementRepaint(&file_input->e, NULL); 184 } 185 } 186 } else if (msg==UI_MSG_DESTROY) { 187 free(filelist); 188 filelist = NULL; 189 selected = -1; 190 UIElement *el = table->e.children; 191 printf("child %p\n", el); 192 while (el!=NULL) { 193 printf("child %p\n", el); 194 } 195 } else if (msg==UI_MSG_UPDATE) { 196 UITableResizeColumns(table); 197 } 198 return 0; 199 } 200 201 int ButtonCloseEvent(UIElement *element, UIMessage msg, int di, void *dp) { 202 if (msg==UI_MSG_CLICKED) { 203 UIElementDestroy(&element->window->e); 204 } 205 return 0; 206 } 207 208 void ShowModalWindow(UIWindow *parent, const char *def_dir, const char *def_file, CallbackFn cb) { 209 if (modal_win==NULL) { 210 // printf("create modal window\n"); 211 int w = UIElementMessage(&parent->e, UI_MSG_GET_WIDTH, 0, 0); 212 int h = UIElementMessage(&parent->e, UI_MSG_GET_HEIGHT, 0, 0); 213 modal_win = UIWindowCreate(parent, 0, def_file?"Save File":"Open File", w, h); 214 modal_win->e.messageUser = WinModalEvent; 215 UIPanel *panel_out = UIPanelCreate(&modal_win->e, UI_PANEL_GRAY|UI_PANEL_EXPAND); 216 UILabel *lbl_title = UILabelCreate(&panel_out->e, 0, def_file?"Save File":"Open File", -1); 217 UIPanel *panel_top = UIPanelCreate(&panel_out->e, UI_PANEL_GRAY|UI_PANEL_MEDIUM_SPACING|UI_PANEL_HORIZONTAL); 218 UITextbox *path_input = UITextboxCreate(&panel_top->e, UI_ELEMENT_DISABLED|UI_ELEMENT_H_FILL); 219 if (def_dir!=NULL) { 220 UITextboxReplace(path_input, def_dir, -1, false); 221 } 222 223 UITextbox *filename_input = UITextboxCreate(&panel_top->e, UI_ELEMENT_TAB_STOP|UI_ELEMENT_H_FILL); 224 225 printf("path_input: %p (%s)\nfilename_input: %p (%s)\n", path_input, def_dir, filename_input, def_file); 226 if (def_file!=NULL) { 227 UITextboxReplace(filename_input, def_file, -1, false); 228 } 229 230 UIButton *btn_save = UIButtonCreate(&panel_top->e, UI_ELEMENT_TAB_STOP, def_file?"Save":"Open", -1); 231 btn_save->e.messageUser = cb; 232 233 UIButton *btn_cancel = UIButtonCreate(&panel_top->e, UI_ELEMENT_TAB_STOP, "Cancel", -1); 234 btn_cancel->e.messageUser = ButtonCloseEvent; 235 236 UITable *table = UITableCreate(&panel_out->e, UI_ELEMENT_V_FILL, "Directory"); 237 table->itemCount = 1; // at least '..' element 238 // @todo setting the initial directory this way is 100% trashcan 239 char *init_path = NULL; 240 if (def_dir==NULL) { 241 init_path = malloc(sizeof(char)*2); 242 init_path[0] = '.'; 243 init_path[1] = '\0'; 244 } else { 245 init_path = strndup(def_dir, PATH_MAX-1); 246 } 247 table->e.cp = (void *)init_path; 248 table->e.messageUser = TableEvent; 249 UITableResizeColumns(table); 250 } else { 251 UIElementFocus(&modal_win->e); 252 } 253 } 254 255 int ButtonSaveEvent(UIElement *element, UIMessage msg, int di, void *dp) { 256 if (msg==UI_MSG_CLICKED && img!=NULL) { 257 // printf("save button clicked\n"); 258 char fname[strlen(img->filename)+7]; 259 int n = snprintf(fname, NAME_MAX, "atlas_%s", img->filename); 260 assert(n>0); 261 ShowModalWindow(element->window, img->dirname, fname, ButtonDialogSaveEvent); 262 } 263 return 0; 264 } 265 266 int ButtonOpenEvent(UIElement *element, UIMessage msg, int di, void *dp) { 267 if (msg==UI_MSG_CLICKED) { 268 // printf("open button clicked\n"); 269 ShowModalWindow(element->window, getenv("HOME"), NULL, ButtonDialogOpenEvent); 270 } 271 return 0; 272 } 273 274 int SliderEvent(UIElement *element, UIMessage msg, int di, void *dp) { 275 if (msg==UI_MSG_VALUE_CHANGED) { 276 if (img==NULL) return 1; 277 278 float slider_pos = ((UISlider *)element)->position; 279 float step = 1.0f / (float)img->frame_count; 280 int new_cols = (int)(slider_pos / step); 281 if (new_cols>0 && cols!=new_cols) { 282 //printf("new_cols: %d\n", new_cols); 283 cols = new_cols; 284 PreviewUpdate(img, element->cp); 285 } 286 } 287 288 return 0; 289 } 290 291 int WinMainEvent(UIElement *element, UIMessage msg, int di, void *dp) { 292 if (msg==UI_MSG_DESTROY) { 293 printf("main win bye\n"); 294 free(img); 295 exit(0); 296 } 297 return 0; 298 } 299 300 void PreviewUpdate(Animation *img, UIImageDisplay *img_disp) { 301 // gen new spritesheet and refresh the preview 302 Spritesheet ss = SpritesheetGen(img, cols); 303 //printf("spritesheet width: %d, height: %d, stride: %d, len: %zu\n", ss.width, ss.height, ss.stride, ss.len); 304 305 uint32_t *frame0 = calloc(ss.width*ss.height, sizeof(uint32_t)); 306 assert(frame0!=NULL); 307 308 for (uint32_t i=0; i<ss.width*ss.height; ++i) { 309 frame0[i] = UI_COLOR_FROM_RGBA(ss.data[i*4+0], ss.data[i*4+1], ss.data[i*4+2], ss.data[i*4+3]); 310 } 311 UIImageDisplaySetContent(img_disp, frame0, ss.width, ss.height, ss.stride); 312 UIElementRefresh(img_disp->e.parent); 313 UIElementRefresh(&img_disp->e); 314 315 free(frame0); 316 free(ss.data); 317 318 UILabel *label = (UILabel *)img_disp->e.cp; 319 char label_text[256] = {0}; 320 snprintf((char * restrict)&label_text, 255, "Size: %4dx%4dpx", ss.width, ss.height); 321 UILabelSetContent(label, label_text, -1); 322 UIElementRefresh(label->e.parent); 323 }