//+------------------------------------------------------------------+
//|                                             AI UI COMPONENTS.mqh |
//|                           Copyright 2025, Allan Munene Mutiiria. |
//|                                   https://t.me/Forex_Algo_Trader |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, Allan Munene Mutiiria."
#property link "https://t.me/Forex_Algo_Trader"
#property strict

#include "AI CREATE OBJECTS FNS.mqh"

enum ENUM_SCROLLBAR_MODE
{
   SCROLL_DYNAMIC_ALWAYS,
   SCROLL_DYNAMIC_HOVER,
   SCROLL_WHEEL_ONLY
};
input ENUM_SCROLLBAR_MODE ScrollbarMode = SCROLL_DYNAMIC_HOVER;

#define resourceImg "::AI MQL5.bmp"
#define resourceImgLogo "::AI LOGO.bmp"
#define resourceNewChat "::AI NEW CHAT.bmp"
#define resourceClear "::AI CLEAR.bmp"
#define resourceHistory "::AI HISTORY.bmp"

#define SCROLL_LEADER "ChatGPT_Scroll_Leader"
#define SCROLL_UP_REC "ChatGPT_Scroll_Up_Rec"
#define SCROLL_UP_LABEL "ChatGPT_Scroll_Up_Label"
#define SCROLL_DOWN_REC "ChatGPT_Scroll_Down_Rec"
#define SCROLL_DOWN_LABEL "ChatGPT_Scroll_Down_Label"
#define SCROLL_SLIDER "ChatGPT_Scroll_Slider"
#define P_SCROLL_LEADER "ChatGPT_P_Scroll_Leader"
#define P_SCROLL_UP_REC "ChatGPT_P_Scroll_Up_Rec"
#define P_SCROLL_UP_LABEL "ChatGPT_P_Scroll_Up_Label"
#define P_SCROLL_DOWN_REC "ChatGPT_P_Scroll_Down_Rec"
#define P_SCROLL_DOWN_LABEL "ChatGPT_P_Scroll_Down_Label"
#define P_SCROLL_SLIDER "ChatGPT_P_Scroll_Slider"
#define BIG_SCROLL_LEADER "ChatGPT_Big_Scroll_Leader"
#define BIG_SCROLL_UP_REC "ChatGPT_Big_Scroll_Up_Rec"
#define BIG_SCROLL_UP_LABEL "ChatGPT_Big_Scroll_Up_Label"
#define BIG_SCROLL_DOWN_REC "ChatGPT_Big_Scroll_Down_Rec"
#define BIG_SCROLL_DOWN_LABEL "ChatGPT_Big_Scroll_Down_Label"
#define BIG_SCROLL_SLIDER "ChatGPT_Big_Scroll_Slider"
#define SEARCH_SCROLL_LEADER "ChatGPT_Search_Scroll_Leader"
#define SEARCH_SCROLL_UP_REC "ChatGPT_Search_Scroll_Up_Rec"
#define SEARCH_SCROLL_UP_LABEL "ChatGPT_Search_Scroll_Up_Label"
#define SEARCH_SCROLL_DOWN_REC "ChatGPT_Search_Scroll_Down_Rec"
#define SEARCH_SCROLL_DOWN_LABEL "ChatGPT_Search_Scroll_Down_Label"
#define SEARCH_SCROLL_SLIDER "ChatGPT_Search_Scroll_Slider"

struct Chat {
   int id;
   string title;
   string history;
};

Chat chats[];
int current_chat_id = -1;
string current_title = "";
string conversationHistory = "";
string currentPrompt = "";

bool button_hover = false;
color button_original_bg = clrRoyalBlue;
color button_darker_bg;
bool clear_hover = false;
bool new_chat_hover = false;
color clear_original_bg = clrLightCoral;
color clear_darker_bg;
color new_chat_original_bg = clrLightBlue;
color new_chat_darker_bg;
color chart_button_bg = clrLightGreen;
color chart_button_darker_bg;
bool chart_hover = false;
color close_original_bg = clrWhiteSmoke;
color close_darker_bg;
bool close_hover = false;
color toggle_original_bg = clrLightGray;
color toggle_darker_bg;
bool toggle_hover = false;
color history_original_bg = clrWhite;
color history_darker_bg;
bool history_hover = false;
color see_more_original_bg = clrRoyalBlue;
color see_more_darker_bg;
bool see_more_hover = false;
color big_close_original_bg = clrLightGray;
color big_close_darker_bg;
bool big_close_hover = false;
color search_original_bg = clrLightSlateGray;
color search_darker_bg;
bool search_hover = false;
color search_close_original_bg = clrLightGray;
color search_close_darker_bg;
bool search_close_hover = false;
color delete_original_bg = clrBeige;
color delete_darker_bg;
int chartButtonW = 50;
int signalButtonW = 110;
int sendButtonW = 50;  // Smaller for icon-only

color signal_button_bg = clrLightBlue;
color signal_button_darker_bg;
bool signal_hover = false;

int expandedSidebarWidth = 150;
int contractedSidebarWidth = 50;
bool sidebarExpanded = true;
int g_sidebarWidth = 150;
int g_dashboardX = 10;
int g_mainContentX = g_dashboardX + g_sidebarWidth;
int g_mainY = 20;
int g_mainWidth = 550;
int g_dashboardWidth = g_sidebarWidth + g_mainWidth;
int g_mainHeight = 0;
int g_padding = 10;
int g_sidePadding = 6;
int g_textPadding = 10;
int g_headerHeight = 40;
int g_displayHeight = 280;
int g_footerHeight = 180;
int g_promptHeight = 130;
int g_margin = 5;
int g_buttonHeight = 35;
int g_editHeight = 25;
int g_lineSpacing = 2;
int g_editW = 0;
bool scroll_visible = false;
bool mouse_in_display = false;
int scroll_pos = 0;
int prev_scroll_pos = -1;
int slider_height = 20;
bool movingStateSlider = false;
int mlbDownX_Slider = 0;
int mlbDownY_Slider = 0;
int mlbDown_YD_Slider = 0;
int g_total_height = 0;
int g_visible_height = 0;
bool p_scroll_visible = false;
bool mouse_in_prompt = false;
int p_scroll_pos = 0;
int p_slider_height = 20;
bool p_movingStateSlider = false;
int p_mlbDownX_Slider = 0;
int p_mlbDownY_Slider = 0;
int p_mlbDown_YD_Slider = 0;
int p_total_height = 0;
int p_visible_height = 0;
color g_promptBg = clrOldLace;
string g_scaled_image_resource = "";
string g_scaled_sidebar_resource = "";
string g_scaled_sidebar_small = "";
string g_scaled_newchat_resource = "";
string g_scaled_clear_resource = "";
string g_scaled_history_resource = "";
bool dashboard_visible = true;
string dashboardObjects[20];
int objCount = 0;
bool showing_small_history_popup = false;
int small_popup_x, small_popup_y, small_popup_w, small_popup_h;
string small_popup_objects[];
string small_chat_bgs[];
string small_delete_btns[];
bool showing_big_history_popup = false;
int big_popup_x, big_popup_y, big_popup_w, big_popup_h;
string big_popup_objects[];
string big_chat_bgs[];
string big_delete_btns[];
string side_chat_bgs[];
string side_delete_btns[];
int big_scroll_pos = 0;
bool big_scroll_visible = false;
int big_total_height = 0;
int big_visible_height = 0;
int big_slider_height = 20;
bool big_movingStateSlider = false;
int big_mlbDownX_Slider = 0;
int big_mlbDownY_Slider = 0;
int big_mlbDown_YD_Slider = 0;
bool just_opened_big = false;
bool just_opened_small = false;
bool showing_search_popup = false;
int search_popup_x, search_popup_y, search_popup_w, search_popup_h;
string search_popup_objects[];
string search_chat_bgs[];
string search_delete_btns[];
int search_scroll_pos = 0;
bool search_scroll_visible = false;
int search_total_height = 0;
int search_visible_height = 0;
int search_slider_height = 20;
bool search_movingStateSlider = false;
int search_mlbDownX_Slider = 0;
int search_mlbDownY_Slider = 0;
int search_mlbDown_YD_Slider = 0;
bool just_opened_search = false;
string current_search_query = "";

string EncodeID(int id) {
   string chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
   string res = "";
   if (id == 0) return "0";
   while (id > 0) {
      res = StringSubstr(chars, id % 62, 1) + res;
      id /= 62;
   }
   return res;
}

int DecodeID(string enc) {
   string chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
   int id = 0;
   for (int i = 0; i < StringLen(enc); i++) {
      id = id * 62 + StringFind(chars, StringSubstr(enc, i, 1));
   }
   return id;
}

int GetChatIndex(int id) {
   for (int i = 0; i < ArraySize(chats); i++) {
      if (chats[i].id == id) return i;
   }
   return -1;
}

bool IsTimestamp(string line) {
   StringTrimLeft(line);
   StringTrimRight(line);
   if (StringLen(line) != 5) return false;
   if (StringGetCharacter(line, 2) != ':') return false;
   string hh = StringSubstr(line, 0, 2);
   string mm = StringSubstr(line, 3, 2);
   int h = (int)StringToInteger(hh);
   int m = (int)StringToInteger(mm);
   if (h < 0 || h > 23 || m < 0 || m > 59) return false;
   return true;
}

color DarkenColor(color colorValue, double factor = 0.8) {
   int red = int((colorValue & 0xFF) * factor);
   int green = int(((colorValue >> 8) & 0xFF) * factor);
   int blue = int(((colorValue >> 16) & 0xFF) * factor);
   return (color)(red | (green << 8) | (blue << 16));
}

int getFontSizeByDPI(int baseFontSize, int baseDPI = 96) {
   int currentDPI = (int)TerminalInfoInteger(TERMINAL_SCREEN_DPI);
   int scaledFontSize = (int)(baseFontSize * (double)baseDPI / currentDPI);
   return MathMax(scaledFontSize, 8);
}

void ScaleImage(uint &pixels[], int original_width, int original_height, int new_width, int new_height) {
   uint scaled_pixels[];
   ArrayResize(scaled_pixels, new_width * new_height);
   for (int y = 0; y < new_height; y++) {
      for (int x = 0; x < new_width; x++) {
         double original_x = (double)x * original_width / new_width;
         double original_y = (double)y * original_height / new_height;
         uint pixel = BicubicInterpolate(pixels, original_width, original_height, original_x, original_y);
         scaled_pixels[y * new_width + x] = pixel;
      }
   }
   ArrayResize(pixels, new_width * new_height);
   ArrayCopy(pixels, scaled_pixels);
}

uint BicubicInterpolate(uint &pixels[], int width, int height, double x, double y) {
   int x0 = (int)x;
   int y0 = (int)y;
   double fractional_x = x - x0;
   double fractional_y = y - y0;
   int x_indices[4], y_indices[4];
   for (int i = -1; i <= 2; i++) {
      x_indices[i + 1] = MathMin(MathMax(x0 + i, 0), width - 1);
      y_indices[i + 1] = MathMin(MathMax(y0 + i, 0), height - 1);
   }
   uint neighborhood_pixels[16];
   for (int j = 0; j < 4; j++) {
      for (int i = 0; i < 4; i++) {
         neighborhood_pixels[j * 4 + i] = pixels[y_indices[j] * width + x_indices[i]];
      }
   }
   uchar alpha_components[16], red_components[16], green_components[16], blue_components[16];
   for (int i = 0; i < 16; i++) {
      GetArgb(neighborhood_pixels[i], alpha_components[i], red_components[i], green_components[i], blue_components[i]);
   }
   uchar alpha_out = (uchar)BicubicInterpolateComponent(alpha_components, fractional_x, fractional_y);
   uchar red_out = (uchar)BicubicInterpolateComponent(red_components, fractional_x, fractional_y);
   uchar green_out = (uchar)BicubicInterpolateComponent(green_components, fractional_x, fractional_y);
   uchar blue_out = (uchar)BicubicInterpolateComponent(blue_components, fractional_x, fractional_y);
   return (alpha_out << 24) | (red_out << 16) | (green_out << 8) | blue_out;
}

