comparison postdog/main.c @ 118:249881ceff7b

[PostDog] Updated some core logic. Will create a bookmark for postdog until the launch as this is annoying to deal with.
author June Park <parkjune1995@gmail.com>
date Wed, 07 Jan 2026 13:24:38 -0800
parents b91f2dd6f84d
children 7387eec8e7f8
comparison
equal deleted inserted replaced
117:b91f2dd6f84d 118:249881ceff7b
44 size_t size; 44 size_t size;
45 } ResponseBuffer; 45 } ResponseBuffer;
46 46
47 typedef struct { 47 typedef struct {
48 char *filename; 48 char *filename;
49 char *title;
49 Rectangle rect; 50 Rectangle rect;
50 long time_modified; 51 long time_modified;
51 boolean deleted; 52 boolean deleted;
52 } HistoryItem; 53 } HistoryItem;
53 54
67 68
68 static uint32 counter = 0; 69 static uint32 counter = 0;
69 HistoryItem *history_items = NULL; 70 HistoryItem *history_items = NULL;
70 HistoryItem *new_history_items = NULL; 71 HistoryItem *new_history_items = NULL;
71 72
73 // Global UI state
74 char *url_input_text = NULL;
75 char *url_result_text = NULL;
76 char **url_body_map = NULL;
77 int active_method_dropdown = 0;
78
72 int CompareHistoryItemsByDate(const void *a, const void *b) { 79 int CompareHistoryItemsByDate(const void *a, const void *b) {
73 HistoryItem *itemA = (HistoryItem *)a; 80 HistoryItem *itemA = (HistoryItem *)a;
74 HistoryItem *itemB = (HistoryItem *)b; 81 HistoryItem *itemB = (HistoryItem *)b;
75 return (itemB->time_modified - itemA->time_modified); 82 return (itemB->time_modified - itemA->time_modified);
83 }
84
85 char *PostDog_Extract_Title(const char *filename)
86 {
87 char full_file_path[512] = {0};
88 snprintf(full_file_path, 512, "%s/%s", POSTDOG_PATHS, filename);
89 FILE *file = fopen(full_file_path, "r");
90 if (!file)
91 return strdup(filename);
92
93 char *title = malloc(sizeof(char) * 512);
94 if (!fgets(title, 512, file)) {
95 fclose(file);
96 return strdup(filename);
97 }
98
99 return title;
76 } 100 }
77 101
78 // TODO: Make this into generic fucntion so I can use it across different thing. 102 // TODO: Make this into generic fucntion so I can use it across different thing.
79 void PostDog_List_Directory(const char *path, HistoryItem **p_file_arr) 103 void PostDog_List_Directory(const char *path, HistoryItem **p_file_arr)
80 { 104 {
89 printf("Directory is empty or cannot be read.\n"); 113 printf("Directory is empty or cannot be read.\n");
90 } else { 114 } else {
91 do { 115 do {
92 HistoryItem item = {0}; 116 HistoryItem item = {0};
93 item.filename = strdup(fileinfo.name); 117 item.filename = strdup(fileinfo.name);
94 item.time_modified = fileinfo.time_write; 118 item.title = PostDog_Extract_Title(fileinfo.name);
119 item.time_modified = fileinfo.time_write;
95 item.deleted = FALSE; 120 item.deleted = FALSE;
96 Dowa_Array_Push(file_arr, item); 121 Dowa_Array_Push(file_arr, item);
97 } while (_findnext(handle, &fileinfo) == 0); 122 } while (_findnext(handle, &fileinfo) == 0);
98 _findclose(handle); 123 _findclose(handle);
99 } 124 }
111 snprintf(full_path, sizeof(full_path), "%s/%s", path, entry->d_name); 136 snprintf(full_path, sizeof(full_path), "%s/%s", path, entry->d_name);
112 if (stat(full_path, &file_stat) == 0) 137 if (stat(full_path, &file_stat) == 0)
113 { 138 {
114 HistoryItem item = {0}; 139 HistoryItem item = {0};
115 item.filename = strdup(entry->d_name); 140 item.filename = strdup(entry->d_name);
141 item.title = PostDog_Extract_Title(entry->d_name);
116 item.time_modified = file_stat.st_mtime; 142 item.time_modified = file_stat.st_mtime;
117 item.deleted = FALSE; 143 item.deleted = FALSE;
118 Dowa_Array_Push(file_arr, item); 144 Dowa_Array_Push(file_arr, item);
119 } 145 }
120 } 146 }
186 } 212 }
187 fwrite(values, 1, strlen(values), file); 213 fwrite(values, 1, strlen(values), file);
188 fclose(file); 214 fclose(file);
189 } 215 }
190 216
191 void PostDog_Request_SaveFile( 217 void PostDog_Request_SaveFile(void)
192 const char *url, 218 {
193 const char *method, 219 const char *method = PostDog_Enum_To_String(active_method_dropdown);
194 const char *headers,
195 const char *body,
196 const char *response)
197 {
198 size_t new_file_size = 1024 * 1024; 220 size_t new_file_size = 1024 * 1024;
199 Dowa_Arena *arena = Dowa_Arena_Create(1024 * 1024 * 2); 221 Dowa_Arena *arena = Dowa_Arena_Create(1024 * 1024 * 2);
200 char *new_file = Dowa_Arena_Allocate(arena, 1024 * 1024); 222 char *new_file = Dowa_Arena_Allocate(arena, 1024 * 1024);
223 char *title = malloc(strlen(method) + strlen(url_input_text) + 2);
224 sprintf(title, "%s %s", method, url_input_text);
201 snprintf( 225 snprintf(
202 new_file, 226 new_file,
203 new_file_size, 227 new_file_size,
204 "%s\n" 228 "%s\n"
205 "---\n" 229 "---\n"
207 "---\n" 231 "---\n"
208 "%s\n" 232 "%s\n"
209 "---\n" 233 "---\n"
210 "%s\n" 234 "%s\n"
211 "---\n" 235 "---\n"
236 "%s\n"
237 "---\n"
238 "%s\n"
239 "---\n"
240 "%s\n"
241 "---\n"
212 "%s\n", 242 "%s\n",
213 url, 243 title,
244 url_input_text,
214 method, 245 method,
215 headers, 246 url_body_map[TAB_HEADER],
216 body, 247 url_body_map[TAB_BODY],
217 response 248 url_body_map[TAB_GET_PARAMS],
249 url_body_map[TAB_BAR],
250 url_result_text
218 ); 251 );
219 char *filename = Dowa_Arena_Allocate(arena, 1024); 252 char *filename = Dowa_Arena_Allocate(arena, 1024);
220 if (!filename) 253 if (!filename)
221 { 254 {
222 perror("Error opening file"); 255 perror("Error opening file");
234 snprintf(filename, 1024, "%s.txt", uuid4); 267 snprintf(filename, 1024, "%s.txt", uuid4);
235 PostDog_History_CreateFile(filename, new_file); 268 PostDog_History_CreateFile(filename, new_file);
236 269
237 HistoryItem item = {0}; 270 HistoryItem item = {0};
238 item.filename = strdup(filename); 271 item.filename = strdup(filename);
272 item.title = title;
239 item.deleted = FALSE; 273 item.deleted = FALSE;
240 memcpy(item.filename, filename, strlen(filename) + 1);
241 Dowa_Array_Push(new_history_items, item); 274 Dowa_Array_Push(new_history_items, item);
242 275
243 Dowa_Arena_Free(arena); 276 Dowa_Arena_Free(arena);
244 } 277 }
245 278
261 buf->data[buf->size] = 0; 294 buf->data[buf->size] = 0;
262 295
263 return real_size; 296 return real_size;
264 } 297 }
265 298
266 int PostDog_Http_Request( 299 int PostDog_Http_Request(void)
267 const char *url, 300 {
268 const char *method, 301 const char *method = PostDog_Enum_To_String(active_method_dropdown);
269 const char *headers,
270 const char *body,
271 char *response, size_t response_size)
272 {
273 CURL *curl; 302 CURL *curl;
274 CURLcode res; 303 CURLcode res;
275 ResponseBuffer buffer = { .data = malloc(1), .size = 0 }; 304 ResponseBuffer buffer = { .data = malloc(1), .size = 0 };
276 305
277 response[0] = '\n'; 306 url_result_text[0] = '\n';
278 307
279 if (buffer.data == NULL) 308 if (buffer.data == NULL)
280 { 309 {
281 snprintf(response, response_size, "Error: Failed to allocate memory"); 310 snprintf(url_result_text, RESULT_BUFFER_LENGTH, "Error: Failed to allocate memory");
282 return -1; 311 return -1;
283 } 312 }
284 buffer.data[0] = '\0'; 313 buffer.data[0] = '\0';
285 314
286 curl_global_init(CURL_GLOBAL_DEFAULT); 315 curl_global_init(CURL_GLOBAL_DEFAULT);
289 if (curl) 318 if (curl)
290 { 319 {
291 struct curl_slist *headerList = NULL; 320 struct curl_slist *headerList = NULL;
292 321
293 // Set URL 322 // Set URL
294 curl_easy_setopt(curl, CURLOPT_URL, url); 323 curl_easy_setopt(curl, CURLOPT_URL, url_input_text);
295 324
296 // Set HTTP method 325 // Set HTTP method
297 if (strcmp(method, "POST") == 0) 326 if (strcmp(method, "POST") == 0)
298 { 327 {
299 curl_easy_setopt(curl, CURLOPT_POST, 1L); 328 curl_easy_setopt(curl, CURLOPT_POST, 1L);
300 if (body && strlen(body) > 0) 329 if (url_body_map[TAB_BODY] && strlen(url_body_map[TAB_BODY]) > 0)
301 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body); 330 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, url_body_map[TAB_BODY]);
302 } 331 }
303 else if (strcmp(method, "PUT") == 0) 332 else if (strcmp(method, "PUT") == 0)
304 { 333 {
305 curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT"); 334 curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
306 if (body && strlen(body) > 0) 335 if (url_body_map[TAB_BODY] && strlen(url_body_map[TAB_BODY]) > 0)
307 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body); 336 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, url_body_map[TAB_BODY]);
308 } 337 }
309 else if (strcmp(method, "DELETE") == 0) 338 else if (strcmp(method, "DELETE") == 0)
310 { 339 {
311 curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE"); 340 curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
312 } 341 }
313 // Default is GET 342 // Default is GET
314 343
315 // Parse and add headers 344 // Parse and add headers
316 if (headers && strlen(headers) > 0) 345 if (url_body_map[TAB_HEADER] && strlen(url_body_map[TAB_HEADER]) > 0)
317 { 346 {
318 char *headersCopy = strdup(headers); 347 char *headersCopy = strdup(url_body_map[TAB_HEADER]);
319 char *line = strtok(headersCopy, "\n"); 348 char *line = strtok(headersCopy, "\n");
320 while (line != NULL) { 349 while (line != NULL) {
321 // Trim whitespace
322 while (*line == ' ' || *line == '\t') line++; 350 while (*line == ' ' || *line == '\t') line++;
323 if (strlen(line) > 0) 351 if (strlen(line) > 0)
324 headerList = curl_slist_append(headerList, line); 352 headerList = curl_slist_append(headerList, line);
325 line = strtok(NULL, "\n"); 353 line = strtok(NULL, "\n");
326 } 354 }
332 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, Postdog_Curl_Callback); 360 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, Postdog_Curl_Callback);
333 curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&buffer); 361 curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&buffer);
334 362
335 // Follow redirects 363 // Follow redirects
336 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); 364 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
337 // Set timeout
338 curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30L); 365 curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30L);
339 // Perform request
340 res = curl_easy_perform(curl); 366 res = curl_easy_perform(curl);
341 367
342 if (res != CURLE_OK) 368 if (res != CURLE_OK)
343 snprintf(response, response_size, "Error: %s\n", curl_easy_strerror(res)); 369 snprintf(url_result_text, RESULT_BUFFER_LENGTH, "Error: %s\n", curl_easy_strerror(res));
344 else 370 else
345 { 371 {
346 long response_code; 372 long response_code;
347 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); 373 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
348 374
349 if (buffer.size > response_size) 375 if (buffer.size > RESULT_BUFFER_LENGTH)
350 printf("TODO: Realloc\n"); 376 printf("TODO: Realloc\n");
351 377
352 snprintf(response, response_size, "HTTP Status: %ld\n\n%s", 378 snprintf(url_result_text, RESULT_BUFFER_LENGTH, "HTTP Status: %ld\n\n%s",
353 response_code, buffer.data ? buffer.data : ""); 379 response_code, buffer.data ? buffer.data : "");
354 } 380 }
355 381
356 // Cleanup
357 if (headerList) curl_slist_free_all(headerList); 382 if (headerList) curl_slist_free_all(headerList);
358 curl_easy_cleanup(curl); 383 curl_easy_cleanup(curl);
359 } 384 }
360 else 385 else
361 snprintf(response, response_size, "Error: Failed to initialize curl"); 386 snprintf(url_result_text, RESULT_BUFFER_LENGTH, "Error: Failed to initialize curl");
362 387
363 free(buffer.data); 388 free(buffer.data);
364 curl_global_cleanup(); 389 curl_global_cleanup();
365 390
366 PostDog_Request_SaveFile( 391 PostDog_Request_SaveFile();
367 url,
368 method,
369 headers,
370 body,
371 response);
372 return 0; 392 return 0;
373 } 393 }
374 394
375 void PostDog_Update_URL(char **p_url_input_text, char* get_params) 395 void PostDog_Update_URL(void)
376 { 396 {
377 char *url_input_text = *p_url_input_text; 397 // Save existing query string if present
378
379 // Reset
380 char *question_mark = strchr(url_input_text, '?'); 398 char *question_mark = strchr(url_input_text, '?');
381 if (question_mark) 399 if (question_mark)
382 *question_mark = '\0'; 400 *question_mark = '\0';
383 401
384 int get_params_length = (int)strlen(get_params) ; 402 int get_params_length = (int)strlen(url_body_map[TAB_GET_PARAMS]);
385 if (get_params_length == 0) 403 if (get_params_length == 0)
386 return; 404 return;
387 405
388 char *separator = "?"; 406 char *separator = "?";
389 407
390 Dowa_Arena *arena = Dowa_Arena_Create(1024*1024); 408 Dowa_Arena *arena = Dowa_Arena_Create(1024*1024);
391 char **lines = Dowa_String_Split(get_params, "\n", get_params_length, 1, arena); 409 char **lines = Dowa_String_Split(url_body_map[TAB_GET_PARAMS], "\n", get_params_length, 1, arena);
392 for (int i = 0; i < Dowa_Array_Length(lines); i++) 410 for (int i = 0; i < Dowa_Array_Length(lines); i++)
393 { 411 {
394 char *line = lines[i]; 412 char *line = lines[i];
395 char **key_value = Dowa_String_Split(line, " ", (int)strlen(line), 1, arena); 413 char **key_value = Dowa_String_Split(line, " ", (int)strlen(line), 1, arena);
396 414
424 if (strstr(value, "DELETE")) 442 if (strstr(value, "DELETE"))
425 return 3; 443 return 3;
426 return 0; 444 return 0;
427 } 445 }
428 446
429 void PostDog_Params_Reset( 447 void PostDog_Params_Reset(void)
430 char **p_url_input_text, 448 {
431 int *p_active_method_dropdown, 449 url_input_text[0] = '\0';
432 char **url_body_map, 450 url_result_text[0] = '\0';
433 char **p_url_result_text
434 )
435 {
436 char *url_input_text = *p_url_input_text;
437 char *url_result_text = *p_url_result_text;
438 int active_method_dropdown = *p_active_method_dropdown;
439
440 url_input_text = "";
441 url_result_text = "";
442 active_method_dropdown = 0; 451 active_method_dropdown = 0;
443 for (int i = 0; i < Dowa_Array_Length(url_body_map); i++) 452 for (int i = 0; i < Dowa_Array_Length(url_body_map); i++)
444 url_body_map[i] = ""; 453 url_body_map[i][0] = '\0';
445 } 454 }
446 455
447 void PostDog_Load_File( 456 void PostDog_Load_File(const char *filename)
448 const char *filename, 457 {
449 char **p_url_input_text,
450 int *p_active_method_dropdown,
451 char **url_body_map,
452 char **p_url_result_text
453 ) {
454 char *url_input_text = *p_url_input_text;
455 char *url_result_text = *p_url_result_text;
456 int active_method_dropdown = *p_active_method_dropdown;
457
458 char full_file_path[512] = {0}; 458 char full_file_path[512] = {0};
459 snprintf(full_file_path, 512, "%s/%s", POSTDOG_PATHS, filename); 459 snprintf(full_file_path, 512, "%s/%s", POSTDOG_PATHS, filename);
460 FILE *file = fopen(full_file_path, "r"); 460 FILE *file = fopen(full_file_path, "r");
461 if (!file) 461 if (!file)
462 return; 462 return;
473 473
474 char **values = Dowa_String_Split(file_buffer, "---\n", file_size, 4, split_arena); 474 char **values = Dowa_String_Split(file_buffer, "---\n", file_size, 4, split_arena);
475 475
476 for (int i = 0; i < Dowa_Array_Length(values); i++) 476 for (int i = 0; i < Dowa_Array_Length(values); i++)
477 { 477 {
478 if (i == 0) 478 switch (i)
479 { 479 {
480 snprintf(url_input_text, strlen(values[i]) + 1, "%s", values[i]); 480 case 0: // Title - skip
481 url_input_text[strcspn(url_input_text, "\n")] = '\0'; 481 break;
482 } 482
483 else if (i == 1) 483 case 1: // URL
484 active_method_dropdown = PostDog_String_To_MethodEnum(values[i]); 484 snprintf(url_input_text, strlen(values[i]) + 1, "%s", values[i]);
485 else if (i <= 3) 485 url_input_text[strcspn(url_input_text, "\n")] = '\0';
486 { 486 break;
487 snprintf(url_body_map[i-2], strlen(values[i]) + 1, "%s", values[i]); 487
488 for (int j = strlen(values[i]); j > 0; j--) 488 case 2: // Method
489 active_method_dropdown = PostDog_String_To_MethodEnum(values[i]);
490 break;
491
492 case 3: // Headers (TAB_HEADER)
493 case 4: // Body (TAB_BODY)
494 case 5: // Get Params (TAB_GET_PARAMS)
495 case 6: // Bar (TAB_BAR)
489 { 496 {
490 if (url_body_map[i-2][j] == '\n') 497 int map_index = i - 3; // 3->0, 4->1, 5->2, 6->3
498 snprintf(url_body_map[map_index], strlen(values[i]) + 1, "%s", values[i]);
499 // Trim trailing newlines
500 for (int j = strlen(values[i]); j > 0; j--)
491 { 501 {
492 url_body_map[i-2][j] = '\0'; 502 if (url_body_map[map_index][j] == '\n')
493 break; 503 {
504 url_body_map[map_index][j] = '\0';
505 break;
506 }
494 } 507 }
508 break;
495 } 509 }
496 } 510
497 else 511 default: // Response (index 7+)
498 snprintf(url_result_text, strlen(values[i]) + 1, "%s", values[i]); 512 snprintf(url_result_text, strlen(values[i]) + 1, "%s", values[i]);
513 break;
514 }
499 } 515 }
500 516
501 Dowa_Arena_Free(init_arena); 517 Dowa_Arena_Free(init_arena);
502 Dowa_Arena_Free(split_arena); 518 Dowa_Arena_Free(split_arena);
503 } 519 }
593 Font customFont = LoadFontEx("postdog/Roboto-Regular.ttf", 20, 0, 0); 609 Font customFont = LoadFontEx("postdog/Roboto-Regular.ttf", 20, 0, 0);
594 GuiSetFont(customFont); 610 GuiSetFont(customFont);
595 GuiSetStyle(DEFAULT, TEXT_SIZE, 10); 611 GuiSetStyle(DEFAULT, TEXT_SIZE, 10);
596 Image logo_original = LoadImage("postdog/epi_all_colors.png"); 612 Image logo_original = LoadImage("postdog/epi_all_colors.png");
597 ImageResize(&logo_original, 60, 60); 613 ImageResize(&logo_original, 60, 60);
614 SetWindowIcon(logo_original);
598 Texture2D logo_texture = LoadTextureFromImage(logo_original); 615 Texture2D logo_texture = LoadTextureFromImage(logo_original);
599 UnloadImage(logo_original); 616 UnloadImage(logo_original);
600 617
601 // -- Starting pos ---// 618 // -- Starting pos ---//
602 Rectangle history_sidebar = { 0 }; 619 Rectangle history_sidebar = { 0 };
612 Rectangle url_text_bounds = { 0 }; 629 Rectangle url_text_bounds = { 0 };
613 Rectangle url_enter_button = { 0 }; 630 Rectangle url_enter_button = { 0 };
614 Rectangle method_dropdown = { 0 }; 631 Rectangle method_dropdown = { 0 };
615 632
616 633
617 char *url_input_text = (char *)malloc(sizeof(char) * URL_TEXT_BUFFER_LENGTH); 634 // Initialize global UI state
635 url_input_text = (char *)malloc(sizeof(char) * URL_TEXT_BUFFER_LENGTH);
618 snprintf(url_input_text, URL_TEXT_BUFFER_LENGTH, "https://httpbin.org/get"); 636 snprintf(url_input_text, URL_TEXT_BUFFER_LENGTH, "https://httpbin.org/get");
619 637
620 char **url_body_map = NULL;
621 Dowa_Array_Push(url_body_map, (char *)malloc(sizeof(char) * HEADER_BUFFER_LENGTH)); 638 Dowa_Array_Push(url_body_map, (char *)malloc(sizeof(char) * HEADER_BUFFER_LENGTH));
622 Dowa_Array_Push(url_body_map, (char *)malloc(sizeof(char) * BODY_BUFFER_LENGTH)); 639 Dowa_Array_Push(url_body_map, (char *)malloc(sizeof(char) * BODY_BUFFER_LENGTH));
623 Dowa_Array_Push(url_body_map, (char *)malloc(sizeof(char) * DEFAULT_TEXT_BUFFER_LENGTH)); 640 Dowa_Array_Push(url_body_map, (char *)malloc(sizeof(char) * DEFAULT_TEXT_BUFFER_LENGTH));
624 Dowa_Array_Push(url_body_map, (char *)malloc(sizeof(char) * DEFAULT_TEXT_BUFFER_LENGTH)); 641 Dowa_Array_Push(url_body_map, (char *)malloc(sizeof(char) * DEFAULT_TEXT_BUFFER_LENGTH));
625 642
626 snprintf(url_body_map[TAB_HEADER], HEADER_BUFFER_LENGTH, "Content-Type: application/json"); 643 snprintf(url_body_map[TAB_HEADER], HEADER_BUFFER_LENGTH, "Content-Type: application/json");
627 snprintf(url_body_map[TAB_BODY], HEADER_BUFFER_LENGTH, ""); 644 snprintf(url_body_map[TAB_BODY], HEADER_BUFFER_LENGTH, "");
628 645
629 char *url_result_text = (char *)malloc(sizeof(char) * RESULT_BUFFER_LENGTH); 646 url_result_text = (char *)malloc(sizeof(char) * RESULT_BUFFER_LENGTH);
630 647
631 int active_method_dropdown = 0;
632 bool method_edit = false; 648 bool method_edit = false;
633 649
634 int sendRequest; 650 int sendRequest;
635 651
636 // -- input --// 652 // -- input --//
688 704
689 int32 number_of_skipped_items = 0; 705 int32 number_of_skipped_items = 0;
690 for (int i = 0; i < total; i++) 706 for (int i = 0; i < total; i++)
691 { 707 {
692 HistoryItem *curr_history_items = i < new_history_items_length ? 708 HistoryItem *curr_history_items = i < new_history_items_length ?
693 &new_history_items[i] : &history_items[i - new_history_items_length]; 709 &new_history_items[i - new_history_items_length - 1] : &history_items[i - new_history_items_length];
694 710
695 if (curr_history_items->deleted) 711 if (curr_history_items->deleted)
696 { 712 {
697 number_of_skipped_items++; 713 number_of_skipped_items++;
698 continue; 714 continue;
812 }; 828 };
813 829
814 Rectangle source = { 0, 0, logo_texture.width, logo_texture.height }; 830 Rectangle source = { 0, 0, logo_texture.width, logo_texture.height };
815 DrawTexturePro(logo_texture, source, dest, (Vector2){0, 0}, 0.0f, WHITE); 831 DrawTexturePro(logo_texture, source, dest, (Vector2){0, 0}, 0.0f, WHITE);
816 832
817 // Draw history items with scissor mode for clipping
818 BeginScissorMode(history_list_area.x, history_list_area.y, history_list_area.width, history_list_area.height); 833 BeginScissorMode(history_list_area.x, history_list_area.y, history_list_area.width, history_list_area.height);
819 for (int i = 0; i < total; i++) 834 for (int i = 0; i < total; i++)
820 { 835 {
821 HistoryItem *curr_history_items = i < new_history_items_length ? 836 HistoryItem *curr_history_items = i < new_history_items_length ?
822 &new_history_items[i] : &history_items[i - new_history_items_length]; 837 &new_history_items[i - new_history_items_length - 1] : &history_items[i - new_history_items_length];
823 838
824 if (curr_history_items->deleted) 839 if (curr_history_items->deleted)
825 continue; 840 continue;
826 841
827 float diff = curr_history_items->rect.height*0.3; 842 float diff = curr_history_items->rect.height*0.3;
836 DrawRectangleRec(icon_area, Fade(YELLOW, 0.1f)); 851 DrawRectangleRec(icon_area, Fade(YELLOW, 0.1f));
837 852
838 Rectangle icon_area_left_column = LeftColumn(icon_area, 0.5, 0); 853 Rectangle icon_area_left_column = LeftColumn(icon_area, 0.5, 0);
839 Rectangle icon_area_right_column = RightColumn(icon_area, icon_area_left_column, 0); 854 Rectangle icon_area_right_column = RightColumn(icon_area, icon_area_left_column, 0);
840 855
841 GuiDrawText(curr_history_items->filename, AddPadding(filename_area, padding), TEXT_ALIGN_CENTER, RED); 856 GuiDrawText(curr_history_items->title, AddPadding(filename_area, padding), TEXT_ALIGN_CENTER, RED);
842 if (GuiButton(AddPaddingHorizontal(icon_area_left_column, padding), "view")) 857 if (GuiButton(AddPaddingHorizontal(icon_area_left_column, padding), "view"))
843 PostDog_Load_File( 858 PostDog_Load_File(curr_history_items->filename);
844 curr_history_items->filename,
845 &url_input_text,
846 &active_method_dropdown,
847 url_body_map,
848 &url_result_text
849 );
850 if (GuiButton(AddPaddingHorizontal(icon_area_right_column,padding), "delete")) 859 if (GuiButton(AddPaddingHorizontal(icon_area_right_column,padding), "delete"))
851 { 860 {
852 if (!remove(PostDog_Construct_URL(curr_history_items->filename))) 861 if (!remove(PostDog_Construct_URL(curr_history_items->filename)))
853 curr_history_items->deleted = TRUE; 862 curr_history_items->deleted = TRUE;
854 else 863 else
855 fprintf(stderr, "Wasn't able to delete file: %s \n", curr_history_items->filename); 864 fprintf(stderr, "Wasn't able to delete file: %s \n", curr_history_items->filename);
856 } 865 }
857 } 866 }
858 EndScissorMode(); 867 EndScissorMode();
859 868
860 // Draw scroll indicator for history
861 if (total > 0) 869 if (total > 0)
862 { 870 {
863 float content_height = total * (item_height + padding); 871 float content_height = total * (item_height + padding);
864 if (content_height > history_list_area.height) 872 if (content_height > history_list_area.height)
865 { 873 {
881 if (GuiTextBox(url_input_bounds, url_input_text, DEFAULT_TEXT_BUFFER_LENGTH, url_input_edit)) 889 if (GuiTextBox(url_input_bounds, url_input_text, DEFAULT_TEXT_BUFFER_LENGTH, url_input_edit))
882 url_input_edit = !url_input_edit; 890 url_input_edit = !url_input_edit;
883 891
884 sendRequest = GuiButton(url_enter_button, "ENTER"); 892 sendRequest = GuiButton(url_enter_button, "ENTER");
885 if (sendRequest) 893 if (sendRequest)
886 PostDog_Http_Request( 894 PostDog_Http_Request();
887 url_input_text,
888 PostDog_Enum_To_String(active_method_dropdown),
889 url_body_map[TAB_HEADER],
890 url_body_map[TAB_BODY],
891 url_result_text,
892 RESULT_BUFFER_LENGTH
893 );
894 if (GuiDropdownBox(method_dropdown, "GET;POST;PUT;DELETE", &active_method_dropdown, method_edit)) 895 if (GuiDropdownBox(method_dropdown, "GET;POST;PUT;DELETE", &active_method_dropdown, method_edit))
895 method_edit = !method_edit; 896 method_edit = !method_edit;
896 897
897 // Input Tabs Rect 898 // Input Tabs Rect
898 DrawRectangleRec(input_area, Fade(BLUE, 0.1f)); 899 DrawRectangleRec(input_area, Fade(BLUE, 0.1f));
899 DrawRectangleRec(input_tab, Fade(DARKBLUE, 0.1f)); 900 DrawRectangleRec(input_tab, Fade(DARKBLUE, 0.1f));
900 GuiSetStyle(TOGGLE, GROUP_PADDING, 0); 901 GuiSetStyle(TOGGLE, GROUP_PADDING, 0);
901 GuiDrawRectangle(input_body, 1, GetColor(GuiGetStyle(TEXTBOX, BORDER)), GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_PRESSED))); 902 GuiDrawRectangle(input_body, 1, GetColor(GuiGetStyle(TEXTBOX, BORDER)), GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_PRESSED)));
902 903
903 // Create scrollable input body with offset
904 BeginScissorMode(input_body.x, input_body.y, input_body.width, input_body.height); 904 BeginScissorMode(input_body.x, input_body.y, input_body.width, input_body.height);
905 Rectangle scrolled_input = AddPadding(input_body, padding * 2); 905 Rectangle scrolled_input = AddPadding(input_body, padding * 2);
906 scrolled_input.y += input_body_scroll_offset; 906 scrolled_input.y += input_body_scroll_offset;
907 scrolled_input.height = MAX_SCROLL_HEIGHT; 907 scrolled_input.height = MAX_SCROLL_HEIGHT;
908 if (JUNE_GuiTextBox(scrolled_input, url_body_map[active_input_tab], DEFAULT_TEXT_BUFFER_LENGTH, input_body_bool)) 908 if (JUNE_GuiTextBox(scrolled_input, url_body_map[active_input_tab], DEFAULT_TEXT_BUFFER_LENGTH, input_body_bool))
909 input_body_bool = !input_body_bool; 909 input_body_bool = !input_body_bool;
910 EndScissorMode(); 910 EndScissorMode();
911 911
912 // Draw scroll indicator for input body
913 if (input_body_scroll_offset < 0) { 912 if (input_body_scroll_offset < 0) {
914 float scrollbar_height = 50; // Fixed size indicator 913 float scrollbar_height = 10;
915 float max_scroll = 1000; // Estimated max scroll 914 float scrollbar_y = input_body.y - (input_body_scroll_offset / MAX_SCROLL_HEIGHT) * (input_body.height - scrollbar_height);
916 float scrollbar_y = input_body.y - (input_body_scroll_offset / max_scroll) * (input_body.height - scrollbar_height);
917 Rectangle scrollbar = { 915 Rectangle scrollbar = {
918 input_body.x + input_body.width - 5, 916 input_body.x + input_body.width - 5,
919 scrollbar_y, 917 scrollbar_y,
920 5, 918 5,
921 scrollbar_height 919 scrollbar_height
923 DrawRectangleRec(scrollbar, Fade(BLUE, 0.5f)); 921 DrawRectangleRec(scrollbar, Fade(BLUE, 0.5f));
924 } 922 }
925 923
926 GuiToggleGroup(input_tab_item, "Header;Body;Get Param;Bar", &active_input_tab); 924 GuiToggleGroup(input_tab_item, "Header;Body;Get Param;Bar", &active_input_tab);
927 925
928 PostDog_Update_URL(&url_input_text, url_body_map[TAB_GET_PARAMS]); 926 PostDog_Update_URL();
929 927
930 // Result Rect 928 // Result Rect
931 DrawRectangleRec(result_area, Fade(GREEN, 0.1f)); 929 DrawRectangleRec(result_area, Fade(GREEN, 0.1f));
932 DrawRectangleRec(result_body, Fade(DARKGREEN, 0.1f)); 930 DrawRectangleRec(result_body, Fade(DARKGREEN, 0.1f));
933 931
937 scrolled_result.y += result_body_scroll_offset; 935 scrolled_result.y += result_body_scroll_offset;
938 scrolled_result.height = MAX_SCROLL_HEIGHT; 936 scrolled_result.height = MAX_SCROLL_HEIGHT;
939 GuiTextBoxMulti(scrolled_result, url_result_text, RESULT_BUFFER_LENGTH, false); 937 GuiTextBoxMulti(scrolled_result, url_result_text, RESULT_BUFFER_LENGTH, false);
940 EndScissorMode(); 938 EndScissorMode();
941 939
942 // Draw scroll indicator for result body
943 if (result_body_scroll_offset < 0) { 940 if (result_body_scroll_offset < 0) {
944 float scrollbar_height = 50; // Fixed size indicator 941 float scrollbar_height = 10;
945 float max_scroll = 1000; // Estimated max scroll 942 float scrollbar_y = result_body.y - (result_body_scroll_offset / MAX_SCROLL_HEIGHT) * (result_body.height - scrollbar_height);
946 float scrollbar_y = result_body.y - (result_body_scroll_offset / max_scroll) * (result_body.height - scrollbar_height);
947 Rectangle scrollbar = { 943 Rectangle scrollbar = {
948 result_body.x + result_body.width - 5, 944 result_body.x + result_body.width - 5,
949 scrollbar_y, 945 scrollbar_y,
950 5, 946 5,
951 scrollbar_height 947 scrollbar_height