//+------------------------------------------------------------------+
//|                                           KalmanVolumeTrend.mq5 |
//|                                  Copyright 2024, BigBeluga/Antigravity |
//|                                https://www.tradingview.com/u/BigBeluga/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, BigBeluga/Antigravity"
#property link      "https://www.tradingview.com/u/BigBeluga/"
#property version   "1.00"
#property indicator_chart_window

#property indicator_buffers 19
#property indicator_plots   3

//--- plot 1: TrendLine
#property indicator_label1  "Trend Line"
#property indicator_type1   DRAW_COLOR_LINE
#property indicator_color1  clrBlue, clrMagenta
#property indicator_style1  STYLE_SOLID
#property indicator_width1  3

//--- plot 2: Volume Bars
#property indicator_label2  "Volume Bars"
#property indicator_type2   DRAW_COLOR_CANDLES
#property indicator_color2  clrBlue, clrMagenta
#property indicator_width2  1

//--- plot 3: Volume Dot (solid tip at volumeBar)
#property indicator_label3  "Volume Dot"
#property indicator_type3   DRAW_COLOR_ARROW
#property indicator_color3  clrBlue, clrMagenta
#property indicator_width3  2

//--- input parameters
input ENUM_APPLIED_PRICE InpSource           = PRICE_CLOSE;      // Source
input double             InpProcessNoise     = 0.0005;           // Process Noise (Q)
input double             InpMeasurementNoise = 0.4;              // Measurement Noise (R)
input double             InpMultiplier       = 2.0;              // Band multiplier
input color              InpUpTrendColor     = C'26,108,202';    // Up Trend Color
input color              InpDnTrendColor     = C'202,26,173';    // Down Trend Color
input int                InpDashX            = 20;               // Dashboard X Offset
input int                InpDashY            = 20;               // Dashboard Y Offset

//--- plot buffers (indices 0-8)
double BuffTrendLine[];      // 0  – Plot 1 data
double BuffTrendColor[];     // 1  – Plot 1 color index
double BuffVolOpen[];        // 2  – Plot 2 open
double BuffVolHigh[];        // 3  – Plot 2 high
double BuffVolLow[];         // 4  – Plot 2 low
double BuffVolClose[];       // 5  – Plot 2 close
double BuffVolColor[];       // 6  – Plot 2 color index
double BuffVolDot[];         // 7  – Plot 3 data (volumeBar tip)
double BuffVolDotColor[];    // 8  – Plot 3 color index

//--- calculation buffers (indices 9-18)
double BuffKF[];             // 9
double BuffUpKF[];           // 10
double BuffLoKF[];           // 11
double BuffATR[];            // 12
double BuffDirection[];      // 13
double BuffDelta[];          // 14
double BuffP[];              // 15
double BuffBuySum[];         // 16
double BuffSellSum[];        // 17
double BuffDeltaSum[];       // 18

int handleATR;