double BicubicInterpolateComponent(uchar &components[], double fractional_x, double fractional_y) {
   double weights_x[4];
   double t = fractional_x;
   weights_x[0] = (-0.5 * t * t * t + t * t - 0.5 * t);
   weights_x[1] = (1.5 * t * t * t - 2.5 * t * t + 1);
   weights_x[2] = (-1.5 * t * t * t + 2 * t * t + 0.5 * t);
   weights_x[3] = (0.5 * t * t * t - 0.5 * t * t);
   double y_values[4];
   for (int j = 0; j < 4; j++) {
      y_values[j] = weights_x[0] * components[j * 4 + 0] + weights_x[1] * components[j * 4 + 1] +
                    weights_x[2] * components[j * 4 + 2] + weights_x[3] * components[j * 4 + 3];
   }
   double weights_y[4];
   t = fractional_y;
   weights_y[0] = (-0.5 * t * t * t + t * t - 0.5 * t);
   weights_y[1] = (1.5 * t * t * t - 2.5 * t * t + 1);
   weights_y[2] = (-1.5 * t * t * t + 2 * t * t + 0.5 * t);
   weights_y[3] = (0.5 * t * t * t - 0.5 * t * t);
   double result = weights_y[0] * y_values[0] + weights_y[1] * y_values[1] +
                   weights_y[2] * y_values[2] + weights_y[3] * y_values[3];
   return MathMax(0, MathMin(255, result));
}

void GetArgb(uint pixel, uchar &alpha, uchar &red, uchar &green, uchar &blue) {
   alpha = (uchar)((pixel >> 24) & 0xFF);
   red = (uchar)((pixel >> 16) & 0xFF);
   green = (uchar)((pixel >> 8) & 0xFF);
   blue = (uchar)(pixel & 0xFF);
}

void CreateScrollbar() {
   int displayX = g_mainContentX + g_sidePadding;
   int displayY = g_mainY + g_headerHeight + g_padding;
   int displayW = g_mainWidth - 2 * g_sidePadding;
   int scrollbar_x = displayX + displayW - 16;
   int scrollbar_y = displayY + 16;
   int scrollbar_width = 16;
   int scrollbar_height = g_displayHeight - 2 * 16;
   int button_size = 16;
   createRecLabel(SCROLL_LEADER, scrollbar_x, scrollbar_y, scrollbar_width, scrollbar_height, C'220,220,220', 1, clrGainsboro, BORDER_FLAT, STYLE_SOLID, CORNER_LEFT_UPPER);
   createRecLabel(SCROLL_UP_REC, scrollbar_x, displayY, scrollbar_width, button_size, clrGainsboro, 1, clrGainsboro, BORDER_FLAT, STYLE_SOLID, CORNER_LEFT_UPPER);
   createLabel(SCROLL_UP_LABEL, scrollbar_x + 2, displayY + -2, CharToString(0x35), clrDimGray, getFontSizeByDPI(10), "Webdings", CORNER_LEFT_UPPER);
   createRecLabel(SCROLL_DOWN_REC, scrollbar_x, displayY + g_displayHeight - button_size, scrollbar_width, button_size, clrGainsboro, 1, clrGainsboro, BORDER_FLAT, STYLE_SOLID, CORNER_LEFT_UPPER);
   createLabel(SCROLL_DOWN_LABEL, scrollbar_x + 2, displayY + g_displayHeight - button_size + -2, CharToString(0x36), clrDimGray, getFontSizeByDPI(10), "Webdings", CORNER_LEFT_UPPER);
   slider_height = CalculateSliderHeight();
   createRecLabel(SCROLL_SLIDER, scrollbar_x, displayY + g_displayHeight - button_size - slider_height, scrollbar_width, slider_height, clrSilver, 1, clrGainsboro, BORDER_FLAT, STYLE_SOLID, CORNER_LEFT_UPPER);
}

void CreatePromptScrollbar() {
   int promptX = g_mainContentX + g_sidePadding;
   int footerY = g_mainY + g_headerHeight + g_padding + g_displayHeight + g_padding;
   int promptY = footerY + g_margin;
   int promptW = g_mainWidth - 2 * g_sidePadding;
   int scrollbar_x = promptX + promptW - 16;
   int scrollbar_y = promptY + 16;
   int scrollbar_width = 16;
   int scrollbar_height = g_promptHeight - 2 * 16;
   int button_size = 16;
   createRecLabel(P_SCROLL_LEADER, scrollbar_x, scrollbar_y, scrollbar_width, scrollbar_height, C'220,220,220', 1, clrGainsboro, BORDER_FLAT, STYLE_SOLID, CORNER_LEFT_UPPER);
   createRecLabel(P_SCROLL_UP_REC, scrollbar_x, promptY, scrollbar_width, button_size, clrGainsboro, 1, clrGainsboro, BORDER_FLAT, STYLE_SOLID, CORNER_LEFT_UPPER);
   createLabel(P_SCROLL_UP_LABEL, scrollbar_x + 2, promptY + -2, CharToString(0x35), clrDimGray, getFontSizeByDPI(10), "Webdings", CORNER_LEFT_UPPER);
   createRecLabel(P_SCROLL_DOWN_REC, scrollbar_x, promptY + g_promptHeight - button_size, scrollbar_width, button_size, clrGainsboro, 1, clrGainsboro, BORDER_FLAT, STYLE_SOLID, CORNER_LEFT_UPPER);
   createLabel(P_SCROLL_DOWN_LABEL, scrollbar_x + 2, promptY + g_promptHeight - button_size + -2, CharToString(0x36), clrDimGray, getFontSizeByDPI(10), "Webdings", CORNER_LEFT_UPPER);
   p_slider_height = CalculatePromptSliderHeight();
   createRecLabel(P_SCROLL_SLIDER, scrollbar_x, promptY + g_promptHeight - button_size - p_slider_height, scrollbar_width, p_slider_height, clrSilver, 1, clrGainsboro, BORDER_FLAT, STYLE_SOLID, CORNER_LEFT_UPPER);
}

void DeleteScrollbar() {
   ObjectDelete(0, SCROLL_LEADER);
   ObjectDelete(0, SCROLL_UP_REC);
   ObjectDelete(0, SCROLL_UP_LABEL);
   ObjectDelete(0, SCROLL_DOWN_REC);
   ObjectDelete(0, SCROLL_DOWN_LABEL);
   ObjectDelete(0, SCROLL_SLIDER);
}

void DeletePromptScrollbar() {
   ObjectDelete(0, P_SCROLL_LEADER);
   ObjectDelete(0, P_SCROLL_UP_REC);
   ObjectDelete(0, P_SCROLL_UP_LABEL);
   ObjectDelete(0, P_SCROLL_DOWN_REC);
   ObjectDelete(0, P_SCROLL_DOWN_LABEL);
   ObjectDelete(0, P_SCROLL_SLIDER);
}

int CalculateSliderHeight() {
   int scroll_area_height = g_displayHeight - 2 * 16;
   int slider_min_height = 20;
   if (g_total_height <= g_visible_height) return scroll_area_height;
   double visible_ratio = (double)g_visible_height / g_total_height;
   int height = (int)MathFloor(scroll_area_height * visible_ratio);
   return MathMax(slider_min_height, height);
}

int CalculatePromptSliderHeight() {
   int scroll_area_height = g_promptHeight - 2 * 16;
   int slider_min_height = 20;
   if (p_total_height <= p_visible_height) return scroll_area_height;
   double visible_ratio = (double)p_visible_height / p_total_height;
   int height = (int)MathFloor(scroll_area_height * visible_ratio);
   return MathMax(slider_min_height, height);
}

void UpdateSliderPosition() {
   int displayX = g_mainContentX + g_sidePadding;
   int displayY = g_mainY + g_headerHeight + g_padding;
   int scrollbar_x = displayX + (g_mainWidth - 2 * g_sidePadding) - 16;
   int scrollbar_y = displayY + 16;
   int scroll_area_height = g_displayHeight - 2 * 16;
   int max_scroll = MathMax(0, g_total_height - g_visible_height);
   if (max_scroll <= 0) return;
   double scroll_ratio = (double)scroll_pos / max_scroll;
   int scroll_area_y_max = scrollbar_y + scroll_area_height - slider_height;
   int scroll_area_y_min = scrollbar_y;
   int new_y = scroll_area_y_min + (int)(scroll_ratio * (scroll_area_y_max - scroll_area_y_min));
   new_y = MathMax(scroll_area_y_min, MathMin(new_y, scroll_area_y_max));
   ObjectSetInteger(0, SCROLL_SLIDER, OBJPROP_YDISTANCE, new_y);
}

void UpdatePromptSliderPosition() {
   int promptX = g_mainContentX + g_sidePadding;
   int footerY = g_mainY + g_headerHeight + g_padding + g_displayHeight + g_padding;
   int promptY = footerY + g_margin;
   int scrollbar_x = promptX + (g_mainWidth - 2 * g_sidePadding) - 16;
   int scrollbar_y = promptY + 16;
   int scroll_area_height = g_promptHeight - 2 * 16;
   int max_scroll = MathMax(0, p_total_height - p_visible_height);
   if (max_scroll <= 0) return;
   double scroll_ratio = (double)p_scroll_pos / max_scroll;
   int scroll_area_y_max = scrollbar_y + scroll_area_height - p_slider_height;
   int scroll_area_y_min = scrollbar_y;
   int new_y = scroll_area_y_min + (int)(scroll_ratio * (scroll_area_y_max - scroll_area_y_min));
   new_y = MathMax(scroll_area_y_min, MathMin(new_y, scroll_area_y_max));
   ObjectSetInteger(0, P_SCROLL_SLIDER, OBJPROP_YDISTANCE, new_y);
}

void UpdateButtonColors() {
   int max_scroll = MathMax(0, g_total_height - g_visible_height);
   if (scroll_pos == 0) {
      ObjectSetInteger(0, SCROLL_UP_LABEL, OBJPROP_COLOR, clrSilver);
   } else {
      ObjectSetInteger(0, SCROLL_UP_LABEL, OBJPROP_COLOR, clrDimGray);
   }
   if (scroll_pos == max_scroll) {
      ObjectSetInteger(0, SCROLL_DOWN_LABEL, OBJPROP_COLOR, clrSilver);
   } else {
      ObjectSetInteger(0, SCROLL_DOWN_LABEL, OBJPROP_COLOR, clrDimGray);
   }
}

void UpdatePromptButtonColors() {
   int max_scroll = MathMax(0, p_total_height - p_visible_height);
   if (p_scroll_pos == 0) {
      ObjectSetInteger(0, P_SCROLL_UP_LABEL, OBJPROP_COLOR, clrSilver);
   } else {
      ObjectSetInteger(0, P_SCROLL_UP_LABEL, OBJPROP_COLOR, clrDimGray);
   }
   if (p_scroll_pos == max_scroll) {
      ObjectSetInteger(0, P_SCROLL_DOWN_LABEL, OBJPROP_COLOR, clrSilver);
   } else {
      ObjectSetInteger(0, P_SCROLL_DOWN_LABEL, OBJPROP_COLOR, clrDimGray);
   }
}

void ScrollUp() {
   if (scroll_pos > 0) {
      scroll_pos = MathMax(0, scroll_pos - 30);
      UpdateResponseDisplay();
      if (scroll_visible) {
         UpdateSliderPosition();
         UpdateButtonColors();
      }
   }
}

void ScrollDown() {
   int max_scroll = MathMax(0, g_total_height - g_visible_height);
   if (scroll_pos < max_scroll) {
      scroll_pos = MathMin(max_scroll, scroll_pos + 30);
      UpdateResponseDisplay();
      if (scroll_visible) {
         UpdateSliderPosition();
         UpdateButtonColors();
      }
   }
}

void PromptScrollUp() {
   if (p_scroll_pos > 0) {
      p_scroll_pos = MathMax(0, p_scroll_pos - 30);
      UpdatePromptDisplay();
      if (p_scroll_visible) {
         UpdatePromptSliderPosition();
         UpdatePromptButtonColors();
      }
   }
}

void PromptScrollDown() {
   int max_scroll = MathMax(0, p_total_height - p_visible_height);
   if (p_scroll_pos < max_scroll) {
      p_scroll_pos = MathMin(max_scroll, p_scroll_pos + 30);
      UpdatePromptDisplay();
      if (p_scroll_visible) {
         UpdatePromptSliderPosition();
         UpdatePromptButtonColors();
      }
   }
}

int SplitOnString(string inputText, string delim, string &result[]) {
   ArrayResize(result, 0);
   int pos = 0;
   int delim_len = StringLen(delim);
   while (true) {
      int found = StringFind(inputText, delim, pos);
      if (found == -1) {
         string part = StringSubstr(inputText, pos);
         if (StringLen(part) > 0 || ArraySize(result) > 0) {
            int size = ArraySize(result);
            ArrayResize(result, size + 1);
            result[size] = part;
         }
         break;
      }
      string part = StringSubstr(inputText, pos, found - pos);
      int size = ArraySize(result);
      ArrayResize(result, size + 1);
      result[size] = part;
      pos = found + delim_len;
   }
   return ArraySize(result);
}

