aboutsummaryrefslogblamecommitdiffstats
path: root/Lua/src/menu/UMenuText.pas
blob: a3d1383470f6a89f3c1e5374d6983fbd82a22bd5 (plain) (tree)























































































































































































































































































































































































                                                                                                                                                                                                                            
{* UltraStar Deluxe - Karaoke Game
 *
 * UltraStar Deluxe is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; see the file COPYING. If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 *
 * $URL$
 * $Id$
 *}

unit UMenuText;

interface

{$IFDEF FPC}
  {$MODE Delphi}
{$ENDIF}

{$I switches.inc}

uses
  TextGL,
  UTexture,
  gl, 
  math,
  SysUtils,
  SDL;

type
  TText = class
    private
      SelectBool:   boolean;
      TextString:   string;
      TextTiles:    array of string;

      STicks:       Cardinal;
      SelectBlink:  boolean;
    public
      X:      real;
      Y:      real;
      Z:      real;
      MoveX:  real;       //Some Modifier for X - Position that don't affect the real Y
      MoveY:  real;       //Some Modifier for Y - Position that don't affect the real Y
      W:      real;       //text wider than W is broken
//      H:      real;
      Size:   real;
      ColR:   real;
      ColG:   real;
      ColB:   real;
      Alpha:  real;
      Int:    real;
      Style:  integer;
      Visible:  boolean;
      Align:    integer; // 0 = left, 1 = center, 2 = right

      //Reflection
      Reflection:           boolean;
      ReflectionSpacing:    real;

      procedure SetSelect(Value: boolean);
      property Selected: boolean read SelectBool write SetSelect;

      procedure SetText(Value: string);
      property  Text: string read TextString write SetText;

      procedure DeleteLastL; //Procedure to Delete Last Letter

      procedure Draw;
      constructor Create; overload;
      constructor Create(X, Y: real; Text: string); overload;
      constructor Create(ParX, ParY, ParW: real; ParStyle: integer; ParSize, ParColR, ParColG, ParColB: real; ParAlign: integer; ParText: string; ParReflection: boolean; ParReflectionSpacing: real; ParZ: real); overload;
  end;

implementation

uses UGraphic,
     StrUtils;

procedure TText.SetSelect(Value: boolean);
begin
  SelectBool := Value;
  
  //Set Cursor Visible
  SelectBlink := True;
  STicks := SDL_GetTicks() div 550;
end;

procedure TText.SetText(Value: string);
var
  NextPos:   Cardinal;  //NextPos of a Space etc.
  LastPos:   Cardinal;  //LastPos "
  LastBreak: Cardinal;  //Last Break
  isBreak:   boolean;   //True if the Break is not Caused because the Text is out of the area
  FirstWord: Word;      //Is First Word after Break?
  Len:       Word;      //Length of the Tiles Array

  function GetNextPos: boolean;
  var
    T1, {T2,} T3: Cardinal;
  begin
    LastPos := NextPos;

    //Next Space (If Width is given)
    if (W > 0) then
      T1 := PosEx(' ', Value, LastPos + 1)
    else T1 := Length(Value);

    {//Next -
    T2 := PosEx('-', Value, LastPos + 1);}

    //Next Break
    T3 := PosEx('\n', Value, LastPos + 1);

    if T1 = 0 then
      T1 := Length(Value);
    {if T2 = 0 then
      T2 := Length(Value); }
    if T3 = 0 then
      T3 := Length(Value);

    //Get Nearest Pos
    NextPos := min(T1, T3{min(T2, T3)});

    if (LastPos = Length(Value)) then
      NextPos := 0;

    isBreak := (NextPos = T3) AND (NextPos <> Length(Value));
    Result := (NextPos <> 0);
  end;

  procedure AddBreak(const From, bTo: Cardinal);
  begin
    if (isBreak) OR (bTo - From >= 1) then
    begin
      Inc(Len);
      SetLength (TextTiles, Len);
      TextTiles[Len-1] := Trim(Copy(Value, From, bTo - From));

      if isBreak then
        LastBreak := bTo + 2
      else
        LastBreak := bTo + 1;
      FirstWord := 0;
    end;
  end;