//+------------------------------------------------------------------+
int OnInit()
{
   SetIndexBuffer(0,  BuffTrendLine,    INDICATOR_DATA);
   SetIndexBuffer(1,  BuffTrendColor,   INDICATOR_COLOR_INDEX);
   SetIndexBuffer(2,  BuffVolOpen,      INDICATOR_DATA);
   SetIndexBuffer(3,  BuffVolHigh,      INDICATOR_DATA);
   SetIndexBuffer(4,  BuffVolLow,       INDICATOR_DATA);
   SetIndexBuffer(5,  BuffVolClose,     INDICATOR_DATA);
   SetIndexBuffer(6,  BuffVolColor,     INDICATOR_COLOR_INDEX);
   SetIndexBuffer(7,  BuffVolDot,       INDICATOR_DATA);
   SetIndexBuffer(8,  BuffVolDotColor,  INDICATOR_COLOR_INDEX);
   SetIndexBuffer(9,  BuffKF,           INDICATOR_CALCULATIONS);
   SetIndexBuffer(10, BuffUpKF,         INDICATOR_CALCULATIONS);
   SetIndexBuffer(11, BuffLoKF,         INDICATOR_CALCULATIONS);
   SetIndexBuffer(12, BuffATR,          INDICATOR_CALCULATIONS);
   SetIndexBuffer(13, BuffDirection,    INDICATOR_CALCULATIONS);
   SetIndexBuffer(14, BuffDelta,        INDICATOR_CALCULATIONS);
   SetIndexBuffer(15, BuffP,            INDICATOR_CALCULATIONS);
   SetIndexBuffer(16, BuffBuySum,       INDICATOR_CALCULATIONS);
   SetIndexBuffer(17, BuffSellSum,      INDICATOR_CALCULATIONS);
   SetIndexBuffer(18, BuffDeltaSum,     INDICATOR_CALCULATIONS);

   // Plot 1: TrendLine
   PlotIndexSetInteger(0, PLOT_COLOR_INDEXES, 2);
   PlotIndexSetInteger(0, PLOT_LINE_COLOR, 0, InpUpTrendColor);
   PlotIndexSetInteger(0, PLOT_LINE_COLOR, 1, InpDnTrendColor);
   PlotIndexSetDouble(0,  PLOT_EMPTY_VALUE, EMPTY_VALUE);

   // Plot 2: VolumeBars
   PlotIndexSetInteger(1, PLOT_COLOR_INDEXES, 2);
   PlotIndexSetInteger(1, PLOT_LINE_COLOR, 0, InpUpTrendColor);
   PlotIndexSetInteger(1, PLOT_LINE_COLOR, 1, InpDnTrendColor);
   PlotIndexSetDouble(1,  PLOT_EMPTY_VALUE, EMPTY_VALUE);

   // Plot 3: VolumeDot – Wingdings 159 is a filled bullet circle
   PlotIndexSetInteger(2, PLOT_COLOR_INDEXES, 2);
   PlotIndexSetInteger(2, PLOT_LINE_COLOR, 0, InpUpTrendColor);
   PlotIndexSetInteger(2, PLOT_LINE_COLOR, 1, InpDnTrendColor);
   PlotIndexSetInteger(2, PLOT_ARROW, 159);
   PlotIndexSetDouble(2,  PLOT_EMPTY_VALUE, EMPTY_VALUE);

   // Absolute Zero cleanup of any possible legacy objects (ghosts)
   for(int pass = 0; pass < 2; pass++) 
   {
      for(int i = ObjectsTotal(0) - 1; i >= 0; i--)
      {
         string name = ObjectName(0, i);
         if(StringFind(name, "KVT") >= 0 || StringFind(name, "Kalman") >= 0 || 
            StringFind(name, "Dash") >= 0 || StringFind(name, "Volume") >= 0 ||
            StringFind(name, "Buy") >= 0 || StringFind(name, "Sell") >= 0 ||
            StringFind(name, "Delta") >= 0 || StringFind(name, "Total") >= 0 ||
            StringFind(name, "Header") >= 0 || StringFind(name, "Label") >= 0)
         {
            ObjectDelete(0, name);
         }
      }
   }
   ChartRedraw(0);

   handleATR = iATR(_Symbol, _Period, 200);
   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   for(int i = ObjectsTotal(0) - 1; i >= 0; i--)
   {
      string name = ObjectName(0, i);
      if(StringFind(name, "KVT") >= 0 || StringFind(name, "Kalman") >= 0 || 
         StringFind(name, "Dash") >= 0 || StringFind(name, "Volume") >= 0 ||
         StringFind(name, "Buy") >= 0 || StringFind(name, "Sell") >= 0 ||
         StringFind(name, "Delta") >= 0 || StringFind(name, "Total") >= 0 ||
         StringFind(name, "Header") >= 0 || StringFind(name, "Label") >= 0)
      {
         ObjectDelete(0, name);
      }
   }
   ChartRedraw(0);
}