string ReplaceExactDoublePeriods(string text) {
   string result = "";
   int len = StringLen(text);
   for (int i = 0; i < len; i++) {
      if (i + 1 < len && StringGetCharacter(text, i) == '.' && StringGetCharacter(text, i + 1) == '.') {
         bool preceded = (i > 0 && StringGetCharacter(text, i - 1) == '.');
         bool followed = (i + 2 < len && StringGetCharacter(text, i + 2) == '.');
         if (!preceded && !followed) {
            result += "\n";
            i++;
         } else {
            result += ".";
         }
      } else {
         result += StringSubstr(text, i, 1);
      }
   }
   return result;
}

void WrapText(const string inputText, const string font, const int fontSize, const int maxWidth, string &wrappedLines[], int offset = 0) {
   const int maxChars = 60;
   ArrayResize(wrappedLines, 0);
   TextSetFont(font, fontSize);
   string processedText = ReplaceExactDoublePeriods(inputText);
   string paragraphs[];
   int numParagraphs = StringSplit(processedText, '\n', paragraphs);
   for (int p = 0; p < numParagraphs; p++) {
      string para = paragraphs[p];
      if (StringLen(para) == 0) {
         int size = ArraySize(wrappedLines);
         ArrayResize(wrappedLines, size + 1);
         wrappedLines[size] = " ";
         continue;
      }
      string words[];
      int numWords = StringSplit(para, ' ', words);
      string currentLine = "";
      for (int w = 0; w < numWords; w++) {
         if (StringLen(words[w]) == 0) continue;
         string testLine = currentLine + (StringLen(currentLine) > 0 ? " " : "") + words[w];
         uint wid, hei;
         TextGetSize(testLine, wid, hei);
         int textWidth = (int)wid;
         if (textWidth + offset <= maxWidth && StringLen(testLine) <= maxChars) {
            currentLine = testLine;
         } else {
            if (StringLen(currentLine) > 0) {
               int size = ArraySize(wrappedLines);
               ArrayResize(wrappedLines, size + 1);
               wrappedLines[size] = currentLine;
            }
            currentLine = words[w];
            TextGetSize(currentLine, wid, hei);
            textWidth = (int)wid;
            if (textWidth + offset > maxWidth || StringLen(currentLine) > maxChars) {
               string wrappedWord = "";
               for (int c = 0; c < StringLen(words[w]); c++) {
                  string testWord = wrappedWord + StringSubstr(words[w], c, 1);
                  TextGetSize(testWord, wid, hei);
                  int wordWidth = (int)wid;
                  if (wordWidth + offset > maxWidth || StringLen(testWord) > maxChars) {
                     if (StringLen(wrappedWord) > 0) {
                        int size = ArraySize(wrappedLines);
                        ArrayResize(wrappedLines, size + 1);
                        wrappedLines[size] = wrappedWord;
                     }
                     wrappedWord = StringSubstr(words[w], c, 1);
                  } else {
                     wrappedWord = testWord;
                  }
               }
               currentLine = wrappedWord;
            }
         }
      }
      if (StringLen(currentLine) > 0) {
         int size = ArraySize(wrappedLines);
         ArrayResize(wrappedLines, size + 1);
         wrappedLines[size] = currentLine;
      }
   }
}

void CreatePlaceholder() {
   if (ObjectFind(0, "ChatGPT_PromptPlaceholder") < 0 && StringLen(currentPrompt) == 0) {
      int placeholderFontSize = 10;
      string placeholderFont = "Arial";
      int lineHeight = TextGetHeight("A", placeholderFont, placeholderFontSize);
      int footerY = g_mainY + g_headerHeight + g_padding + g_displayHeight + g_padding;
      int promptY = footerY + g_margin;
      int editY = promptY + g_promptHeight - g_editHeight - 5;
      int editX = g_mainContentX + g_sidePadding + g_textPadding;
      int labelY = editY + (g_editHeight - lineHeight) / 2 - 3;
      createLabel("ChatGPT_PromptPlaceholder", editX + 2, labelY, "Type your prompt here...", clrGray, placeholderFontSize, placeholderFont, CORNER_LEFT_UPPER, ANCHOR_LEFT_UPPER);
      ChartRedraw();
   }
}

void DeletePlaceholder() {
   if (ObjectFind(0, "ChatGPT_PromptPlaceholder") >= 0) {
      ObjectDelete(0, "ChatGPT_PromptPlaceholder");
      ChartRedraw();
   }
}

void UpdateSidebarDynamic() {
   int total = ObjectsTotal(0, 0, -1);
   for (int j = total - 1; j >= 0; j--) {
      string name = ObjectName(0, j, 0, -1);
      if (StringFind(name, "ChatGPT_NewChatButton") == 0 || StringFind(name, "ChatGPT_ClearButton") == 0 || StringFind(name, "ChatGPT_HistoryButton") == 0 || StringFind(name, "ChatGPT_SearchButton") == 0 || StringFind(name, "ChatGPT_ChatLabel_") == 0 || StringFind(name, "ChatGPT_ChatBg_") == 0 || StringFind(name, "ChatGPT_SidebarLogo") == 0 || StringFind(name, "ChatGPT_NewChatIcon") == 0 || StringFind(name, "ChatGPT_NewChatLabel") == 0 || StringFind(name, "ChatGPT_ClearIcon") == 0 || StringFind(name, "ChatGPT_ClearLabel") == 0 || StringFind(name, "ChatGPT_HistoryIcon") == 0 || StringFind(name, "ChatGPT_HistoryLabel") == 0 || StringFind(name, "ChatGPT_SearchLabel") == 0 || StringFind(name, "ChatGPT_SearchIcon") == 0 || StringFind(name, "ChatGPT_ToggleButton") == 0 || StringFind(name, "ChatGPT_SideDelete_") == 0) {
         ObjectDelete(0, name);
      }
   }
   ArrayResize(side_chat_bgs, 0);
   ArrayResize(side_delete_btns, 0);
   int sidebarX = g_dashboardX;
   int itemY = g_mainY + 10;
   string sidebar_logo_resource = sidebarExpanded ? ((StringLen(g_scaled_sidebar_resource) > 0) ? g_scaled_sidebar_resource : resourceImgLogo) : ((StringLen(g_scaled_sidebar_small) > 0) ? g_scaled_sidebar_small : resourceImgLogo);
   int logo_size = sidebarExpanded ? 81 : 30;
   createBitmapLabel("ChatGPT_SidebarLogo", sidebarX + (g_sidebarWidth - logo_size)/2, itemY, logo_size, logo_size, sidebar_logo_resource, clrNONE, CORNER_LEFT_UPPER);
   ObjectSetInteger(0, "ChatGPT_SidebarLogo", OBJPROP_ZORDER, 1);
   itemY += logo_size + 5;
   createButton("ChatGPT_SearchButton", sidebarX + 5, itemY, g_sidebarWidth - 10, g_buttonHeight, "", clrWhite, 11, search_original_bg, clrDarkSlateGray);
   ObjectSetInteger(0, "ChatGPT_SearchButton", OBJPROP_ZORDER, 1);
   int iconX = sidebarExpanded ? sidebarX + 5 + 10 : sidebarX + (g_sidebarWidth - 20)/2-6;
   createLabel("ChatGPT_SearchIcon", iconX, itemY + (g_buttonHeight - 20)/2-6, "L", clrWhite, 24, "Webdings", CORNER_LEFT_UPPER);
   ObjectSetInteger(0, "ChatGPT_SearchIcon", OBJPROP_ZORDER, 2);
   ObjectSetInteger(0, "ChatGPT_SearchIcon", OBJPROP_SELECTABLE, false);
   if (sidebarExpanded) {
      createLabel("ChatGPT_SearchLabel", sidebarX + 5 + 10 + 20 + 5, itemY + (g_buttonHeight - 20)/2, "Search", clrWhite, 11, "Arial", CORNER_LEFT_UPPER);
      ObjectSetInteger(0, "ChatGPT_SearchLabel", OBJPROP_ZORDER, 2);
      ObjectSetInteger(0, "ChatGPT_SearchLabel", OBJPROP_SELECTABLE, false);
   }
   itemY += g_buttonHeight + 5;
   createButton("ChatGPT_NewChatButton", sidebarX + 5, itemY, g_sidebarWidth - 10, g_buttonHeight, "", clrWhite, 11, new_chat_original_bg, clrRoyalBlue);
   ObjectSetInteger(0, "ChatGPT_NewChatButton", OBJPROP_ZORDER, 1);
   string newchat_icon_resource = (StringLen(g_scaled_newchat_resource) > 0) ? g_scaled_newchat_resource : resourceNewChat;
   iconX = sidebarExpanded ? sidebarX + 5 + 10 : sidebarX + 5 + (g_sidebarWidth - 10 - 30)/2;
   createBitmapLabel("ChatGPT_NewChatIcon", iconX, itemY + (g_buttonHeight - 30)/2, 30, 30, newchat_icon_resource, clrNONE, CORNER_LEFT_UPPER);
   ObjectSetInteger(0, "ChatGPT_NewChatIcon", OBJPROP_ZORDER, 2);
   ObjectSetInteger(0, "ChatGPT_NewChatIcon", OBJPROP_SELECTABLE, false);
   if (sidebarExpanded) {
      createLabel("ChatGPT_NewChatLabel", sidebarX + 5 + 10 + 30 + 5, itemY + (g_buttonHeight - 20)/2, "New Chat", clrWhite, 11, "Arial", CORNER_LEFT_UPPER);
      ObjectSetInteger(0, "ChatGPT_NewChatLabel", OBJPROP_ZORDER, 2);
      ObjectSetInteger(0, "ChatGPT_NewChatLabel", OBJPROP_SELECTABLE, false);
   }
   itemY += g_buttonHeight + 5;
   createButton("ChatGPT_ClearButton", sidebarX + 5, itemY, g_sidebarWidth - 10, g_buttonHeight, "", clrWhite, 11, clear_original_bg, clrIndianRed);
   ObjectSetInteger(0, "ChatGPT_ClearButton", OBJPROP_ZORDER, 1);
   string clear_icon_resource = (StringLen(g_scaled_clear_resource) > 0) ? g_scaled_clear_resource : resourceClear;
   iconX = sidebarExpanded ? sidebarX + 5 + 10 : sidebarX + 5 + (g_sidebarWidth - 10 - 30)/2;
   createBitmapLabel("ChatGPT_ClearIcon", iconX, itemY + (g_buttonHeight - 30)/2, 30, 30, clear_icon_resource, clrNONE, CORNER_LEFT_UPPER);
   ObjectSetInteger(0, "ChatGPT_ClearIcon", OBJPROP_ZORDER, 2);
   ObjectSetInteger(0, "ChatGPT_ClearIcon", OBJPROP_SELECTABLE, false);
   if (sidebarExpanded) {
      createLabel("ChatGPT_ClearLabel", sidebarX + 5 + 10 + 30 + 5, itemY + (g_buttonHeight - 20)/2, "Clear", clrWhite, 11, "Arial", CORNER_LEFT_UPPER);
      ObjectSetInteger(0, "ChatGPT_ClearLabel", OBJPROP_ZORDER, 2);
      ObjectSetInteger(0, "ChatGPT_ClearLabel", OBJPROP_SELECTABLE, false);
   }
   itemY += g_buttonHeight + 5;
   createButton("ChatGPT_HistoryButton", sidebarX + 5, itemY, g_sidebarWidth - 10, g_buttonHeight, "", clrBlack, 12, history_original_bg, clrGray);
   ObjectSetInteger(0, "ChatGPT_HistoryButton", OBJPROP_ZORDER, 1);
   string history_icon_resource = (StringLen(g_scaled_history_resource) > 0) ? g_scaled_history_resource : resourceHistory;
   iconX = sidebarExpanded ? sidebarX + 5 + 10 : sidebarX + 5 + (g_sidebarWidth - 10 - 30)/2;
   createBitmapLabel("ChatGPT_HistoryIcon", iconX, itemY + (g_buttonHeight - 30)/2, 30, 30, history_icon_resource, clrNONE, CORNER_LEFT_UPPER);
   ObjectSetInteger(0, "ChatGPT_HistoryIcon", OBJPROP_ZORDER, 2);
   ObjectSetInteger(0, "ChatGPT_HistoryIcon", OBJPROP_SELECTABLE, false);
   if (sidebarExpanded) {
      createLabel("ChatGPT_HistoryLabel", sidebarX + 5 + 10 + 30 + 5, itemY + (g_buttonHeight - 20)/2, "History", clrBlack, 12, "Arial", CORNER_LEFT_UPPER);
      ObjectSetInteger(0, "ChatGPT_HistoryLabel", OBJPROP_ZORDER, 2);
      ObjectSetInteger(0, "ChatGPT_HistoryLabel", OBJPROP_SELECTABLE, false);
   }
   itemY += g_buttonHeight + 5;
   if (sidebarExpanded) {
      int numChats = MathMin(ArraySize(chats), 7);
      int chatIndices[7];
      for (int i = 0; i < numChats; i++) {
         chatIndices[i] = ArraySize(chats) - 1 - i;
      }
      for (int i = 0; i < numChats; i++) {
         int chatIdx = chatIndices[i];
         string hashed_id = EncodeID(chats[chatIdx].id);
         string fullText = chats[chatIdx].title + " > " + hashed_id;
         string labelText = fullText;
         if (StringLen(fullText) > 19) {
            labelText = StringSubstr(fullText, 0, 16) + "...";
         }
         string bgName = "ChatGPT_ChatBg_" + hashed_id;
         createRecLabel(bgName, sidebarX + 5 + 10, itemY, g_sidebarWidth - 10 - 10, 25, clrBeige, 1, DarkenColor(clrBeige, 0.9), BORDER_FLAT, STYLE_SOLID);
         ObjectSetInteger(0, bgName, OBJPROP_ZORDER, 1);
         color textColor = (chats[chatIdx].id == current_chat_id) ? clrBlue : clrBlack;
         createLabel("ChatGPT_ChatLabel_" + hashed_id, sidebarX + 10 + 10, itemY + 3, labelText, textColor, 10, "Arial", CORNER_LEFT_UPPER, ANCHOR_LEFT_UPPER);
         ObjectSetInteger(0, "ChatGPT_ChatLabel_" + hashed_id, OBJPROP_ZORDER, 2);
         string deleteName = "ChatGPT_SideDelete_" + hashed_id;
         createButton(deleteName, sidebarX + g_sidebarWidth - 30, itemY + 3, 0, 20, "V", clrBeige, 15, clrBeige, clrBeige, "Wingdings 2");
         ObjectSetInteger(0, deleteName, OBJPROP_ZORDER, 2);
         int size = ArraySize(side_chat_bgs);
         ArrayResize(side_chat_bgs, size + 1);
         side_chat_bgs[size] = bgName;
         int del_size = ArraySize(side_delete_btns);
         ArrayResize(side_delete_btns, del_size + 1);
         side_delete_btns[del_size] = deleteName;
         itemY += 25 + 3;
      }
   }
   itemY += 5;
   string toggle_text = sidebarExpanded ? "9" : ":";
   createButton("ChatGPT_ToggleButton", sidebarX + 5, itemY, g_sidebarWidth - 10, g_buttonHeight, toggle_text, clrBlack, 15, toggle_original_bg, clrGray,"Webdings");
   ObjectSetInteger(0, "ChatGPT_ToggleButton", OBJPROP_ZORDER, 1);
   ChartRedraw();
}

