{"id":1071,"date":"2014-04-22T21:48:39","date_gmt":"2014-04-22T20:48:39","guid":{"rendered":"http:\/\/tulip-ui.azurewebsites.net\/?page_id=1071"},"modified":"2014-04-22T23:14:27","modified_gmt":"2014-04-22T22:14:27","slug":"tulip-ui-helpers-pas","status":"publish","type":"page","link":"https:\/\/tulip-ui.azurewebsites.net\/?page_id=1071","title":{"rendered":"Tulip.UI.Helpers.pas"},"content":{"rendered":"<div style=\"background-color: #FFFFFF; width: 680px\">\n<p style=\"text-align: right;\"><a title=\"Source Files\" href=\"http:\/\/tulip-ui.azurewebsites.net\/?page_id=1091\">Source Files<\/a><\/p>\n<p><code><\/p>\n<pre>\r\n{******************************************************************************}\r\n{                                                                              }\r\n{                        Tulip - User Interface Library                        }\r\n{                                                                              }\r\n{         Copyright(c) 2012 - 2013 Marcos Gomes. All rights Reserved.          }\r\n{                                                                              }\r\n{  --------------------------------------------------------------------------  }\r\n{                                                                              }\r\n{  This product is based on Asphyre Sphinx (c) 2000 - 2012  Yuriy Kotsarenko.  }\r\n{       All rights reserved. Official web site: http:\/\/www.afterwarp.net       }\r\n{                                                                              }\r\n{******************************************************************************}\r\n{                                                                              }\r\n{  Important Notice:                                                           }\r\n{                                                                              }\r\n{  If you modify\/use this code or one of its parts either in original or       }\r\n{  modified form, you must comply with Mozilla Public License Version 2.0,     }\r\n{  including section 3, \"Responsibilities\". Failure to do so will result in    }\r\n{  the license breach, which will be resolved in the court. Remember that      }\r\n{  violating author's rights either accidentally or intentionally is           }\r\n{  considered a serious crime in many countries. Thank you!                    }\r\n{                                                                              }\r\n{  !! Please *read* Mozilla Public License 2.0 document located at:            }\r\n{  http:\/\/www.mozilla.org\/MPL\/                                                 }\r\n{                                                                              }\r\n{  --------------------------------------------------------------------------  }\r\n{                                                                              }\r\n{  The contents of this file are subject to the Mozilla Public License         }\r\n{  Version 2.0 (the \"License\"); you may not use this file except in            }\r\n{  compliance with the License. You may obtain a copy of the License at        }\r\n{  http:\/\/www.mozilla.org\/MPL\/                                                 }\r\n{                                                                              }\r\n{  Software distributed under the License is distributed on an \"AS IS\"         }\r\n{  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the     }\r\n{  License for the specific language governing rights and limitations          }\r\n{  under the License.                                                          }\r\n{                                                                              }\r\n{  The Original Code is Tulip.UI.Helpers.pas.                                  }\r\n{                                                                              }\r\n{  The Initial Developer of the Original Code is Marcos Gomes.                 }\r\n{  Portions created by Marcos Gomes are Copyright (C) 2012, Marcos Gomes.      }\r\n{  All Rights Reserved.                                                        }\r\n{                                                                              }\r\n{******************************************************************************}\r\n{                                                                              }\r\n{  Tulip.UI.Helpers.pas                                 Modified: 23-Mar-2013  }\r\n{  --------------------------------------------------------------------------  }\r\n{                                                                              }\r\n{    Helper routines for importing and saving content from Images and Fonts    }\r\n{                                                                              }\r\n{                                Version 1.03                                  }\r\n{                                                                              }\r\n{******************************************************************************}\r\n\r\nunit Tulip.UI.Helpers;\r\n\r\ninterface\r\n\r\nuses\r\n  System.Classes, System.SysUtils, System.Math, System.Generics.Collections,\r\n  \/\/ Asphyre Units\r\n  AsphyreDef, AsphyreTypes, AsphyreArchives, AsphyreFonts, AsphyreImages,\r\n  AsphyreXML, MediaUtils, StreamUtils, Vectors2, Vectors2px,\r\n  \/\/ Tulip UI Units\r\n  Tulip.UI.Types;\r\n\r\nconst\r\n  foFonts = 'Fonts\\';\r\n  foImages = 'Images\\';\r\n  foNone = '';\r\n\r\ntype\r\n\r\n{$REGION 'TAsphyreFont'}\r\n  TAsphyreFontHelper = class helper for TAsphyreFont\r\n  private\r\n    function ParseStream(const Stream: TMemoryStream): Boolean;\r\n\r\n  public\r\n    function SaveXmlToArchive(const Archive: TAsphyreArchive;\r\n      const Folder: String = foNone): Boolean;\r\n    function SaveXmlToArchiveFile(const FileName: String;\r\n      const Folder: String = foNone): Boolean;\r\n\r\n    function SaveXmlToMemStream: TMemoryStream;\r\n\r\n    procedure TextRectEx(const Pos, Size: TPoint2; const Text: UniString;\r\n      const Colors: TColor2; Alpha: SizeFloat;\r\n      const HorizontalAlign: THorizontalAlign = aLeft;\r\n      const VerticalAlign: TVerticalAlign = aTop;\r\n      ParagraphLine: Boolean = True);\r\n  end;\r\n{$ENDREGION}\r\n{$REGION 'TAsphyreFonts'}\r\n\r\n  TAsphyreFontsHelper = class helper for TAsphyreFonts\r\n    function InsertFromArchive(const Name: String;\r\n      const Archive: TAsphyreArchive; const Folder: String = foNone): Integer;\r\n    function InsertFromArchiveFile(const Name, FileName: String;\r\n      const Folder: String = foNone): Integer;\r\n\r\n    function InsertFromMemStream(const Name: String;\r\n      const FontStream, ImageStream: TMemoryStream): Integer;\r\n\r\n    function SaveAllToArchive(const Archive: TAsphyreArchive;\r\n      const Folder: String = foNone): Boolean;\r\n    function SaveAllToArchiveFile(const FileName: String;\r\n      const Folder: String = foNone): Boolean;\r\n\r\n    function SaveToArchive(const Name: String; const Archive: TAsphyreArchive;\r\n      const Folder: String = foNone): Boolean; overload;\r\n    function SaveToArchiveFile(const Name, FileName: String;\r\n      const Folder: String = foNone): Boolean; overload;\r\n\r\n    function SaveToArchive(const Index: Integer; const Archive: TAsphyreArchive;\r\n      const Folder: String = foNone): Boolean; overload;\r\n    function SaveToArchiveFile(const Index: Integer; const FileName: String;\r\n      const Folder: String = foNone): Boolean; overload;\r\n  end;\r\n{$ENDREGION}\r\n{$REGION 'TAsphyreImage'}\r\n\r\n  TAsphyreImageHelper = class helper for TAsphyreImage\r\n    function SaveToArchive(const Archive: TAsphyreArchive;\r\n      const Folder: String = foNone): Boolean;\r\n    function SaveToArchiveFile(const FileName: String;\r\n      const Folder: String = foNone): Boolean;\r\n\r\n    function SaveToMemStream: TMemoryStream;\r\n  end;\r\n{$ENDREGION}\r\n{$REGION 'TAsphyreImages'}\r\n\r\n  TAsphyreImagesHelper = class helper for TAsphyreImages\r\n    function InsertFromArchive(const Name: String;\r\n      const Archive: TAsphyreArchive; const Folder: String = foNone): Integer;\r\n    function InsertFromArchiveFile(const Name, FileName: String;\r\n      const Folder: String = foNone): Integer;\r\n\r\n    function InsertFromStream(const Name: String;\r\n      const ImageStream: TMemoryStream): Integer;\r\n\r\n    function SaveAllToArchive(const Archive: TAsphyreArchive;\r\n      const Folder: String = foNone): Boolean;\r\n    function SaveAllToArchiveFile(const FileName: String;\r\n      const Folder: String = foNone): Boolean;\r\n\r\n    function SaveToArchive(const Name: String; const Archive: TAsphyreArchive;\r\n      const Folder: String = foNone): Boolean; overload;\r\n    function SaveToArchiveFile(const Name, FileName: String;\r\n      const Folder: String = foNone): Boolean; overload;\r\n\r\n    function SaveToArchive(const Index: Integer; const Archive: TAsphyreArchive;\r\n      const Folder: String = foNone): Boolean; overload;\r\n    function SaveToArchiveFile(const Index: Integer; const FileName: String;\r\n      const Folder: String = foNone): Boolean; overload;\r\n  end;\r\n{$ENDREGION}\r\n\r\nimplementation\r\n\r\n{$REGION 'TAsphyreFont'}\r\n{ TAsphyreFontHelper }\r\n\r\nfunction TAsphyreFontHelper.ParseStream(const Stream: TMemoryStream): Boolean;\r\nvar\r\n  Node, Child: TXMLNode;\r\nbegin\r\n  Node := LoadXMLFromStream(Stream);\r\n\r\n  Result := Node <> nil;\r\n  if (not Result) then\r\n    Exit;\r\n\r\n  Self.FFontSize.x := ParseInt(Node.FieldValue['width'], 0);\r\n  Self.FFontSize.y := ParseInt(Node.FieldValue['height'], 0);\r\n  Self.Kerning := ParseFloat(Node.FieldValue['kerning'], 0);\r\n\r\n  for Child in Node do\r\n    if (SameText(Child.Name, 'item')) then\r\n      Self.ParseEntry(Child);\r\n\r\n  FreeAndNil(Node);\r\nend;\r\n\r\nfunction TAsphyreFontHelper.SaveXmlToArchive(const Archive: TAsphyreArchive;\r\n  const Folder: String = foNone): Boolean;\r\nvar\r\n  Stream: TMemoryStream;\r\nbegin\r\n  Result := False;\r\n\r\n  if (Archive = nil) then\r\n    Exit;\r\n\r\n  Stream := Self.SaveXmlToMemStream;\r\n\r\n  if Stream = nil then\r\n    Exit;\r\n\r\n  Result := Archive.WriteRecord(Folder + Self.Name + '.xml', Stream.Memory,\r\n    Stream.Size, artFile);\r\n\r\n  Stream.Free;\r\nend;\r\n\r\nfunction TAsphyreFontHelper.SaveXmlToArchiveFile(const FileName: String;\r\n  const Folder: String = foNone): Boolean;\r\nvar\r\n  Media: TAsphyreArchive;\r\nbegin\r\n  Media := TAsphyreArchive.Create;\r\n\r\n  ArchiveTypeAccess := ataAnyFile;\r\n  Media.OpenMode := aomUpdate;\r\n\r\n  Result := Media.OpenFile(FileName);\r\n\r\n  if (Result) then\r\n  begin\r\n    Result := SaveXmlToArchive(Media, Folder);\r\n  end;\r\n\r\n  Media.Free;\r\nend;\r\n\r\nfunction TAsphyreFontHelper.SaveXmlToMemStream: TMemoryStream;\r\nvar\r\n  Node, Child: TXMLNode;\r\n  Stream: TMemoryStream;\r\n  BoolResult: Boolean;\r\n  Entry: TLetterEntry;\r\n  I: Integer;\r\nbegin\r\n  Node := TXMLNode.Create('font');\r\n  Node.AddField('width', IntToStr(Self.FFontSize.x));\r\n  Node.AddField('height', IntToStr(Self.FFontSize.y));\r\n  Node.AddField('kerning', FloatToStr(Self.Kerning));\r\n\r\n  for I := 0 to 65535 do\r\n  begin\r\n    Entry := Self.Entries[I];\r\n\r\n    if ((Entry.Top = 0) and (Entry.Pos = Point2px(0, 0)) and\r\n      (Entry.Size = Point2px(0, 0)) and (Entry.Leading = 0) and\r\n      (Entry.Trailing = 0)) then\r\n    begin\r\n      Continue;\r\n    end;\r\n\r\n    Child := Node.AddChild('item');\r\n\r\n    if I <= 126 then\r\n    begin\r\n      Child.AddField('ascii', IntToStr(I));\r\n    end\r\n    else\r\n    begin\r\n      Child.AddField('ucode', IntToStr(I));\r\n    end;\r\n    if (I > 32) and (I <> 34) then\r\n      Child.AddField('raw', WideChar(I));\r\n    Child.AddField('top', IntToStr(Entry.Top));\r\n    Child.AddField('x', IntToStr(Entry.Pos.x));\r\n    Child.AddField('y', IntToStr(Entry.Pos.y));\r\n    Child.AddField('width', IntToStr(Entry.Size.x));\r\n    Child.AddField('height', IntToStr(Entry.Size.y));\r\n    Child.AddField('leading', IntToStr(Entry.Leading));\r\n    Child.AddField('trailing', IntToStr(Entry.Trailing));\r\n  end;\r\n\r\n  Stream := TMemoryStream.Create;\r\n  BoolResult := Node.SaveToStream(Stream);\r\n\r\n  if not BoolResult then\r\n  begin\r\n    Stream.Free;\r\n    FreeAndNil(Node);\r\n    Result := nil;\r\n    Exit;\r\n  end;\r\n\r\n  Result := Stream;\r\n\r\n  FreeAndNil(Node);\r\nend;\r\n\r\nprocedure TAsphyreFontHelper.TextRectEx(const Pos, Size: TPoint2;\r\n  const Text: UniString; const Colors: TColor2; Alpha: SizeFloat;\r\n  const HorizontalAlign: THorizontalAlign; const VerticalAlign: TVerticalAlign;\r\n  ParagraphLine: Boolean);\r\nvar\r\n  Para, ParaTo: Integer;\r\n  WordNo, WordTo, NoWords, Index: Integer;\r\n  CurSize, PreSize, BlnkSpace, MaxSize, Height, Ident, PosAdd: Single;\r\n  CurPos: TPoint2;\r\n\r\n  I, ParaNo: Integer;\r\n  EmptySizeX, EmptySizeY, xPos, YPos: Single;\r\n  LineText: WideString;\r\n  Lines: TList<UniString>;\r\n  ParaList: TList<Integer>;\r\nbegin\r\n  Lines := TList<UniString>.Create;\r\n  ParaList := TList<Integer>.Create;\r\n\r\n  Self.SplitText(Text);\r\n\r\n  Para := -1;\r\n  ParaNo := 0;\r\n  WordNo := 0;\r\n\r\n  Self.ClearStyles();\r\n  Self.PushStyle(Colors, 0);\r\n\r\n  CurPos.x := Pos.x;\r\n  CurPos.y := Pos.y;\r\n  Height := 0;\r\n  MaxSize := Size.x;\r\n\r\n  while (WordNo < Length(Self.Words)) do\r\n  begin\r\n    CurSize := 0;\r\n    BlnkSpace := 0;\r\n\r\n    WordTo := WordNo;\r\n    ParaTo := Para;\r\n\r\n    while (CurSize + BlnkSpace < MaxSize) and (WordTo < Length(Self.Words)) and\r\n      (ParaTo = Para) do\r\n    begin\r\n      CurSize := CurSize + TextWidth(Self.Words[WordTo].Text);\r\n      BlnkSpace := BlnkSpace + Self.FWhitespace * Self.FScale;\r\n      ParaTo := Self.Words[WordTo].ParaNum;\r\n\r\n      Inc(WordTo);\r\n    end;\r\n\r\n    NoWords := (WordTo - WordNo) - 1;\r\n    if (WordTo >= Length(Self.Words)) and (CurSize + BlnkSpace < MaxSize) then\r\n    begin\r\n      Inc(NoWords);\r\n    end;\r\n\r\n    if (NoWords < 1) then\r\n    begin\r\n      \/\/ Case 1. New paragraph.\r\n      if (ParaTo <> Para) then\r\n      begin\r\n        Para := ParaTo;\r\n\r\n        if (WordNo >= 1) and (HorizontalAlign = aJustify) then\r\n        begin\r\n          ParaList.Add(ParaNo);\r\n        end;\r\n\r\n        if (WordNo >= 1) and (ParagraphLine) then\r\n          Lines.Add('');\r\n\r\n        Inc(ParaNo);\r\n        Continue;\r\n      end\r\n      else\r\n        \/\/ Case 2. Exhausted words or size doesn't fit.\r\n        Break;\r\n    end;\r\n\r\n    if ((Height + Self.FLinespace) * (Lines.Count + 1)) <= Size.y then\r\n    begin\r\n      LineText := '';\r\n      for Index := WordNo to WordNo + NoWords - 1 do\r\n      begin\r\n        if Index = (WordNo + NoWords - 1) then\r\n          LineText := LineText + Self.Words[Index].Text\r\n        else\r\n          LineText := LineText + Self.Words[Index].Text + ' ';\r\n      end;\r\n      Lines.Add(LineText);\r\n\r\n      \/\/ Calculate max line height\r\n      Height := Max(Height, TextHeight(LineText));\r\n    end\r\n    else\r\n      Break;\r\n\r\n    Inc(ParaNo);\r\n    Inc(WordNo, NoWords);\r\n  end;\r\n\r\n  \/\/ Draw all lines\r\n  for I := 0 to Lines.Count - 1 do\r\n  begin\r\n    EmptySizeX := Size.x - TextWidth(Lines[I]);\r\n    EmptySizeY := Size.y - ((Height + Self.FLinespace) * (Lines.Count));\r\n\r\n    case VerticalAlign of\r\n      aTop:\r\n        YPos := CurPos.y;\r\n      aMiddle:\r\n        YPos := CurPos.y + Round(EmptySizeY \/ 2);\r\n      aBottom:\r\n        YPos := CurPos.y + Round(EmptySizeY);\r\n    else\r\n      YPos := CurPos.y;\r\n    end;\r\n\r\n    case HorizontalAlign of\r\n      aLeft:\r\n        xPos := CurPos.x;\r\n      aCenter:\r\n        xPos := CurPos.x + Round(EmptySizeX \/ 2);\r\n      aRight:\r\n        xPos := CurPos.x + Round(EmptySizeX);\r\n      aJustify:\r\n        begin\r\n          xPos := CurPos.x;\r\n\r\n          Self.SplitText(Lines[I]);\r\n\r\n          PreSize := 0.0;\r\n          for index := 0 to Length(Self.Words) - 1 do\r\n          begin\r\n            PreSize := PreSize + TextWidth(Self.Words[Index].Text);\r\n          end;\r\n\r\n          if (Length(Self.Words) - 1) > 0 then\r\n            Ident := (Size.x - PreSize) \/ (Length(Self.Words) - 1)\r\n          else\r\n            Ident := 0.0;\r\n\r\n          \/\/ Next line is paragraph\r\n          for index := 0 to ParaList.Count - 1 do\r\n          begin\r\n            if ParagraphLine then\r\n              if (ParaList[index] = (I + 2)) then\r\n              begin\r\n                Ident := Self.FWhitespace * Self.FScale;\r\n                Break;\r\n              end\r\n              else if (ParaList[index] = (I + 1)) then\r\n              begin\r\n                Ident := Self.FWhitespace * Self.FScale;\r\n                Break;\r\n              end;\r\n          end;\r\n\r\n          \/\/ Is the last Line\r\n          if (I = (Lines.Count - 1)) then\r\n            Ident := Self.FWhitespace * Self.FScale;\r\n\r\n          \/\/ Draw word by word\r\n          PosAdd := 0.0;\r\n          for Index := 0 to Length(Self.Words) - 1 do\r\n          begin\r\n            Self.DisplayText(Point2(xPos + Round(PosAdd), YPos),\r\n              Self.Words[Index].Text, Alpha);\r\n            PosAdd := PosAdd + Self.TextWidth(Self.Words[Index].Text) + Ident;\r\n          end;\r\n        end\r\n    else\r\n      xPos := CurPos.x;\r\n    end;\r\n\r\n    if HorizontalAlign <> aJustify then\r\n      Self.DisplayText(Point2(xPos, YPos), Lines[I], Alpha);\r\n\r\n    CurPos.x := Pos.x;\r\n    CurPos.y := CurPos.y + Height + Self.FLinespace;\r\n  end;\r\n\r\n  Self.ClearStyles();\r\n\r\n  Lines.Free;\r\n  ParaList.Free;\r\nend;\r\n{$ENDREGION}\r\n{$REGION 'TAsphyreFonts'}\r\n{ TAsphyreFontsHelper }\r\n\r\nfunction TAsphyreFontsHelper.InsertFromArchive(const Name: String;\r\n  const Archive: TAsphyreArchive; const Folder: String = foNone): Integer;\r\nvar\r\n  FontStream: TMemoryStream;\r\n  ImageStream: TMemoryStream;\r\nbegin\r\n  Result := -1;\r\n\r\n  if (Archive = nil) then\r\n    Exit;\r\n\r\n  FontStream := TMemoryStream.Create;\r\n\r\n  if not(Archive.ReadMemStream(Folder + Name + '.xml', FontStream)) then\r\n  begin\r\n    FontStream.Free;\r\n    Exit;\r\n  end;\r\n\r\n  ImageStream := TMemoryStream.Create;\r\n\r\n  if not(Archive.ReadMemStream(Folder + Name + '.image', ImageStream)) then\r\n  begin\r\n    FontStream.Free;\r\n    ImageStream.Free;\r\n    Exit;\r\n  end;\r\n\r\n  Result := InsertFromMemStream(Name, FontStream, ImageStream);\r\n\r\n  FontStream.Free;\r\n  ImageStream.Free;\r\nend;\r\n\r\nfunction TAsphyreFontsHelper.InsertFromArchiveFile(const Name, FileName: String;\r\n  const Folder: String = foNone): Integer;\r\nvar\r\n  Media: TAsphyreArchive;\r\nbegin\r\n  Result := -1;\r\n\r\n  Media := TAsphyreArchive.Create;\r\n\r\n  ArchiveTypeAccess := ataAnyFile;\r\n  Media.OpenMode := aomReadOnly;\r\n\r\n  if (Media.OpenFile(FileName)) then\r\n  begin\r\n    Result := InsertFromArchive(Name, Media, Folder);\r\n  end;\r\n\r\n  Media.Free;\r\nend;\r\n\r\nfunction TAsphyreFontsHelper.InsertFromMemStream(const Name: String;\r\n  const FontStream, ImageStream: TMemoryStream): Integer;\r\nvar\r\n  ImageIndex: Integer;\r\nbegin\r\n  Result := -1;\r\n\r\n  \/\/ (1) Check whether a valid image list is provided.\r\n  if (Self.FImages = nil) then\r\n    Exit;\r\n\r\n  \/\/ (2) Resolve the bitmap font's graphics.\r\n  ImageIndex := Self.FImages.InsertFromStream(Name, ImageStream);\r\n  if (ImageIndex = -1) then\r\n    Exit;\r\n\r\n  \/\/ (3) Create new font and try to parse its description.\r\n  Result := Self.InsertFont();\r\n  if (not Self.Fonts[Result].ParseStream(FontStream)) then\r\n  begin\r\n    RemoveFont(Result);\r\n    Result := -1;\r\n    Exit;\r\n  end;\r\n\r\n  \/\/ (4) Assign font attributes.\r\n  Self.Fonts[Result].ImageIndex := ImageIndex;\r\n  Self.Fonts[Result].Name := Name;\r\nend;\r\n\r\nfunction TAsphyreFontsHelper.SaveAllToArchive(const Archive: TAsphyreArchive;\r\n  const Folder: String = foNone): Boolean;\r\nvar\r\n  I: Integer;\r\nbegin\r\n  Result := False;\r\n\r\n  if (Archive = nil) or (Self.Count = 0) then\r\n    Exit;\r\n\r\n  for I := 0 to Self.Count - 1 do\r\n  begin\r\n    if not(Self.SaveToArchive(Self.Items[I].Name, Archive, Folder)) then\r\n    begin\r\n      Exit;\r\n    end;\r\n  end;\r\n\r\n  Result := True;\r\nend;\r\n\r\nfunction TAsphyreFontsHelper.SaveAllToArchiveFile(const FileName: String;\r\n  const Folder: String = foNone): Boolean;\r\nvar\r\n  Media: TAsphyreArchive;\r\nbegin\r\n  Media := TAsphyreArchive.Create;\r\n\r\n  ArchiveTypeAccess := ataAnyFile;\r\n  Media.OpenMode := aomUpdate;\r\n\r\n  Result := Media.OpenFile(FileName);\r\n\r\n  if (Result) then\r\n  begin\r\n    Result := SaveAllToArchive(Media, Folder);\r\n  end;\r\n\r\n  Media.Free;\r\nend;\r\n\r\nfunction TAsphyreFontsHelper.SaveToArchive(const Name: String;\r\n  const Archive: TAsphyreArchive; const Folder: String = foNone): Boolean;\r\nbegin\r\n  Result := False;\r\n\r\n  if (Archive = nil) then\r\n    Exit;\r\n\r\n  if not(Self.Images.Image[Name].SaveToArchive(Archive, Folder)) then\r\n  begin\r\n    Exit;\r\n  end;\r\n\r\n  if not(Self.Font[Name].SaveXmlToArchive(Archive, Folder)) then\r\n  begin\r\n    Exit;\r\n  end;\r\n\r\n  Result := True;\r\nend;\r\n\r\nfunction TAsphyreFontsHelper.SaveToArchiveFile(const Name, FileName: String;\r\n  const Folder: String = foNone): Boolean;\r\nvar\r\n  Media: TAsphyreArchive;\r\nbegin\r\n  Media := TAsphyreArchive.Create;\r\n\r\n  ArchiveTypeAccess := ataAnyFile;\r\n  Media.OpenMode := aomUpdate;\r\n\r\n  Result := Media.OpenFile(FileName);\r\n\r\n  if (Result) then\r\n  begin\r\n    Result := Self.SaveToArchive(Name, Media, Folder);\r\n  end;\r\n\r\n  Media.Free;\r\nend;\r\n\r\nfunction TAsphyreFontsHelper.SaveToArchive(const Index: Integer;\r\n  const Archive: TAsphyreArchive; const Folder: String = foNone): Boolean;\r\nbegin\r\n  Result := False;\r\n\r\n  if (Archive = nil) then\r\n    Exit;\r\n\r\n  if not(Self.Images.Items[Self.Items[Index].ImageIndex].SaveToArchive(Archive, Folder)) then\r\n  begin\r\n    Exit;\r\n  end;\r\n\r\n  if not(Self.Items[Index].SaveXmlToArchive(Archive, Folder)) then\r\n  begin\r\n    Exit;\r\n  end;\r\n\r\n  Result := True;\r\nend;\r\n\r\nfunction TAsphyreFontsHelper.SaveToArchiveFile(const Index: Integer;\r\n  const FileName: String; const Folder: String = foNone): Boolean;\r\nvar\r\n  Media: TAsphyreArchive;\r\nbegin\r\n  Media := TAsphyreArchive.Create;\r\n\r\n  ArchiveTypeAccess := ataAnyFile;\r\n  Media.OpenMode := aomUpdate;\r\n\r\n  Result := Media.OpenFile(FileName);\r\n\r\n  if (Result) then\r\n  begin\r\n    Result := Self.SaveToArchive(Index, Media, Folder);\r\n  end;\r\n\r\n  Media.Free;\r\nend;\r\n{$ENDREGION}\r\n{$REGION 'TAsphyreImage'}\r\n{ TAsphyreImageHelper }\r\n\r\nfunction TAsphyreImageHelper.SaveToArchive(const Archive: TAsphyreArchive;\r\n  const Folder: String = foNone): Boolean;\r\nvar\r\n  Stream: TMemoryStream;\r\nbegin\r\n  Result := False;\r\n\r\n  if (Archive = nil) then\r\n    Exit;\r\n\r\n  Stream := Self.SaveToMemStream;\r\n\r\n  if Stream = nil then\r\n    Exit;\r\n\r\n  \/\/ position to the beginning of our stream\r\n  Stream.Seek(0, soFromBeginning);\r\n  Result := Archive.WriteRecord(Folder + Self.Name + '.image', Stream.Memory,\r\n    Stream.Size, artImage);\r\n\r\n  Stream.Free;\r\nend;\r\n\r\nfunction TAsphyreImageHelper.SaveToArchiveFile(const FileName: String;\r\n  const Folder: String = foNone): Boolean;\r\nvar\r\n  Media: TAsphyreArchive;\r\nbegin\r\n  Media := TAsphyreArchive.Create;\r\n\r\n  ArchiveTypeAccess := ataAnyFile;\r\n  Media.OpenMode := aomUpdate;\r\n\r\n  Result := Media.OpenFile(FileName);\r\n\r\n  if (Result) then\r\n  begin\r\n    Result := SaveToArchive(Media, Folder);\r\n  end;\r\n\r\n  Media.Free;\r\nend;\r\n\r\nfunction TAsphyreImageHelper.SaveToMemStream: TMemoryStream;\r\nvar\r\n  ImageStream: TMemoryStream;\r\n  Bits: Pointer;\r\n  Pitch: Integer;\r\n  Index: Integer;\r\n  Bytes: Integer;\r\n  TextureNo: Integer;\r\n  BoolResult: Boolean;\r\nbegin\r\n  ImageStream := TMemoryStream.Create;\r\n\r\n  \/\/ --> Format\r\n  StreamPutByte(ImageStream, Byte(Self.PixelFormat));\r\n  \/\/ --> Pattern Size\r\n  StreamPutWord(ImageStream, Self.PatternSize.x);\r\n  StreamPutWord(ImageStream, Self.PatternSize.y);\r\n  \/\/ --> Pattern Count\r\n  StreamPutLongInt(ImageStream, Self.PatternCount);\r\n  \/\/ --> Visible Size\r\n  StreamPutWord(ImageStream, Self.VisibleSize.x);\r\n  StreamPutWord(ImageStream, Self.VisibleSize.y);\r\n  \/\/ --> Texture Size\r\n  StreamPutWord(ImageStream, Self.Texture[0].Width);\r\n  StreamPutWord(ImageStream, Self.Texture[0].Height);\r\n  \/\/ --> Texture Count\r\n  StreamPutWord(ImageStream, Self.TextureCount);\r\n\r\n  for TextureNo := 0 to Self.TextureCount - 1 do\r\n  begin\r\n    Bytes := Self.Texture[TextureNo].BytesPerPixel * Self.Texture\r\n      [TextureNo].Width;\r\n\r\n    Self.Texture[TextureNo].Lock(Bounds(0, 0, Self.Texture[TextureNo].Width,\r\n      Self.Texture[TextureNo].Height), Bits, Pitch);\r\n\r\n    BoolResult := (Bits <> nil) and (Pitch > 0);\r\n    if (not BoolResult) then\r\n    begin\r\n      ImageStream.Free;\r\n      Result := nil;\r\n      Exit;\r\n    end;\r\n\r\n    for Index := 0 to Self.Texture[TextureNo].Height - 1 do\r\n    begin\r\n      ImageStream.WriteBuffer(Bits^, Bytes);\r\n\r\n      Inc(PtrInt(Bits), Pitch);\r\n    end;\r\n\r\n    Self.Texture[TextureNo].Unlock();\r\n  end;\r\n\r\n  Result := ImageStream;\r\nend;\r\n{$ENDREGION}\r\n{$REGION 'TAsphyreImages'}\r\n{ TAsphyreImagesHelper }\r\n\r\nfunction TAsphyreImagesHelper.InsertFromArchive(const Name: String;\r\n  const Archive: TAsphyreArchive; const Folder: String = foNone): Integer;\r\nvar\r\n  ImageStream: TMemoryStream;\r\nbegin\r\n  Result := -1;\r\n\r\n  if (Archive = nil) then\r\n    Exit;\r\n\r\n  ImageStream := TMemoryStream.Create;\r\n\r\n  if not(Archive.ReadMemStream(Folder + Name + '.image', ImageStream)) then\r\n  begin\r\n    ImageStream.Free;\r\n    Exit;\r\n  end;\r\n\r\n  Result := Self.InsertFromStream(Name, ImageStream);\r\n\r\n  ImageStream.Free;\r\nend;\r\n\r\nfunction TAsphyreImagesHelper.InsertFromArchiveFile(const Name,\r\n  FileName: String; const Folder: String = foNone): Integer;\r\nvar\r\n  Media: TAsphyreArchive;\r\nbegin\r\n  Result := -1;\r\n\r\n  Media := TAsphyreArchive.Create;\r\n\r\n  ArchiveTypeAccess := ataAnyFile;\r\n  Media.OpenMode := aomReadOnly;\r\n\r\n  if (Media.OpenFile(FileName)) then\r\n  begin\r\n    Result := Self.InsertFromArchive(Name, Media, Folder);\r\n  end;\r\n\r\n  Media.Free;\r\nend;\r\n\r\nfunction TAsphyreImagesHelper.InsertFromStream(const Name: String;\r\n  const ImageStream: TMemoryStream): Integer;\r\nvar\r\n  ImageItem: TAsphyreImage;\r\nbegin\r\n  ImageItem := TAsphyreImage.Create();\r\n\r\n  ImageItem.Name := Name;\r\n  ImageItem.MipMapping := True;\r\n  ImageItem.DynamicImage := False;\r\n  ImageItem.PixelFormat := apf_Unknown;\r\n\r\n  ImageStream.Seek(0, soFromBeginning);\r\n  if (not ImageItem.LoadFromStream(ImageStream)) then\r\n  begin\r\n    FreeAndNil(ImageItem);\r\n    Result := -1;\r\n    Exit;\r\n  end;\r\n\r\n  Result := Self.Insert(ImageItem);\r\nend;\r\n\r\nfunction TAsphyreImagesHelper.SaveAllToArchive(const Archive: TAsphyreArchive;\r\n  const Folder: String = foNone): Boolean;\r\nvar\r\n  I: Integer;\r\nbegin\r\n  Result := False;\r\n\r\n  if (Archive = nil) or (Self.ItemCount = 0) then\r\n    Exit;\r\n\r\n  for I := 0 to Self.ItemCount - 1 do\r\n  begin\r\n    if not (Assigned(Self.Images[I])) then\r\n    begin\r\n      Continue;\r\n    end;\r\n\r\n    if not(Self.SaveToArchive(I, Archive, Folder)) then\r\n    begin\r\n      Exit;\r\n    end;\r\n  end;\r\n\r\n  Result := True;\r\nend;\r\n\r\nfunction TAsphyreImagesHelper.SaveAllToArchiveFile(const FileName: String;\r\n  const Folder: String = foNone): Boolean;\r\nvar\r\n  Media: TAsphyreArchive;\r\nbegin\r\n  Media := TAsphyreArchive.Create;\r\n\r\n  ArchiveTypeAccess := ataAnyFile;\r\n  Media.OpenMode := aomUpdate;\r\n\r\n  Result := Media.OpenFile(FileName);\r\n\r\n  if (Result) then\r\n  begin\r\n    Result := Self.SaveAllToArchive(Media, Folder);\r\n  end;\r\n\r\n  Media.Free;\r\nend;\r\n\r\nfunction TAsphyreImagesHelper.SaveToArchive(const Index: Integer;\r\n  const Archive: TAsphyreArchive; const Folder: String = foNone): Boolean;\r\nbegin\r\n  Result := False;\r\n\r\n  if (Archive = nil) then\r\n    Exit;\r\n\r\n  if not(Self.Items[Index].SaveToArchive(Archive, Folder)) then\r\n  begin\r\n    Exit;\r\n  end;\r\n\r\n  Result := True;\r\nend;\r\n\r\nfunction TAsphyreImagesHelper.SaveToArchive(const Name: String;\r\n  const Archive: TAsphyreArchive; const Folder: String = foNone): Boolean;\r\nbegin\r\n  Result := False;\r\n\r\n  if (Archive = nil) then\r\n    Exit;\r\n\r\n  if not(Self.Image[Name].SaveToArchive(Archive, Folder)) then\r\n  begin\r\n    Exit;\r\n  end;\r\n\r\n  Result := True;\r\nend;\r\n\r\nfunction TAsphyreImagesHelper.SaveToArchiveFile(const Index: Integer;\r\n  const FileName: String; const Folder: String = foNone): Boolean;\r\nvar\r\n  Media: TAsphyreArchive;\r\nbegin\r\n  Media := TAsphyreArchive.Create;\r\n\r\n  ArchiveTypeAccess := ataAnyFile;\r\n  Media.OpenMode := aomUpdate;\r\n\r\n  Result := Media.OpenFile(FileName);\r\n\r\n  if (Result) then\r\n  begin\r\n    Result := Self.SaveToArchive(Index, Media, Folder);\r\n  end;\r\n\r\n  Media.Free;\r\nend;\r\n\r\nfunction TAsphyreImagesHelper.SaveToArchiveFile(const Name, FileName: String;\r\n  const Folder: String = foNone): Boolean;\r\nvar\r\n  Media: TAsphyreArchive;\r\nbegin\r\n  Media := TAsphyreArchive.Create;\r\n\r\n  ArchiveTypeAccess := ataAnyFile;\r\n  Media.OpenMode := aomUpdate;\r\n\r\n  Result := Media.OpenFile(FileName);\r\n\r\n  if (Result) then\r\n  begin\r\n    Result := Self.SaveToArchive(Name, Media, Folder);\r\n  end;\r\n\r\n  Media.Free;\r\nend;\r\n{$ENDREGION}\r\n\r\nend.\r\n<\/pre>\n<p><\/code>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Source Files {******************************************************************************} { } { Tulip &#8211; User Interface Library } { } { Copyright(c) 2012 &#8211; 2013 Marcos Gomes. All rights Reserved. } { } { &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211; } <a class=\"more-link\" href=\"https:\/\/tulip-ui.azurewebsites.net\/?page_id=1071\">Continue Reading &rarr;<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"parent":1091,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":[],"_links":{"self":[{"href":"https:\/\/tulip-ui.azurewebsites.net\/index.php?rest_route=\/wp\/v2\/pages\/1071"}],"collection":[{"href":"https:\/\/tulip-ui.azurewebsites.net\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/tulip-ui.azurewebsites.net\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/tulip-ui.azurewebsites.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/tulip-ui.azurewebsites.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1071"}],"version-history":[{"count":2,"href":"https:\/\/tulip-ui.azurewebsites.net\/index.php?rest_route=\/wp\/v2\/pages\/1071\/revisions"}],"predecessor-version":[{"id":1731,"href":"https:\/\/tulip-ui.azurewebsites.net\/index.php?rest_route=\/wp\/v2\/pages\/1071\/revisions\/1731"}],"up":[{"embeddable":true,"href":"https:\/\/tulip-ui.azurewebsites.net\/index.php?rest_route=\/wp\/v2\/pages\/1091"}],"wp:attachment":[{"href":"https:\/\/tulip-ui.azurewebsites.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1071"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}