//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
{
   if(rates_total < 201) return(0);

   int start = prev_calculated - 1;
   if(start < 0) start = 0;

   if(CopyBuffer(handleATR, 0, 0, rates_total, BuffATR) <= 0) return(0);

   double src[];
   ArraySetAsSeries(src, false);
   if(InpSource == PRICE_CLOSE)      ArrayCopy(src, close);
   else if(InpSource == PRICE_OPEN)  ArrayCopy(src, open);
   else if(InpSource == PRICE_HIGH)  ArrayCopy(src, high);
   else if(InpSource == PRICE_LOW)   ArrayCopy(src, low);
   else if(InpSource == PRICE_MEDIAN)   { ArrayResize(src, rates_total); for(int i=0; i<rates_total; i++) src[i] = (high[i]+low[i])/2.0; }
   else if(InpSource == PRICE_TYPICAL)  { ArrayResize(src, rates_total); for(int i=0; i<rates_total; i++) src[i] = (high[i]+low[i]+close[i])/3.0; }
   else if(InpSource == PRICE_WEIGHTED) { ArrayResize(src, rates_total); for(int i=0; i<rates_total; i++) src[i] = (high[i]+low[i]+close[i]*2.0)/4.0; }

   if(prev_calculated == 0)
   {
      ObjectsDeleteAll(0, "KVT_");
      for(int i=0; i<rates_total; i++) { BuffKF[i] = src[i]; BuffP[i] = 1.0; }
   }

   for(int i = start; i < rates_total; i++)
   {
      // --- Kalman Filter ---
      double last_x = (i > 0) ? BuffKF[i-1] : src[i];
      double last_p = (i > 0) ? BuffP[i-1]  : 1.0;

      double p_pred = last_p + InpProcessNoise;
      double k_gain = p_pred / (p_pred + InpMeasurementNoise);
      double x_curr = last_x + k_gain * (src[i] - last_x);
      double p_curr = (1.0 - k_gain) * p_pred;

      BuffKF[i] = x_curr;
      BuffP[i]  = p_curr;

      double cur_atr = BuffATR[i] * InpMultiplier;
      BuffUpKF[i] = x_curr + cur_atr;
      BuffLoKF[i] = x_curr - cur_atr;

      // --- Direction: compare previous close against the CURRENT band (matches PineScript) ---
      bool direction = (i > 0) ? (BuffDirection[i-1] == 1) : false;
      if(i > 0)
      {
         if     (close[i] > BuffUpKF[i] && close[i-1] < BuffUpKF[i]) direction = true;
         else if(close[i] < BuffLoKF[i] && close[i-1] > BuffLoKF[i]) direction = false;
      }
      BuffDirection[i] = direction ? 1 : 0;

      bool t_change = (i > 0) && (BuffDirection[i] != BuffDirection[i-1]);

      double kfTrendLine = direction ? BuffLoKF[i] : BuffUpKF[i];

      // --- Trend line: break (EMPTY_VALUE) on the reversal bar itself ---
      BuffTrendLine[i]  = t_change ? EMPTY_VALUE : kfTrendLine;
      BuffTrendColor[i] = direction ? 0 : 1;

      // --- Delta calculation ---
      double delta_sign = (close[i] > open[i]) ? (double)tick_volume[i] : -(double)tick_volume[i];

      double max_abs_delta = 0.001;
      int start_idx = MathMax(0, i - 99);
      for(int j = start_idx; j <= i; j++)
      {
         double v = (double)tick_volume[j];
         if(v > max_abs_delta) max_abs_delta = v;
      }
      double delta = delta_sign / max_abs_delta * 2.0;
      BuffDelta[i] = delta;

      // --- Volume bars ---
      double atr1 = BuffATR[i];
      double volBarPrice = kfTrendLine + atr1 * MathAbs(delta) * (direction ? 1.0 : -1.0);

      double range_sum = 0;
      int    range_cnt = 0;
      for(int j = MathMax(0, i - 99); j <= i; j++) { range_sum += high[j] - low[j]; range_cnt++; }
      double atr2 = (range_cnt > 0 ? range_sum / range_cnt : 0.0) * 0.1 * (direction ? 1.0 : -1.0);

      BuffVolOpen[i]  = kfTrendLine + atr2;
      BuffVolClose[i] = volBarPrice;
      BuffVolHigh[i]  = MathMax(BuffVolOpen[i], BuffVolClose[i]);
      BuffVolLow[i]   = MathMin(BuffVolOpen[i], BuffVolClose[i]);
      BuffVolColor[i] = (delta > 0) ? 0 : 1;

      // --- Volume dot: solid-color marker at the tip of each volume bar ---
      BuffVolDot[i]      = volBarPrice;
      BuffVolDotColor[i] = (delta > 0) ? 0 : 1;

      // --- Buy/Sell/Delta accumulation (reset at trend change) ---
      double buy   = (t_change || i == 0) ? 0.0 : BuffBuySum[i-1];
      double sell  = (t_change || i == 0) ? 0.0 : BuffSellSum[i-1];
      double d_sum = (t_change || i == 0) ? 0.0 : BuffDeltaSum[i-1];

      buy   += (delta_sign > 0 ? delta_sign : 0.0);
      sell  += (delta_sign < 0 ? MathAbs(delta_sign) : 0.0);
      d_sum += delta_sign;

      BuffBuySum[i]   = buy;
      BuffSellSum[i]  = sell;
      BuffDeltaSum[i] = d_sum;

      // --- Chart objects: only keep the most recent 500 bars ---
      if(i >= rates_total - 500)
      {
         string label_id = "KVT_L_" + IntegerToString(i);
         string x_id     = "KVT_X_" + IntegerToString(i);
         string circ_id  = "KVT_C_" + IntegerToString(i);

         // Volume extreme labels
         if(MathAbs(delta) > 1.5)
         {
            ObjectCreate(0, label_id, OBJ_TEXT, 0, time[i], volBarPrice);
            ObjectSetString(0,  label_id, OBJPROP_TEXT,     FormatVolume(delta_sign));
            ObjectSetInteger(0, label_id, OBJPROP_ANCHOR,   direction ? ANCHOR_TOP : ANCHOR_BOTTOM);
            ObjectSetInteger(0, label_id, OBJPROP_COLOR,    clrWhite);
            ObjectSetInteger(0, label_id, OBJPROP_FONTSIZE, 8);

            ObjectCreate(0, x_id, OBJ_TEXT, 0, time[i], direction ? high[i] : low[i]);
            ObjectSetString(0,  x_id, OBJPROP_TEXT,     direction ? "X" : "x");
            ObjectSetInteger(0, x_id, OBJPROP_ANCHOR,   direction ? ANCHOR_BOTTOM : ANCHOR_TOP);
            ObjectSetInteger(0, x_id, OBJPROP_COLOR,    clrWhite);
            ObjectSetInteger(0, x_id, OBJPROP_FONTSIZE, 10);
         }
         else { ObjectDelete(0, label_id); ObjectDelete(0, x_id); }

         // Direction change circle: drawn on the first bar of the new trend segment
         ObjectDelete(0, circ_id);
         if(i > 1 && BuffDirection[i-1] != BuffDirection[i-2])
         {
            color circ_col = direction ? InpUpTrendColor : InpDnTrendColor;
            ObjectCreate(0, circ_id, OBJ_ARROW, 0, time[i], kfTrendLine);
            ObjectSetInteger(0, circ_id, OBJPROP_ARROWCODE, 159);
            ObjectSetInteger(0, circ_id, OBJPROP_COLOR,     circ_col);
            ObjectSetInteger(0, circ_id, OBJPROP_WIDTH,     1);
         }
      }

      if(i == rates_total - 1) UpdateDashboard(buy, sell, d_sum);
   }
   return(rates_total);
}