void ShowSmallHistoryPopup(int button_y) {
   ArrayResize(small_popup_objects, 0);
   ArrayResize(small_chat_bgs, 0);
   ArrayResize(small_delete_btns, 0);
   long history_x = ObjectGetInteger(0, "ChatGPT_HistoryButton", OBJPROP_XDISTANCE);
   long history_w = ObjectGetInteger(0, "ChatGPT_HistoryButton", OBJPROP_XSIZE);
   int popup_x = (int)(history_x + history_w);
   int popup_y = button_y;
   int popup_w = 200;
   int item_height = 25;
   int num_chats = MathMin(ArraySize(chats), 7);
   int items_h = num_chats * (item_height + 5) - 5;
   int popup_h = items_h + g_buttonHeight + 20;
   string popup_bg = "ChatGPT_SmallHistoryBg";
   createRecLabel(popup_bg, popup_x, popup_y, popup_w, popup_h, clrWhite, 1, clrLightGray);
   int size = ArraySize(small_popup_objects);
   ArrayResize(small_popup_objects, size + 1);
   small_popup_objects[size] = popup_bg;
   int item_y = popup_y + 10;
   for (int i = 0; i < num_chats; i++) {
      int chatIdx = ArraySize(chats) - 1 - i;
      string hashed_id = EncodeID(chats[chatIdx].id);
      string labelText = chats[chatIdx].title;
      if (StringLen(labelText) > 25) labelText = StringSubstr(labelText, 0, 22) + "...";
      string bgName = "ChatGPT_SmallChatBg_" + hashed_id;
      createRecLabel(bgName, popup_x + 10, item_y, popup_w - 20, item_height, clrBeige, 1, DarkenColor(clrBeige, 0.9), BORDER_FLAT, STYLE_SOLID);
      string labelName = "ChatGPT_SmallChatLabel_" + hashed_id;
      createLabel(labelName, popup_x + 20, item_y + 3, labelText, clrBlack, 10, "Arial", CORNER_LEFT_UPPER, ANCHOR_LEFT_UPPER);
      string deleteName = "ChatGPT_SmallDelete_" + hashed_id;
      createButton(deleteName, popup_x + popup_w - 20 - 15, item_y + 3, 0, 20, "V", clrBeige, 15, clrBeige, clrBeige, "Wingdings 2");
      size = ArraySize(small_popup_objects);
      ArrayResize(small_popup_objects, size + 3);
      small_popup_objects[size] = bgName;
      small_popup_objects[size + 1] = labelName;
      small_popup_objects[size + 2] = deleteName;
      int bg_size = ArraySize(small_chat_bgs);
      ArrayResize(small_chat_bgs, bg_size + 1);
      small_chat_bgs[bg_size] = bgName;
      int del_size = ArraySize(small_delete_btns);
      ArrayResize(small_delete_btns, del_size + 1);
      small_delete_btns[del_size] = deleteName;
      item_y += item_height + 5;
   }
   string see_more = "ChatGPT_SeeMoreButton";
   createButton(see_more, popup_x + 10, item_y, popup_w - 20, g_buttonHeight, "See All", clrWhite, 11, see_more_original_bg, clrDarkBlue);
   size = ArraySize(small_popup_objects);
   ArrayResize(small_popup_objects, size + 1);
   small_popup_objects[size] = see_more;
   small_popup_x = popup_x;
   small_popup_y = popup_y;
   small_popup_w = popup_w;
   small_popup_h = popup_h;
   showing_small_history_popup = true;
   just_opened_small = true;
}

void DeleteSmallHistoryPopup() {
   for (int i = 0; i < ArraySize(small_popup_objects); i++) {
      ObjectDelete(0, small_popup_objects[i]);
   }
   ArrayResize(small_popup_objects, 0);
   ArrayResize(small_chat_bgs, 0);
   ArrayResize(small_delete_btns, 0);
   showing_small_history_popup = false;
}

void ShowBigHistoryPopup() {
   ArrayResize(big_popup_objects, 0);
   ArrayResize(big_chat_bgs, 0);
   ArrayResize(big_delete_btns, 0);
   big_scroll_pos = 0;
   big_scroll_visible = false;
   int popup_w = g_mainWidth - 20;
   int item_height = 25;
   int num_chats = ArraySize(chats);
   big_total_height = num_chats * (item_height + 5) - 5;
   int max_h = g_displayHeight - 20;
   int content_h = max_h - 40 - 10;
   big_visible_height = content_h - 35;
   int popup_h = max_h;
   big_popup_w = popup_w;
   big_popup_h = popup_h;
   big_popup_x = g_mainContentX + 10;
   big_popup_y = g_mainY + g_headerHeight + g_padding + 10;
   string popup_bg = "ChatGPT_BigHistoryBg";
   createRecLabel(popup_bg, big_popup_x, big_popup_y, popup_w, popup_h, C'250,250,250', 1, clrDodgerBlue);
   int size = ArraySize(big_popup_objects);
   ArrayResize(big_popup_objects, size + 1);
   big_popup_objects[size] = popup_bg;
   string close_button = "ChatGPT_BigCloseButton";
   createButton(close_button, big_popup_x + popup_w - 80 - 10 + 40, big_popup_y + 5, 40, 30, "r", clrRed, 13, big_close_original_bg, clrGray,"Webdings");
   size = ArraySize(big_popup_objects);
   ArrayResize(big_popup_objects, size + 1);
   big_popup_objects[size] = close_button;
   int content_y = big_popup_y + 40;
   string content_bg = "ChatGPT_BigContentBg";
   createRecLabel(content_bg, big_popup_x + 10, content_y, popup_w - 20, content_h, clrWhite, 1, clrGainsboro, BORDER_FLAT, STYLE_SOLID);
   size = ArraySize(big_popup_objects);
   ArrayResize(big_popup_objects, size + 1);
   big_popup_objects[size] = content_bg;
   bool need_big_scroll = big_total_height > big_visible_height;
   int reserved_w = need_big_scroll ? 16 : 0;
   int item_w = popup_w - 20 - 20 - reserved_w;
   UpdateBigHistoryDisplay();
   if (need_big_scroll) {
      CreateBigScrollbar();
      big_scroll_visible = true;
      UpdateBigSliderPosition();
      UpdateBigButtonColors();
   }
   showing_big_history_popup = true;
   just_opened_big = true;
   ChartRedraw();
}

void CreateBigScrollbar() {
   int scrollbar_x = big_popup_x + big_popup_w - 10 - 16;
   int scrollbar_y = big_popup_y + 40 + 16;
   int scrollbar_width = 16;
   int scrollbar_height = big_popup_h - 40 - 10 - 2 * 16;
   int button_size = 16;
   createRecLabel(BIG_SCROLL_LEADER, scrollbar_x, scrollbar_y, scrollbar_width, scrollbar_height, C'220,220,220', 1, clrGainsboro, BORDER_FLAT, STYLE_SOLID, CORNER_LEFT_UPPER);
   createRecLabel(BIG_SCROLL_UP_REC, scrollbar_x, big_popup_y + 40, scrollbar_width, button_size, clrGainsboro, 1, clrGainsboro, BORDER_FLAT, STYLE_SOLID, CORNER_LEFT_UPPER);
   createLabel(BIG_SCROLL_UP_LABEL, scrollbar_x + 2, big_popup_y + 40 + -2, CharToString(0x35), clrDimGray, getFontSizeByDPI(10), "Webdings", CORNER_LEFT_UPPER);
   createRecLabel(BIG_SCROLL_DOWN_REC, scrollbar_x, big_popup_y + 40 + (big_popup_h - 40 - 10) - button_size, scrollbar_width, button_size, clrGainsboro, 1, clrGainsboro, BORDER_FLAT, STYLE_SOLID, CORNER_LEFT_UPPER);
   createLabel(BIG_SCROLL_DOWN_LABEL, scrollbar_x + 2, big_popup_y + 40 + (big_popup_h - 40 - 10) - button_size + -2, CharToString(0x36), clrDimGray, getFontSizeByDPI(10), "Webdings", CORNER_LEFT_UPPER);
   big_slider_height = CalculateBigSliderHeight();
   createRecLabel(BIG_SCROLL_SLIDER, scrollbar_x, big_popup_y + 40 + (big_popup_h - 40 - 10) - button_size - big_slider_height, scrollbar_width, big_slider_height, clrSilver, 1, clrGainsboro, BORDER_FLAT, STYLE_SOLID, CORNER_LEFT_UPPER);
   int size = ArraySize(big_popup_objects);
   ArrayResize(big_popup_objects, size + 6);
   big_popup_objects[size] = BIG_SCROLL_LEADER;
   big_popup_objects[size + 1] = BIG_SCROLL_UP_REC;
   big_popup_objects[size + 2] = BIG_SCROLL_UP_LABEL;
   big_popup_objects[size + 3] = BIG_SCROLL_DOWN_REC;
   big_popup_objects[size + 4] = BIG_SCROLL_DOWN_LABEL;
   big_popup_objects[size + 5] = BIG_SCROLL_SLIDER;
}

int CalculateBigSliderHeight() {
   int scroll_area_height = big_popup_h - 40 - 25 - 2 * 16;
   int slider_min_height = 20;
   if (big_total_height <= big_visible_height) return scroll_area_height;
   double visible_ratio = (double)big_visible_height / big_total_height;
   int height = (int)MathFloor(scroll_area_height * visible_ratio);
   return MathMax(slider_min_height, height);
}

void UpdateBigSliderPosition() {
   int scrollbar_x = big_popup_x + big_popup_w - 10 - 16;
   int scrollbar_y = big_popup_y + 40 + 16;
   int scroll_area_height = big_popup_h - 40 - 25 - 2 * 16;
   int max_scroll = MathMax(0, big_total_height - big_visible_height);
   if (max_scroll <= 0) return;
   double scroll_ratio = (double)big_scroll_pos / max_scroll;
   int scroll_area_y_max = scrollbar_y + scroll_area_height - big_slider_height;
   int scroll_area_y_min = scrollbar_y;
   int new_y = scroll_area_y_min + (int)(scroll_ratio * (scroll_area_y_max - scroll_area_y_min));
   new_y = MathMax(scroll_area_y_min, MathMin(new_y, scroll_area_y_max));
   ObjectSetInteger(0, BIG_SCROLL_SLIDER, OBJPROP_YDISTANCE, new_y);
}

