unit omegaGUI;

interface

{  ******************           OMEGA GUI INTERFASE MODULE           ******************

    Модуль для отображения GUI-интерфейся в модуле OmegaEngine
    Автор: Dj_smart (icq: 9804336)
    Версия: 1.1
    Просьба всех добравшихся до этого модуля не удалять информацию выше :)

  **************************       ИСПОЛЬЗОВАНИЕ МОДУЛЯ      **************************

    Инифиализация: guiInit('путь к папке с гуй-данными');
                   guiInit('data/gui');

    Если вы используете только базовые элементы, то пропустите текст ниже.
    если нуждаетесь в активных элементах, то вам нужно описать такие элементы в своем коде.

    guiProcess;
      необходимо вызывать эту процедуру в одной из процедур обсчета в движке
      (тех, которые вызываются при помощи Timer_Create)
      достаточно одной
    guiDraw;
      необходимо вызывать эту процедуру ПОСЛЕ всех прорисовок активных элементов
    guiFocus;
      необходимо вызывать эту процедуру ДО всех прорисовок активных элементов

    ПРИМЕЧАНИЯ

      1. Курсор не рисуется, рисуйте сами :)
      2. В связи с известным глюком в омеге насчет курсора используются свое определение
        (к guiProcess добавлено guiRefreshMouse)
      3. guiVolume - можете задать громкость клика по элементам, задав это

  ************************** Б А З О В Ы Е   Э Л Е М Е Н Т Ы **************************

  *** ФОРМА ***
    Описание: Рисует форму
    Требования: Рисуется через процедуру guiDrawForm
    Параметры: X,Y (позиция)
               W,H (размер),
               Text (текст заголовка),
               trans (прозрачность)
    Использование: guiDrawForm('Форма1',X,Y,W,H)

  *** РАМКА ***
    Описание: Рисует рамку
    Требования: Рисуется через процедуру guiDrawMemoBorder
    Параметры: X,Y (позиция)
               W,H (размер),
               Text (текст заголовка),
               Transparenty (прозрачность)
    Использование: guiDrawMemoBorder(X,Y,W,H);

  *** Панель с вкладками ***
    Описание: Рисует панель с переключаемыми вкладками снизу
    Требования: Рисуется через процедуру guiDrawTabs
    Параметры: X,Y (позиция)
               W,H (размер),
               Text (текст заголовка),
               Tabs (тексты вкладок, разделенные символом "|", включая "|" в конце)
               SelId - глобальная переменная, хрянящая выбранную вкладку
    Использование: guiDrawTabs(X,Y,W,H,'Tabs1','Tab1|Tab2|Tab3|',b); // b - var b:integer;

  *** НАДПИСЬ ***
    Описание: Рисует надпись
    Требования: Рисуется через процедуру guiDrawText
    Параметры: X,Y (позиция)
               Text (текст надписи),
               doCenter (центрирование надписи),
               doHover (подсвечена ли надпись)
               trans (прозрачность)
    Использование: guiDrawText('Текст1',X,Y)

  *** КНОПКА ***
    Описание: Рисует кнопку, которую можно нажать
    Требования: Рисуется через функцию guiDrawButton
    Параметры: X,Y (позиция)
               W (ширина)
               Text (текст надписи)
               doCenter - центрирование надписи
    Использование: if guiDrawButton('Text',X,Y,W)=button_button_click then ... на нее нажали
      button_none - ничего не сделано
      button_hover - над ней курсор
      button_click - на нее нажали

  *** Прогресс-бар ***
    Описание: Рисует полоску прогресса
    Требования: Рисуется через процедуру guiDrawProgressBar(X,Y,W,Coef:single);
    Параметры: X,Y (позиция)
               W (ширина)
               Coef (коэффициент заполненности - 0.0 - пуст, 1.0 - полон)
    Использование: guiDrawProgressBar(X,Y,W,0.5)

  *** ЧЕК БОКС ***
    Описание: Рисует чек-бокс который можно отметить или снять
    Требования: Рисуется через процедуру guiDrawCheckBox
    Параметры: X,Y (позиция),
               doVal - глобальная переменная, хрянящая состояние
    Использование: guiDrawCheckBox('Text',X,Y,b); // b - var b:boolean;

  *** РАДИО-КНОПКИ ***
    Описание: Рисует список радио-кнопок, из которых можно выбрать только одну
    Требования: Рисуется через процедуру guiDrawRadioButtons
    Параметры: X,Y (позиция),
               Text (текст надписисей через символ "|". в конце обязательно |),
               doVal - глобальная переменная, хрянящая активную кнопку
    Использование: guiDrawCheckBox('Value1|Value2|Value3|',X,Y,b); // b - var b:integer;

  ************************** А К Т И В Н Ы Е   Э Л Е М Е Н Т Ы **************************

  *** ПОЛЕ ВВОДА ***
    Описание: Рисует поле ввода
    Требования: Требует объявления переменной типа TMyEdit с заданием параметров.
    Параметры: X,Y (позиция),
               W (ширина),
               Text (введенный текст)
               TextType (тип текста)
                 tt_normal - обычный текст
                 tt_numbers - только цифры
               Hint (текст описания)
    Использование: guiDrawEdit(@Имя_переменной); - нарисовать
                   guiInitEdit(@Имя_переменной,X,Y,Width:integer;[Text,Hint:String;TextType:byte]); - проинициализировать
    Events: OnChange - при изменении данных. // Edit1.OnChange:=@OnChangeEnent;

   *** Выпадающий список ***
    Описание: Рисует выпадающий список
    Требования: Требует объявления переменной типа TMyComboBox с заданием параметров.
    Параметры: X,Y (позиция),
               W (ширина),
               ElementsTexture - текстура (PTexture), которую можно привязать к элементам списка.
                 Пока реализовано лишь понумерованая привязка, тип эл №1 - спрайт №1.
                 Требует задания Tex_SetFramesSize, желательно до 16x16, спрайт
                 все равно отображается при размере 16х16.
               Values массив значений, задавать через SetLength
               SelId - выбранный элемент. доступ к значению через Values[SelId].
                 первый эл. под номером 0
    Использование: guiDrawComboBox(@Имя_переменной); - нарисовать
                   guiInitComboBox(@Имя_переменной,X,Y,Width:integer); - проинициализировать
    Events: OnChange - выборе другого элемента

    *** Всплывающее меню ***
    Описание: Рисует вспывающее меню
    Требования: Требует объявления переменной типа TMyPopup с инициализацией элементов.
    Использование: guiShowPopup(X,Y,@Имя_переменной) - вызвать выпадание списка
                   gupInitPopup(@Имя_переменной,'Вырезать|Копировать|Вставить|Удалить',@Процедура_обработки); - проинициализировать,
                     где Процедура_обработки - процедура, которая вызывается при выборе пункта меню
                     procedure Процедура_обработки(selected:integer);
                     begin
                       case selected of
                         0: ; // Вырезать
                         1: ; // Копировать
                         2: ; // Вставить
                         3: ; // Удалить
                       end;
                     end;
                   Можно запретить нажимать элементы, указывая на переменную
                     Имя_переменной.Items[3].Active:=false; // запретить эл. "Удалить"
    Events: OnSelect(selected:integer) - при выборе элемента

    *** Track-bar ***
    Описание: Рисует ползунок
    Требования: Требует объявления переменной типа TMyTrakBar с заданием параметров.
    Параметры: X,Y (позиция),
               W (ширина),
               Max (максимальное значение, Min - 0)
               Value - позиция ползунка, нужно привязать переменную типа integer:
                 trVolume.Value:=@GameVolume; // var GameVolume:integer;
    Использование: guiDrawTrackBar(@Имя_переменной);
    Events: OnChange - при перемещении ползунка
  }

uses Windows, OMEGA{, };