begin
  //Set TExtstring
  TextString := Value;

  //Set Cursor Visible
  SelectBlink := True;
  STicks := SDL_GetTicks() div 550;

  //Exit if there is no Need to Create Tiles
  if (W <= 0) and (Pos('\n', Value) = 0) then
  begin
    SetLength (TextTiles, 1);
    TextTiles[0] := Value;
    Exit;
  end;

  //Create Tiles
  //Reset Text Array
  SetLength (TextTiles, 0);
  Len := 0;

  //Reset Counter Vars
  LastPos := 1;
  NextPos := 1;
  LastBreak := 1;
  FirstWord := 1;

  if (W > 0) then
  begin
    //Set Font Properties
    SetFontStyle(Style);
    SetFontSize(Size);
  end;

  //go Through Text
  while (GetNextPos) do
  begin
      //Break in Text
      if isBreak then
      begin
        //Look for Break before the Break
        if (glTextWidth(Copy(Value, LastBreak, NextPos - LastBreak + 1)) > W) AND (NextPos-LastPos > 1) then
        begin
          isBreak := False;
          //Not the First word after Break, so we don't have to break within a word
          if (FirstWord > 1) then
          begin
            //Add Break before actual Position, because there the Text fits the Area
            AddBreak(LastBreak, LastPos);
          end
          else //First Word after Break Break within the Word
          begin
            //ToDo
            //AddBreak(LastBreak, LastBreak + 155);
          end;
        end;

        isBreak := True;
        //Add Break from Text
        AddBreak(LastBreak, NextPos);
      end
      //Text comes out of the Text Area -> CreateBreak
      else if (glTextWidth(Copy(Value, LastBreak, NextPos - LastBreak + 1)) > W) then
      begin
        //Not the First word after Break, so we don't have to break within a word
        if (FirstWord > 1) then
        begin
          //Add Break before actual Position, because there the  Text fits the Area
          AddBreak(LastBreak, LastPos);
        end
        else //First Word after Break -> Break within the Word
        begin
          //ToDo
          //AddBreak(LastBreak, LastBreak + 155);
        end;
      end;
    //end;
    Inc(FirstWord)
  end;
  //Add Ending
  AddBreak(LastBreak, Length(Value)+1);
end;

procedure TText.DeleteLastL;
var
  S: string;
  L: integer;
begin
  S := TextString;
  L := Length(S);
  if (L > 0) then
    SetLength(S, L-1);

  SetText(S);
end;

procedure TText.Draw;
var
  X2, Y2: real;
  Text2:  string;
  I:      integer;
begin
  if Visible then
  begin
    SetFontStyle(Style);
    SetFontSize(Size);
    SetFontItalic(False);

    glColor4f(ColR*Int, ColG*Int, ColB*Int, Alpha);

    //Reflection
    if Reflection = true then
      SetFontReflection(true, ReflectionSpacing)
    else
      SetFontReflection(false,0);

    //if selected set blink...
    if SelectBool then
    begin
      I := SDL_GetTicks() div 550;
      if I <> STicks then
      begin //Change Visability
        STicks := I;
        SelectBlink := Not SelectBlink;
      end;
    end;

    {if (False) then //no width set draw as one long string
    begin
      if not (SelectBool AND SelectBlink) then
        Text2 := Text
      else
        Text2 := Text + '|';

      case Align of
        0: X2 := X;
        1: X2 := X - glTextWidth(Text2)/2;
        2: X2 := X - glTextWidth(Text2);
      end;

      SetFontPos(X2, Y);
      glPrint(Text2);
      SetFontStyle(0); // reset to default
    end
    else
    begin}
    //now use allways:
    //draw text as many strings
      Y2 := Y + MoveY;
      for I := 0 to high(TextTiles) do
      begin
        if (not (SelectBool and SelectBlink)) or (I <> high(TextTiles)) then
          Text2 := TextTiles[I]
        else
          Text2 := TextTiles[I] + '|';

        case Align of
          0: X2 := X + MoveX;
          1: X2 := X + MoveX - glTextWidth(Text2)/2;
          2: X2 := X + MoveX - glTextWidth(Text2);
        end;

        SetFontPos(X2, Y2);

        SetFontZ(Z);

        glPrint(Text2);

        {if Size >= 10 then
          Y2 := Y2 + Size * 0.93
        else}
        if (Style = 1) then
          Y2 := Y2 + Size * 0.93
        else
          Y2 := Y2 + Size * 0.72;
      end;
      SetFontStyle(0); // reset to default

    //end;
  end;
end;

constructor TText.Create;
begin
  Create(0, 0, '');
end;

constructor TText.Create(X, Y: real; Text: string);
begin
  Create(X, Y, 0, 0, 30, 0, 0, 0, 0, Text, false, 0, 0);
end;

constructor TText.Create(ParX, ParY, ParW: real; ParStyle: integer; ParSize, ParColR, ParColG, ParColB: real; ParAlign: integer; ParText: string; ParReflection: boolean; ParReflectionSpacing: real; ParZ:real);
begin
  inherited Create;
  Alpha := 1;
  X := ParX;
  Y := ParY;
  W := ParW;
  Z := ParZ;
  Style := ParStyle;
  Size := ParSize;
  Text := ParText;
  ColR := ParColR;
  ColG := ParColG;
  ColB := ParColB;
  Int := 1;
  Align := ParAlign;
  SelectBool := false;
  Visible := true;
  Reflection:= ParReflection;
  ReflectionSpacing:= ParReflectionSpacing;
end;

end.