void UpdateBigButtonColors() {
   int max_scroll = MathMax(0, big_total_height - big_visible_height);
   if (big_scroll_pos == 0) {
      ObjectSetInteger(0, BIG_SCROLL_UP_LABEL, OBJPROP_COLOR, clrSilver);
   } else {
      ObjectSetInteger(0, BIG_SCROLL_UP_LABEL, OBJPROP_COLOR, clrDimGray);
   }
   if (big_scroll_pos == max_scroll) {
      ObjectSetInteger(0, BIG_SCROLL_DOWN_LABEL, OBJPROP_COLOR, clrSilver);
   } else {
      ObjectSetInteger(0, BIG_SCROLL_DOWN_LABEL, OBJPROP_COLOR, clrDimGray);
   }
}

void BigScrollUp() {
   if (big_scroll_pos > 0) {
      big_scroll_pos = MathMax(0, big_scroll_pos - 30);
      UpdateBigHistoryDisplay();
      if (big_scroll_visible) {
         UpdateBigSliderPosition();
         UpdateBigButtonColors();
      }
   }
}

void BigScrollDown() {
   int max_scroll = MathMax(0, big_total_height - big_visible_height);
   if (big_scroll_pos < max_scroll) {
      big_scroll_pos = MathMin(max_scroll, big_scroll_pos + 30);
      UpdateBigHistoryDisplay();
      if (big_scroll_visible) {
         UpdateBigSliderPosition();
         UpdateBigButtonColors();
      }
   }
}

void UpdateBigHistoryDisplay() {
   int total = ObjectsTotal(0, 0, -1);
   for (int j = total - 1; j >= 0; j--) {
      string name = ObjectName(0, j, 0, -1);
      if (StringFind(name, "ChatGPT_BigChatBg_") == 0 || StringFind(name, "ChatGPT_BigChatLabel_") == 0 || StringFind(name, "ChatGPT_BigDelete_") == 0) {
         ObjectDelete(0, name);
      }
   }
   ArrayResize(big_chat_bgs, 0);
   ArrayResize(big_delete_btns, 0);
   int content_y = big_popup_y + 40;
   int content_h = big_popup_h - 40 - 10;
   int item_height = 25;
   int num_chats = ArraySize(chats);
   big_total_height = num_chats * (item_height + 5) - 5;
   bool need_big_scroll = big_total_height > big_visible_height;
   int reserved_w = need_big_scroll ? 16 : 0;
   int item_w = big_popup_w - 20 - 20 - reserved_w;
   int item_y = content_y + 10 - big_scroll_pos;
   int end_y = content_y + content_h - 25;
   int start_idx = 0;
   int current_h = 0;
   for (int i = 0; i < num_chats; i++) {
      if (current_h >= big_scroll_pos) {
         start_idx = i;
         item_y = content_y + 10 + (current_h - big_scroll_pos);
         break;
      }
      current_h += item_height + 5;
   }
   int visible_count = 0;
   current_h = 0;
   for (int i = start_idx; i < num_chats; i++) {
      if (current_h + item_height > big_visible_height) break;
      current_h += item_height + 5;
      visible_count++;
   }
   for (int i = 0; i < visible_count; i++) {
      int chatIdx = num_chats - 1 - (start_idx + i);
      string hashed_id = EncodeID(chats[chatIdx].id);
      string fullText = chats[chatIdx].title + " > " + hashed_id;
      string labelText = fullText;
      if (StringLen(fullText) > 35) {
         labelText = StringSubstr(fullText, 0, 32) + "...";
      }
      string bgName = "ChatGPT_BigChatBg_" + hashed_id;
      if (item_y >= content_y + 10 && item_y < end_y) {
         createRecLabel(bgName, big_popup_x + 20, item_y, item_w, item_height, clrBeige, 1, DarkenColor(clrBeige, 0.9), BORDER_FLAT, STYLE_SOLID);
      }
      string labelName = "ChatGPT_BigChatLabel_" + hashed_id;
      if (item_y >= content_y + 10 && item_y < end_y) {
         createLabel(labelName, big_popup_x + 30, item_y + 3, labelText, clrBlack, 10, "Arial", CORNER_LEFT_UPPER, ANCHOR_LEFT_UPPER);
      }
      string deleteName = "ChatGPT_BigDelete_" + hashed_id;
      if (item_y >= content_y + 10 && item_y < end_y) {
         createButton(deleteName, big_popup_x + 20 + item_w - 15, item_y + 3, 0, 20, "V", clrBeige, 15, clrBeige, clrBeige, "Wingdings 2");
      }
      int size = ArraySize(big_popup_objects);
      ArrayResize(big_popup_objects, size + 3);
      big_popup_objects[size] = bgName;
      big_popup_objects[size + 1] = labelName;
      big_popup_objects[size + 2] = deleteName;
      int bg_size = ArraySize(big_chat_bgs);
      ArrayResize(big_chat_bgs, bg_size + 1);
      big_chat_bgs[bg_size] = bgName;
      int del_size = ArraySize(big_delete_btns);
      ArrayResize(big_delete_btns, del_size + 1);
      big_delete_btns[del_size] = deleteName;
      item_y += item_height + 5;
   }
   ChartRedraw();
}

void DeleteBigHistoryPopup() {
   for (int i = 0; i < ArraySize(big_popup_objects); i++) {
      ObjectDelete(0, big_popup_objects[i]);
   }
   ArrayResize(big_popup_objects, 0);
   ArrayResize(big_chat_bgs, 0);
   ArrayResize(big_delete_btns, 0);
   showing_big_history_popup = false;
   big_scroll_visible = false;
}

void ShowSearchPopup() {
   current_search_query = "";
   ArrayResize(search_popup_objects, 0);
   ArrayResize(search_chat_bgs, 0);
   ArrayResize(search_delete_btns, 0);
   search_scroll_pos = 0;
   search_scroll_visible = false;
   int popup_w = g_mainWidth - 20;
   int item_height = 25;
   int num_chats = ArraySize(chats);
   search_total_height = num_chats * (item_height + 5) - 5;
   int max_h = g_displayHeight - 20;
   int content_h = max_h - 40 - 40 - 10;
   search_visible_height = content_h - 35;
   int popup_h = max_h;
   search_popup_w = popup_w;
   search_popup_h = popup_h;
   search_popup_x = g_mainContentX + 10;
   search_popup_y = g_mainY + g_headerHeight + g_padding + 10;
   string popup_bg = "ChatGPT_SearchBg";
   createRecLabel(popup_bg, search_popup_x, search_popup_y, popup_w, popup_h, C'250,250,250', 1, clrDodgerBlue);
   int size = ArraySize(search_popup_objects);
   ArrayResize(search_popup_objects, size + 1);
   search_popup_objects[size] = popup_bg;
   string close_button = "ChatGPT_SearchCloseButton";
   createButton(close_button, search_popup_x + popup_w -40 -10, search_popup_y + 5, 40, 30, "r", clrRed, 13, search_close_original_bg, clrGray,"Webdings");
   size = ArraySize(search_popup_objects);
   ArrayResize(search_popup_objects, size + 1);
   search_popup_objects[size] = close_button;
   string search_edit = "ChatGPT_SearchInput";
   createEdit(search_edit, search_popup_x + 10, search_popup_y + 5, popup_w - 20 - 40 - 10, 30, "", clrBlack, 16, clrGainsboro, clrLightGray, "Calibri");
   ObjectSetInteger(0, search_edit, OBJPROP_BORDER_TYPE, BORDER_FLAT);
   size = ArraySize(search_popup_objects);
   ArrayResize(search_popup_objects, size + 1);
   search_popup_objects[size] = search_edit;
   string search_placeholder = "ChatGPT_SearchPlaceholder";
   int lineHeight = TextGetHeight("A", "Arial", 11);
   int labelY = search_popup_y + 5 + (30 - lineHeight) / 2 - 3;
   createLabel(search_placeholder, search_popup_x + 10 + 2, labelY, "Search Chats", clrGray, 11, "Arial", CORNER_LEFT_UPPER);
   size = ArraySize(search_popup_objects);
   ArrayResize(search_popup_objects, size + 1);
   search_popup_objects[size] = search_placeholder;
   int content_y = search_popup_y + 40 + 40;
   string content_bg = "ChatGPT_SearchContentBg";
   createRecLabel(content_bg, search_popup_x + 10, content_y, popup_w - 20, content_h, clrWhite, 1, clrGainsboro, BORDER_FLAT, STYLE_SOLID);
   size = ArraySize(search_popup_objects);
   ArrayResize(search_popup_objects, size + 1);
   search_popup_objects[size] = content_bg;
   bool need_search_scroll = search_total_height > search_visible_height;
   int reserved_w = need_search_scroll ? 16 : 0;
   int item_w = popup_w - 20 - 20 - reserved_w;
   UpdateSearchDisplay();
   if (need_search_scroll) {
      CreateSearchScrollbar();
      search_scroll_visible = true;
      UpdateSearchSliderPosition();
      UpdateSearchButtonColors();
   }
   showing_search_popup = true;
   just_opened_search = true;
   ChartRedraw();
}

void CreateSearchScrollbar() {
   int scrollbar_x = search_popup_x + search_popup_w - 10 - 16;
   int scrollbar_y = search_popup_y + 40 + 40 + 16;
   int scrollbar_width = 16;
   int scrollbar_height = search_popup_h - 40 - 40 - 10 - 2 * 16;
   int button_size = 16;
   createRecLabel(SEARCH_SCROLL_LEADER, scrollbar_x, scrollbar_y, scrollbar_width, scrollbar_height, C'220,220,220', 1, clrGainsboro, BORDER_FLAT, STYLE_SOLID, CORNER_LEFT_UPPER);
   createRecLabel(SEARCH_SCROLL_UP_REC, scrollbar_x, search_popup_y + 40 + 40, scrollbar_width, button_size, clrGainsboro, 1, clrGainsboro, BORDER_FLAT, STYLE_SOLID, CORNER_LEFT_UPPER);
   createLabel(SEARCH_SCROLL_UP_LABEL, scrollbar_x + 2, search_popup_y + 40 + 40 + -2, CharToString(0x35), clrDimGray, getFontSizeByDPI(10), "Webdings", CORNER_LEFT_UPPER);
   createRecLabel(SEARCH_SCROLL_DOWN_REC, scrollbar_x, search_popup_y + 40 + 40 + (search_popup_h - 40 - 40 - 10) - button_size, scrollbar_width, button_size, clrGainsboro, 1, clrGainsboro, BORDER_FLAT, STYLE_SOLID, CORNER_LEFT_UPPER);
   createLabel(SEARCH_SCROLL_DOWN_LABEL, scrollbar_x + 2, search_popup_y + 40 + 40 + (search_popup_h - 40 - 40 - 10) - button_size + -2, CharToString(0x36), clrDimGray, getFontSizeByDPI(10), "Webdings", CORNER_LEFT_UPPER);
   search_slider_height = CalculateSearchSliderHeight();
   createRecLabel(SEARCH_SCROLL_SLIDER, scrollbar_x, search_popup_y + 40 + 40 + (search_popup_h - 40 - 40 - 10) - button_size - search_slider_height, scrollbar_width, search_slider_height, clrSilver, 1, clrGainsboro, BORDER_FLAT, STYLE_SOLID, CORNER_LEFT_UPPER);
   int size = ArraySize(search_popup_objects);
   ArrayResize(search_popup_objects, size + 6);
   search_popup_objects[size] = SEARCH_SCROLL_LEADER;
   search_popup_objects[size + 1] = SEARCH_SCROLL_UP_REC;
   search_popup_objects[size + 2] = SEARCH_SCROLL_UP_LABEL;
   search_popup_objects[size + 3] = SEARCH_SCROLL_DOWN_REC;
   search_popup_objects[size + 4] = SEARCH_SCROLL_DOWN_LABEL;
   search_popup_objects[size + 5] = SEARCH_SCROLL_SLIDER;
}

int CalculateSearchSliderHeight() {
   int scroll_area_height = search_popup_h - 40 - 40 - 25 - 2 * 16;
   int slider_min_height = 20;
   if (search_total_height <= search_visible_height) return scroll_area_height;
   double visible_ratio = (double)search_visible_height / search_total_height;
   int height = (int)MathFloor(scroll_area_height * visible_ratio);
   return MathMax(slider_min_height, height);
}