const
  formYOffset = 2; formXOffset=2;
  textColor = $00FFFFFF; textHoverColor = $00C5C583; textScale = 0.6; textXOffset = 2; textYOffset = 4;

  // ширина и высота символа в Thefont.tga
  symbolWidth = 7; symbolHeight = 10;

  {*** позиция (X,Y) и ширина (Width,Height) разных элементов из Gui.tga
   как правило указано половина ширины/высоты. например при прорисовки
   кнопки длинной 100 и buttonWidth=32 значит, что настоящая длинна ее - 64 px,
   что будет нарисовано 32 пиксела кнопки(половина) затем 1 пиксель(32-й) разтянут на 36 пикселей (100-32*2)
   и затем дорисована вторая половина кнопки ***}
    buttonX = 0; buttonY = 0; buttonWidth = 32; buttonHeight = 24; // кнопка
    cboxX = 32; cboxY = 0; cboxWidth = 16; cboxHeight = 16; // чекбокс
    rdX = 48; rdY = 0; rdWidth = 16; rdHeight = 16; // радио-кнопка
    frmX = 64; frmY = 0; frmWidth = 24; frmHeight = 24; // форма
    tblX = 0; tblY = 89; tblWidth = 16; tblHeight = 16; // таблица
    tblHX = 32; tblHY = 89; tblHWidth = 1; tblHHeight = 14; // разделитель полей в таблице
    editX = 64; editY = 48; editWidth = 3; editHeight = 17; // поле ввода
    editselX = 168; editselY = 34; editselWidth = 2; editselHeight = 13; // отметка в поле ввода
    comboX = 71; comboY = 48; comboWidth = 3; comboSelWidth = 17; comboHeight = 17; // поле выбора
    {***  рамка и элементы после раскрытия поля выбора ***}
      comboMoveX = 144; comboMoveY = 0; comboMoveWidth = 12; comboMoveHeight = 12; comboMovePHeight = 25;
      comboSize = 16;
      comboLineX = 144; comboLineY = 49; comboLineWidth = 12; comboLineHeight = 4;
    {*** ***}
    memoX = 112; memoY = 0; memoWidth = 16; memoHeight = 16; // многострочный вывод
    selX = 109; selY = 48; selWidth = 3; selHeight = 17; // каретка ввода текста
    pbX = 0; pbY = 72; pbWidth = 3; pbHeight = 17; // прогрессбар
    tabX = 72; tabY = 65; tabWidth = 32; tabHeight = 24; // вкладка
    trackX = 168; trackY = 0; trackWidth=15; trackHeight = 17; // трак-бар


    elX = 112; elY = 32; elWidth = 32; elHeight = 16; // элемент любого списка
    layX = 8; layY = 72; layWidth = 16; layHeight = 10; // рискладки и фунц-льные кнопки
  {*** ***}

  // результаты нажатия кнопки
  button_none=0; // ничего не сделано
  button_hover=1; // над ней курсор
  button_click=2; // на нее нажали

  // тип текста
  tt_normal=0;
  tt_numbers=1;

  // тип фокуса
  ft_none=0;
  ft_edit=1;
  ft_combobox=2;
  ft_comboboxmove=3;
  ft_trackbar=4;
  ft_popup=5;
  ft_tablemove=6;

  // alignment

  align_left = 0;
  align_center = 1;
  align_right = 2;

type

  PMyEdit=^TMyEdit;
  TMyEdit=record
    X,Y,W:integer;
    Text,Hint:string;
    TTNumbersValue:PInteger;
    TextType:byte;
    OnChange:procedure;
    Offset,SelectStart,SelectEnd:Integer;
    LeftText,RightText:string;
  end;
  PMyComboBox=^TMyComboBox;
  TMyComboBox=record
    X,Y,W:integer;
    prOffset,Offset:Integer;
    ElementsTexture:PTexture;
    Values:array of String;
    SelId:Integer;
    OnChange:procedure;
  end;
  PMyTable=^TMyTable;
  TTableHeader=record
    Text:string;
    Width:single;
    Align:byte;
  end;
  TMyTable=record
    X,Y,W,H:integer;
    prOffset,Offset:Integer;
    Headers:array of TTableHeader;
    Size:TPoint;
    Values:array of array of String;
    SelId:Integer;
  end;
  PMyTrakBar=^TMyTrakBar;
  TMyTrakBar=record
    X,Y,W,Max:integer;
    Value:PInteger;
    prOffset,LastValue:Integer;
    OnChange:procedure;
  end;
  TMyAction=record
    Text:string;
    Active:Boolean;
  end;
  PMyPopup=^TMyPopup;
  TMyPopup=record
    X,Y,Width:Integer;
    Items:array of TMyAction;
    OnSelect:procedure(selected:integer);
  end;

var
  txtMainTex, txtFont: PTexture;
  Font : PFont2D;
  sndButtonClick : PSound;
  RbState,LbState:Boolean;
  R:oeRect;
  EditActionsPopup:TMyPopup;
  ClickOnEdit:Boolean;
  MoveOffset,EditSelectStart:Integer;
  guiVolume:Integer=100;
  RuLayout:Boolean=True;
  selVal:Integer;
  Focus:record
    FocusType:Byte;
    asEdit:PMyEdit;
    asComboBox:PMyComboBox;
    asTrackBar:PMyTrakBar;
    asPopup:PMyPopup;
    asTable:PMyTable;
  end;

  procedure guiDrawForm(Text:string; X,Y,W,H:single;trans:Byte=255);
  procedure guiDrawText(Text:string; X,Y:single; doCenter:Boolean=false; doHover:Boolean=false;trans:byte=255);
  function guiDrawButton(Text:string; X,Y,W:single; doCenter:Boolean=true):integer;
  procedure guiDrawCheckBox(Text:string; X,Y:single;var doVal:Boolean);
  procedure guiDrawRadioButtons(Text:string; X,Y:single;var doVal:integer);
  procedure guiDrawTabs(X,Y,W,H:Integer;Name,Tabs:string; var SelId:integer);
  procedure guiDrawEdit(ed:PMyEdit);
  procedure guiDrawComboBox(cm:PMyComboBox);
  procedure guiDrawMemoBorder(X,Y,W,H:single;Transparenty:Byte=255);
  procedure guiDrawProgressBar(X,Y,W,Coef:single);
  procedure guiDrawTrackBar(track:PMyTrakBar);
  procedure guiDrawSelection(X,Y,W:single;sel:Boolean);
  procedure guiDrawTable(tb:PMyTable;Transparenty:byte=255);

  procedure guiShowPopup(X,Y:integer;pp:PMyPopup);

  procedure guiInitEdit(ed:PMyEdit;X,Y,Width:integer;Text:String='';Hint:String='';TextType:byte=tt_normal;TTValue:Pinteger=nil);
  procedure guiInitComboBox(cb:PMyComboBox;X,Y,Width:integer);
  procedure guiInitTable(tb:PMyTable;X,Y,W,H:integer);
  procedure guiTableAddHeader(tb:PMyTable;Text:string;Width:single;Align:byte);
  procedure gupInitPopup(pp:PMyPopup;Texts:string;OnSelect:Pointer=nil);
  procedure guiPopupAddAction(pp:PMyPopup;Text:string);

  procedure guiInit(Dir:string);
  procedure guiProcess;
  procedure guiPlayClick;
  procedure guiDraw;
  procedure guiFocus;
  function guiMouseClick:Boolean;
  function guiMouseClickR:Boolean;
  function MouseInBorder(X,Y,W,H:single):Boolean;
  procedure guiRefreshMouse;

  var Mouse_X,Mouse_Y:integer;

