changeset 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 c39582f937e5
files postdog/main.c third_party/raylib/include/raygui.h
diffstat 2 files changed, 143 insertions(+), 125 deletions(-) [+]
line wrap: on
line diff
--- a/postdog/main.c	Wed Jan 07 05:02:45 2026 -0800
+++ b/postdog/main.c	Wed Jan 07 13:24:38 2026 -0800
@@ -46,6 +46,7 @@
 
 typedef struct {
   char *filename;
+  char *title; 
   Rectangle rect;
   long time_modified;
   boolean deleted;
@@ -69,10 +70,33 @@
 HistoryItem *history_items = NULL;
 HistoryItem *new_history_items = NULL;
 
+// Global UI state
+char *url_input_text = NULL;
+char *url_result_text = NULL;
+char **url_body_map = NULL;
+int active_method_dropdown = 0;
+
 int CompareHistoryItemsByDate(const void *a, const void *b) {
   HistoryItem *itemA = (HistoryItem *)a;
   HistoryItem *itemB = (HistoryItem *)b;
-  return (itemB->time_modified - itemA->time_modified); 
+  return (itemB->time_modified - itemA->time_modified);
+}
+
+char *PostDog_Extract_Title(const char *filename)
+{
+  char full_file_path[512] = {0};
+  snprintf(full_file_path, 512, "%s/%s", POSTDOG_PATHS, filename);
+  FILE *file = fopen(full_file_path, "r");
+  if (!file)
+    return strdup(filename);
+
+  char *title = malloc(sizeof(char) * 512);
+  if (!fgets(title, 512, file)) {
+    fclose(file);
+    return strdup(filename);
+  }
+
+  return title;
 }
 
 // TODO: Make this into generic fucntion so I can use it across different thing.
@@ -91,7 +115,8 @@
     do {
       HistoryItem item = {0};
       item.filename = strdup(fileinfo.name);
-      item.time_modified = fileinfo.time_write; 
+      item.title = PostDog_Extract_Title(fileinfo.name);
+      item.time_modified = fileinfo.time_write;
       item.deleted = FALSE;
       Dowa_Array_Push(file_arr, item);
     } while (_findnext(handle, &fileinfo) == 0);
@@ -113,6 +138,7 @@
     {
       HistoryItem item = {0};
       item.filename = strdup(entry->d_name);
+      item.title = PostDog_Extract_Title(entry->d_name);
       item.time_modified = file_stat.st_mtime;
       item.deleted = FALSE;
       Dowa_Array_Push(file_arr, item);
@@ -188,16 +214,14 @@
   fclose(file);
 }
 
-void PostDog_Request_SaveFile(
-    const char *url,
-    const char *method,
-    const char *headers,
-    const char *body, 
-    const char *response)
+void PostDog_Request_SaveFile(void)
 {
+  const char *method = PostDog_Enum_To_String(active_method_dropdown);
   size_t new_file_size = 1024 * 1024;
   Dowa_Arena *arena = Dowa_Arena_Create(1024 * 1024 * 2);
   char *new_file = Dowa_Arena_Allocate(arena, 1024 * 1024);
+  char *title = malloc(strlen(method) + strlen(url_input_text) + 2);
+  sprintf(title, "%s %s", method, url_input_text);
   snprintf(
       new_file,
       new_file_size,
@@ -209,12 +233,21 @@
       "---\n"
       "%s\n"
       "---\n"
+      "%s\n"
+      "---\n"
+      "%s\n"
+      "---\n"
+      "%s\n"
+      "---\n"
       "%s\n",
-      url,
+      title,
+      url_input_text,
       method,
-      headers,
-      body,
-      response
+      url_body_map[TAB_HEADER],
+      url_body_map[TAB_BODY],
+      url_body_map[TAB_GET_PARAMS],
+      url_body_map[TAB_BAR],
+      url_result_text
   );
   char *filename = Dowa_Arena_Allocate(arena, 1024);
   if (!filename)
@@ -236,8 +269,8 @@
 
   HistoryItem item = {0};
   item.filename = strdup(filename);
+  item.title = title;
   item.deleted = FALSE;
-  memcpy(item.filename, filename, strlen(filename) + 1);
   Dowa_Array_Push(new_history_items, item);
   
   Dowa_Arena_Free(arena);
@@ -263,22 +296,18 @@
   return real_size;
 }
 
-int PostDog_Http_Request(
-    const char *url,
-    const char *method,
-    const char *headers,
-    const char *body, 
-    char *response, size_t response_size)
+int PostDog_Http_Request(void)
 {
+  const char *method = PostDog_Enum_To_String(active_method_dropdown);
   CURL *curl;
   CURLcode res;
   ResponseBuffer buffer = { .data = malloc(1), .size = 0 };
 
-  response[0] = '\n';
+  url_result_text[0] = '\n';
 
   if (buffer.data == NULL)
   {
-    snprintf(response, response_size, "Error: Failed to allocate memory");
+    snprintf(url_result_text, RESULT_BUFFER_LENGTH, "Error: Failed to allocate memory");
     return -1;
   }
   buffer.data[0] = '\0';
@@ -291,20 +320,20 @@
     struct curl_slist *headerList = NULL;
 
     // Set URL
-    curl_easy_setopt(curl, CURLOPT_URL, url);
+    curl_easy_setopt(curl, CURLOPT_URL, url_input_text);
 
     // Set HTTP method
     if (strcmp(method, "POST") == 0)
     {
       curl_easy_setopt(curl, CURLOPT_POST, 1L);
-      if (body && strlen(body) > 0)
-        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body);
-    } 
+      if (url_body_map[TAB_BODY] && strlen(url_body_map[TAB_BODY]) > 0)
+        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, url_body_map[TAB_BODY]);
+    }
     else if (strcmp(method, "PUT") == 0)
     {
       curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
-      if (body && strlen(body) > 0)
-        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body);
+      if (url_body_map[TAB_BODY] && strlen(url_body_map[TAB_BODY]) > 0)
+        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, url_body_map[TAB_BODY]);
     }
     else if (strcmp(method, "DELETE") == 0)
     {
@@ -313,12 +342,11 @@
     // Default is GET
 
     // Parse and add headers
-    if (headers && strlen(headers) > 0)
+    if (url_body_map[TAB_HEADER] && strlen(url_body_map[TAB_HEADER]) > 0)
     {
-      char *headersCopy = strdup(headers);
+      char *headersCopy = strdup(url_body_map[TAB_HEADER]);
       char *line = strtok(headersCopy, "\n");
       while (line != NULL) {
-        // Trim whitespace
         while (*line == ' ' || *line == '\t') line++;
         if (strlen(line) > 0)
           headerList = curl_slist_append(headerList, line);
@@ -334,61 +362,51 @@
 
     // Follow redirects
     curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
-    // Set timeout
     curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30L);
-    // Perform request
     res = curl_easy_perform(curl);
 
     if (res != CURLE_OK)
-      snprintf(response, response_size, "Error: %s\n", curl_easy_strerror(res));
+      snprintf(url_result_text, RESULT_BUFFER_LENGTH, "Error: %s\n", curl_easy_strerror(res));
     else
     {
       long response_code;
       curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
 
-      if (buffer.size > response_size)
+      if (buffer.size > RESULT_BUFFER_LENGTH)
         printf("TODO: Realloc\n");
 
-      snprintf(response, response_size, "HTTP Status: %ld\n\n%s",
+      snprintf(url_result_text, RESULT_BUFFER_LENGTH, "HTTP Status: %ld\n\n%s",
                response_code, buffer.data ? buffer.data : "");
     }
 
-    // Cleanup
     if (headerList) curl_slist_free_all(headerList);
     curl_easy_cleanup(curl);
   }
   else
-    snprintf(response, response_size, "Error: Failed to initialize curl");
+    snprintf(url_result_text, RESULT_BUFFER_LENGTH, "Error: Failed to initialize curl");
 
   free(buffer.data);
   curl_global_cleanup();
 
-  PostDog_Request_SaveFile(
-    url,
-    method,
-    headers,
-    body,
-    response);
+  PostDog_Request_SaveFile();
   return 0;
 }
 
-void PostDog_Update_URL(char **p_url_input_text, char* get_params)
+void PostDog_Update_URL(void)
 {
-  char *url_input_text = *p_url_input_text;
-
-  // Reset 
+  // Save existing query string if present
   char *question_mark = strchr(url_input_text, '?');
   if (question_mark)
     *question_mark = '\0';
 
-  int get_params_length = (int)strlen(get_params) ;
+  int get_params_length = (int)strlen(url_body_map[TAB_GET_PARAMS]);
   if (get_params_length == 0)
     return;
 
   char *separator = "?";
 
   Dowa_Arena *arena = Dowa_Arena_Create(1024*1024);
-  char **lines = Dowa_String_Split(get_params, "\n", get_params_length, 1, arena);
+  char **lines = Dowa_String_Split(url_body_map[TAB_GET_PARAMS], "\n", get_params_length, 1, arena);
   for (int i = 0; i < Dowa_Array_Length(lines); i++)
   {
     char *line = lines[i];
@@ -426,35 +444,17 @@
   return 0;
 }
 
-void PostDog_Params_Reset(
-    char **p_url_input_text,
-    int  *p_active_method_dropdown,
-    char **url_body_map,
-    char **p_url_result_text
-)
+void PostDog_Params_Reset(void)
 {
-  char *url_input_text = *p_url_input_text;
-  char *url_result_text = *p_url_result_text;
-  int active_method_dropdown = *p_active_method_dropdown;
-
-  url_input_text = "";
-  url_result_text = "";
+  url_input_text[0] = '\0';
+  url_result_text[0] = '\0';
   active_method_dropdown = 0;
   for (int i = 0; i < Dowa_Array_Length(url_body_map); i++)
-    url_body_map[i] = "";
+    url_body_map[i][0] = '\0';
 }
 
-void PostDog_Load_File(
-    const char *filename,
-    char **p_url_input_text,
-    int  *p_active_method_dropdown,
-    char **url_body_map,
-    char **p_url_result_text
-) { 
-  char *url_input_text = *p_url_input_text;
-  char *url_result_text = *p_url_result_text;
-  int active_method_dropdown = *p_active_method_dropdown;
-
+void PostDog_Load_File(const char *filename)
+{
   char full_file_path[512] = {0};
   snprintf(full_file_path, 512, "%s/%s", POSTDOG_PATHS, filename);
   FILE *file = fopen(full_file_path, "r");
@@ -475,27 +475,43 @@
 
   for (int i = 0; i < Dowa_Array_Length(values); i++)
   {
-    if (i == 0)
-    {
-      snprintf(url_input_text, strlen(values[i]) + 1, "%s", values[i]);
-      url_input_text[strcspn(url_input_text, "\n")] = '\0';
-    }
-    else if (i == 1)
-      active_method_dropdown = PostDog_String_To_MethodEnum(values[i]);
-    else if (i <= 3)
+    switch (i)
     {
-      snprintf(url_body_map[i-2], strlen(values[i]) + 1, "%s", values[i]);
-      for (int j = strlen(values[i]); j > 0; j--)
+      case 0:  // Title - skip
+        break;
+
+      case 1:  // URL
+        snprintf(url_input_text, strlen(values[i]) + 1, "%s", values[i]);
+        url_input_text[strcspn(url_input_text, "\n")] = '\0';
+        break;
+
+      case 2:  // Method
+        active_method_dropdown = PostDog_String_To_MethodEnum(values[i]);
+        break;
+
+      case 3:  // Headers (TAB_HEADER)
+      case 4:  // Body (TAB_BODY)
+      case 5:  // Get Params (TAB_GET_PARAMS)
+      case 6:  // Bar (TAB_BAR)
       {
-        if (url_body_map[i-2][j] == '\n')
+        int map_index = i - 3;  // 3->0, 4->1, 5->2, 6->3
+        snprintf(url_body_map[map_index], strlen(values[i]) + 1, "%s", values[i]);
+        // Trim trailing newlines
+        for (int j = strlen(values[i]); j > 0; j--)
         {
-          url_body_map[i-2][j] = '\0';
-          break;
+          if (url_body_map[map_index][j] == '\n')
+          {
+            url_body_map[map_index][j] = '\0';
+            break;
+          }
         }
+        break;
       }
+
+      default:  // Response (index 7+)
+        snprintf(url_result_text, strlen(values[i]) + 1, "%s", values[i]);
+        break;
     }
-    else
-      snprintf(url_result_text, strlen(values[i]) + 1, "%s", values[i]);
   }
 
   Dowa_Arena_Free(init_arena);
@@ -595,6 +611,7 @@
   GuiSetStyle(DEFAULT, TEXT_SIZE, 10);
   Image logo_original = LoadImage("postdog/epi_all_colors.png");
   ImageResize(&logo_original, 60, 60);
+  SetWindowIcon(logo_original);
   Texture2D logo_texture = LoadTextureFromImage(logo_original); 
   UnloadImage(logo_original);
 
@@ -614,10 +631,10 @@
   Rectangle method_dropdown = { 0 };
 
 
-  char *url_input_text = (char *)malloc(sizeof(char) * URL_TEXT_BUFFER_LENGTH);
+  // Initialize global UI state
+  url_input_text = (char *)malloc(sizeof(char) * URL_TEXT_BUFFER_LENGTH);
   snprintf(url_input_text, URL_TEXT_BUFFER_LENGTH, "https://httpbin.org/get");
 
-  char **url_body_map = NULL;
   Dowa_Array_Push(url_body_map, (char *)malloc(sizeof(char) * HEADER_BUFFER_LENGTH));
   Dowa_Array_Push(url_body_map, (char *)malloc(sizeof(char) * BODY_BUFFER_LENGTH));
   Dowa_Array_Push(url_body_map, (char *)malloc(sizeof(char) * DEFAULT_TEXT_BUFFER_LENGTH));
@@ -626,9 +643,8 @@
   snprintf(url_body_map[TAB_HEADER], HEADER_BUFFER_LENGTH, "Content-Type: application/json");
   snprintf(url_body_map[TAB_BODY], HEADER_BUFFER_LENGTH, "");
 
-  char *url_result_text = (char *)malloc(sizeof(char) * RESULT_BUFFER_LENGTH);
+  url_result_text = (char *)malloc(sizeof(char) * RESULT_BUFFER_LENGTH);
 
-  int active_method_dropdown = 0;
   bool method_edit = false;
 
   int sendRequest;
@@ -690,7 +706,7 @@
     for (int i = 0; i < total; i++)
     {
       HistoryItem *curr_history_items = i < new_history_items_length ?
-        &new_history_items[i] : &history_items[i - new_history_items_length];
+        &new_history_items[i - new_history_items_length - 1] : &history_items[i - new_history_items_length];
 
       if (curr_history_items->deleted)
       {
@@ -814,12 +830,11 @@
       Rectangle source = { 0, 0, logo_texture.width, logo_texture.height };
       DrawTexturePro(logo_texture, source, dest, (Vector2){0, 0}, 0.0f, WHITE);
 
-      // Draw history items with scissor mode for clipping
       BeginScissorMode(history_list_area.x, history_list_area.y, history_list_area.width, history_list_area.height);
         for (int i = 0; i < total; i++)
         {
           HistoryItem *curr_history_items = i < new_history_items_length ? 
-            &new_history_items[i] : &history_items[i - new_history_items_length];
+            &new_history_items[i - new_history_items_length - 1] : &history_items[i - new_history_items_length];
 
           if (curr_history_items->deleted)
             continue;
@@ -838,15 +853,9 @@
           Rectangle icon_area_left_column = LeftColumn(icon_area, 0.5, 0);
           Rectangle icon_area_right_column = RightColumn(icon_area, icon_area_left_column, 0);
 
-          GuiDrawText(curr_history_items->filename, AddPadding(filename_area, padding), TEXT_ALIGN_CENTER, RED);
+          GuiDrawText(curr_history_items->title, AddPadding(filename_area, padding), TEXT_ALIGN_CENTER, RED);
           if (GuiButton(AddPaddingHorizontal(icon_area_left_column, padding), "view"))
-            PostDog_Load_File(
-                curr_history_items->filename,
-                &url_input_text,
-                &active_method_dropdown,
-                url_body_map,
-                &url_result_text
-            );
+            PostDog_Load_File(curr_history_items->filename);
           if (GuiButton(AddPaddingHorizontal(icon_area_right_column,padding), "delete"))
           {
             if (!remove(PostDog_Construct_URL(curr_history_items->filename)))
@@ -857,7 +866,6 @@
         }
       EndScissorMode();
 
-      // Draw scroll indicator for history
       if (total > 0)
       {
         float content_height = total * (item_height + padding);
@@ -883,14 +891,7 @@
 
       sendRequest = GuiButton(url_enter_button, "ENTER");
       if (sendRequest)
-        PostDog_Http_Request(
-            url_input_text,
-            PostDog_Enum_To_String(active_method_dropdown),
-            url_body_map[TAB_HEADER],
-            url_body_map[TAB_BODY],
-            url_result_text,
-            RESULT_BUFFER_LENGTH
-        );
+        PostDog_Http_Request();
       if (GuiDropdownBox(method_dropdown, "GET;POST;PUT;DELETE", &active_method_dropdown, method_edit))
         method_edit = !method_edit;
 
@@ -900,7 +901,6 @@
       GuiSetStyle(TOGGLE, GROUP_PADDING, 0);
       GuiDrawRectangle(input_body, 1, GetColor(GuiGetStyle(TEXTBOX, BORDER)), GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_PRESSED)));
 
-      // Create scrollable input body with offset
       BeginScissorMode(input_body.x, input_body.y, input_body.width, input_body.height);
         Rectangle scrolled_input = AddPadding(input_body, padding * 2);
         scrolled_input.y += input_body_scroll_offset;
@@ -909,11 +909,9 @@
           input_body_bool = !input_body_bool;
       EndScissorMode();
 
-      // Draw scroll indicator for input body
       if (input_body_scroll_offset < 0) {
-        float scrollbar_height = 50; // Fixed size indicator
-        float max_scroll = 1000; // Estimated max scroll
-        float scrollbar_y = input_body.y - (input_body_scroll_offset / max_scroll) * (input_body.height - scrollbar_height);
+        float scrollbar_height = 10; 
+        float scrollbar_y = input_body.y - (input_body_scroll_offset / MAX_SCROLL_HEIGHT) * (input_body.height - scrollbar_height);
         Rectangle scrollbar = {
           input_body.x + input_body.width - 5,
           scrollbar_y,
@@ -925,7 +923,7 @@
 
       GuiToggleGroup(input_tab_item, "Header;Body;Get Param;Bar", &active_input_tab);
 
-      PostDog_Update_URL(&url_input_text, url_body_map[TAB_GET_PARAMS]);
+      PostDog_Update_URL();
 
       // Result Rect
       DrawRectangleRec(result_area, Fade(GREEN, 0.1f));
@@ -939,11 +937,9 @@
         GuiTextBoxMulti(scrolled_result, url_result_text, RESULT_BUFFER_LENGTH, false);
       EndScissorMode();
 
-      // Draw scroll indicator for result body
       if (result_body_scroll_offset < 0) {
-        float scrollbar_height = 50; // Fixed size indicator
-        float max_scroll = 1000; // Estimated max scroll
-        float scrollbar_y = result_body.y - (result_body_scroll_offset / max_scroll) * (result_body.height - scrollbar_height);
+        float scrollbar_height = 10;
+        float scrollbar_y = result_body.y - (result_body_scroll_offset / MAX_SCROLL_HEIGHT) * (result_body.height - scrollbar_height);
         Rectangle scrollbar = {
           result_body.x + result_body.width - 5,
           scrollbar_y,
--- a/third_party/raylib/include/raygui.h	Wed Jan 07 05:02:45 2026 -0800
+++ b/third_party/raylib/include/raygui.h	Wed Jan 07 13:24:38 2026 -0800
@@ -738,7 +738,6 @@
 RAYGUIAPI int GuiButton(Rectangle bounds, const char *text);                                           // Button control, returns true when clicked
 RAYGUIAPI int GuiLabelButton(Rectangle bounds, const char *text);                                      // Label button control, returns true when clicked
 RAYGUIAPI int GuiToggle(Rectangle bounds, const char *text, bool *active);                             // Toggle Button control
-RAYGUIAPI void JUNE_DrawRectangleLinesNoBottom(Rectangle rect, float thickness, Color color);
 RAYGUIAPI int GuiToggleGroup(Rectangle bounds, const char *text, int *active);                         // Toggle Group control
 RAYGUIAPI int GuiToggleSlider(Rectangle bounds, const char *text, int *active);                        // Toggle Slider control
 RAYGUIAPI int GuiCheckBox(Rectangle bounds, const char *text, bool *checked);                          // Check Box control, returns true when active
@@ -770,6 +769,10 @@
 RAYGUIAPI int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv);                 // Color Panel control that updates Hue-Saturation-Value color value, used by GuiColorPickerHSV()
 //----------------------------------------------------------------------------------------------------------
 
+
+// ---- CUSTOM ---- //
+RAYGUIAPI void JUNE_DrawRectangleLinesNoBottom(Rectangle rect, float thickness, Color color);
+
 #if !defined(RAYGUI_NO_ICONS)
 
 #if !defined(RAYGUI_CUSTOM_ICONS)
@@ -2107,7 +2110,7 @@
           JUNE_DrawRectangleLinesNoBottom(
               bounds, 
               GuiGetStyle(TOGGLE, BORDER_WIDTH),
-              GetColor(GuiGetStyle(TOGGLE, BORDER_COLOR_PRESSED))
+              GetColor(GuiGetStyle(TOGGLE, ((*active)? BORDER_COLOR_PRESSED : (BORDER + state*3))))
           );
         }
         else
@@ -2123,7 +2126,26 @@
     }
     else
     {
-        GuiDrawRectangle(bounds, GuiGetStyle(TOGGLE, BORDER_WIDTH), GetColor(GuiGetStyle(TOGGLE, BORDER + state*3)), GetColor(GuiGetStyle(TOGGLE, BASE + state*3)));
+        Rectangle tmp = bounds;
+        tmp.height += GuiGetStyle(TOGGLE, BORDER_WIDTH); 
+        if (*active)
+        {
+          GuiDrawRectangle(
+              tmp, 
+              0, 
+              GetColor(GuiGetStyle(TOGGLE, ((*active)? BORDER_COLOR_PRESSED : (BORDER + state*3)))), 
+              GetColor(GuiGetStyle(TOGGLE, ((*active)? BASE_COLOR_PRESSED : (BASE + state*3))))
+          );
+          JUNE_DrawRectangleLinesNoBottom(
+              bounds, 
+              GuiGetStyle(TOGGLE, BORDER_WIDTH),
+              GetColor(GuiGetStyle(TOGGLE, ((*active)? BORDER_COLOR_PRESSED : (BORDER + state*3))))
+          );
+        }
+        else
+        {
+          GuiDrawRectangle(bounds, GuiGetStyle(TOGGLE, BORDER_WIDTH), GetColor(GuiGetStyle(TOGGLE, BORDER + state*3)), GetColor(GuiGetStyle(TOGGLE, BASE + state*3)));
+        }
         GuiDrawText(text, GetTextBounds(TOGGLE, bounds), GuiGetStyle(TOGGLE, TEXT_ALIGNMENT), GetColor(GuiGetStyle(TOGGLE, TEXT + state*3)));
     }