//+------------------------------------------------------------------+
string FormatVolume(double vol)
{
   vol = MathAbs(vol);
   if(vol >= 1000000) return DoubleToString(vol / 1000000.0, 1) + "M";
   if(vol >= 1000)    return DoubleToString(vol / 1000.0,    1) + "K";
   return DoubleToString(vol, 0);
}

string FormatSignedVolume(double vol)
{
   string sign = (vol >= 0) ? "+" : "-";
   return sign + FormatVolume(vol);
}

//+------------------------------------------------------------------+
color ColorBlend(color col, int step)
{
   uint  c = (uint)col;
   uchar r = (uchar)( c        & 0xFF);
   uchar g = (uchar)((c >>  8) & 0xFF);
   uchar b = (uchar)((c >> 16) & 0xFF);

   double factor = 0.35 + (step * 0.065);
   r = (uchar)MathMin(255, (int)(r * factor));
   g = (uchar)MathMin(255, (int)(g * factor));
   b = (uchar)MathMin(255, (int)(b * factor));

   return (color)((uint)b << 16 | (uint)g << 8 | (uint)r);
}

//+------------------------------------------------------------------+
// Dashboard UI Engine
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
void UpdateDashboard(double buy, double sell, double delta)
{
   int win_w   = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS);
   int win_h   = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS);
   
   int col_w   = 75, bar_h = 14, spacing = 8;
   int table_w = (col_w + spacing) * 3 + spacing;
   int table_h = 245; 

   // Manually calculate the X from the LEFT to bypass the Price Scale bug
   int x_base = win_w - InpDashX - table_w;
   int y_top  = win_h - InpDashY - table_h;

   double max_vol = MathMax(buy, MathMax(sell, MathAbs(delta)));
   if(max_vol == 0) max_vol = 0.1;

   int buy_score   = (int)MathMin(10, (buy           / max_vol) * 10);
   int sell_score  = (int)MathMin(10, (sell          / max_vol) * 10);
   int delta_score = (int)MathMin(10, (MathAbs(delta) / max_vol) * 10);

   color buy_col   = InpUpTrendColor;
   color sell_col  = InpDnTrendColor;
   color delta_bar = (delta > 0) ? InpUpTrendColor : InpDnTrendColor;
   color delta_hdr = C'128,128,128';

   // Layout positions
   int bars_y    = y_top + 10;
   int headers_y = bars_y + 10 * (bar_h + 1) + 10;
   int total_y   = headers_y + 40 + 10;
   int total_h   = 25;

   // --- Precision White Border (OBJ_EDIT) ---
   string frame_id = "KVT_D_Frame";
   ObjectDelete(0, frame_id);
   ObjectCreate(0, frame_id, OBJ_EDIT, 0, 0, 0);
   ObjectSetInteger(0, frame_id, OBJPROP_CORNER,      CORNER_LEFT_UPPER);
   ObjectSetInteger(0, frame_id, OBJPROP_XDISTANCE,   x_base - 5);
   ObjectSetInteger(0, frame_id, OBJPROP_YDISTANCE,   y_top - 5);
   ObjectSetInteger(0, frame_id, OBJPROP_XSIZE,       table_w);
   ObjectSetInteger(0, frame_id, OBJPROP_YSIZE,       (total_y + total_h) - y_top + 10);
   ObjectSetInteger(0, frame_id, OBJPROP_BGCOLOR,     CLR_NONE);
   ObjectSetInteger(0, frame_id, OBJPROP_BORDER_COLOR, clrWhite);
   ObjectSetInteger(0, frame_id, OBJPROP_COLOR,       clrWhite);
   ObjectSetInteger(0, frame_id, OBJPROP_READONLY,    true);
   ObjectSetInteger(0, frame_id, OBJPROP_SELECTABLE,  false);
   ObjectSetInteger(0, frame_id, OBJPROP_ZORDER,      0);

   ObjectDelete(0, "KVT_D_T");
   int total_w = table_w - spacing;

   // Floating Total Volume text
   PlaceEdit("KVT_D_TT", "TOTAL VOLUME: " + FormatVolume(buy + sell), 9,
             x_base + 5, total_y, total_w, total_h, ALIGN_LEFT, CLR_NONE);
   ObjectSetInteger(0, "KVT_D_TT", OBJPROP_BORDER_COLOR, C'0,0,0');

   DrawCol("BUY",   buy_score,   buy_col,   buy_col,   buy,   x_base + (col_w + spacing) * 0, headers_y, bars_y, col_w, bar_h);
   DrawCol("SELL",  sell_score,  sell_col,  sell_col,  sell,  x_base + (col_w + spacing) * 1, headers_y, bars_y, col_w, bar_h);
   DrawCol("DELTA", delta_score, delta_hdr, delta_bar, delta, x_base + (col_w + spacing) * 2, headers_y, bars_y, col_w, bar_h, true);
   ChartRedraw(0);
}