void UpdateSearchSliderPosition() {
   int scrollbar_x = search_popup_x + search_popup_w - 10 - 16;
   int scrollbar_y = search_popup_y + 40 + 40 + 16;
   int scroll_area_height = search_popup_h - 40 - 40 - 25 - 2 * 16;
   int max_scroll = MathMax(0, search_total_height - search_visible_height);
   if (max_scroll <= 0) return;
   double scroll_ratio = (double)search_scroll_pos / max_scroll;
   int scroll_area_y_max = scrollbar_y + scroll_area_height - search_slider_height;
   int scroll_area_y_min = scrollbar_y;
   int new_y = scroll_area_y_min + (int)(scroll_ratio * (scroll_area_y_max - scroll_area_y_min));
   new_y = MathMax(scroll_area_y_min, MathMin(new_y, scroll_area_y_max));
   ObjectSetInteger(0, SEARCH_SCROLL_SLIDER, OBJPROP_YDISTANCE, new_y);
}

void UpdateSearchButtonColors() {
   int max_scroll = MathMax(0, search_total_height - search_visible_height);
   if (search_scroll_pos == 0) {
      ObjectSetInteger(0, SEARCH_SCROLL_UP_LABEL, OBJPROP_COLOR, clrSilver);
   } else {
      ObjectSetInteger(0, SEARCH_SCROLL_UP_LABEL, OBJPROP_COLOR, clrDimGray);
   }
   if (search_scroll_pos == max_scroll) {
      ObjectSetInteger(0, SEARCH_SCROLL_DOWN_LABEL, OBJPROP_COLOR, clrSilver);
   } else {
      ObjectSetInteger(0, SEARCH_SCROLL_DOWN_LABEL, OBJPROP_COLOR, clrDimGray);
   }
}

void SearchScrollUp() {
   if (search_scroll_pos > 0) {
      search_scroll_pos = MathMax(0, search_scroll_pos - 30);
      UpdateSearchDisplay();
      if (search_scroll_visible) {
         UpdateSearchSliderPosition();
         UpdateSearchButtonColors();
      }
   }
}

void SearchScrollDown() {
   int max_scroll = MathMax(0, search_total_height - search_visible_height);
   if (search_scroll_pos < max_scroll) {
      search_scroll_pos = MathMin(max_scroll, search_scroll_pos + 30);
      UpdateSearchDisplay();
      if (search_scroll_visible) {
         UpdateSearchSliderPosition();
         UpdateSearchButtonColors();
      }
   }
}

void UpdateSearchDisplay() {
   int total = ObjectsTotal(0, 0, -1);
   for (int j = total - 1; j >= 0; j--) {
      string name = ObjectName(0, j, 0, -1);
      if (StringFind(name, "ChatGPT_SearchChatBg_") == 0 || StringFind(name, "ChatGPT_SearchChatLabel_") == 0 || StringFind(name, "ChatGPT_SearchDelete_") == 0) {
         ObjectDelete(0, name);
      }
   }
   ArrayResize(search_chat_bgs, 0);
   ArrayResize(search_delete_btns, 0);
   Chat filtered[];
   ArrayResize(filtered, 0);
   for (int i = 0; i < ArraySize(chats); i++) {
      string lower_title = chats[i].title;
      StringToLower(lower_title);
      string lower_history = chats[i].history;
      StringToLower(lower_history);
      string lower_query = current_search_query;
      StringToLower(lower_query);
      if (StringFind(lower_title, lower_query) >= 0 || StringFind(lower_history, lower_query) >= 0 || lower_query == "") {
         int fsize = ArraySize(filtered);
         ArrayResize(filtered, fsize + 1);
         filtered[fsize] = chats[i];
      }
   }
   int num_chats = ArraySize(filtered);
   search_total_height = num_chats * (25 + 5) - 5;
   bool need_search_scroll = search_total_height > search_visible_height;
   bool prev_search_scroll_visible = search_scroll_visible;
   search_scroll_visible = need_search_scroll;
   if (search_scroll_visible != prev_search_scroll_visible) {
      if (search_scroll_visible) {
         CreateSearchScrollbar();
      } else {
         DeleteSearchScrollbar();
      }
   }
   int reserved_w = search_scroll_visible ? 16 : 0;
   int item_w = search_popup_w - 20 - 20 - reserved_w;
   int item_y = search_popup_y + 40 + 40 + 10 - search_scroll_pos;
   int end_y = search_popup_y + 40 + 40 + (search_popup_h - 40 - 40 - 10) - 25;
   int start_idx = 0;
   int current_h = 0;
   for (int i = 0; i < num_chats; i++) {
      if (current_h >= search_scroll_pos) {
         start_idx = i;
         item_y = search_popup_y + 40 + 40 + 10 + (current_h - search_scroll_pos);
         break;
      }
      current_h += 25 + 5;
   }
   int visible_count = 0;
   current_h = 0;
   for (int i = start_idx; i < num_chats; i++) {
      if (current_h + 25 > search_visible_height) break;
      current_h += 25 + 5;
      visible_count++;
   }
   for (int i = 0; i < visible_count; i++) {
      int chatIdx = num_chats - 1 - (start_idx + i);
      string hashed_id = EncodeID(filtered[chatIdx].id);
      string fullText = filtered[chatIdx].title + " > " + hashed_id;
      string labelText = fullText;
      if (StringLen(fullText) > 35) {
         labelText = StringSubstr(fullText, 0, 32) + "...";
      }
      string bgName = "ChatGPT_SearchChatBg_" + hashed_id;
      if (item_y >= search_popup_y + 40 + 40 + 10 && item_y < end_y) {
         createRecLabel(bgName, search_popup_x + 20, item_y, item_w, 25, clrBeige, 1, DarkenColor(clrBeige, 0.9), BORDER_FLAT, STYLE_SOLID);
      }
      string labelName = "ChatGPT_SearchChatLabel_" + hashed_id;
      if (item_y >= search_popup_y + 40 + 40 + 10 && item_y < end_y) {
         createLabel(labelName, search_popup_x + 30, item_y + 3, labelText, clrBlack, 10, "Arial", CORNER_LEFT_UPPER, ANCHOR_LEFT_UPPER);
      }
      string deleteName = "ChatGPT_SearchDelete_" + hashed_id;
      if (item_y >= search_popup_y + 40 + 40 + 10 && item_y < end_y) {
         createButton(deleteName, search_popup_x + 20 + item_w - 25, item_y + 3, 0, 20, "V", clrBeige, 15, clrBeige, clrBeige, "Wingdings 2");
      }
      int size = ArraySize(search_popup_objects);
      ArrayResize(search_popup_objects, size + 3);
      search_popup_objects[size] = bgName;
      search_popup_objects[size + 1] = labelName;
      search_popup_objects[size + 2] = deleteName;
      int bg_size = ArraySize(search_chat_bgs);
      ArrayResize(search_chat_bgs, bg_size + 1);
      search_chat_bgs[bg_size] = bgName;
      int del_size = ArraySize(search_delete_btns);
      ArrayResize(search_delete_btns, del_size + 1);
      search_delete_btns[del_size] = deleteName;
      item_y += 25 + 5;
   }
   if (search_scroll_visible) {
      search_slider_height = CalculateSearchSliderHeight();
      ObjectSetInteger(0, SEARCH_SCROLL_SLIDER, OBJPROP_YSIZE, search_slider_height);
      UpdateSearchSliderPosition();
      UpdateSearchButtonColors();
   }
   ChartRedraw();
}

void DeleteSearchScrollbar() {
   ObjectDelete(0, SEARCH_SCROLL_LEADER);
   ObjectDelete(0, SEARCH_SCROLL_UP_REC);
   ObjectDelete(0, SEARCH_SCROLL_UP_LABEL);
   ObjectDelete(0, SEARCH_SCROLL_DOWN_REC);
   ObjectDelete(0, SEARCH_SCROLL_DOWN_LABEL);
   ObjectDelete(0, SEARCH_SCROLL_SLIDER);
}

void DeleteSearchPopup() {
   for (int i = 0; i < ArraySize(search_popup_objects); i++) {
      ObjectDelete(0, search_popup_objects[i]);
   }
   DeleteSearchScrollbar();
   ArrayResize(search_popup_objects, 0);
   ArrayResize(search_chat_bgs, 0);
   ArrayResize(search_delete_btns, 0);
   showing_search_popup = false;
   search_scroll_visible = false;
}

void CreateDashboard() {
   objCount = 0;
   g_mainHeight = g_headerHeight + 2 * g_padding + g_displayHeight + g_footerHeight;
   int displayX = g_mainContentX + g_sidePadding;
   int displayY = g_mainY + g_headerHeight + g_padding;
   int displayW = g_mainWidth - 2 * g_sidePadding;
   int footerY = displayY + g_displayHeight + g_padding;
   int promptY = footerY + g_margin;
   int buttonsY = promptY + g_promptHeight + g_margin;
   int chartX = g_mainContentX + g_sidePadding;
   int sendX = g_mainContentX + g_mainWidth - g_sidePadding - sendButtonW;
   dashboardObjects[objCount++] = "ChatGPT_MainContainer";
   createRecLabel("ChatGPT_MainContainer", g_mainContentX, g_mainY, g_mainWidth, g_mainHeight, clrWhite, 1, clrLightGray);
   dashboardObjects[objCount++] = "ChatGPT_HeaderBg";
   createRecLabel("ChatGPT_HeaderBg", g_mainContentX, g_mainY, g_mainWidth, g_headerHeight, clrWhiteSmoke, 0, clrNONE);
   string logo_resource = (StringLen(g_scaled_image_resource) > 0) ? g_scaled_image_resource : resourceImg;
   dashboardObjects[objCount++] = "ChatGPT_HeaderLogo";
   createBitmapLabel("ChatGPT_HeaderLogo", g_mainContentX + g_sidePadding, g_mainY + (g_headerHeight - 40)/2, 104, 40, logo_resource, clrWhite, CORNER_LEFT_UPPER);
   string title = "ChatGPT AI EA";
   string titleFont = "Arial Rounded MT Bold";
   int titleSize = 14;
   TextSetFont(titleFont, titleSize);
   uint titleWid, titleHei;
   TextGetSize(title, titleWid, titleHei);
   int titleY = g_mainY + (g_headerHeight - (int)titleHei) / 2 - 4;
   int titleX = g_mainContentX + g_sidePadding + 104 + 5;
   dashboardObjects[objCount++] = "ChatGPT_TitleLabel";
   createLabel("ChatGPT_TitleLabel", titleX, titleY, title, clrDarkSlateGray, titleSize, titleFont, CORNER_LEFT_UPPER, ANCHOR_LEFT_UPPER);
   string dateStr = TimeToString(TimeTradeServer(), TIME_MINUTES);
   string dateFont = "Arial";
   int dateSize = 12;
   TextSetFont(dateFont, dateSize);
   uint dateWid, dateHei;
   TextGetSize(dateStr, dateWid, dateHei);
   int dateX = g_mainContentX + g_mainWidth / 2 - (int)(dateWid / 2) + 20;
   int dateY = g_mainY + (g_headerHeight - (int)dateHei) / 2 - 4;
   dashboardObjects[objCount++] = "ChatGPT_DateLabel";
   createLabel("ChatGPT_DateLabel", dateX, dateY, dateStr, clrSlateGray, dateSize, dateFont, CORNER_LEFT_UPPER, ANCHOR_LEFT_UPPER);
   int closeWidth = 32;
   int closeX = g_mainContentX + g_mainWidth - closeWidth - g_sidePadding;
   int closeY = g_mainY + 4;
   dashboardObjects[objCount++] = "ChatGPT_CloseButton";
   createButton("ChatGPT_CloseButton", closeX, closeY, closeWidth, g_headerHeight - 8, "r", clrRed, 20, close_original_bg, clrWhiteSmoke, "Webdings");
   dashboardObjects[objCount++] = "ChatGPT_ResponseBg";
   createRecLabel("ChatGPT_ResponseBg", displayX, displayY, displayW, g_displayHeight, clrWhite, 1, clrGainsboro, BORDER_FLAT, STYLE_SOLID);
   dashboardObjects[objCount++] = "ChatGPT_FooterBg";
   createRecLabel("ChatGPT_FooterBg", g_mainContentX, footerY, g_mainWidth, g_footerHeight, clrGainsboro, 0, clrNONE);
   dashboardObjects[objCount++] = "ChatGPT_PromptBg";
   createRecLabel("ChatGPT_PromptBg", displayX, promptY, displayW, g_promptHeight, g_promptBg, 1, g_promptBg, BORDER_FLAT, STYLE_SOLID);
   int editY = promptY + g_promptHeight - g_editHeight - 5;
   int editX = displayX + g_textPadding;
   g_editW = displayW - 2 * g_textPadding;
   dashboardObjects[objCount++] = "ChatGPT_PromptEdit";
   createEdit("ChatGPT_PromptEdit", editX, editY, g_editW, g_editHeight, "", clrBlack, 13, DarkenColor(g_promptBg,0.93), DarkenColor(g_promptBg,0.87),"Calibri");
   ObjectSetInteger(0, "ChatGPT_PromptEdit", OBJPROP_BORDER_TYPE, BORDER_FLAT);
   
   
   dashboardObjects[objCount++] = "ChatGPT_GetChartButton";
   createButton("ChatGPT_GetChartButton", chartX, buttonsY, chartButtonW, g_buttonHeight, "?", clrBlack, 25, chart_button_bg, clrDarkGreen, "Wingdings");
   
   int signalX = chartX + chartButtonW + 10;
   createButton("ChatGPT_GetSignalButton", signalX, buttonsY, signalButtonW, g_buttonHeight, "Get Signal", clrBlack, 11, signal_button_bg, clrDarkBlue);
   dashboardObjects[objCount++] = "ChatGPT_GetSignalButton";
   
   dashboardObjects[objCount++] = "ChatGPT_SendPromptButton";
   createButton("ChatGPT_SendPromptButton", sendX, buttonsY, sendButtonW, g_buttonHeight, "@", clrWhite, 23, button_original_bg, clrDarkBlue, "Wingdings 3");   
   
   ChartRedraw();
}