implementation

  function GetClipboardText(Wnd: HWND; var Str: string): Boolean;
  var
    hData: HGlobal;
  begin
    Result := True;
    if OpenClipboard(Wnd) then
    begin
      try
        hData := GetClipboardData(CF_TEXT);
        if hData <> 0 then
        begin
          try
            SetString(Str, PChar(GlobalLock(hData)), GlobalSize(hData));
          finally
            GlobalUnlock(hData);
          end;
        end
        else
          Result := False;
        Str := PChar(@Str[1]);
      finally
        CloseClipboard;
      end;
    end
    else
      Result := False;
  end;

  procedure SetClipboardText(Str:string);
  var
    hMem: Cardinal; pMem: PChar;
  begin
     OpenClipboard(0);
     hMem := GlobalAlloc(GMEM_DDESHARE or GMEM_MOVEABLE, Length(Str)+1);
     pMem := GlobalLock(hMem);
     lstrcpy (PChar(pMem), @Str[1]);
     GlobalUnlock(hMem);
     EmptyClipboard;
     SetClipboardData(CF_TEXT, hMem);
     SetClipboardData(CF_LOCALE, hMem);
     CloseClipboard;
     GlobalFree(hMem);
  end;

  procedure ReloadTb(pr:PMyTable);
  var l:Integer;
  begin
    l:=(pr.H div elHeight)-1;
    pr.prOffset:=Round((pr.Offset/(pr.Size.Y-l))*(l*elHeight-comboMovePHeight-comboMoveHeight*2-5));
  end;

  procedure ReloadPr(pr:PMyComboBox);
  begin
    pr.prOffset:=Round((pr.Offset/(Length(pr.Values)-comboSize))*(comboSize*elHeight-comboMovePHeight-comboMoveHeight*2-2));
  end;

  procedure guiPlayClick;
  begin
    Snd_Play(sndButtonClick,0,VOLUME(guiVolume),0,False);
  end;

  procedure guiSelectAll(asEd:PMyEdit);
  begin
    asEd.SelectEnd:=0;
    asEd.SelectStart:=Length(asEd.Text);
  end;

  procedure guiDeleteSelected(asEd:PMyEdit);
  var st,l:Integer;
  begin
    if asEd.SelectEnd>asEd.SelectStart then begin
      st:=asEd.SelectStart;
      l:=asEd.SelectEnd-st;
    end else if asEd.SelectEnd<asEd.SelectStart then begin
      st:=asEd.SelectEnd;
      l:=asEd.SelectStart-st;
    end else Exit;
    asEd.Text:=asEd.LeftText+asEd.RightText;
    asEd.LeftText:=Copy(asEd.Text,1,st);
    asEd.RightText:=Copy(asEd.Text,st+l+1,Length(asEd.Text));
    asEd.Text:=asEd.LeftText+asEd.RightText;
    asEd.SelectStart:=0;
    asEd.SelectEnd:=0;
    Key_BeginReadText(PAnsiChar(asEd.LeftText));
  end;

  procedure guiCopySelected(asEd:PMyEdit);
  var st,l:Integer;
  begin
    if asEd.SelectEnd>asEd.SelectStart then begin
      st:=asEd.SelectStart;
      l:=asEd.SelectEnd-st;
    end else if asEd.SelectEnd<asEd.SelectStart then begin
      st:=asEd.SelectEnd;
      l:=asEd.SelectStart-st;
    end else Exit;
    SetClipboardText(Copy(asEd.Text,st+1,l));
  end;

  procedure guiPaste(asEd:PMyEdit);
  var st,l:Integer;
      s:string;
  begin
    guiDeleteSelected(asEd);
    //asEd.SelectStart:=Length(asEd.LeftText);
    GetClipboardText(HInstance,s);
    asEd.LeftText:=asEd.LeftText+s;
    //asEd.SelectEnd:=Length(asEd.LeftText);
    asEd.Text:=asEd.LeftText+asEd.RightText;
    Key_BeginReadText(PAnsiChar(asEd.LeftText));
    asEd.SelectStart:=0;
    asEd.SelectEnd:=0;
  end;

  procedure guiRefreshMouse;
  var p:TPoint;
  begin
    getCursorPos(p);
    Mouse_X:=p.X;
    Mouse_Y:=p.Y;
  end;

  function MouseInBorder(X,Y,W,H:single):Boolean;
  begin
    result:=(Mouse_X>=X) and (Mouse_Y>=Y) and (Mouse_X<=X+W) and (Mouse_Y<=Y+H);
  end;

  procedure guiPopupAddAction(pp:PMyPopup;Text:string);
  var id:Integer;
  begin
    id:=Length(pp.Items);
    SetLength(pp.Items,id+1);
    pp.Items[id].Text:=Text;
    pp.Items[id].Active:=True;
   // pp.Items[id].Action:=Action;
    if Length(Text)>pp.Width then pp.Width:=Length(Text);
  end;

  procedure guiShowPopup(X,Y:integer;pp:PMyPopup);
  begin
    Focus.FocusType:=ft_popup;
    Focus.asPopup:=pp;
    pp.X:=X;
    pp.Y:=Y;
  end;

  procedure gupInitPopup(pp:PMyPopup;Texts:string;OnSelect:Pointer=nil);

  begin
    while Pos('|',Texts)<>0 do begin
      guiPopupAddAction(pp,Copy(Texts,1,Pos('|',Texts)-1));
      Delete(Texts,1,Pos('|',Texts));
    end;
    guiPopupAddAction(pp,Texts);
    pp.OnSelect:=OnSelect;
  end;

  procedure guiInitTable(tb:PMyTable;X,Y,W,H:integer);
  begin
    tb.X:=X;
    tb.Y:=Y;
    tb.W:=W;
    tb.H:=(H div elHeight)*elHeight;
    tb.prOffset:=0;
    tb.Offset:=0;
    tb.Size.X:=0;
    tb.Size.Y:=0;
    tb.SelId:=-1;
  end;

  procedure guiTableAddHeader(tb:PMyTable;Text:string;Width:single;Align:byte);
  begin
    SetLength(tb.Headers,tb.Size.X+1);
    tb.Headers[tb.Size.X].Text:=Text;
    tb.Headers[tb.Size.X].Width:=Width;
    tb.Headers[tb.Size.X].Align:=Align;
    Inc(tb.Size.X);
  end;

  procedure guiInitComboBox(cb:PMyComboBox;X,Y,Width:integer);
  begin
    cb.X:=X;
    cb.Y:=Y;
    cb.W:=Width;
  end;

  procedure guiInitEdit(ed:PMyEdit;X,Y,Width:integer;Text:String='';Hint:String='';TextType:byte=tt_normal;TTValue:Pinteger=nil);
  begin
    ed.X:=X;
    ed.Y:=Y;
    ed.W:=Width;
    if Text<>'' then ed.Text:=Text;
    if Hint<>'' then ed.Hint:=Hint;
    ed.TextType:=TextType;
    if Assigned(TTValue) then begin
      ed.TTNumbersValue:=TTValue;
      ed.Text:=U_IntToStr(TTValue^);
    end;
  end;

  procedure guiDrawTable(tb:PMyTable;Transparenty:byte=255);
  var X,Y,W,H,n,m,j,offs,l,k,dW,i:Integer;
  begin
    l:=(tb.H div elHeight)-1;
    X:=round(tb.X); Y:=Round(tb.Y);
    W:=round(tb.W-tblWidth*2); H:=Round(tb.H-tblHeight*2);
    dW:=tb.W;
    r.X:=tblX; r.y:=tblY; r.Width:=tblWidth; r.Height:=tblHeight;
    CSprite_Draw(txtMainTex,X,Y,tblWidth,tblHeight,@r,Transparenty);
    r.X:=tblX+tblWidth;
    CSprite_Draw(txtMainTex,X+W+tblWidth,Y,tblWidth,tblHeight,@r,Transparenty);
    r.y:=tblY+tblHeight;
    CSprite_Draw(txtMainTex,X+W+tblWidth,Y+H+tblHeight,tblWidth,tblHeight,@r,Transparenty);
    r.X:=tblX; r.y:=tblY+tblHeight;
    CSprite_Draw(txtMainTex,X,Y+H+tblHeight,tblWidth,tblHeight,@r,Transparenty);
    r.X:=tblX+tblWidth; r.y:=tblY+tblHeight; r.Width:=1;
    CSprite_Draw(txtMainTex,X+tblWidth,Y+H+tblHeight,W,tblHeight,@r,Transparenty);
    r.y:=tblY;
    CSprite_Draw(txtMainTex,X+tblWidth,Y,W,tblHeight,@r,Transparenty);
    r.X:=tblX; r.y:=tblY+tblHeight; r.Width:=tblWidth; r.Height:=1;
    CSprite_Draw(txtMainTex,X,Y+tblHeight,tblWidth,H,@r,Transparenty);
    r.X:=tblX+tblWidth;
    CSprite_Draw(txtMainTex,X+W+tblWidth,Y+tblHeight,tblWidth,H,@r,Transparenty);
    r.Width:=1;
    CSprite_Draw(txtMainTex,X+tblWidth,Y+tblHeight,W,H,@r,Transparenty);
    if l<tb.Size.Y then begin
      Dec(dW,comboMoveWidth);
      i:=0;
      if Focus.FocusType=ft_none then
      if MouseInBorder(X+dW-2,Y+elHeight+1,comboMoveWidth,comboMoveHeight) then begin
        if Mouse_Down(1) then begin
          i:=1;
        end else
        if LbState then begin
          guiPlayClick;
          if tb.Offset>0 then Dec(tb.Offset);
          ReloadTb(tb);
        end;
      end;
      r.X:=comboMoveX+comboMoveWidth*i; r.y:=comboMoveY;
      r.Width:=comboMoveWidth; r.Height:=comboMoveHeight;
      CSprite_Draw(txtMainTex,X+dW-2,Y+elHeight+1,comboMoveWidth,comboMoveHeight,@r,Transparenty);
      i:=0;
      if Focus.FocusType=ft_none then
      if MouseInBorder(X+dW-2,Y+tb.H-comboMoveHeight-2,comboMoveWidth,comboMoveHeight) then begin
        if Mouse_Down(1) then begin
          i:=1;
        end else
        if LbState then begin
          guiPlayClick;
          if tb.Offset<tb.Size.Y-l then Inc(tb.Offset);
          ReloadTb(tb);
        end;
      end;
      r.X:=comboMoveX+comboMoveWidth*i; r.y:=comboMoveHeight+comboMoveY+comboMovePHeight;
      r.Width:=comboMoveWidth; r.Height:=comboMoveHeight;
      CSprite_Draw(txtMainTex,X+dW-2,Y+tb.H-comboMoveHeight-2,comboMoveWidth,comboMoveHeight,@r,Transparenty);
      if Focus.FocusType=ft_tablemove then begin
        i:=1;
      end else i:=0;
      r.X:=comboMoveX+comboMoveWidth*i; r.y:=comboMoveHeight+comboMoveY;
      r.Width:=comboMoveWidth; r.Height:=comboMovePHeight;
      CSprite_Draw(txtMainTex,X+dW-2,Y+elHeight+comboMoveHeight+2+tb.prOffset,comboMoveWidth,comboMovePHeight,@r,Transparenty);
      if MouseInBorder(X+dW-2,Y+elHeight+comboMoveHeight+2+tb.prOffset,comboMoveWidth,comboMovePHeight) then begin
        if Mouse_Down(1) and (LbState=false) then begin
          guiPlayClick;
          Focus.FocusType:=ft_tablemove;
          Focus.asTable:=tb;
          MoveOffset:=Mouse_Y-({Y+elHeight+comboMoveHeight+2+}tb.prOffset);
        end;
      end;
    end;
    offs:=Round(dW*tb.Headers[0].Width);
    r.X:=tblHX; r.y:=tblHY; r.Width:=tblHWidth; r.Height:=tblHHeight;
    for n:=1 to tb.Size.X-1 do begin
      CSprite_Draw(txtMainTex,X+offs,Y,tblHWidth,tblHHeight,@r,Transparenty);
      Inc(offs,Round(dW*tb.Headers[n].Width));
    end;
    offs:=0;
    for n:=0 to tb.Size.X-1 do begin
      case tb.Headers[n].Align of
        align_left:j:=2;
        align_center:j:=Round(dW*tb.Headers[n].Width/2-(Length(tb.Headers[n].Text)+1)*symbolWidth/2);
        align_right:j:=Round(dW*tb.Headers[n].Width-(Length(tb.Headers[n].Text)+1)*symbolWidth);
      end;
      guiDrawText(tb.Headers[n].Text,X+j+offs,Y);
      Inc(offs,Round(dW*tb.Headers[n].Width));
    end;
    if l>tb.Size.Y then l:=tb.Size.Y;
    for n:=0 to l-1 do begin
      if n+tb.Offset=tb.SelId then begin
        guiDrawSelection(X,Y+(n+1)*elHeight,dW-2,true);
      end else
      if (Focus.FocusType=ft_none) and MouseInBorder(X,Y+(n+1)*elHeight,dW-4,elHeight-1) then begin
        guiDrawSelection(X,Y+(n+1)*elHeight,dW-2,false);
        if guiMouseClick then begin
          guiPlayClick;
          tb.SelId:=n+tb.Offset;
        end;
      end;
      offs:=2;
      for m:=0 to tb.Size.X-1 do begin
        case tb.Headers[m].Align of
          align_left:j:=0;
          align_center:j:=Round(dW*tb.Headers[m].Width/2-(Length(tb.Values[n+tb.Offset,m])+1)*symbolWidth/2);
          align_right:j:=Round(dW*tb.Headers[m].Width-(Length(tb.Values[n+tb.Offset,m])+1)*symbolWidth);
        end;
        guiDrawText(tb.Values[n+tb.Offset,m],X+j+offs,Y+(n+1)*elHeight);
        Inc(offs,Round(dW*tb.Headers[m].Width));
      end;
    end;
  end;

  procedure guiDrawTrackBar(track:PMyTrakBar);
  var i,d:Integer;
  begin
    i:=0;
    d:=Round(track.X+(track.W-trackWidth+pbWidth*2)*(track.Value^/track.Max));
    if MouseInBorder(d,track.Y,trackWidth,trackHeight) and (Focus.FocusType=ft_none) then begin
      i:=1;
      if Mouse_Click(1) then begin
        guiPlayClick;
        Focus.FocusType:=ft_trackbar;
        Focus.asTrackBar:=track;
        track.LastValue:=track.Value^;
        track.prOffset:=Mouse_X-d;
      end;
    end;
    guiDrawProgressBar(track.X,track.Y,track.W,track.Value^/track.Max);
    r.X:=trackX; r.y:=trackY+i*trackHeight;
    r.Width:=trackWidth; r.Height:=trackHeight;
    CSprite_Draw(txtMainTex,d,track.Y,trackWidth,trackHeight,@r);
  end;


  function guiDrawTabButton(Text:string; X,Y,W:single; Selected:boolean):boolean;
  var i:Integer;

  begin
    if Selected then i:=2 else i:=0;
    Result:=False;
    if MouseInBorder(X,Y,W+tabWidth,tabHeight) and (Focus.FocusType=ft_none) then begin
      if i=0 then i:=1;                             
      if guiMouseClick then begin
        guiPlayClick;
        Focus.FocusType:=ft_none;
        Result:=True;
      end;
    end;
    r.X:=tabX+i*tabWidth;
    r.y:=tabY;
    r.Width:=tabWidth/2;r.Height:=tabHeight;
    CSprite_Draw(txtMainTex,X,Y,tabWidth/2,tabHeight,@r);
    r.X:=r.X+tabWidth/2;
    CSprite_Draw(txtMainTex,X+W+tabWidth/2,Y,tabWidth/2,tabHeight,@r);
    r.Width:=1;
    CSprite_Draw(txtMainTex,X+tabWidth/2,Y,W,tabHeight,@r);

    guiDrawText(Text,X+tabWidth/2+W/2,Y+textYOffset,True);
  end;

  procedure guiDrawTabs(X,Y,W,H:Integer;Name,Tabs:string; var SelId:integer);
  var str,ActiveStr:string;
      iOff,i,k:Integer;
  begin

    iOff:=0;k:=0;
    while Pos('|',Tabs)<>0 do begin
      str:=Copy(Tabs,1,Pos('|',Tabs)-1);
      if guiDrawTabButton(str,X+iOff+2,Y+H,Length(str)*symbolWidth,SelId=k) then
        SelId:=k;
      if SelId=k then begin
        ActiveStr:=str;
      end;
      iOff:=iOff+Length(str)*symbolWidth+tabWidth+1;
      Inc(k);
      Delete(Tabs,1,Pos('|',Tabs));
    end;
    guiDrawForm(Name+' - '+ActiveStr,X,Y,W,H);
  end;

  procedure guiProcess;
  var asEd:PMyEdit;
      n,i,edlen:Integer;
  begin
    guiRefreshMouse;
    case Focus.FocusType of
      ft_edit:begin
        Inc(selVal);
        asEd:=Focus.asEdit;
        asEd.LeftText:=Key_EndReadText;
        asEd.Text:=asEd.LeftText+asEd.RightText;
        if asEd.TextType=tt_numbers then begin
          n:=1;
          while n<=Length(asEd.Text) do begin
            if not (asEd.Text[n] in ['0'..'9']) then begin
              Delete(asEd.Text,n,1);
              Dec(n);
            end;
            Inc(n);
          end;
          if asEd.Text='' then asEd.Text:='0';
          if Assigned(asEd.TTNumbersValue) then
            asEd.TTNumbersValue^:=U_StrToInt(PAnsiChar(asEd.Text));
        end;
        if Key_Press(K_LEFT) and (Length(asEd.LeftText)>0) then begin
          asEd.RightText:=asEd.LeftText[Length(asEd.LeftText)]+asEd.RightText;
          Delete(asEd.LeftText,Length(asEd.LeftText),1);
          Key_BeginReadText(PAnsiChar(asEd.LeftText));
        end;
        if Key_Press(K_RIGHT) and (Length(asEd.RightText)>0) then begin
          asEd.LeftText:=asEd.LeftText+asEd.RightText[1];
          Delete(asEd.RightText,1,1);
          Key_BeginReadText(PAnsiChar(asEd.LeftText));
        end;
        if Key_Press(K_DELETE) and ((Length(asEd.RightText)>0) or ((asEd.SelectStart<>asEd.SelectEnd) and (Length(asEd.Text)>0))) then begin
          if asEd.SelectStart<>asEd.SelectEnd then
            guiDeleteSelected(asEd) else Delete(asEd.RightText,1,1);
        end;
        if Key_Down(K_CTRL) and Key_Press(K_V) then begin
          guiPaste(asEd);
        end;
        if Key_Down(K_CTRL) and Key_Press(K_C) and (asEd.SelectStart<>asEd.SelectEnd) then begin
          guiCopySelected(asEd);
        end;
        if Key_Down(K_CTRL) and Key_Press(K_X) and (asEd.SelectStart<>asEd.SelectEnd) then begin
          guiCopySelected(asEd);
          guiDeleteSelected(asEd);
        end;
        if Key_Down(K_CTRL) and Key_Press(K_A) then begin
          guiSelectAll(asEd);
        end;
        edlen:=asEd.W div symbolWidth;
        i:=round(Mouse_X-asEd.X-editWidth+symbolWidth/2) div symbolWidth+asEd.Offset;
        if i>Length(asEd.Text) then i:=Length(asEd.Text);
        if i<0 then i:=0;
        if (asEd.SelectStart<>asEd.SelectEnd) and (Mouse_Down(1)) then begin
          if (i<asEd.Offset) and (asEd.Offset>0) then Dec(asEd.Offset);
          if (i>asEd.Offset+edlen-1) and (asEd.Offset<Length(asEd.Text)-edlen+1) then Inc(asEd.Offset);
        end;
      end;
    end;
  end;

  procedure guiDrawSelection(X,Y,W:single;sel:Boolean);
  begin
    if sel then r.Y:=elY+elHeight else r.Y:=elY;
    r.X:=elX; r.Width:=elWidth/2; r.Height:=elHeight;
    CSprite_Draw(txtMainTex,X,Y,elWidth/2,elHeight,@r);
    r.X:=elX+elWidth/2;
    CSprite_Draw(txtMainTex,X+W-elWidth/2,Y,elWidth/2,elHeight,@r);
    r.Width:=0;
    CSprite_Draw(txtMainTex,X+elWidth/2,Y,W-elWidth,elHeight,@r);
  end;

  procedure guiFocus;
  var asCb:PMyComboBox;
      asTr:PMyTrakBar;
      asPP:PMyPopup;
      n,i,j:Integer;
  begin
    case Focus.FocusType of
      ft_popup:begin
        asPP:=Focus.asPopup;
        guiDrawMemoBorder(asPP.X,asPP.Y,(asPP.Width+2)*symbolWidth-memoWidth*2+4,Length(asPP.Items)*elHeight-memoHeight*2+4);
        for i:=0 to Length(asPP.Items)-1 do begin
          if asPP.Items[i].Active and MouseInBorder(asPP.X+2,asPP.Y+i*elHeight+2,(asPP.Width+2)*symbolWidth,elHeight-1) and guiMouseClick then begin
            guiPlayClick;
            Focus.FocusType:=ft_none;
            //asPP.Selected:=i;
            if Assigned(asPP.OnSelect) then
              asPP.OnSelect(i);
            LBState:=false;
            Break;
          end;
        end;
      end;
      ft_trackbar:begin
        asTr:=Focus.asTrackBar;
        i:=Round(asTr.Max*(Mouse_X-asTr.X-asTr.prOffset)/(asTr.W-trackWidth+pbWidth*2));
        if i<0 then i:=0; if i>asTr.Max then i:=asTr.Max;
        asTr.Value^:=i;
        if (asTr.LastValue<>asTr.Value^) and Assigned(asTr.OnChange) then begin
          asTr.OnChange;
        end;
        asTr.LastValue:=asTr.Value^
      end;
      ft_combobox:begin
        asCb:=Focus.asComboBox;
        i:=Length(asCb.Values);
        if i>comboSize then i:=comboSize;
        for n:=asCb.Offset to asCb.Offset+i-1 do begin
          j:=n-asCb.Offset;
          if MouseInBorder(asCb.X+2,asCb.Y+comboHeight+1+j*elHeight,asCb.W+comboSelWidth-comboMoveWidth-2,elHeight-1) then begin
            if guiMouseClick then begin
              guiPlayClick;
              asCb.SelId:=n;
              Focus.FocusType:=ft_none;
            end;
          end;
        end;
      end;
    end;
  end;

  procedure guiDraw;
  var asCb:PMyComboBox;
      asEd:PMyEdit;
      asTr:PMyTrakBar;
      asPP:PMyPopup;
      asTb:PMyTable;
      n,i,j,st,l,eOffset:Integer;
      b:Boolean;
      s:string;
  begin
    case Focus.FocusType of
      ft_popup:begin
        asPP:=Focus.asPopup;
        guiDrawMemoBorder(asPP.X,asPP.Y,(asPP.Width+2)*symbolWidth-memoWidth*2+4,Length(asPP.Items)*elHeight-memoHeight*2+4);
        for i:=0 to Length(asPP.Items)-1 do begin
          if asPP.Items[i].Active then begin
            if MouseInBorder(asPP.X+2,asPP.Y+i*elHeight+2,(asPP.Width+2)*symbolWidth,elHeight-1) then begin
              guiDrawSelection(asPP.X+2,asPP.Y+i*elHeight+2,(asPP.Width+2)*symbolWidth,false);
            end;
            guiDrawText(asPP.Items[i].Text,asPP.X+4,asPP.Y+i*elHeight+2);
          end else
            guiDrawText(asPP.Items[i].Text,asPP.X+4,asPP.Y+i*elHeight+2,False,False,96);
        end;
      end;
      ft_trackbar:begin
        asTr:=Focus.asTrackBar;
        i:=Round(asTr.X+(asTr.W-trackWidth+pbWidth*2)*(asTr.Value^/asTr.Max));
        guiDrawText(U_IntToStr(asTr.Value^),i+trackWidth,asTr.Y);
      end;
      ft_edit:begin
        b:=True;
        asEd:=Focus.asEdit;
          r.X:=layX; r.Y:=layY;
          if RuLayout then r.X:=r.X+layWidth;
          r.Width:=layWidth; r.Height:=layHeight;
          CSprite_Draw(txtMainTex,asEd.X+asEd.W-layWidth+editWidth,asEd.Y-layHeight,layWidth,layHeight,@r);
          if MouseInBorder(asEd.X+asEd.W-layWidth+editWidth,asEd.Y-layHeight,layWidth,layHeight) then begin
            guiDrawText('Язык',asEd.X+asEd.W+editWidth+2,asEd.Y);
            r.X:=layX+layWidth*3;
            CSprite_Draw(txtMainTex,asEd.X+asEd.W-layWidth+editWidth,asEd.Y-layHeight,layWidth,layHeight,@r);
            if guiMouseClick then begin
              guiPlayClick;
              RuLayout:=not RuLayout;
              if RuLayout then Key_LoadLayout(K_LAYOUT_RUS) else
                Key_LoadLayout(K_LAYOUT_ENG);
              LbState:=False;
            end;
          end;
          r.X:=layX+layWidth*2;
          CSprite_Draw(txtMainTex,asEd.X+asEd.W-layWidth*2+editWidth-2,asEd.Y-layHeight,layWidth,layHeight,@r);
          if MouseInBorder(asEd.X+asEd.W-layWidth*2+editWidth-2,asEd.Y-layHeight,layWidth,layHeight) then begin
            guiDrawText('Действия',asEd.X+asEd.W+editWidth+2,asEd.Y);
            r.X:=layX+layWidth*3;
            CSprite_Draw(txtMainTex,asEd.X+asEd.W-layWidth*2+editWidth-2,asEd.Y-layHeight,layWidth,layHeight,@r);
            if guiMouseClick then begin
              guiPlayClick;
              b:=asEd.SelectStart-asEd.SelectEnd<>0;
              EditActionsPopup.Items[0].Active:=b;
              EditActionsPopup.Items[1].Active:=b;
              EditActionsPopup.Items[3].Active:=b;
              EditActionsPopup.Items[4].Active:=asEd.Text<>'';
              guiShowPopup(asEd.X+asEd.W-layWidth*2+editWidth-2,asEd.Y-layHeight,@EditActionsPopup);
              LbState:=False;
            end;
          end;
      end;
      ft_tablemove:begin
        asTb:=Focus.asTable;
        asTb.prOffset:=Mouse_Y-MoveOffset;
        if asTb.prOffset<0 then asTb.prOffset:=0;
        l:=(asTb.H div elHeight)-1;
        if asTb.prOffset>l*elHeight-2*comboMoveHeight-comboMovePHeight-5 then asTb.prOffset:=l*elHeight-2*comboMoveHeight-comboMovePHeight-5;
        asTb.Offset:=Round((asTb.prOffset/(l*elHeight-comboMovePHeight-comboMoveHeight*2-5)*(asTb.Size.Y-l)));
        if asTb.Offset>asTb.Size.Y-l then asTb.Offset:=asTb.Size.Y-l;
        
        if not Mouse_Down(1) then begin
          guiPlayClick;
          Focus.FocusType:=ft_none;
          LbState:=False;
        end;
      end;
      ft_combobox,ft_comboboxmove:begin
        j:=0; eOffset:=0;
        asCb:=Focus.asComboBox;
        if asCb.ElementsTexture<>nil then eOffset:=elHeight;
        i:=Length(asCb.Values);
        if i>comboSize then begin
          i:=comboSize;
          j:=comboMoveWidth;
        end;
        guiDrawMemoBorder(asCb.X,asCb.Y+comboHeight-1,asCb.W-memoWidth-1,i*elHeight-memoHeight*2+4);
        for n:=asCb.Offset to asCb.Offset+i-1 do begin
          i:=n-asCb.Offset;
          if MouseInBorder(asCb.X+2,asCb.Y+comboHeight+1+i*elHeight,asCb.W+comboSelWidth-6-j,elHeight-1) and (Focus.FocusType=ft_combobox) then begin
            guiDrawSelection(asCb.X+2,asCb.Y+comboHeight+1+i*elHeight,asCb.W+comboSelWidth-6-j,false);
          end else if asCb.SelId=n then begin
            guiDrawSelection(asCb.X+2,asCb.Y+comboHeight+1+i*elHeight,asCb.W+comboSelWidth-6-j,true);
          end;
          s:=asCb.Values[n];
          if Length(s)>asCb.W div symbolWidth then s:=Copy(s,1,asCb.W div symbolWidth);
          if eOffset<>0 then begin
            ASprite_Draw(asCb.ElementsTexture,asCb.X+2,asCb.Y+comboHeight+i*elHeight,
              elHeight,elHeight,n+1);
          end;
          guiDrawText(s,asCb.X+2+eOffset,asCb.Y+comboHeight+i*elHeight);
        end;
        if j<>0 then begin
          r.X:=comboLineX; r.Y:=comboLineY; r.Width:=comboLineWidth; r.Height:=comboLineHeight;
          CSprite_Draw(txtMainTex,
            asCb.X+asCb.W+2,
            asCb.Y+comboHeight+1+comboMoveHeight,
            comboMoveWidth,comboSize*elHeight-comboMoveHeight,@r);
          r.X:=comboMoveX; r.Y:=comboMoveY; r.Width:=comboMoveWidth; r.Height:=comboMoveHeight;
          if MouseInBorder(asCb.X+asCb.W+2,
            asCb.Y+comboHeight+1,
            comboMoveWidth,comboMoveHeight) and (Focus.FocusType=ft_combobox) then begin
            if guiMouseClick then begin
              guiPlayClick;
              if asCb.Offset>0 then Dec(asCb.Offset);
              ReloadPr(asCb);
            end;
            if Mouse_Down(1) then r.X:=r.X+comboMoveWidth;
          end;
          CSprite_Draw(txtMainTex,
            asCb.X+asCb.W+2,
            asCb.Y+comboHeight+1,
            comboMoveWidth,comboMoveHeight,@r);
          r.X:=comboMoveX; r.Y:=comboMoveY+comboMoveHeight+comboMovePHeight; r.Width:=comboMoveWidth; r.Height:=comboMoveHeight;
          if MouseInBorder(asCb.X+asCb.W+2,
            asCb.Y+(comboSize-1)*elHeight+comboHeight+5,
            comboMoveWidth,comboMoveHeight) and (Focus.FocusType=ft_combobox) then begin
            if guiMouseClick then begin
              guiPlayClick;
              if asCb.Offset<Length(asCb.Values)-comboSize then inc(asCb.Offset);
              ReloadPr(asCb);
            end;
            if Mouse_Down(1) then r.X:=r.X+comboMoveWidth;
          end;
          CSprite_Draw(txtMainTex,
            asCb.X+asCb.W+2,
            asCb.Y+comboHeight+(comboSize-1)*elHeight+5,
            comboMoveWidth,comboMoveHeight,@r);
          r.X:=comboMoveX; r.Y:=comboMoveY+comboMoveHeight; r.Width:=comboMoveWidth; r.Height:=comboMovePHeight;

          if Focus.FocusType=ft_combobox then begin
            if MouseInBorder(asCb.X+asCb.W+2,
              asCb.Y+asCb.prOffset+comboHeight+comboMoveHeight+2,
              comboMoveWidth,comboMovePHeight) then begin
              if Mouse_Down(1) then begin
                guiPlayClick;
                Focus.FocusType:=ft_comboboxmove;
                MoveOffset:=Mouse_Y-asCb.prOffset;
              end;
            end;
          end else begin
            r.X:=r.X+comboMoveWidth;
            asCb.prOffset:=Mouse_Y-MoveOffset;
            if asCb.prOffset<0 then asCb.prOffset:=0;
            if asCb.prOffset>comboSize*elHeight-2*comboMoveHeight-comboMovePHeight-2 then asCb.prOffset:=comboSize*elHeight-2*comboMoveHeight-comboMovePHeight-2;
            asCb.Offset:=Round((asCb.prOffset/(comboSize*elHeight-comboMovePHeight-comboMoveHeight*2-2)*(length(asCb.Values)-comboSize)));
            if asCb.Offset>Length(asCb.Values)-comboSize then asCb.Offset:=Length(asCb.Values)-comboSize;
            if not Mouse_Down(1) then begin
              guiPlayClick;
              Focus.FocusType:=ft_combobox;
              LbState:=False;
            end;
          end;
          CSprite_Draw(txtMainTex,
            asCb.X+asCb.W+2,
            asCb.Y+asCb.prOffset+comboHeight+comboMoveHeight+2,
            comboMoveWidth,comboMovePHeight,@r);
        end;
      end;
    end;
    if guiMouseClick or guiMouseClickR then begin
      if Focus.FocusType<>ft_none then begin
        guiPlayClick;
        Focus.FocusType:=ft_none;
      end;
    end;
    LbState:=Mouse_Down(1);
    RbState:=Mouse_Down(0);
  end;

  function guiMouseClick:Boolean;
  begin
    Result:=(Mouse_Down(1)=False) and (LbState);
    if Result then LbState:=False;
  end;

  function guiMouseClickR:Boolean;
  begin
    Result:=(Mouse_Down(0)=False) and (RbState);
    if Result then RbState:=False;
  end;



  procedure OnEditPopupAction(selected:Integer);
  begin
    case selected of
      0:begin
        guiCopySelected(Focus.asEdit);
        guiDeleteSelected(Focus.asEdit);
      end;
      1:begin
        guiCopySelected(Focus.asEdit);
      end;
      2:begin
        guiPaste(Focus.asEdit);
      end;
      3:begin
        guiDeleteSelected(Focus.asEdit);
      end;
      4:begin
        guiSelectAll(Focus.asEdit);
        guiDeleteSelected(Focus.asEdit);
      end;
    end;
    Focus.FocusType:=ft_edit;
  end;

  procedure guiInit(Dir:string);
  begin
    Snd_Init;
    txtMainTex:= Tex_LoadFromFile(PAnsiChar(Dir+'/Gui.tga'),0,0);
    txtFont:= Tex_LoadFromFile(PAnsiChar(Dir+'/Thefont.tga'),0,0);
    Tex_SetFramesSize(txtFont,symbolWidth,symbolHeight);
    sndButtonClick := Snd_LoadFromFile(PAnsiChar(Dir+'/buttonclick.wav'),1);

    gupInitPopup(@EditActionsPopup,'Вырезать|Копировать|Вставить|Удалить|Удалить все',@OnEditPopupAction);

    Key_LoadLayout(K_LAYOUT_RUS);
  end;

  procedure guiDrawText(Text:string; X,Y:single; doCenter:Boolean=false; doHover:Boolean=false;trans:byte=255);
  var cl:integer;
      n,i,jx,jy:Integer;
  begin
    if doCenter then X:=X-symbolWidth*Length(text)/2-1;
    if doHover then cl:=textHoverColor else cl:=textColor;
    jx:=Round(x); jy:=Round(y);
    for n:=1 to Length(Text) do begin
      i:=Ord(text[n])-31;
      if i = -18 then begin
        jX:=Round(x);
        jY:=jY+10;
        Continue;
      end;
      ASprite_Draw(txtFont,jX+textXOffset,jY+textYOffset,symbolWidth,symbolHeight,i,trans);
      Inc(jX,symbolWidth);
    end;
  end;

  procedure guiDrawProgressBar(X,Y,W,Coef:single);
  begin
    r.X:=pbX; r.Y:=pbY; r.Width:=pbWidth; r.Height:=pbHeight;
    CSprite_Draw(txtMainTex,X,Y,pbWidth,pbHeight,@r);
    r.X:=pbX+pbWidth; r.Width:=0;
    CSprite_Draw(txtMainTex,X+pbWidth,Y,W*Coef,pbHeight,@r);
    r.X:=pbX+pbWidth+1;
    CSprite_Draw(txtMainTex,X+pbWidth+W*Coef,Y,W*(1-Coef),pbHeight,@r);
    r.X:=pbX+pbWidth+2; r.Width:=pbWidth;
    CSprite_Draw(txtMainTex,X+pbWidth+W,Y,pbWidth,pbHeight,@r);
  end;

  procedure guiDrawEdit(ed:PMyEdit);
  var s:string;
      i,st,l,n,edlen,ds,dl,dn,offset,caret:Integer;
  begin
    r.X:=editX; r.Y:=editY;
    r.Width:=editWidth; r.Height:=editHeight;
    CSprite_Draw(txtMainTex,ed.X,ed.Y,editWidth,editHeight,@r);
    r.X:=editX+editWidth;
    CSprite_Draw(txtMainTex,ed.X+editWidth+ed.W,ed.Y,editWidth,editHeight,@r);
    r.Width:=0; r.X:=editX+editWidth;
    CSprite_Draw(txtMainTex,ed.X+editWidth,ed.Y,ed.W,editHeight,@r);
    edlen:=ed.W div symbolWidth;
    s:=Copy(ed.Text,ed.Offset+1,edlen);
    
   { if Length(s)>i then begin
      if ed.SelectStart<>ed.SelectEnd then caret:=ed.SelectEnd else
        caret:=Length(ed.LeftText);
      offset:=caret-i-1;
      s:=Copy(s,offset,i);
    end else offset:=0;   }
    if ed.Hint<>'' then begin
      guiDrawText(ed.Hint,ed.X+ed.W+editWidth*2+2,ed.Y);
    end;

    guiDrawText(s,ed.X,ed.Y);

    n:=length(ed.LeftText)-ed.Offset;
    //if ed.Offset>0 then Inc(n);
    if n>edlen then n:=edlen;
    if n<0 then n:=0;

    st:=ed.SelectStart;
    l:=ed.SelectEnd-st;
    if l<0 then begin
      st:=ed.SelectEnd;
      l:=ed.SelectStart-st;
    end;
    if ((Focus.FocusType=ft_edit) or (Focus.FocusType=ft_popup)) and (Focus.asEdit=ed) then begin
      if l<>0 then begin
        ds:=st-ed.Offset;
        dl:=l;
        if ds<0 then begin
          Inc(dl,ds+1);
          ds:=0;
        end;
        if dl>edlen-ds then
          dl:=edlen-ds;
        r.X:=editselX; r.y:=editselY; r.Width:=editselWidth; r.Height:=editselHeight;
        CSprite_Draw(txtMainTex,ed.X+ds*symbolWidth,ed.Y+2,editselWidth,editselHeight,@r);
        r.Width:=1; r.X:=r.X+editselWidth;
        CSprite_Draw(txtMainTex,ed.X+ds*symbolWidth+editselWidth,ed.Y+2,dl*symbolWidth,editselHeight,@r);
        r.X:=r.X+1; r.Width:=editselWidth;
        CSprite_Draw(txtMainTex,ed.X+ds*symbolWidth+editselWidth+dl*symbolWidth,ed.Y+2,editselWidth,editselHeight,@r);
      end else begin
        r.X:=selX; r.y:=selY; r.Width:=selWidth; r.Height:=selHeight;
        CSprite_Draw(txtMainTex,ed.X+1+n*symbolWidth,ed.Y,selWidth,selHeight,@r);
      end;
    end;
    i:=round(Mouse_X-ed.X-editWidth+symbolWidth/2) div symbolWidth+ed.Offset;
    //if (ed.Offset>0) and (Mouse_Down(1)=false) then dec(i);
    if i>Length(ed.Text) then i:=Length(ed.Text);
    if i<0 then i:=0;
    if MouseInBorder(ed.X,ed.Y,comboWidth*2+ed.W,editHeight) and ((Focus.FocusType=ft_none) or ((Focus.FocusType=ft_edit) and (Focus.asEdit=ed))) then begin
      if Mouse_Down(1) and (LbState=False) then begin
        guiPlayClick;
        Focus.FocusType:=ft_edit;
        ed.LeftText:=Copy(ed.Text,1,i);
        ed.RightText:=Copy(ed.Text,i+1,Length(ed.Text)-i);
        Key_BeginReadText(PAnsiChar(ed.LeftText));
        Focus.asEdit:=ed;
        ed.SelectStart:=i;
        ClickOnEdit:=True;
      end;

    end;
    if (Focus.FocusType=ft_edit) and (Focus.asEdit=ed) then begin
      if (ed.SelectStart=ed.SelectEnd) and (Mouse_Down(1)=false) then begin
        if (Length(ed.LeftText)<ed.Offset) and (ed.Offset>0) then Dec(ed.Offset);
        if (Length(ed.LeftText)>ed.Offset+edlen-1) and (ed.Offset<Length(ed.Text)-edlen+1) then Inc(ed.Offset);
      end;
      if (Mouse_Down(1)=False) and LbState and ClickOnEdit then begin
        if ed.SelectEnd-ed.SelectStart<>0 then
          guiPlayClick;
        LbState:=False;
        ed.LeftText:=Copy(ed.Text,1,i);
        ed.RightText:=Copy(ed.Text,i+1,Length(ed.Text)-i);
        Key_BeginReadText(PAnsiChar(ed.LeftText));
        ClickOnEdit:=False;
      end;
      if Mouse_Down(1) and ClickOnEdit then begin
        ed.SelectEnd:=i;
      end;
    end;
  end;

  procedure guiDrawComboBox(cm:PMyComboBox);
  var eOffset:Integer;
  begin
    if cm.ElementsTexture<>nil then eOffset:=elHeight else eOffset:=0;
    r.X:=comboX; r.Y:=comboY;
    r.Width:=comboWidth; r.Height:=comboHeight;
    CSprite_Draw(txtMainTex,cm.X,cm.Y,editWidth,comboHeight,@r);
    if (Length(cm.Values)>0) and MouseInBorder(cm.X,cm.Y,comboSelWidth+cm.W+comboWidth,comboHeight) and (Focus.FocusType=ft_none) then begin
      if guiMouseClick then begin
        guiPlayClick;
        if (Focus.FocusType=ft_combobox) and (Focus.asComboBox=cm) then begin
          Focus.FocusType:=ft_none;
        end else begin
          Focus.FocusType:=ft_combobox;
          Focus.asComboBox:=cm;
          //cm.Offset:=0;
          //cm.prOffset:=0;
        end;
      end;
      r.X:=comboX+comboWidth+comboSelWidth+1;
    end else begin
      r.X:=comboX+comboWidth+1;
    end;
    r.Width:=comboSelWidth;
    CSprite_Draw(txtMainTex,cm.X+comboWidth+cm.W,cm.Y,comboSelWidth,comboHeight,@r);
    r.Width:=0; r.X:=comboX+comboWidth;
    CSprite_Draw(txtMainTex,cm.X+comboWidth,cm.Y,cm.W,comboHeight,@r);
    if eOffset<>0 then begin
      ASprite_Draw(cm.ElementsTexture,cm.X+1,cm.Y,
        elHeight,elHeight,cm.SelId+1);
    end;
    if Length(cm.Values)>0 then
      guiDrawText(cm.Values[cm.SelId],cm.X+eOffset+1,cm.Y)
    else
      guiDrawText('Нет элементов',cm.X,cm.Y,false,False,128)
  end;

  procedure guiDrawRadioButtons(Text:string; X,Y:single;var doVal:integer);
  var i,n:Integer;
      s:string;
      b:Boolean;
  begin
    n:=0;
    while pos('|',Text)<>0 do begin
      s:=Copy(Text,1,Pos('|',Text)-1);
      Delete(Text,1,Pos('|',Text));
      if n=doVal then i:=0 else i:=1;
      b:=False;
      if MouseInBorder(X,Y+n*rdHeight,Text_GetWidth(Font,PAnsiChar(s),textScale,0)+rdWidth,rdHeight-1) and (Focus.FocusType=ft_none) then begin
        i:=i+2;
        if guiMouseClick then begin
          guiPlayClick;
          doVal:=n;
          Focus.FocusType:=ft_none;
        end;
        b:=True;
      end;
      r.X:=rdX; r.Y:=rdY+i*rdHeight;
      r.Width:=rdWidth; r.Height:=rdHeight;
      CSprite_Draw(txtMainTex,X,Y+n*rdHeight,rdWidth,rdHeight,@r);
      guiDrawText(s,X+rdWidth,Y+n*rdHeight,false,b);

      Inc(n);
    end;
  end;

  procedure guiDrawCheckBox(Text:string; X,Y:single;var doVal:Boolean);
  var i:Integer;
      b:Boolean;
  begin
    if doVal then i:=0 else i:=1;
    b:=False;
    if MouseInBorder(X,Y,length(Text)*symbolWidth+cboxWidth,cboxHeight) and (Focus.FocusType=ft_none) then begin
      i:=i+2;
      if guiMouseClick then begin
        guiPlayClick;
        doVal:=not doVal;
        Focus.FocusType:=ft_none;
      end;
      b:=True;
    end;
    r.X:=cboxX; r.Y:=cboxY+i*cboxHeight;
    r.Width:=cboxWidth; r.Height:=cboxHeight;
    CSprite_Draw(txtMainTex,X,Y,cboxWidth,cboxHeight,@r);
    guiDrawText(Text,X+cboxWidth,Y,false,b);
  end;

  function guiDrawButton(Text:string; X,Y,W:single; doCenter:Boolean=true):integer;
  var i:Integer;

  begin
    i:=0;
    W:=W-buttonWidth;
    Result:=button_none;
    if MouseInBorder(X,Y,W+buttonWidth,buttonHeight) and (Focus.FocusType=ft_none) then begin
      i:=1;
      Result:=button_hover;
      if Mouse_Down(1) then i:=2;
      if guiMouseClick then begin
        guiPlayClick;
        Focus.FocusType:=ft_none;
        Result:=button_click;
      end;
    end;
    r.X:=buttonX;
    r.y:=buttonY+i*buttonHeight;
    r.Width:=buttonWidth/2;r.Height:=buttonHeight;
    CSprite_Draw(txtMainTex,X,Y,buttonWidth/2,buttonHeight,@r);
    r.X:=buttonX+buttonWidth/2;
    CSprite_Draw(txtMainTex,X+W+buttonWidth/2,Y,buttonWidth/2,buttonHeight,@r);
    r.Width:=1;
    CSprite_Draw(txtMainTex,X+buttonWidth/2,Y,W,buttonHeight,@r);
    if doCenter then
      guiDrawText(Text,X+buttonWidth/2+W/2,Y+textYOffset,true)
    else
      guiDrawText(Text,X+16,Y+textYOffset,False);
  end;

  procedure guiDrawMemoBorder(X,Y,W,H:single;Transparenty:Byte=255);
  begin
    X:=round(X); Y:=Round(Y);
    W:=round(W); H:=Round(H);
    r.X:=memoX; r.y:=memoY; r.Width:=memoWidth; r.Height:=memoHeight;
    CSprite_Draw(txtMainTex,X,Y,memoWidth,memoHeight,@r,Transparenty);
    r.X:=memoX+memoWidth;
    CSprite_Draw(txtMainTex,X+W+memoWidth,Y,memoWidth,memoHeight,@r,Transparenty);
    r.y:=memoY+memoHeight;
    CSprite_Draw(txtMainTex,X+W+memoWidth,Y+H+memoHeight,memoWidth,memoHeight,@r,Transparenty);
    r.X:=memoX; r.y:=memoY+memoHeight;
    CSprite_Draw(txtMainTex,X,Y+H+memoHeight,memoWidth,memoHeight,@r,Transparenty);
    r.X:=memoX+memoWidth; r.y:=memoY+memoHeight; r.Width:=1;
    CSprite_Draw(txtMainTex,X+memoWidth,Y+H+memoHeight,W,memoHeight,@r,Transparenty);
    r.y:=memoY;
    CSprite_Draw(txtMainTex,X+memoWidth,Y,W,memoHeight,@r,Transparenty);
    r.X:=memoX; r.y:=memoY+memoHeight; r.Width:=memoWidth; r.Height:=1;
    CSprite_Draw(txtMainTex,X,Y+memoHeight,memoWidth,H,@r,Transparenty);
    r.X:=memoX+memoWidth;
    CSprite_Draw(txtMainTex,X+W+memoWidth,Y+memoHeight,memoWidth,H,@r,Transparenty);
    r.Width:=1;
    CSprite_Draw(txtMainTex,X+memoWidth,Y+memoHeight,W,H,@r,Transparenty);
  end;

  procedure guiDrawForm(Text:string; X,Y,W,H:single;trans:Byte=255);
  begin
    W:=W-frmWidth*2;
    H:=H-frmHeight*2;
    r.X:=frmX; r.y:=frmY; r.Width:=frmWidth; r.Height:=frmHeight;
    CSprite_Draw(txtMainTex,X,Y,frmWidth,frmHeight,@r,trans);
    r.X:=frmX+frmWidth;
    CSprite_Draw(txtMainTex,X+W+frmWidth,Y,frmWidth,frmHeight,@r,trans);
    r.y:=frmY+frmHeight;
    CSprite_Draw(txtMainTex,X+W+frmWidth,Y+H+frmHeight,frmWidth,frmHeight,@r,trans);
    r.X:=frmX; r.y:=frmY+frmHeight;
    CSprite_Draw(txtMainTex,X,Y+H+frmHeight,frmWidth,frmHeight,@r,trans);
    r.X:=frmX+frmWidth; r.y:=frmY+frmHeight; r.Width:=1;
    CSprite_Draw(txtMainTex,X+frmWidth,Y+H+frmHeight,W,frmHeight,@r,trans);
    r.y:=frmY;
    CSprite_Draw(txtMainTex,X+frmWidth,Y,W,frmHeight,@r,trans);
    r.X:=frmX; r.y:=frmY+frmHeight; r.Width:=frmWidth; r.Height:=1;
    CSprite_Draw(txtMainTex,X,Y+frmHeight,frmWidth,H,@r,trans);
    r.X:=frmX+frmWidth;
    CSprite_Draw(txtMainTex,X+W+frmWidth,Y+frmHeight,frmWidth,H,@r,trans);
    r.Width:=1;
    CSprite_Draw(txtMainTex,X+frmWidth,Y+frmHeight,W,H,@r,trans);

    guiDrawText(Text,X+textXOffset+formXOffset,Y+formYOffset,False,False,trans);
  end;

end.
