ACSBase.pas
上传用户:yj_qiu
上传日期:2022-08-08
资源大小:23636k
文件大小:48k
源码类别:

游戏引擎

开发平台:

Delphi

  1. (*
  2.  @Abstract(ACS GUI library base unit)
  3.  (C) 2006 George "Mirage" Bakhtadze. <a href="http://www.casteng.com">www.casteng.com</a> <br>
  4.  The source code may be used under either MPL 1.1 or LGPL 2.1 license. See included license.txt file <br>
  5.  Unit contains basic GUI classes and constants
  6. *)
  7. {$Include GDefines.inc}
  8. unit ACSBase;
  9. interface
  10. uses
  11.   TextFile,
  12.   SysUtils,
  13.   BaseTypes, Basics, Props, Base3D, BaseGraph, MarkUp, Resources, Models,
  14.   BaseClasses, BaseMsg, ItemMsg;
  15. const
  16.   // Anchors
  17.   aLeft = 0; aTop = 1; aRight = 2; aBottom = 3;
  18.   // Origins
  19.   HOriginEnum = 'Left&Center&Right';
  20.   VOriginEnum = 'Top&Center&Bottom';
  21.   // Frames
  22.   frNormal = 0; frHover = 1; frPushed = 2; frFocused = 3; frDisabled = 4;
  23.   // GetItemAt results if missed any item
  24.   miLeft = -1; miRight = -2; miUp = -3; miDown = -4;
  25.   // Bound values
  26.   pvLeft = 0; pvTop = 1; pvWidth = 2; pvHeight = 3;
  27.   BoundValuesEnum = 'Left&Top&Width&Height';
  28.   // Align
  29.   AlignEnum = 'None&Top&Left&Right&Bottom&Client';
  30. type
  31.   TAlign       = (alNone, alTop, alLeft, alRight, alBottom, alClient, alAbsolute);
  32.   THOrigin     = (hoLeft, hoCenter, hoRight);
  33.   TVOrigin     = (voTop,  voCenter, voBottom);
  34. //  TBoundValues = (pvLeft, pvTop, pvWidth, pvHeight);
  35.   TGUIItem = class;
  36.   TGUIStateDelegate = function(Caller: TGUIItem): Boolean of object;
  37.   TConstraints = record
  38.     MinWidth, MinHeight, MaxWidth, MaxHeight: Single;
  39.   end;
  40.   /// Responsibilies: Item aggregation, GUI messages forwarding
  41.   TBaseGUIItem = class(TBaseProcessing)
  42.   private
  43.     DefaultModel: TModel;
  44.   protected
  45.     function GetModel: TModel; virtual;
  46.     procedure SetModel(const Value: TModel);
  47.     function GetNonGUIDummyParent: TItem;
  48.     procedure ObtainParentDimensions(out PWidth, PHeight: Single);
  49.     procedure RealignChilds(StartIndex: Integer); virtual;
  50.   public
  51.     AggregatedItem: TItem;                                             // An aggregated item of AggregatedClass if needed
  52.     constructor Create(AManager: TItemsManager); override;
  53.     destructor Destroy; override;
  54.     procedure HandleMessage(const Msg: TMessage); override;
  55.     function GUIHandleMessage(const Msg: TMessage): Boolean; virtual;
  56.     procedure ReturnMessage(const Msg: TMessage); virtual;             // Return a message through the hierarchy
  57.     procedure AddProperties(const Result: Props.TProperties); override;
  58.     procedure SetProperties(Properties: Props.TProperties); override;
  59.     procedure Draw; virtual; abstract;
  60.     property Model: TModel read GetModel write SetModel;
  61.   end;
  62.   TGUIRootItem = class(TBaseGUIItem)
  63.   /// Root GUI item:
  64.   /// Responsibilities: GUI<->general messages forwarding, keyboard focus/mouse capture items handling
  65.   private
  66.     FFocusedItem: TGUIItem;
  67.     procedure SetFocusedItem(const Item: TGUIItem);
  68.   public
  69.     // Keys
  70.     KeyEnter, KeyEscape, KeyUp, KeyDown, KeyLeft, KeyRight: Integer;
  71.     constructor Create(AManager: TItemsManager); override;
  72.     procedure OnSceneAdd; override;
  73.     procedure OnSceneRemove; override;
  74.     procedure HandleMessage(const Msg: TMessage); override;
  75.     procedure ReturnMessage(const Msg: TMessage); override;
  76.     function IsWithinGUI(AX, AY: Single): Boolean;
  77.     procedure Draw; override;
  78.     property FocusedItem: TGUIItem read FFocusedItem write SetFocusedItem;
  79.   end;
  80.   TGUIBounds = class(TBaseGUIItem)
  81.   /// Responsibilities: Bounds handling, layout
  82.   private
  83.     FTransform: TMatrix4s;                               // Transform including translation, rotation and scale
  84.     FLocalViewport: BaseGraph.TViewport;                 // Clipping area in local coordinates
  85.     TransformValid, DisableRealign: Boolean;
  86.     AlignRect: TArea;                                    // A rectangle within which align of the control is done
  87.     FAlign: TAlign;
  88.     FAnchors: BaseTypes.TSet32;
  89.     FHOrigin: THOrigin;                                  // Horizontal and vertival
  90.     FVOrigin: TVOrigin;                                  // origins of coordinates
  91.     FConstraints: TConstraints;
  92.     FPercentValues: BaseTypes.TSet32;                              // X, Y, Width and Height can be interpreted as percents of parent's dimensions
  93.     // Coordinates entered via properties
  94.     FX, FY, FWidth, FHeight, FAngle: Single;
  95.     // Coordinates in pixels in parent's frame
  96.     FPxX, FPxY, FPxWidth, FPxHeight: Single;
  97.     // Client area dimensions
  98. //    FInnerWidth, FInnerHeight: Single;
  99.     // Client (scrollable) viewport
  100.     FClientX, FClientY, FClientWidth, FClientHeight: Single;
  101.     // Scroll position
  102.     FScrollX, FScrollY: Single;
  103.     // Client viewport border (nonclient area)
  104.     FBorder: Integer;
  105.     procedure InvalidateTransform;
  106.     procedure SetX(const Value: Single);
  107.     procedure SetY(const Value: Single);
  108.     procedure SetAngle(const Value: Single);
  109.     procedure SetPxX(Value: Single);
  110.     procedure SetPxY(Value: Single);
  111.     procedure SetPxWidth(Value: Single);
  112.     procedure SetPxHeight(Value: Single);
  113.     procedure SetAlign(const Value: TAlign);
  114.     procedure SetHOrigin(const Value: THOrigin);
  115.     procedure SetVOrigin(const Value: TVOrigin);
  116.     procedure SetPercentValues(const Value: BaseTypes.TSet32);
  117.     procedure SetBorder(const Value: Integer);
  118.     function GetTransform: TMatrix4s;
  119.     function GetLocalViewport: BaseGraph.TViewport;
  120.     procedure ComputeTransform;
  121.   protected
  122.     procedure Realign;
  123.     // Recalculates control's bounds according to anchors when size if control's container (parent) changes
  124.     procedure CalcBounds(var ARect: BaseTypes.TArea);
  125.     procedure ApplyAnchors(ParentDeltaWidth, ParentDeltaHeight: Single); virtual;
  126.     procedure CalcClientArea; virtual;
  127.     procedure SetWidth(const Value: Single); virtual;
  128.     procedure SetHeight(const Value: Single); virtual;
  129.   public
  130.     constructor Create(AManager: TItemsManager); override;          // Regular constructor
  131.     procedure HandleMessage(const Msg: TMessage); override;
  132.     procedure AddProperties(const Result: Props.TProperties); override;
  133.     procedure SetProperties(Properties: Props.TProperties); override;
  134.     function IsWithin(AX, AY: Single): Boolean; virtual;                 // AX and AY are in screen space
  135.     procedure ClientToScreen(var AX, AY: Single);
  136.     procedure ScreenToClient(var AX, AY: Single);
  137.     property Transform: TMatrix4s read GetTransform;
  138.     /// Coordinates and dimensions
  139.     property X:      Single read FX      write SetX;
  140.     property Y:      Single read FY      write SetY;
  141.     property Width:  Single read FWidth  write SetWidth;
  142.     property Height: Single read FHeight write SetHeight;
  143.     property Angle:  Single read FAngle  write SetAngle;
  144.     /// Coordinates and dimensions in pixels
  145.     property PxX:      Single read FPxX      write SetPxX;
  146.     property PxY:      Single read FPxY      write SetPxY;
  147.     property PxWidth:  Single read FPxWidth  write SetPxWidth;
  148.     property PxHeight: Single read FPxHeight write SetPxHeight;
  149.     /// Client viewport
  150.     property ClientX: Single      read FClientX;
  151.     property ClientY: Single      read FClientY;
  152.     property ClientWidth: Single  read FClientWidth;
  153.     property ClientHeight: Single read FClientHeight;
  154.     property Border: Integer read FBorder write SetBorder;
  155.     /// Scroll position
  156.     property ScrollX: Single read FScrollX;
  157.     property ScrollY: Single read FScrollY;
  158.     /// Layout settings
  159.     property HOrigin: THOrigin read FHOrigin write SetHOrigin;
  160.     property VOrigin: TVOrigin read FVOrigin write SetVOrigin;
  161.     property Align:   TAlign   read FAlign   write SetAlign;
  162.     property PercentValues: BaseTypes.TSet32 read FPercentValues write SetPercentValues;
  163.   end;
  164.   TGUIItem = class(TGUIBounds)
  165.   private
  166.     function GetAbility: Boolean;
  167.     procedure SetAbility(const Value: Boolean);
  168.     function GetVisibility: Boolean;
  169.     procedure SetVisibility(const Value: Boolean);
  170.     procedure SetFocused(const Value: Boolean);
  171.     function GetGUIRoot: TGUIRootItem;
  172.     function CanBeFocused: Boolean;
  173.   protected
  174.     CanFocus: Boolean;
  175.     FFocused, Hover, Pushed: Boolean;
  176.     procedure SetState(const Value: TSet32); override;
  177.     function GetStatesSource: TGUIItem;
  178.     procedure UpdateVisualParameters; virtual;
  179.     function isVisibleAndEnabled: Boolean;
  180.     procedure HandleClick(Button, MX, MY: Integer); virtual;
  181.   public
  182.     ParentState: Boolean;
  183.     Color, NormalColor, HoverColor, FocusedColor, PushedColor, DisabledColor: TColor;
  184.     IsVisibleDelegate, IsEnabledDelegate: TGUIStateDelegate;
  185.     constructor Create(AManager: TItemsManager); override;          // Regular constructor
  186.     procedure HandleMessage(const Msg: TMessage); override;
  187.     function GUIHandleMessage(const Msg: TMessage): Boolean; override;
  188.     procedure ReturnMessage(const Msg: TMessage); override;
  189.     procedure Draw; override;
  190.     procedure AddProperties(const Result: Props.TProperties); override;
  191.     procedure SetProperties(Properties: Props.TProperties); override;
  192.     property Enabled: Boolean read GetAbility write SetAbility;
  193.     property Visible: Boolean read GetVisibility write SetVisibility;
  194.     property Focused: Boolean read FFocused write SetFocused;
  195.   end;
  196.   TTextGUIItem = class(TGUIItem)
  197.   private
  198.     FText, RText: string;                                            // Text property value and text to render
  199.   protected
  200.     Colored: Boolean;
  201.     procedure SetText(const AText: string); virtual;
  202.     procedure ResolveLinks; override;
  203.     function GetSizeAdjustable: Boolean; virtual;
  204.   public
  205.     Font: TFont;
  206.     Markup: TMarkup;
  207.     procedure CalcClientArea; override;
  208.     function GetClearedText: string;
  209.     function GUIHandleMessage(const Msg: TMessage): Boolean; override;
  210.     procedure AddProperties(const Result: Props.TProperties); override;
  211.     procedure SetProperties(Properties: Props.TProperties); override;
  212.     procedure DrawText(AX, AY: Single); virtual;
  213.     destructor Destroy; override;
  214.     property Text: string read FText write SetText;
  215.     property CText: string read GetClearedText;
  216.   end;
  217.   TUVGUIItem = class(TGUIItem)
  218.   private
  219.     MaxFrame: Integer;
  220.     FFrame: Integer;
  221.     FUVMap: TUVMap;
  222.   protected
  223.     NormalFrame: Integer;
  224.     UsedFrames: BaseTypes.TSet32;
  225.     procedure UpdateVisualParameters; override;
  226.   public
  227.     constructor Create(AManager: TItemsManager); override;
  228.     procedure AddProperties(const Result: Props.TProperties); override;
  229.     procedure SetProperties(Properties: Props.TProperties); override;
  230.     procedure ResolveLinks; override;
  231.     procedure SetUVMap(const AUVMap: TUVMap; ATotalFrames: Integer);
  232.     procedure SetFrame(const Value: Integer); virtual;
  233.     property Frame: Integer read FFrame write SetFrame;
  234.     property UVMap: TUVMap read FUVMap;
  235.   end;
  236. var AggregatedClass: CItem;
  237. implementation
  238. uses GUIMsg;
  239. function isItemVisibleAndEnabled(Item: TItem): Boolean;
  240. begin
  241.   Result := (Item is TGUIItem) and TGUIItem(Item).Enabled and TGUIItem(Item).Visible;
  242. end;
  243. { TBaseGUIItem }
  244. function TBaseGUIItem.GetModel: TModel;
  245. begin
  246.   Result := DefaultModel;
  247. end;
  248. procedure TBaseGUIItem.SetModel(const Value: TModel);
  249. begin
  250.   if Model = Value then Exit;
  251.   if Assigned(DefaultModel) then FreeAndNil(DefaultModel);
  252.   Model := Value;
  253. end;
  254. function TBaseGUIItem.GetNonGUIDummyParent: TItem;
  255. begin
  256.   Result := Parent;
  257.   while Result is TDummyItem do Result := Result.Parent;                        // Skip dummy items
  258. end;
  259. procedure TBaseGUIItem.ObtainParentDimensions(out PWidth, PHeight: Single);
  260. var ParItem: TItem;
  261. begin
  262.   ParItem := GetNonGUIDummyParent;
  263.   if ParItem is TGUIBounds then begin
  264.     PWidth  := TGUIBounds(ParItem).PxWidth;
  265.     PHeight := TGUIBounds(ParItem).PxHeight;
  266.   end else begin
  267.     PWidth  := Screen.Width;
  268.     PHeight := Screen.Height;
  269.   end;
  270. end;
  271. procedure TBaseGUIItem.RealignChilds(StartIndex: Integer);
  272. var Rect: TArea; Cur: TItem;
  273. begin
  274.   Rect.X1 := 0;
  275.   Rect.Y1 := 0;
  276.   if Self is TGUIBounds then begin
  277.     Rect.X2 := TGUIBounds(Self).PxWidth;
  278.     Rect.Y2 := TGUIBounds(Self).PxHeight;
  279.   end else begin
  280.     Rect.X2 := Screen.Width;
  281.     Rect.Y2 := Screen.Height;
  282.   end;
  283.   Cur := nil;
  284.   while FindNextChildInclDummy(Cur) do if (Cur is TGUIBounds) then TGUIBounds(Cur).CalcBounds(Rect);
  285. end;
  286. constructor TBaseGUIItem.Create(AManager: TItemsManager);
  287. begin
  288.   inherited;
  289.   if AggregatedClass <> nil then begin
  290.     AggregatedItem := AggregatedClass.Create(AManager);
  291.     SendMessage(TAggregateMsg.Create(Self), AggregatedItem, [mfRecipient]);
  292.   end;
  293. end;
  294. destructor TBaseGUIItem.Destroy;
  295. begin
  296.   if Assigned(AggregatedItem) then FreeAndNil(AggregatedItem);
  297.   if Assigned(DefaultModel) then FreeAndNil(DefaultModel);
  298.   inherited;
  299. end;
  300. procedure TBaseGUIItem.HandleMessage(const Msg: TMessage);
  301. begin
  302.   if Assigned(AggregatedItem) then AggregatedItem.HandleMessage(Msg);
  303.   inherited;
  304. end;
  305. function TBaseGUIItem.GUIHandleMessage(const Msg: TMessage): Boolean;
  306.   procedure HandleFor(Item: TItem);
  307.   var i: Integer;
  308.   begin
  309.     Result := True;
  310.     i := Item.TotalChilds-1;
  311.     while (i >= 0) {and Result} do begin
  312.       if isItemVisibleAndEnabled(Item.Childs[i]) then
  313.         TBaseGUIItem(Item.Childs[i]).GUIHandleMessage(Msg) else
  314.           if Item.Childs[i] is TDummyItem then HandleFor(Item.Childs[i]);
  315.       Dec(i);
  316.     end;
  317.   end;
  318. begin
  319.   HandleFor(Self);
  320. end;
  321. procedure TBaseGUIItem.ReturnMessage(const Msg: TMessage);
  322. begin
  323. end;
  324. procedure TBaseGUIItem.AddProperties(const Result: Props.TProperties);
  325. var Props: TProperties; 
  326. begin
  327.   inherited;
  328.   Props := TProperties.Create;
  329.   if AggregatedItem <> nil then begin
  330.     AggregatedItem.AddProperties(Props);
  331.     Result.Merge(Props, False);
  332.   end;
  333.   if Assigned(Model) then begin
  334.     Props.Clear;
  335.     Model.GetProperties(Props);
  336.     Result.Merge(Props, False);
  337.   end;
  338.   FreeAndNil(Props);
  339. end;
  340. procedure TBaseGUIItem.SetProperties(Properties: Props.TProperties);
  341. begin
  342.   inherited;
  343.   if Assigned(AggregatedItem) then AggregatedItem.SetProperties(Properties);
  344.   if Assigned(Model)          then Model.SetProperties(Properties);
  345. end;
  346. { TGUIRootItem }
  347. procedure TGUIRootItem.SetFocusedItem(const Item: TGUIItem);
  348. var OPushed: Boolean;
  349. begin
  350.   if FFocusedItem = Item then Exit;
  351.   if not Item.CanBeFocused then Exit;                             // The item can't be focused
  352.   if Assigned(FFocusedItem) then with FFocusedItem do begin
  353.     FFocused := False;
  354.     OPushed  := Pushed;
  355.     Pushed   := False;
  356.     UpdateVisualParameters;
  357.   end else OPushed := False;
  358.   FFocusedItem          := Item;
  359.   FFocusedItem.FFocused := True;
  360.   FFocusedItem.Pushed   := OPushed;
  361.   FFocusedItem.UpdateVisualParameters;
  362. end;
  363. constructor TGUIRootItem.Create(AManager: TItemsManager);
  364. begin
  365.   inherited;
  366.   KeyEnter  := IK_RETURN;
  367.   KeyEscape := IK_ESCAPE;
  368.   KeyUp     := IK_UP;
  369.   KeyDown   := IK_DOWN;
  370.   KeyLeft   := IK_LEFT;
  371.   KeyRight  := IK_RIGHT;
  372. end;
  373. procedure TGUIRootItem.HandleMessage(const Msg: TMessage);
  374. var i, Index, ind: Integer;
  375.   function GetIndexInParent(Item: TItem): Integer;
  376.   begin
  377.     Result := -1;
  378.     if (Item = nil) or (Item.Parent = nil) then Exit;
  379.     for Result := 0 to Item.Parent.TotalChilds-1 do 
  380.       if Item.Parent.Childs[Result] = Item then Exit;
  381.     Result := -1;
  382.   end;
  383. begin
  384.   if (Msg is TWindowResizeMsg) then SendMessage(Msg, nil, [mfChilds]) else if (Msg is TMouseMsg) then begin
  385.     GUIHandleMessage(Msg);
  386.   end else if (FFocusedItem <> nil) and (Msg is TKeyboardMsg) then begin             // Forward a keyboard message to the focused item
  387.     FFocusedItem.GUIHandleMessage(Msg);
  388.   end else if (Msg is TGUIMessage) then with TGUIMessage(Msg) do begin
  389.     if (Msg.ClassType = TGUIFocusNext) or (Msg.ClassType = TGUIFocusPrev) then begin
  390.       Index := GetIndexInParent(Item);
  391.       ind   := Index;
  392.       for i := 0 to Item.Parent.TotalChilds-1 do begin
  393.         ind := (ind + Ord(Msg.ClassType = TGUIFocusNext) - Ord(Msg.ClassType = TGUIFocusPrev) + Item.Parent.TotalChilds) mod Item.Parent.TotalChilds;
  394.         if (ind <> Index) and (Item.Parent.Childs[ind] is TGUIItem) and ((Item.Parent.Childs[ind] as TGUIItem).CanBeFocused) then begin
  395.           FocusedItem := (Item.Parent.Childs[ind] as TGUIItem);
  396.           Break;
  397.         end;
  398.       end;
  399.     end;
  400.   end else inherited;
  401. end;
  402. procedure TGUIRootItem.ReturnMessage(const Msg: TMessage);
  403. begin
  404.   SendMessage(Msg, nil, [mfCore]);             // Forward the message to the application
  405. end;
  406. function TGUIRootItem.IsWithinGUI(AX, AY: Single): Boolean;
  407. function CheckItem(AItem: TItem): Boolean;
  408. var i: Integer;
  409. begin
  410.   Result := False;
  411.   i := AItem.TotalChilds-1;
  412.   while (i >= 0) and not Result do begin
  413.     if not (AItem.Childs[i] is TGUIItem) then
  414.       Result := CheckItem(AItem.Childs[i]) else
  415.         Result := isItemVisibleAndEnabled(AItem.Childs[i]) and (TGUIItem(AItem.Childs[i]).IsWithin(AX, AY));
  416.     Dec(i);
  417.   end;
  418.   Result := Result or (i >= 0);
  419. end;
  420. begin
  421.   Result := CheckItem(Self);
  422. end;
  423. procedure TGUIRootItem.Draw;
  424. begin
  425.   Screen.CurrentZ := ClearingZ;                                   // ToDo: Eliminate it
  426. end;
  427. procedure TGUIRootItem.OnSceneAdd;
  428. begin
  429.   inherited;
  430.   SendMessage(TSubsystemMsg.Create(saConnect, Self), nil, [mfCore]);
  431. end;
  432. procedure TGUIRootItem.OnSceneRemove;
  433. begin
  434.   inherited;
  435.   SendMessage(TSubsystemMsg.Create(saDisconnect, Self), nil, [mfCore]);
  436. end;
  437. { TGUIBounds }
  438. procedure TGUIBounds.InvalidateTransform;
  439. procedure InvalidateChilds(Item: TItem);
  440. var i: Integer;
  441. begin
  442.   for i := 0 to Item.TotalChilds-1 do begin
  443.     if (Item.Childs[i] is TGUIBounds) then begin
  444.       TGUIBounds(Item.Childs[i]).TransformValid := False;
  445.       InvalidateChilds(Item.Childs[i]);
  446.     end;
  447.     if (Item.Childs[i] is TDummyItem) then InvalidateChilds(Item.Childs[i]);
  448.   end;
  449. end;
  450. begin
  451.   if not TransformValid then Exit;
  452.   TransformValid := False;
  453.   InvalidateChilds(Self);
  454. end;
  455. procedure TGUIBounds.SetHOrigin(const Value: THOrigin);
  456. begin
  457.   FHOrigin := Value;
  458.   Realign;
  459. end;
  460. procedure TGUIBounds.SetVOrigin(const Value: TVOrigin);
  461. begin
  462.   FVOrigin := Value;
  463.   Realign;
  464. end;
  465. /// Recalculates control's bounds according to layout parameters
  466. procedure TGUIBounds.Realign;
  467. var ParItem: TItem;
  468. begin
  469.   if DisableRealign then Exit;
  470.   ParItem := GetNonGUIDummyParent;
  471.   if ParItem is TBaseGUIItem then TBaseGUIItem(ParItem).RealignChilds(0);
  472. end;
  473. procedure TGUIBounds.CalcBounds(var ARect: BaseTypes.TArea);
  474. var OfsX, OfsY, ParW, ParH, NewPxW, NewPxH: Single; Msg: TWindowResizeMsg;
  475. begin
  476. //  ObtainParentDimensions(ParW, ParH);
  477.   OfsX := ARect.X1;
  478.   OfsY := ARect.Y1;
  479.   ParW := ARect.X2 - ARect.X1;
  480.   ParH := ARect.Y2 - ARect.Y1;
  481.   AlignRect := ARect;
  482.   if pvWidth  in FPercentValues then NewPxW  := ParW/100 * FWidth  else NewPxW := FWidth;
  483.   if pvHeight in FPercentValues then NewPxH  := ParH/100 * FHeight else NewPxH := FHeight;
  484.   case FAlign of
  485.     alNone, alAbsolute: begin
  486.       if FAlign = alAbsolute then begin                      // Use original rect
  487.         OfsX := 0; OfsY := 0;
  488.         ObtainParentDimensions(ParW, ParH);
  489.         AlignRect.X1 := 0;
  490.         AlignRect.Y1 := 0;
  491.         AlignRect.X2 := ParW;
  492.         AlignRect.Y2 := ParH;
  493.       end;
  494.       if pvLeft in FPercentValues then FPxX := OfsX + ParW/100 * FX else FPxX := OfsX + FX;
  495.       if pvTop  in FPercentValues then FPxY := OfsY + ParH/100 * FY else FPxY := OfsY + FY;
  496.       case HOrigin of
  497.         hoCenter: FPxX := FPxX + Round((ParW - NewPxW) * 0.5);
  498.         hoRight:  FPxX := FPxX + ParW - NewPxW;
  499.       end;
  500.       case VOrigin of
  501.         voCenter: FPxY := FPxY + Round((ParH - NewPxH) * 0.5);
  502.         voBottom: FPxY := FPxY + ParH - NewPxH;
  503.       end;
  504.     end;
  505.     alLeft: begin
  506.       FPxX   := OfsX + FX;
  507.       FPxY   := OfsY + FY;
  508.       NewPxH := ParH - FY*2;
  509.       ARect.X1 := ARect.X1 + NewPxW + FX;
  510.     end;
  511.     alTop: begin
  512.       FPxX   := OfsX + FX;
  513.       FPxY   := OfsY + FY;
  514.       NewPxW := ParW - FX*2;
  515.       ARect.Y1 := ARect.Y1 + NewPxH + FY;
  516.     end;
  517.     alRight: begin
  518.       FPxY   := OfsY + FY;
  519.       FPxX   := OfsX + ParW - NewPxW + FX;
  520.       NewPxH := ParH - FY*2;
  521.       ARect.X2 := ARect.X2 - NewPxW + FX;
  522.     end;
  523.     alBottom: begin
  524.       FPxX   := OfsX + FX;
  525.       FPxY   := OfsY + ParH - NewPxH + FY;
  526.       NewPxW := ParW - FX*2;
  527.       ARect.Y2 := ARect.Y2 - NewPxH + FY;
  528.     end;
  529.     alClient: begin
  530.       FPxX   := OfsX + FX;
  531.       FPxY   := OfsY + FY;
  532.       NewPxW := ParW - FX*2;
  533.       NewPxH := ParH - FY*2;
  534.       ARect.X1 := ARect.X2;
  535.       ARect.Y1 := ARect.Y2;
  536.     end;
  537.   end;
  538.   if (FPxWidth <> NewPxW) or (FPxHeight <> NewPxH) then
  539.     Msg := TWindowResizeMsg.Create(FPxWidth, FPxHeight, NewPxW, NewPxH) else
  540.       Msg := nil;
  541.   FPxWidth  := NewPxW;
  542.   FPxHeight := NewPxH;
  543.   CalcClientArea;
  544.   if Assigned(Msg) then SendMessage(Msg, nil, [mfChilds]);
  545.   InvalidateTransform;
  546. end;
  547. procedure TGUIBounds.ApplyAnchors(ParentDeltaWidth, ParentDeltaHeight: Single);
  548. var NewLeft, NewTop, NewWidth, NewHeight: Single;
  549. begin
  550.   if Align <> alNone then Exit;
  551.   NewLeft   := PxX;
  552.   NewTop    := PxY;
  553.   NewWidth  := PxWidth;
  554.   NewHeight := PxHeight;
  555.   DisableRealign := True;                                            // Avoid redundant realign
  556.   
  557.   if not (pvLeft in FPercentValues) then begin                       // Calculate new left bound
  558.     if not (aLeft in FAnchors) then
  559.       if aRight in FAnchors then
  560.         NewLeft := NewLeft + ParentDeltaWidth else
  561.           NewLeft := NewLeft + ParentDeltaWidth*0.5;
  562.   end;
  563.   if not (pvTop in FPercentValues) then begin                        // Calculate new top bound
  564.     if not (aTop in FAnchors) then
  565.       if aBottom in FAnchors then
  566.         NewTop := NewTop + ParentDeltaHeight else
  567.           NewTop := NewTop + ParentDeltaHeight*0.5;
  568.   end;
  569.   if not (pvWidth in FPercentValues) then begin                      // Calculate new width
  570.     if aRight in FAnchors then
  571.       if aLeft in FAnchors then
  572.         NewWidth := NewWidth + ParentDeltaWidth;
  573.   end;
  574.   if not (pvHeight in FPercentValues) then begin                     // Calculate new height
  575.     if aBottom in FAnchors then
  576.       if aTop in FAnchors then
  577.         NewHeight := NewHeight + ParentDeltaHeight;
  578.   end;
  579.   PxX      := NewLeft;
  580.   PxY      := NewTop;
  581.   PxWidth  := NewWidth;
  582.   pxHeight := NewHeight;
  583.   DisableRealign := False;
  584.   Realign;
  585. end;
  586. procedure TGUIBounds.CalcClientArea;
  587. begin
  588.   FClientX      := Border;
  589.   FClientY      := Border;
  590.   FClientWidth  := PxWidth  - Border;
  591.   FClientHeight := PxHeight - Border;
  592.   InvalidateTransform;
  593. end;
  594. procedure TGUIBounds.SetWidth(const Value: Single);
  595. var NewWidth: Single;
  596. begin
  597.   NewWidth := MinS(MaxS(Value, FConstraints.MinWidth), FConstraints.MaxWidth);
  598.   if FWidth = NewWidth then Exit;
  599.   FWidth := NewWidth;
  600.   Realign;
  601. end;
  602. procedure TGUIBounds.SetHeight(const Value: Single);
  603. var NewHeight: Single;
  604. begin
  605.   NewHeight := MinS(MaxS(Value, FConstraints.MinHeight), FConstraints.MaxHeight);
  606.   if FHeight = NewHeight then Exit;
  607.   FHeight := NewHeight;
  608.   Realign;
  609. end;
  610. procedure TGUIBounds.SetX(const Value: Single);
  611. begin
  612.   FX := Value;
  613.   Realign;
  614. //  InvalidateTransform;
  615. end;
  616. procedure TGUIBounds.SetY(const Value: Single);
  617. begin
  618.   FY := Value;
  619.   Realign;
  620. //  InvalidateTransform;
  621. end;
  622. procedure TGUIBounds.SetPxX(Value: Single);
  623. begin
  624.   case HOrigin of
  625.     hoLeft:   Value := Value - AlignRect.X1;
  626.     hoCenter: Value := Value - Round((AlignRect.X1 + AlignRect.X2 - PxWidth) * 0.5);
  627.     hoRight:  Value := Value - AlignRect.X2 + PxWidth;
  628.   end;
  629.   if pvLeft in FPercentValues then Value := Value/(AlignRect.X2 - AlignRect.X1)*100;
  630.   X := Value;
  631. end;
  632. procedure TGUIBounds.SetPxY(Value: Single);
  633. begin
  634.   case VOrigin of
  635.     voTop:    Value := Value - AlignRect.Y1;
  636.     voCenter: Value := Value - Round((AlignRect.Y1 + AlignRect.Y2 - PxHeight) * 0.5);
  637.     voBottom: Value := Value - AlignRect.Y2 + PxHeight;
  638.   end;
  639.   if pvTop in FPercentValues then Value := Value/(AlignRect.Y2 - AlignRect.Y1)*100;
  640.   Y := Value;
  641. end;
  642. procedure TGUIBounds.SetPxWidth(Value: Single);
  643. begin
  644.   if pvWidth in FPercentValues then Value := Value/(AlignRect.X2-AlignRect.X1)*100;
  645.   Width := Value;
  646. end;
  647. procedure TGUIBounds.SetPxHeight(Value: Single);
  648. begin
  649.   if pvHeight in FPercentValues then Value := Value/(AlignRect.Y2-AlignRect.Y1)*100;
  650.   Height := Value;
  651. end;
  652. procedure TGUIBounds.SetAngle(const Value: Single);
  653. begin
  654.   FAngle := Value;
  655.   Realign;
  656. //  InvalidateTransform;
  657. end;
  658. procedure TGUIBounds.SetAlign(const Value: TAlign);
  659. begin
  660.   FAlign := Value;
  661.   Realign;
  662. end;
  663. procedure TGUIBounds.SetPercentValues(const Value: BaseTypes.TSet32);
  664. begin
  665.   FPercentValues := Value;
  666.   Realign;
  667. end;
  668. procedure TGUIBounds.SetBorder(const Value: Integer);
  669. begin
  670.   FBorder := Value;
  671.   CalcClientArea;
  672. end;
  673. function TGUIBounds.GetTransform: TMatrix4s;
  674. begin
  675.   if not TransformValid then ComputeTransform;
  676.   Result := FTransform;
  677. end;
  678. function TGUIBounds.GetLocalViewport: BaseGraph.TViewport;
  679. begin
  680.   if not TransformValid then ComputeTransform;
  681.   Result := FLocalViewport;
  682. end;
  683. procedure TGUIBounds.ComputeTransform;
  684. var ClX, ClY, ClW, ClH, SX, SY: Single; ParItem: TItem; ParBounds: TGUIBounds; V: TVector4s;
  685. begin
  686.   if TransformValid then Exit;
  687.   TransformValid := True;
  688.   ParItem := GetNonGUIDummyParent;
  689.   ZRotationMatrix4s(FTransform, FAngle/180*pi);
  690. //  FTransform := MulMatrix4s(TranslationMatrix4s(FX, FY, 0), FTransform);
  691.   FTransform.M[3, 0] := PxX;
  692.   FTransform.M[3, 1] := PxY;
  693. //  MulMatrix4s(TransMat, ScaleMatrix4s(FScale.X, FScale.Y, FScale.Z), TransMat);
  694.   if ParItem is TGUIBounds then begin
  695.     ParBounds := TGUIBounds(ParItem);
  696.     FTransform.M[3, 0] := FTransform.M[3, 0] - ParBounds.ScrollX;
  697.     FTransform.M[3, 1] := FTransform.M[3, 1] - ParBounds.ScrollY;
  698.     FTransform := MulMatrix4s(FTransform, ParBounds.Transform);
  699. //    W := TGUIBounds(ParItem).PXWidth; H := TGUIBounds(ParItem).PxHeight;
  700.     ClX := ParBounds.ClientX;
  701.     ClY := ParBounds.ClientY;
  702.     ClW := ParBounds.ClientWidth;
  703.     ClH := ParBounds.ClientHeight;
  704.     SX  := ParBounds.ScrollX;
  705.     SY  := ParBounds.ScrollY;
  706.   end else begin
  707.     ParBounds := nil;
  708.     ClX := 0;
  709.     ClY := 0;
  710.     ClW := Screen.Width;
  711.     ClH := Screen.Height;
  712.     SX  := 0;
  713.     SY  := 0;
  714.   end;
  715.   FLocalViewport.Left   := ClX - PxX + SX;
  716.   FLocalViewport.Top    := ClY - PxY + SY;
  717.   FLocalViewport.Right  := ClW - PxX;
  718.   FLocalViewport.Bottom := ClH - PxY;
  719.   if ParBounds <> nil then begin                                  // Clip the viewport against parent's viewport
  720.     FLocalViewport.Left   := MaxS(FLocalViewport.Left,   ParBounds.GetLocalViewport.Left   - PxX);
  721.     FLocalViewport.Top    := MaxS(FLocalViewport.Top,    ParBounds.GetLocalViewport.Top    - PxY);
  722.     FLocalViewport.Right  := MinS(FLocalViewport.Right,  ParBounds.GetLocalViewport.Right  - PxX);
  723.     FLocalViewport.Bottom := MinS(FLocalViewport.Bottom, ParBounds.GetLocalViewport.Bottom - PxY);
  724.   end;
  725.   V := GetVector4s(0, 0, 0, 1);
  726.   V := Transform4Vector4s(FTransform, V);
  727. end;
  728.                         { *** }
  729. constructor TGUIBounds.Create(AManager: TItemsManager); 
  730. begin
  731.   inherited;
  732.   FConstraints.MinWidth  := 0;
  733.   FConstraints.MinHeight := 0;
  734.   FConstraints.MaxWidth  := 10000;
  735.   FConstraints.MaxHeight := 10000;
  736.   FX := 0; FY := 0;
  737.   FAngle := 0;
  738.   Width  := 96;
  739.   Height := 24;
  740.   FAnchors := [aLeft, aTop];
  741.   FHOrigin := hoLeft;
  742.   FVOrigin := voTop;
  743.   FBorder  := 0;
  744.   FScrollX := 0;
  745.   FPercentValues := [];
  746. end;
  747. procedure TGUIBounds.HandleMessage(const Msg: TMessage);
  748. begin
  749.   inherited;
  750.   if (Msg is TWindowResizeMsg) then with TWindowResizeMsg(Msg) do
  751.     ApplyAnchors(NewWidth - OldWidth, NewHeight - OldHeight);
  752. end;
  753. procedure TGUIBounds.AddProperties(const Result: Props.TProperties);
  754. begin
  755.   inherited;
  756.   if not Assigned(Result) then Exit;
  757.   Result.AddSetProperty('LayoutValues in percent', FPercentValues, [], BoundValuesEnum, '');
  758.   Result.AddEnumerated('LayoutAlign',             [], Ord(FAlign),   AlignEnum);
  759.   Result.AddEnumerated('LayoutHorizontal origin', [], Ord(FHOrigin), HOriginEnum);
  760.   Result.AddEnumerated('LayoutVertical origin',   [], Ord(FVOrigin), VOriginEnum);
  761.   Result.Add('LayoutMin width',  vtSingle, [], FloatToStr(FConstraints.MinWidth),  '');
  762.   Result.Add('LayoutMin height', vtSingle, [], FloatToStr(FConstraints.MinHeight), '');
  763.   Result.Add('LayoutMax width',  vtSingle, [], FloatToStr(FConstraints.MaxWidth),  '');
  764.   Result.Add('LayoutMax height', vtSingle, [], FloatToStr(FConstraints.MaxHeight), '');
  765.   Result.Add('LayoutX',      vtSingle, [], FloatToStr(FX),      '');
  766.   Result.Add('LayoutY',      vtSingle, [], FloatToStr(FY),      '');
  767.   Result.Add('LayoutWidth',  vtSingle, [], FloatToStr(FWidth),  '');
  768.   Result.Add('LayoutHeight', vtSingle, [], FloatToStr(FHeight), '');
  769.   Result.Add('LayoutIn pixelsX',      vtSingle, [poDerivative], FloatToStr(PxX),      '');
  770.   Result.Add('LayoutIn pixelsY',      vtSingle, [poDerivative], FloatToStr(PxY),      '');
  771.   Result.Add('LayoutIn pixelsWidth',  vtSingle, [poDerivative], FloatToStr(PxWidth),  '');
  772.   Result.Add('LayoutIn pixelsHeight', vtSingle, [poDerivative], FloatToStr(PxHeight), '');
  773.   Result.Add('LayoutAngle', vtSingle, [], FloatToStr(FAngle), '');
  774.   Result.Add('LayoutAnchorsLeft',   vtBoolean, [], OnOffStr[aLeft   in FAnchors], '');
  775.   Result.Add('LayoutAnchorsTop',    vtBoolean, [], OnOffStr[aTop    in FAnchors], '');
  776.   Result.Add('LayoutAnchorsRight',  vtBoolean, [], OnOffStr[aRight  in FAnchors], '');
  777.   Result.Add('LayoutAnchorsBottom', vtBoolean, [], OnOffStr[aBottom in FAnchors], '');
  778.   //  Result.Add('LayoutWidth% by parent''s',  vtBoolean, [], OnOffStr[rvWidth  in FRelativeValues], '');
  779. //  Result.Add('LayoutHeight% by parent''s', vtBoolean, [], OnOffStr[rvHeight in FRelativeValues], '');
  780. end;
  781. procedure TGUIBounds.SetProperties(Properties: Props.TProperties);
  782. begin
  783.   inherited;
  784.   if Properties.SetSetProperty('LayoutValues in percent', FPercentValues, BoundValuesEnum) then PercentValues := FPercentValues;
  785.   if Properties.Valid('LayoutAlign')             then Align   := TAlign(Properties.GetAsInteger('LayoutAlign'));
  786.   if Properties.Valid('LayoutHorizontal origin') then HOrigin := THOrigin(Properties.GetAsInteger('LayoutHorizontal origin'));
  787.   if Properties.Valid('LayoutVertical origin')   then VOrigin := TVOrigin(Properties.GetAsInteger('LayoutVertical origin'));
  788.   if Properties.Valid('LayoutMin width')  then FConstraints.MinWidth  := StrToFloatDef(Properties['LayoutMin width'],  0);
  789.   if Properties.Valid('LayoutMin height') then FConstraints.MinHeight := StrToFloatDef(Properties['LayoutMin height'], 0);
  790.   if Properties.Valid('LayoutMax width')  then FConstraints.MaxWidth  := StrToFloatDef(Properties['LayoutMax width'],  0);
  791.   if Properties.Valid('LayoutMax height') then FConstraints.MaxHeight := StrToFloatDef(Properties['LayoutMax height'], 0);
  792.   if Properties.Valid('LayoutIn pixelsX')      then PxX      := StrToFloatDef(Properties['LayoutIn pixelsX'],      0);
  793.   if Properties.Valid('LayoutIn pixelsY')      then PxY      := StrToFloatDef(Properties['LayoutIn pixelsY'],      0);
  794.   if Properties.Valid('LayoutIn pixelsWidth')  then PxWidth  := StrToFloatDef(Properties['LayoutIn pixelsWidth'],  80);
  795.   if Properties.Valid('LayoutIn pixelsHeight') then PxHeight := StrToFloatDef(Properties['LayoutIn pixelsHeight'], 14);
  796.   if Properties.Valid('LayoutX')      then X      := StrToFloatDef(Properties['LayoutX'],      0);
  797.   if Properties.Valid('LayoutY')      then Y      := StrToFloatDef(Properties['LayoutY'],      0);
  798.   if Properties.Valid('LayoutWidth')  then Width  := StrToFloatDef(Properties['LayoutWidth'],  80);
  799.   if Properties.Valid('LayoutHeight') then Height := StrToFloatDef(Properties['LayoutHeight'], 14);
  800.   if Properties.Valid('LayoutAngle') then Angle := StrToFloatDef(Properties['LayoutAngle'], 0);
  801.   if Properties.Valid('LayoutAnchorsLeft')   then if Properties.GetAsInteger('LayoutAnchorsLeft')   > 0 then
  802.     FAnchors := FAnchors + [aLeft]   else FAnchors := FAnchors - [aLeft];
  803.   if Properties.Valid('LayoutAnchorsTop')    then if Properties.GetAsInteger('LayoutAnchorsTop')    > 0 then
  804.     FAnchors := FAnchors + [aTop]    else FAnchors := FAnchors - [aTop];
  805.   if Properties.Valid('LayoutAnchorsRight')  then if Properties.GetAsInteger('LayoutAnchorsRight')  > 0 then
  806.     FAnchors := FAnchors + [aRight]  else FAnchors := FAnchors - [aRight];
  807.   if Properties.Valid('LayoutAnchorsBottom') then if Properties.GetAsInteger('LayoutAnchorsBottom') > 0 then
  808.     FAnchors := FAnchors + [aBottom] else FAnchors := FAnchors - [aBottom];
  809.   
  810. {  if Properties.Valid('LayoutWidth% by parent''s')  then if Properties.GetAsInteger('LayoutWidth% by parent''s')  > 0 then
  811.     FRelativeValues := FRelativeValues + [rvWidth]  else FRelativeValues := FRelativeValues - [rvWidth];
  812.   if Properties.Valid('LayoutHeight% by parent''s') then if Properties.GetAsInteger('LayoutHeight% by parent''s') > 0 then
  813.     FRelativeValues := FRelativeValues + [rvHeight] else FRelativeValues := FRelativeValues - [rvHeight];}
  814. end;
  815. function TGUIBounds.IsWithin(AX, AY: Single): Boolean;
  816. begin
  817. {  TX := 0; TY := 0;
  818.   ClientToScreen(TX, TY);
  819.   Result := (AX > TX) and (AY > TY) and (AX < TX + Width) and (AY < TY + Height);}
  820.   ScreenToClient(AX, AY);
  821.   Result := (AX > 0) and (AY > 0) and (AX < PxWidth) and (AY < PxHeight);
  822. end;
  823. procedure TGUIBounds.ClientToScreen(var AX, AY: Single);
  824. var V: TVector4s;                       // ToDo -cOptimization: Optimize (eliminate) it.
  825. begin
  826.   V := GetVector4s(AX, AY, 0, 1);
  827.   V := Transform4Vector4s(Transform, V);
  828.   AX := V.X; AY := V.Y;
  829. end;
  830. procedure TGUIBounds.ScreenToClient(var AX, AY: Single);
  831. var V, v1, v2: TVector4s;                       // ToDo -cOptimization: Optimize (eliminate) it.
  832. m1, m2: TMatrix4s;
  833. begin
  834.   V := GetVector4s(AX, AY, 0, 1);
  835.   m1 := InvertMatrix4s(Transform);
  836.   m2 := InvertAffineMatrix4s(Transform);
  837.   V1 := Transform4Vector4s(m1, V);
  838.   V2 := Transform4Vector4s(m2, V);
  839.   if not EqualsVector4s(v1, v2) then begin
  840.     m1 := InvertMatrix4s(Transform);
  841.     m2 := InvertAffineMatrix4s(Transform);
  842.     V.X := 7;
  843.   end;
  844.   V := V1;
  845. //  V.X := V.X - Transform._41;
  846. //  V.Y := V.Y - Transform._42;
  847.   AX := V.X; AY := V.Y;
  848. end;
  849. { TGUIItem }
  850. function TGUIItem.GetAbility: Boolean;
  851. begin
  852.   if Assigned(IsEnabledDelegate) then
  853.     Result := IsEnabledDelegate(Self) else
  854.       Result := isProcessing in State;
  855. end;
  856. procedure TGUIItem.SetAbility(const Value: Boolean);
  857. begin
  858.   if Value then State := FState + [isProcessing] else State := FState - [isProcessing];
  859. end;
  860. function TGUIItem.GetVisibility: Boolean;
  861. begin
  862.   if Assigned(IsVisibleDelegate) then
  863.     Result := IsVisibleDelegate(Self) else
  864.       Result := isVisible in State;
  865. end;
  866. procedure TGUIItem.SetVisibility(const Value: Boolean);
  867. begin
  868.   if Value then State := FState + [isVisible] else State := FState - [isVisible];
  869. end;
  870. function TGUIItem.GetStatesSource: TGUIItem;
  871. begin
  872.   Result := Self;
  873.   while Result.ParentState and (GetNonGUIDummyParent is TGUIItem) do Result := TGUIItem(GetNonGUIDummyParent);
  874. end;
  875. procedure TGUIItem.SetFocused(const Value: Boolean);
  876. begin
  877.   if not CanBeFocused then Exit;
  878.   if GetGUIRoot <> nil then
  879.     if Value then GetGUIRoot.FocusedItem := Self else GetGUIRoot.FocusedItem := nil;
  880. end;
  881. function TGUIItem.GetGUIRoot: TGUIRootItem;
  882. var Item: TItem;
  883. begin
  884.   Item := Parent;
  885.   while Assigned(Item) and not (Item is TGUIRootItem) do Item := Item.Parent;
  886.   Result := Item as TGUIRootItem;
  887. {
  888.   Result := nil;
  889.   Item := Parent;
  890.   while Item <> nil do begin
  891.     if Item is TGUIRootItem then begin
  892.       Result := TGUIRootItem(Item);
  893.       Exit;
  894.     end;
  895.     Item := Item.Parent;
  896.   end;}
  897. end;
  898. function TGUIItem.CanBeFocused: Boolean;
  899. begin
  900.   Result := isVisibleAndEnabled and CanFocus;
  901. end;
  902.                         { *** }
  903. constructor TGUIItem.Create(AManager: TItemsManager);
  904. begin
  905.   inherited;
  906.   NormalColor.C   := $80C0C0C0;
  907.   PushedColor.C   := $FFFFFFFF;
  908.   FocusedColor.C  := $FF80FFFF;
  909.   HoverColor.C    := $FFFFFFFF;
  910.   DisabledColor.C := $FF808080;
  911.   Color           := NormalColor;
  912. end;
  913. procedure TGUIItem.HandleMessage(const Msg: TMessage);
  914. begin
  915.   inherited;
  916.   if Msg.ClassType = TGUIStateChangeMsg then UpdateVisualParameters else
  917.     if Msg.ClassType = TWindowResizeMsg then Realign;
  918.     //    if not (isProcessing in OldValue) and (isProcessing in NewValue) then SetControlState(csNormal);
  919.     //    if (isProcessing in OldValue) and not (isProcessing in NewValue) then SetControlState(csDisabled);
  920.   
  921. end;
  922. function TGUIItem.GUIHandleMessage(const Msg: TMessage): Boolean;
  923. begin
  924.   Result := inherited GUIHandleMessage(Msg);
  925.   if not Result then Exit;
  926.   if Msg is TInputMessage then begin
  927.     if ParentState then begin
  928.       Result := False; Exit;
  929.     end;
  930.     if Msg.ClassType = TMouseDownMsg then with TMouseDownMsg(Msg) do begin
  931.       if (Button = IK_MOUSELEFT) and Hover then begin
  932.         ReturnMessage(TGUIDownMsg.Create(Self));
  933.         if CanBeFocused then Focused := True;
  934.         Pushed := True;
  935.         UpdateVisualParameters;
  936.       end;
  937.     end else if Msg.ClassType = TMouseUpMsg then with TMouseUpMsg(Msg) do begin
  938.       if (Button = IK_MOUSELEFT) then begin
  939.         if Pushed and Hover then HandleClick(Button, X, Y);
  940.         Pushed := False;
  941.         UpdateVisualParameters;
  942.       end;
  943.     end else if (Msg.ClassType = TMouseMoveMsg) then with TMouseMoveMsg(Msg) do begin
  944.       if IsWithin(X, Y) then begin
  945.         Hover := True;
  946.         X := -20000;                                   // Move the mouse out of any control
  947.       end else Hover := False;
  948.       UpdateVisualParameters;
  949.     end;
  950. // Keyboard handle for focused controls
  951.     if Focused then begin
  952.       if Msg.ClassType = TKeyClickMsg then with TKeyClickMsg(Msg) do begin
  953.         if Key = GetGUIRoot.KeyDown then SendMessage(TGUIFocusNext.Create(Self), GetGUIRoot, [mfRecipient]);
  954.         if Key = GetGUIRoot.KeyUp   then SendMessage(TGUIFocusPrev.Create(Self), GetGUIRoot, [mfRecipient]);
  955.       end;
  956.       if Msg.ClassType = TKeyDownMsg then with TKeyDownMsg(Msg) do
  957.         if Key = GetGUIRoot.KeyEnter then begin Pushed := True; UpdateVisualParameters; end;
  958.       if Msg.ClassType = TKeyUpMsg then with TKeyUpMsg(Msg) do
  959.         if Key = GetGUIRoot.KeyEnter then begin
  960.           if Pushed then HandleClick(Key, 0, 0);
  961.           Pushed := False; UpdateVisualParameters;
  962.         end;
  963.     end;    
  964.   end;
  965. end;
  966. procedure TGUIItem.Draw;
  967. begin
  968.   Screen.Transform := Transform;
  969.   Screen.Viewport := GetLocalViewport;
  970. end;
  971. procedure TGUIItem.AddProperties(const Result: Props.TProperties);
  972. begin
  973.   inherited;
  974.   if not Assigned(Result) then Exit;
  975.   AddColor4sProperty(Result, 'Color',          ColorTo4S(NormalColor));
  976.   AddColor4sProperty(Result, 'ColorHover',    ColorTo4S(HoverColor));
  977.   AddColor4sProperty(Result, 'ColorPushed',   ColorTo4S(PushedColor));
  978.   AddColor4sProperty(Result, 'ColorFocused',  ColorTo4S(FocusedColor));
  979.   AddColor4sProperty(Result, 'ColorDisabled', ColorTo4S(DisabledColor));
  980.   Result.Add('Enabled', vtBoolean,             [], OnOffStr[isProcessing in State], '');
  981.   Result.Add('Use parent''s state', vtBoolean, [], OnOffStr[ParentState], '');
  982.   Result.Add('Can be focused', vtBoolean,      [], OnOffStr[CanFocus], '');
  983. end;
  984. procedure TGUIItem.SetProperties(Properties: Props.TProperties);
  985. begin
  986.   inherited;
  987.   SetColorProperty(Properties, 'Color',          NormalColor);
  988.   SetColorProperty(Properties, 'ColorHover',    HoverColor);
  989.   SetColorProperty(Properties, 'ColorPushed',   PushedColor);
  990.   SetColorProperty(Properties, 'ColorFocused',  FocusedColor);
  991.   SetColorProperty(Properties, 'ColorDisabled', DisabledColor);
  992.   Color := NormalColor;
  993.   if Properties.Valid('Enabled') then
  994.     Enabled := Properties.GetAsInteger('Enabled') > 0;
  995.   if Properties.Valid('Use parent''s state') then ParentState := Properties.GetAsInteger('Use parent''s state') > 0;
  996.   if Properties.Valid('Can be focused') then CanFocus := Properties.GetAsInteger('Can be focused') > 0;
  997.   UpdateVisualParameters;
  998. end;
  999. function TGUIItem.isVisibleAndEnabled: Boolean;
  1000. var Item: TItem;
  1001. begin
  1002.   Result := False;
  1003.   Item := Self;
  1004.   while Item <> nil do begin
  1005.     if (Item is TGUIItem) and (not TGUIItem(Item).Enabled or not TGUIItem(Item).Visible) then Exit;
  1006.     Item := Item.Parent;
  1007.   end;
  1008.   Result := True;
  1009. end;
  1010. procedure TGUIItem.HandleClick(Button, MX, MY: Integer);
  1011. begin
  1012. //  if (Button = IK_MOUSELEFT) or (Button = GetGUIRoot.KeyEnter) then
  1013.   ReturnMessage(TGUIClickMsg.Create(Self));
  1014. end;
  1015. procedure TGUIItem.UpdateVisualParameters;
  1016. begin
  1017.   if not GetStatesSource.Enabled then Color := DisabledColor else
  1018.     if GetStatesSource.Pushed then Color := PushedColor else
  1019.       if GetStatesSource.Hover then Color := HoverColor else
  1020.         if GetStatesSource.Focused then Color := FocusedColor else
  1021.           Color := NormalColor;
  1022.   SendMessage(TGUIStateChangeMsg.Create(Self), nil, [mfChilds]);
  1023. {$IFDEF LOGGING}
  1024. //  if FControlState = csHover then Log.Log('Hovered: "' + Name + '" of class ' + ClassName, lkInfo);
  1025. {$ENDIF}
  1026. end;
  1027. procedure TGUIItem.ReturnMessage(const Msg: TMessage);
  1028. var ParItem: TItem;
  1029. begin
  1030.   Assert(Msg is TGUIMessage, ClassName + '.ReturnMessage: Only GUI messages allowed');
  1031. //  if Msg is TGUIMessage then with TGUIMessage(Msg) do
  1032. //    if Item = nil then Item := Self as TGUIItem;                    // The message was generated by control Data object
  1033.   ParItem := GetNonGUIDummyParent;
  1034.   if (ParItem is TBaseGUIItem) then TBaseGUIItem(ParItem).ReturnMessage(Msg);
  1035. end;
  1036. procedure TGUIItem.SetState(const Value: TSet32);
  1037. begin
  1038.   inherited;
  1039.   UpdateVisualParameters;
  1040. end;
  1041. { TTextGUIItem }
  1042. procedure TTextGUIItem.ResolveLinks;
  1043. var FontRes: TItem;
  1044. begin
  1045.   if ResolveLink('Font', FontRes) then begin
  1046.     if not (FontRes is TFont) then
  1047.       Font := FontRes as TFont else
  1048.         Font := FontRes as TFont;
  1049.   end;
  1050. end;
  1051. function TTextGUIItem.GetSizeAdjustable: Boolean;
  1052. begin
  1053.   Result := not Colored;
  1054. end;
  1055. procedure TTextGUIItem.CalcClientArea;
  1056. begin
  1057.   inherited;
  1058.   if Colored and Assigned(Markup) then MarkUp.Invalidate;
  1059. end;
  1060. function TTextGUIItem.GetClearedText: string;
  1061. begin
  1062.   if Colored then begin
  1063.     if Markup = nil then Markup := TSimpleMarkup.Create;
  1064.     MarkUp.DefaultFont   := Font;
  1065.     MarkUp.DefaultWidth  := PxWidth;
  1066.     Markup.FormattedText := RText;
  1067.     Result := Markup.PureText;
  1068.   end else Result := RText;
  1069. end;
  1070. procedure TTextGUIItem.SetText(const AText: string);
  1071. var w, h: Single;
  1072. begin
  1073.   FText := AText; RText := FText;
  1074.   if (Font = nil) then Exit;
  1075.   if GetSizeAdjustable then begin
  1076.     Font.GetTextExtent(CText, w, h);
  1077.     PxWidth  := w;
  1078.     PxHeight := h;
  1079.   end else GetClearedText;
  1080. end;
  1081. procedure TTextGUIItem.AddProperties(const Result: Props.TProperties);
  1082. begin
  1083.   inherited;
  1084.   if Assigned(Result) then begin
  1085.     Result.Add('Text',    vtString,  [], Text, '');
  1086.     Result.Add('CText',   vtString,  [poReadOnly], CText, '');
  1087.     Result.Add('Colored', vtBoolean, [], OnOffStr[Colored], '');
  1088.   end;  
  1089.   AddItemLink(Result, 'Font', [], 'TFont');
  1090. end;
  1091. procedure TTextGUIItem.SetProperties(Properties: Props.TProperties);
  1092. begin
  1093.   inherited;
  1094.   if Properties.Valid('Text')    then Text := Properties['Text'];
  1095.   if Properties.Valid('Colored') then Colored := Properties.GetAsInteger('Colored') > 0;
  1096.   if Properties.Valid('Font')    then SetLinkProperty('Font', Properties['Font']);
  1097.   ResolveLinks;
  1098. end;
  1099. destructor TTextGUIItem.Destroy;
  1100. begin
  1101.   if Markup <> nil then FreeAndNil(Markup);
  1102.   inherited;
  1103. end;
  1104. procedure TTextGUIItem.DrawText(AX, AY: Single);
  1105. var i, CurPos: Integer; Tag: TTag;
  1106. begin
  1107.   if Colored and (MarkUp <> nil) then begin
  1108.     GetClearedText;
  1109.     CurPos := 0;
  1110.     Screen.MoveTo(AX, AY);
  1111.     for i := 0 to MarkUp.TotalTags-1 do begin
  1112.       Tag := MarkUp.Tags[i];
  1113.       if CurPos <> Tag.Position then begin
  1114.         Screen.PutText(Copy(MarkUp.PureText, CurPos+1, Tag.Position-CurPos));
  1115.         CurPos := Tag.Position;
  1116.       end;
  1117.       if Tag.ClassType = TMoveToTag     then with TMoveToTag(Tag)     do Screen.MoveTo(X, Y);
  1118.       if Tag.ClassType = TColorTag      then with TColorTag(Tag)      do Screen.SetColor(TColor(Screen.Color.C and $FF000000 or Color.C));
  1119.       if Tag.ClassType = TAlphaColorTag then with TAlphaColorTag(Tag) do Screen.SetColor(Color);
  1120.       if Tag.ClassType = TColorResetTag then with TColorResetTag(Tag) do Screen.SetColor(Self.Color);
  1121.     end;
  1122.     Screen.PutText(Copy(MarkUp.PureText, CurPos+1, Length(MarkUp.PureText)));
  1123.   end else Screen.PutTextXY(AX, AY, CText);
  1124. end;
  1125. function TTextGUIItem.GUIHandleMessage(const Msg: TMessage): Boolean;
  1126. begin
  1127.   Result := inherited GUIHandleMessage(Msg);
  1128.   if not Result then Exit;
  1129.   if MSg.ClassType = TWindowResizeMsg then if Colored and Assigned(Markup) then MarkUp.Invalidate;
  1130. end;
  1131. { TUVGUIItem }
  1132. procedure TUVGUIItem.UpdateVisualParameters;
  1133. begin
  1134.   inherited;
  1135.   Frame := NormalFrame;
  1136.   if not GetStatesSource.Enabled then begin
  1137.     if frDisabled in UsedFrames then Frame := NormalFrame + Ord(frHover in UsedFrames) + Ord(frPushed in UsedFrames) + Ord(frFocused in UsedFrames) + 1;
  1138.   end else if GetStatesSource.Pushed then begin
  1139.     if frPushed in UsedFrames then Frame := NormalFrame + Ord(frHover in UsedFrames) + 1;
  1140.   end else if GetStatesSource.Hover then begin
  1141.     if frHover in UsedFrames then Frame := NormalFrame + 1;
  1142.   end else if GetStatesSource.Focused then begin
  1143.     if frFocused in UsedFrames then Frame := NormalFrame + Ord(frHover in UsedFrames) + Ord(frPushed in UsedFrames) + 1;
  1144.   end;
  1145. end;
  1146. constructor TUVGUIItem.Create(AManager: TItemsManager);
  1147. begin
  1148.   inherited;
  1149.   SetUVMap(nil, 0);
  1150. end;
  1151. procedure TUVGUIItem.AddProperties(const Result: Props.TProperties);
  1152. begin
  1153.   inherited;
  1154.   AddItemLink(Result, 'UVMap', [], 'TUVMapResource');
  1155.   if not Assigned(Result) then Exit;
  1156.   Result.Add('UVFrame',     vtInt, [],           IntToStr(NormalFrame), '');
  1157.   Result.Add('UVMax frame', vtInt, [poReadOnly], IntToStr(MaxFrame),    '');
  1158.   Result.Add('UVUse hover frame',    vtBoolean, [], OnOffStr[frHover    in UsedFrames], '');
  1159.   Result.Add('UVUse pressed frame',  vtBoolean, [], OnOffStr[frPushed   in UsedFrames], '');
  1160.   Result.Add('UVUse disabled frame', vtBoolean, [], OnOffStr[frDisabled in UsedFrames], '');
  1161. end;
  1162. procedure TUVGUIItem.SetProperties(Properties: Props.TProperties);
  1163. begin
  1164.   inherited;
  1165.   if Properties.Valid('UVMap') then SetLinkProperty('UVMap', Properties['UVMap']);
  1166.   ResolveLinks;
  1167.   if Properties.Valid('UVFrame')              then NormalFrame := StrToIntDef(Properties['UVFrame'], 0);
  1168.   if Properties.Valid('UVUse hover frame')    then if Properties.GetAsInteger('UVUse hover frame') > 0 then
  1169.     Include(UsedFrames, frHover) else
  1170.       Exclude(UsedFrames, frHover);
  1171.   if Properties.Valid('UVUse pushed frame')   then if Properties.GetAsInteger('UVUse pushed frame') > 0 then
  1172.     Include(UsedFrames, frPushed) else
  1173.       Exclude(UsedFrames, frPushed);
  1174.   if Properties.Valid('UVUse disabled frame') then if Properties.GetAsInteger('UVUse disabled frame') > 0 then
  1175.     Include(UsedFrames, frDisabled) else
  1176.       Exclude(UsedFrames, frDisabled);
  1177.   Frame := NormalFrame;
  1178. end;
  1179. procedure TUVGUIItem.ResolveLinks;
  1180. var UVMapRes: TItem;
  1181. begin
  1182.   inherited;
  1183.   if ResolveLink('UVMap', UVMapRes) then SetUVMap((UVMapRes as TUVMapResource).Data, (UVMapRes as TUVMapResource).TotalElements - 1);
  1184. end;
  1185. procedure TUVGUIItem.SetUVMap(const AUVMap: TUVMap; ATotalFrames: Integer);
  1186. begin
  1187.   if (AUVMap <> nil) and (ATotalFrames > 0) then begin
  1188.     MaxFrame      := ATotalFrames-1;
  1189.     FUVMap   := AUVMap;
  1190.   end else FUVMap := GetDefaultUVMap;
  1191.   Frame := NormalFrame;
  1192. end;
  1193. procedure TUVGUIItem.SetFrame(const Value: Integer);
  1194. begin
  1195.   if (Value = FFrame) or (Value > MaxFrame) then Exit;
  1196.   FFrame := Value;
  1197. end;
  1198. end.