//+------------------------------------------------------------------+
void DrawCol(string name, int score, color hdr_col, color bar_col, double val,
             int x_dist, int head_y, int bars_y, int w, int h, bool show_sign = false)
{
   // --- Header Box ---
   int head_h = 40;
   string t_id = "KVT_D_H_" + name;
   ObjectDelete(0, t_id);
   ObjectCreate(0, t_id, OBJ_EDIT, 0, 0, 0);
   ObjectSetInteger(0, t_id, OBJPROP_CORNER,      CORNER_LEFT_UPPER);
   ObjectSetInteger(0, t_id, OBJPROP_XDISTANCE,   x_dist);
   ObjectSetInteger(0, t_id, OBJPROP_YDISTANCE,   head_y);
   ObjectSetInteger(0, t_id, OBJPROP_XSIZE,       w);
   ObjectSetInteger(0, t_id, OBJPROP_YSIZE,       head_h);
   ObjectSetInteger(0, t_id, OBJPROP_BGCOLOR,     hdr_col);
   ObjectSetInteger(0, t_id, OBJPROP_BORDER_COLOR, hdr_col);
   ObjectSetInteger(0, t_id, OBJPROP_READONLY,    true);
   ObjectSetInteger(0, t_id, OBJPROP_SELECTABLE,  false);
   ObjectSetInteger(0, t_id, OBJPROP_ZORDER,      1);

   string val_str = show_sign ? FormatSignedVolume(val) : FormatVolume(val);

   PlaceEdit("KVT_D_HN_" + name, name,    9, x_dist, head_y + 3,  w, head_h / 2, ALIGN_CENTER, hdr_col);
   PlaceEdit("KVT_D_HV_" + name, val_str, 9, x_dist, head_y + 20, w, head_h / 2, ALIGN_CENTER, hdr_col);

   // --- Histogram Bars ---
   for(int i = 0; i < 10; i++)
   {
      string b_id = "KVT_D_B_" + name + "_" + IntegerToString(i);
      ObjectDelete(0, b_id);
      ObjectCreate(0, b_id, OBJ_EDIT, 0, 0, 0);
      ObjectSetInteger(0, b_id, OBJPROP_CORNER,      CORNER_LEFT_UPPER);
      ObjectSetInteger(0, b_id, OBJPROP_XDISTANCE,   x_dist);
      // Stack bars downwards from bars_y
      ObjectSetInteger(0, b_id, OBJPROP_YDISTANCE,   bars_y + (9 - i) * (h + 1));
      ObjectSetInteger(0, b_id, OBJPROP_XSIZE,       w);
      ObjectSetInteger(0, b_id, OBJPROP_YSIZE,       h);
      ObjectSetInteger(0, b_id, OBJPROP_READONLY,    true);
      ObjectSetInteger(0, b_id, OBJPROP_SELECTABLE,  false);
      ObjectSetInteger(0, b_id, OBJPROP_ZORDER,      1);

      if(i < score)
      {
         color b_col = ColorBlend(bar_col, i);
         ObjectSetInteger(0, b_id, OBJPROP_BGCOLOR,      b_col);
         ObjectSetInteger(0, b_id, OBJPROP_BORDER_COLOR, b_col);
      }
      else
      {
         ObjectSetInteger(0, b_id, OBJPROP_BGCOLOR,      C'10,10,10');
         ObjectSetInteger(0, b_id, OBJPROP_BORDER_COLOR, C'10,10,10');
      }
   }
}