int TextGetHeight(string text, string font, int fontSize) {
   uint wid, hei;
   TextSetFont(font, fontSize);
   TextGetSize(text, wid, hei);
   return (int)hei;
}

void ComputeLinesAndHeight(const string &font, const int fontSize, const int timestampFontSize,
                           const int adjustedLineHeight, const int adjustedTimestampHeight,
                           const int messageMargin, const int maxTextWidth,
                           const string &msgRoles[], const string &msgContents[], const string &msgTimestamps[],
                           const int numMessages, int &totalHeight_out, int &totalLines_out,
                           string &allLines_out[], string &lineRoles_out[], int &lineHeights_out[]) {
   ArrayResize(allLines_out, 0);
   ArrayResize(lineRoles_out, 0);
   ArrayResize(lineHeights_out, 0);
   totalLines_out = 0;
   totalHeight_out = 0;
   for (int m = 0; m < numMessages; m++) {
      string wrappedLines[];
      WrapText(msgContents[m], font, fontSize, maxTextWidth, wrappedLines);
      int numLines = ArraySize(wrappedLines);
      int currSize = ArraySize(allLines_out);
      ArrayResize(allLines_out, currSize + numLines + 1);
      ArrayResize(lineRoles_out, currSize + numLines + 1);
      ArrayResize(lineHeights_out, currSize + numLines + 1);
      for (int l = 0; l < numLines; l++) {
         allLines_out[currSize + l] = wrappedLines[l];
         lineRoles_out[currSize + l] = msgRoles[m];
         lineHeights_out[currSize + l] = adjustedLineHeight;
         totalHeight_out += adjustedLineHeight;
      }
      allLines_out[currSize + numLines] = msgTimestamps[m];
      lineRoles_out[currSize + numLines] = msgRoles[m] + "_timestamp";
      lineHeights_out[currSize + numLines] = adjustedTimestampHeight;
      totalHeight_out += adjustedTimestampHeight;
      totalLines_out += numLines + 1;
      if (m < numMessages - 1) {
         totalHeight_out += messageMargin;
      } else if (m == numMessages - 1 && numMessages > 0) {
         if (totalHeight_out > 0) totalHeight_out -= messageMargin;  // Adjust if last
      }
   }
}

void UpdateResponseDisplay() {
   if (showing_small_history_popup || showing_big_history_popup || showing_search_popup) return;
   int total = ObjectsTotal(0, 0, -1);
   for (int j = total - 1; j >= 0; j--) {
      string name = ObjectName(0, j, 0, -1);
      if (StringFind(name, "ChatGPT_ResponseLine_") == 0 ||
          StringFind(name, "ChatGPT_MessageBg_") == 0 ||
          StringFind(name, "ChatGPT_MessageText_") == 0 ||
          StringFind(name, "ChatGPT_Timestamp_") == 0) {
         ObjectDelete(0, name);
      }
   }
   string displayText = conversationHistory;
   int textX = g_mainContentX + g_sidePadding + g_textPadding;
   int textY = g_mainY + g_headerHeight + g_padding + g_textPadding;
   int fullMaxWidth = g_mainWidth - 2 * g_sidePadding - 2 * g_textPadding;
   if (displayText == "") {
      string objName = "ChatGPT_ResponseLine_0";
      createLabel(objName, textX, textY, "Type your prompt here and click Send to chat with the AI.", clrGray, 10, "Arial", CORNER_LEFT_UPPER, ANCHOR_LEFT_UPPER);
      g_total_height = 0;
      g_visible_height = g_displayHeight - 2 * g_textPadding;
      if (scroll_visible) {
         DeleteScrollbar();
         scroll_visible = false;
      }
      ChartRedraw();
      return;
   }
   string parts[];
   int numParts = StringSplit(displayText, '\n', parts);
   string msgRoles[];
   string msgContents[];
   string msgTimestamps[];
   string currentRole = "";
   string currentContent = "";
   string currentTimestamp = "";
   for (int p = 0; p < numParts; p++) {
      string line = parts[p];
      string trimmed = line;
      StringTrimLeft(trimmed);
      StringTrimRight(trimmed);
      if (StringLen(trimmed) == 0) {
         if (currentRole != "") currentContent += "\n";
         continue;
      }
      if (StringFind(trimmed, "You: ") == 0) {
         if (currentRole != "") {
            int size = ArraySize(msgRoles);
            ArrayResize(msgRoles, size + 1);
            ArrayResize(msgContents, size + 1);
            ArrayResize(msgTimestamps, size + 1);
            msgRoles[size] = currentRole;
            msgContents[size] = currentContent;
            msgTimestamps[size] = currentTimestamp;
         }
         currentRole = "User";
         currentContent = StringSubstr(line, StringFind(line, "You: ") + 5);
         currentTimestamp = "";
         continue;
      } else if (StringFind(trimmed, "AI: ") == 0) {
         if (currentRole != "") {
            int size = ArraySize(msgRoles);
            ArrayResize(msgRoles, size + 1);
            ArrayResize(msgContents, size + 1);
            ArrayResize(msgTimestamps, size + 1);
            msgRoles[size] = currentRole;
            msgContents[size] = currentContent;
            msgTimestamps[size] = currentTimestamp;
         }
         currentRole = "AI";
         currentContent = StringSubstr(line, StringFind(line, "AI: ") + 4);
         currentTimestamp = "";
         continue;
      } else if (IsTimestamp(trimmed)) {
         currentTimestamp = trimmed;
         int size = ArraySize(msgRoles);
         ArrayResize(msgRoles, size + 1);
         ArrayResize(msgContents, size + 1);
         ArrayResize(msgTimestamps, size + 1);
         msgRoles[size] = currentRole;
         msgContents[size] = currentContent;
         msgTimestamps[size] = currentTimestamp;
         currentRole = "";
         currentContent = "";
         currentTimestamp = "";
      } else {
         if (currentRole != "") {
            currentContent += "\n" + line;
         }
      }
   }
   if (currentRole != "") {
      int size = ArraySize(msgRoles);
      ArrayResize(msgRoles, size + 1);
      ArrayResize(msgContents, size + 1);
      ArrayResize(msgTimestamps, size + 1);
      msgRoles[size] = currentRole;
      msgContents[size] = currentContent;
      msgTimestamps[size] = currentTimestamp;
   }
   int numMessages = ArraySize(msgRoles);
   if (numMessages == 0) {
      string objName = "ChatGPT_ResponseLine_0";
      createLabel(objName, textX, textY, "Type your prompt here and click Send to chat with the AI.", clrGray, 10, "Arial", CORNER_LEFT_UPPER, ANCHOR_LEFT_UPPER);
      g_total_height = 0;
      g_visible_height = g_displayHeight - 2 * g_textPadding;
      if (scroll_visible) {
         DeleteScrollbar();
         scroll_visible = false;
      }
      ChartRedraw();
      return;
   }
   string font = "Arial";
   int fontSize = 10;
   int timestampFontSize = 8;
   int lineHeight = TextGetHeight("A", font, fontSize);
   int timestampHeight = TextGetHeight("A", font, timestampFontSize);
   int adjustedLineHeight = lineHeight + g_lineSpacing;
   int adjustedTimestampHeight = timestampHeight + g_lineSpacing;
   int messageMargin = 12;
   int visibleHeight = g_displayHeight - 2 * g_textPadding;
   g_visible_height = visibleHeight;
   string tentativeAllLines[];
   string tentativeLineRoles[];
   int tentativeLineHeights[];
   int tentativeTotalHeight, tentativeTotalLines;
   ComputeLinesAndHeight(font, fontSize, timestampFontSize, adjustedLineHeight, adjustedTimestampHeight,
                         messageMargin, fullMaxWidth, msgRoles, msgContents, msgTimestamps, numMessages,
                         tentativeTotalHeight, tentativeTotalLines, tentativeAllLines, tentativeLineRoles, tentativeLineHeights);
   bool need_scroll = tentativeTotalHeight > visibleHeight;
   bool should_show_scrollbar = false;
   int reserved_width = 0;
   if (ScrollbarMode != SCROLL_WHEEL_ONLY) {
      should_show_scrollbar = need_scroll && (ScrollbarMode == SCROLL_DYNAMIC_ALWAYS || (ScrollbarMode == SCROLL_DYNAMIC_HOVER && mouse_in_display));
      if (should_show_scrollbar) {
         reserved_width = 16;
      }
   }
   string allLines[];
   string lineRoles[];
   int lineHeights[];
   int totalHeight, totalLines;
   if (reserved_width > 0) {
      ComputeLinesAndHeight(font, fontSize, timestampFontSize, adjustedLineHeight, adjustedTimestampHeight,
                            messageMargin, fullMaxWidth - reserved_width, msgRoles, msgContents, msgTimestamps, numMessages,
                            totalHeight, totalLines, allLines, lineRoles, lineHeights);
   } else {
      totalHeight = tentativeTotalHeight;
      totalLines = tentativeTotalLines;
      ArrayCopy(allLines, tentativeAllLines);
      ArrayCopy(lineRoles, tentativeLineRoles);
      ArrayCopy(lineHeights, tentativeLineHeights);
   }
   g_total_height = totalHeight;
   bool prev_scroll_visible = scroll_visible;
   scroll_visible = should_show_scrollbar;
   if (scroll_visible != prev_scroll_visible) {
      if (scroll_visible) {
         CreateScrollbar();
      } else {
         DeleteScrollbar();
      }
   }
   int max_scroll = MathMax(0, totalHeight - visibleHeight);
   if (scroll_pos > max_scroll) scroll_pos = max_scroll;
   if (scroll_pos < 0) scroll_pos = 0;
   if (totalHeight > visibleHeight && scroll_pos == prev_scroll_pos && prev_scroll_pos == -1) {
      scroll_pos = max_scroll;
   }
   if (scroll_visible) {
      slider_height = CalculateSliderHeight();
      ObjectSetInteger(0, SCROLL_SLIDER, OBJPROP_YSIZE, slider_height);
      UpdateSliderPosition();
      UpdateButtonColors();
   }
   int currentY = textY - scroll_pos;
   int endY = textY + visibleHeight;
   int startLineIndex = 0;
   int currentHeight = 0;
   for (int line = 0; line < totalLines; line++) {
      if (currentHeight >= scroll_pos) {
         startLineIndex = line;
         currentY = textY + (currentHeight - scroll_pos);
         break;
      }
      currentHeight += lineHeights[line];
      if (line < totalLines - 1 && StringFind(lineRoles[line], "_timestamp") >= 0 && StringFind(lineRoles[line + 1], "_timestamp") < 0) {
         currentHeight += messageMargin;
      }
   }
   int numVisibleLines = 0;
   int visibleHeightUsed = 0;
   for (int line = startLineIndex; line < totalLines; line++) {
      int lineHeight = lineHeights[line];
      if (visibleHeightUsed + lineHeight > visibleHeight) break;
      visibleHeightUsed += lineHeight;
      numVisibleLines++;
      if (line < totalLines - 1 && StringFind(lineRoles[line], "_timestamp") >= 0 && StringFind(lineRoles[line + 1], "_timestamp") < 0) {
         if (visibleHeightUsed + messageMargin > visibleHeight) break;
         visibleHeightUsed += messageMargin;
      }
   }
   int leftX = g_mainContentX + g_sidePadding + g_textPadding;
   int rightX = g_mainContentX + g_mainWidth - g_sidePadding - g_textPadding - reserved_width;
   color userColor = clrGray;
   color aiColor = clrBlue;
   color timestampColor = clrDarkGray;
   for (int li = 0; li < numVisibleLines; li++) {
      int lineIndex = startLineIndex + li;
      if (lineIndex >= totalLines) break;
      string line = allLines[lineIndex];
      string role = lineRoles[lineIndex];
      bool isTimestamp = StringFind(role, "_timestamp") >= 0;
      int currFontSize = isTimestamp ? timestampFontSize : fontSize;
      color textCol = isTimestamp ? timestampColor : (StringFind(role, "User") >= 0 ? userColor : aiColor);
      string display_line = line;
      if (line == " ") {
         display_line = " ";
         textCol = clrWhite;
      }
      int textX_pos = (StringFind(role, "User") >= 0) ? rightX : leftX;
      ENUM_ANCHOR_POINT textAnchor = (StringFind(role, "User") >= 0) ? ANCHOR_RIGHT_UPPER : ANCHOR_LEFT_UPPER;
      string lineName = "ChatGPT_MessageText_" + IntegerToString(lineIndex);
      if (currentY >= textY && currentY < endY) {
         createLabel(lineName, textX_pos, currentY, display_line, textCol, currFontSize, font, CORNER_LEFT_UPPER, textAnchor);
      }
      currentY += lineHeights[lineIndex];
      if (lineIndex < totalLines - 1 && StringFind(lineRoles[lineIndex], "_timestamp") >= 0 && StringFind(lineRoles[lineIndex + 1], "_timestamp") < 0) {
         currentY += messageMargin;
      }
   }
   ChartRedraw();
}

