Mercurial
view postdog/main.c @ 150:c37490913530
[Config] Updated .vimrc files and made command for ctags movements.
| author | June Park <parkjune1995@gmail.com> |
|---|---|
| date | Sat, 10 Jan 2026 13:30:28 -0800 |
| parents | 249881ceff7b |
| children | 7387eec8e7f8 |
line wrap: on
line source
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <sys/stat.h> #include "dowa/dowa.h" #include <curl/curl.h> #include "third_party/raylib/include/raylib.h" #define RAYGUI_IMPLEMENTATION #include "third_party/raylib/include/raygui.h" #ifndef POSTDOG_PATHS #define POSTDOG_PATHS "/Users/mrjunejune/zenbu/postdog/history" #endif #define SCREEN_WIDTH 1280 #define SCREEN_HEIGHT 780 #define MAX_SCROLL_HEIGHT 10000 #define HEADER_BUFFER_LENGTH 1024 * 4 #define DEFAULT_TEXT_BUFFER_LENGTH 1024 * 4 #define URL_TEXT_BUFFER_LENGTH 1024 * 10 #define BODY_BUFFER_LENGTH 1024 * 1024 * 5 #define RESULT_BUFFER_LENGTH 1024 * 1024 * 5 #ifdef _WIN32 #include <direct.h> #include <io.h> #define mkdir(path, mode) _mkdir(path) #define access _access #define F_OK 0 #else #include <sys/stat.h> #include <dirent.h> #include <unistd.h> #endif typedef Dowa_KV(char*, char*) INPUT_HASHMAP; typedef struct { char *data; size_t size; } ResponseBuffer; typedef struct { char *filename; char *title; Rectangle rect; long time_modified; boolean deleted; } HistoryItem; typedef struct { Rectangle rectangle; char *label; bool active; } TabItem; typedef enum { TAB_HEADER = 0, TAB_BODY, TAB_GET_PARAMS, TAB_BAR, TAB_LENGTH } PostDog_Tab_Enum; static uint32 counter = 0; 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); } 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. void PostDog_List_Directory(const char *path, HistoryItem **p_file_arr) { HistoryItem *file_arr = *p_file_arr; #ifdef _WIN32 struct _finddata_t fileinfo; intptr_t handle; char search_path[256]; sprintf(search_path, "%s\\*", path); if ((handle = _findfirst(search_path, &fileinfo)) == -1L) { printf("Directory is empty or cannot be read.\n"); } else { do { HistoryItem item = {0}; item.filename = strdup(fileinfo.name); 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); _findclose(handle); } #else struct dirent *entry; struct stat file_stat; DIR *dp = opendir(path); if (dp == NULL) return; char full_path[256]; while ((entry = readdir(dp))) { if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue; snprintf(full_path, sizeof(full_path), "%s/%s", path, entry->d_name); if (stat(full_path, &file_stat) == 0) { 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); } } closedir(dp); #endif int count = Dowa_Array_Length(file_arr); if (count > 1) { qsort(file_arr, count, sizeof(HistoryItem), CompareHistoryItemsByDate); } } int PostDog_History_Load(HistoryItem **p_history_files) { if (access(POSTDOG_PATHS, F_OK) == -1) { printf("Directory '%s' not found. Creating it...\n", POSTDOG_PATHS); if (mkdir(POSTDOG_PATHS, 0777) != 0) return -1; return 0; } printf("Directory '%s' already exists.\n", POSTDOG_PATHS); PostDog_List_Directory(POSTDOG_PATHS, p_history_files); return 0; } bool InArea(Vector2 mouse_position, Rectangle area) { return ( mouse_position.x >= area.x && mouse_position.x < area.x + area.width && mouse_position.y >= area.y && mouse_position.y < area.y + area.height ); } bool Clicked(Vector2 mouse_position, Rectangle area) { return (InArea(mouse_position, area) && IsMouseButtonPressed(MOUSE_BUTTON_LEFT)); } char *PostDog_Enum_To_String(int active_enum) { switch(active_enum) { case 0: return "GET"; case 1: return "POST"; case 2: return "PUT"; case 3: return "DELETE"; } return 0; } char *PostDog_Construct_URL(char *filename) { char full_file_path[512] = {0}; snprintf(full_file_path, 512, "%s/%s", POSTDOG_PATHS, filename); return &full_file_path; } void PostDog_History_CreateFile(char *filename, char* values) { char full_file_path[512] = {0}; snprintf(full_file_path, 512, "%s/%s", POSTDOG_PATHS, filename); FILE *file = fopen(full_file_path, "w"); if (!file) { printf("Failed to create a file: %s\n", full_file_path); return; } fwrite(values, 1, strlen(values), file); fclose(file); } 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, "%s\n" "---\n" "%s\n" "---\n" "%s\n" "---\n" "%s\n" "---\n" "%s\n" "---\n" "%s\n" "---\n" "%s\n" "---\n" "%s\n", title, url_input_text, method, 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) { perror("Error opening file"); exit(EXIT_FAILURE); } char *uuid4 = (char *)Dowa_Arena_Allocate(arena, 37); if (!uuid4) { perror("Error uuid"); exit(EXIT_FAILURE); } int32 seed = (uint32)time(NULL) ^ counter++; Dowa_String_UUID(seed, uuid4); snprintf(filename, 1024, "%s.txt", uuid4); PostDog_History_CreateFile(filename, new_file); HistoryItem item = {0}; item.filename = strdup(filename); item.title = title; item.deleted = FALSE; Dowa_Array_Push(new_history_items, item); Dowa_Arena_Free(arena); } static size_t Postdog_Curl_Callback(void *contents, size_t size, size_t nmemb, void *userp) { size_t real_size = size * nmemb; ResponseBuffer *buf = (ResponseBuffer *)userp; char *ptr = realloc(buf->data, buf->size + real_size + 1); if (ptr == NULL) { printf("Not enough memory for response\n"); return 0; } buf->data = ptr; memcpy(&(buf->data[buf->size]), contents, real_size); buf->size += real_size; buf->data[buf->size] = 0; return real_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 }; url_result_text[0] = '\n'; if (buffer.data == NULL) { snprintf(url_result_text, RESULT_BUFFER_LENGTH, "Error: Failed to allocate memory"); return -1; } buffer.data[0] = '\0'; curl_global_init(CURL_GLOBAL_DEFAULT); curl = curl_easy_init(); if (curl) { struct curl_slist *headerList = NULL; // Set 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 (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 (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) { curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE"); } // Default is GET // Parse and add headers if (url_body_map[TAB_HEADER] && strlen(url_body_map[TAB_HEADER]) > 0) { char *headersCopy = strdup(url_body_map[TAB_HEADER]); char *line = strtok(headersCopy, "\n"); while (line != NULL) { while (*line == ' ' || *line == '\t') line++; if (strlen(line) > 0) headerList = curl_slist_append(headerList, line); line = strtok(NULL, "\n"); } curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerList); free(headersCopy); } // Set write callback curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, Postdog_Curl_Callback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&buffer); // Follow redirects curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30L); res = curl_easy_perform(curl); if (res != CURLE_OK) 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 > RESULT_BUFFER_LENGTH) printf("TODO: Realloc\n"); snprintf(url_result_text, RESULT_BUFFER_LENGTH, "HTTP Status: %ld\n\n%s", response_code, buffer.data ? buffer.data : ""); } if (headerList) curl_slist_free_all(headerList); curl_easy_cleanup(curl); } else snprintf(url_result_text, RESULT_BUFFER_LENGTH, "Error: Failed to initialize curl"); free(buffer.data); curl_global_cleanup(); PostDog_Request_SaveFile(); return 0; } void PostDog_Update_URL(void) { // 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(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(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]; char **key_value = Dowa_String_Split(line, " ", (int)strlen(line), 1, arena); if (Dowa_Array_Length(key_value) < 2) break; strcat(url_input_text, separator); strcat(url_input_text, key_value[0]); strcat(url_input_text, "="); for (int i = 1; i < Dowa_Array_Length(key_value); i++) { if (!key_value[i] || key_value[i][0] == '\0') break; if (i > 1) strcat(url_input_text, "%20"); strcat(url_input_text, key_value[i]); } separator = "&"; } Dowa_Arena_Free(arena); } int PostDog_String_To_MethodEnum(char *value) { if (strstr(value, "GET")) return 0; if (strstr(value, "POST")) return 1; if (strstr(value, "PUT")) return 2; if (strstr(value, "DELETE")) return 3; return 0; } void PostDog_Params_Reset(void) { 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][0] = '\0'; } 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"); if (!file) return; fseek(file, 0, SEEK_END); size_t file_size = ftell(file); fseek(file, 0, SEEK_SET); Dowa_Arena *init_arena = Dowa_Arena_Create(file_size + 2); Dowa_Arena *split_arena = Dowa_Arena_Create(file_size * 2); char *file_buffer = Dowa_Arena_Allocate(init_arena, file_size+1); fread(file_buffer, 1, file_size, file); fclose(file); char **values = Dowa_String_Split(file_buffer, "---\n", file_size, 4, split_arena); for (int i = 0; i < Dowa_Array_Length(values); i++) { switch (i) { 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) { 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--) { 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; } } Dowa_Arena_Free(init_arena); Dowa_Arena_Free(split_arena); } Rectangle AddPadding(Rectangle rect, float padding) { return (Rectangle){ rect.x + padding, rect.y + padding, rect.width - (2 * padding), rect.height - (2 * padding) }; } Rectangle AddPaddingHorizontal(Rectangle rect, float padding) { return (Rectangle){ rect.x + padding, rect.y, rect.width - (2 * padding), rect.height }; } Rectangle AddPaddingVertical(Rectangle rect, float padding) { return (Rectangle){ rect.x, rect.y + padding, rect.width, rect.height - (2 * padding) }; } // Layout helper functions Rectangle RightOf(Rectangle ref, float padding) { return (Rectangle){ .x = ref.x + ref.width + padding, .y = ref.y, .width = 0, .height = ref.height }; } Rectangle Below(Rectangle ref, float padding) { return (Rectangle){ .x = ref.x, .y = ref.y + ref.height + padding, .width = ref.width, .height = 0 }; } Rectangle LeftColumn(Rectangle container, float ratio, float padding) { return (Rectangle){ .x = container.x + padding, .y = container.y + padding, .width = (container.width * ratio) - padding, .height = container.height - (2 * padding) }; } Rectangle RightColumn(Rectangle container, Rectangle leftCol, float padding) { return (Rectangle){ .x = leftCol.x + leftCol.width + padding, .y = container.y + padding, .width = container.width - leftCol.width - (3 * padding), .height = container.height - (2 * padding) }; } Rectangle HorizontalSplit(Rectangle container, float ratio) { return (Rectangle){ .x = container.x, .y = container.y, .width = container.width * ratio, .height = container.height }; } int main() { // -- initizlied --// InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "PostDog"); SetWindowState(FLAG_WINDOW_RESIZABLE); SetTargetFPS(60); Font customFont = LoadFontEx("postdog/Roboto-Regular.ttf", 20, 0, 0); GuiSetFont(customFont); 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); // -- Starting pos ---// Rectangle history_sidebar = { 0 }; Dowa_Array_Reserve(history_items, 10); Dowa_Array_Reserve(new_history_items, 10); PostDog_History_Load(&history_items); int32 *history_deleted_items = NULL; Rectangle url_area = { 0 }; Rectangle textBounds = { 0 }; Rectangle url_input_bounds = { 0 }; bool url_input_edit = false; Rectangle url_text_bounds = { 0 }; Rectangle url_enter_button = { 0 }; Rectangle method_dropdown = { 0 }; // 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"); 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)); Dowa_Array_Push(url_body_map, (char *)malloc(sizeof(char) * DEFAULT_TEXT_BUFFER_LENGTH)); snprintf(url_body_map[TAB_HEADER], HEADER_BUFFER_LENGTH, "Content-Type: application/json"); snprintf(url_body_map[TAB_BODY], HEADER_BUFFER_LENGTH, ""); url_result_text = (char *)malloc(sizeof(char) * RESULT_BUFFER_LENGTH); bool method_edit = false; int sendRequest; // -- input --// Rectangle input_area = { 0 }; Rectangle input_tab = { 0 }; Rectangle input_tab_item = { 0 }; Rectangle input_body = { 0 }; bool input_body_bool = false; // -- result --// Rectangle result_area = { 0 }; Rectangle result_body = { 0 }; // General styling. float padding = 10; // TODO make it % based? int active_input_tab = 0; int prev_input_tab = 0; // Scroll offsets float history_scroll_offset = 0; float input_body_scroll_offset = 0; float result_body_scroll_offset = 0; while (!WindowShouldClose()) { int screen_width = GetScreenWidth(); int screen_height = GetScreenHeight(); if ((IsKeyDown(KEY_LEFT_SUPER) || IsKeyDown(KEY_LEFT_CONTROL)) && IsKeyDown(KEY_EQUAL)) GuiSetStyle(DEFAULT, TEXT_SIZE, GuiGetStyle(DEFAULT, TEXT_SIZE) + 1); if ((IsKeyDown(KEY_LEFT_SUPER) || IsKeyDown(KEY_LEFT_CONTROL)) && IsKeyDown(KEY_MINUS)) GuiSetStyle(DEFAULT, TEXT_SIZE, GuiGetStyle(DEFAULT, TEXT_SIZE) - 1); Rectangle screen = { 0, 0, screen_width, screen_height }; // -- Side bar --// history_sidebar = LeftColumn(screen, 0.15, padding); Rectangle content_area = RightColumn(screen, history_sidebar, padding); Rectangle logo_area = (Rectangle){ .x = history_sidebar.x, .y = history_sidebar.y, .width = history_sidebar.width, .height = 80 }; Rectangle history_list_area = Below(logo_area, padding); history_list_area.width = history_sidebar.width; history_list_area.height = history_sidebar.height - logo_area.height - padding; int32 new_history_items_length = Dowa_Array_Length(new_history_items); int32 history_item_length = Dowa_Array_Length(history_items); int32 total = new_history_items_length + history_item_length; float item_height = history_list_area.height * 0.10; int32 number_of_skipped_items = 0; for (int i = 0; i < total; i++) { HistoryItem *curr_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) { number_of_skipped_items++; continue; } curr_history_items->rect = (Rectangle){ .x = history_list_area.x, .y = history_list_area.y + (padding + item_height) * (i - number_of_skipped_items) + history_scroll_offset, .width = history_list_area.width, .height = item_height }; } // --- URL --- // url_area = (Rectangle){ .x = content_area.x, .y = content_area.y, .width = content_area.width, .height = content_area.height * 0.1 }; float url_control_y = url_area.y + (url_area.height - TEXT_SIZE * 2) / 2; url_text_bounds = (Rectangle){ .x = url_area.x + padding, .y = url_control_y, .width = 7 * (TEXT_SIZE / 2), .height = TEXT_SIZE * 2 }; url_input_bounds = RightOf(url_text_bounds, padding); url_input_bounds.width = url_area.width * 0.7; url_input_bounds.height = TEXT_SIZE * 2; url_enter_button = RightOf(url_input_bounds, padding); url_enter_button.width = url_area.width * 0.1; url_enter_button.height = TEXT_SIZE * 2; method_dropdown = RightOf(url_enter_button, padding); method_dropdown.width = url_area.width * 0.1; method_dropdown.height = TEXT_SIZE * 2; // -- Body -- // Rectangle body_area = Below(url_area, 0); body_area.height = content_area.height - url_area.height; input_area = HorizontalSplit(body_area, 0.5); result_area = RightOf(input_area, 0); result_area.width = body_area.width - input_area.width; input_tab = (Rectangle){ .x = input_area.x + padding, .y = input_area.y + padding, .width = input_area.width - (2 * padding), .height = input_area.height * 0.1 }; input_tab_item = input_tab; input_tab_item.width = input_tab.width / 4; input_body = Below(input_tab, 0); input_body.width = input_tab.width; input_body.height = input_area.height - input_tab.height - (2 * padding); // -- Result -- / result_body = (Rectangle){ .x = result_area.x + padding, .y = input_body.y, .width = result_area.width - (2 * padding), .height = input_body.height }; Vector2 mouse_position = GetMousePosition(); float mouse_wheel = GetMouseWheelMove(); // Reset input body scroll when tab changes if (prev_input_tab != active_input_tab) { input_body_scroll_offset = 0; prev_input_tab = active_input_tab; } // Handle scroll wheel for history if (InArea(mouse_position, history_list_area) && mouse_wheel != 0) { history_scroll_offset += mouse_wheel * 30; // 30 pixels per wheel tick // Clamp scroll offset float max_scroll = (total * (item_height + padding)) - history_list_area.height; if (history_scroll_offset > 0) history_scroll_offset = 0; if (history_scroll_offset < -max_scroll && max_scroll > 0) history_scroll_offset = -max_scroll; } // Handle scroll wheel for input body if (InArea(mouse_position, input_body) && mouse_wheel != 0) { input_body_scroll_offset += mouse_wheel * 30; if (input_body_scroll_offset > 0) input_body_scroll_offset = 0; } // Handle scroll wheel for result body if (InArea(mouse_position, result_body) && mouse_wheel != 0) { result_body_scroll_offset += mouse_wheel * 30; if (result_body_scroll_offset > 0) result_body_scroll_offset = 0; } BeginDrawing(); ClearBackground(GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); DrawRectangleRec(history_sidebar, Fade(GRAY, 0.1f)); // DrawRectangleRec(logo_area, Fade(BLUE, 0.2f)); Rectangle logo_image_rect = AddPadding(logo_area, padding); // Fit logo to area while maintaining aspect ratio float logo_size = logo_image_rect.height < logo_image_rect.width ? logo_image_rect.height : logo_image_rect.width; Rectangle dest = { .x = logo_image_rect.x + (logo_image_rect.width - logo_size) / 2, // Center horizontally .y = logo_image_rect.y, .width = logo_size, .height = logo_size }; Rectangle source = { 0, 0, logo_texture.width, logo_texture.height }; DrawTexturePro(logo_texture, source, dest, (Vector2){0, 0}, 0.0f, WHITE); 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 - new_history_items_length - 1] : &history_items[i - new_history_items_length]; if (curr_history_items->deleted) continue; float diff = curr_history_items->rect.height*0.3; // DrawRectangleRec(curr_history_items->rect, Fade(RED, 0.1f)); Rectangle filename_area = curr_history_items->rect; filename_area.height -= diff; Rectangle icon_area = Below(filename_area, 0); icon_area.height = diff; DrawRectangleRec(filename_area, Fade(BLUE, 0.1f)); DrawRectangleRec(icon_area, Fade(YELLOW, 0.1f)); 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->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); if (GuiButton(AddPaddingHorizontal(icon_area_right_column,padding), "delete")) { if (!remove(PostDog_Construct_URL(curr_history_items->filename))) curr_history_items->deleted = TRUE; else fprintf(stderr, "Wasn't able to delete file: %s \n", curr_history_items->filename); } } EndScissorMode(); if (total > 0) { float content_height = total * (item_height + padding); if (content_height > history_list_area.height) { float scrollbar_height = (history_list_area.height / content_height) * history_list_area.height; float scrollbar_y = history_list_area.y - (history_scroll_offset / content_height) * history_list_area.height; Rectangle scrollbar = { history_list_area.x + history_list_area.width - 5, scrollbar_y, 5, scrollbar_height }; DrawRectangleRec(scrollbar, Fade(WHITE, 0.5f)); } } // URL area Rect GuiDrawText("URL: ", url_text_bounds, TEXT_ALIGN_CENTER, RED); DrawRectangleRec(url_area, Fade(RED, 0.1f)); if (GuiTextBox(url_input_bounds, url_input_text, DEFAULT_TEXT_BUFFER_LENGTH, url_input_edit)) url_input_edit = !url_input_edit; sendRequest = GuiButton(url_enter_button, "ENTER"); if (sendRequest) PostDog_Http_Request(); if (GuiDropdownBox(method_dropdown, "GET;POST;PUT;DELETE", &active_method_dropdown, method_edit)) method_edit = !method_edit; // Input Tabs Rect DrawRectangleRec(input_area, Fade(BLUE, 0.1f)); DrawRectangleRec(input_tab, Fade(DARKBLUE, 0.1f)); GuiSetStyle(TOGGLE, GROUP_PADDING, 0); GuiDrawRectangle(input_body, 1, GetColor(GuiGetStyle(TEXTBOX, BORDER)), GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_PRESSED))); 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; scrolled_input.height = MAX_SCROLL_HEIGHT; if (JUNE_GuiTextBox(scrolled_input, url_body_map[active_input_tab], DEFAULT_TEXT_BUFFER_LENGTH, input_body_bool)) input_body_bool = !input_body_bool; EndScissorMode(); if (input_body_scroll_offset < 0) { 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, 5, scrollbar_height }; DrawRectangleRec(scrollbar, Fade(BLUE, 0.5f)); } GuiToggleGroup(input_tab_item, "Header;Body;Get Param;Bar", &active_input_tab); PostDog_Update_URL(); // Result Rect DrawRectangleRec(result_area, Fade(GREEN, 0.1f)); DrawRectangleRec(result_body, Fade(DARKGREEN, 0.1f)); // Create scrollable result body with offset BeginScissorMode(result_body.x, result_body.y, result_body.width, result_body.height); Rectangle scrolled_result = result_body; scrolled_result.y += result_body_scroll_offset; scrolled_result.height = MAX_SCROLL_HEIGHT; GuiTextBoxMulti(scrolled_result, url_result_text, RESULT_BUFFER_LENGTH, false); EndScissorMode(); if (result_body_scroll_offset < 0) { 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, 5, scrollbar_height }; DrawRectangleRec(scrollbar, Fade(GREEN, 0.5f)); } if (url_input_edit && (IsKeyDown(KEY_LEFT_SUPER) || IsKeyDown(KEY_LEFT_CONTROL)) && IsKeyPressed(KEY_C)) { SetClipboardText(url_input_text); } else if (input_body_bool && (IsKeyDown(KEY_LEFT_SUPER) || IsKeyDown(KEY_LEFT_CONTROL)) && IsKeyPressed(KEY_C)) { SetClipboardText(url_body_map[active_input_tab]); } else if (InArea(mouse_position, result_body)) { DrawRectangleRec(result_body, Fade(GREEN, 0.3f)); if ((IsKeyDown(KEY_LEFT_SUPER) || IsKeyDown(KEY_LEFT_CONTROL)) && IsKeyPressed(KEY_C)) SetClipboardText(url_result_text); } EndDrawing(); } CloseWindow(); return 0; }