//+------------------------------------------------------------------+
void PlaceEdit(string id, string text, int font_size, int x, int y, int w, int h, ENUM_ALIGN_MODE align, color bg_col = CLR_NONE)
{
   ObjectDelete(0, id);
   ObjectCreate(0, id, OBJ_EDIT, 0, 0, 0);
   ObjectSetInteger(0, id, OBJPROP_CORNER,        CORNER_LEFT_UPPER);
   ObjectSetInteger(0, id, OBJPROP_XDISTANCE,     x);
   ObjectSetInteger(0, id, OBJPROP_YDISTANCE,     y);
   ObjectSetInteger(0, id, OBJPROP_XSIZE,         w);
   ObjectSetInteger(0, id, OBJPROP_YSIZE,         h);
   ObjectSetString(0,  id, OBJPROP_TEXT,          text);
   ObjectSetInteger(0, id, OBJPROP_COLOR,         clrWhite);
   ObjectSetInteger(0, id, OBJPROP_FONTSIZE,      font_size);
   ObjectSetInteger(0, id, OBJPROP_ALIGN,         align);
   ObjectSetInteger(0, id, OBJPROP_READONLY,      true);
   ObjectSetInteger(0, id, OBJPROP_BGCOLOR,       bg_col);
   ObjectSetInteger(0, id, OBJPROP_BORDER_COLOR,  bg_col);
   ObjectSetInteger(0, id, OBJPROP_SELECTABLE,    false);
   ObjectSetInteger(0, id, OBJPROP_ZORDER,        2);
}

