comparison postdog/main.c @ 57:d4cdb87212fb

[PostDog] Working version.
author June Park <parkjune1995@gmail.com>
date Fri, 19 Dec 2025 18:00:30 -0800
parents b3e82d22f961
children ccb42d5bf8fd
comparison
equal deleted inserted replaced
55:0dcfbf5ba997 57:d4cdb87212fb
14 #define RAYGUI_IMPLEMENTATION 14 #define RAYGUI_IMPLEMENTATION
15 #include "third_party/raylib/include/raygui.h" 15 #include "third_party/raylib/include/raygui.h"
16 16
17 #define SCREEN_WIDTH 1280 17 #define SCREEN_WIDTH 1280
18 #define SCREEN_HEIGHT 780 18 #define SCREEN_HEIGHT 780
19 #define SIDEBAR_WIDTH 200
20 #define URL_INPUT_HEIGHT 40
21 #define PADDING 15
22
23 #define TEXT_SIZE 10 19 #define TEXT_SIZE 10
24 #define LINE_HEIGHT 15 20 #define LINE_HEIGHT 15
25 21 #define GENERIC_PADDING 15
22
23 #define SIDEBAR_WIDTH 200
24 #define SIDEBAR_PADDING_GENERAL 5
25 #define SIDEBAR_AREA_PADDING_X 10
26 #define SIDEBAR_AREA_PADDING_Y 10
27 #define SIDEBAR_REFERSH_BUTTON_WIDTH 90
28 #define SIDEBAR_REFERSH_BUTTON_HEIGHT 20
29 #define SIDEBAR_HISTORY_ITEM_HEIGHT 45
30
31 #define URL_INPUT_HEIGHT 40
32
33 #define TAB_LEN 3
26 #define METHOD_BUTTON_WIDTH 100 34 #define METHOD_BUTTON_WIDTH 100
27 #define METHOD_BUTTON_HEIGHT 40 35 #define METHOD_BUTTON_HEIGHT 40
28 #define SEND_BUTTON_WIDTH 100 36 #define SEND_BUTTON_WIDTH 100
29 #define SEND_BUTTON_HEIGHT 40 37 #define SEND_BUTTON_HEIGHT 40
30 38
46 char method[16]; 54 char method[16];
47 time_t timestamp; 55 time_t timestamp;
48 } HistoryItem; 56 } HistoryItem;
49 57
50 typedef enum { 58 typedef enum {
51 ActiveTab_JSON = 0 59 ActiveTab_JSON = 0,
52 ActiveTab_Headers, 60 ActiveTab_Headers,
53 ActiveTab_Params, 61 ActiveTab_Params,
54 } ActiveTab 62 } ActiveTab;
55 63
56 // Callback function for curl to write response data 64 // Callback function for curl to write response data
57 static size_t Postdog_Curl_Callback(void *contents, size_t size, size_t nmemb, void *userp) 65 static size_t Postdog_Curl_Callback(void *contents, size_t size, size_t nmemb, void *userp)
58 { 66 {
59 size_t real_size = size * nmemb; 67 size_t real_size = size * nmemb;
447 int screenHeight = GetScreenHeight(); 455 int screenHeight = GetScreenHeight();
448 456
449 // Layout calculations 457 // Layout calculations
450 Rectangle sidebar = { 0, 10, SIDEBAR_WIDTH, screenHeight }; 458 Rectangle sidebar = { 0, 10, SIDEBAR_WIDTH, screenHeight };
451 459
452 float mainX = SIDEBAR_WIDTH + PADDING; 460 float mainX = SIDEBAR_WIDTH + GENERIC_PADDING;
453 float mainWidth = screenWidth - SIDEBAR_WIDTH - PADDING * 2; 461 float mainWidth = screenWidth - SIDEBAR_WIDTH - GENERIC_PADDING * 2;
454 462
455 // URL input box - leave space for SEND button on the right 463 // URL input box - leave space for SEND button on the right
456 Rectangle urlBox = { 464 Rectangle urlBox = {
457 mainX, 465 mainX,
458 PADDING, 466 GENERIC_PADDING,
459 mainWidth - SEND_BUTTON_WIDTH - PADDING, 467 mainWidth - SEND_BUTTON_WIDTH - GENERIC_PADDING,
460 URL_INPUT_HEIGHT 468 URL_INPUT_HEIGHT
461 }; 469 };
462 470
463 // SEND button positioned beside URL input 471 // SEND button positioned beside URL input
464 Rectangle sendButton = { 472 Rectangle sendButton = {
465 urlBox.x + urlBox.width + PADDING, 473 urlBox.x + urlBox.width + GENERIC_PADDING,
466 PADDING, 474 GENERIC_PADDING,
467 SEND_BUTTON_WIDTH, 475 SEND_BUTTON_WIDTH,
468 SEND_BUTTON_HEIGHT 476 SEND_BUTTON_HEIGHT
469 }; 477 };
470 478
471 // Method dropdown below URL 479 // Method dropdown below URL
472 Rectangle methodButton = { 480 Rectangle methodButton = {
473 mainX, 481 mainX,
474 urlBox.y + urlBox.height + PADDING, 482 urlBox.y + urlBox.height + GENERIC_PADDING,
475 METHOD_BUTTON_WIDTH, 483 METHOD_BUTTON_WIDTH,
476 METHOD_BUTTON_HEIGHT 484 METHOD_BUTTON_HEIGHT
477 }; 485 };
478 486
479 float tabHeight = 30; 487 float tabHeight = 30;
480 float contentY = methodButton.y + methodButton.height + PADDING + tabHeight; 488 float contentY = methodButton.y + methodButton.height + GENERIC_PADDING + tabHeight;
481 float contentHeight = screenHeight - contentY - PADDING; 489 float contentHeight = screenHeight - contentY - GENERIC_PADDING;
482 490
483 float panelWidth = (mainWidth - PADDING) / 2; 491 float panelWidth = (mainWidth - GENERIC_PADDING) / 2;
484 492
485 Rectangle tabBar = { 493 Rectangle tabBar = {
486 mainX, 494 mainX,
487 methodButton.y + methodButton.height + PADDING, 495 methodButton.y + methodButton.height + GENERIC_PADDING,
488 panelWidth, 496 panelWidth,
489 tabHeight 497 tabHeight
490 }; 498 };
491 499
492 Rectangle requestPanel = { 500 Rectangle requestPanel = {
495 panelWidth, 503 panelWidth,
496 contentHeight 504 contentHeight
497 }; 505 };
498 506
499 Rectangle responsePanel = { 507 Rectangle responsePanel = {
500 mainX + panelWidth + PADDING, 508 mainX + panelWidth + GENERIC_PADDING,
501 contentY, 509 contentY,
502 panelWidth, 510 panelWidth,
503 contentHeight 511 contentHeight
504 }; 512 };
505 513
506 BeginDrawing(); 514 BeginDrawing();
507 ClearBackground(GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); 515 ClearBackground(GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR)));
508 516
509 // Sidebar with history 517 // --- Sidebar Component---
510 DrawRectangleRec(sidebar, Fade(GRAY, 0.1f)); 518 DrawRectangleRec(sidebar, Fade(GRAY, 0.1f));
511 GuiGroupBox(sidebar, "HISTORY"); 519 GuiGroupBox(sidebar, "HISTORY");
512 520
513 // Refresh history button 521 Rectangle refreshBtn = {
514 Rectangle refreshBtn = { sidebar.x + 5, sidebar.y + 5, 90, 20 }; 522 sidebar.x + SIDEBAR_PADDING_GENERAL,
515 if (GuiButton(refreshBtn, "Refresh")) { 523 sidebar.y + SIDEBAR_PADDING_GENERAL,
524 SIDEBAR_REFERSH_BUTTON_WIDTH,
525 SIDEBAR_REFERSH_BUTTON_HEIGHT
526 };
527 if (GuiButton(refreshBtn, "Refresh"))
528 {
516 historyCount = PostDog_HistoryDistory_ItemsLoad(historyItems, MAX_HISTORY_ITEMS); 529 historyCount = PostDog_HistoryDistory_ItemsLoad(historyItems, MAX_HISTORY_ITEMS);
517 } 530 }
518 531
519 // Scroll area for history 532 Rectangle historyArea = {
520 Rectangle historyArea = { sidebar.x + 5, sidebar.y + 30, sidebar.width - 10, sidebar.height - 40 }; 533 sidebar.x + SIDEBAR_PADDING_GENERAL,
521 534 sidebar.y + SIDEBAR_AREA_PADDING_Y,
522 // Handle scroll 535 sidebar.width - SIDEBAR_AREA_PADDING_X,
523 if (CheckCollisionPointRec(GetMousePosition(), historyArea)) { 536 sidebar.height - SIDEBAR_AREA_PADDING_Y
537 };
538 if (CheckCollisionPointRec(GetMousePosition(), historyArea))
539 {
524 float wheel = GetMouseWheelMove(); 540 float wheel = GetMouseWheelMove();
525 historyScroll.y += wheel * 20; 541 historyScroll.y += wheel * 20;
526 if (historyScroll.y < 0) historyScroll.y = 0; 542 if (historyScroll.y < 0) historyScroll.y = 0;
527 } 543 }
528 544
529 BeginScissorMode(historyArea.x, historyArea.y, historyArea.width, historyArea.height); 545 BeginScissorMode(historyArea.x, historyArea.y, historyArea.width, historyArea.height);
530 546
531 if (historyCount == 0) { 547 if (historyCount == 0)
532 DrawText("No requests yet", historyArea.x + 5, historyArea.y + 5, 10, DARKGRAY); 548 {
533 } else { 549 DrawText("No requests yet", historyArea.x + 5, historyArea.y + 25, 10, DARKGRAY);
534 int yPos = historyArea.y + 5 - (int)historyScroll.y; 550 }
535 int itemHeight = 45; 551 else
536 552 {
537 for (int i = 0; i < historyCount; i++) { 553 int item_y_position = historyArea.y + 5 - (int)historyScroll.y;
538 if (yPos > historyArea.y - itemHeight && yPos < historyArea.y + historyArea.height) { 554 for (
539 Rectangle itemRect = { historyArea.x, yPos, historyArea.width, itemHeight - 2 }; 555 int current_history_item_number = 0;
556 current_history_item_number < historyCount;
557 current_history_item_number++
558 )
559 {
560 if (item_y_position > historyArea.y - SIDEBAR_HISTORY_ITEM_HEIGHT && item_y_position < historyArea.y + historyArea.height)
561 {
562 Rectangle itemRect = { historyArea.x, item_y_position, historyArea.width, SIDEBAR_HISTORY_ITEM_HEIGHT - 2 };
540 563
541 // Draw button for history item 564 // Draw button for history item
542 Color bgColor = (selectedHistoryIndex == i) ? Fade(BLUE, 0.3f) : Fade(LIGHTGRAY, 0.5f); 565 Color bgColor = (selectedHistoryIndex == current_history_item_number) ? Fade(BLUE, 0.3f) : Fade(LIGHTGRAY, 0.5f);
543 566 if (CheckCollisionPointRec(GetMousePosition(), itemRect) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
544 if (CheckCollisionPointRec(GetMousePosition(), itemRect) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) { 567 {
545 // Load this request 568 // TODO: This is cringe as fuck probably should just have a strucut that we assign and then zero out lol
546 char tempUrl[1024], tempMethod[16], tempHeaders[HEADER_INPUT_BUFFER_LEN], tempBody[JSON_INPUT_BUFFER_LEN]; 569 char tempUrl[1024], tempMethod[16], tempHeaders[HEADER_INPUT_BUFFER_LEN], tempBody[JSON_INPUT_BUFFER_LEN];
547 570
548 if (PostDog_HistoryDirectory_LoadRequest( 571 if (PostDog_HistoryDirectory_LoadRequest(
549 historyItems[i].filename, tempUrl, tempMethod, tempHeaders, tempBody) == 0) 572 historyItems[current_history_item_number].filename, tempUrl, tempMethod, tempHeaders, tempBody) == 0)
550 { 573 {
551 strncpy(urlInput, tempUrl, sizeof(urlInput) - 1); 574 strncpy(urlInput, tempUrl, sizeof(urlInput) - 1);
552 strncpy(headersInput, tempHeaders, sizeof(headersInput) - 1); 575 strncpy(headersInput, tempHeaders, sizeof(headersInput) - 1);
553 strncpy(jsonInput, tempBody, sizeof(jsonInput) - 1); 576 strncpy(jsonInput, tempBody, sizeof(jsonInput) - 1);
554 577
555 // Set method 578 // Set method
556 for (int m = 0; m < 4; m++) { 579 for (int m = 0; m < 4; m++)
557 if (strcmp(methods[m], tempMethod) == 0) { 580 {
581 if (strcmp(methods[m], tempMethod) == 0)
582 {
558 methodActive = m; 583 methodActive = m;
559 break; 584 break;
560 } 585 }
561 } 586 }
562 587
563 selectedHistoryIndex = i; 588 selectedHistoryIndex = current_history_item_number;
564 strcpy(responseText, "Request loaded from history. Click SEND to execute."); 589 strcpy(responseText, "Request loaded from history. Click SEND to execute.");
565 } 590 }
566 } 591 }
567 592
568 DrawRectangleRec(itemRect, bgColor); 593 DrawRectangleRec(itemRect, bgColor);
569 DrawRectangleLinesEx(itemRect, 1, GRAY); 594 DrawRectangleLinesEx(itemRect, 1, GRAY);
570 595
571 // Draw method badge 596 // Draw method badge
572 DrawText(historyItems[i].method, itemRect.x + 5, yPos + 5, 10, BLACK); 597 DrawText(historyItems[current_history_item_number].method, itemRect.x + 5, item_y_position + 5, 10, BLACK);
573 598
574 // Draw timestamp (date only) 599 // Draw timestamp (date only)
575 char dateStr[16] = ""; 600 char dateStr[16] = "";
576 if (strlen(historyItems[i].filename) >= 8) { 601 if (strlen(historyItems[current_history_item_number].filename) >= 8)
602 {
577 snprintf(dateStr, sizeof(dateStr), "%.4s-%.2s-%.2s", 603 snprintf(dateStr, sizeof(dateStr), "%.4s-%.2s-%.2s",
578 historyItems[i].filename, historyItems[i].filename + 4, historyItems[i].filename + 6); 604 historyItems[current_history_item_number].filename, historyItems[current_history_item_number].filename + 4, historyItems[current_history_item_number].filename + 6);
579 } 605 }
580 DrawText(dateStr, itemRect.x + 5, yPos + 18, 8, DARKGRAY); 606 DrawText(dateStr, itemRect.x + 5, item_y_position + 18, 8, DARKGRAY);
581 607
582 // Draw time 608 // Draw time
583 char timeStr[16] = ""; 609 char timeStr[16] = "";
584 if (strlen(historyItems[i].filename) >= 15) { 610 if (strlen(historyItems[current_history_item_number].filename) >= 15) {
585 snprintf(timeStr, sizeof(timeStr), "%.2s:%.2s:%.2s", 611 snprintf(timeStr, sizeof(timeStr), "%.2s:%.2s:%.2s",
586 historyItems[i].filename + 9, historyItems[i].filename + 11, historyItems[i].filename + 13); 612 historyItems[current_history_item_number].filename + 9, historyItems[current_history_item_number].filename + 11, historyItems[current_history_item_number].filename + 13);
587 } 613 }
588 DrawText(timeStr, itemRect.x + 5, yPos + 28, 8, DARKGRAY); 614 DrawText(timeStr, itemRect.x + 5, item_y_position + 28, 8, DARKGRAY);
589 } 615 }
590 616
591 yPos += itemHeight; 617 item_y_position += SIDEBAR_HISTORY_ITEM_HEIGHT;
592 } 618 }
593 } 619 }
594 620
595 EndScissorMode(); 621 EndScissorMode();
596 622
597 // URL Input 623 // --- URL Input Component ---
598 GuiLabel((Rectangle){ mainX, PADDING - 15, 100, 20 }, "URL:"); 624 GuiLabel((Rectangle){ mainX, GENERIC_PADDING - 15, 100, 20 }, "URL:");
599 if (GuiTextBox(urlBox, urlInput, 1024, urlEditMode)) 625 if (GuiTextBox(urlBox, urlInput, 1024, urlEditMode))
600 { 626 {
601 urlEditMode = !urlEditMode; 627 urlEditMode = !urlEditMode;
602 } 628 }
603 // Copy support for URL 629 if (urlEditMode && (IsKeyDown(KEY_LEFT_SUPER) || IsKeyDown(KEY_LEFT_CONTROL)) && IsKeyPressed(KEY_C))
604 if (urlEditMode && (IsKeyDown(KEY_LEFT_SUPER) || IsKeyDown(KEY_LEFT_CONTROL)) && IsKeyPressed(KEY_C)) { 630 {
605 SetClipboardText(urlInput); 631 SetClipboardText(urlInput);
606 } 632 }
607 633
608 // Send button (beside URL) 634 // Send button (beside URL)
609 if (GuiButton(sendButton, "SEND")) 635 if (GuiButton(sendButton, "SEND") || (urlEditMode && IsKeyDown(KEY_ENTER)))
610 { 636 {
611 strcpy(responseText, "Sending request...\n"); 637 strcpy(responseText, "Sending request...\n");
612 638
613 // Make the actual HTTP request 639 // Make the actual HTTP request
614 char tempResponse[16384]; 640 char tempResponse[16384];
622 saveRequestToHistory(urlInput, selectedMethod, requestHeaders, requestBody); 648 saveRequestToHistory(urlInput, selectedMethod, requestHeaders, requestBody);
623 649
624 // Reload history to show the new request 650 // Reload history to show the new request
625 historyCount = PostDog_HistoryDistory_ItemsLoad(historyItems, MAX_HISTORY_ITEMS); 651 historyCount = PostDog_HistoryDistory_ItemsLoad(historyItems, MAX_HISTORY_ITEMS);
626 652
653 // Making the requests.
627 PostDog_Make_HttpRequest(urlInput, selectedMethod, requestHeaders, 654 PostDog_Make_HttpRequest(urlInput, selectedMethod, requestHeaders,
628 requestBody, tempResponse, sizeof(tempResponse)); 655 requestBody, tempResponse, sizeof(tempResponse));
629
630 strncpy(responseText, tempResponse, sizeof(responseText) - 1); 656 strncpy(responseText, tempResponse, sizeof(responseText) - 1);
631 responseText[sizeof(responseText) - 1] = '\0'; 657 responseText[sizeof(responseText) - 1] = '\0';
632 } 658 }
633 659
634 // Tab toggle (3 tabs now) 660 // Tab toggle (3 tabs now)
647 activeTab = ActiveTab_Headers; 673 activeTab = ActiveTab_Headers;
648 } 674 }
649 675
650 if (GuiButton(paramsTab, activeTab == ActiveTab_Params ? "#191#Params" : "Params")) 676 if (GuiButton(paramsTab, activeTab == ActiveTab_Params ? "#191#Params" : "Params"))
651 { 677 {
652 activeTab = ActiveTab_Headers; 678 activeTab = ActiveTab_Params;
653 } 679 }
654 680
655 const char *panelTitle; 681 const char *panelTitle;
656 switch(activeTab) { 682 switch(activeTab) {
657 case ActiveTab_JSON: 683 case ActiveTab_JSON:
658 { 684 {
659 panelTitle = "Request Body (JSON)" 685 panelTitle = "Request Body (JSON)";
686 break;
660 } 687 }
661 case ActiveTab_Headers: 688 case ActiveTab_Headers:
662 { 689 {
663 panelTitle = "Request Headers" 690 panelTitle = "Request Headers";
691 break;
664 } 692 }
665 case ActiveTab_Params: 693 case ActiveTab_Params:
666 { 694 {
667 panelTitle = "Query Parameters" 695 panelTitle = "Query Parameters";
696 break;
668 } 697 }
669 } 698 }
670 699
671 // Panel title 700 // Panel title
672 GuiGroupBox(requestPanel, panelTitle); 701 GuiGroupBox(requestPanel, panelTitle);
693 722
694 // Manual scroll handling with mouse wheel 723 // Manual scroll handling with mouse wheel
695 if (CheckCollisionPointRec(GetMousePosition(), textArea)) 724 if (CheckCollisionPointRec(GetMousePosition(), textArea))
696 { 725 {
697 float wheel = GetMouseWheelMove(); 726 float wheel = GetMouseWheelMove();
698 switch(activeTab) { 727 switch(activeTab)
728 {
699 case ActiveTab_JSON: 729 case ActiveTab_JSON:
700 { 730 {
701 jsonScroll.y += wheel * 20; 731 jsonScroll.y += wheel * 20;
702 if (jsonScroll.y < 0) jsonScroll.y = 0; 732 if (jsonScroll.y < 0) jsonScroll.y = 0;
703 } 733 }
711 paramsScroll.y += wheel * 20; 741 paramsScroll.y += wheel * 20;
712 if (paramsScroll.y < 0) paramsScroll.y = 0; 742 if (paramsScroll.y < 0) paramsScroll.y = 0;
713 } 743 }
714 } 744 }
715 } 745 }
716 if (activeTab == 0) 746
717 { 747 char *copyFromInput;
718 BeginScissorMode(textArea.x, textArea.y, textArea.width, textArea.height); 748 bool *currentMode;
719 749 switch(activeTab)
720 int yPos = textArea.y + 5 - (int)jsonScroll.y; 750 {
721 char *textCopy = strdup(jsonInput); 751 case ActiveTab_JSON:
722 char *line = strtok(textCopy, "\n"); 752 {
723 753 PostDog_Render_TextWithScroll(textArea, jsonScroll, jsonInput);
724 while (line != NULL && yPos < textArea.y + textArea.height) 754 copyFromInput = jsonInput;
725 { 755 currentMode = &jsonEditMode;
726 if (yPos + LINE_HEIGHT > textArea.y) { 756 break;
727 DrawText(line, textArea.x + 5, yPos, TEXT_SIZE, DARKGRAY); 757 }
758 case ActiveTab_Headers:
759 {
760 PostDog_Render_TextWithScroll(textArea, headersScroll, headersInput);
761 copyFromInput = headersInput;
762 currentMode = &headersEditMode;
763 break;
764 }
765 case ActiveTab_Params:
766 {
767 PostDog_Render_TextWithScroll(textArea, paramsScroll, paramsInput);
768 copyFromInput = paramsInput;
769 currentMode = &paramsEditMode;
770
771 Rectangle updateUrlBtn = { textArea.x + 30, textArea.y + textArea.height - 10, 120, 20 };
772 // TODO: Automatic update
773 if (GuiButton(updateUrlBtn, "Update URL"))
774 {
775 char tempUrl[1024];
776 strncpy(tempUrl, urlInput, sizeof(tempUrl) - 1);
777
778 // Remove existing params if any
779 char *questionMark = strchr(tempUrl, '?');
780 if (questionMark) *questionMark = '\0';
781
782 updateUrlWithParams(urlInput, sizeof(urlInput), tempUrl, paramsInput);
728 } 783 }
729 yPos += LINE_HEIGHT; 784 break;
730 line = strtok(NULL, "\n"); 785 }
731 } 786 }
732 free(textCopy); 787
733 788 if ((IsKeyDown(KEY_LEFT_SUPER) || IsKeyDown(KEY_LEFT_CONTROL)) && IsKeyPressed(KEY_C))
734 EndScissorMode(); 789 {
735 790 SetClipboardText(copyFromInput);
736 if ((IsKeyDown(KEY_LEFT_SUPER) || IsKeyDown(KEY_LEFT_CONTROL)) && IsKeyPressed(KEY_C)) { 791 }
737 SetClipboardText(jsonInput); 792
738 } 793 Rectangle editBtn = { textArea.x + textArea.width - 60, textArea.y + textArea.height - 10, 50, 20 };
739 794 if (GuiButton(editBtn, "Edit"))
740 // Edit button 795 {
741 Rectangle editBtn = { textArea.x + textArea.width - 60, textArea.y + textArea.height - 10, 50, 20 }; 796 *currentMode = !(*currentMode);
742 if (GuiButton(editBtn, "Edit")) {
743 jsonEditMode = !jsonEditMode;
744 }
745 } else if (activeTab == 1) {
746 BeginScissorMode(textArea.x, textArea.y, textArea.width, textArea.height);
747
748 int yPos = textArea.y + 5 - (int)headersScroll.y;
749 char *textCopy = strdup(headersInput);
750 char *line = strtok(textCopy, "\n");
751
752 while (line != NULL && yPos < textArea.y + textArea.height)
753 {
754 if (yPos + LINE_HEIGHT > textArea.y)
755 {
756 DrawText(line, textArea.x + 5, yPos, TEXT_SIZE, DARKGRAY);
757 }
758 yPos += LINE_HEIGHT;
759 line = strtok(NULL, "\n");
760 }
761 free(textCopy);
762
763 EndScissorMode();
764
765 if ((IsKeyDown(KEY_LEFT_SUPER) || IsKeyDown(KEY_LEFT_CONTROL)) && IsKeyPressed(KEY_C)) {
766 SetClipboardText(headersInput);
767 }
768
769 // Edit button
770 Rectangle editBtn = { textArea.x + textArea.width - 60, textArea.y + textArea.height + 5, 50, 20 };
771 if (GuiButton(editBtn, "Edit")) {
772 headersEditMode = !headersEditMode;
773 }
774 } else {
775 // Params input with manual scroll
776 BeginScissorMode(textArea.x, textArea.y, textArea.width, textArea.height);
777
778 int yPos = textArea.y + 5 - (int)paramsScroll.y;
779 char *textCopy = strdup(paramsInput);
780 char *line = strtok(textCopy, "\n");
781
782 while (line != NULL && yPos < textArea.y + textArea.height) {
783 if (yPos + LINE_HEIGHT > textArea.y) {
784 DrawText(line, textArea.x + 5, yPos, TEXT_SIZE, DARKGRAY);
785 }
786 yPos += LINE_HEIGHT;
787 line = strtok(NULL, "\n");
788 }
789 free(textCopy);
790
791 EndScissorMode();
792
793 if ((IsKeyDown(KEY_LEFT_SUPER) || IsKeyDown(KEY_LEFT_CONTROL)) && IsKeyPressed(KEY_C)) {
794 SetClipboardText(paramsInput);
795 }
796
797 // Buttons
798 Rectangle editBtn = { textArea.x + textArea.width - 60, textArea.y + textArea.height + 5, 50, 20 };
799 if (GuiButton(editBtn, "Edit"))
800 {
801 paramsEditMode = !paramsEditMode;
802 }
803
804 Rectangle updateUrlBtn = { textArea.x, textArea.y + textArea.height + 5, 120, 20 };
805 if (GuiButton(updateUrlBtn, "Update URL"))
806 {
807 char tempUrl[1024];
808 strncpy(tempUrl, urlInput, sizeof(tempUrl) - 1);
809 // Remove existing params if any
810 char *questionMark = strchr(tempUrl, '?');
811 if (questionMark) *questionMark = '\0';
812
813 updateUrlWithParams(urlInput, sizeof(urlInput), tempUrl, paramsInput);
814 }
815 } 797 }
816 798
817 // Response Panel with scroll 799 // Response Panel with scroll
818 GuiGroupBox(responsePanel, "Response"); 800 GuiGroupBox(responsePanel, "Response");
819 801