void UpdatePromptDisplay() {
   if (showing_small_history_popup || showing_big_history_popup || showing_search_popup) return;
   int total = ObjectsTotal(0, 0, -1);
   for (int j = total - 1; j >= 0; j--) {
      string name = ObjectName(0, j, 0, -1);
      if (StringFind(name, "ChatGPT_PromptLine_") == 0) {
         ObjectDelete(0, name);
      }
   }
   int promptX = g_mainContentX + g_sidePadding;
   int footerY = g_mainY + g_headerHeight + g_padding + g_displayHeight + g_padding;
   int promptY = footerY + g_margin;
   int textX = promptX + g_textPadding;
   int textY = promptY + g_textPadding;
   int editY = promptY + g_promptHeight - g_editHeight - 5;
   int fullMaxWidth = g_mainWidth - 2 * g_sidePadding - 2 * g_textPadding;
   int visibleHeight = editY - textY - g_textPadding - g_margin;
   if (currentPrompt == "") {
      p_total_height = 0;
      p_visible_height = visibleHeight;
      if (p_scroll_visible) {
         DeletePromptScrollbar();
         p_scroll_visible = false;
      }
      ObjectSetInteger(0, "ChatGPT_PromptEdit", OBJPROP_XSIZE, g_editW);
      ChartRedraw();
      return;
   }
   string font = "Arial";
   int fontSize = 10;
   int lineHeight = TextGetHeight("A", font, fontSize);
   int adjustedLineHeight = lineHeight + g_lineSpacing;
   p_visible_height = visibleHeight;
   string wrappedLines[];
   WrapText(currentPrompt, font, fontSize, fullMaxWidth, wrappedLines);
   int totalLines = ArraySize(wrappedLines);
   int totalHeight = totalLines * adjustedLineHeight;
   bool need_scroll = totalHeight > visibleHeight;
   bool should_show_scrollbar = false;
   int reserved_width = 0;
   if (ScrollbarMode != SCROLL_WHEEL_ONLY) {
      should_show_scrollbar = need_scroll && (ScrollbarMode == SCROLL_DYNAMIC_ALWAYS || (ScrollbarMode == SCROLL_DYNAMIC_HOVER && mouse_in_prompt));
      if (should_show_scrollbar) {
         reserved_width = 16;
      }
   }
   if (reserved_width > 0) {
      WrapText(currentPrompt, font, fontSize, fullMaxWidth - reserved_width, wrappedLines);
      totalLines = ArraySize(wrappedLines);
      totalHeight = totalLines * adjustedLineHeight;
   }
   p_total_height = totalHeight;
   bool prev_p_scroll_visible = p_scroll_visible;
   p_scroll_visible = should_show_scrollbar;
   if (p_scroll_visible != prev_p_scroll_visible) {
      if (p_scroll_visible) {
         CreatePromptScrollbar();
      } else {
         DeletePromptScrollbar();
      }
   }
   ObjectSetInteger(0, "ChatGPT_PromptEdit", OBJPROP_XSIZE, g_editW - reserved_width);
   int max_scroll = MathMax(0, totalHeight - visibleHeight);
   if (p_scroll_pos > max_scroll) p_scroll_pos = max_scroll;
   if (p_scroll_pos < 0) p_scroll_pos = 0;
   if (p_scroll_visible) {
      p_slider_height = CalculatePromptSliderHeight();
      ObjectSetInteger(0, P_SCROLL_SLIDER, OBJPROP_YSIZE, p_slider_height);
      UpdatePromptSliderPosition();
      UpdatePromptButtonColors();
   }
   int currentY = textY - p_scroll_pos;
   int endY = textY + visibleHeight;
   int startLineIndex = 0;
   int currentHeight = 0;
   for (int line = 0; line < totalLines; line++) {
      if (currentHeight >= p_scroll_pos) {
         startLineIndex = line;
         currentY = textY + (currentHeight - p_scroll_pos);
         break;
      }
      currentHeight += adjustedLineHeight;
   }
   int numVisibleLines = 0;
   int visibleHeightUsed = 0;
   for (int line = startLineIndex; line < totalLines; line++) {
      if (visibleHeightUsed + adjustedLineHeight > visibleHeight) break;
      visibleHeightUsed += adjustedLineHeight;
      numVisibleLines++;
   }
   int textX_pos = textX;
   color textCol = clrBlack;
   for (int li = 0; li < numVisibleLines; li++) {
      int lineIndex = startLineIndex + li;
      if (lineIndex >= totalLines) break;
      string line = wrappedLines[lineIndex];
      string display_line = line;
      if (line == " ") {
         display_line = " ";
         textCol = clrWhite;
      }
      string lineName = "ChatGPT_PromptLine_" + IntegerToString(lineIndex);
      if (currentY >= textY && currentY < endY) {
         createLabel(lineName, textX_pos, currentY, display_line, textCol, fontSize, font, CORNER_LEFT_UPPER, ANCHOR_LEFT_UPPER);
      }
      currentY += adjustedLineHeight;
   }
   ChartRedraw();
}

void UpdateDashboardPositions() {
   ObjectSetInteger(0, "ChatGPT_DashboardBg", OBJPROP_XSIZE, g_dashboardWidth);
   ObjectSetInteger(0, "ChatGPT_SidebarBg", OBJPROP_XSIZE, g_sidebarWidth - 2 - 1);
   int diff = g_mainContentX - (g_dashboardX + (sidebarExpanded ? contractedSidebarWidth : expandedSidebarWidth));
   for (int i = 0; i < objCount; i++) {
      string obj = dashboardObjects[i];
      if (ObjectFind(0, obj) >= 0) {
         long curX = ObjectGetInteger(0, obj, OBJPROP_XDISTANCE);
         ObjectSetInteger(0, obj, OBJPROP_XDISTANCE, curX + diff);
      }
   }
   uint date_wid, date_hei;
   string dateStr = TimeToString(TimeTradeServer(), TIME_MINUTES);
   TextSetFont("Arial", 12);
   TextGetSize(dateStr, date_wid, date_hei);
   int dateX = g_mainContentX + g_mainWidth / 2 - (int)(date_wid / 2) + 20;
   int dateY = (int)ObjectGetInteger(0, "ChatGPT_DateLabel", OBJPROP_YDISTANCE);
   ObjectSetInteger(0, "ChatGPT_DateLabel", OBJPROP_XDISTANCE, dateX);
   int closeWidth = 32;
   int closeX = g_mainContentX + g_mainWidth - closeWidth - g_sidePadding;
   ObjectSetInteger(0, "ChatGPT_CloseButton", OBJPROP_XDISTANCE, closeX);
   int promptW = g_mainWidth - 2 * g_sidePadding;
   int editX = g_mainContentX + g_sidePadding + g_textPadding;
   g_editW = promptW - 2 * g_textPadding;
   ObjectSetInteger(0, "ChatGPT_PromptEdit", OBJPROP_XDISTANCE, editX);
   ObjectSetInteger(0, "ChatGPT_PromptEdit", OBJPROP_XSIZE, g_editW);
   
   int chartX = g_mainContentX + g_sidePadding;
   int sendX = g_mainContentX + g_mainWidth - g_sidePadding - sendButtonW;
   
   ObjectSetInteger(0, "ChatGPT_GetChartButton", OBJPROP_XDISTANCE, chartX);
   ObjectSetInteger(0, "ChatGPT_SendPromptButton", OBJPROP_XDISTANCE, sendX);
   
   int signalX = chartX + chartButtonW + 10;
   ObjectSetInteger(0, "ChatGPT_GetSignalButton", OBJPROP_XDISTANCE, signalX);   
   
   int displayX = g_mainContentX + g_sidePadding;
   int displayW = g_mainWidth - 2 * g_sidePadding;
   ObjectSetInteger(0, "ChatGPT_ResponseBg", OBJPROP_XDISTANCE, displayX);
   ObjectSetInteger(0, "ChatGPT_ResponseBg", OBJPROP_XSIZE, displayW);
   ObjectSetInteger(0, "ChatGPT_PromptBg", OBJPROP_XDISTANCE, displayX);
   ObjectSetInteger(0, "ChatGPT_PromptBg", OBJPROP_XSIZE, displayW);
   int footerY = g_mainY + g_headerHeight + g_padding + g_displayHeight + g_padding;
   ObjectSetInteger(0, "ChatGPT_FooterBg", OBJPROP_XDISTANCE, g_mainContentX);
   ObjectSetInteger(0, "ChatGPT_FooterBg", OBJPROP_XSIZE, g_mainWidth);
   if (ObjectFind(0, "ChatGPT_PromptPlaceholder") >= 0) {
      int labelY = (int)ObjectGetInteger(0, "ChatGPT_PromptPlaceholder", OBJPROP_YDISTANCE);
      ObjectSetInteger(0, "ChatGPT_PromptPlaceholder", OBJPROP_XDISTANCE, editX + 2);
   }
   if (scroll_visible) {
      int displayY = g_mainY + g_headerHeight + g_padding;
      int scrollbar_x = displayX + displayW - 16;
      int button_size = 16;
      ObjectSetInteger(0, SCROLL_LEADER, OBJPROP_XDISTANCE, scrollbar_x);
      ObjectSetInteger(0, SCROLL_UP_REC, OBJPROP_XDISTANCE, scrollbar_x);
      ObjectSetInteger(0, SCROLL_UP_LABEL, OBJPROP_XDISTANCE, scrollbar_x + 2);
      ObjectSetInteger(0, SCROLL_DOWN_REC, OBJPROP_XDISTANCE, scrollbar_x);
      ObjectSetInteger(0, SCROLL_DOWN_LABEL, OBJPROP_XDISTANCE, scrollbar_x + 2);
      ObjectSetInteger(0, SCROLL_SLIDER, OBJPROP_XDISTANCE, scrollbar_x);
      UpdateSliderPosition();
   }
   if (p_scroll_visible) {
      int promptX = g_mainContentX + g_sidePadding;
      int promptY = footerY + g_margin;
      int promptW = g_mainWidth - 2 * g_sidePadding;
      int scrollbar_x = promptX + promptW - 16;
      int button_size = 16;
      ObjectSetInteger(0, P_SCROLL_LEADER, OBJPROP_XDISTANCE, scrollbar_x);
      ObjectSetInteger(0, P_SCROLL_UP_REC, OBJPROP_XDISTANCE, scrollbar_x);
      ObjectSetInteger(0, P_SCROLL_UP_LABEL, OBJPROP_XDISTANCE, scrollbar_x + 2);
      ObjectSetInteger(0, P_SCROLL_DOWN_REC, OBJPROP_XDISTANCE, scrollbar_x);
      ObjectSetInteger(0, P_SCROLL_DOWN_LABEL, OBJPROP_XDISTANCE, scrollbar_x + 2);
      ObjectSetInteger(0, P_SCROLL_SLIDER, OBJPROP_XDISTANCE, scrollbar_x);
      UpdatePromptSliderPosition();
   }
}
